Skip to content

Commit dbd99ad

Browse files
committed
WidgetDriver: add ToDevice widget events and machine actions.
It consists of the following changes: - add a `NotifyNewToDeviceEvent` ToWidget request (a request that will be sent to the widget from the client when the client receives a widget action over the widget api) - add the `SendToDeviceRequest` (driver request that will be sent from the widget and asks the driver to send a ToDevice event) - add the ToDeviceActions to the required enums: `IncomingMessage`(machine), `MatrixDriverResponse`, `FromWidgetResponse`, `FromWidgetRequest`, `MatrixDriverRequestData`
1 parent 747fac9 commit dbd99ad

File tree

7 files changed

+162
-18
lines changed

7 files changed

+162
-18
lines changed

crates/matrix-sdk/src/widget/filter.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use ruma::{
2323
use serde::Deserialize;
2424
use tracing::debug;
2525

26-
use super::machine::SendEventRequest;
26+
use super::machine::{SendEventRequest, SendToDeviceRequest};
2727

2828
/// A Filter for Matrix events. It is used to decide if a given event can be
2929
/// sent to the widget and if a widget is allowed to send an event to a
@@ -147,8 +147,8 @@ impl ToDeviceEventFilter {
147147
}
148148

149149
impl ToDeviceEventFilter {
150-
fn matches(&self, filter_input: &FilterInput) -> bool {
151-
matches!(filter_input,FilterInput::ToDevice(f_in) if f_in.event_type == self.event_type)
150+
fn matches(&self, filter_input: &FilterInput<'_>) -> bool {
151+
matches!(filter_input,FilterInput::ToDevice(f_in) if f_in.event_type == self.event_type.to_string())
152152
}
153153
}
154154

@@ -243,11 +243,17 @@ pub struct FilterInputToDevice<'a> {
243243
/// Create a filter input of type [`FilterInput::ToDevice`]`.
244244
impl<'a> TryFrom<&'a Raw<AnyToDeviceEvent>> for FilterInput<'a> {
245245
type Error = serde_json::Error;
246-
fn try_from(raw_event: Raw<AnyToDeviceEvent>) -> Result<Self, Self::Error> {
246+
fn try_from(raw_event: &'a Raw<AnyToDeviceEvent>) -> Result<Self, Self::Error> {
247247
// deserialize_as::<FilterInput> will first try state, message like and then to-device.
248248
// The `AnyToDeviceEvent` would match message like first, so we need to explicitly
249249
// deserialize as `FilterInputToDevice`.
250-
raw_event.deserialize_as::<FilterInputToDevice>().map(FilterInput::ToDevice)
250+
raw_event.deserialize_as::<FilterInputToDevice<'a>>().map(FilterInput::ToDevice)
251+
}
252+
}
253+
254+
impl<'a> From<&'a SendToDeviceRequest> for FilterInput<'a> {
255+
fn from(request: &'a SendToDeviceRequest) -> Self {
256+
FilterInput::ToDevice(FilterInputToDevice { event_type: &request.event_type })
251257
}
252258
}
253259

crates/matrix-sdk/src/widget/machine/driver_req.rs

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,17 @@
1414

1515
//! A high-level API for requests that we send to the matrix driver.
1616
17-
use std::marker::PhantomData;
17+
use std::{collections::BTreeMap, marker::PhantomData};
1818

1919
use ruma::{
20-
api::client::{account::request_openid_token, delayed_events::update_delayed_event},
21-
events::AnyTimelineEvent,
20+
api::client::{
21+
account::request_openid_token, delayed_events::update_delayed_event,
22+
to_device::send_event_to_device,
23+
},
24+
events::{AnyTimelineEvent, AnyToDeviceEventContent},
2225
serde::Raw,
26+
to_device::DeviceIdOrAllDevices,
27+
OwnedUserId,
2328
};
2429
use serde::Deserialize;
2530
use serde_json::value::RawValue as RawJsonValue;
@@ -52,6 +57,9 @@ pub(crate) enum MatrixDriverRequestData {
5257
/// Send matrix event that corresponds to the given description.
5358
SendMatrixEvent(SendEventRequest),
5459

60+
/// Send matrix event that corresponds to the given description.
61+
SendToDeviceEvent(SendToDeviceRequest),
62+
5563
/// Data for sending a UpdateDelayedEvent client server api request.
5664
UpdateDelayedEvent(UpdateDelayedEventRequest),
5765
}
@@ -253,6 +261,45 @@ impl FromMatrixDriverResponse for SendEventResponse {
253261
}
254262
}
255263

