wamp_core/messages/
call.rs

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