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}