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