feat(ffi): First step for RoomList in FFI bindings.

This commit is contained in:
Ivan Enderlin
2023-06-07 17:38:11 +02:00
parent 5416ba06f5
commit 68c19f4129
5 changed files with 218 additions and 7 deletions

View File

@@ -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-sliding-sync"] }
matrix-sdk-ui = { path = "../../crates/matrix-sdk-ui" }
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

View File

@@ -50,6 +50,7 @@ callback interface SlidingSyncListStateObserver {
void did_receive_update(SlidingSyncState new_state);
};
// Used by `SlidingSync` _and_ `RoomList`. Be careful.
[Enum]
interface RoomListEntry {
Empty();
@@ -167,3 +168,33 @@ callback interface SessionVerificationControllerDelegate {
void did_cancel();
void did_finish();
};
enum RoomListState {
"Init",
"FirstRooms",
"AllRooms",
"CarryOn",
"Terminated",
};
callback interface RoomListStateObserver {
void on_update(RoomListState state);
};
[Enum]
interface RoomListEntriesUpdate {
Append(sequence<RoomListEntry> values);
Clear();
PushFront(RoomListEntry value);
PushBack(RoomListEntry value);
PopFront();
PopBack();
Insert(u32 index, RoomListEntry value);
Set(u32 index, RoomListEntry value);
Remove(u32 index);
Reset(sequence<RoomListEntry> values);
};
callback interface RoomListEntriesObserver {
void on_update(RoomListEntriesUpdate room_entries_update);
};

View File

@@ -30,6 +30,7 @@ pub mod event;
mod helpers;
pub mod notification;
pub mod room;
pub mod room_list;
pub mod room_member;
pub mod session_verification;
pub mod sliding_sync;
@@ -45,8 +46,9 @@ pub use platform::*;
// Re-exports for more convenient use inside other submodules
use self::error::ClientError;
pub use self::{
authentication_service::*, client::*, event::*, notification::*, room::*, room_member::*,
session_verification::*, sliding_sync::*, task_handle::TaskHandle, timeline::*, tracing::*,
authentication_service::*, client::*, event::*, notification::*, room::*, room_list::*,
room_member::*, session_verification::*, sliding_sync::*, task_handle::TaskHandle, timeline::*,
tracing::*,
};
uniffi::include_scaffolding!("api");

View File

@@ -0,0 +1,170 @@
use std::{fmt::Debug, sync::Arc};
use eyeball_im::VectorDiff;
use futures_util::{pin_mut, StreamExt};
use crate::{Client, RoomListEntry, TaskHandle, RUNTIME};
#[uniffi::export]
impl Client {
/// Get a new `RoomList` instance.
pub fn room_list(&self) -> Result<Arc<RoomList>, RoomListError> {
Ok(Arc::new(RoomList {
inner: Arc::new(
RUNTIME
.block_on(async { matrix_sdk_ui::RoomList::new(self.inner.clone()).await })
.map_err(RoomListError::from)?,
),
}))
}
}
#[derive(uniffi::Error)]
pub enum RoomListError {
SlidingSync { error: String },
UnknownList { list_name: String },
InputHasNotBeenApplied,
RoomNotFound { room_name: String },
}
impl From<matrix_sdk_ui::room_list::Error> for RoomListError {
fn from(value: matrix_sdk_ui::room_list::Error) -> Self {
use matrix_sdk_ui::room_list::Error::*;
match value {
SlidingSync(error) => Self::SlidingSync { error: error.to_string() },
UnknownList(list_name) => Self::UnknownList { list_name },
InputHasNotBeenApplied(_) => Self::InputHasNotBeenApplied,
RoomNotFound(room_id) => Self::RoomNotFound { room_name: room_id.to_string() },
}
}
}
#[derive(uniffi::Object)]
pub struct RoomList {
inner: Arc<matrix_sdk_ui::RoomList>,
}
#[uniffi::export]
impl RoomList {
fn sync(&self) -> Arc<TaskHandle> {
let this = self.inner.clone();
Arc::new(TaskHandle::new(RUNTIME.spawn(async move {
let sync_stream = this.sync();
pin_mut!(sync_stream);
while let Some(_) = sync_stream.next().await {
// keep going!
}
})))
}
fn state(&self, observer: Box<dyn RoomListStateObserver>) -> Arc<TaskHandle> {
let state_stream = self.inner.state();
Arc::new(TaskHandle::new(RUNTIME.spawn(async move {
pin_mut!(state_stream);
while let Some(state) = state_stream.next().await {
observer.on_update(state.into());
}
})))
}
fn entries(
&self,
observer: Box<dyn RoomListEntriesObserver>,
) -> Result<RoomListEntriesResult, RoomListError> {
let (entries, entries_stream) =
RUNTIME.block_on(async { self.inner.entries().await.map_err(RoomListError::from) })?;
Ok(RoomListEntriesResult {
entries: entries.iter().map(Into::into).collect(),
entries_stream: Arc::new(TaskHandle::new(RUNTIME.spawn(async move {
pin_mut!(entries_stream);
while let Some(diff) = entries_stream.next().await {
observer.on_update(diff.into());
}
}))),
})
}
}
#[derive(uniffi::Record)]
pub struct RoomListEntriesResult {
pub entries: Vec<RoomListEntry>,
pub entries_stream: Arc<TaskHandle>,
}
// Also declared in the UDL file.
pub enum RoomListState {
Init,
FirstRooms,
AllRooms,
CarryOn,
Terminated,
}
impl From<matrix_sdk_ui::room_list::State> for RoomListState {
fn from(value: matrix_sdk_ui::room_list::State) -> Self {
use matrix_sdk_ui::room_list::State::*;
match value {
Init => Self::Init,
FirstRooms => Self::FirstRooms,
AllRooms => Self::AllRooms,
CarryOn => Self::CarryOn,
Terminated { .. } => Self::Terminated,
}
}
}
// Also declared in the UDL file.
pub trait RoomListStateObserver: Send + Sync + Debug {
fn on_update(&self, state: RoomListState);
}
pub enum RoomListEntriesUpdate {
Append { values: Vec<RoomListEntry> },
Clear,
PushFront { value: RoomListEntry },
PushBack { value: RoomListEntry },
PopFront,
PopBack,
Insert { index: u32, value: RoomListEntry },
Set { index: u32, value: RoomListEntry },
Remove { index: u32 },
Reset { values: Vec<RoomListEntry> },
}
impl From<VectorDiff<matrix_sdk::RoomListEntry>> for RoomListEntriesUpdate {
fn from(other: VectorDiff<matrix_sdk::RoomListEntry>) -> Self {
match other {
VectorDiff::Append { values } => {
Self::Append { values: values.into_iter().map(Into::into).collect() }
}
VectorDiff::Clear => Self::Clear,
VectorDiff::PushFront { value } => Self::PushFront { value: value.into() },
VectorDiff::PushBack { value } => Self::PushBack { value: value.into() },
VectorDiff::PopFront => Self::PopFront,
VectorDiff::PopBack => Self::PopBack,
VectorDiff::Insert { index, value } => {
Self::Insert { index: u32::try_from(index).unwrap(), value: value.into() }
}
VectorDiff::Set { index, value } => {
Self::Set { index: u32::try_from(index).unwrap(), value: value.into() }
}
VectorDiff::Remove { index } => Self::Remove { index: u32::try_from(index).unwrap() },
VectorDiff::Reset { values } => {
Self::Reset { values: values.into_iter().map(Into::into).collect() }
}
}
}
}
// Also declared in the UDL file.
pub trait RoomListEntriesObserver: Send + Sync + Debug {
fn on_update(&self, room_entries_update: RoomListEntriesUpdate);
}

View File

@@ -332,12 +332,20 @@ pub enum RoomListEntry {
Filled { room_id: String },
}
impl From<MatrixRoomEntry> for RoomListEntry {
fn from(value: MatrixRoomEntry) -> Self {
(&value).into()
}
}
impl From<&MatrixRoomEntry> for RoomListEntry {
fn from(other: &MatrixRoomEntry) -> Self {
match other {
fn from(value: &MatrixRoomEntry) -> Self {
match value {
MatrixRoomEntry::Empty => Self::Empty,
MatrixRoomEntry::Filled(b) => Self::Filled { room_id: b.to_string() },
MatrixRoomEntry::Invalidated(b) => Self::Invalidated { room_id: b.to_string() },
MatrixRoomEntry::Filled(room_id) => Self::Filled { room_id: room_id.to_string() },
MatrixRoomEntry::Invalidated(room_id) => {
Self::Invalidated { room_id: room_id.to_string() }
}
}
}
}