Skip to main content

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