7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 1 | // Copyright 2025 The Matrix.org Foundation C.I.C. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 2 | // |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 4 | // you may not use this file except in compliance with the License. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 5 | // You may obtain a copy of the License at |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 6 | // |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 8 | // |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 9 | // Unless required by applicable law or agreed to in writing, software |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 12 | // See the License for that specific language governing permissions and |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 13 | // limitations under the License. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 14 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 15 | use std::sync::{Arc, Mutex}; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 16 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 17 | use language_tags::LanguageTag; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 18 | use matrix_sdk::widget::{MessageLikeEventFilter, StateEventFilter, ToDeviceEventFilter}; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 19 | use matrix_sdk_common::{SendOutsideWasm, SyncOutsideWasm}; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 20 | use ruma::events::MessageLikeEventType; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 21 | use tracing::error; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 22 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 23 | use crate::{room::Room, runtime::get_runtime_handle}; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 24 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 25 | #[derive(uniffi::Record)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 26 | pub struct WidgetDriverAndHandle { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 27 | pub driver: Arc<WidgetDriver>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 28 | pub handle: Arc<WidgetDriverHandle>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 29 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 30 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 31 | #[matrix_sdk_ffi_macros::export] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 32 | pub fn make_widget_driver(settings: WidgetSettings) -> Result<WidgetDriverAndHandle, ParseError> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 33 | let (driver, handle) = matrix_sdk::widget::WidgetDriver::new(settings.try_into()?); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 34 | Ok(WidgetDriverAndHandle { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 35 | driver: Arc::new(WidgetDriver(Mutex::new(Some(driver)))), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 36 | handle: Arc::new(WidgetDriverHandle(handle)), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 37 | }) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 38 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 39 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 40 | /// An object that handles all interactions of a widget living inside a webview |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 41 | /// or IFrame with the Matrix world. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 42 | #[derive(uniffi::Object)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 43 | pub struct WidgetDriver(Mutex<Option<matrix_sdk::widget::WidgetDriver>>); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 44 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 45 | #[matrix_sdk_ffi_macros::export] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 46 | impl WidgetDriver { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 47 | pub async fn run( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 48 | &self, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 49 | room: Arc<Room>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 50 | capabilities_provider: Box<dyn WidgetCapabilitiesProvider>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 51 | ) { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 52 | let Some(driver) = self.0.lock().unwrap().take() else { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 53 | error!("Can't call run multiple times on a WidgetDriver"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 54 | return; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 55 | }; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 56 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 57 | let capabilities_provider = CapabilitiesProviderWrap(capabilities_provider.into()); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 58 | if let Err(()) = driver.run((*room.inner).clone(), capabilities_provider).await { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 59 | // TODO |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 60 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 61 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 62 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 63 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 64 | /// Information about a widget. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 65 | #[derive(uniffi::Record, Clone)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 66 | pub struct WidgetSettings { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 67 | /// Widget's unique identifier. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 68 | pub widget_id: String, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 69 | /// Whether or not the widget should be initialized on load message |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 70 | /// (`ContentLoad` message), or upon creation/attaching of the widget to |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 71 | /// the SDK's state machine that drives the API. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 72 | pub init_after_content_load: bool, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 73 | /// This contains the url from the widget state event. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 74 | /// In this url placeholders can be used to pass information from the client |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 75 | /// to the widget. Possible values are: `$widgetId`, `$parentUrl`, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 76 | /// `$userId`, `$lang`, `$fontScale`, `$analyticsID`. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 77 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 78 | /// # Examples |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 79 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 80 | /// e.g `http://widget.domain?username=$userId` |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 81 | /// will become: `http://widget.domain?username=@user_matrix_id:server.domain`. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 82 | raw_url: String, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 83 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 84 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 85 | impl TryFrom<WidgetSettings> for matrix_sdk::widget::WidgetSettings { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 86 | type Error = ParseError; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 87 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 88 | fn try_from(value: WidgetSettings) -> Result<Self, Self::Error> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 89 | let WidgetSettings { widget_id, init_after_content_load, raw_url } = value; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 90 | Ok(matrix_sdk::widget::WidgetSettings::new(widget_id, init_after_content_load, &raw_url)?) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 91 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 92 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 93 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 94 | impl From<matrix_sdk::widget::WidgetSettings> for WidgetSettings { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 95 | fn from(value: matrix_sdk::widget::WidgetSettings) -> Self { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 96 | WidgetSettings { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 97 | widget_id: value.widget_id().to_owned(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 98 | init_after_content_load: value.init_on_content_load(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 99 | raw_url: value.raw_url().to_string(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 100 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 101 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 102 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 103 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 104 | /// Create the actual url that can be used to setup the WebView or IFrame |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 105 | /// that contains the widget. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 106 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 107 | /// # Arguments |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 108 | /// * `widget_settings` - The widget settings to generate the url for. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 109 | /// * `room` - A Matrix room which is used to query the logged in username |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 110 | /// * `props` - Properties from the client that can be used by a widget to adapt |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 111 | /// to the client. e.g. language, font-scale... |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 112 | #[matrix_sdk_ffi_macros::export] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 113 | pub async fn generate_webview_url( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 114 | widget_settings: WidgetSettings, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 115 | room: Arc<Room>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 116 | props: ClientProperties, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 117 | ) -> Result<String, ParseError> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 118 | Ok(matrix_sdk::widget::WidgetSettings::generate_webview_url( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 119 | &widget_settings.clone().try_into()?, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 120 | &room.inner, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 121 | props.into(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 122 | ) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 123 | .await |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 124 | .map(|url| url.to_string())?) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 125 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 126 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 127 | /// `WidgetSettings` are usually created from a state event. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 128 | /// (currently unimplemented) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 129 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 130 | /// In some cases the client wants to create custom `WidgetSettings` |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 131 | /// for specific rooms based on other conditions. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 132 | /// This function returns a `WidgetSettings` object which can be used |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 133 | /// to setup a widget using `run_client_widget_api` |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 134 | /// and to generate the correct url for the widget. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 135 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 136 | /// # Arguments |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 137 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 138 | /// * `props` - A struct containing the configuration parameters for a element |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 139 | /// call widget. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 140 | #[matrix_sdk_ffi_macros::export] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 141 | pub fn new_virtual_element_call_widget( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 142 | props: matrix_sdk::widget::VirtualElementCallWidgetProperties, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 143 | config: matrix_sdk::widget::VirtualElementCallWidgetConfig, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 144 | ) -> Result<WidgetSettings, ParseError> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 145 | Ok(matrix_sdk::widget::WidgetSettings::new_virtual_element_call_widget(props, config) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 146 | .map(|w| w.into())?) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 147 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 148 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 149 | /// The Capabilities required to run a element call widget. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 150 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 151 | /// This is intended to be used in combination with: `acquire_capabilities` of |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 152 | /// the `CapabilitiesProvider`. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 153 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 154 | /// `acquire_capabilities` can simply return the `WidgetCapabilities` from this |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 155 | /// function. Even if there are non intersecting permissions to what the widget |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 156 | /// requested. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 157 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 158 | /// Editing and extending the capabilities from this function is also possible, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 159 | /// but should only be done as temporal workarounds until this function is |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 160 | /// adjusted |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 161 | #[matrix_sdk_ffi_macros::export] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 162 | pub fn get_element_call_required_permissions( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 163 | own_user_id: String, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 164 | own_device_id: String, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 165 | ) -> WidgetCapabilities { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 166 | use ruma::events::StateEventType; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 167 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 168 | let read_send = vec![ |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 169 | // To read and send rageshake requests from other room members |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 170 | WidgetEventFilter::MessageLikeWithType { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 171 | event_type: "org.matrix.rageshake_request".to_owned(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 172 | }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 173 | // To read and send encryption keys |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 174 | WidgetEventFilter::ToDevice { event_type: "io.element.call.encryption_keys".to_owned() }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 175 | // TODO change this to the appropriate to-device version once ready |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 176 | // remove this once all matrixRTC call apps supports to-device encryption. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 177 | WidgetEventFilter::MessageLikeWithType { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 178 | event_type: "io.element.call.encryption_keys".to_owned(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 179 | }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 180 | // To read and send custom EC reactions. They are different to normal `m.reaction` |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 181 | // because they can be send multiple times to the same event. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 182 | WidgetEventFilter::MessageLikeWithType { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 183 | event_type: "io.element.call.reaction".to_owned(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 184 | }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 185 | // This allows send raise hand reactions. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 186 | WidgetEventFilter::MessageLikeWithType { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 187 | event_type: MessageLikeEventType::Reaction.to_string(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 188 | }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 189 | // This allows to detect if someone does not raise their hand anymore. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 190 | WidgetEventFilter::MessageLikeWithType { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 191 | event_type: MessageLikeEventType::RoomRedaction.to_string(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 192 | }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 193 | // This allows declining an incoming call and detect if someone declines a call. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 194 | WidgetEventFilter::MessageLikeWithType { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 195 | event_type: MessageLikeEventType::RtcDecline.to_string(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 196 | }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 197 | ]; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 198 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 199 | WidgetCapabilities { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 200 | read: vec![ |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 201 | // To compute the current state of the matrixRTC session. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 202 | WidgetEventFilter::StateWithType { event_type: StateEventType::CallMember.to_string() }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 203 | // To display the name of the room. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 204 | WidgetEventFilter::StateWithType { event_type: StateEventType::RoomName.to_string() }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 205 | // To detect leaving/kicked room members during a call. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 206 | WidgetEventFilter::StateWithType { event_type: StateEventType::RoomMember.to_string() }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 207 | // To decide whether to encrypt the call streams based on the room encryption setting. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 208 | WidgetEventFilter::StateWithType { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 209 | event_type: StateEventType::RoomEncryption.to_string(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 210 | }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 211 | // This allows the widget to check the room version, so it can know about |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 212 | // version-specific auth rules (namely MSC3779). |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 213 | WidgetEventFilter::StateWithType { event_type: StateEventType::RoomCreate.to_string() }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 214 | ] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 215 | .into_iter() |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 216 | .chain(read_send.clone()) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 217 | .collect(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 218 | send: vec, with no leading underscore. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 240 | WidgetEventFilter::StateWithTypeAndStateKey { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 241 | event_type: StateEventType::CallMember.to_string(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 242 | state_key: format!("{own_user_id}_{own_device_id}"), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 243 | }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 244 | // Same as above for [MSC3779] and [MSC4143](https://github.com/matrix-org/matrix-spec-proposals/pull/4143), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 245 | // with application suffix |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 246 | WidgetEventFilter::StateWithTypeAndStateKey { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 247 | event_type: StateEventType::CallMember.to_string(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 248 | state_key: format!("{own_user_id}_{own_device_id}_m.call"), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 249 | }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 250 | // The same as above but with an underscore. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 251 | // To work around the issue that state events starting with `@` have to be Matrix id's |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 252 | // but we use mxId+deviceId. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 253 | WidgetEventFilter::StateWithTypeAndStateKey { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 254 | event_type: StateEventType::CallMember.to_string(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 255 | state_key: format!("_{own_user_id}_{own_device_id}"), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 256 | }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 257 | // Same as above for [MSC4143], with application suffix |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 258 | WidgetEventFilter::StateWithTypeAndStateKey { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 259 | event_type: StateEventType::CallMember.to_string(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 260 | state_key: format!("_{own_user_id}_{own_device_id}_m.call"), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 261 | }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 262 | ] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 263 | .into_iter() |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 264 | .chain(read_send) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 265 | .collect(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 266 | requires_client: true, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 267 | update_delayed_event: true, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 268 | send_delayed_event: true, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 269 | download_files: true, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 270 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 271 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 272 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 273 | #[derive(uniffi::Record)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 274 | pub struct ClientProperties { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 275 | /// The client_id provides the widget with the option to behave differently |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 276 | /// for different clients. e.g org.example.ios. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 277 | client_id: String, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 278 | /// The language tag the client is set to e.g. en-us. (Undefined and invalid |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 279 | /// becomes: `en-US`) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 280 | language_tag: Option<String>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 281 | /// A string describing the theme (dark, light) or org.example.dark. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 282 | /// (default: `light`) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 283 | theme: Option<String>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 284 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 285 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 286 | impl From<ClientProperties> for matrix_sdk::widget::ClientProperties { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 287 | fn from(value: ClientProperties) -> Self { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 288 | let ClientProperties { client_id, language_tag, theme } = value; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 289 | let language_tag = language_tag.and_then(|l| LanguageTag::parse(&l).ok()); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 290 | Self::new(&client_id, language_tag, theme) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 291 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 292 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 293 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 294 | /// A handle that encapsulates the communication between a widget driver and the |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 295 | /// corresponding widget (inside a webview or IFrame). |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 296 | #[derive(uniffi::Object)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 297 | pub struct WidgetDriverHandle(matrix_sdk::widget::WidgetDriverHandle); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 298 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 299 | #[matrix_sdk_ffi_macros::export] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 300 | impl WidgetDriverHandle { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 301 | /// Receive a message from the widget driver. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 302 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 303 | /// The message must be passed on to the widget. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 304 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 305 | /// Returns `None` if the widget driver is no longer running. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 306 | pub async fn recv(&self) -> Option<String> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 307 | self.0.recv().await |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 308 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 309 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 310 | //// Send a message from the widget to the widget driver. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 311 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 312 | /// Returns `false` if the widget driver is no longer running. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 313 | pub async fn send(&self, msg: String) -> bool { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 314 | self.0.send(msg).await |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 315 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 316 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 317 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 318 | /// Capabilities that a widget can request from a client. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 319 | #[derive(uniffi::Record)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 320 | pub struct WidgetCapabilities { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 321 | /// Types of the messages that a widget wants to be able to fetch. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 322 | pub read: Vec<WidgetEventFilter>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 323 | /// Types of the messages that a widget wants to be able to send. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 324 | pub send: Vec<WidgetEventFilter>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 325 | /// If this capability is requested by the widget, it can not operate |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 326 | /// separately from the Matrix client. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 327 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 328 | /// This means clients should not offer to open the widget in a separate |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 329 | /// browser/tab/webview that is not connected to the postmessage widget-api. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 330 | pub requires_client: bool, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 331 | /// This allows the widget to ask the client to update delayed events. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 332 | pub update_delayed_event: bool, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 333 | /// This allows the widget to send events with a delay. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 334 | pub send_delayed_event: bool, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 335 | /// This allows the widget to download files (avatars) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 336 | pub download_files: bool, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 337 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 338 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 339 | impl From<WidgetCapabilities> for matrix_sdk::widget::Capabilities { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 340 | fn from(value: WidgetCapabilities) -> Self { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 341 | Self { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 342 | read: value.read.into_iter().map(Into::into).collect(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 343 | send: value.send.into_iter().map(Into::into).collect(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 344 | requires_client: value.requires_client, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 345 | update_delayed_event: value.update_delayed_event, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 346 | send_delayed_event: value.send_delayed_event, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 347 | download_file: value.download_files, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 348 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 349 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 350 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 351 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 352 | impl From<matrix_sdk::widget::Capabilities> for WidgetCapabilities { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 353 | fn from(value: matrix_sdk::widget::Capabilities) -> Self { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 354 | Self { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 355 | read: value.read.into_iter().map(Into::into).collect(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 356 | send: value.send.into_iter().map(Into::into).collect(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 357 | requires_client: value.requires_client, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 358 | update_delayed_event: value.update_delayed_event, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 359 | send_delayed_event: value.send_delayed_event, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 360 | download_files: value.download_file, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 361 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 362 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 363 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 364 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 365 | /// Different kinds of filters that could be applied to the timeline events. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 366 | #[derive(uniffi::Enum, Clone)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 367 | pub enum WidgetEventFilter { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 368 | /// Matches message-like events with the given `type`. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 369 | MessageLikeWithType { event_type: String }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 370 | /// Matches `m.room.message` events with the given `msgtype`. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 371 | RoomMessageWithMsgtype { msgtype: String }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 372 | /// Matches state events with the given `type`, regardless of `state_key`. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 373 | StateWithType { event_type: String }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 374 | /// Matches state events with the given `type` and `state_key`. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 375 | StateWithTypeAndStateKey { event_type: String, state_key: String }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 376 | /// Matches to-device events with the given `event_type`. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 377 | ToDevice { event_type: String }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 378 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 379 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 380 | impl From<WidgetEventFilter> for matrix_sdk::widget::Filter { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 381 | fn from(value: WidgetEventFilter) -> Self { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 382 | match value { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 383 | WidgetEventFilter::MessageLikeWithType { event_type } => { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 384 | Self::MessageLike(MessageLikeEventFilter::WithType(event_type.into())) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 385 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 386 | WidgetEventFilter::RoomMessageWithMsgtype { msgtype } => { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 387 | Self::MessageLike(MessageLikeEventFilter::RoomMessageWithMsgtype(msgtype)) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 388 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 389 | WidgetEventFilter::StateWithType { event_type } => { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 390 | Self::State(StateEventFilter::WithType(event_type.into())) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 391 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 392 | WidgetEventFilter::StateWithTypeAndStateKey { event_type, state_key } => { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 393 | Self::State(StateEventFilter::WithTypeAndStateKey(event_type.into(), state_key)) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 394 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 395 | WidgetEventFilter::ToDevice { event_type } => { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 396 | Self::ToDevice(ToDeviceEventFilter { event_type: event_type.into() }) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 397 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 398 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 399 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 400 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 401 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 402 | impl From<matrix_sdk::widget::Filter> for WidgetEventFilter { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 403 | fn from(value: matrix_sdk::widget::Filter) -> Self { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 404 | use matrix_sdk::widget::Filter as F; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 405 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 406 | match value { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 407 | F::MessageLike(MessageLikeEventFilter::WithType(event_type)) => { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 408 | Self::MessageLikeWithType { event_type: event_type.to_string() } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 409 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 410 | F::MessageLike(MessageLikeEventFilter::RoomMessageWithMsgtype(msgtype)) => { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 411 | Self::RoomMessageWithMsgtype { msgtype } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 412 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 413 | F::State(StateEventFilter::WithType(event_type)) => { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 414 | Self::StateWithType { event_type: event_type.to_string() } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 415 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 416 | F::State(StateEventFilter::WithTypeAndStateKey(event_type, state_key)) => { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 417 | Self::StateWithTypeAndStateKey { event_type: event_type.to_string(), state_key } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 418 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 419 | F::ToDevice(ToDeviceEventFilter { event_type }) => { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 420 | Self::ToDevice { event_type: event_type.to_string() } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 421 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 422 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 423 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 424 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 425 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 426 | #[matrix_sdk_ffi_macros::export(callback_interface)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 427 | pub trait WidgetCapabilitiesProvider: SendOutsideWasm + SyncOutsideWasm { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 428 | fn acquire_capabilities(&self, capabilities: WidgetCapabilities) -> WidgetCapabilities; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 429 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 430 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 431 | struct CapabilitiesProviderWrap(Arc<dyn WidgetCapabilitiesProvider>); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 432 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 433 | impl matrix_sdk::widget::CapabilitiesProvider for CapabilitiesProviderWrap { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 434 | async fn acquire_capabilities( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 435 | &self, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 436 | capabilities: matrix_sdk::widget::Capabilities, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 437 | ) -> matrix_sdk::widget::Capabilities { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 438 | let this = self.0.clone(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 439 | // This could require a prompt to the user. Ideally the callback |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 440 | // interface would just be async, but that's not supported yet so use |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 441 | // one of tokio's blocking task threads instead. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 442 | get_runtime_handle() |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 443 | .spawn_blocking(move || this.acquire_capabilities(capabilities.into()).into()) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 444 | .await |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 445 | // propagate panics from the blocking task |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 446 | .unwrap() |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 447 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 448 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 449 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 450 | #[derive(Debug, thiserror::Error, uniffi::Error)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 451 | #[uniffi(flat_error)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 452 | pub enum ParseError { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 453 | #[error("empty host")] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 454 | EmptyHost, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 455 | #[error("invalid international domain name")] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 456 | IdnaError, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 457 | #[error("invalid port number")] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 458 | InvalidPort, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 459 | #[error("invalid IPv4 address")] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 460 | InvalidIpv4Address, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 461 | #[error("invalid IPv6 address")] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 462 | InvalidIpv6Address, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 463 | #[error("invalid domain character")] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 464 | InvalidDomainCharacter, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 465 | #[error("relative URL without a base")] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 466 | RelativeUrlWithoutBase, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 467 | #[error("relative URL with a cannot-be-a-base base")] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 468 | RelativeUrlWithCannotBeABaseBase, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 469 | #[error("a cannot-be-a-base URL doesn’t have a host to set")] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 470 | SetHostOnCannotBeABaseUrl, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 471 | #[error("URLs more than 4 GB are not supported")] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 472 | Overflow, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 473 | #[error("unknown URL parsing error")] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 474 | Other, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 475 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 476 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 477 | impl From<url::ParseError> for ParseError { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 478 | fn from(value: url::ParseError) -> Self { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 479 | match value { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 480 | url::ParseError::EmptyHost => Self::EmptyHost, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 481 | url::ParseError::IdnaError => Self::IdnaError, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 482 | url::ParseError::InvalidPort => Self::InvalidPort, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 483 | url::ParseError::InvalidIpv4Address => Self::InvalidIpv4Address, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 484 | url::ParseError::InvalidIpv6Address => Self::InvalidIpv6Address, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 485 | url::ParseError::InvalidDomainCharacter => Self::InvalidDomainCharacter, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 486 | url::ParseError::RelativeUrlWithoutBase => Self::RelativeUrlWithoutBase, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 487 | url::ParseError::RelativeUrlWithCannotBeABaseBase => { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 488 | Self::RelativeUrlWithCannotBeABaseBase |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 489 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 490 | url::ParseError::SetHostOnCannotBeABaseUrl => Self::SetHostOnCannotBeABaseUrl, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 491 | url::ParseError::Overflow => Self::Overflow, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 492 | _ => Self::Other, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 493 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 494 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 495 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 496 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 497 | #[cfg(test)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 498 | mod tests { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 499 | use matrix_sdk::widget::Capabilities; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 500 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 501 | use super::get_element_call_required_permissions; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 502 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 503 | #[test] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 504 | fn element_call_permissions_are_correct() { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 505 | let widget_cap = get_element_call_required_permissions( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 506 | "@my_user:my_domain.org".to_owned(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 507 | "ABCDEFGHI".to_owned(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 508 | ); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 509 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 510 | // We test two things: |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 511 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 512 | // Converting the WidgetCapability (ffi struct) to Capabilities (rust sdk |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 513 | // struct) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 514 | let cap = Into::<Capabilities>::into(widget_cap); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 515 | // Converting Capabilities (rust sdk struct) to a json list. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 516 | let cap_json_repr = serde_json::to_string(&cap).unwrap(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 517 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 518 | // Converting to a Vec<String> allows to check if the required elements exist |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 519 | // without breaking the test each time the order of permissions might |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 520 | // change. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 521 | let permission_array: Vec<String> = serde_json::from_str(&cap_json_repr).unwrap(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 522 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 523 | let cap_assert = |capability: &str| { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 524 | assert!( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 525 | permission_array.contains(&capability.to_owned()), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 526 | "The \"{capability}\" capability was missing from the element call capability list." |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 527 | ); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 528 | }; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 529 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 530 | cap_assert("io.element.requires_client"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 531 | cap_assert("org.matrix.msc4157.update_delayed_event"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 532 | cap_assert("org.matrix.msc4157.send.delayed_event"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 533 | cap_assert("org.matrix.msc2762.receive.state_event:org.matrix.msc3401.call.member"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 534 | cap_assert("org.matrix.msc2762.receive.state_event:m.room.name"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 535 | cap_assert("org.matrix.msc2762.receive.state_event:m.room.member"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 536 | cap_assert("org.matrix.msc2762.receive.state_event:m.room.encryption"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 537 | cap_assert("org.matrix.msc2762.receive.event:org.matrix.rageshake_request"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 538 | cap_assert("org.matrix.msc2762.receive.event:io.element.call.encryption_keys"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 539 | cap_assert("org.matrix.msc2762.receive.state_event:m.room.create"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 540 | cap_assert( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 541 | "org.matrix.msc2762.send.state_event:org.matrix.msc3401.call.member#@my_user:my_domain.org", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 542 | ); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 543 | cap_assert( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 544 | "org.matrix.msc2762.send.state_event:org.matrix.msc3401.call.member#@my_user:my_domain.org_ABCDEFGHI", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 545 | ); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 546 | cap_assert( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 547 | "org.matrix.msc2762.send.state_event:org.matrix.msc3401.call.member#@my_user:my_domain.org_ABCDEFGHI_m.call", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 548 | ); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 549 | cap_assert( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 550 | "org.matrix.msc2762.send.state_event:org.matrix.msc3401.call.member#_@my_user:my_domain.org_ABCDEFGHI", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 551 | ); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 552 | cap_assert( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 553 | "org.matrix.msc2762.send.state_event:org.matrix.msc3401.call.member#_@my_user:my_domain.org_ABCDEFGHI_m.call", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 554 | ); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 555 | cap_assert("org.matrix.msc2762.send.event:org.matrix.rageshake_request"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 556 | cap_assert("org.matrix.msc2762.send.event:io.element.call.encryption_keys"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 557 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 558 | // RTC decline |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 559 | cap_assert("org.matrix.msc2762.receive.event:org.matrix.msc4310.rtc.decline"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 560 | cap_assert("org.matrix.msc2762.send.event:org.matrix.msc4310.rtc.decline"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 561 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 562 | // Download avatars |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 563 | cap_assert("org.matrix.msc4039.download_file"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 564 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 565 | } |