264+
/// Ask the client to send matrix event that corresponds to the given
265+
/// description and returns an event ID (or a delay ID,
266+
/// see [MSC4140](https://github.com/matrix-org/matrix-spec-proposals/pull/4140)) as a response.
267+
#[derive(Clone, Debug, Deserialize)]
268+
pub(crate) struct SendToDeviceRequest {
269+
/// The type of the event.
270+
#[serde(rename = "type")]
271+
pub(crate) event_type: String,
272+
// If the to_device message should be encrypted or not.
273+
pub(crate) encrypted: bool,
274+
/// The messages that will be encrypted (per device) and sent.
275+
/// They are organized in a map of user_id -> device_id -> content like the
276+
/// cs api request.
277+
pub(crate) messages:
278+
BTreeMap<OwnedUserId, BTreeMap<DeviceIdOrAllDevices, Raw<AnyToDeviceEventContent>>>,
279+
}
280+
281+
impl From<SendToDeviceRequest> for MatrixDriverRequestData {
282+
fn from(value: SendToDeviceRequest) -> Self {
283+
MatrixDriverRequestData::SendToDeviceEvent(value)
284+
}
285+
}
286+
287+
impl MatrixDriverRequest for SendToDeviceRequest {
288+
type Response = send_event_to_device::v3::Response;
289+
}
290+
291+
impl FromMatrixDriverResponse for send_event_to_device::v3::Response {
292+
fn from_response(ev: MatrixDriverResponse) -> Option<Self> {
293+
match ev {
294+
MatrixDriverResponse::MatrixToDeviceSent(response) => Some(response),
295+
_ => {
296+
error!("bug in MatrixDriver, received wrong event response");
297+
None
298+
}
299+
}
300+
}
301+
}
302+
256303
/// Ask the client to send a UpdateDelayedEventRequest with the given `delay_id`
257304
/// and `action`. Defined by [MSC4157](https://github.com/matrix-org/matrix-spec-proposals/pull/4157)
258305
#[derive(Deserialize, Debug, Clone)]

crates/matrix-sdk/src/widget/machine/from_widget.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,15 @@ use ruma::{
1717
api::client::{
1818
delayed_events::{delayed_message_event, delayed_state_event, update_delayed_event},
1919
error::{ErrorBody, StandardErrorBody},
20+
to_device::send_event_to_device,
2021
},
2122
events::AnyTimelineEvent,
2223
serde::Raw,
2324
OwnedEventId, OwnedRoomId,
2425
};
2526
use serde::{Deserialize, Serialize};
2627

27-
use super::{SendEventRequest, UpdateDelayedEventRequest};
28+
use super::{driver_req::SendToDeviceRequest, SendEventRequest, UpdateDelayedEventRequest};
2829
use crate::{widget::StateKeySelector, Error, HttpError, RumaApiError};
2930

3031
#[derive(Deserialize, Debug)]
@@ -37,6 +38,7 @@ pub(super) enum FromWidgetRequest {
3738
#[serde(rename = "org.matrix.msc2876.read_events")]
3839
ReadEvent(ReadEventRequest),
3940
SendEvent(SendEventRequest),
41+
SendToDevice(SendToDeviceRequest),
4042
#[serde(rename = "org.matrix.msc4157.update_delayed_event")]
4143
DelayedEventUpdate(UpdateDelayedEventRequest),
4244
}
@@ -68,7 +70,7 @@ impl FromWidgetErrorResponse {
6870
}
6971
}
7072

