wamp_core/messages/
abort.rs

1use super::{helpers, MessageDirection, WampMessage};
2use crate::roles::Roles;
3use serde::{
4    de::{self, Visitor},
5    Deserialize, Serialize,
6};
7use serde_json::Value;
8use std::marker::PhantomData;
9
10#[derive(Debug, Clone, PartialEq, Eq)]
11/// # Abort - [wamp-proto](https://wamp-proto.org/wamp_latest_ietf.html#name-abort-2)
12/// Represents an Abort message in the WAMP protocol.
13/// ## Examples
14/// ```
15/// use wamp_core::messages::Abort;
16/// use wamp_core::abort;
17/// use serde_json::json;
18/// # let mut abort_message2 = abort!("wamp.error.no_such_realm");
19///
20/// let abort_message = Abort {
21///     reason: "wamp.error.no_such_realm".to_string(),
22///     details: json!({})
23/// };
24///
25/// # assert_eq!(abort_message, abort_message2);
26/// ```
27/// ### Serializer
28/// Implements serde Serialize trait for Abort
29/// ```
30/// use wamp_core::messages::Abort;
31/// use serde_json::{json, to_string};
32///
33/// // Create an Abort message
34/// let abort = Abort {
35///     details: json!({ "message": "The realm does not exist." }),
36///     reason: "wamp.error.no_such_realm".to_string()
37/// };
38///
39/// // Establish raw json data string
40/// let data = r#"[3,{"message":"The realm does not exist."},"wamp.error.no_such_realm"]"#;
41///
42/// // Here we convert it from an `Abort` frame, to a string representation.
43/// let abort = to_string(&abort).unwrap();
44///
45/// // Confirm that our abort frame strings are equal to eachother
46/// assert_eq!(abort, data);
47/// ```
48/// ### Deserializer
49/// Implements serde Deserialize trait for Abort
50/// ```
51/// use wamp_core::messages::Abort;
52/// use serde_json::from_str;
53///
54/// // Here is our raw json data string
55/// let data = r#"[3,{"message":"The realm does not exist."},"wamp.error.no_such_realm"]"#;
56///
57/// // Here we convert it to an `Abort` frame
58/// let abort = from_str::<Abort>(data).unwrap();
59///
60/// // Confirm that our error type deserialized
61/// assert_eq!(abort.reason, "wamp.error.no_such_realm");
62/// ```
63pub struct Abort {
64    pub details: Value,
65    pub reason: String,
66}
67
68#[macro_export]
69/// # Abort Macro - [wamp-proto](https://wamp-proto.org/wamp_latest_ietf.html#name-abort-2)
70/// Abort macro allows for default empty implementation of details object on Abort.
71/// ## Examples
72/// ```
73/// use wamp_core::messages::Abort;
74/// use wamp_core::abort;
75/// use serde_json::json;
76///
77/// // Construct with default empty details object
78/// let mut abort_message = abort!("wamp.error.no_such_realm");
79/// assert_eq!(abort_message.details, json!({}));
80///
81/// // Construct with custom details
82/// let abort_message2 = abort!("wamp.error.no_such_realm", json!({
83///     "message": "The realm does not exist."
84/// }));
85///
86/// assert_ne!(abort_message, abort_message2);
87/// abort_message.details = json!({ "message": "The realm does not exist." });
88/// assert_eq!(abort_message, abort_message2);
89///
90/// // These macro invocations are the same as the following:
91/// let abort_message3 = Abort {
92///     reason: "wamp.error.no_such_realm".to_string(),
93///     details: json!({
94///         "message": "The realm does not exist."
95///     })
96/// };
97///
98/// assert_eq!(abort_message, abort_message3);
99/// assert_eq!(abort_message2, abort_message3);
100/// ```
101macro_rules! abort {
102    ($reason:expr) => {
103        abort! {$reason, serde_json::json!({})}
104    };
105
106    ($reason:expr, $details:expr) => {
107        Abort {
108            details: $details,
109            reason: $reason.to_string(),
110        }
111    };
112}
113
114impl WampMessage for Abort {
115    const ID: u64 = 3;
116
117    fn direction(role: crate::roles::Roles) -> &'static super::MessageDirection {
118        match role {
119            Roles::Callee => &MessageDirection {
120                receives: &true,
121                sends: &false,
122            },
123            Roles::Caller => &MessageDirection {
124                receives: &true,
125                sends: &false,
126            },
127            Roles::Publisher => &MessageDirection {
128                receives: &true,
129                sends: &false,
130            },
131            Roles::Subscriber => &MessageDirection {
132                receives: &true,
133                sends: &false,
134            },
135            Roles::Dealer => &MessageDirection {
136                receives: &false,
137                sends: &true,
138            },
139            Roles::Broker => &MessageDirection {
140                receives: &false,
141                sends: &true,
142            },
143        }
144    }
145}
146
147impl Serialize for Abort {
148    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
149    where
150        S: serde::Serializer,
151    {
152        let details =
153            helpers::ser_value_is_object::<S, _>(&self.details, "Details must be object like.")?;
154        (Self::ID, &details, &self.reason).serialize(serializer)
155    }
156}
157
158impl<'de> Deserialize<'de> for Abort {
159    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
160    where
161        D: serde::Deserializer<'de>,
162    {
163        struct AbortVisitor(PhantomData<u8>, PhantomData<String>, PhantomData<Value>);
164
165        impl<'vi> Visitor<'vi> for AbortVisitor {
166            type Value = Abort;
167
168            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
169                formatter.write_str("WAMP Abort frame, expressed as a sequence.")
170            }
171
172            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
173            where
174                A: de::SeqAccess<'vi>,
175            {
176                let message_id: u64 =
177                    helpers::deser_seq_element(&mut seq, "Message ID must be type u8.")?;
178                helpers::validate_id::<Abort, A, _>(&message_id, "Abort")?;
179                let details: Value =
180                    helpers::deser_seq_element(&mut seq, "Details must be a JSON value.")?;
181                let reason: String =
182                    helpers::deser_seq_element(&mut seq, "Reason must be a String.")?;
183                helpers::deser_value_is_object::<A, _>(&details, "Details must be object like.")?;
184                Ok(Abort { reason, details })
185            }
186        }
187
188        deserializer.deserialize_struct(
189            "Abort",
190            &["reason", "details"],
191            AbortVisitor(PhantomData, PhantomData, PhantomData),
192        )
193    }
194}