wamp_core/messages/publish.rs
1use crate::roles::Roles;
2use serde::de::{SeqAccess, Visitor};
3use serde::{Deserialize, Deserializer, Serialize};
4use serde_json::{json, Value};
5use std::fmt::Formatter;
6use std::marker::PhantomData;
7
8use super::{helpers, MessageDirection, WampMessage};
9
10#[derive(Debug, PartialEq, Eq, Clone)]
11/// # Publish - [wamp-proto](https://wamp-proto.org/wamp_latest_ietf.html#name-publish-2)
12/// Represents an publish message in the WAMP protocol.
13/// ## Examples
14/// ```
15/// use wamp_core::messages::Publish;
16/// use wamp_core::publish;
17/// use serde_json::{json, Value};
18///
19/// let publish = Publish {
20/// request_id: 1,
21/// options: json!({ }),
22/// topic: "topic".to_string(),
23/// args: Value::Null,
24/// kwargs: Value::Null
25/// };
26///
27/// let publish2 = publish!("topic");
28///
29/// assert_eq!(publish, publish2);
30/// ```
31/// ### Serializer
32/// Serde Serialize trait implementation for publish.
33/// ```
34/// use wamp_core::messages::Publish;
35/// use serde_json::{json, to_string};
36///
37/// let publish = Publish {
38/// request_id: 7814135,
39/// options: json!({}),
40/// topic: "com.myapp.user.new".to_string(),
41/// args: json!(["johnny"]),
42/// kwargs: json!({"firstname":"John","surname":"Doe"})
43/// };
44///
45/// let publish2_string = r#"[16,7814135,{},"com.myapp.user.new",["johnny"],{"firstname":"John","surname":"Doe"}]"#;
46///
47/// let publish_string = to_string(&publish).unwrap();
48/// assert_eq!(publish_string, publish2_string);
49/// ```
50/// ### Deserializer
51/// Serde Deserialize trait implementation for publish.
52/// ```
53/// use wamp_core::messages::Publish;
54/// use serde_json::{json, from_str};
55///
56/// let publish = Publish {
57/// request_id: 7814135,
58/// options: json!({}),
59/// topic: "com.myapp.user.new".to_string(),
60/// args: json!(["johnny"]),
61/// kwargs: json!({"firstname":"John","surname":"Doe"})
62/// };
63///
64/// let publish2_string = r#"[16,7814135,{},"com.myapp.user.new",["johnny"],{"firstname":"John","surname":"Doe"}]"#;
65///
66/// let publish2 = from_str::<Publish>(publish2_string).unwrap();
67/// assert_eq!(publish, publish2);
68/// ```
69pub struct Publish {
70 pub request_id: u64,
71 pub options: Value,
72 pub topic: String,
73 pub args: Value,
74 pub kwargs: Value,
75}
76
77#[macro_export]
78/// ## Publish Macro - [wamp-proto](https://wamp-proto.org/wamp_latest_ietf.html#name-publish-2)
79/// Publish message builder with thread safe auto-incrementing request-ids.
80/// ### Examples
81/// ```
82/// use wamp_core::publish;
83/// use wamp_core::messages::Publish;
84/// use serde_json::{json, Value};
85///
86/// // Create a Publish message with default values
87/// let publish = publish!("topic");
88///
89/// // Which is the same as creating this:
90/// let publish2 = Publish {
91/// topic: "topic".to_string(),
92/// request_id: 1,
93/// options: json!({}),
94/// args: Value::Null,
95/// kwargs: Value::Null
96/// };
97///
98/// assert_eq!(publish, publish2);
99///
100/// // Some other ways you can construct it using the macro
101///
102/// // Create a publish with custom options but empty args and kwargs
103/// let _ = publish!("topic", json!( { "key": "value" } ));
104///
105/// // Create a publish with custom args or kwargs, but empty options
106/// let _ = publish!("topic", args: json!( [ 1, 2, 3 ] ));
107/// let _ = publish!("topic", kwargs: json!( { "key": "value" } ));
108///
109/// // Create a publish with custom args and kwargs, but empty options
110/// let _ = publish!("topic", args: json!([ 1, 2, 3 ]), kwargs: json!({ "key": "value" }));
111///
112/// // Create a publish with custom options, and either custom args OR custom kwargs
113/// let _ = publish!("topic", json!( { "key": "value" } ), args: json!( [ 1, 2, 3 ] ));
114/// let _ = publish!("topic", json!( { "key": "value" } ), kwargs: json!( { "key": "value" } ));
115///
116/// // Create a publish with custom options, and both custom args and kwargs
117/// // Note that when you use all "required" arguments for the struuct, keyword arguments should not be used for args and kwargs
118/// let _ = publish!("topic", json!({}), json!([]), json!({}));
119/// ```
120macro_rules! publish {
121 ($topic:expr) => {
122 publish! {$topic, serde_json::json!({}), serde_json::Value::Null, serde_json::Value::Null}
123 };
124
125 ($topic:expr, $options:expr) => {
126 publish! {$topic, $options, serde_json::Value::Null, serde_json::Value::Null}
127 };
128
129 ($topic:expr, args: $args:expr) => {
130 publish! {$topic, serde_json::json!({}), $args, serde_json::Value::Null}
131 };
132
133 ($topic:expr, kwargs: $kwargs:expr) => {
134 publish! {$topic, serde_json::json!({}), serde_json::Value::Null, $kwargs}
135 };
136
137 ($topic:expr, args: $args:expr, kwargs: $kwargs:expr) => {
138 publish! {$topic, serde_json::json!({}), $args, $kwargs}
139 };
140
141 ($topic:expr, $options:expr, args: $args:expr) => {
142 publish! {$topic, $options, $args, serde_json::Value::Null}
143 };
144
145 ($topic:expr, $options:expr, kwargs: $kwargs:expr) => {
146 publish! {$topic, $options, serde_json::Value::Null, $kwargs}
147 };
148
149 ($topic:expr, $options:expr, $args:expr, $kwargs:expr) => {{
150 Publish {
151 request_id: $crate::factories::increment(),
152 options: $options,
153 topic: $topic.to_string(),
154 args: $args,
155 kwargs: $kwargs,
156 }
157 }};
158}
159
160impl WampMessage for Publish {
161 const ID: u64 = 16;
162
163 fn direction(role: Roles) -> &'static MessageDirection {
164 match role {
165 Roles::Caller => &MessageDirection {
166 receives: &false,
167 sends: &true,
168 },
169 Roles::Callee => &MessageDirection {
170 receives: &false,
171 sends: &false,
172 },
173 Roles::Publisher => &MessageDirection {
174 receives: &false,
175 sends: &true,
176 },
177 Roles::Subscriber => &MessageDirection {
178 receives: &false,
179 sends: &false,
180 },
181 Roles::Dealer => &MessageDirection {
182 receives: &false,
183 sends: &false,
184 },
185 Roles::Broker => &MessageDirection {
186 receives: &true,
187 sends: &false,
188 },
189 }
190 }
191}
192
193impl Serialize for Publish {
194 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
195 where
196 S: serde::Serializer,
197 {
198 let options =
199 helpers::ser_value_is_object::<S, _>(&self.options, "Options must be object like.")?;
200 let args =
201 helpers::ser_value_is_args::<S, _>(&self.args, "Args must be Array like or Null.")?;
202 let kwargs = helpers::ser_value_is_kwargs::<S, _>(
203 &self.kwargs,
204 "Kwargs must be Object like or Null.",
205 )?;
206 if args.is_null() {
207 if kwargs.is_null() {
208 (Self::ID, &self.request_id, options, &self.topic).serialize(serializer)
209 } else {
210 (
211 Self::ID,
212 &self.request_id,
213 options,
214 &self.topic,
215 json!([]),
216 kwargs,
217 )
218 .serialize(serializer)
219 }
220 } else {
221 if kwargs.is_null() {
222 (Self::ID, &self.request_id, options, &self.topic, args).serialize(serializer)
223 } else {
224 (
225 Self::ID,
226 &self.request_id,
227 options,
228 &self.topic,
229 args,
230 kwargs,
231 )
232 .serialize(serializer)
233 }
234 }
235 }
236}
237
238impl<'de> Deserialize<'de> for Publish {
239 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
240 where
241 D: Deserializer<'de>,
242 {
243 struct PublishVisitor(
244 PhantomData<u8>,
245 PhantomData<u64>,
246 PhantomData<Value>,
247 PhantomData<String>,
248 PhantomData<Value>,
249 PhantomData<Value>,
250 );
251
252 impl<'vi> Visitor<'vi> for PublishVisitor {
253 type Value = Publish;
254 fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
255 formatter.write_str("A sequence of Publish components.")
256 }
257
258 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
259 where
260 A: SeqAccess<'vi>,
261 {
262 let message_id: u64 = helpers::deser_seq_element(
263 &mut seq,
264 "Message ID must be present and type u8.",
265 )?;
266 helpers::validate_id::<Publish, A, _>(&message_id, "Publish")?;
267 let request_id: u64 = helpers::deser_seq_element(
268 &mut seq,
269 "Request ID must be present and type u64.",
270 )?;
271 let options: Value = helpers::deser_seq_element(
272 &mut seq,
273 "Options must be present and object like.",
274 )?;
275 helpers::deser_value_is_object::<A, _>(&options, "Options must be object like.")?;
276 let topic: String =
277 helpers::deser_seq_element(&mut seq, "topic must be present and object like.")?;
278 let args: Value = helpers::deser_args_kwargs_element(
279 &mut seq,
280 "Args must be array like or null.",
281 )?;
282 let kwargs: Value = helpers::deser_args_kwargs_element(
283 &mut seq,
284 "Kwargs must be object like or null.",
285 )?;
286 Ok(Publish {
287 request_id,
288 options,
289 topic,
290 args,
291 kwargs,
292 })
293 }
294 }
295
296 deserializer.deserialize_struct(
297 "Publish",
298 &["request_id", "options", "topic", "args", "kwargs"],
299 PublishVisitor(
300 PhantomData,
301 PhantomData,
302 PhantomData,
303 PhantomData,
304 PhantomData,
305 PhantomData,
306 ),
307 )
308 }
309}