71-
/// Create a error response to send to the widget from a matrix sdk error.
73+
/// Create an error response to send to the widget from a matrix sdk error.
7274
pub(crate) fn from_error(error: Error) -> Self {
7375
match error {
7476
Error::Http(e) => FromWidgetErrorResponse::from_http_error(*e),
@@ -97,6 +99,7 @@ struct FromWidgetError {
9799
message: String,
98100

99101
/// Optional matrix error hinting at workarounds for specific errors.
102+
#[serde(skip_serializing_if = "Option::is_none")]
100103
matrix_api_error: Option<FromWidgetMatrixErrorBody>,
101104
}
102105

@@ -230,10 +233,26 @@ impl From<delayed_state_event::unstable::Response> for SendEventResponse {
230233
/// [`update_delayed_event`](update_delayed_event::unstable::Response)
231234
/// which derives Serialize. (The response struct from Ruma does not derive
232235
/// serialize)
236+
/// This is intentionally an empty tuple struct (not a unit struct), so that it
237+
/// serializes to `{}` instead of `Null` when returned to the widget as json.
233238
#[derive(Serialize, Debug)]
234239
pub(crate) struct UpdateDelayedEventResponse {}
235240
impl From<update_delayed_event::unstable::Response> for UpdateDelayedEventResponse {
236241
fn from(_: update_delayed_event::unstable::Response) -> Self {
237242
Self {}
238243
}
239244
}
245+
246+
/// The response to the widget that it received the to-device event.
247+
/// Only used as the response for the successful send case.
248+
/// FromWidgetErrorResponse will be used otherwise.
249+
/// This is intentionally an empty tuple struct (not a unit struct), so that it
250+
/// serializes to `{}` instead of `Null` when returned to the widget as json.
251+
#[derive(Serialize, Debug)]
252+
pub(crate) struct SendToDeviceEventResponse {}
253+
254+
impl From<send_event_to_device::v3::Response> for SendToDeviceEventResponse {
255+
fn from(_: send_event_to_device::v3::Response) -> Self {
256+
Self {}
257+
}
258+
}

crates/matrix-sdk/src/widget/machine/incoming.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
// limitations under the License.
1414

1515
use ruma::{
16-
api::client::{account::request_openid_token, delayed_events},
17-
events::AnyTimelineEvent,
16+
api::client::{account::request_openid_token, delayed_events, to_device::send_event_to_device},
17+
events::{AnyTimelineEvent, AnyToDeviceEvent},
1818
serde::Raw,
1919
};
2020
use serde::{de, Deserialize, Deserializer};
@@ -47,8 +47,12 @@ pub(crate) enum IncomingMessage {
4747
/// The `MatrixDriver` notified the `WidgetMachine` of a new matrix event.
4848
///
4949
/// This means that the machine previously subscribed to some events
50-
/// ([`crate::widget::Action::Subscribe`] request).
50+
/// ([`crate::widget::Action::SubscribeTimeline`] request).
5151
MatrixEventReceived(Raw<AnyTimelineEvent>),
52+
53+
/// The `MatrixDriver` notified the `WidgetMachine` of a new to_device
54+
/// event.
55+
ToDeviceReceived(Raw<AnyToDeviceEvent>),
5256
}
5357

5458
pub(crate) enum MatrixDriverResponse {
@@ -65,6 +69,7 @@ pub(crate) enum MatrixDriverResponse {
6569
/// Client sent some matrix event. The response contains the event ID.
6670
/// A response to an `Action::SendMatrixEvent` command.
6771
MatrixEventSent(SendEventResponse),
72+
MatrixToDeviceSent(send_event_to_device::v3::Response),
6873
MatrixDelayedEventUpdate(delayed_events::update_delayed_event::unstable::Response),
6974
}
7075

crates/matrix-sdk/src/widget/machine/mod.rs

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
use std::time::Duration;
1818

1919
use driver_req::UpdateDelayedEventRequest;
20-
use from_widget::UpdateDelayedEventResponse;
20+
use from_widget::{SendToDeviceEventResponse, UpdateDelayedEventResponse};
2121
use indexmap::IndexMap;
2222
use ruma::{
2323
serde::{JsonObject, Raw},
@@ -41,8 +41,9 @@ use self::{
4141
openid::{OpenIdResponse, OpenIdState},
4242
pending::{PendingRequests, RequestLimits},
4343
to_widget::{
44-
NotifyCapabilitiesChanged, NotifyNewMatrixEvent, NotifyOpenIdChanged, RequestCapabilities,
45-
ToWidgetRequest, ToWidgetRequestHandle, ToWidgetResponse,
44+
NotifyCapabilitiesChanged, NotifyNewMatrixEvent, NotifyNewToDeviceEvent,
45+
NotifyOpenIdChanged, RequestCapabilities, ToWidgetRequest, ToWidgetRequestHandle,
46+
ToWidgetResponse,
4647
},
4748
};
4849
#[cfg(doc)]
@@ -64,7 +65,9 @@ mod tests;
6465
mod to_widget;
6566

6667
pub(crate) use self::{
67-
driver_req::{MatrixDriverRequestData, ReadStateEventRequest, SendEventRequest},
68+
driver_req::{
69+
MatrixDriverRequestData, ReadStateEventRequest, SendEventRequest, SendToDeviceRequest,
70+
},
6871
from_widget::SendEventResponse,
6972
incoming::{IncomingMessage, MatrixDriverResponse},
7073
};
@@ -179,6 +182,21 @@ impl WidgetMachine {
179182
})
180183
.unwrap_or_default()
181184
}
185+
IncomingMessage::ToDeviceReceived(to_device_raw) => {
186+
let CapabilitiesState::Negotiated(capabilities) = &self.capabilities else {
187+
error!("Received to device event before capabilities negotiation");
188+
return Vec::new();
189+
};
190+
191+
capabilities
192+
.allow_reading(&to_device_raw)
193+
.then(|| {
194+
self.send_to_widget_request(NotifyNewToDeviceEvent(to_device_raw))
195+
.map(|(_request, action)| vec![action])
196+
.unwrap_or_default()
197+
})
198+
.unwrap_or_default()
199+
}
182200
}
183201
}
184202

@@ -247,6 +265,11 @@ impl WidgetMachine {
247265
.map(|a| vec![a])
248266
.unwrap_or_default(),
249267

268+
FromWidgetRequest::SendToDevice(req) => self
269+
.process_to_device_request(req, raw_request)
270+
.map(|a| vec![a])
271+
.unwrap_or_default(),
272+
250273
FromWidgetRequest::GetOpenId {} => {
251274
let mut actions =
252275
vec![Self::send_from_widget_response(raw_request, Ok(OpenIdResponse::Pending))];
@@ -436,7 +459,35 @@ impl WidgetMachine {
436459
result.map_err(FromWidgetErrorResponse::from_error),
437460
)]
438461
});
462+
Some(action)
463+
}
439464

