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