diff --git a/crates/matrix-sdk/Cargo.toml b/crates/matrix-sdk/Cargo.toml index 5ec0ee230..2e28a6315 100644 --- a/crates/matrix-sdk/Cargo.toml +++ b/crates/matrix-sdk/Cargo.toml @@ -47,7 +47,6 @@ experimental-timeline = [] sliding-sync = [ "matrix-sdk-base/sliding-sync", - "anyhow", "dep:derive_builder", ] diff --git a/crates/matrix-sdk/src/error.rs b/crates/matrix-sdk/src/error.rs index e1e6c565d..dda3fef16 100644 --- a/crates/matrix-sdk/src/error.rs +++ b/crates/matrix-sdk/src/error.rs @@ -193,6 +193,11 @@ pub enum Error { #[error(transparent)] ImageError(#[from] ImageError), + /// An error occurred during decryption. + #[cfg(feature = "sliding-sync")] + #[error(transparent)] + SlidingSync(#[from] crate::sliding_sync::Error), + /// An other error was raised /// this might happen because encryption was enabled on the base-crate /// but not here and that raised. diff --git a/crates/matrix-sdk/src/sliding_sync.rs b/crates/matrix-sdk/src/sliding_sync.rs index 4ba3afe12..b7666fdec 100644 --- a/crates/matrix-sdk/src/sliding_sync.rs +++ b/crates/matrix-sdk/src/sliding_sync.rs @@ -15,7 +15,6 @@ use std::{fmt::Debug, sync::Arc}; -use anyhow::{bail, Context}; use futures_core::stream::Stream; use futures_signals::signal::Mutable; use matrix_sdk_base::deserialized_responses::{SyncResponse, SyncTimelineEvent}; @@ -27,10 +26,21 @@ use ruma::{ events::RoomEventType, OwnedRoomId, RoomId, UInt, }; +use thiserror::Error; use url::Url; use crate::{Client, Result}; +/// Internal representation of errors in Sliding Sync +#[derive(Error, Debug)] +#[non_exhaustive] +pub enum Error { + #[error("Received response for {found} lists, yet we have {expected}.")] + BadViewsCount { found: usize, expected: usize }, + #[error("The sliding sync response could not be handled: {0}")] + BadResponse(String), +} + /// The state the [`SlidingSyncView`] is in. /// /// The lifetime of a SlidingSync usually starts at a `Preload`, getting a fast @@ -442,13 +452,15 @@ impl SlidingSync { &self, resp: v4::Response, views: &[SlidingSyncView], - ) -> anyhow::Result { + ) -> Result { let mut processed = self.client.process_sliding_sync(resp.clone()).await?; tracing::info!("main client processed."); self.pos.replace(Some(resp.pos)); let mut updated_views = Vec::new(); if resp.lists.len() != views.len() { - bail!("Received response for {} lists, yet we have {}", resp.lists.len(), views.len()); + return Err( + Error::BadViewsCount { found: resp.lists.len(), expected: views.len() }.into() + ); } for (view, updates) in std::iter::zip(views, &resp.lists) { @@ -497,7 +509,7 @@ impl SlidingSync { /// Run this stream to receive new updates from the server. pub async fn stream<'a>( &self, - ) -> anyhow::Result> + '_> { + ) -> Result> + '_, crate::Error> { let views = self.views.lock_ref().to_vec(); let extensions = self.extensions.clone(); let client = self.client.clone(); @@ -878,7 +890,7 @@ impl SlidingSyncView { } #[tracing::instrument(skip(self, ops))] - fn room_ops(&self, ops: &Vec) -> anyhow::Result<()> { + fn room_ops(&self, ops: &Vec) -> Result<(), Error> { let mut rooms_list = self.rooms_list.lock_mut(); let _rooms_map = self.rooms.lock_mut(); for op in ops { @@ -886,9 +898,16 @@ impl SlidingSyncView { v4::SlidingOp::Sync => { let start: u32 = op .range - .context("`range` must be present for Sync and Update operation")? + .ok_or_else(|| { + Error::BadResponse( + "`range` must be present for Sync and Update operation".to_owned(), + ) + })? .0 - .try_into()?; + .try_into() + .map_err(|e| { + Error::BadResponse(format!("`range` not a valid int: {:}", e)) + })?; let room_ids = op.room_ids.clone(); room_ids .into_iter() @@ -902,21 +921,41 @@ impl SlidingSyncView { v4::SlidingOp::Delete => { let pos: u32 = op .index - .context("`index` must be present for DELETE operation")? - .try_into()?; + .ok_or_else(|| { + Error::BadResponse( + "`index` must be present for DELETE operation".to_owned(), + ) + })? + .try_into() + .map_err(|e| { + Error::BadResponse(format!( + "`index` not a valid int for DELETE: {:}", + e + )) + })?; rooms_list.set_cloned(pos as usize, RoomListEntry::Empty); } v4::SlidingOp::Insert => { let pos: usize = op .index - .context("`index` must be present for INSERT operation")? - .try_into()?; + .ok_or_else(|| { + Error::BadResponse( + "`index` must be present for INSERT operation".to_owned(), + ) + })? + .try_into() + .map_err(|e| { + Error::BadResponse(format!( + "`index` not a valid int for INSERT: {:}", + e + )) + })?; let sliced = rooms_list.as_slice(); - let room = RoomListEntry::Filled( - op.room_id - .clone() - .context("`room_id` must be present for INSERT operation")?, - ); + let room = RoomListEntry::Filled(op.room_id.clone().ok_or_else(|| { + Error::BadResponse( + "`room_id` must be present for INSERT operation".to_owned(), + ) + })?); let mut dif = 0usize; loop { // find the next empty slot and drop it @@ -925,7 +964,7 @@ impl SlidingSyncView { let (next_p, overflown) = pos.overflowing_add(dif); let check_after = !overflown && next_p < sliced.len(); if !check_prev && !check_after { - bail!("We were asked to insert but could not find any direction to shift to"); + return Err(Error::BadResponse("We were asked to insert but could not find any direction to shift to".to_owned())); } if check_prev && sliced[prev_p].empty_or_invalidated() { @@ -945,13 +984,24 @@ impl SlidingSyncView { v4::SlidingOp::Invalidate => { let max_len = rooms_list.len(); let (mut pos, end): (u32, u32) = if let Some(range) = op.range { - (range.0.try_into()?, range.1.try_into()?) + ( + range.0.try_into().map_err(|e| { + Error::BadResponse(format!("`range.0` not a valid int: {:}", e)) + })?, + range.1.try_into().map_err(|e| { + Error::BadResponse(format!("`range.1` not a valid int: {:}", e)) + })?, + ) } else { - bail!("`range` must be given on `Invalidate` operation") + return Err(Error::BadResponse( + "`range` must be given on `Invalidate` operation".to_owned(), + )); }; if pos > end { - bail!("Invalid invalidation, end smaller than start"); + return Err(Error::BadResponse( + "Invalid invalidation, end smaller than start".to_owned(), + )); } while pos < end { @@ -983,7 +1033,7 @@ impl SlidingSyncView { } #[tracing::instrument(skip(self, ops))] - fn handle_response(&self, rooms_count: u32, ops: &Vec) -> anyhow::Result { + fn handle_response(&self, rooms_count: u32, ops: &Vec) -> Result { let mut missing = rooms_count.checked_sub(self.rooms_list.lock_ref().len() as u32).unwrap_or_default(); let mut changed = false;