ruma_client_api/delayed_events/
delayed_message_event.rs

1//! `PUT /_matrix/client/*/rooms/{roomId}/send/{eventType}/{txnId}`
2//!
3//! Send a delayed event (a scheduled message) to a room. [MSC4140](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::{request, response, Metadata},
12        metadata,
13        serde::Raw,
14        OwnedRoomId, OwnedTransactionId,
15    };
16    use ruma_events::{AnyMessageLikeEventContent, MessageLikeEventContent, MessageLikeEventType};
17    use serde_json::value::to_raw_value as to_raw_json_value;
18
19    use crate::delayed_events::DelayParameters;
20
21    const METADATA: Metadata = 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/send/:event_type/:txn_id",
28        }
29    };
30    /// Request type for the [`delayed_message_event`](crate::delayed_events::delayed_message_event)
31    /// endpoint.
32    #[request(error = crate::Error)]
33    pub struct Request {
34        /// The room to send the event to.
35        #[ruma_api(path)]
36        pub room_id: OwnedRoomId,
37
38        /// The type of event to send.
39        #[ruma_api(path)]
40        pub event_type: MessageLikeEventType,
41
42        /// The transaction ID for this event.
43        ///
44        /// Clients should generate a unique ID across requests within the
45        /// same session. A session is identified by an access token, and
46        /// persists when the [access token is refreshed].
47        ///
48        /// It will be used by the server to ensure idempotency of requests.
49        ///
50        /// [access token is refreshed]: https://spec.matrix.org/latest/client-server-api/#refreshing-access-tokens
51        #[ruma_api(path)]
52        pub txn_id: OwnedTransactionId,
53
54        /// The timeout duration for this delayed event.
55        #[ruma_api(query_all)]
56        pub delay_parameters: DelayParameters,
57
58        /// The event content to send.
59        #[ruma_api(body)]
60        pub body: Raw<AnyMessageLikeEventContent>,
61    }
62
63    /// Response type for the
64    /// [`delayed_message_event`](crate::delayed_events::delayed_message_event) endpoint.
65    #[response(error = crate::Error)]
66    pub struct Response {
67        /// The `delay_id` generated for this delayed event. Used to interact with delayed events.
68        pub delay_id: String,
69    }
70
71    impl Request {
72        /// Creates a new `Request` with the given room id, transaction id, `delay_parameters` and
73        /// event content.
74        ///
75        /// # Errors
76        ///
77        /// Since `Request` stores the request body in serialized form, this function can fail if
78        /// `T`s [`::serde::Serialize`] implementation can fail.
79        pub fn new<T>(
80            room_id: OwnedRoomId,
81            txn_id: OwnedTransactionId,
82            delay_parameters: DelayParameters,
83            content: &T,
84        ) -> serde_json::Result<Self>
85        where
86            T: MessageLikeEventContent,
87        {
88            Ok(Self {
89                room_id,
90                txn_id,
91                event_type: content.event_type(),
92                delay_parameters,
93                body: Raw::from_json(to_raw_json_value(content)?),
94            })
95        }
96
97        /// Creates a new `Request` with the given room id, transaction id, event type,
98        /// `delay_parameters` and raw event content.
99        pub fn new_raw(
100            room_id: OwnedRoomId,
101            txn_id: OwnedTransactionId,
102            event_type: MessageLikeEventType,
103            delay_parameters: DelayParameters,
104            body: Raw<AnyMessageLikeEventContent>,
105        ) -> Self {
106            Self { room_id, event_type, txn_id, delay_parameters, body }
107        }
108    }
109
110    impl Response {
111        /// Creates a new `Response` with the tokens required to control the delayed event using the
112        /// [`crate::delayed_events::update_delayed_event::unstable::Request`] request.
113        pub fn new(delay_id: String) -> Self {
114            Self { delay_id }
115        }
116    }
117
118    #[cfg(all(test, feature = "client"))]
119    mod tests {
120        use ruma_common::{
121            api::{MatrixVersion, OutgoingRequest, SendAccessToken},
122            owned_room_id,
123        };
124        use ruma_events::room::message::RoomMessageEventContent;
125        use serde_json::{json, Value as JsonValue};
126        use web_time::Duration;
127
128        use super::Request;
129        use crate::delayed_events::delayed_message_event::unstable::DelayParameters;
130
131        #[test]
132        fn serialize_delayed_message_request() {
133            let room_id = owned_room_id!("!roomid:example.org");
134
135            let req = Request::new(
136                room_id,
137                "1234".into(),
138                DelayParameters::Timeout { timeout: Duration::from_millis(103) },
139                &RoomMessageEventContent::text_plain("test"),
140            )
141            .unwrap();
142            let request: http::Request<Vec<u8>> = req
143                .try_into_http_request(
144                    "https://homeserver.tld",
145                    SendAccessToken::IfRequired("auth_tok"),
146                    &[MatrixVersion::V1_1],
147                )
148                .unwrap();
149            let (parts, body) = request.into_parts();
150            assert_eq!(
151                "https://homeserver.tld/_matrix/client/v3/rooms/!roomid:example.org/send/m.room.message/1234?org.matrix.msc4140.delay=103",
152                parts.uri.to_string()
153            );
154            assert_eq!("PUT", parts.method.to_string());
155            assert_eq!(
156                json!({"msgtype":"m.text","body":"test"}),
157                serde_json::from_str::<JsonValue>(std::str::from_utf8(&body).unwrap()).unwrap()
158            );
159        }
160    }
161}