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}