|
1 | | -use pyo3::{Bound, Py, PyAny, Python, types::PyDict}; |
| 1 | +use pyo3::{ |
| 2 | + Bound, Py, PyAny, Python, |
| 3 | + types::{PyBytes, PyDict}, |
| 4 | +}; |
2 | 5 | use std::sync::Arc; |
3 | 6 | use tokio::sync::RwLock; |
4 | 7 |
|
5 | 8 | use crate::{ |
6 | | - exceptions::rust_err::NatsrpyResult, |
7 | | - utils::{headers::NatsrpyHeadermapExt, natsrpy_future}, |
| 9 | + exceptions::rust_err::{NatsrpyError, NatsrpyResult}, |
| 10 | + utils::{natsrpy_future, py_types::TimeValue}, |
8 | 11 | }; |
9 | 12 |
|
10 | 13 | #[pyo3::pyclass] |
11 | 14 | pub struct JetStreamMessage { |
12 | | - message: async_nats::Message, |
13 | | - headers: Option<Py<PyDict>>, |
| 15 | + message: crate::message::Message, |
14 | 16 | acker: Arc<RwLock<async_nats::jetstream::message::Acker>>, |
15 | 17 | } |
16 | 18 |
|
17 | | -impl From<async_nats::jetstream::Message> for JetStreamMessage { |
18 | | - fn from(value: async_nats::jetstream::Message) -> Self { |
| 19 | +impl TryFrom<async_nats::jetstream::Message> for JetStreamMessage { |
| 20 | + type Error = NatsrpyError; |
| 21 | + |
| 22 | + fn try_from(value: async_nats::jetstream::Message) -> Result<Self, Self::Error> { |
19 | 23 | let (message, acker) = value.split(); |
20 | | - Self { |
21 | | - message, |
22 | | - headers: None, |
| 24 | + Ok(Self { |
| 25 | + message: message.try_into()?, |
23 | 26 | acker: Arc::new(RwLock::new(acker)), |
24 | | - } |
| 27 | + }) |
| 28 | + } |
| 29 | +} |
| 30 | + |
| 31 | +impl JetStreamMessage { |
| 32 | + pub fn inner_ack<'py>( |
| 33 | + &self, |
| 34 | + py: Python<'py>, |
| 35 | + kind: async_nats::jetstream::message::AckKind, |
| 36 | + double: bool, |
| 37 | + ) -> NatsrpyResult<Bound<'py, PyAny>> { |
| 38 | + let acker_guard = self.acker.clone(); |
| 39 | + natsrpy_future(py, async move { |
| 40 | + if double { |
| 41 | + acker_guard.read().await.double_ack_with(kind).await?; |
| 42 | + } else { |
| 43 | + acker_guard.read().await.ack_with(kind).await?; |
| 44 | + } |
| 45 | + Ok(()) |
| 46 | + }) |
25 | 47 | } |
26 | 48 | } |
27 | 49 |
|
28 | 50 | #[pyo3::pymethods] |
29 | 51 | impl JetStreamMessage { |
30 | 52 | #[getter] |
31 | | - pub fn subject(&self) -> &str { |
| 53 | + #[must_use] |
| 54 | + pub const fn subject(&self) -> &str { |
32 | 55 | self.message.subject.as_str() |
33 | 56 | } |
34 | 57 | #[getter] |
35 | | - pub fn reply(&self) -> Option<&str> { |
36 | | - self.message.reply.as_ref().map(async_nats::Subject::as_str) |
| 58 | + #[must_use] |
| 59 | + pub const fn reply(&self) -> &Option<String> { |
| 60 | + &self.message.reply |
37 | 61 | } |
38 | 62 | #[getter] |
39 | | - pub fn payload(&self) -> &[u8] { |
| 63 | + #[must_use] |
| 64 | + pub const fn payload(&self) -> &Py<PyBytes> { |
40 | 65 | &self.message.payload |
41 | 66 | } |
42 | 67 | #[getter] |
43 | | - pub fn headers(&mut self, py: Python<'_>) -> NatsrpyResult<Py<PyDict>> { |
44 | | - if let Some(headers) = &self.headers { |
45 | | - Ok(headers.clone_ref(py)) |
46 | | - } else { |
47 | | - let headermap = self.message.headers.clone().unwrap_or_default(); |
48 | | - let headers = headermap.to_pydict(py)?.unbind(); |
49 | | - self.headers = Some(headers.clone_ref(py)); |
50 | | - Ok(headers) |
51 | | - } |
52 | | - } |
53 | | - |
54 | | - pub fn ack<'py>(&self, py: Python<'py>) -> NatsrpyResult<Bound<'py, PyAny>> { |
55 | | - let acker_guard = self.acker.clone(); |
56 | | - natsrpy_future(py, async move { |
57 | | - acker_guard.read().await.ack().await?; |
58 | | - Ok(()) |
59 | | - }) |
| 68 | + pub const fn headers(&mut self) -> &Py<PyDict> { |
| 69 | + &self.message.headers |
| 70 | + } |
| 71 | + |
| 72 | + #[pyo3(signature=(double=false))] |
| 73 | + pub fn ack<'py>(&self, py: Python<'py>, double: bool) -> NatsrpyResult<Bound<'py, PyAny>> { |
| 74 | + self.inner_ack(py, async_nats::jetstream::message::AckKind::Ack, double) |
| 75 | + } |
| 76 | + |
| 77 | + #[pyo3(signature=(delay=None, double=false))] |
| 78 | + pub fn nack<'py>( |
| 79 | + &self, |
| 80 | + py: Python<'py>, |
| 81 | + delay: Option<TimeValue>, |
| 82 | + double: bool, |
| 83 | + ) -> NatsrpyResult<Bound<'py, PyAny>> { |
| 84 | + self.inner_ack( |
| 85 | + py, |
| 86 | + async_nats::jetstream::message::AckKind::Nak(delay.map(Into::into)), |
| 87 | + double, |
| 88 | + ) |
| 89 | + } |
| 90 | + |
| 91 | + #[pyo3(signature=(double=false))] |
| 92 | + pub fn progress<'py>(&self, py: Python<'py>, double: bool) -> NatsrpyResult<Bound<'py, PyAny>> { |
| 93 | + self.inner_ack( |
| 94 | + py, |
| 95 | + async_nats::jetstream::message::AckKind::Progress, |
| 96 | + double, |
| 97 | + ) |
| 98 | + } |
| 99 | + |
| 100 | + #[pyo3(signature=(double=false))] |
| 101 | + pub fn next<'py>(&self, py: Python<'py>, double: bool) -> NatsrpyResult<Bound<'py, PyAny>> { |
| 102 | + self.inner_ack(py, async_nats::jetstream::message::AckKind::Next, double) |
| 103 | + } |
| 104 | + |
| 105 | + #[pyo3(signature=(double=false))] |
| 106 | + pub fn term<'py>(&self, py: Python<'py>, double: bool) -> NatsrpyResult<Bound<'py, PyAny>> { |
| 107 | + self.inner_ack(py, async_nats::jetstream::message::AckKind::Term, double) |
| 108 | + } |
| 109 | + |
| 110 | + #[must_use] |
| 111 | + pub fn __repr__(&self) -> String { |
| 112 | + self.message.__repr__() |
60 | 113 | } |
61 | 114 | } |
0 commit comments