Skip to content

Commit c6eb6d2

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 49b343c commit c6eb6d2

File tree

6 files changed

+160
-14
lines changed

6 files changed

+160
-14
lines changed

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

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,20 @@
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, MessageLikeEventType, StateEventType, TimelineEventType},
20+
api::client::{
21+
account::request_openid_token, delayed_events::update_delayed_event,
22+
to_device::send_event_to_device,
23+
},
24+
events::{
25+
AnyTimelineEvent, AnyToDeviceEventContent, MessageLikeEventType, StateEventType,
26+
TimelineEventType, ToDeviceEventType,
27+
},
2228
serde::Raw,
29+
to_device::DeviceIdOrAllDevices,
30+
OwnedUserId,
2331
};
2432
use serde::Deserialize;
2533
use serde_json::value::RawValue as RawJsonValue;
@@ -52,6 +60,9 @@ pub(crate) enum MatrixDriverRequestData {
5260
/// Send matrix event that corresponds to the given description.
5361
SendMatrixEvent(SendEventRequest),
5462

63+
/// Send matrix event that corresponds to the given description.
64+
SendToDeviceEvent(SendToDeviceRequest),
65+
5566
/// Data for sending a UpdateDelayedEvent client server api request.
5667
UpdateDelayedEvent(UpdateDelayedEventRequest),
5768
}
@@ -253,6 +264,45 @@ impl FromMatrixDriverResponse for SendEventResponse {
253264
}
254265
}
255266

267+
/// Ask the client to send matrix event that corresponds to the given
268+
/// description and returns an event ID (or a delay ID,
269+
/// see [MSC4140](https://github.com/matrix-org/matrix-spec-proposals/pull/4140)) as a response.
270+
#[derive(Clone, Debug, Deserialize)]
271+
pub(crate) struct SendToDeviceRequest {
272+
/// The type of the event.
273+
#[serde(rename = "type")]
274+
pub(crate) event_type: ToDeviceEventType,
275+
// If the to_device message should be encrypted or not.
276+
pub(crate) encrypted: bool,
277+
/// The messages that will be encrypted (per device) and sent.
278+
/// They are organized in a map of user_id -> device_id -> content like the
279+
/// cs api request.
280+
pub(crate) messages:
281+
BTreeMap<OwnedUserId, BTreeMap<DeviceIdOrAllDevices, Raw<AnyToDeviceEventContent>>>,
282+
}
283+
284+
impl From<SendToDeviceRequest> for MatrixDriverRequestData {
285+
fn from(value: SendToDeviceRequest) -> Self {
286+
MatrixDriverRequestData::SendToDeviceEvent(value)
287+
}
288+
}
289+
290+
impl MatrixDriverRequest for SendToDeviceRequest {
291+
type Response = send_event_to_device::v3::Response;
292+
}
293+
294+
impl FromMatrixDriverResponse for send_event_to_device::v3::Response {
295+
fn from_response(ev: MatrixDriverResponse) -> Option<Self> {
296+
match ev {
297+
MatrixDriverResponse::MatrixToDeviceSent(response) => Some(response),
298+
_ => {
299+
error!("bug in MatrixDriver, received wrong event response");
300+
None
301+
}
302+
}
303+
}
304+
}
305+
256306
/// Ask the client to send a UpdateDelayedEventRequest with the given `delay_id`
257307
/// and `action`. Defined by [MSC4157](https://github.com/matrix-org/matrix-spec-proposals/pull/4157)
258308
#[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, MessageLikeEventType, StateEventType},
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: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
1717
use std::{iter, time::Duration};
1818

