Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ once_cell = "1.16.0"
pin-project-lite = "0.2.9"
rand = "0.8.5"
reqwest = { version = "0.12.4", default-features = false }
ruma = { git = "https://github.com/ruma/ruma", rev = "e5a370f7e5fcebb0da6e4945e51c5fafba9aa5f0", features = [
ruma = { git = "https://github.com/ruma/ruma", rev = "c37843e9be619ffac8c4d33ad3a6a175cc32610c", features = [
"client-api-c",
"compat-upload-signatures",
"compat-user-id",
Expand All @@ -53,9 +53,10 @@ ruma = { git = "https://github.com/ruma/ruma", rev = "e5a370f7e5fcebb0da6e4945e5
"compat-encrypted-stickers",
"unstable-msc3401",
"unstable-msc3266",
"unstable-msc4075"
"unstable-msc4075",
"unstable-msc4140",
] }
ruma-common = { git = "https://github.com/ruma/ruma", rev = "e5a370f7e5fcebb0da6e4945e51c5fafba9aa5f0" }
ruma-common = { git = "https://github.com/ruma/ruma", rev = "c37843e9be619ffac8c4d33ad3a6a175cc32610c" }
serde = "1.0.151"
serde_html_form = "0.2.0"
serde_json = "1.0.91"
Expand Down
2 changes: 2 additions & 0 deletions crates/matrix-sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ Additions:
- Add `send_call_notification` and `send_call_notification_if_needed` methods. This allows to implement sending ring events on call start.
- The `get_media_content`, `get_media_file` and `get_file` methods of the
`Media` api now support the new authenticated media endpoints.
- WidgetDriver: Support the `"future_timeout"` and `"future_group_id"` fields in the `send_event` widget actions.
This allows to send future events, as defined in [MSC4157](https://github.com/matrix-org/matrix-spec-proposals/pull/4157)

# 0.7.0

Expand Down
15 changes: 10 additions & 5 deletions crates/matrix-sdk/src/widget/machine/driver_req.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,18 @@
use std::marker::PhantomData;

use ruma::{
api::client::account::request_openid_token,
api::client::{account::request_openid_token, future::FutureParameters},
events::{AnyTimelineEvent, MessageLikeEventType, StateEventType, TimelineEventType},
serde::Raw,
OwnedEventId,
};
use serde::Deserialize;
use serde_json::value::RawValue as RawJsonValue;
use tracing::error;

use super::{incoming::MatrixDriverResponse, Action, MatrixDriverRequestMeta, WidgetMachine};
use super::{
from_widget::SendEventResponse, incoming::MatrixDriverResponse, Action,
MatrixDriverRequestMeta, WidgetMachine,
};
use crate::widget::{Capabilities, StateKeySelector};

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -217,6 +219,9 @@ pub(crate) struct SendEventRequest {
pub(crate) state_key: Option<String>,
/// Raw content of an event.
pub(crate) content: Box<RawJsonValue>,
/// Additional send event parameters to send a future event.
#[serde(flatten)]
pub(crate) future_event_parameters: Option<FutureParameters>,
}

impl From<SendEventRequest> for MatrixDriverRequestData {
Expand All @@ -226,10 +231,10 @@ impl From<SendEventRequest> for MatrixDriverRequestData {
}

impl MatrixDriverRequest for SendEventRequest {
type Response = OwnedEventId;
type Response = SendEventResponse;
}

impl FromMatrixDriverResponse for OwnedEventId {
impl FromMatrixDriverResponse for SendEventResponse {
fn from_response(ev: MatrixDriverResponse) -> Option<Self> {
match ev {
MatrixDriverResponse::MatrixEventSent(response) => Some(response),
Expand Down
75 changes: 68 additions & 7 deletions crates/matrix-sdk/src/widget/machine/from_widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,17 @@
use std::fmt;

use ruma::{
api::client::future,
events::{AnyTimelineEvent, MessageLikeEventType, StateEventType},
serde::Raw,
OwnedEventId, RoomId,
OwnedEventId, OwnedRoomId,
};
use serde::{Deserialize, Serialize};

use super::SendEventRequest;
use crate::widget::StateKeySelector;

#[derive(Deserialize)]
#[derive(Deserialize, Debug)]
#[serde(tag = "action", rename_all = "snake_case", content = "data")]
pub(super) enum FromWidgetRequest {
SupportedApiVersions {},
Expand Down Expand Up @@ -111,7 +112,7 @@ pub(super) enum ApiVersion {
MSC3846,
}

#[derive(Deserialize)]
#[derive(Deserialize, Debug)]
#[serde(untagged)]
pub(super) enum ReadEventRequest {
ReadStateEvent {
Expand All @@ -132,8 +133,68 @@ pub(super) struct ReadEventResponse {
pub(super) events: Vec<Raw<AnyTimelineEvent>>,
}

#[derive(Serialize)]
pub(super) struct SendEventResponse<'a> {
pub(super) room_id: &'a RoomId,
pub(super) event_id: OwnedEventId,
#[derive(Serialize, Debug)]
pub(crate) struct SendEventResponse {
/// The room id for the send event.
pub(crate) room_id: Option<OwnedRoomId>,
/// The event id of the send event. It's optional because if it's a future
/// event, it does not get the event_id at this point.
pub(crate) event_id: Option<OwnedEventId>,
/// A token to send/insert the future event into the DAG.
pub(crate) send_token: Option<String>,
/// A token to cancel this future event. It will never be sent if this is
/// called.
pub(crate) cancel_token: Option<String>,
/// The `future_group_id` generated for this future event. Used to connect
/// multiple future events. Only one of the connected future events will be
/// sent and inserted into the DAG.
pub(crate) future_group_id: Option<String>,
/// A token used to refresh the timer of the future event. This allows
/// to implement heartbeat-like capabilities. An event is only sent once
/// a refresh in the timeout interval is missed.
///
/// If the future event does not have a timeout this will be `None`.
pub(crate) refresh_token: Option<String>,
}

impl SendEventResponse {
pub(crate) fn from_event_id(event_id: OwnedEventId) -> Self {
SendEventResponse {
room_id: None,
event_id: Some(event_id),
send_token: None,
cancel_token: None,
future_group_id: None,
refresh_token: None,
}
}
pub(crate) fn set_room_id(&mut self, room_id: OwnedRoomId) {
self.room_id = Some(room_id);
}
}

impl From<future::send_future_message_event::unstable::Response> for SendEventResponse {
fn from(val: future::send_future_message_event::unstable::Response) -> Self {
SendEventResponse {
room_id: None,
event_id: None,
send_token: Some(val.send_token),
cancel_token: Some(val.cancel_token),
future_group_id: Some(val.future_group_id),
refresh_token: val.refresh_token,
}
}
}

impl From<future::send_future_state_event::unstable::Response> for SendEventResponse {
fn from(val: future::send_future_state_event::unstable::Response) -> Self {
SendEventResponse {
room_id: None,
event_id: None,
send_token: Some(val.send_token),
cancel_token: Some(val.cancel_token),
future_group_id: Some(val.future_group_id),
refresh_token: val.refresh_token,
}
}
}
12 changes: 7 additions & 5 deletions crates/matrix-sdk/src/widget/machine/incoming.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use ruma::{
api::client::account::request_openid_token, events::AnyTimelineEvent, serde::Raw, OwnedEventId,
};
use ruma::{api::client::account::request_openid_token, events::AnyTimelineEvent, serde::Raw};
use serde::{de, Deserialize, Deserializer};
use serde_json::value::RawValue as RawJsonValue;
use uuid::Uuid;

use super::{from_widget::FromWidgetRequest, to_widget::ToWidgetResponse};
use super::{
from_widget::{FromWidgetRequest, SendEventResponse},
to_widget::ToWidgetResponse,
};
use crate::widget::Capabilities;

/// Incoming event that the client API must process.
Expand Down Expand Up @@ -56,7 +57,7 @@ pub(crate) enum MatrixDriverResponse {
MatrixEventRead(Vec<Raw<AnyTimelineEvent>>),
/// Client sent some matrix event. The response contains the event ID.
/// A response to an `Action::SendMatrixEvent` command.
MatrixEventSent(OwnedEventId),
MatrixEventSent(SendEventResponse),
}

pub(super) struct IncomingWidgetMessage {
Expand All @@ -65,6 +66,7 @@ pub(super) struct IncomingWidgetMessage {
pub(super) kind: IncomingWidgetMessageKind,
}

#[derive(Debug)]
pub(super) enum IncomingWidgetMessageKind {
Request(Raw<FromWidgetRequest>),
Response(ToWidgetResponse),
Expand Down
12 changes: 7 additions & 5 deletions crates/matrix-sdk/src/widget/machine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use self::{
},
from_widget::{
FromWidgetErrorResponse, FromWidgetRequest, ReadEventRequest, ReadEventResponse,
SendEventResponse, SupportedApiVersionsResponse,
SupportedApiVersionsResponse,
},
incoming::{IncomingWidgetMessage, IncomingWidgetMessageKind},
openid::{OpenIdResponse, OpenIdState},
Expand Down Expand Up @@ -64,6 +64,7 @@ mod to_widget;

pub(crate) use self::{
driver_req::{MatrixDriverRequestData, ReadStateEventRequest, SendEventRequest},
from_widget::SendEventResponse,
incoming::{IncomingMessage, MatrixDriverResponse},
};

Expand Down Expand Up @@ -343,10 +344,11 @@ impl WidgetMachine {
}

let (request, action) = self.send_matrix_driver_request(request);
request.then(|result, machine| {
let room_id = &machine.room_id;
let response = result.map(|event_id| SendEventResponse { event_id, room_id });
vec![machine.send_from_widget_result_response(raw_request, response)]
request.then(|mut result, machine| {
if let Ok(r) = result.as_mut() {
r.set_room_id(machine.room_id.clone().to_owned());
}
vec![machine.send_from_widget_result_response(raw_request, result)]
});
action
}
Expand Down
1 change: 1 addition & 0 deletions crates/matrix-sdk/src/widget/machine/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ mod api_versions;
mod capabilities;
mod error;
mod openid;
mod send_event;

const WIDGET_ID: &str = "test-widget";

Expand Down
43 changes: 43 additions & 0 deletions crates/matrix-sdk/src/widget/machine/tests/send_event.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use std::time::Duration;

use assert_matches2::assert_let;
use ruma::{api::client::future::FutureParameters, events::TimelineEventType};

use super::WIDGET_ID;
use crate::widget::machine::{
from_widget::FromWidgetRequest,
incoming::{IncomingWidgetMessage, IncomingWidgetMessageKind},
};

#[test]
fn parse_future_event_widget_action() {
let raw = json_string!({
"api": "fromWidget",
"widgetId": WIDGET_ID,
"requestId": "send_event-request-id",
"action": "send_event",
"data": {
"content": {},
"future_timeout": 10000,
"room_id": "!rXAYvblqYaGiJmeRdR:matrix.org",
"state_key": "_@abc:example.org_VFKPEKYWMP",
"type": "org.matrix.msc3401.call.member",
},
});
assert_let!(
IncomingWidgetMessageKind::Request(incoming_request) =
serde_json::from_str::<IncomingWidgetMessage>(&raw).unwrap().kind
);
assert_let!(
FromWidgetRequest::SendEvent(send_event_request) = incoming_request.deserialize().unwrap()
);
assert_let!(
FutureParameters::Timeout { timeout, group_id } =
send_event_request.future_event_parameters.unwrap()
);

assert_eq!(timeout, Duration::from_millis(10000));
assert_eq!(group_id, None);
assert_eq!(send_event_request.event_type, TimelineEventType::CallMember);
assert_eq!(send_event_request.state_key.unwrap(), "_@abc:example.org_VFKPEKYWMP".to_owned());
}
2 changes: 1 addition & 1 deletion crates/matrix-sdk/src/widget/machine/to_widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ where
}
}

#[derive(Deserialize)]
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub(super) struct ToWidgetResponse {
/// The action from the original request.
Expand Down
Loading