Skip to main content

ruma_events/stream/
subscribe.rs

1//! Types for the `m.stream.subscribe` to-device event ([MSC4471]).
2//!
3//! [MSC4471]: https://github.com/matrix-org/matrix-spec-proposals/pull/4471
4
5use ruma_common::{OwnedDeviceId, OwnedEventId, OwnedRoomId};
6use ruma_macros::EventContent;
7use serde::{Deserialize, Serialize};
8
9/// The content of a to-device `m.stream.subscribe` event.
10///
11/// Sent by a subscriber device to the publisher device named in a stream descriptor.
12#[derive(Clone, Debug, Deserialize, Serialize, EventContent)]
13#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
14#[ruma_event(
15    type = "org.matrix.msc4471.stream.subscribe",
16    alias = "m.stream.subscribe",
17    kind = ToDevice,
18)]
19pub struct ToDeviceStreamSubscribeEventContent {
20    /// The room containing the stream descriptor.
21    pub room_id: OwnedRoomId,
22
23    /// The event containing the stream descriptor.
24    pub event_id: OwnedEventId,
25
26    /// The subscriber device which should receive updates.
27    ///
28    /// The device must belong to the subscribing user; the publisher verifies
29    /// this before accepting the subscription.
30    pub subscriber_device_id: OwnedDeviceId,
31
32    /// If `true`, request a fresh `replace` operation rather than continuing from the current
33    /// state.
34    #[serde(default, skip_serializing_if = "ruma_common::serde::is_default")]
35    pub resync: bool,
36}
37
38impl ToDeviceStreamSubscribeEventContent {
39    /// Creates a new `ToDeviceStreamSubscribeEventContent` with the given
40    /// room, event, and subscriber device.
41    pub fn new(
42        room_id: OwnedRoomId,
43        event_id: OwnedEventId,
44        subscriber_device_id: OwnedDeviceId,
45    ) -> Self {
46        Self { room_id, event_id, subscriber_device_id, resync: false }
47    }
48}
49
50#[cfg(test)]
51mod tests {
52    use assert_matches2::assert_matches;
53    use ruma_common::{
54        canonical_json::assert_to_canonical_json_eq, owned_device_id, owned_event_id,
55        owned_room_id, serde::Raw,
56    };
57    use serde_json::{from_value as from_json_value, json};
58
59    use super::ToDeviceStreamSubscribeEventContent;
60    use crate::{AnyToDeviceEvent, ToDeviceEvent};
61
62    #[test]
63    fn subscribe_round_trip() {
64        let mut content = ToDeviceStreamSubscribeEventContent::new(
65            owned_room_id!("!room:example.org"),
66            owned_event_id!("$event:example.org"),
67            owned_device_id!("SUBSCRIBERDEVICE"),
68        );
69        content.resync = true;
70
71        assert_to_canonical_json_eq!(
72            content,
73            json!({
74                "room_id": "!room:example.org",
75                "event_id": "$event:example.org",
76                "subscriber_device_id": "SUBSCRIBERDEVICE",
77                "resync": true,
78            })
79        );
80
81        let deserialized: ToDeviceStreamSubscribeEventContent =
82            Raw::new(&content).unwrap().deserialize().unwrap();
83        assert_eq!(deserialized.subscriber_device_id, "SUBSCRIBERDEVICE");
84        assert!(deserialized.resync);
85    }
86
87    #[test]
88    fn subscribe_resync_default() {
89        let content = ToDeviceStreamSubscribeEventContent::new(
90            owned_room_id!("!room:example.org"),
91            owned_event_id!("$event:example.org"),
92            owned_device_id!("SUBSCRIBERDEVICE"),
93        );
94
95        assert_to_canonical_json_eq!(
96            content,
97            json!({
98                "room_id": "!room:example.org",
99                "event_id": "$event:example.org",
100                "subscriber_device_id": "SUBSCRIBERDEVICE",
101            })
102        );
103    }
104
105    #[test]
106    fn subscribe_resync_default_deserializes_false() {
107        let json = json!({
108            "room_id": "!room:example.org",
109            "event_id": "$event:example.org",
110            "subscriber_device_id": "SUBSCRIBERDEVICE",
111        });
112
113        let content = from_json_value::<ToDeviceStreamSubscribeEventContent>(json).unwrap();
114        assert!(!content.resync);
115    }
116
117    #[test]
118    fn any_to_device_subscribe() {
119        let event = json!({
120            "sender": "@alice:example.org",
121            "type": "org.matrix.msc4471.stream.subscribe",
122            "content": {
123                "room_id": "!room:example.org",
124                "event_id": "$event:example.org",
125                "subscriber_device_id": "SUBSCRIBERDEVICE",
126            },
127        });
128
129        let event = from_json_value::<AnyToDeviceEvent>(event).unwrap();
130        assert_matches!(event, AnyToDeviceEvent::StreamSubscribe(ToDeviceEvent { content, .. }));
131        assert!(!content.resync);
132    }
133
134    #[test]
135    fn any_to_device_subscribe_stable_alias() {
136        let event = json!({
137            "sender": "@alice:example.org",
138            "type": "m.stream.subscribe",
139            "content": {
140                "room_id": "!room:example.org",
141                "event_id": "$event:example.org",
142                "subscriber_device_id": "SUBSCRIBERDEVICE",
143            },
144        });
145
146        let event = from_json_value::<AnyToDeviceEvent>(event).unwrap();
147        assert_matches!(event, AnyToDeviceEvent::StreamSubscribe(ToDeviceEvent { content, .. }));
148        assert!(!content.resync);
149    }
150}