From e038ced2c6e2caa071088ece2c08aaff628e7d7d Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Tue, 17 Oct 2023 18:01:38 +0200 Subject: [PATCH] widget: Add toWidget & MatrixDriver response handling skeleton --- Cargo.lock | 1 + crates/matrix-sdk/Cargo.toml | 1 + .../matrix-sdk/src/widget/machine/actions.rs | 93 ++++++------ .../src/widget/machine/driver_req.rs | 134 ++++++++++++++++++ .../matrix-sdk/src/widget/machine/events.rs | 10 +- crates/matrix-sdk/src/widget/machine/mod.rs | 99 +++++++++++-- .../matrix-sdk/src/widget/machine/outgoing.rs | 82 ----------- .../src/widget/machine/to_widget.rs | 43 +++++- crates/matrix-sdk/src/widget/mod.rs | 64 +++++---- 9 files changed, 360 insertions(+), 167 deletions(-) create mode 100644 crates/matrix-sdk/src/widget/machine/driver_req.rs delete mode 100644 crates/matrix-sdk/src/widget/machine/outgoing.rs diff --git a/Cargo.lock b/Cargo.lock index a29faa67d..9ac6c3e78 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3070,6 +3070,7 @@ dependencies = [ "hyper", "image 0.24.7", "imbl", + "indexmap 2.0.2", "language-tags", "mas-oidc-client", "matrix-sdk-base", diff --git a/crates/matrix-sdk/Cargo.toml b/crates/matrix-sdk/Cargo.toml index 8281000c1..aa87cd247 100644 --- a/crates/matrix-sdk/Cargo.toml +++ b/crates/matrix-sdk/Cargo.toml @@ -81,6 +81,7 @@ futures-util = { workspace = true } http = { workspace = true } hyper = { version = "0.14.20", features = ["http1", "http2", "server"], optional = true } imbl = { version = "2.0.0", features = ["serde"] } +indexmap = "2.0.2" language-tags = { version = "0.3.2", optional = true } matrix-sdk-base = { version = "0.6.0", path = "../matrix-sdk-base", default_features = false } matrix-sdk-common = { version = "0.6.0", path = "../matrix-sdk-common" } diff --git a/crates/matrix-sdk/src/widget/machine/actions.rs b/crates/matrix-sdk/src/widget/machine/actions.rs index c8e54b68f..39e91eff2 100644 --- a/crates/matrix-sdk/src/widget/machine/actions.rs +++ b/crates/matrix-sdk/src/widget/machine/actions.rs @@ -12,36 +12,45 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::{borrow::Cow, error::Error, ops::Deref}; +use std::error::Error; use ruma::events::{MessageLikeEventType, StateEventType, TimelineEventType}; use serde::{Deserialize, Serialize}; use serde_json::Value as JsonValue; +use uuid::Uuid; -use crate::widget::{Permissions, StateKeySelector}; +use super::driver_req::AcquirePermissions; +use crate::widget::StateKeySelector; /// Action (a command) that client (driver) must perform. -#[allow(dead_code)] // TODO: Remove once all actions are implemented. #[derive(Debug)] pub(crate) enum Action { /// Send a raw message to the widget. SendToWidget(String), - /// Acquire permissions from the user given the set of desired permissions. - /// Must eventually be answered with `Event::PermissionsAcquired`. - AcquirePermissions(Command), - /// Get OpenId token for a given request ID. - GetOpenId(Command<()>), - /// Read message event(s). - ReadMessageLikeEvent(Command), - /// Read state event(s). - ReadStateEvent(Command), - /// Send matrix event that corresponds to the given description. - SendMatrixEvent(Command), + + /// Command that is sent from the client widget API state machine to the + /// client (driver) that must be performed. Once the command is executed, + /// the client will typically generate an `Event` with the result of it. + MatrixDriverRequest { + /// Certain commands are typically answered with certain event once the + /// command is performed. The api state machine will "tag" each command + /// with some "cookie" (in this case just an ID), so that once the + /// result of the execution of this command is received, it could be + /// matched. + request_id: Uuid, + + /// Data associated with this command. + data: MatrixDriverRequestData, + }, + /// Subscribe to the events in the *current* room, i.e. a room which this /// widget is instantiated with. The client is aware of the room. + #[allow(dead_code)] Subscribe, + /// Unsuscribe from the events in the *current* room. Symmetrical to /// `Subscribe`. + #[allow(dead_code)] Unsubscribe, } @@ -78,38 +87,24 @@ pub(crate) struct SendEventCommand { pub(crate) content: JsonValue, } -/// Command that is sent from the client widget API state machine to the -/// client (driver) that must be performed. Once the command is executed, -/// the client will typically generate an `Event` with the result of it. #[derive(Debug)] -pub(crate) struct Command { - /// Certain commands are typically answered with certain event once the - /// command is performed. The api state machine will "tag" each command - /// with some "cookie" (in this case just an ID), so that once the - /// result of the execution of this command is received, it could be - /// matched. - id: String, - // Data associated with this command. - data: T, -} +#[allow(dead_code)] +pub(crate) enum MatrixDriverRequestData { + /// Acquire permissions from the user given the set of desired permissions. + /// Must eventually be answered with `Event::PermissionsAcquired`. + AcquirePermissions(AcquirePermissions), -impl Command { - /// Consumes the command and produces a command result with given data. - pub(crate) fn result(self, result: Result) -> CommandResult { - CommandResult { id: self.id, result: result.map_err(|e| e.to_string().into()) } - } + /// Get OpenId token for a given request ID. + GetOpenId, - pub(crate) fn ok(self, value: U) -> CommandResult { - CommandResult { id: self.id, result: Ok(value) } - } -} + /// Read message event(s). + ReadMessageLikeEvent(ReadMessageLikeEventCommand), -impl Deref for Command { - type Target = T; + /// Read state event(s). + ReadStateEvent(ReadStateEventCommand), - fn deref(&self) -> &Self::Target { - &self.data - } + /// Send matrix event that corresponds to the given description. + SendMatrixEvent(SendEventCommand), } /// The result of the execution of a command. Note that this type can only be @@ -118,9 +113,19 @@ impl Deref for Command { /// client (driver) won't be able to send "invalid" commands, because they could /// only be generated from a `Command` instance. #[allow(dead_code)] // TODO: Remove once results are used. -pub(crate) struct CommandResult { +pub(crate) struct MatrixDriverResponse { /// ID of the command that was executed. See `Command::id` for more details. - id: String, + request_id: Uuid, /// Result of the execution of the command. - result: Result>, + result: Result, +} + +impl MatrixDriverResponse { + pub(crate) fn new(request_id: Uuid, result: Result) -> Self { + Self { request_id, result: result.map_err(|e| e.to_string()) } + } + + pub(crate) fn ok(request_id: Uuid, value: T) -> Self { + Self { request_id, result: Ok(value) } + } } diff --git a/crates/matrix-sdk/src/widget/machine/driver_req.rs b/crates/matrix-sdk/src/widget/machine/driver_req.rs new file mode 100644 index 000000000..6e0c804f6 --- /dev/null +++ b/crates/matrix-sdk/src/widget/machine/driver_req.rs @@ -0,0 +1,134 @@ +// Copyright 2023 The Matrix.org Foundation C.I.C. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![allow(dead_code)] + +//! A high-level API for requests that we send to the matrix driver. + +use std::marker::PhantomData; + +//use ruma::{ +// api::client::account::request_openid_token::v3::Response as +// RumaOpenIdResponse, events::AnyTimelineEvent, serde::Raw, OwnedEventId, +//}; +use tracing::error; + +use super::{ + actions::MatrixDriverRequestData, + //actions::{ReadMessageLikeEventCommand, SendEventCommand}, + Event, + MatrixDriverRequestMeta, + WidgetMachine, +}; +use crate::widget::Permissions; + +/// A handle to a pending `toWidget` request. +pub(crate) struct MatrixDriverRequestHandle<'m, T> { + request_meta: Option<&'m mut MatrixDriverRequestMeta>, + _phantom: PhantomData T>, +} + +impl<'m, T> MatrixDriverRequestHandle<'m, T> +where + T: MatrixDriverResponse, +{ + pub(crate) fn new(request_meta: &'m mut MatrixDriverRequestMeta) -> Self { + Self { request_meta: Some(request_meta), _phantom: PhantomData } + } + + pub(crate) fn null() -> Self { + Self { request_meta: None, _phantom: PhantomData } + } + + pub(crate) fn then( + self, + response_handler: impl FnOnce(T, &mut WidgetMachine) + Send + 'static, + ) { + if let Some(request_meta) = self.request_meta { + request_meta.response_fn = Some(Box::new(move |event, machine| { + if let Some(response_data) = T::from_event(event) { + response_handler(response_data, machine) + } + })); + } + } +} + +/// Represents a request that the widget API state machine can send. +pub(crate) trait MatrixDriverRequest: Into { + type Response: MatrixDriverResponse; +} + +pub(crate) trait MatrixDriverResponse: Sized { + fn from_event(_: Event) -> Option; +} + +/// Ask the client (permission provider) to acquire given permissions +/// from the user. The client must eventually respond with granted permissions. +#[derive(Debug)] +pub(crate) struct AcquirePermissions { + pub(crate) desired_permissions: Permissions, +} + +pub(crate) struct AcquirePermissionsResponse { + pub(crate) granted_permissions: Permissions, +} + +impl From for MatrixDriverRequestData { + fn from(value: AcquirePermissions) -> Self { + MatrixDriverRequestData::AcquirePermissions(value) + } +} + +impl MatrixDriverRequest for AcquirePermissions { + type Response = AcquirePermissionsResponse; +} + +impl MatrixDriverResponse for AcquirePermissionsResponse { + fn from_event(ev: Event) -> Option { + match ev { + Event::PermissionsAcquired(_) => todo!(), + Event::MessageFromWidget(_) | Event::MatrixEventReceived(_) => { + error!("this should be unreachable, no ID to match"); + None + } + Event::OpenIdReceived(_) | Event::MatrixEventSent(_) | Event::MatrixEventRead(_) => { + error!("bug in MatrixDriver, received wrong event response"); + None + } + } + } +} + +/* +/// Request open ID from the Matrix client. +pub(crate) struct RequestOpenId; +impl MatrixDriverRequest for RequestOpenId { + type Response = RumaOpenIdResponse; +} + +/// Ask the client to read matrix event(s) that corresponds to the given +/// description and return a list of events as a response. +pub(crate) struct ReadMatrixEvent(pub(crate) ReadMessageLikeEventCommand); +impl MatrixDriverRequest for ReadMatrixEvent { + type Response = Vec>; +} + +/// Ask the client to send matrix event that corresponds to the given +/// description and return an event ID as a response. +pub(crate) struct SendMatrixEvent(pub(crate) SendEventCommand); +impl MatrixDriverRequest for SendMatrixEvent { + type Response = OwnedEventId; +} + */ diff --git a/crates/matrix-sdk/src/widget/machine/events.rs b/crates/matrix-sdk/src/widget/machine/events.rs index 459040f6f..61a37510d 100644 --- a/crates/matrix-sdk/src/widget/machine/events.rs +++ b/crates/matrix-sdk/src/widget/machine/events.rs @@ -17,7 +17,7 @@ use ruma::{ events::AnyTimelineEvent, serde::Raw, OwnedEventId, }; -use super::actions::CommandResult; +use super::actions::MatrixDriverResponse; use crate::widget::Permissions; /// Incoming event that the client API must process. @@ -29,14 +29,14 @@ pub(crate) enum Event { MatrixEventReceived(Raw), /// Client acquired permissions from the user. /// A response to an `Action::AcquirePermissions` command. - PermissionsAcquired(CommandResult), + PermissionsAcquired(MatrixDriverResponse), /// Client got OpenId token for a given request ID. /// A response to an `Action::GetOpenId` command. - OpenIdReceived(CommandResult), + OpenIdReceived(MatrixDriverResponse), /// Client read some matrix event(s). /// A response to an `Action::ReadMatrixEvent` commands. - MatrixEventRead(CommandResult>>), + MatrixEventRead(MatrixDriverResponse>>), /// Client sent some matrix event. The response contains the event ID. /// A response to an `Action::SendMatrixEvent` command. - MatrixEventSent(CommandResult), + MatrixEventSent(MatrixDriverResponse), } diff --git a/crates/matrix-sdk/src/widget/machine/mod.rs b/crates/matrix-sdk/src/widget/machine/mod.rs index 6faa7c382..2bb888a73 100644 --- a/crates/matrix-sdk/src/widget/machine/mod.rs +++ b/crates/matrix-sdk/src/widget/machine/mod.rs @@ -16,23 +16,28 @@ #![warn(unreachable_pub)] +use indexmap::{map::Entry, IndexMap}; use serde::Serialize; +use serde_json::value::RawValue as RawJsonValue; use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}; use tracing::{error, instrument}; use uuid::Uuid; -use self::to_widget::{RequestPermissions, ToWidgetRequest}; +use self::{ + driver_req::{AcquirePermissions, MatrixDriverRequest, MatrixDriverRequestHandle}, + to_widget::{RequestPermissions, ToWidgetRequest, ToWidgetRequestHandle}, +}; mod actions; +mod driver_req; mod events; mod openid; -mod outgoing; #[cfg(test)] mod tests; mod to_widget; pub(crate) use self::{ - actions::{Action, SendEventCommand}, + actions::{Action, MatrixDriverRequestData, MatrixDriverResponse, SendEventCommand}, events::Event, }; #[cfg(doc)] @@ -44,6 +49,8 @@ use super::WidgetDriver; pub(crate) struct WidgetMachine { widget_id: String, actions_sender: UnboundedSender, + pending_to_widget_requests: IndexMap, + pending_matrix_driver_requests: IndexMap, } impl WidgetMachine { @@ -55,17 +62,31 @@ impl WidgetMachine { init_on_content_load: bool, ) -> (Self, UnboundedReceiver) { let (actions_sender, actions_receiver) = unbounded_channel(); - let this = Self { widget_id, actions_sender }; + let mut machine = Self { + widget_id, + actions_sender, + pending_to_widget_requests: IndexMap::new(), + pending_matrix_driver_requests: IndexMap::new(), + }; if !init_on_content_load { - this.send_to_widget(RequestPermissions {}); + machine + .send_to_widget_request(RequestPermissions {}) + // rustfmt please + .then(|desired_permissions, machine| { + machine.send_matrix_driver_request(AcquirePermissions { desired_permissions }); + // TODO: use the result! (chain another `.then`) + }); } - (this, actions_receiver) + (machine, actions_receiver) } #[instrument(skip_all, fields(action = T::ACTION))] - fn send_to_widget(&self, to_widget_request: T) { + fn send_to_widget_request( + &mut self, + to_widget_request: T, + ) -> ToWidgetRequestHandle<'_, T::ResponseData> { #[derive(Serialize)] #[serde(tag = "api", rename = "toWidget", rename_all = "camelCase")] struct ToWidgetRequestSerHelper<'a, T> { @@ -75,23 +96,57 @@ impl WidgetMachine { data: T, } + let request_id = Uuid::new_v4(); let full_request = ToWidgetRequestSerHelper { widget_id: &self.widget_id, - request_id: Uuid::new_v4(), + request_id, action: T::ACTION, data: to_widget_request, }; + let serialized = match serde_json::to_string(&full_request) { Ok(msg) => msg, Err(e) => { error!("Failed to serialize outgoing message: {e}"); - return; + return ToWidgetRequestHandle::null(); } }; if let Err(e) = self.actions_sender.send(Action::SendToWidget(serialized)) { error!("Failed to send action: {e}"); + return ToWidgetRequestHandle::null(); } + + let request_meta = ToWidgetRequestMeta::new(T::ACTION); + let Entry::Vacant(entry) = self.pending_to_widget_requests.entry(request_id) else { + panic!("uuid collision"); + }; + let meta = entry.insert(request_meta); + + ToWidgetRequestHandle::new(meta) + } + + #[instrument(skip_all)] + fn send_matrix_driver_request( + &mut self, + matrix_driver_request: T, + ) -> MatrixDriverRequestHandle<'_, T::Response> { + let request_id = Uuid::new_v4(); + if let Err(e) = self + .actions_sender + .send(Action::MatrixDriverRequest { request_id, data: matrix_driver_request.into() }) + { + error!("Failed to send action: {e}"); + return MatrixDriverRequestHandle::null(); + } + + let request_meta = MatrixDriverRequestMeta::new(); + let Entry::Vacant(entry) = self.pending_matrix_driver_requests.entry(request_id) else { + panic!("uuid collision"); + }; + let meta = entry.insert(request_meta); + + MatrixDriverRequestHandle::new(meta) } /// Processes an incoming event (an incoming raw message from a widget, @@ -101,3 +156,29 @@ impl WidgetMachine { // TODO: Process the event. } } + +type ToWidgetResponseFn = Box, &mut WidgetMachine) + Send>; + +pub(crate) struct ToWidgetRequestMeta { + #[allow(dead_code)] + action: &'static str, + response_fn: Option, +} + +impl ToWidgetRequestMeta { + fn new(action: &'static str) -> Self { + Self { action, response_fn: None } + } +} + +type MatrixDriverResponseFn = Box; + +pub(crate) struct MatrixDriverRequestMeta { + response_fn: Option, +} + +impl MatrixDriverRequestMeta { + fn new() -> Self { + Self { response_fn: None } + } +} diff --git a/crates/matrix-sdk/src/widget/machine/outgoing.rs b/crates/matrix-sdk/src/widget/machine/outgoing.rs deleted file mode 100644 index 3085ced24..000000000 --- a/crates/matrix-sdk/src/widget/machine/outgoing.rs +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2023 The Matrix.org Foundation C.I.C. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! A high-level API to generate commands (requests) that we send either -//! directly to the widget, or to the matrix driver/client. - -use ruma::{ - api::client::account::request_openid_token::v3::Response as RumaOpenIdResponse, - events::AnyTimelineEvent, serde::Raw, OwnedEventId, -}; - -use super::{ - actions::{ReadMessageLikeEventCommand, SendEventCommand}, - openid::OpenIdResponse, -}; -use crate::widget::Permissions; - -/// Represents a request that the widget API state machine can send. -pub(crate) trait Request { - type Response; -} - -// `toWidget` requests - -/// Send a request to a widget asking it to respond with the list of -/// permissinos (capabilities) that the widget wants to have. -pub(crate) struct RequestPermissions; -impl Request for RequestPermissions { - type Response = Permissions; -} - -/// Send a request to the widget asking it to update its permissions. -pub(crate) struct UpdatePermissions(pub(crate) Permissions); -impl Request for UpdatePermissions { - type Response = (); -} - -/// Send a request to the widget asking it to update its open ID state. -pub(crate) struct UpdateOpenId(pub(crate) OpenIdResponse); -impl Request for UpdateOpenId { - type Response = (); -} - -// requests to the `MatrixDriver` - -/// Ask the client (permission provider) to acquire given permissions -/// from the user. The client must eventually respond with granted permissions. -pub(crate) struct AcquirePermissions(pub(crate) Permissions); -impl Request for AcquirePermissions { - type Response = Permissions; -} - -/// Request open ID from the Matrix client. -pub(crate) struct RequestOpenId; -impl Request for RequestOpenId { - type Response = RumaOpenIdResponse; -} - -/// Ask the client to read matrix event(s) that corresponds to the given -/// description and return a list of events as a response. -pub(crate) struct ReadMatrixEvent(pub(crate) ReadMessageLikeEventCommand); -impl Request for ReadMatrixEvent { - type Response = Vec>; -} - -/// Ask the client to send matrix event that corresponds to the given -/// description and return an event ID as a response. -pub(crate) struct SendMatrixEvent(pub(crate) SendEventCommand); -impl Request for SendMatrixEvent { - type Response = OwnedEventId; -} diff --git a/crates/matrix-sdk/src/widget/machine/to_widget.rs b/crates/matrix-sdk/src/widget/machine/to_widget.rs index 2e3597258..98d5e3773 100644 --- a/crates/matrix-sdk/src/widget/machine/to_widget.rs +++ b/crates/matrix-sdk/src/widget/machine/to_widget.rs @@ -12,13 +12,53 @@ // See the License for the specific language governing permissions and // limitations under the License. -use serde::Serialize; +use std::marker::PhantomData; + +use serde::{de::DeserializeOwned, Serialize}; +use tracing::error; + +use super::{ToWidgetRequestMeta, WidgetMachine}; +use crate::widget::Permissions; + +/// A handle to a pending `toWidget` request. +pub(crate) struct ToWidgetRequestHandle<'m, T> { + request_meta: Option<&'m mut ToWidgetRequestMeta>, + _phantom: PhantomData T>, +} + +impl<'m, T> ToWidgetRequestHandle<'m, T> +where + T: DeserializeOwned, +{ + pub(crate) fn new(request_meta: &'m mut ToWidgetRequestMeta) -> Self { + Self { request_meta: Some(request_meta), _phantom: PhantomData } + } + + pub(crate) fn null() -> Self { + Self { request_meta: None, _phantom: PhantomData } + } + + pub(crate) fn then( + self, + response_handler: impl FnOnce(T, &mut WidgetMachine) + Send + 'static, + ) { + if let Some(request_meta) = self.request_meta { + request_meta.response_fn = Some(Box::new(move |raw_response_data, machine| { + match serde_json::from_str(raw_response_data.get()) { + Ok(response_data) => response_handler(response_data, machine), + Err(e) => error!("Failed to deserialize toWidget response: {e}"), + } + })); + } + } +} /// A request that the driver can send to the widget. /// /// In postmessage interface terms: an `"api": "toWidget"` message. pub(crate) trait ToWidgetRequest: Serialize { const ACTION: &'static str; + type ResponseData: DeserializeOwned; } /// Request the widget to send the list of capabilities that it wants to have. @@ -27,4 +67,5 @@ pub(crate) struct RequestPermissions {} impl ToWidgetRequest for RequestPermissions { const ACTION: &'static str = "capabilities"; + type ResponseData = Permissions; } diff --git a/crates/matrix-sdk/src/widget/mod.rs b/crates/matrix-sdk/src/widget/mod.rs index 8c5d87601..9c11c6cbb 100644 --- a/crates/matrix-sdk/src/widget/mod.rs +++ b/crates/matrix-sdk/src/widget/mod.rs @@ -19,7 +19,10 @@ use tokio::sync::mpsc::unbounded_channel; use tokio_util::sync::{CancellationToken, DropGuard}; use self::{ - machine::{Action, Event, SendEventCommand, WidgetMachine}, + machine::{ + Action, Event, MatrixDriverRequestData, MatrixDriverResponse, SendEventCommand, + WidgetMachine, + }, matrix::MatrixDriver, }; use crate::{room::Room, Result}; @@ -148,31 +151,40 @@ impl WidgetDriver { while let Some(action) = actions.recv().await { match action { Action::SendToWidget(msg) => self.to_widget_tx.send(msg).await.map_err(|_| ())?, - Action::AcquirePermissions(cmd) => { - let obtained = permissions_provider.acquire_permissions(cmd.clone()).await; - let event = Event::PermissionsAcquired(cmd.ok(obtained)); - events_tx.send(event).map_err(|_| ())?; - } - Action::GetOpenId(cmd) => { - let result = cmd.result(matrix_driver.get_open_id().await); - events_tx.send(Event::OpenIdReceived(result)).map_err(|_| ())?; - } - Action::ReadMessageLikeEvent(cmd) => { - let events = matrix_driver - .read_message_like_events(cmd.event_type.clone(), cmd.limit) - .await; - events_tx.send(Event::MatrixEventRead(cmd.result(events))).map_err(|_| ())?; - } - Action::ReadStateEvent(cmd) => { - let events = matrix_driver - .read_state_events(cmd.event_type.clone(), &cmd.state_key) - .await; - events_tx.send(Event::MatrixEventRead(cmd.result(events))).map_err(|_| ())?; - } - Action::SendMatrixEvent(cmd) => { - let SendEventCommand { event_type, state_key, content } = cmd.clone(); - let matrix_event_id = matrix_driver.send(event_type, state_key, content).await; - let event = Event::MatrixEventSent(cmd.result(matrix_event_id)); + Action::MatrixDriverRequest { request_id: id, data } => { + let event = match data { + MatrixDriverRequestData::AcquirePermissions(cmd) => { + let obtained = permissions_provider + .acquire_permissions(cmd.desired_permissions.clone()) + .await; + + Event::PermissionsAcquired(MatrixDriverResponse::ok(id, obtained)) + } + MatrixDriverRequestData::GetOpenId => { + let result = + MatrixDriverResponse::new(id, matrix_driver.get_open_id().await); + Event::OpenIdReceived(result) + } + MatrixDriverRequestData::ReadMessageLikeEvent(cmd) => { + let events = matrix_driver + .read_message_like_events(cmd.event_type.clone(), cmd.limit) + .await; + Event::MatrixEventRead(MatrixDriverResponse::new(id, events)) + } + MatrixDriverRequestData::ReadStateEvent(cmd) => { + let events = matrix_driver + .read_state_events(cmd.event_type.clone(), &cmd.state_key) + .await; + Event::MatrixEventRead(MatrixDriverResponse::new(id, events)) + } + MatrixDriverRequestData::SendMatrixEvent(cmd) => { + let SendEventCommand { event_type, state_key, content } = cmd.clone(); + let matrix_event_id = + matrix_driver.send(event_type, state_key, content).await; + Event::MatrixEventSent(MatrixDriverResponse::new(id, matrix_event_id)) + } + }; + events_tx.send(event).map_err(|_| ())?; } Action::Subscribe => {