matrix_sdk_ffi/
sync_service.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 that specific language governing permissions and
13// limitations under the License.
14
15use std::{fmt::Debug, sync::Arc};
16
17use futures_util::pin_mut;
18use matrix_sdk::Client;
19use matrix_sdk_common::{SendOutsideWasm, SyncOutsideWasm};
20use matrix_sdk_ui::{
21    sync_service::{
22        State as MatrixSyncServiceState, SyncService as MatrixSyncService,
23        SyncServiceBuilder as MatrixSyncServiceBuilder,
24    },
25    unable_to_decrypt_hook::UtdHookManager,
26};
27
28use crate::{
29    error::ClientError, helpers::unwrap_or_clone_arc, room_list::RoomListService,
30    runtime::get_runtime_handle, TaskHandle,
31};
32
33#[derive(uniffi::Enum)]
34pub enum SyncServiceState {
35    Idle,
36    Running,
37    Terminated,
38    Error,
39    Offline,
40}
41
42impl From<MatrixSyncServiceState> for SyncServiceState {
43    fn from(value: MatrixSyncServiceState) -> Self {
44        match value {
45            MatrixSyncServiceState::Idle => Self::Idle,
46            MatrixSyncServiceState::Running => Self::Running,
47            MatrixSyncServiceState::Terminated => Self::Terminated,
48            MatrixSyncServiceState::Error(_error) => Self::Error,
49            MatrixSyncServiceState::Offline => Self::Offline,
50        }
51    }
52}
53
54#[matrix_sdk_ffi_macros::export(callback_interface)]
55pub trait SyncServiceStateObserver: SendOutsideWasm + SyncOutsideWasm + Debug {
56    fn on_update(&self, state: SyncServiceState);
57}
58
59#[derive(uniffi::Object)]
60pub struct SyncService {
61    pub(crate) inner: Arc<MatrixSyncService>,
62    utd_hook: Option<Arc<UtdHookManager>>,
63}
64
65#[matrix_sdk_ffi_macros::export]
66impl SyncService {
67    pub fn room_list_service(&self) -> Arc<RoomListService> {
68        Arc::new(RoomListService {
69            inner: self.inner.room_list_service(),
70            utd_hook: self.utd_hook.clone(),
71        })
72    }
73
74    pub async fn start(&self) {
75        self.inner.start().await
76    }
77
78    pub async fn stop(&self) {
79        self.inner.stop().await
80    }
81
82    pub fn state(&self, listener: Box<dyn SyncServiceStateObserver>) -> Arc<TaskHandle> {
83        let state_stream = self.inner.state();
84
85        Arc::new(TaskHandle::new(get_runtime_handle().spawn(async move {
86            pin_mut!(state_stream);
87
88            while let Some(state) = state_stream.next().await {
89                listener.on_update(state.into());
90            }
91        })))
92    }
93
94    /// Force expiring both sliding sync sessions.
95    ///
96    /// This ensures that the sync service is stopped before expiring both
97    /// sessions. It should be used sparingly, as it will cause a restart of
98    /// the sessions on the server as well.
99    pub async fn expire_sessions(&self) {
100        self.inner.expire_sessions().await;
101    }
102}
103
104#[derive(Clone, uniffi::Object)]
105pub struct SyncServiceBuilder {
106    builder: MatrixSyncServiceBuilder,
107    utd_hook: Option<Arc<UtdHookManager>>,
108}
109
110impl SyncServiceBuilder {
111    pub(crate) fn new(client: Client, utd_hook: Option<Arc<UtdHookManager>>) -> Arc<Self> {
112        Arc::new(Self { builder: MatrixSyncService::builder(client), utd_hook })
113    }
114}
115
116#[matrix_sdk_ffi_macros::export]
117impl SyncServiceBuilder {
118    pub fn with_cross_process_lock(self: Arc<Self>) -> Arc<Self> {
119        let this = unwrap_or_clone_arc(self);
120        let builder = this.builder.with_cross_process_lock();
121        Arc::new(Self { builder, ..this })
122    }
123
124    /// Enable the "offline" mode for the [`SyncService`].
125    pub fn with_offline_mode(self: Arc<Self>) -> Arc<Self> {
126        let this = unwrap_or_clone_arc(self);
127        let builder = this.builder.with_offline_mode();
128        Arc::new(Self { builder, ..this })
129    }
130
131    pub fn with_share_pos(self: Arc<Self>, enable: bool) -> Arc<Self> {
132        let this = unwrap_or_clone_arc(self);
133        let builder = this.builder.with_share_pos(enable);
134        Arc::new(Self { builder, ..this })
135    }
136
137    pub async fn finish(self: Arc<Self>) -> Result<Arc<SyncService>, ClientError> {
138        let this = unwrap_or_clone_arc(self);
139        Ok(Arc::new(SyncService {
140            inner: Arc::new(this.builder.build().await?),
141            utd_hook: this.utd_hook,
142        }))
143    }
144}