ruma_client_api/delayed_events/
delayed_state_event.rs

1//! `PUT /_matrix/client/*/rooms/{roomId}/state/{eventType}/{txnId}`
2//!
3//! Send a delayed state event (a scheduled state event) to a room. [MSC](https://github.com/matrix-org/matrix-spec-proposals/pull/4140)
4
5pub mod unstable {
6    //! `msc4140` ([MSC])
7    //!
8    //! [MSC]: https://github.com/matrix-org/matrix-spec-proposals/pull/4140
9
10    use ruma_common::{
11        api::{auth_scheme::AccessToken, request, response},
12        metadata,
13        serde::Raw,
14        OwnedRoomId,
15    };
16    use ruma_events::{AnyStateEventContent, StateEventContent, StateEventType};
17    use serde_json::value::to_raw_value as to_raw_json_value;
18
19    use crate::delayed_events::DelayParameters;
20
21    metadata! {
22        method: PUT,
23        rate_limited: false,
24        authentication: AccessToken,
25        history: {
26            // We use the unstable prefix for the delay query parameter but the stable v3 endpoint.
27            unstable => "/_matrix/client/v3/rooms/{room_id}/state/{event_type}/{state_key}",
28        }
29    }
30
31    /// Request type for the [`delayed_state_event`](crate::delayed_events::delayed_state_event)
32    /// endpoint.
33    #[request(error = crate::Error)]
34    pub struct Request {
35        /// The room to send the event to.
36        #[ruma_api(path)]
37        pub room_id: OwnedRoomId,
38
39        /// The type of event to send.
40        #[ruma_api(path)]
41        pub event_type: StateEventType,
42
43        /// The state_key for the state to send.
44        #[ruma_api(path)]
45        pub state_key: String,
46
47        /// Additional parameters to describe sending a delayed event.
48        ///
49        /// Only three combinations for `timeout` and `delay_parent_id` are possible.
50        /// The enum [`DelayParameters`] enforces this.
51        #[ruma_api(query_all)]
52        pub delay_parameters: DelayParameters,
53
54        /// The event content to send.
55        #[ruma_api(body)]
56        pub body: Raw<AnyStateEventContent>,
57    }
58
59    /// Response type for the [`delayed_state_event`](crate::delayed_events::delayed_state_event)
60    /// endpoint.
61    #[response(error = crate::Error)]
62    pub struct Response {
63        /// The `delay_id` generated for this delayed event. Used to interact with delayed events.
64        pub delay_id: String,
65    }
66
67    impl Request {
68        /// Creates a new `Request` with the given room id, state_key delay_parameters and
69        /// event content.
70        ///
71        /// # Errors
72        ///
73        /// Since `Request` stores the request body in serialized form, this function can fail if
74        /// `T`s [`::serde::Serialize`] implementation can fail.
75        pub fn new<T>(
76            room_id: OwnedRoomId,
77            state_key: String,
78            delay_parameters: DelayParameters,
79            content: &T,
80        ) -> serde_json::Result<Self>
81        where
82            T: StateEventContent,
83        {
84            Ok(Self {
85                room_id,
86                state_key,
87                event_type: content.event_type(),
88                delay_parameters,
89                body: Raw::from_json(to_raw_json_value(content)?),
90            })
91        }
92
93        /// Creates a new `Request` with the given room id, event type, state key,
94        /// delay parameters and raw event content.
95        pub fn new_raw(
96            room_id: OwnedRoomId,
97            state_key: String,
98            event_type: StateEventType,
99            delay_parameters: DelayParameters,
100            body: Raw<AnyStateEventContent>,
101        ) -> Self {
102            Self { room_id, event_type, state_key, body, delay_parameters }
103        }
104    }
105
106    impl Response {
107        /// Creates a new `Response` with the tokens required to control the delayed event using the
108        /// [`crate::delayed_events::update_delayed_event::unstable::Request`] request.
109        pub fn new(delay_id: String) -> Self {
110            Self { delay_id }
111        }
112    }
113
114    #[cfg(all(test, feature = "client"))]
115    mod tests {
116        use std::borrow::Cow;
117
118        use ruma_common::{
119            api::{
120                auth_scheme::SendAccessToken, MatrixVersion, OutgoingRequest, SupportedVersions,
121            },
122            owned_room_id,
123            serde::Raw,
124        };
125        use serde_json::{json, Value as JsonValue};
126        use web_time::Duration;
127
128        use super::Request;
129        use crate::delayed_events::DelayParameters;
130
131        fn create_delayed_event_request(
132            delay_parameters: DelayParameters,
133        ) -> (http::request::Parts, Vec<u8>) {
134            let supported = SupportedVersions {
135                versions: [MatrixVersion::V1_1].into(),
136                features: Default::default(),
137            };
138
139            Request::new_raw(
140                owned_room_id!("!roomid:example.org"),
141                "@userAsStateKey:example.org".to_owned(),
142                "com.example.custom_state".into(),
143                delay_parameters,
144                Raw::new(&json!({ "key": "value" })).unwrap().cast_unchecked(),
145            )
146            .try_into_http_request(
147                "https://homeserver.tld",
148                SendAccessToken::IfRequired("auth_tok"),
149                Cow::Owned(supported),
150            )
151            .unwrap()
152            .into_parts()
153        }
154
155        #[test]
156        fn serialize_delayed_state_request() {
157            let (parts, body) = create_delayed_event_request(DelayParameters::Timeout {
158                timeout: Duration::from_millis(1_234_321),
159            });
160            assert_eq!(
161                "https://homeserver.tld/_matrix/client/v3/rooms/!roomid:example.org/state/com.example.custom_state/@userAsStateKey:example.org?org.matrix.msc4140.delay=1234321",
162                parts.uri.to_string()
163            );
164            assert_eq!("PUT", parts.method.to_string());
165            assert_eq!(
166                json!({ "key": "value" }),
167                serde_json::from_str::<JsonValue>(std::str::from_utf8(&body).unwrap()).unwrap()
168            );
169        }
170    }
171}