465+
fn process_to_device_request(
466+
&mut self,
467+
request: SendToDeviceRequest,
468+
raw_request: Raw<FromWidgetRequest>,
469+
) -> Option<Action> {
470+
let CapabilitiesState::Negotiated(capabilities) = &self.capabilities else {
471+
error!("Received send event request before capabilities negotiation");
472+
return None;
473+
};
474+
475+
if !capabilities.allow_sending(&request) {
476+
return Some(Self::send_from_widget_error_string_response(
477+
raw_request,
478+
format!("Not allowed to send to-device message of type: {}", request.event_type),
479+
));
480+
}
481+
482+
let (request, action) = self.send_matrix_driver_request(request)?;
483+
request.then(|result, _| {
484+
vec![Self::send_from_widget_response(
485+
raw_request,
486+
result
487+
.map(Into::<SendToDeviceEventResponse>::into)
488+
.map_err(FromWidgetErrorResponse::from_error),
489+
)]
490+
});
440491
Some(action)
441492
}
442493

crates/matrix-sdk/src/widget/machine/to_widget.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@
1414

1515
use std::marker::PhantomData;
1616

17-
use ruma::{events::AnyTimelineEvent, serde::Raw};
17+
use ruma::{
18+
events::{AnyTimelineEvent, AnyToDeviceEvent},
19+
serde::Raw,
20+
};
1821
use serde::{de::DeserializeOwned, Deserialize, Serialize};
1922
use serde_json::value::RawValue as RawJsonValue;
2023
use tracing::error;
@@ -124,3 +127,14 @@ impl ToWidgetRequest for NotifyNewMatrixEvent {
124127

125128
#[derive(Deserialize)]
126129
pub(crate) struct Empty {}
130+
131+
/// Notify the widget that we received a new matrix event.
132+
/// This is a "response" to the widget subscribing to the events in the room.
133+
#[derive(Serialize)]
134+
#[serde(transparent)]
135+
pub(crate) struct NotifyNewToDeviceEvent(pub(crate) Raw<AnyToDeviceEvent>);
136+
137+
impl ToWidgetRequest for NotifyNewToDeviceEvent {
138+
const ACTION: &'static str = "send_to_device";
139+
type ResponseData = Empty;
140+
}

crates/matrix-sdk/src/widget/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,8 @@ impl WidgetDriver {
236236
.update_delayed_event(req.delay_id, req.action)
237237
.await
238238
.map(MatrixDriverResponse::MatrixDelayedEventUpdate),
239+
240+
MatrixDriverRequestData::SendToDeviceEvent(req) => todo!(),
239241
};
240242

241243
// Forward the matrix driver response to the incoming message stream.

0 commit comments

Comments
 (0)