wot_td/protocol/
mqtt.rs

1//! MQTT Binding Template
2
3use alloc::{string::String, vec::Vec};
4
5use crate::extend::ExtendableThing;
6use serde::{Deserialize, Serialize};
7use serde_with::{serde_as, skip_serializing_none, OneOrMany};
8
9/// MQTT Control Packet
10#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, Hash)]
11pub enum ControlPacket {
12    #[serde(rename = "mqv:publish")]
13    Publish,
14    #[serde(rename = "mqv:subscribe")]
15    Subscribe,
16    #[serde(rename = "mqv:unsubscribe")]
17    Unsubscribe,
18}
19
20/// MQTT Quality of service
21#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, Hash)]
22pub enum QoS {
23    #[serde(rename = "quality:0")]
24    AtMostOnce,
25    #[serde(rename = "quality:1")]
26    AtLeastOnce,
27    #[serde(rename = "quality:2")]
28    ExactlyOnce,
29}
30
31/// Extended fields the Form
32#[serde_as]
33#[skip_serializing_none]
34#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, Hash, Default)]
35pub struct Form {
36    #[serde(
37        rename = "mqv:retain",
38        skip_serializing_if = "core::ops::Not::not",
39        default
40    )]
41    pub retain: bool,
42    #[serde(rename = "mqv:controlPacket")]
43    pub control_packet: Option<ControlPacket>,
44    #[serde(rename = "mqv:qos")]
45    pub qos: Option<QoS>,
46    #[serde(rename = "mqv:topic")]
47    pub topic: Option<String>,
48    #[serde(rename = "mqv:filter", skip_serializing_if = "Vec::is_empty", default)]
49    #[serde_as(as = "OneOrMany<_>")]
50    pub filter: Vec<String>,
51}
52
53/// MQTT Protocol extension
54#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash, Default)]
55pub struct MqttProtocol {}
56
57impl ExtendableThing for MqttProtocol {
58    type InteractionAffordance = ();
59    type PropertyAffordance = ();
60    type ActionAffordance = ();
61    type EventAffordance = ();
62    type Form = Form;
63    type ExpectedResponse = ();
64    type DataSchema = ();
65    type ObjectSchema = ();
66    type ArraySchema = ();
67}
68
69#[cfg(test)]
70mod test {
71    use alloc::vec;
72
73    use super::MqttProtocol;
74    use crate::thing::Form;
75    use crate::thing::{DefaultedFormOperations::Custom, FormOperation::*};
76
77    fn deserialize_form(s: &str, r: Form<MqttProtocol>) {
78        let f: crate::thing::Form<MqttProtocol> = serde_json::from_str(s).unwrap();
79        assert_eq!(f, r);
80    }
81
82    #[test]
83    fn simple_filter() {
84        let s = r#"{
85            "href": "mqtt://broker.com:1883",
86            "op": [
87                "subscribeevent",
88                "unsubscribeevent"
89            ],
90            "mqv:filter": "thing1/events/overheating"
91        }"#;
92
93        let expected = Form {
94            op: Custom(vec![SubscribeEvent, UnsubscribeEvent]),
95            href: "mqtt://broker.com:1883".into(),
96            other: super::Form {
97                filter: vec!["thing1/events/overheating".into()],
98                ..Default::default()
99            },
100            ..Default::default()
101        };
102
103        deserialize_form(s, expected);
104    }
105
106    #[test]
107    fn complex_filter() {
108        let s = r#"{
109            "href": "mqtt://broker.com:1883",
110            "op": [
111                "readproperty",
112                "observeproperty"
113            ],
114            "mqv:qos": "quality:1",
115            "mqv:retain" : true,
116            "mqv:filter": "application/devices/thing1/properties/test"
117        }"#;
118
119        let expected = Form {
120            op: Custom(vec![ReadProperty, ObserveProperty]),
121            href: "mqtt://broker.com:1883".into(),
122            other: super::Form {
123                qos: Some(super::QoS::AtLeastOnce),
124                retain: true,
125                filter: vec!["application/devices/thing1/properties/test".into()],
126                ..Default::default()
127            },
128            ..Default::default()
129        };
130
131        deserialize_form(s, expected);
132    }
133}