wamp_core/messages/error.rs
1use super::{
2 Call, Cancel, Invocation, MessageDirection, Publish, Register, Subscribe, Unregister,
3 Unsubscribe, WampMessage,
4};
5use crate::{messages::helpers, roles::Roles};
6use serde::{de::Visitor, Deserialize, Serialize};
7use serde_json::{json, Value};
8use serde_repr::{Deserialize_repr, Serialize_repr};
9use std::marker::PhantomData;
10
11#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq, Eq)]
12#[repr(u64)]
13pub enum WampErrorEvent {
14 Unsubscribe = Unsubscribe::ID,
15 Subscribe = Subscribe::ID,
16 Publish = Publish::ID,
17 Register = Register::ID,
18 Unregister = Unregister::ID,
19 Invocation = Invocation::ID,
20 Cancel = Cancel::ID,
21 Call = Call::ID,
22}
23
24#[derive(Debug, Clone, PartialEq, Eq)]
25/// # Error
26/// Represents an Error message in WAMP protocol.
27/// ## Wamp Docs
28/// > [Protocol Errors](https://wamp-proto.org/wamp_latest_ietf.html#name-protocol-errors)
29/// >
30/// > [Subscribe Error](https://wamp-proto.org/wamp_latest_ietf.html#name-subscribe-error)
31/// >
32/// > [Unsubscribe Error](https://wamp-proto.org/wamp_latest_ietf.html#name-unsubscribe-error)
33/// >
34/// > [Publish Error](https://wamp-proto.org/wamp_latest_ietf.html#name-publish-error)
35/// >
36/// > [Register Error](https://wamp-proto.org/wamp_latest_ietf.html#name-register-error)
37/// >
38/// > [Unregister Error](https://wamp-proto.org/wamp_latest_ietf.html#name-unregister-error)
39/// >
40/// > [Invocation Error](https://wamp-proto.org/wamp_latest_ietf.html#name-invocation-error)
41/// >
42/// > [Call Error](https://wamp-proto.org/wamp_latest_ietf.html#name-call-error)
43/// >
44/// ## Examples
45/// ```
46/// use wamp_core::messages::{WampError, WampErrorEvent};
47/// use serde_json::{json, from_value};
48///
49/// let error = WampError{
50/// event: WampErrorEvent::Call,
51/// request_id: 1,
52/// details: json!({}),
53/// error: "com.myapp.error.object_write_protected".to_string(),
54/// args: json!(["Object is write protected."]),
55/// kwargs: json!({"severity": 3})
56/// };
57/// ```
58/// ### Serializer
59/// Implementation of Serializer for WAMP Error
60/// ```
61/// use wamp_core::messages::{WampError, WampErrorEvent};
62/// use serde_json::{json, to_string};
63///
64/// let error = WampError{
65/// event: WampErrorEvent::Call,
66/// request_id: 7814135,
67/// details: json!({}),
68/// error: "com.myapp.error.object_write_protected".to_string(),
69/// args: json!(["Object is write protected."]),
70/// kwargs: json!({"severity": 3})
71/// };
72///
73/// let data = r#"[8,48,7814135,{},"com.myapp.error.object_write_protected",["Object is write protected."],{"severity":3}]"#;
74///
75/// let data2 = to_string(&error).unwrap();
76///
77/// assert_eq!(data, data2)
78/// ```
79/// ### Deserializer
80/// Implementation of serde Deserialize for WAMP Error
81/// ```
82/// use wamp_core::messages::{WampError, WampErrorEvent};
83/// use serde_json::{json, from_str};
84///
85/// let error = WampError {
86/// event: WampErrorEvent::Call,
87/// request_id: 7814135,
88/// details: json!({}),
89/// error: "com.myapp.error.object_write_protected".to_string(),
90/// args: json!(["Object is write protected."]),
91/// kwargs: json!({"severity": 3})
92/// };
93///
94/// let data = r#"[8,48,7814135,{},"com.myapp.error.object_write_protected",["Object is write protected."],{"severity":3}]"#;
95///
96/// let error2 = from_str::<WampError>(data).unwrap();
97///
98/// assert_eq!(error, error2);
99/// ```
100pub struct WampError {
101 pub event: WampErrorEvent,
102 pub request_id: u64,
103 pub details: Value,
104 pub error: String,
105 pub args: Value,
106 pub kwargs: Value,
107}
108
109#[macro_export]
110/// # Error Macro
111/// This macro is used for constructing wamp errors with default empty or custom details, args, and kwargs.
112/// ## Examples
113/// ```
114/// use wamp_core::messages::{WampErrorEvent, WampError};
115/// use wamp_core::error;
116/// use serde_json::{json, Value};
117///
118/// // Create an error with default values
119/// let error = error!(WampErrorEvent::Call, 1, "wamp.error.unknown_realm");
120///
121/// // Which is the same as creating this
122/// let error2 = WampError {
123/// event: WampErrorEvent::Call,
124/// request_id: 1,
125/// details: json!({}),
126/// error: "wamp.error.unknown_realm".to_string(),
127/// args: Value::Null,
128/// kwargs: Value::Null
129/// };
130///
131/// assert_eq!(error, error2);
132///
133/// // Some other ways to use the macro
134///
135/// // Create error with custom details
136/// let _ = error!(WampErrorEvent::Call, 1, "wamp.error.unknown", json!({ "key": "value" }));
137///
138/// // create error with empty default details and custom args or kwargs
139/// let _ = error!(WampErrorEvent::Call, 1, "wamp.error.unknown", args: json!([ 1, 2, 3 ]));
140/// let _ = error!(WampErrorEvent::Call, 1, "wamp.error.unknown", kwargs: json!({ "key": "value" }));
141///
142/// // create error with empty default details and custom args and kwargs
143/// let _ = error!(WampErrorEvent::Call, 1, "wamp.error.unknown", args: json!([ 1, 2, 3 ]), kwargs: json!({ "key": "value" }));
144///
145/// // note that when you use all values, you do not need keyword arguments for args and kwargs
146/// let _ = error!(WampErrorEvent::Call, 1, "wamp.error.unknown", json!({}), json!([1, 2, 3]), json!({ "key": "value" }));
147/// ```
148macro_rules! error {
149 ($event:expr, $request_id:expr, $error:expr) => {
150 error! {$event, $request_id, $error, serde_json::json!({})}
151 };
152
153 ($event:expr, $request_id:expr, $error:expr, args: $args:expr, kwargs: $kwargs:expr) => {
154 error! {$event, $request_id, $error, serde_json::json!({}), $args, $kwargs}
155 };
156
157 ($event:expr, $request_id:expr, $error:expr, args: $args:expr) => {
158 error! {$event, $request_id, $error, serde_json::json!({}), $args, serde_json::Value::Null}
159 };
160
161 ($event:expr, $request_id:expr, $error:expr, kwargs: $kwargs:expr) => {
162 error! {$event, $request_id, $error, serde_json::json!({}), serde_json::Value::Null, $kwargs}
163 };
164
165 ($event:expr, $request_id:expr, $error:expr, $details:expr) => {
166 error! {$event, $request_id, $error, $details, serde_json::Value::Null, serde_json::Value::Null}
167 };
168
169 ($event:expr, $request_id:expr, $error:expr, $details:expr, args: $args:expr) => {
170 error! {$event, $request_id, $error, $details, $args, serde_json::Value::Null}
171 };
172
173 ($event:expr, $request_id:expr, $error:expr, $details:expr, kwargs: $kwargs:expr) => {
174 error! {$event, $request_id, $error, $details, serde_json::Value::Null, $kwargs}
175 };
176
177 ($event:expr, $request_id:expr, $error:expr, $details:expr, $args:expr, $kwargs:expr) => {
178 WampError {
179 event: $event,
180 request_id: $request_id,
181 details: $details,
182 error: $error.to_string(),
183 args: $args,
184 kwargs: $kwargs,
185 }
186 };
187}
188
189impl WampMessage for WampError {
190 const ID: u64 = 8;
191
192 fn direction(role: Roles) -> &'static MessageDirection {
193 match role {
194 Roles::Callee => &MessageDirection {
195 receives: &true,
196 sends: &true,
197 },
198 Roles::Caller => &MessageDirection {
199 receives: &true,
200 sends: &false,
201 },
202 Roles::Publisher => &MessageDirection {
203 receives: &true,
204 sends: &false,
205 },
206 Roles::Subscriber => &MessageDirection {
207 receives: &true,
208 sends: &false,
209 },
210 Roles::Dealer => &MessageDirection {
211 receives: &true,
212 sends: &true,
213 },
214 Roles::Broker => &MessageDirection {
215 receives: &false,
216 sends: &true,
217 },
218 }
219 }
220}
221
222impl Serialize for WampError {
223 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
224 where
225 S: serde::Serializer,
226 {
227 let details =
228 helpers::ser_value_is_object::<S, _>(&self.details, "Details must be Object like.")?;
229 let args =
230 helpers::ser_value_is_args::<S, _>(&self.args, "Args must be Array like or Null.")?;
231 let kwargs = helpers::ser_value_is_kwargs::<S, _>(
232 &self.kwargs,
233 "Kwargs must be Object like or Null.",
234 )?;
235
236 if args.is_null() {
237 if kwargs.is_null() {
238 (
239 Self::ID,
240 &self.event,
241 &self.request_id,
242 details,
243 &self.error,
244 )
245 .serialize(serializer)
246 } else {
247 (
248 Self::ID,
249 &self.event,
250 &self.request_id,
251 details,
252 &self.error,
253 json!([]),
254 kwargs,
255 )
256 .serialize(serializer)
257 }
258 } else {
259 if kwargs.is_null() {
260 (
261 Self::ID,
262 &self.event,
263 &self.request_id,
264 details,
265 &self.error,
266 args,
267 )
268 .serialize(serializer)
269 } else {
270 (
271 Self::ID,
272 &self.event,
273 &self.request_id,
274 details,
275 &self.error,
276 args,
277 kwargs,
278 )
279 .serialize(serializer)
280 }
281 }
282 }
283}
284
285impl<'de> Deserialize<'de> for WampError {
286 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
287 where
288 D: serde::Deserializer<'de>,
289 {
290 struct WampErrorVisitor(
291 PhantomData<u64>,
292 PhantomData<WampErrorEvent>,
293 PhantomData<u64>,
294 PhantomData<Value>,
295 PhantomData<String>,
296 PhantomData<Value>,
297 PhantomData<Value>,
298 );
299
300 impl<'vi> Visitor<'vi> for WampErrorVisitor {
301 type Value = WampError;
302
303 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
304 formatter.write_str("A sequence of WampError components.")
305 }
306
307 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
308 where
309 A: serde::de::SeqAccess<'vi>,
310 {
311 let message_id: u64 = helpers::deser_seq_element(
312 &mut seq,
313 "Message id must be present and type u64.",
314 )?;
315 helpers::validate_id::<WampError, A, _>(&message_id, "WampError")?;
316 let event: WampErrorEvent = helpers::deser_seq_element(
317 &mut seq,
318 "Message type of error must be present and type u64",
319 )?;
320 let request_id: u64 = helpers::deser_seq_element(
321 &mut seq,
322 "Request ID must be present and type u64",
323 )?;
324 let details: Value = helpers::deser_seq_element(
325 &mut seq,
326 "Details must be present and object like",
327 )?;
328 helpers::deser_value_is_object::<A, _>(&details, "Details must be object like.")?;
329 let error: String = helpers::deser_seq_element(
330 &mut seq,
331 "Error URI must be present and type String",
332 )?;
333 helpers::deser_value_is_object::<A, _>(&details, "Details must be object like.")?;
334 let args: Value = helpers::deser_args_kwargs_element(
335 &mut seq,
336 "Args must be array like or null.",
337 )?;
338 let kwargs: Value = helpers::deser_args_kwargs_element(
339 &mut seq,
340 "Kwargs must be object like or null.",
341 )?;
342 Ok(WampError {
343 event,
344 request_id,
345 details,
346 error,
347 args,
348 kwargs,
349 })
350 }
351 }
352
353 deserializer.deserialize_struct(
354 "WampError",
355 &["event", "request_id", "details", "error", "args", "kwargs"],
356 WampErrorVisitor(
357 PhantomData,
358 PhantomData,
359 PhantomData,
360 PhantomData,
361 PhantomData,
362 PhantomData,
363 PhantomData,
364 ),
365 )
366 }
367}