[fractal] API: manage sync module from app directly
- From: Daniel Garcia Moreno <danigm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [fractal] API: manage sync module from app directly
- Date: Tue, 30 Jun 2020 07:43:09 +0000 (UTC)
commit 5ea9182f0ad41a0faffbcfbd95d932cb217fa5ac
Author: Alejandro DomÃnguez <adomu net-c com>
Date: Wed Jun 24 03:04:32 2020 +0200
API: manage sync module from app directly
fractal-gtk/src/app/backend_loop.rs | 51 +----
fractal-gtk/src/appop/sync.rs | 145 ++++++++++++-
fractal-matrix-api/src/backend/mod.rs | 18 +-
fractal-matrix-api/src/backend/sync.rs | 360 ++++++++++++++++----------------
fractal-matrix-api/src/backend/types.rs | 36 +---
5 files changed, 331 insertions(+), 279 deletions(-)
---
diff --git a/fractal-gtk/src/app/backend_loop.rs b/fractal-gtk/src/app/backend_loop.rs
index 03a08342..48b721d1 100644
--- a/fractal-gtk/src/app/backend_loop.rs
+++ b/fractal-gtk/src/app/backend_loop.rs
@@ -1,7 +1,7 @@
use crate::app::App;
use crate::i18n::i18n;
use lazy_static::lazy_static;
-use log::{error, info};
+use log::error;
use regex::Regex;
use crate::actions::{activate_action, AppState};
@@ -19,53 +19,6 @@ pub fn backend_loop(rx: Receiver<BKResponse>) {
BKResponse::ShutDown => {
break;
}
- BKResponse::Token(uid, tk, dev, server_url, id_url) => {
- APPOP!(bk_login, (uid, tk, dev, server_url, id_url));
- }
- BKResponse::Sync(Ok(since)) => {
- info!("SYNC");
- let s = Some(since);
- APPOP!(synced, (s));
- }
- BKResponse::Rooms(Ok((rooms, default))) => {
- let clear_room_list = true;
- APPOP!(set_rooms, (rooms, clear_room_list));
- // Open the newly joined room
- let jtr = default.as_ref().map(|r| r.id.clone());
- APPOP!(set_join_to_room, (jtr));
- if let Some(room) = default {
- let room_id = room.id;
- APPOP!(set_active_room_by_id, (room_id));
- }
- }
- BKResponse::UpdateRooms(Ok(rooms)) => {
- let clear_room_list = false;
- APPOP!(set_rooms, (rooms, clear_room_list));
- }
- BKResponse::RoomMessages(Ok(msgs)) => {
- APPOP!(show_room_messages, (msgs));
- }
-
- BKResponse::RemoveMessage(Ok((room, msg))) => {
- APPOP!(remove_message, (room, msg));
- }
- BKResponse::RoomNotifications(r, n, h) => {
- APPOP!(set_room_notifications, (r, n, h));
- }
- BKResponse::RoomName(roomid, name) => {
- let n = Some(name);
- APPOP!(room_name_change, (roomid, n));
- }
- BKResponse::RoomTopic(roomid, topic) => {
- let t = Some(topic);
- APPOP!(room_topic_change, (roomid, t));
- }
- BKResponse::NewRoomAvatar(roomid) => {
- APPOP!(new_room_avatar, (roomid));
- }
- BKResponse::RoomMemberEvent(ev) => {
- APPOP!(room_member_event, (ev));
- }
// errors
BKResponse::AccountDestructionError(err) => {
@@ -194,7 +147,7 @@ pub fn backend_loop(rx: Receiver<BKResponse>) {
APPOP!(reset_directory_state);
APPOP!(show_error, (error));
}
- BKResponse::Sync(Err((err, number_tries))) => {
+ BKResponse::SyncError(err, number_tries) => {
let err_str = format!("{:?}", err);
error!(
"SYNC Error: {}",
diff --git a/fractal-gtk/src/appop/sync.rs b/fractal-gtk/src/appop/sync.rs
index 80730dc0..84e186ab 100644
--- a/fractal-gtk/src/appop/sync.rs
+++ b/fractal-gtk/src/appop/sync.rs
@@ -1,8 +1,16 @@
+use fractal_api::util::ResultExpectLog;
+use log::info;
+use std::thread;
+
use crate::i18n::i18n;
+use crate::app::App;
use crate::appop::AppOp;
-use crate::backend::BKCommand;
+use crate::backend::{
+ sync::{self, RoomElement, SyncRet},
+ BKCommand, BKResponse,
+};
impl AppOp {
pub fn initial_sync(&self, show: bool) {
@@ -14,24 +22,145 @@ impl AppOp {
}
pub fn sync(&mut self, initial: bool, number_tries: u64) {
- if let (Some(login_data), true) = (self.login_data.clone(), !self.syncing) {
+ if let (Some(login_data), false) = (self.login_data.clone(), self.syncing) {
self.syncing = true;
// for the initial sync we set the since to None to avoid long syncing
// the since can be a very old value and following the spec we should
// do the initial sync without a since:
// https://matrix.org/docs/spec/client_server/latest.html#syncing
- let since = if initial { None } else { self.since.clone() };
- self.backend
- .send(BKCommand::Sync(
+ let join_to_room = self.join_to_room.clone();
+ let since = self.since.clone().filter(|_| !initial);
+ let tx = self.backend.clone();
+ thread::spawn(move || {
+ match sync::sync(
login_data.server_url,
login_data.access_token,
login_data.uid,
- self.join_to_room.clone(),
+ join_to_room,
since,
initial,
number_tries,
- ))
- .unwrap();
+ ) {
+ Ok(SyncRet::NoSince { rooms, next_batch }) => {
+ match rooms {
+ Ok((rooms, default)) => {
+ let clear_room_list = true;
+ APPOP!(set_rooms, (rooms, clear_room_list));
+ // Open the newly joined room
+ let jtr = default.as_ref().map(|r| r.id.clone());
+ APPOP!(set_join_to_room, (jtr));
+ if let Some(room) = default {
+ let room_id = room.id;
+ APPOP!(set_active_room_by_id, (room_id));
+ }
+ }
+ Err(err) => {
+ tx.send(BKCommand::SendBKResponse(BKResponse::RoomsError(err)))
+ .expect_log("Connection closed");
+ }
+ };
+
+ info!("SYNC");
+ let s = Some(next_batch);
+ APPOP!(synced, (s));
+ }
+ Ok(SyncRet::WithSince {
+ update_rooms,
+ room_messages,
+ room_notifications,
+ update_rooms_2,
+ other,
+ next_batch,
+ }) => {
+ match update_rooms {
+ Ok(rooms) => {
+ let clear_room_list = false;
+ APPOP!(set_rooms, (rooms, clear_room_list));
+ }
+ Err(err) => {
+ tx.send(BKCommand::SendBKResponse(BKResponse::UpdateRoomsError(
+ err,
+ )))
+ .expect_log("Connection closed");
+ }
+ }
+
+ match room_messages {
+ Ok(msgs) => {
+ APPOP!(show_room_messages, (msgs));
+ }
+ Err(err) => {
+ tx.send(BKCommand::SendBKResponse(BKResponse::RoomMessagesError(
+ err,
+ )))
+ .expect_log("Connection closed");
+ }
+ }
+
+ match update_rooms_2 {
+ Ok(rooms) => {
+ let clear_room_list = false;
+ APPOP!(set_rooms, (rooms, clear_room_list));
+ }
+ Err(err) => {
+ tx.send(BKCommand::SendBKResponse(BKResponse::UpdateRoomsError(
+ err,
+ )))
+ .expect_log("Connection closed");
+ }
+ }
+
+ for (room_id, unread_notifications) in room_notifications {
+ let r = room_id;
+ let n = unread_notifications.notification_count;
+ let h = unread_notifications.highlight_count;
+ APPOP!(set_room_notifications, (r, n, h));
+ }
+
+ match other {
+ Ok(other) => {
+ for room_element in other {
+ match room_element {
+ RoomElement::Name(room_id, name) => {
+ let n = Some(name);
+ APPOP!(room_name_change, (room_id, n));
+ }
+ RoomElement::Topic(room_id, topic) => {
+ let t = Some(topic);
+ APPOP!(room_topic_change, (room_id, t));
+ }
+ RoomElement::NewAvatar(room_id) => {
+ APPOP!(new_room_avatar, (room_id));
+ }
+ RoomElement::MemberEvent(event) => {
+ APPOP!(room_member_event, (event));
+ }
+ RoomElement::RemoveMessage(room_id, msg_id) => {
+ APPOP!(remove_message, (room_id, msg_id));
+ }
+ }
+ }
+ }
+ Err(err) => {
+ tx.send(BKCommand::SendBKResponse(BKResponse::RoomElementError(
+ err,
+ )))
+ .expect_log("Connection closed");
+ }
+ }
+
+ info!("SYNC");
+ let s = Some(next_batch);
+ APPOP!(synced, (s));
+ }
+ Err((err, n_tries)) => {
+ tx.send(BKCommand::SendBKResponse(BKResponse::SyncError(
+ err, n_tries,
+ )))
+ .expect_log("Connection closed");
+ }
+ }
+ });
}
}
diff --git a/fractal-matrix-api/src/backend/mod.rs b/fractal-matrix-api/src/backend/mod.rs
index 966059d4..e63cf782 100644
--- a/fractal-matrix-api/src/backend/mod.rs
+++ b/fractal-matrix-api/src/backend/mod.rs
@@ -9,7 +9,7 @@ pub mod directory;
pub mod media;
pub mod register;
pub mod room;
-mod sync;
+pub mod sync;
mod types;
pub mod user;
@@ -41,25 +41,9 @@ impl Backend {
let tx = self.tx.clone();
match cmd {
- // Sync module
- Ok(BKCommand::Sync(server, access_token, uid, jtr, since, initial, number_tries)) => {
- sync::sync(
- self,
- server,
- access_token,
- uid,
- jtr,
- since,
- initial,
- number_tries,
- )
- }
-
- // Internal commands
Ok(BKCommand::SendBKResponse(response)) => {
tx.send(response).expect_log("Connection closed");
}
-
Ok(BKCommand::ShutDown) => {
tx.send(BKResponse::ShutDown)
.expect_log("Connection closed");
diff --git a/fractal-matrix-api/src/backend/sync.rs b/fractal-matrix-api/src/backend/sync.rs
index ef66e4fb..08bb1d01 100644
--- a/fractal-matrix-api/src/backend/sync.rs
+++ b/fractal-matrix-api/src/backend/sync.rs
@@ -1,5 +1,3 @@
-use crate::backend::types::BKResponse;
-use crate::backend::types::Backend;
use crate::client::ProxySettings;
use crate::error::Error;
use crate::globals;
@@ -20,21 +18,43 @@ use crate::types::Room;
use crate::types::RoomMembership;
use crate::types::RoomTag;
use crate::util::matrix_response;
-use crate::util::ResultExpectLog;
use log::error;
use reqwest::blocking::Client;
-use ruma_identifiers::{RoomId, UserId};
+use ruma_identifiers::{EventId, RoomId, UserId};
use serde_json::value::from_value;
use std::{
+ collections::HashMap,
convert::{TryFrom, TryInto},
thread,
time::{self, Duration},
};
use url::Url;
+pub enum RoomElement {
+ Name(RoomId, String),
+ Topic(RoomId, String),
+ NewAvatar(RoomId),
+ MemberEvent(Event),
+ RemoveMessage(RoomId, EventId),
+}
+
+pub enum SyncRet {
+ NoSince {
+ rooms: Result<(Vec<Room>, Option<Room>), Error>,
+ next_batch: String,
+ },
+ WithSince {
+ update_rooms: Result<Vec<Room>, Error>,
+ room_messages: Result<Vec<Message>, Error>,
+ room_notifications: HashMap<RoomId, UnreadNotificationsCount>,
+ update_rooms_2: Result<Vec<Room>, Error>,
+ other: Result<Vec<RoomElement>, Error>,
+ next_batch: String,
+ },
+}
+
pub fn sync(
- bk: &Backend,
base: Url,
access_token: AccessToken,
user_id: UserId,
@@ -42,9 +62,7 @@ pub fn sync(
since: Option<String>,
initial: bool,
number_tries: u64,
-) {
- let tx = bk.tx.clone();
-
+) -> Result<SyncRet, (Error, u64)> {
let (timeout, filter) = if !initial {
(time::Duration::from_secs(30), Default::default())
} else {
@@ -95,196 +113,188 @@ pub fn sync(
set_presence: Default::default(),
};
- thread::spawn(move || {
- let client_builder_timeout =
- Client::builder().timeout(Some(Duration::from_secs(globals::TIMEOUT) + timeout));
+ let client_builder_timeout =
+ Client::builder().timeout(Some(Duration::from_secs(globals::TIMEOUT) + timeout));
- let query = ProxySettings::current().and_then(|proxy_settings| {
- let client = proxy_settings
- .apply_to_client_builder(client_builder_timeout)?
- .build()?;
- let request = sync_events(base.clone(), ¶ms)?;
- let response = client.execute(request)?;
+ let query = ProxySettings::current().and_then(|proxy_settings| {
+ let client = proxy_settings
+ .apply_to_client_builder(client_builder_timeout)?
+ .build()?;
+ let request = sync_events(base.clone(), ¶ms)?;
+ let response = client.execute(request)?;
- matrix_response::<SyncResponse>(response)
- });
+ matrix_response::<SyncResponse>(response)
+ });
- match query {
- Ok(response) => {
- if since.is_some() {
- let join = &response.rooms.join;
+ match query {
+ Ok(response) => {
+ if since.is_none() {
+ let rooms = Room::from_sync_response(&response, user_id, base)
+ .map(|rooms| {
+ let def = join_to_room
+ .and_then(|jtr| rooms.iter().find(|x| x.id == jtr).cloned());
+ (rooms, def)
+ })
+ .map_err(Into::into);
- // New rooms
- let rs = Room::from_sync_response(&response, user_id.clone(), base)
- .map_err(Into::into);
- tx.send(BKResponse::UpdateRooms(rs))
- .expect_log("Connection closed");
+ let next_batch = response.next_batch;
- // Message events
- let msgs = join
- .iter()
- .try_fold(Vec::new(), |mut acum, (k, room)| {
- let events = room.timeline.events.iter();
- Message::from_json_events_iter(&k, events).map(|msgs| {
- acum.extend(msgs);
- acum
- })
+ Ok(SyncRet::NoSince { rooms, next_batch })
+ } else {
+ let join = &response.rooms.join;
+
+ // New rooms
+ let update_rooms =
+ Room::from_sync_response(&response, user_id.clone(), base).map_err(Into::into);
+
+ // Message events
+ let room_messages = join
+ .iter()
+ .try_fold(Vec::new(), |mut acum, (k, room)| {
+ let events = room.timeline.events.iter();
+ Message::from_json_events_iter(&k, events).map(|msgs| {
+ acum.extend(msgs);
+ acum
})
- .map_err(Into::into);
- tx.send(BKResponse::RoomMessages(msgs))
- .expect_log("Connection closed");
+ })
+ .map_err(Into::into);
- // Room notifications
- for (k, room) in join.iter() {
- let UnreadNotificationsCount {
- highlight_count: h,
- notification_count: n,
- } = room.unread_notifications;
- tx.send(BKResponse::RoomNotifications(k.clone(), n, h))
- .expect_log("Connection closed");
- }
+ // Room notifications
+ let room_notifications = join
+ .iter()
+ .map(|(k, room)| (k.clone(), room.unread_notifications.clone()))
+ .collect();
- // Typing notifications
- let rooms: Vec<Room> = join
- .iter()
- .map(|(k, room)| {
- let ephemerals = &room.ephemeral.events;
- let typing: Vec<Member> = ephemerals.iter()
- .flat_map(|event| {
- event
- .get("content")
- .and_then(|x| x.get("user_ids"))
- .and_then(|x| x.as_array())
- .unwrap_or(&vec![])
- .to_owned()
- })
- .filter_map(|user| from_value(user).ok())
- // ignoring the user typing notifications
- .filter(|user| *user != user_id)
- .map(|uid| {
- Member {
- uid,
- alias: None,
- avatar: None,
- }
- })
- .collect();
+ // Typing notifications
+ let update_rooms_2 = Ok(join
+ .iter()
+ .map(|(k, room)| {
+ let ephemerals = &room.ephemeral.events;
+ let typing: Vec<Member> = ephemerals.iter()
+ .flat_map(|event| {
+ event
+ .get("content")
+ .and_then(|x| x.get("user_ids"))
+ .and_then(|x| x.as_array())
+ .unwrap_or(&vec![])
+ .to_owned()
+ })
+ .filter_map(|user| from_value(user).ok())
+ // ignoring the user typing notifications
+ .filter(|user| *user != user_id)
+ .map(|uid| {
+ Member {
+ uid,
+ alias: None,
+ avatar: None,
+ }
+ })
+ .collect();
- Room {
- typing_users: typing,
- ..Room::new(k.clone(), RoomMembership::Joined(RoomTag::None))
- }
- })
- .collect();
- tx.send(BKResponse::UpdateRooms(Ok(rooms)))
- .expect_log("Connection closed");
+ Room {
+ typing_users: typing,
+ ..Room::new(k.clone(), RoomMembership::Joined(RoomTag::None))
+ }
+ })
+ .collect());
- // Other events
- join.iter()
- .flat_map(|(k, room)| {
- room.timeline
- .events
- .iter()
- .filter(|x| x["type"] != "m.room.message")
- .map(move |ev| Event {
+ // Other events
+ let other = join
+ .iter()
+ .flat_map(|(k, room)| {
+ room.timeline
+ .events
+ .iter()
+ .filter(|x| x["type"] != "m.room.message")
+ .map(move |ev| {
+ Ok(Event {
room: k.clone(),
sender: UserId::try_from(
ev["sender"].as_str().unwrap_or_default(),
- )
- .unwrap(),
- // TODO: Correct error management is too hard here,
- // needs refactoring, but this workaround
- // is enough
+ )?,
content: ev["content"].clone(),
redacts: ev["redacts"]
.as_str()
- .and_then(|r| r.try_into().ok()),
+ .map(|r| r.try_into())
+ .transpose()?,
stype: ev["type"].as_str().map(Into::into).unwrap_or_default(),
id: ev["id"].as_str().map(Into::into).unwrap_or_default(),
})
- })
- .for_each(|ev| {
- match ev.stype.as_ref() {
- "m.room.name" => {
- let name = ev.content["name"]
- .as_str()
- .map(Into::into)
- .unwrap_or_default();
- tx.send(BKResponse::RoomName(ev.room.clone(), name))
- .expect_log("Connection closed");
- }
- "m.room.topic" => {
- let t = ev.content["topic"]
- .as_str()
- .map(Into::into)
- .unwrap_or_default();
- tx.send(BKResponse::RoomTopic(ev.room.clone(), t))
- .expect_log("Connection closed");
- }
- "m.room.avatar" => {
- tx.send(BKResponse::NewRoomAvatar(ev.room.clone()))
- .expect_log("Connection closed");
- }
- "m.room.member" => {
- tx.send(BKResponse::RoomMemberEvent(ev))
- .expect_log("Connection closed");
- }
- "m.sticker" => {
- // This event is managed in the room list
- }
- "m.room.redaction" => {
- let _ = tx.send(BKResponse::RemoveMessage(Ok((
- ev.room.clone(),
- ev.redacts.expect("Events of type m.room.redaction should have a
'redacts' field"),
- ))));
- }
- _ => {
- error!("EVENT NOT MANAGED: {:?}", ev);
- }
+ })
+ })
+ .filter_map(|ev| {
+ let ev = match ev {
+ Ok(ev) => ev,
+ Err(err) => return Some(Err(err)),
+ };
+
+ match ev.stype.as_ref() {
+ "m.room.name" => {
+ let name = ev.content["name"]
+ .as_str()
+ .map(Into::into)
+ .unwrap_or_default();
+ Some(Ok(RoomElement::Name(ev.room.clone(), name)))
}
- });
- } else {
- let rooms_def = Room::from_sync_response(&response, user_id, base)
- .map(|rooms| {
- let def = join_to_room
- .and_then(|jtr| rooms.iter().find(|x| x.id == jtr).cloned());
- (rooms, def)
- })
- .map_err(Into::into);
- tx.send(BKResponse::Rooms(rooms_def))
- .expect_log("Connection closed");
- }
+ "m.room.topic" => {
+ let t = ev.content["topic"]
+ .as_str()
+ .map(Into::into)
+ .unwrap_or_default();
+ Some(Ok(RoomElement::Topic(ev.room.clone(), t)))
+ }
+ "m.room.avatar" => Some(Ok(RoomElement::NewAvatar(ev.room.clone()))),
+ "m.room.member" => Some(Ok(RoomElement::MemberEvent(ev))),
+ "m.room.redaction" => Some(Ok(RoomElement::RemoveMessage(
+ ev.room.clone(),
+ ev.redacts.expect(
+ "Events of type m.room.redaction should have a 'redacts' field",
+ ),
+ ))),
+ "m.sticker" => {
+ // This event is managed in the room list
+ None
+ }
+ _ => {
+ error!("EVENT NOT MANAGED: {:?}", ev);
+ None
+ }
+ }
+ })
+ .collect();
let next_batch = response.next_batch;
- tx.send(BKResponse::Sync(Ok(next_batch)))
- .expect_log("Connection closed");
- }
- Err(err) => {
- // we wait if there's an error to avoid 100% CPU
- // we wait even longer, if it's a 429 (Too Many Requests) error
- let waiting_time =
- // Once the Rust issue https://github.com/rust-lang/rust/issues/53667 is resolved, we can
hopefully write
- // if let Error::NetworkError(status) = err && status.as_u16() == 429
- if let Error::NetworkError(status) = err {
- if status.as_u16() == 429 {
- 10 * 2_u64.pow(number_tries.try_into().expect(
- "The number of sync tries couldn't be transformed into a u32.",
- ))
- } else {
- 10
- }
- } else {
- 10
- };
- error!(
- "Sync Error, waiting {:?} seconds to respond for the next sync",
- waiting_time
- );
- thread::sleep(time::Duration::from_secs(waiting_time));
- tx.send(BKResponse::Sync(Err((err, number_tries))))
- .expect_log("Connection closed");
+ Ok(SyncRet::WithSince {
+ update_rooms,
+ room_messages,
+ room_notifications,
+ update_rooms_2,
+ other,
+ next_batch,
+ })
}
}
- });
+ Err(err) => {
+ // we wait if there's an error to avoid 100% CPU
+ // we wait even longer, if it's a 429 (Too Many Requests) error
+ let waiting_time = match err {
+ Error::NetworkError(status) if status.as_u16() == 429 => {
+ 10 * 2_u64.pow(
+ number_tries
+ .try_into()
+ .expect("The number of sync tries couldn't be transformed into a u32."),
+ )
+ }
+ _ => 10,
+ };
+ error!(
+ "Sync Error, waiting {:?} seconds to respond for the next sync",
+ waiting_time
+ );
+ thread::sleep(time::Duration::from_secs(waiting_time));
+
+ Err((err, number_tries))
+ }
+ }
}
diff --git a/fractal-matrix-api/src/backend/types.rs b/fractal-matrix-api/src/backend/types.rs
index 4dee0669..b4f77150 100644
--- a/fractal-matrix-api/src/backend/types.rs
+++ b/fractal-matrix-api/src/backend/types.rs
@@ -1,28 +1,12 @@
-use ruma_identifiers::{DeviceId, EventId, RoomId, UserId};
+use ruma_identifiers::RoomId;
use std::sync::mpsc::Sender;
use std::sync::{Arc, Condvar, Mutex};
use std::thread;
use crate::error::Error;
-use crate::r0::AccessToken;
-use crate::types::Event;
-use crate::types::Message;
-use crate::types::Room;
-
-use url::Url;
-
#[derive(Debug)]
pub enum BKCommand {
- Sync(
- Url,
- AccessToken,
- UserId,
- Option<RoomId>,
- Option<String>,
- bool,
- u64,
- ),
ShutDown,
SendBKResponse(BKResponse),
}
@@ -30,19 +14,6 @@ pub enum BKCommand {
#[derive(Debug)]
pub enum BKResponse {
ShutDown,
- Token(UserId, AccessToken, Option<DeviceId>, Url, Url),
- Sync(Result<String, (Error, u64)>),
- Rooms(Result<(Vec<Room>, Option<Room>), Error>),
- UpdateRooms(Result<Vec<Room>, Error>),
- NewRoomAvatar(RoomId),
- RoomMemberEvent(Event),
- RoomMessages(Result<Vec<Message>, Error>),
- RoomMessagesInit(Vec<Message>),
- RemoveMessage(Result<(RoomId, EventId), Error>),
- RoomName(RoomId, String),
- RoomTopic(RoomId, String),
- MediaUrl(Url),
- RoomNotifications(RoomId, i32, i32),
//errors
LoginError(Error),
@@ -83,6 +54,11 @@ pub enum BKResponse {
RoomAvatarError(Error),
SentMsgError(Error),
AttachedFileError(Error),
+ RoomsError(Error),
+ UpdateRoomsError(Error),
+ RoomMessagesError(Error),
+ RoomElementError(Error),
+ SyncError(Error, u64),
}
#[derive(Debug, Clone, Copy)]
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]