mirror of
https://github.com/matrix-org/matrix-rust-sdk.git
synced 2026-05-19 14:19:06 -04:00
ffi: add bindings for App
This commit is contained in:
@@ -29,7 +29,7 @@ eyeball-im = { workspace = true }
|
||||
extension-trait = "1.0.1"
|
||||
futures-core = { workspace = true }
|
||||
futures-util = { workspace = true }
|
||||
matrix-sdk-ui = { path = "../../crates/matrix-sdk-ui", default-features = false, features = ["e2e-encryption", "experimental-room-list", "experimental-encryption-sync", "experimental-notification-client"] }
|
||||
matrix-sdk-ui = { path = "../../crates/matrix-sdk-ui", default-features = false, features = ["e2e-encryption", "experimental-room-list", "experimental-encryption-sync", "experimental-notification-client", "experimental-app"] }
|
||||
mime = "0.3.16"
|
||||
# FIXME: we currently can't feature flag anything in the api.udl, therefore we must enforce experimental-sliding-sync being exposed here..
|
||||
# see https://github.com/matrix-org/matrix-rust-sdk/issues/1014
|
||||
|
||||
110
bindings/matrix-sdk-ffi/src/app.rs
Normal file
110
bindings/matrix-sdk-ffi/src/app.rs
Normal file
@@ -0,0 +1,110 @@
|
||||
// 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 that specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::{fmt::Debug, sync::Arc};
|
||||
|
||||
use futures_util::{pin_mut, StreamExt as _};
|
||||
use matrix_sdk::Client;
|
||||
use matrix_sdk_ui::app::{
|
||||
App as MatrixApp, AppBuilder as MatrixAppBuilder, AppState as MatrixAppState,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error::ClientError, helpers::unwrap_or_clone_arc, room_list::RoomListService,
|
||||
task_handle::TaskHandle, RUNTIME,
|
||||
};
|
||||
|
||||
#[derive(uniffi::Enum)]
|
||||
pub enum AppState {
|
||||
Running,
|
||||
Terminated,
|
||||
Error,
|
||||
}
|
||||
|
||||
impl From<MatrixAppState> for AppState {
|
||||
fn from(value: MatrixAppState) -> Self {
|
||||
match value {
|
||||
MatrixAppState::Running => Self::Running,
|
||||
MatrixAppState::Terminated => Self::Terminated,
|
||||
MatrixAppState::Error => Self::Error,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[uniffi::export(callback_interface)]
|
||||
pub trait AppStateObserver: Send + Sync + Debug {
|
||||
fn on_update(&self, state: AppState);
|
||||
}
|
||||
|
||||
#[derive(uniffi::Object)]
|
||||
pub struct App {
|
||||
inner: MatrixApp,
|
||||
}
|
||||
|
||||
#[uniffi::export]
|
||||
impl App {
|
||||
pub fn room_list_service(&self) -> Arc<RoomListService> {
|
||||
Arc::new(RoomListService { inner: self.inner.room_list_service() })
|
||||
}
|
||||
|
||||
fn state(&self, listener: Box<dyn AppStateObserver>) -> Arc<TaskHandle> {
|
||||
let state_stream = self.inner.observe_state();
|
||||
|
||||
Arc::new(TaskHandle::new(RUNTIME.spawn(async move {
|
||||
pin_mut!(state_stream);
|
||||
|
||||
while let Some(state) = state_stream.next().await {
|
||||
listener.on_update(state.into());
|
||||
}
|
||||
})))
|
||||
}
|
||||
|
||||
pub fn start(&self) -> Result<(), ClientError> {
|
||||
let start = self.inner.start();
|
||||
RUNTIME.block_on(async { Ok(start.await?) })
|
||||
}
|
||||
|
||||
pub fn pause(&self) -> Result<(), ClientError> {
|
||||
Ok(self.inner.pause()?)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, uniffi::Object)]
|
||||
pub struct AppBuilder {
|
||||
builder: MatrixAppBuilder,
|
||||
}
|
||||
|
||||
impl AppBuilder {
|
||||
pub(crate) fn new(client: Client) -> Arc<Self> {
|
||||
Arc::new(Self { builder: MatrixApp::builder(client) })
|
||||
}
|
||||
}
|
||||
|
||||
#[uniffi::export]
|
||||
impl AppBuilder {
|
||||
pub fn with_encryption_sync(
|
||||
self: Arc<Self>,
|
||||
with_cross_process_lock: bool,
|
||||
app_identifier: Option<String>,
|
||||
) -> Arc<Self> {
|
||||
let this = unwrap_or_clone_arc(self);
|
||||
let builder = this.builder.with_encryption_sync(with_cross_process_lock, app_identifier);
|
||||
Arc::new(Self { builder })
|
||||
}
|
||||
|
||||
pub fn finish(self: Arc<Self>) -> Result<Arc<App>, ClientError> {
|
||||
let this = unwrap_or_clone_arc(self);
|
||||
RUNTIME.block_on(async move { Ok(Arc::new(App { inner: this.builder.build().await? })) })
|
||||
}
|
||||
}
|
||||
@@ -32,8 +32,8 @@ use url::Url;
|
||||
|
||||
use super::{room::Room, session_verification::SessionVerificationController, RUNTIME};
|
||||
use crate::{
|
||||
client, notification::NotificationClientBuilder, notification_settings::NotificationSettings,
|
||||
ClientError,
|
||||
app::AppBuilder, client, notification::NotificationClientBuilder,
|
||||
notification_settings::NotificationSettings, ClientError,
|
||||
};
|
||||
|
||||
#[derive(Clone, uniffi::Record)]
|
||||
@@ -588,6 +588,10 @@ impl Client {
|
||||
NotificationClientBuilder::new(self.inner.clone())
|
||||
}
|
||||
|
||||
pub fn app(&self) -> Arc<AppBuilder> {
|
||||
AppBuilder::new(self.inner.clone())
|
||||
}
|
||||
|
||||
pub fn get_notification_settings(&self) -> Arc<NotificationSettings> {
|
||||
RUNTIME.block_on(async move {
|
||||
Arc::new(NotificationSettings::new(
|
||||
|
||||
@@ -4,7 +4,7 @@ use matrix_sdk::{
|
||||
self, encryption::CryptoStoreError, HttpError, IdParseError,
|
||||
NotificationSettingsError as SdkNotificationSettingsError, StoreError,
|
||||
};
|
||||
use matrix_sdk_ui::{encryption_sync, notification_client, timeline};
|
||||
use matrix_sdk_ui::{app, encryption_sync, notification_client, timeline};
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum ClientError {
|
||||
@@ -90,6 +90,12 @@ impl From<notification_client::Error> for ClientError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<app::Error> for ClientError {
|
||||
fn from(e: app::Error) -> Self {
|
||||
Self::new(e)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error, uniffi::Error)]
|
||||
#[uniffi(flat_error)]
|
||||
pub enum RoomError {
|
||||
|
||||
@@ -20,6 +20,7 @@ macro_rules! unwrap_or_clone_arc_into_variant {
|
||||
};
|
||||
}
|
||||
|
||||
mod app;
|
||||
mod authentication_service;
|
||||
mod client;
|
||||
mod client_builder;
|
||||
|
||||
@@ -16,6 +16,7 @@ use tokio::sync::RwLock;
|
||||
|
||||
use crate::{client::Client, room::Room, timeline::EventTimelineItem, TaskHandle, RUNTIME};
|
||||
|
||||
// TODO(bnjbvr) remove
|
||||
#[uniffi::export]
|
||||
impl Client {
|
||||
/// Get a new `RoomListService` instance.
|
||||
@@ -102,28 +103,11 @@ impl From<RoomListInput> for matrix_sdk_ui::room_list_service::Input {
|
||||
|
||||
#[derive(uniffi::Object)]
|
||||
pub struct RoomListService {
|
||||
inner: Arc<matrix_sdk_ui::RoomListService>,
|
||||
pub(crate) inner: Arc<matrix_sdk_ui::RoomListService>,
|
||||
}
|
||||
|
||||
#[uniffi::export]
|
||||
impl RoomListService {
|
||||
fn sync(&self) {
|
||||
let this = self.inner.clone();
|
||||
|
||||
RUNTIME.spawn(async move {
|
||||
let sync_stream = this.sync();
|
||||
pin_mut!(sync_stream);
|
||||
|
||||
while sync_stream.next().await.is_some() {
|
||||
// keep going!
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn stop_sync(&self) -> Result<(), RoomListError> {
|
||||
self.inner.stop_sync().map_err(Into::into)
|
||||
}
|
||||
|
||||
fn is_syncing(&self) -> bool {
|
||||
use matrix_sdk_ui::room_list_service::State;
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ pub enum AppState {
|
||||
}
|
||||
|
||||
pub struct App {
|
||||
room_list: Arc<RoomListService>,
|
||||
room_list_service: Arc<RoomListService>,
|
||||
encryption_sync: Option<Arc<EncryptionSync>>,
|
||||
task_handle: Arc<Mutex<Option<JoinHandle<()>>>>,
|
||||
state_observer: SharedObservable<AppState>,
|
||||
@@ -67,8 +67,8 @@ impl App {
|
||||
|
||||
/// Get the underlying `RoomListService` instance for easier access to its
|
||||
/// methods.
|
||||
pub fn room_list_service(&self) -> &RoomListService {
|
||||
&*self.room_list
|
||||
pub fn room_list_service(&self) -> Arc<RoomListService> {
|
||||
self.room_list_service.clone()
|
||||
}
|
||||
|
||||
/// Observe the current state of the application.
|
||||
@@ -84,7 +84,7 @@ impl App {
|
||||
/// spawned to run the syncs, then it will be properly aborted and
|
||||
/// restarted.
|
||||
pub async fn start(&self) -> Result<(), Error> {
|
||||
let room_list = self.room_list.clone();
|
||||
let room_list = self.room_list_service.clone();
|
||||
let encryption_sync = self.encryption_sync.clone();
|
||||
let state_observer = self.state_observer.clone();
|
||||
|
||||
@@ -162,7 +162,7 @@ impl App {
|
||||
/// to call this API when the application exits, although not strictly
|
||||
/// necessary.
|
||||
pub fn pause(&self) -> Result<(), Error> {
|
||||
self.room_list.stop_sync()?;
|
||||
self.room_list_service.stop_sync()?;
|
||||
if let Some(ref encryption_sync) = self.encryption_sync {
|
||||
encryption_sync.stop()?;
|
||||
}
|
||||
@@ -170,6 +170,7 @@ impl App {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AppBuilder {
|
||||
/// SDK client.
|
||||
client: Client,
|
||||
@@ -243,7 +244,7 @@ impl AppBuilder {
|
||||
};
|
||||
|
||||
let app = App {
|
||||
room_list: Arc::new(room_list),
|
||||
room_list_service: Arc::new(room_list),
|
||||
encryption_sync,
|
||||
state_observer: SharedObservable::new(AppState::Running),
|
||||
task_handle: Default::default(),
|
||||
|
||||
Reference in New Issue
Block a user