events: update future endpoints and rename future to delay

To match the latest version of the MSC
This commit is contained in:
Timo 2024-07-29 16:38:38 +02:00 committed by GitHub
parent 14d7415f0d
commit 878d2b287b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 330 additions and 310 deletions

View File

@ -0,0 +1,37 @@
//! Endpoints for sending and interacting with delayed events.
pub mod delayed_message_event;
pub mod delayed_state_event;
pub mod update_delayed_event;
use serde::{Deserialize, Serialize};
use web_time::Duration;
/// The query parameters for a delayed event request.
/// It contains the `timeout` configuration for a delayed event.
///
/// ### Note:
///
/// This is an Enum since the following properties might be added:
///
/// The **Timeout** case might get an additional optional `delay_parent_id` property.
/// The optional parent id is used to create a secondary timeout.
/// In a delay group with two timeouts only one of them will ever be sent.
///
/// The **Action** case might be added:
/// Adds an additional action to a delay event without a timeout but requires a `delay_id` (of the
/// parent delay event). A possible matrix event that can be send as an alternative to the parent
/// delay.
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(untagged)]
pub enum DelayParameters {
/// Sending a delayed event with a timeout. The response will contain a (server
/// generated) `delay_id` instead of an `event_id`.
Timeout {
/// The timeout duration for this delayed event.
#[serde(with = "ruma_common::serde::duration::ms")]
#[serde(rename = "org.matrix.msc4140.delay")]
timeout: Duration,
},
}

View File

