matrix_sdk/widget/machine/
to_widget.rs

1// Copyright 2023 The Matrix.org Foundation C.I.C.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::marker::PhantomData;
16
17use ruma::{
18    events::{AnyStateEvent, AnyTimelineEvent, AnyToDeviceEvent},
19    serde::Raw,
20};
21use serde::{Deserialize, Serialize, de::DeserializeOwned};
22use serde_json::value::RawValue as RawJsonValue;
23use tracing::error;
24
25use super::{Action, ToWidgetRequestMeta, WidgetMachine, openid::OpenIdResponse};
26use crate::widget::Capabilities;
27
28/// A handle to a pending `toWidget` request.
29pub(crate) struct ToWidgetRequestHandle<'m, T> {
30    request_meta: &'m mut ToWidgetRequestMeta,
31    _phantom: PhantomData<fn() -> T>,
32}
33
34impl<'m, T> ToWidgetRequestHandle<'m, T>
35where
36    T: DeserializeOwned,
37{
38    pub(crate) fn new(request_meta: &'m mut ToWidgetRequestMeta) -> Self {
39        Self { request_meta, _phantom: PhantomData }
40    }
41
42    pub(crate) fn add_response_handler(
43        self,
44        response_handler: impl FnOnce(T, &mut WidgetMachine) -> Vec<Action> + Send + 'static,
45    ) {
46        self.request_meta.response_fn = Some(Box::new(move |raw_response_data, machine| {
47            match serde_json::from_str(raw_response_data.get()) {
48                Ok(response_data) => response_handler(response_data, machine),
49                Err(e) => {
50                    error!("Failed to deserialize toWidget response: {e}");
51                    Vec::new()
52                }
53            }
54        }));
55    }
56}
57
58#[derive(Deserialize, Debug)]
59#[serde(rename_all = "camelCase")]
60pub(super) struct ToWidgetResponse {
61    /// The action from the original request.
62    pub(super) action: String,
63
64    /// The data from the original request.
65    #[allow(dead_code)]
66    #[serde(rename = "data")]
67    pub(super) request_data: Box<RawJsonValue>,
68
69    /// The response data.
70    #[serde(rename = "response")]
71    pub(super) response_data: Box<RawJsonValue>,
72}
73
74/// A request that the driver can send to the widget.
75///
76/// In postmessage interface terms: an `"api": "toWidget"` message.
77pub(crate) trait ToWidgetRequest: Serialize {
78    const ACTION: &'static str;
79    type ResponseData: DeserializeOwned;
80}
81
82/// Request the widget to send the list of capabilities that it wants to have.
83#[derive(Serialize)]
84pub(super) struct RequestCapabilities {}
85
86impl ToWidgetRequest for RequestCapabilities {
87    const ACTION: &'static str = "capabilities";
88    type ResponseData = RequestCapabilitiesResponse;
89}
90
91#[derive(Deserialize)]
92pub(super) struct RequestCapabilitiesResponse {
93    pub(super) capabilities: Capabilities,
94}
95
96/// Notify the widget that the list of the granted capabilities has changed.
97#[derive(Serialize)]
98pub(super) struct NotifyCapabilitiesChanged {
99    pub(super) requested: Capabilities,
100    pub(super) approved: Capabilities,
101}
102
103impl ToWidgetRequest for NotifyCapabilitiesChanged {
104    const ACTION: &'static str = "notify_capabilities";
105    type ResponseData = Empty;
106}
107
108/// Notify the widget that the OpenID credentials changed.
109#[derive(Serialize)]
110pub(crate) struct NotifyOpenIdChanged(pub(crate) OpenIdResponse);
111
112impl ToWidgetRequest for NotifyOpenIdChanged {
113    const ACTION: &'static str = "openid_credentials";
114    type ResponseData = OpenIdResponse;
115}
116
117/// Notify the widget that we received a new Matrix event.
118/// This is a "response" to the widget subscribing to the events in the room.
119#[derive(Serialize)]
120#[serde(transparent)]
121pub(crate) struct NotifyNewMatrixEvent(pub(crate) Raw<AnyTimelineEvent>);
122
123impl ToWidgetRequest for NotifyNewMatrixEvent {
124    const ACTION: &'static str = "send_event";
125    type ResponseData = Empty;
126}
127
128/// Notify the widget that room state has changed.
129/// This is a "response" to the widget subscribing to the events in the room.
130#[derive(Serialize)]
131pub(crate) struct NotifyStateUpdate {
132    pub(super) state: Vec<Raw<AnyStateEvent>>,
133}
134
135impl ToWidgetRequest for NotifyStateUpdate {
136    const ACTION: &'static str = "update_state";
137    type ResponseData = Empty;
138}
139
140#[derive(Deserialize)]
141pub(crate) struct Empty {}
142
143/// Notify the widget that we received a new Matrix to-device message.
144/// This is a "response" to the widget subscribing to the to-device messages.
145#[derive(Serialize)]
146#[serde(transparent)]
147pub(crate) struct NotifyNewToDeviceMessage(pub(crate) Raw<AnyToDeviceEvent>);
148
149impl ToWidgetRequest for NotifyNewToDeviceMessage {
150    const ACTION: &'static str = "send_to_device";
151    type ResponseData = Empty;
152}