solace_rs/
message.rs

1pub mod destination;
2pub mod inbound;
3pub mod outbound;
4
5use crate::SolClientReturnCode;
6pub use destination::{DestinationType, MessageDestination};
7use enum_primitive::*;
8pub use inbound::InboundMessage;
9pub use outbound::{OutboundMessage, OutboundMessageBuilder};
10use solace_rs_sys as ffi;
11use std::ffi::CStr;
12use std::mem;
13use std::mem::size_of;
14use std::ptr;
15use std::time::{Duration, SystemTime};
16use thiserror::Error;
17
18// the below assertions makes sure that u32 can always be converted into usize safely.
19#[allow(dead_code)]
20const ASSERT_USIZE_IS_AT_LEAST_U32: () = assert!(size_of::<u32>() <= size_of::<usize>());
21
22enum_from_primitive! {
23    #[derive(Debug, PartialEq, Eq)]
24    #[repr(u32)]
25    pub enum DeliveryMode {
26        Direct=ffi::SOLCLIENT_DELIVERY_MODE_DIRECT,
27        Persistent=ffi::SOLCLIENT_DELIVERY_MODE_PERSISTENT,
28        NonPersistent=ffi::SOLCLIENT_DELIVERY_MODE_NONPERSISTENT
29    }
30}
31
32enum_from_primitive! {
33    #[derive(Debug, PartialEq, Eq)]
34    #[repr(u32)]
35    pub enum ClassOfService {
36        One=ffi::SOLCLIENT_COS_1,
37        Two=ffi::SOLCLIENT_COS_2,
38        Three=ffi::SOLCLIENT_COS_3,
39    }
40}
41
42enum_from_primitive! {
43    #[derive(Debug, PartialEq, Eq)]
44    #[repr(i32)]
45    pub enum CacheStatus {
46        InvalidMessage=ffi::solClient_cacheStatus_SOLCLIENT_CACHE_INVALID_MESSAGE,
47        LiveMessage=ffi::solClient_cacheStatus_SOLCLIENT_CACHE_LIVE_MESSAGE,
48        CacheMessage=ffi::solClient_cacheStatus_SOLCLIENT_CACHE_MESSAGE,
49        SuspectMessage=ffi::solClient_cacheStatus_SOLCLIENT_CACHE_SUSPECT_MESSAGE,
50    }
51}
52
53impl From<ClassOfService> for u32 {
54    fn from(val: ClassOfService) -> Self {
55        match val {
56            ClassOfService::One => ffi::SOLCLIENT_COS_1,
57            ClassOfService::Two => ffi::SOLCLIENT_COS_2,
58            ClassOfService::Three => ffi::SOLCLIENT_COS_3,
59        }
60    }
61}
62
63#[derive(Error, Debug)]
64pub enum MessageError {
65    #[error("failed to get field. SolClient return code: {0}")]
66    FieldError(&'static str, SolClientReturnCode),
67    #[error("failed to convert field from solace")]
68    FieldConvertionError(&'static str),
69}
70
71type Result<T> = std::result::Result<T, MessageError>;
72
73pub trait Message<'a> {
74    /// .
75    ///
76    /// # Safety
77    ///
78    /// Should return ptr to a owned valid message.
79    /// No other alias for the ptr should exists.
80    /// Other methods will not check if the message is valid or not
81    ///
82    /// .
83    unsafe fn get_raw_message_ptr(&'a self) -> ffi::solClient_opaqueMsg_pt;
84
85    fn get_payload(&'a self) -> Result<Option<&'a [u8]>> {
86        let mut buffer = ptr::null_mut();
87        let mut buffer_len: u32 = 0;
88
89        let msg_ops_rc = unsafe {
90            ffi::solClient_msg_getBinaryAttachmentPtr(
91                self.get_raw_message_ptr(),
92                &mut buffer,
93                &mut buffer_len,
94            )
95        };
96
97        let rc = SolClientReturnCode::from_raw(msg_ops_rc);
98        match rc {
99            SolClientReturnCode::Ok => (),
100            SolClientReturnCode::NotFound => return Ok(None),
101            _ => return Err(MessageError::FieldError("payload", rc)),
102        }
103
104        // the compile time check ASSERT_USIZE_IS_AT_LEAST_U32 guarantees that this conversion is
105        // possible
106        let buf_len = buffer_len.try_into().unwrap();
107
108        let safe_slice = unsafe { std::slice::from_raw_parts(buffer as *const u8, buf_len) };
109
110        Ok(Some(safe_slice))
111    }
112
113    fn get_xml_part(&'a self) -> Result<Option<&'a [u8]>> {
114        let mut buffer = ptr::null_mut();
115        let mut buffer_len: u32 = 0;
116
117        let msg_ops_rc = unsafe {
118            ffi::solClient_msg_getXmlPtr(self.get_raw_message_ptr(), &mut buffer, &mut buffer_len)
119        };
120
121        let rc = SolClientReturnCode::from_raw(msg_ops_rc);
122        match rc {
123            SolClientReturnCode::Ok => (),
124            SolClientReturnCode::NotFound => return Ok(None),
125            _ => return Err(MessageError::FieldError("xml_part", rc)),
126        }
127
128        // the compile time check ASSERT_USIZE_IS_AT_LEAST_U32 guarantees that this conversion is
129        // possible
130        let buf_len = buffer_len.try_into().unwrap();
131
132        let safe_slice = unsafe { std::slice::from_raw_parts(buffer as *const u8, buf_len) };
133
134        Ok(Some(safe_slice))
135    }
136
137    fn get_application_message_id(&'a self) -> Option<&'a str> {
138        let mut buffer = ptr::null();
139
140        let rc = unsafe {
141            ffi::solClient_msg_getApplicationMessageId(self.get_raw_message_ptr(), &mut buffer)
142        };
143
144        let rc = SolClientReturnCode::from_raw(rc);
145
146        if !rc.is_ok() {
147            return None;
148        }
149
150        let c_str = unsafe { CStr::from_ptr(buffer) };
151
152        c_str.to_str().ok()
153    }
154
155    fn get_application_msg_type(&'a self) -> Option<&'a str> {
156        let mut buffer = ptr::null();
157
158        let rc = unsafe {
159            ffi::solClient_msg_getApplicationMsgType(self.get_raw_message_ptr(), &mut buffer)
160        };
161
162        let rc = SolClientReturnCode::from_raw(rc);
163
164        if !rc.is_ok() {
165            return None;
166        }
167
168        let c_str = unsafe { CStr::from_ptr(buffer) };
169
170        c_str.to_str().ok()
171    }
172
173    fn get_class_of_service(&'a self) -> Result<ClassOfService> {
174        let mut cos: u32 = 0;
175        let rc =
176            unsafe { ffi::solClient_msg_getClassOfService(self.get_raw_message_ptr(), &mut cos) };
177
178        let rc = SolClientReturnCode::from_raw(rc);
179        if !rc.is_ok() {
180            return Err(MessageError::FieldError("ClassOfService", rc));
181        }
182
183        let Some(cos) = ClassOfService::from_u32(cos) else {
184            return Err(MessageError::FieldConvertionError("ClassOfService"));
185        };
186
187        Ok(cos)
188    }
189
190    fn get_correlation_id(&'a self) -> Result<Option<&'a str>> {
191        let mut buffer = ptr::null();
192
193        let rc =
194            unsafe { ffi::solClient_msg_getCorrelationId(self.get_raw_message_ptr(), &mut buffer) };
195
196        let rc = SolClientReturnCode::from_raw(rc);
197        match rc {
198            SolClientReturnCode::Ok => (),
199            SolClientReturnCode::NotFound => return Ok(None),
200            _ => return Err(MessageError::FieldError("correlation_id", rc)),
201        }
202
203        let c_str = unsafe { CStr::from_ptr(buffer) };
204
205        let str = c_str
206            .to_str()
207            .map_err(|_| MessageError::FieldConvertionError("correlation_id"))?;
208
209        Ok(Some(str))
210    }
211
212    fn is_eliding_eligible(&'a self) -> bool {
213        let unsafe_result =
214            unsafe { ffi::solClient_msg_isElidingEligible(self.get_raw_message_ptr()) };
215
216        unsafe_result != 0
217    }
218
219    fn get_expiration(&'a self) -> i64 {
220        let mut exp: i64 = 0;
221        unsafe { ffi::solClient_msg_getExpiration(self.get_raw_message_ptr(), &mut exp) };
222
223        exp
224    }
225
226    fn get_priority(&'a self) -> Result<Option<u8>> {
227        let mut priority: i32 = 0;
228        let rc =
229            unsafe { ffi::solClient_msg_getPriority(self.get_raw_message_ptr(), &mut priority) };
230
231        let rc = SolClientReturnCode::from_raw(rc);
232        if !rc.is_ok() {
233            return Err(MessageError::FieldError("priority", rc));
234        }
235
236        if priority == -1 {
237            return Ok(None);
238        }
239
240        Ok(Some(priority as u8))
241    }
242
243    fn get_sequence_number(&'a self) -> Result<Option<i64>> {
244        let mut seq_num: i64 = 0;
245        let rc = unsafe {
246            ffi::solClient_msg_getSequenceNumber(self.get_raw_message_ptr(), &mut seq_num)
247        };
248        let rc = SolClientReturnCode::from_raw(rc);
249
250        match rc {
251            SolClientReturnCode::Ok => Ok(Some(seq_num)),
252            SolClientReturnCode::NotFound => Ok(None),
253            _ => Err(MessageError::FieldError("sequence_number", rc)),
254        }
255    }
256
257    fn get_destination(&'a self) -> Result<Option<MessageDestination>> {
258        let mut dest_struct: ffi::solClient_destination = ffi::solClient_destination {
259            destType: ffi::solClient_destinationType_SOLCLIENT_NULL_DESTINATION,
260            dest: ptr::null_mut(),
261        };
262
263        let rc = unsafe {
264            ffi::solClient_msg_getDestination(
265                self.get_raw_message_ptr(),
266                &mut dest_struct,
267                mem::size_of::<ffi::solClient_destination>(),
268            )
269        };
270
271        let rc = SolClientReturnCode::from_raw(rc);
272
273        match rc {
274            SolClientReturnCode::NotFound => Ok(None),
275            SolClientReturnCode::Fail => Err(MessageError::FieldError("destination", rc)),
276            _ => Ok(Some(MessageDestination::from(dest_struct))),
277        }
278    }
279
280    fn get_reply_to(&'a self) -> Result<Option<MessageDestination>> {
281        let mut dest_struct: ffi::solClient_destination = ffi::solClient_destination {
282            destType: ffi::solClient_destinationType_SOLCLIENT_NULL_DESTINATION,
283            dest: ptr::null_mut(),
284        };
285
286        let rc = unsafe {
287            ffi::solClient_msg_getReplyTo(
288                self.get_raw_message_ptr(),
289                &mut dest_struct,
290                mem::size_of::<ffi::solClient_destination>(),
291            )
292        };
293
294        let rc = SolClientReturnCode::from_raw(rc);
295
296        match rc {
297            SolClientReturnCode::NotFound => Ok(None),
298            SolClientReturnCode::Fail => Err(MessageError::FieldError("destination", rc)),
299            _ => Ok(Some(MessageDestination::from(dest_struct))),
300        }
301    }
302
303    fn is_reply(&'a self) -> bool {
304        let res = unsafe { ffi::solClient_msg_isReplyMsg(self.get_raw_message_ptr()) };
305        res != 0
306    }
307
308    fn get_sender_timestamp(&'a self) -> Result<Option<SystemTime>> {
309        let mut ts: i64 = 0;
310        let rc =
311            unsafe { ffi::solClient_msg_getSenderTimestamp(self.get_raw_message_ptr(), &mut ts) };
312
313        let rc = SolClientReturnCode::from_raw(rc);
314
315        match rc {
316            SolClientReturnCode::NotFound => Ok(None),
317            SolClientReturnCode::Ok => Ok(Some(
318                SystemTime::UNIX_EPOCH + Duration::from_millis(ts.try_into().unwrap()),
319            )),
320            _ => Err(MessageError::FieldError("sender_timestamp", rc)),
321        }
322    }
323
324    fn get_user_data(&'a self) -> Result<Option<&'a [u8]>> {
325        let mut buffer = ptr::null_mut();
326        let mut buffer_len: u32 = 0;
327
328        let rc = unsafe {
329            ffi::solClient_msg_getUserDataPtr(
330                self.get_raw_message_ptr(),
331                &mut buffer,
332                &mut buffer_len,
333            )
334        };
335
336        let rc = SolClientReturnCode::from_raw(rc);
337        match rc {
338            SolClientReturnCode::Ok => (),
339            SolClientReturnCode::NotFound => return Ok(None),
340            _ => return Err(MessageError::FieldError("user_data", rc)),
341        }
342
343        // the compile time check ASSERT_USIZE_IS_AT_LEAST_U32 guarantees that this conversion is
344        // possible
345        let buf_len = buffer_len.try_into().unwrap();
346
347        let safe_slice = unsafe { std::slice::from_raw_parts(buffer as *const u8, buf_len) };
348
349        Ok(Some(safe_slice))
350    }
351}