matrix_sdk/widget/machine/
from_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::collections::BTreeMap;
16
17use as_variant::as_variant;
18use ruma::{
19    OwnedEventId, OwnedRoomId,
20    api::client::{
21        delayed_events::{delayed_message_event, delayed_state_event, update_delayed_event},
22        error::{ErrorBody, StandardErrorBody},
23    },
24    events::AnyTimelineEvent,
25    serde::Raw,
26};
27use serde::{Deserialize, Serialize};
28use tracing::error;
29
30use super::{
31    MatrixDriverResponse, SendEventRequest, UpdateDelayedEventRequest,
32    driver_req::SendToDeviceRequest,
33};
34use crate::{
35    Error, HttpError, RumaApiError,
36    widget::{StateKeySelector, machine::driver_req::FromMatrixDriverResponse},
37};
38
39#[derive(Deserialize, Debug)]
40#[serde(tag = "action", rename_all = "snake_case", content = "data")]
41pub(super) enum FromWidgetRequest {
42    SupportedApiVersions {},
43    ContentLoaded {},
44    #[serde(rename = "get_openid")]
45    GetOpenId {},
46    #[serde(rename = "org.matrix.msc2876.read_events")]
47    ReadEvent(ReadEventsRequest),
48    SendEvent(SendEventRequest),
49    SendToDevice(SendToDeviceRequest),
50    #[serde(rename = "org.matrix.msc4157.update_delayed_event")]
51    DelayedEventUpdate(UpdateDelayedEventRequest),
52}
53
54/// The full response a client sends to a [`FromWidgetRequest`] in case of an
55/// error.
56#[derive(Serialize)]
57pub(super) struct FromWidgetErrorResponse {
58    error: FromWidgetError,
59}
60
61impl FromWidgetErrorResponse {
62    /// Create a error response to send to the widget from an http error.
63    pub(crate) fn from_http_error(error: HttpError) -> Self {
64        let message = error.to_string();
65        let matrix_api_error = match error {
66            HttpError::Api(error) => {
67                as_variant!(*error, ruma::api::error::FromHttpResponseError::Server(RumaApiError::ClientApi(err)) => err)
68            }
69            _ => None,
70        };
71
72        Self {
73            error: FromWidgetError {
74                message,
75                matrix_api_error: matrix_api_error.and_then(|api_error| match api_error.body {
76                    ErrorBody::Standard(response) => Some(FromWidgetMatrixErrorBody {
77                        http_status: api_error.status_code.as_u16().into(),
78                        response,
79                    }),
80                    _ => None,
81                }),
82            },
83        }
84    }
85
86    /// Create an error response to send to the widget from a Matrix SDK error.
87    pub(crate) fn from_error(error: Error) -> Self {
88        match error {
89            Error::Http(e) => FromWidgetErrorResponse::from_http_error(*e),
90            // For UnknownError's we do not want to have the `unknown error` bit in the message.
91            // Hence we only convert the inner error to a string.
92            Error::UnknownError(e) => FromWidgetErrorResponse::from_string(e.to_string()),
93            _ => FromWidgetErrorResponse::from_string(error.to_string()),
94        }
95    }
96
97    /// Create a error response to send to the widget from a string.
98    pub(crate) fn from_string<S: Into<String>>(error: S) -> Self {
99        Self { error: FromWidgetError { message: error.into(), matrix_api_error: None } }
100    }
101}
102
103/// Serializable section of an error response send by the client as a
104/// response to a [`FromWidgetRequest`].
105#[derive(Serialize)]
106struct FromWidgetError {
107    /// Unspecified error message text that caused this widget action to
108    /// fail.
109    ///
110    /// This is useful to prompt the user on an issue but cannot be used to
111    /// decide on how to deal with the error.
112    message: String,
113
114    /// Optional Matrix error hinting at workarounds for specific errors.
115    #[serde(skip_serializing_if = "Option::is_none")]
116    matrix_api_error: Option<FromWidgetMatrixErrorBody>,
117}
118
119/// Serializable section of a widget response that represents a Matrix error.
120#[derive(Serialize)]
121struct FromWidgetMatrixErrorBody {
122    /// Status code of the http response.
123    http_status: u32,
124
125    /// Standard error response including the `errorcode` and the `error`
126    /// message as defined in the [spec](https://spec.matrix.org/v1.12/client-server-api/#standard-error-response).
127    response: StandardErrorBody,
128}
129
130/// The serializable section of a widget response containing the supported
131/// versions.
132#[derive(Serialize)]
133pub(super) struct SupportedApiVersionsResponse {
134    supported_versions: Vec<ApiVersion>,
135}
136
137impl SupportedApiVersionsResponse {
138    /// The currently supported widget api versions from the rust widget driver.
139    pub(super) fn new() -> Self {
140        Self {
141            supported_versions: vec![
142                ApiVersion::V0_0_1,
143                ApiVersion::V0_0_2,
144                ApiVersion::MSC2762,
145                ApiVersion::MSC2762UpdateState,
146                ApiVersion::MSC2871,
147                ApiVersion::MSC3819,
148            ],
149        }
150    }
151}
152
153#[derive(Serialize)]
154#[allow(dead_code)] // not all variants used right now
155pub(super) enum ApiVersion {
156    /// First stable version.
157    #[serde(rename = "0.0.1")]
158    V0_0_1,
159
160    /// Second stable version.
161    #[serde(rename = "0.0.2")]
162    V0_0_2,
163
164    /// Supports sending and receiving events.
165    #[serde(rename = "org.matrix.msc2762")]
166    MSC2762,
167
168    /// Supports receiving room state with the `update_state` action.
169    #[serde(rename = "org.matrix.msc2762_update_state")]
170    MSC2762UpdateState,
171
172    /// Supports sending approved capabilities back to the widget.
173    #[serde(rename = "org.matrix.msc2871")]
174    MSC2871,
175
176    /// Supports navigating to a URI.
177    #[serde(rename = "org.matrix.msc2931")]
178    MSC2931,
179
180    /// Supports capabilities renegotiation.
181    #[serde(rename = "org.matrix.msc2974")]
182    MSC2974,
183
184    /// Supports reading events in a room (deprecated).
185    #[serde(rename = "org.matrix.msc2876")]
186    MSC2876,
187
188    /// Supports sending and receiving to-device events.
189    #[serde(rename = "org.matrix.msc3819")]
190    MSC3819,
191
192    /// Supports access to the TURN servers.
193    #[serde(rename = "town.robin.msc3846")]
194    MSC3846,
195}
196
197#[derive(Deserialize, Debug)]
198pub(super) struct ReadEventsRequest {
199    #[serde(rename = "type")]
200    pub(super) event_type: String,
201    pub(super) state_key: Option<StateKeySelector>,
202    pub(super) limit: Option<u32>,
203}
204
205#[derive(Debug, Serialize)]
206pub(super) struct ReadEventsResponse {
207    pub(super) events: Vec<Raw<AnyTimelineEvent>>,
208}
209
210#[derive(Serialize, Debug)]
211pub(crate) struct SendEventResponse {
212    /// The room id for the send event.
213    pub(crate) room_id: Option<OwnedRoomId>,
214    /// The event id of the send event. It's optional because if it's a delayed
215    /// event, it does not get the event_id at this point.
216    pub(crate) event_id: Option<OwnedEventId>,
217    /// The `delay_id` generated for this delayed event. Used to interact with
218    /// the delayed event.
219    pub(crate) delay_id: Option<String>,
220}
221
222impl SendEventResponse {
223    pub(crate) fn from_event_id(event_id: OwnedEventId) -> Self {
224        SendEventResponse { room_id: None, event_id: Some(event_id), delay_id: None }
225    }
226    pub(crate) fn set_room_id(&mut self, room_id: OwnedRoomId) {
227        self.room_id = Some(room_id);
228    }
229}
230
231impl From<delayed_message_event::unstable::Response> for SendEventResponse {
232    fn from(val: delayed_message_event::unstable::Response) -> Self {
233        SendEventResponse { room_id: None, event_id: None, delay_id: Some(val.delay_id) }
234    }
235}
236
237impl From<delayed_state_event::unstable::Response> for SendEventResponse {
238    fn from(val: delayed_state_event::unstable::Response) -> Self {
239        SendEventResponse { room_id: None, event_id: None, delay_id: Some(val.delay_id) }
240    }
241}
242
243/// A wrapper type for the empty okay response from
244/// [`update_delayed_event`](update_delayed_event::unstable::Response)
245/// which derives Serialize. (The response struct from Ruma does not derive
246/// serialize)
247/// This is intentionally an empty tuple struct (not a unit struct), so that it
248/// serializes to `{}` instead of `Null` when returned to the widget as json.
249#[derive(Serialize, Debug)]
250pub(crate) struct UpdateDelayedEventResponse {}
251impl From<update_delayed_event::unstable::Response> for UpdateDelayedEventResponse {
252    fn from(_: update_delayed_event::unstable::Response) -> Self {
253        Self {}
254    }
255}
256
257/// Response for a send-to-device request.
258/// The failure map contains recipients that didn't receive the content due to:
259/// - Recipient devices not being found
260/// - Encryption failures (e.g., missing one-time keys)
261/// - Network/Server errors during sending
262#[derive(Serialize, Debug, Default)]
263pub(crate) struct SendToDeviceEventResponse {
264    #[serde(skip_serializing_if = "BTreeMap::is_empty")]
265    pub failures: BTreeMap<String, Vec<String>>,
266}
267
268impl FromMatrixDriverResponse for SendToDeviceEventResponse {
269    fn from_response(matrix_driver_response: MatrixDriverResponse) -> Option<Self> {
270        match matrix_driver_response {
271            MatrixDriverResponse::ToDeviceSent(resp) => Some(Self { failures: resp.failures }),
272            _ => {
273                error!("bug in MatrixDriver, received wrong event response");
274                None
275            }
276        }
277    }
278}