azure_functions/bindings/
signalr_message.rs

1use crate::{
2    rpc::{typed_data::Data, TypedData},
3    FromVec,
4};
5use serde::{Deserialize, Serialize};
6use serde_json::{to_string, to_value, Value};
7
8/// Represents the SignalR message output binding.
9///
10/// The following binding attributes are supported:
11///
12/// | Name         | Description                                                                                                                  |
13/// |--------------|------------------------------------------------------------------------------------------------------------------------------|
14/// | `name`       | The name of the parameter being bound.                                                                                       |
15/// | `hub_name`   | The name of the SignalR hub that will receive the message.                                                                   |
16/// | `connection` | The name of the app setting that contains the SignalR Service connection string. Defaults to `AzureSignalRConnectionString`. |
17///
18/// # Examples
19///
20/// This example implements an HTTP-triggered Azure Function that returns a SignalRMessage binding:
21///
22/// ```rust
23/// use azure_functions::{
24///     bindings::{HttpRequest, SignalRMessage},
25///     func,
26/// };
27/// use serde_json::{to_value, Value};
28///
29/// #[func]
30/// #[binding(name = "req", auth_level = "anonymous", methods = "post")]
31/// #[binding(name = "$return", hub_name = "chat", connection = "myconnection")]
32/// pub fn send_message(req: HttpRequest) -> SignalRMessage {
33///     SignalRMessage {
34///         user_id: req.query_params().get("user").map(|v| v.to_owned()),
35///         group_name: req.query_params().get("group").map(|v| v.to_owned()),
36///         target: "newMessage".to_owned(),
37///         arguments: vec![req.query_params().get("message").map_or(Value::Null, |v| to_value(v).unwrap())],
38///     }
39/// }
40/// ```
41#[derive(Debug, Clone, Serialize, Deserialize)]
42#[serde(rename_all = "camelCase")]
43pub struct SignalRMessage {
44    /// The optional user id to send the message to.
45    pub user_id: Option<String>,
46    /// The optional group name to send the message to.
47    pub group_name: Option<String>,
48    /// The target method name to invoke on each SignalR client.
49    pub target: String,
50    /// The arguments to pass to the target method.
51    pub arguments: Vec<Value>,
52}
53
54#[doc(hidden)]
55impl Into<TypedData> for SignalRMessage {
56    fn into(self) -> TypedData {
57        TypedData {
58            data: Some(Data::Json(
59                to_string(&self).expect("failed to convert SignalR message to JSON string"),
60            )),
61        }
62    }
63}
64
65#[doc(hidden)]
66impl FromVec<SignalRMessage> for TypedData {
67    fn from_vec(vec: Vec<SignalRMessage>) -> Self {
68        TypedData {
69            data: Some(Data::Json(
70                Value::Array(vec.into_iter().map(|m| to_value(m).unwrap()).collect()).to_string(),
71            )),
72        }
73    }
74}
75
76#[cfg(test)]
77mod tests {
78    use super::*;
79    use serde_json::to_value;
80
81    #[test]
82    fn it_serializes_to_json() {
83        let json = to_string(&SignalRMessage {
84            user_id: Some("foo".to_owned()),
85            group_name: Some("bar".to_owned()),
86            target: "baz".to_owned(),
87            arguments: vec![
88                to_value(1).unwrap(),
89                to_value("foo").unwrap(),
90                to_value(false).unwrap(),
91            ],
92        })
93        .unwrap();
94
95        assert_eq!(
96            json,
97            r#"{"userId":"foo","groupName":"bar","target":"baz","arguments":[1,"foo",false]}"#
98        );
99    }
100
101    #[test]
102    fn it_converts_to_typed_data() {
103        let message = SignalRMessage {
104            user_id: Some("foo".to_owned()),
105            group_name: Some("bar".to_owned()),
106            target: "baz".to_owned(),
107            arguments: vec![
108                to_value(1).unwrap(),
109                to_value("foo").unwrap(),
110                to_value(false).unwrap(),
111            ],
112        };
113
114        let data: TypedData = message.into();
115        assert_eq!(
116            data.data,
117            Some(Data::Json(
118                r#"{"userId":"foo","groupName":"bar","target":"baz","arguments":[1,"foo",false]}"#
119                    .to_string()
120            ))
121        );
122    }
123}