Skip to main content

ruma_events/
stream.rs

1//! Types for the `m.stream` namespace ([MSC4471]).
2//!
3//! [MSC4471]: https://github.com/matrix-org/matrix-spec-proposals/pull/4471
4
5use std::time::Duration;
6
7use ruma_common::OwnedDeviceId;
8use serde::{Deserialize, Serialize};
9
10pub mod cancel;
11pub mod subscribe;
12pub mod update;
13
14/// A descriptor advertising that a room event has a live event stream.
15///
16/// See [MSC4471] for the proposal.
17///
18/// [MSC4471]: https://github.com/matrix-org/matrix-spec-proposals/pull/4471
19#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
20#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
21pub struct StreamDescriptor {
22    /// The publisher device, owned by the sender of the room event containing the descriptor.
23    pub device_id: OwnedDeviceId,
24
25    /// The lifetime of the descriptor in milliseconds, counted from the room
26    /// event's `origin_server_ts`.
27    #[serde(
28        with = "ruma_common::serde::duration::opt_ms",
29        default,
30        skip_serializing_if = "Option::is_none"
31    )]
32    pub expiry_ms: Option<Duration>,
33}
34
35impl StreamDescriptor {
36    /// Creates a new `StreamDescriptor` for the given publisher device.
37    pub fn new(device_id: OwnedDeviceId) -> Self {
38        Self { device_id, expiry_ms: None }
39    }
40}
41
42#[cfg(test)]
43mod tests {
44    use std::time::Duration;
45
46    use ruma_common::{canonical_json::assert_to_canonical_json_eq, owned_device_id, serde::Raw};
47    use serde_json::json;
48
49    use super::StreamDescriptor;
50    use crate::room::message::{RoomMessageEventContent, RoomMessageEventContentWithoutRelation};
51
52    #[test]
53    fn descriptor_round_trips_inside_room_message() {
54        let mut content = RoomMessageEventContent::text_plain("Hello");
55        content.stream = Some(StreamDescriptor {
56            device_id: owned_device_id!("DEVICEID"),
57            expiry_ms: Some(Duration::from_millis(1_800_000)),
58        });
59
60        assert_to_canonical_json_eq!(
61            content,
62            json!({
63                "msgtype": "m.text",
64                "body": "Hello",
65                "org.matrix.msc4471.stream": {
66                    "device_id": "DEVICEID",
67                    "expiry_ms": 1_800_000,
68                },
69            })
70        );
71
72        let raw = Raw::new(&content).unwrap();
73        let deserialized: RoomMessageEventContent = raw.deserialize().unwrap();
74        let stream = deserialized.stream.unwrap();
75        assert_eq!(stream.device_id, "DEVICEID");
76        assert_eq!(stream.expiry_ms, Some(Duration::from_millis(1_800_000)));
77    }
78
79    #[test]
80    fn replacement_drops_stream() {
81        let mut content = RoomMessageEventContent::text_plain("Hello");
82        content.stream = Some(StreamDescriptor::new(owned_device_id!("DEVICEID")));
83
84        content.apply_replacement(RoomMessageEventContentWithoutRelation::text_plain("Done"));
85
86        assert!(content.stream.is_none());
87        assert_to_canonical_json_eq!(
88            content,
89            json!({
90                "msgtype": "m.text",
91                "body": "Done",
92            })
93        );
94    }
95
96    #[test]
97    fn replacement_keeps_stream() {
98        let mut content = RoomMessageEventContent::text_plain("Hello");
99        content.stream = Some(StreamDescriptor::new(owned_device_id!("DEVICEONE")));
100
101        let mut new_content = RoomMessageEventContentWithoutRelation::text_plain("world");
102        new_content.stream = Some(StreamDescriptor::new(owned_device_id!("DEVICETWO")));
103        content.apply_replacement(new_content);
104
105        let stream = content.stream.as_ref().unwrap();
106        assert_eq!(stream.device_id, "DEVICETWO");
107        assert_to_canonical_json_eq!(
108            content,
109            json!({
110                "msgtype": "m.text",
111                "body": "world",
112                "org.matrix.msc4471.stream": {
113                    "device_id": "DEVICETWO",
114                },
115            })
116        );
117    }
118}