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_application_message_id(&'a self) -> Option<&'a str> {
114 let mut buffer = ptr::null();
115
116 let rc = unsafe {
117 ffi::solClient_msg_getApplicationMessageId(self.get_raw_message_ptr(), &mut buffer)
118 };
119
120 let rc = SolClientReturnCode::from_raw(rc);
121
122 if !rc.is_ok() {
123 return None;
124 }
125
126 let c_str = unsafe { CStr::from_ptr(buffer) };
127
128 c_str.to_str().ok()
129 }
130
131 fn get_application_msg_type(&'a self) -> Option<&'a str> {
132 let mut buffer = ptr::null();
133
134 let rc = unsafe {
135 ffi::solClient_msg_getApplicationMsgType(self.get_raw_message_ptr(), &mut buffer)
136 };
137
138 let rc = SolClientReturnCode::from_raw(rc);
139
140 if !rc.is_ok() {
141 return None;
142 }
143
144 let c_str = unsafe { CStr::from_ptr(buffer) };
145
146 c_str.to_str().ok()
147 }
148
149 fn get_class_of_service(&'a self) -> Result<ClassOfService> {
150 let mut cos: u32 = 0;
151 let rc =
152 unsafe { ffi::solClient_msg_getClassOfService(self.get_raw_message_ptr(), &mut cos) };
153
154 let rc = SolClientReturnCode::from_raw(rc);
155 if !rc.is_ok() {
156 return Err(MessageError::FieldError("ClassOfService", rc));
157 }
158
159 let Some(cos) = ClassOfService::from_u32(cos) else {
160 return Err(MessageError::FieldConvertionError("ClassOfService"));
161 };
162
163 Ok(cos)
164 }
165
166 fn get_correlation_id(&'a self) -> Result<Option<&'a str>> {
167 let mut buffer = ptr::null();
168
169 let rc =
170 unsafe { ffi::solClient_msg_getCorrelationId(self.get_raw_message_ptr(), &mut buffer) };
171
172 let rc = SolClientReturnCode::from_raw(rc);
173 match rc {
174 SolClientReturnCode::Ok => (),
175 SolClientReturnCode::NotFound => return Ok(None),
176 _ => return Err(MessageError::FieldError("correlation_id", rc)),
177 }
178
179 let c_str = unsafe { CStr::from_ptr(buffer) };
180
181 let str = c_str
182 .to_str()
183 .map_err(|_| MessageError::FieldConvertionError("correlation_id"))?;
184
185 Ok(Some(str))
186 }
187
188 fn is_eliding_eligible(&'a self) -> bool {
189 let unsafe_result =
190 unsafe { ffi::solClient_msg_isElidingEligible(self.get_raw_message_ptr()) };
191
192 unsafe_result != 0
193 }
194
195 fn get_expiration(&'a self) -> i64 {
196 let mut exp: i64 = 0;
197 unsafe { ffi::solClient_msg_getExpiration(self.get_raw_message_ptr(), &mut exp) };
198
199 exp
200 }
201
202 fn get_priority(&'a self) -> Result<Option<u8>> {
203 let mut priority: i32 = 0;
204 let rc =
205 unsafe { ffi::solClient_msg_getPriority(self.get_raw_message_ptr(), &mut priority) };
206
207 let rc = SolClientReturnCode::from_raw(rc);
208 if !rc.is_ok() {
209 return Err(MessageError::FieldError("priority", rc));
210 }
211
212 if priority == -1 {
213 return Ok(None);
214 }
215
216 Ok(Some(priority as u8))
217 }
218
219 fn get_sequence_number(&'a self) -> Result<Option<i64>> {
220 let mut seq_num: i64 = 0;
221 let rc = unsafe {
222 ffi::solClient_msg_getSequenceNumber(self.get_raw_message_ptr(), &mut seq_num)
223 };
224 let rc = SolClientReturnCode::from_raw(rc);
225
226 match rc {
227 SolClientReturnCode::Ok => Ok(Some(seq_num)),
228 SolClientReturnCode::NotFound => Ok(None),
229 _ => Err(MessageError::FieldError("sequence_number", rc)),
230 }
231 }
232
233 fn get_destination(&'a self) -> Result<Option<MessageDestination>> {
234 let mut dest_struct: ffi::solClient_destination = ffi::solClient_destination {
235 destType: ffi::solClient_destinationType_SOLCLIENT_NULL_DESTINATION,
236 dest: ptr::null_mut(),
237 };
238
239 let rc = unsafe {
240 ffi::solClient_msg_getDestination(
241 self.get_raw_message_ptr(),
242 &mut dest_struct,
243 mem::size_of::<ffi::solClient_destination>(),
244 )
245 };
246
247 let rc = SolClientReturnCode::from_raw(rc);
248
249 match rc {
250 SolClientReturnCode::NotFound => Ok(None),
251 SolClientReturnCode::Fail => Err(MessageError::FieldError("destination", rc)),
252 _ => Ok(Some(MessageDestination::from(dest_struct))),
253 }
254 }
255
256 fn get_reply_to(&'a self) -> Result<Option<MessageDestination>> {
257 let mut dest_struct: ffi::solClient_destination = ffi::solClient_destination {
258 destType: ffi::solClient_destinationType_SOLCLIENT_NULL_DESTINATION,
259 dest: ptr::null_mut(),
260 };
261
262 let rc = unsafe {
263 ffi::solClient_msg_getReplyTo(
264 self.get_raw_message_ptr(),
265 &mut dest_struct,
266 mem::size_of::<ffi::solClient_destination>(),
267 )
268 };
269
270 let rc = SolClientReturnCode::from_raw(rc);
271
272 match rc {
273 SolClientReturnCode::NotFound => Ok(None),
274 SolClientReturnCode::Fail => Err(MessageError::FieldError("destination", rc)),
275 _ => Ok(Some(MessageDestination::from(dest_struct))),
276 }
277 }
278
279 fn is_reply(&'a self) -> bool {
280 let res = unsafe { ffi::solClient_msg_isReplyMsg(self.get_raw_message_ptr()) };
281 res != 0
282 }
283
284 fn get_sender_timestamp(&'a self) -> Result<Option<SystemTime>> {
285 let mut ts: i64 = 0;
286 let rc =
287 unsafe { ffi::solClient_msg_getSenderTimestamp(self.get_raw_message_ptr(), &mut ts) };
288
289 let rc = SolClientReturnCode::from_raw(rc);
290
291 match rc {
292 SolClientReturnCode::NotFound => Ok(None),
293 SolClientReturnCode::Ok => Ok(Some(
294 SystemTime::UNIX_EPOCH + Duration::from_millis(ts.try_into().unwrap()),
295 )),
296 _ => Err(MessageError::FieldError("sender_timestamp", rc)),
297 }
298 }
299
300 fn get_user_data(&'a self) -> Result<Option<&'a [u8]>> {
301 let mut buffer = ptr::null_mut();
302 let mut buffer_len: u32 = 0;
303
304 let rc = unsafe {
305 ffi::solClient_msg_getUserDataPtr(
306 self.get_raw_message_ptr(),
307 &mut buffer,
308 &mut buffer_len,
309 )
310 };
311
312 let rc = SolClientReturnCode::from_raw(rc);
313 match rc {
314 SolClientReturnCode::Ok => (),
315 SolClientReturnCode::NotFound => return Ok(None),
316 _ => return Err(MessageError::FieldError("user_data", rc)),
317 }
318
319 let buf_len = buffer_len.try_into().unwrap();
322
323 let safe_slice = unsafe { std::slice::from_raw_parts(buffer as *const u8, buf_len) };
324
325 Ok(Some(safe_slice))
326 }
327}