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#[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 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 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 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 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}