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::{events::AnyTimelineEvent, serde::Raw};
18use serde::{de::DeserializeOwned, Deserialize, Serialize};
19use serde_json::value::RawValue as RawJsonValue;
20use tracing::error;
21
22use super::{openid::OpenIdResponse, Action, ToWidgetRequestMeta, WidgetMachine};
23use crate::widget::Capabilities;
24
25/// A handle to a pending `toWidget` request.
26pub(crate) struct ToWidgetRequestHandle<'m, T> {
27    request_meta: Option<&'m mut ToWidgetRequestMeta>,
28    _phantom: PhantomData<fn() -> T>,
29}
30
31impl<'m, T> ToWidgetRequestHandle<'m, T>
32where
33    T: DeserializeOwned,
34{
35    pub(crate) fn new(request_meta: &'m mut ToWidgetRequestMeta) -> Self {
36        Self { request_meta: Some(request_meta), _phantom: PhantomData }
37    }
38
39    pub(crate) fn null() -> Self {
40        Self { request_meta: None, _phantom: PhantomData }
41    }
42
43    pub(crate) fn then(
44        self,
45        response_handler: impl FnOnce(T, &mut WidgetMachine) -> Vec<Action> + Send + 'static,
46    ) {
47        if let Some(request_meta) = self.request_meta {
48            request_meta.response_fn = Some(Box::new(move |raw_response_data, machine| {
49                match serde_json::from_str(raw_response_data.get()) {
50                    Ok(response_data) => response_handler(response_data, machine),
51                    Err(e) => {
52                        error!("Failed to deserialize toWidget response: {e}");
53                        Vec::new()
54                    }
55                }
56            }));
57        }
58    }
59}
60
61#[derive(Deserialize, Debug)]
62#[serde(rename_all = "camelCase")]
63pub(super) struct ToWidgetResponse {
64    /// The action from the original request.
65    pub(super) action: String,
66
67    /// The data from the original request.
68    #[allow(dead_code)]
69    #[serde(rename = "data")]
70    pub(super) request_data: Box<RawJsonValue>,
71
72    /// The response data.
73    #[serde(rename = "response")]
74    pub(super) response_data: Box<RawJsonValue>,
75}
76
77/// A request that the driver can send to the widget.
78///
79/// In postmessage interface terms: an `"api": "toWidget"` message.
80pub(crate) trait ToWidgetRequest: Serialize {
81    const ACTION: &'static str;
82    type ResponseData: DeserializeOwned;
83}
84
85/// Request the widget to send the list of capabilities that it wants to have.
86#[derive(Serialize)]
87pub(super) struct RequestCapabilities {}
88
89impl ToWidgetRequest for RequestCapabilities {
90    const ACTION: &'static str = "capabilities";
91    type ResponseData = RequestCapabilitiesResponse;
92}
93
94#[derive(Deserialize)]
95pub(super) struct RequestCapabilitiesResponse {
96    pub(super) capabilities: Capabilities,
97}
98
99/// Notify the widget that the list of the granted capabilities has changed.
100#[derive(Serialize)]
101pub(super) struct NotifyCapabilitiesChanged {
102    pub(super) requested: Capabilities,
103    pub(super) approved: Capabilities,
104}
105
106impl ToWidgetRequest for NotifyCapabilitiesChanged {
107    const ACTION: &'static str = "notify_capabilities";
108    type ResponseData = Empty;
109}
110
111/// Notify the widget that the OpenID credentials changed.
112#[derive(Serialize)]
113pub(crate) struct NotifyOpenIdChanged(pub(crate) OpenIdResponse);
114
115impl ToWidgetRequest for NotifyOpenIdChanged {
116    const ACTION: &'static str = "openid_credentials";
117    type ResponseData = OpenIdResponse;
118}
119
120/// Notify the widget that we received a new matrix event.
121/// This is a "response" to the widget subscribing to the events in the room.
122#[derive(Serialize)]
123#[serde(transparent)]
124pub(crate) struct NotifyNewMatrixEvent(pub(crate) Raw<AnyTimelineEvent>);
125
126impl ToWidgetRequest for NotifyNewMatrixEvent {
127    const ACTION: &'static str = "send_event";
128    type ResponseData = Empty;
129}
130
131#[derive(Deserialize)]
132pub(crate) struct Empty {}