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