19-
use driver_req::UpdateDelayedEventRequest;
20-
use from_widget::UpdateDelayedEventResponse;
19+
use driver_req::{SendToDeviceRequest, UpdateDelayedEventRequest};
20+
use from_widget::{SendToDeviceEventResponse, UpdateDelayedEventResponse};
2121
use indexmap::IndexMap;
2222
use ruma::{
2323
serde::{JsonObject, Raw},
@@ -41,15 +41,16 @@ 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)]
4950
use super::WidgetDriver;
5051
use super::{
5152
capabilities::{SEND_DELAYED_EVENT, UPDATE_DELAYED_EVENT},
52-
filter::FilterInput,
53+
filter::{FilterInput, FilterInputToDevice},
5354
Capabilities, StateKeySelector,
5455
};
5556
use crate::Result;
@@ -179,6 +180,25 @@ impl WidgetMachine {
179180
}
180181
Vec::new()
181182
}
183+
IncomingMessage::ToDeviceReceived(to_device_raw) => {
184+
let CapabilitiesState::Negotiated(capabilities) = &self.capabilities else {
185+
error!("Received to device event before capabilities negotiation");
186+
return Vec::new();
187+
};
188+
let event_filter_in = match to_device_raw.clone().try_into() {
189+
Ok(filter_in) => filter_in,
190+
Err(e) => {
191+
error!("Failed to convert to device event to filter input: {e}");
192+
return Vec::new();
193+
}
194+
};
195+
if capabilities.allow_reading(&event_filter_in) {
196+
let action =
197+
self.send_to_widget_request(NotifyNewToDeviceEvent(to_device_raw)).1;
198+
return action.map(|a| vec![a]).unwrap_or_default();
199+
}
200+
Vec::new()
201+
}
182202
}
183203
}
184204

@@ -247,6 +267,11 @@ impl WidgetMachine {
247267
.map(|a| vec![a])
248268
.unwrap_or_default(),
249269

270+
FromWidgetRequest::SendToDevice(req) => self
271+
.process_to_device_request(req, raw_request)
272+
.map(|a| vec![a])
273+
.unwrap_or_default(),
274+
250275
FromWidgetRequest::GetOpenId {} => {
251276
let (request, request_action) = self.send_matrix_driver_request(RequestOpenId);
252277
request.then(|res, machine| {
@@ -425,7 +450,38 @@ impl WidgetMachine {
425450
result.map_err(FromWidgetErrorResponse::from_error),
426451
)]
427452
});
453+
action
454+
}
455+
456+
fn process_to_device_request(
457+
&mut self,
458+
request: SendToDeviceRequest,
459+
raw_request: Raw<FromWidgetRequest>,
460+
) -> Option<Action> {
461+
let CapabilitiesState::Negotiated(capabilities) = &self.capabilities else {
462+
error!("Received send event request before capabilities negotiation");
463+
return None;
464+
};
465+
466+
let filter_in =
467+
FilterInput::ToDevice(FilterInputToDevice { event_type: request.event_type.clone() });
428468

469+
if !capabilities.allow_sending(&filter_in) {
470+
return Some(Self::send_from_widget_error_string_response(
471+
raw_request,
472+
format!("Not allowed to send to-device message of type: {}", request.event_type),
473+
));
474+
}
475+
476+
let (request, action) = self.send_matrix_driver_request(request);
477+
request.then(|result, _| {
478+
vec![Self::send_from_widget_response(
479+
raw_request,
480+
result
481+
.map(Into::<SendToDeviceEventResponse>::into)
482+
.map_err(FromWidgetErrorResponse::from_error),
483+
)]
484+
});
429485
action
430486
}
431487

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;
@@ -130,3 +133,14 @@ impl ToWidgetRequest for NotifyNewMatrixEvent {
130133

131134
#[derive(Deserialize)]
132135
pub(crate) struct Empty {}
136+
137+
/// Notify the widget that we received a new matrix event.
138+
/// This is a "response" to the widget subscribing to the events in the room.
139+
#[derive(Serialize)]
140+
#[serde(transparent)]
141+
pub(crate) struct NotifyNewToDeviceEvent(pub(crate) Raw<AnyToDeviceEvent>);
142+
143+
impl ToWidgetRequest for NotifyNewToDeviceEvent {
144+
const ACTION: &'static str = "send_to_device";
145+
type ResponseData = Empty;
146+
}

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

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

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

0 commit comments

Comments
 (0)