@ -1,6 +1,6 @@
//! `PUT /_matrix/client/*/rooms/{roomId}/send_future/{eventType}/{txnId}`
//! `PUT /_matrix/client/*/rooms/{roomId}/send/{eventType}/{txnId}`
//!
//! Send a future (a scheduled message) to a room. [MSC4140](https://github.com/matrix-org/matrix-spec-proposals/pull/4140)
//! Send a delayed event (a scheduled message) to a room. [MSC4140](https://github.com/matrix-org/matrix-spec-proposals/pull/4140)
pub mod unstable {
//! `msc4140` ([MSC])
@ -16,17 +16,18 @@ pub mod unstable {
use ruma_events::{AnyMessageLikeEventContent, MessageLikeEventContent, MessageLikeEventType};
use serde_json::value::to_raw_value as to_raw_json_value;
use crate::future::FutureParameters;
use crate::delayed_events::DelayParameters;
const METADATA: Metadata = metadata! {
method: PUT,
rate_limited: false,
authentication: AccessToken,
history: {
unstable => "/_matrix/client/unstable/org.matrix.msc4140/rooms/:room_id/send_future/:event_type/:txn_id",
// We use the unstable prefix for the delay query parameter but the stable v3 endpoint.
unstable => "/_matrix/client/v3/rooms/:room_id/send/:event_type/:txn_id",
}
};
/// Request type for the [`send_future_message_event`](crate::future::send_future_message_event)
/// Request type for the [`delayed_message_event`](crate::delayed_events::delayed_message_event)
/// endpoint.
#[request(error = crate::Error)]
pub struct Request {
@ -50,12 +51,9 @@ pub mod unstable {
#[ruma_api(path)]
pub txn_id: OwnedTransactionId,
/// Additional parameters to describe sending a future.
///
/// Only three combinations for `future_timeout` and `future_group_id` are possible.
/// The enum [`FutureParameters`] enforces this.
/// The timeout duration for this delayed event.
#[ruma_api(query_all)]
pub future_parameters: FutureParameters,
pub delay_parameters: DelayParameters,
/// The event content to send.
#[ruma_api(body)]
@ -63,26 +61,15 @@ pub mod unstable {
}
/// Response type for the
/// [`send_future_message_event`](crate::future::send_future_message_event) endpoint.
/// [`delayed_message_event`](crate::delayed_events::delayed_message_event) endpoint.
#[response(error = crate::Error)]
pub struct Response {
/// A token to send/insert the future into the DAG.
pub send_token: String,
/// A token to cancel this future. It will never be send if this is called.
pub cancel_token: String,
/// The `future_group_id` generated for this future. Used to connect multiple futures
/// only one of the connected futures will be sent and inserted into the DAG.
pub future_group_id: String,
/// A token used to refresh the timer of the future. This allows
/// to implement heartbeat like capabilities. An event is only sent once
/// a refresh in the timeout interval is missed.
///
/// If the future does not have a timeout this will be `None`.
pub refresh_token: Option<String>,
/// The `delay_id` generated for this delayed event. Used to interact with delayed events.
pub delay_id: String,
}
impl Request {
/// Creates a new `Request` with the given room id, transaction id future_parameters and
/// Creates a new `Request` with the given room id, transaction id, `delay_parameters` and
/// event content.
///
/// # Errors
@ -92,7 +79,7 @@ pub mod unstable {
pub fn new<T>(
room_id: OwnedRoomId,
txn_id: OwnedTransactionId,
future_parameters: FutureParameters,
delay_parameters: DelayParameters,
content: &T,
) -> serde_json::Result<Self>
where
@ -102,34 +89,29 @@ pub mod unstable {
room_id,
txn_id,
event_type: content.event_type(),
future_parameters,
delay_parameters,
body: Raw::from_json(to_raw_json_value(content)?),
})
}
/// Creates a new `Request` with the given room id, transaction id, event type,
/// future parameters and raw event content.
/// `delay_parameters` and raw event content.
pub fn new_raw(
room_id: OwnedRoomId,
txn_id: OwnedTransactionId,
event_type: MessageLikeEventType,
future_parameters: FutureParameters,
delay_parameters: DelayParameters,
body: Raw<AnyMessageLikeEventContent>,
) -> Self {
Self { room_id, event_type, txn_id, future_parameters, body }
Self { room_id, event_type, txn_id, delay_parameters, body }
}
}
impl Response {
/// Creates a new `Response` with the tokens required to control the future using the
/// [`crate::future::update_future::unstable::Request`] request.
pub fn new(
send_token: String,
cancel_token: String,
future_group_id: String,
refresh_token: Option<String>,
) -> Self {
Self { send_token, cancel_token, future_group_id, refresh_token }
/// Creates a new `Response` with the tokens required to control the delayed event using the
/// [`crate::delayed_events::update_delayed_event::unstable::Request`] request.
pub fn new(delay_id: String) -> Self {
Self { delay_id }
}
}
@ -144,19 +126,16 @@ pub mod unstable {
use web_time::Duration;
use super::Request;
use crate::future::send_future_message_event::unstable::FutureParameters;
use crate::delayed_events::delayed_message_event::unstable::DelayParameters;
#[test]
fn serialize_message_future_request() {
fn serialize_delayed_message_request() {
let room_id = owned_room_id!("!roomid:example.org");
let req = Request::new(
room_id,
"1234".into(),
FutureParameters::Timeout {
timeout: Duration::from_millis(103),
group_id: Some("testId".to_owned()),
},
DelayParameters::Timeout { timeout: Duration::from_millis(103) },
&RoomMessageEventContent::text_plain("test"),
)
.unwrap();
@ -169,7 +148,7 @@ pub mod unstable {
.unwrap();
let (parts, body) = request.into_parts();
assert_eq!(
"https://homeserver.tld/_matrix/client/unstable/org.matrix.msc4140/rooms/!roomid:example.org/send_future/m.room.message/1234?future_timeout=103&future_group_id=testId",
"https://homeserver.tld/_matrix/client/v3/rooms/!roomid:example.org/send/m.room.message/1234?org.matrix.msc4140.delay=103",
parts.uri.to_string()
);
assert_eq!("PUT", parts.method.to_string());

View File

@ -0,0 +1,162 @@
//! `PUT /_matrix/client/*/rooms/{roomId}/state/{eventType}/{txnId}`
//!
//! Send a delayed state event (a scheduled state event) to a room. [MSC](https://github.com/matrix-org/matrix-spec-proposals/pull/4140)
pub mod unstable {
//! `msc4140` ([MSC])
//!
//! [MSC]: https://github.com/matrix-org/matrix-spec-proposals/pull/4140
use ruma_common::{
api::{request, response, Metadata},
metadata,
serde::Raw,
OwnedRoomId,
};
use ruma_events::{AnyStateEventContent, StateEventContent, StateEventType};
use serde_json::value::to_raw_value as to_raw_json_value;
use crate::delayed_events::DelayParameters;
const METADATA: Metadata = metadata! {
method: PUT,
rate_limited: false,
authentication: AccessToken,
history: {
// We use the unstable prefix for the delay query parameter but the stable v3 endpoint.
unstable => "/_matrix/client/v3/rooms/:room_id/state/:event_type/:state_key",
}
};
/// Request type for the [`delayed_state_event`](crate::delayed_events::delayed_state_event)
/// endpoint.
#[request(error = crate::Error)]
pub struct Request {
/// The room to send the event to.
#[ruma_api(path)]
pub room_id: OwnedRoomId,
/// The type of event to send.
#[ruma_api(path)]
pub event_type: StateEventType,
/// The state_key for the state to send.
#[ruma_api(path)]
pub state_key: String,
/// Additional parameters to describe sending a delayed event.
///
/// Only three combinations for `timeout` and `delay_parent_id` are possible.
/// The enum [`DelayParameters`] enforces this.
#[ruma_api(query_all)]
pub delay_parameters: DelayParameters,
/// The event content to send.
#[ruma_api(body)]
pub body: Raw<AnyStateEventContent>,
}
/// Response type for the [`delayed_state_event`](crate::delayed_events::delayed_state_event)
/// endpoint.
#[response(error = crate::Error)]
pub struct Response {
/// The `delay_id` generated for this delayed event. Used to interact with delayed events.
pub delay_id: String,
}
impl Request {
/// Creates a new `Request` with the given room id, state_key delay_parameters and
/// event content.
///
/// # Errors
///
/// Since `Request` stores the request body in serialized form, this function can fail if
/// `T`s [`::serde::Serialize`] implementation can fail.
pub fn new<T>(
room_id: OwnedRoomId,
state_key: String,
delay_parameters: DelayParameters,
content: &T,
) -> serde_json::Result<Self>
where
T: StateEventContent,
{
Ok(Self {
room_id,
state_key,
event_type: content.event_type(),
delay_parameters,
body: Raw::from_json(to_raw_json_value(content)?),
})
}
/// Creates a new `Request` with the given room id, event type, state key,
/// delay parameters and raw event content.
pub fn new_raw(
room_id: OwnedRoomId,
state_key: String,
event_type: StateEventType,
delay_parameters: DelayParameters,
body: Raw<AnyStateEventContent>,
) -> Self {
Self { room_id, event_type, state_key, body, delay_parameters }
}
}
impl Response {
/// Creates a new `Response` with the tokens required to control the delayed event using the
/// [`crate::delayed_events::update_delayed_event::unstable::Request`] request.
pub fn new(delay_id: String) -> Self {
Self { delay_id }
}
}
#[cfg(all(test, feature = "client"))]
mod tests {
use ruma_common::{
api::{MatrixVersion, OutgoingRequest, SendAccessToken},
owned_room_id,
};
use ruma_events::room::topic::RoomTopicEventContent;
use serde_json::{json, Value as JsonValue};
use web_time::Duration;
use super::Request;
use crate::delayed_events::DelayParameters;
fn create_delayed_event_request(
delay_parameters: DelayParameters,
) -> (http::request::Parts, Vec<u8>) {
Request::new(
owned_room_id!("!roomid:example.org"),
"@userAsStateKey:example.org".to_owned(),
delay_parameters,
&RoomTopicEventContent::new("my_topic".to_owned()),
)
.unwrap()
.try_into_http_request(
"https://homeserver.tld",
SendAccessToken::IfRequired("auth_tok"),
&[MatrixVersion::V1_1],
)
.unwrap()
.into_parts()
}
#[test]
fn serialize_delayed_state_request() {
let (parts, body) = create_delayed_event_request(DelayParameters::Timeout {
timeout: Duration::from_millis(1_234_321),
});
assert_eq!(
"https://homeserver.tld/_matrix/client/v3/rooms/!roomid:example.org/state/m.room.topic/@userAsStateKey:example.org?org.matrix.msc4140.delay=1234321",
parts.uri.to_string()
);
assert_eq!("PUT", parts.method.to_string());
assert_eq!(
json!({"topic": "my_topic"}),
serde_json::from_str::<JsonValue>(std::str::from_utf8(&body).unwrap()).unwrap()
);
}
}
}

View File

@ -0,0 +1,104 @@
//! `POST /_matrix/client/*/delayed_events/{delayed_id}`
//!
//! Send a delayed event update. This can be a updateing/canceling/sending the associated delayed
//! event.
pub mod unstable {
//! `msc3814` ([MSC])
//!
//! [MSC]: https://github.com/matrix-org/matrix-spec-proposals/pull/4140
use ruma_common::{
api::{request, response, Metadata},
metadata,
serde::StringEnum,
};
use crate::PrivOwnedStr;
const METADATA: Metadata = metadata! {
method: POST,
rate_limited: true,
authentication: AccessToken,
history: {
unstable => "/_matrix/client/unstable/org.matrix.msc4140/delayed_events/:delay_id",
}
};
/// The possible update actions we can do for updating a delayed event.
#[derive(Clone, StringEnum)]
#[ruma_enum(rename_all = "lowercase")]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub enum UpdateAction {
/// Restart the delayed event timeout. (heartbeat ping)
Restart,
/// Send the delayed event immediately independent of the timeout state. (deletes all
/// timers)
Send,
/// Delete the delayed event and never send it. (deletes all timers)
Cancel,
#[doc(hidden)]
_Custom(PrivOwnedStr),
}
/// Request type for the [`update_delayed_event`](crate::delayed_events::update_delayed_event)
/// endpoint.
#[request(error = crate::Error)]
pub struct Request {
/// The delay id that we want to update.
#[ruma_api(path)]
pub delay_id: String,
/// Which kind of update we want to request for the delayed event.
pub action: UpdateAction,
}
impl Request {
/// Creates a new `Request` to update a delayed event.
pub fn new(delay_id: String, action: UpdateAction) -> Self {
Self { delay_id, action }
}
}
/// Response type for the [`update_delayed_event`](crate::delayed_events::update_delayed_event)
/// endpoint.
#[response(error = crate::Error)]
pub struct Response {}
impl Response {
/// Creates a new empty response for the
/// [`update_delayed_event`](crate::delayed_events::update_delayed_event) endpoint.
pub fn new() -> Self {
Self {}
}
}
#[cfg(all(test, feature = "client"))]
mod tests {
use ruma_common::api::{MatrixVersion, OutgoingRequest, SendAccessToken};
use serde_json::{json, Value as JsonValue};
use super::{Request, UpdateAction};
#[test]
fn serialize_update_delayed_event_request() {
let request: http::Request<Vec<u8>> =
Request::new("1234".to_owned(), UpdateAction::Cancel)
.try_into_http_request(
"https://homeserver.tld",
SendAccessToken::IfRequired("auth_tok"),
&[MatrixVersion::V1_1],
)
.unwrap();
let (parts, body) = request.into_parts();
assert_eq!(
"https://homeserver.tld/_matrix/client/unstable/org.matrix.msc4140/delayed_events/1234",
parts.uri.to_string()
);
assert_eq!("POST", parts.method.to_string());
assert_eq!(
json!({"action": "cancel"}),
serde_json::from_str::<JsonValue>(std::str::from_utf8(&body).unwrap()).unwrap()
);
}
}
}

View File

@ -1,38 +0,0 @@
//! Endpoints for sending and receiving futures
pub mod send_future_message_event;
pub mod send_future_state_event;
pub mod update_future;
use serde::{Deserialize, Serialize};
use web_time::Duration;
/// The query parameters for a future request.
/// It can contain the possible timeout and the future_group_id combinations.
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(untagged)]
pub enum FutureParameters {
/// Only sending the timeout creates a timeout future with a new (server generated)
/// group id. The optional group id is used to create a secondary timeout.
/// In a future group with two timeouts only one of them will ever be sent.
Timeout {
/// The timeout duration for this Future.
#[serde(with = "ruma_common::serde::duration::ms")]
#[serde(rename = "future_timeout")]
timeout: Duration,
/// The associated group for this Future.
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "future_group_id")]
group_id: Option<String>,
},
/// Adds an additional action to a future without a timeout but requires a future group_id.
/// A possible matrix event that this future group can resolve to. It can be sent by using the
/// send_token as an alternative to the timeout future of an already existing group.
Action {
/// The associated group for this Future.
#[serde(rename = "future_group_id")]
group_id: String,
},
}

View File

@ -1,175 +0,0 @@
//! `PUT /_matrix/client/*/rooms/{roomId}/state_future/{eventType}/{txnId}`
//!
//! Send a future state (a scheduled state event) to a room. [MSC](https://github.com/matrix-org/matrix-spec-proposals/pull/4140)
pub mod unstable {
//! `msc4140` ([MSC])
//!
//! [MSC]: https://github.com/matrix-org/matrix-spec-proposals/pull/4140
use ruma_common::{
api::{request, response, Metadata},
metadata,
serde::Raw,
OwnedRoomId,
};
use ruma_events::{AnyStateEventContent, StateEventContent, StateEventType};
use serde_json::value::to_raw_value as to_raw_json_value;
use crate::future::FutureParameters;
const METADATA: Metadata = metadata! {
method: PUT,
rate_limited: false,
authentication: AccessToken,
history: {
unstable => "/_matrix/client/unstable/org.matrix.msc4140/rooms/:room_id/state_future/:event_type/:state_key",
}
};
/// Request type for the [`send_future_state_event`](crate::future::send_future_state_event)
/// endpoint.
#[request(error = crate::Error)]
pub struct Request {
/// The room to send the event to.
#[ruma_api(path)]
pub room_id: OwnedRoomId,
/// The type of event to send.
#[ruma_api(path)]
pub event_type: StateEventType,
/// The state_key for the state to send.
#[ruma_api(path)]
pub state_key: String,
/// Additional parameters to describe sending a future.
///
/// Only three combinations for `future_timeout` and `future_group_id` are possible.
/// The enum [`FutureParameters`] enforces this.
#[ruma_api(query_all)]
pub future_parameters: FutureParameters,
/// The event content to send.
#[ruma_api(body)]
pub body: Raw<AnyStateEventContent>,
}
/// Response type for the [`send_future_state_event`](crate::future::send_future_state_event)
/// endpoint.
#[response(error = crate::Error)]
pub struct Response {
/// A token to send/insert the future into the DAG.
pub send_token: String,
/// A token to cancel this future. It will never be send if this is called.
pub cancel_token: String,
/// The `future_group_id` generated for this future. Used to connect multiple futures
/// only one of the connected futures will be sent and inserted into the DAG.
pub future_group_id: String,
/// A token used to refresh the timer of the future. This allows
/// to implement heardbeat like capabilities. An event is only send once
/// a refresh in the timeout interval is missed.
///
/// If the future does not have a timeout this will be `None`.
pub refresh_token: Option<String>,
}
impl Request {
/// Creates a new `Request` with the given room id, state_key future_parameters and
/// event content.
///
/// # Errors
///
/// Since `Request` stores the request body in serialized form, this function can fail if
/// `T`s [`::serde::Serialize`] implementation can fail.
pub fn new<T>(
room_id: OwnedRoomId,
state_key: String,
future_parameters: FutureParameters,
content: &T,
) -> serde_json::Result<Self>
where
T: StateEventContent,
{
Ok(Self {
room_id,
state_key,
event_type: content.event_type(),
future_parameters,
body: Raw::from_json(to_raw_json_value(content)?),
})
}
/// Creates a new `Request` with the given room id, event type, state key,
/// future parameters and raw event content.
pub fn new_raw(
room_id: OwnedRoomId,
state_key: String,
event_type: StateEventType,
future_parameters: FutureParameters,
body: Raw<AnyStateEventContent>,
) -> Self {
Self { room_id, event_type, state_key, body, future_parameters }
}
}
impl Response {
/// Creates a new `Response` with the tokens required to control the future using the
/// [`crate::future::update_future::unstable::Request`] request.
pub fn new(
send_token: String,
cancel_token: String,
future_group_id: String,
refresh_token: Option<String>,
) -> Self {
Self { send_token, cancel_token, future_group_id, refresh_token }
}
}
#[cfg(all(test, feature = "client"))]
mod tests {
use ruma_common::{
api::{MatrixVersion, OutgoingRequest, SendAccessToken},
owned_room_id,
};
use ruma_events::room::topic::RoomTopicEventContent;
use serde_json::{json, Value as JsonValue};
use web_time::Duration;
use super::Request;
use crate::future::FutureParameters;
#[test]
fn serialize_state_future_request() {
let room_id = owned_room_id!("!roomid:example.org");
let req = Request::new(
room_id,
"@userAsStateKey:example.org".to_owned(),
FutureParameters::Timeout {
timeout: Duration::from_millis(1_234_321),
group_id: Some("abs1abs1abs1abs1".to_owned()),
},
&RoomTopicEventContent::new("my_topic".to_owned()),
)
.unwrap();
let request: http::Request<Vec<u8>> = req
.try_into_http_request(
"https://homeserver.tld",
SendAccessToken::IfRequired("auth_tok"),
&[MatrixVersion::V1_1],
)
.unwrap();
let (parts, body) = request.into_parts();
assert_eq!(
"https://homeserver.tld/_matrix/client/unstable/org.matrix.msc4140/rooms/!roomid:example.org/state_future/m.room.topic/@userAsStateKey:example.org?future_timeout=1234321&future_group_id=abs1abs1abs1abs1",
parts.uri.to_string()
);
assert_eq!("PUT", parts.method.to_string());
assert_eq!(
json!({"topic": "my_topic"}),
serde_json::from_str::<JsonValue>(std::str::from_utf8(&body).unwrap()).unwrap()
);
}
}
}

View File

@ -1,49 +0,0 @@
//! `POST /_matrix/client/*/futures/{token}`
//!
//! Send a future token to update/cancel/send the associated future event.
pub mod unstable {
//! `msc3814` ([MSC])
//!
//! [MSC]: https://github.com/matrix-org/matrix-spec-proposals/pull/4140
use ruma_common::{
api::{request, response, Metadata},
metadata,
};
const METADATA: Metadata = metadata! {
method: POST,
rate_limited: true,
authentication: None,
history: {
unstable => "/_matrix/client/unstable/org.matrix.msc4140/future/:token",
}
};
/// Request type for the [`update_future`](crate::future::update_future) endpoint.
#[request(error = crate::Error)]
pub struct Request {
/// The token.
#[ruma_api(path)]
pub token: String,
}
impl Request {
/// Creates a new `Request` to update a future. This is an unauthenticated request and only
/// requires the future token.
pub fn new(token: String) -> serde_json::Result<Self> {
Ok(Self { token })
}
}
/// Response type for the [`update_future`](crate::future::update_future) endpoint.
#[response(error = crate::Error)]
pub struct Response {}
impl Response {
/// Creates a new response for the [`update_future`](crate::future::update_future) endpoint.
pub fn new() -> Self {
Response {}
}
}
}

View File

@ -18,13 +18,13 @@ pub mod config;
pub mod context;
#[cfg(feature = "unstable-msc3814")]
pub mod dehydrated_device;
#[cfg(feature = "unstable-msc4140")]
pub mod delayed_events;
pub mod device;
pub mod directory;
pub mod discovery;
pub mod error;
pub mod filter;
#[cfg(feature = "unstable-msc4140")]
pub mod future;
pub mod http_headers;
pub mod keys;
pub mod knock;