[fractal] API: move items around



commit bc33790afbd3b7e7623407f542df82bdc93ba4e2
Author: Alejandro Domínguez <adomu net-c com>
Date:   Fri Jun 26 04:47:32 2020 +0200

    API: move items around

 fractal-gtk/src/actions/account_settings.rs |   4 +-
 fractal-gtk/src/actions/message.rs          |  15 +-
 fractal-gtk/src/actions/room_settings.rs    |   4 +-
 fractal-gtk/src/app/backend_loop.rs         |  42 +++---
 fractal-gtk/src/app/connect/language.rs     |   4 +-
 fractal-gtk/src/appop/account.rs            |  16 +--
 fractal-gtk/src/appop/directory.rs          |   6 +-
 fractal-gtk/src/appop/invite.rs             |   8 +-
 fractal-gtk/src/appop/login.rs              |   6 +-
 fractal-gtk/src/appop/member.rs             |   4 +-
 fractal-gtk/src/appop/message.rs            |  12 +-
 fractal-gtk/src/appop/room.rs               |  22 +--
 fractal-gtk/src/appop/start_chat.rs         |   4 +-
 fractal-gtk/src/appop/sync.rs               |  19 ++-
 fractal-gtk/src/appop/user.rs               |   6 +-
 fractal-gtk/src/widgets/address.rs          |   8 +-
 fractal-gtk/src/widgets/room.rs             |   4 +-
 fractal-gtk/src/widgets/room_settings.rs    |   8 +-
 fractal-matrix-api/src/backend/directory.rs |   4 +-
 fractal-matrix-api/src/backend/media.rs     |   5 +-
 fractal-matrix-api/src/backend/mod.rs       | 160 ++++++++++++++-------
 fractal-matrix-api/src/backend/room.rs      |   5 +-
 fractal-matrix-api/src/backend/sync.rs      |  19 ++-
 fractal-matrix-api/src/backend/user.rs      |  38 ++++-
 fractal-matrix-api/src/error.rs             |  49 ++++++-
 fractal-matrix-api/src/globals.rs           |   7 +
 fractal-matrix-api/src/model/room.rs        |  27 +++-
 fractal-matrix-api/src/util.rs              | 211 +---------------------------
 28 files changed, 347 insertions(+), 370 deletions(-)
---
diff --git a/fractal-gtk/src/actions/account_settings.rs b/fractal-gtk/src/actions/account_settings.rs
index 3d20bb12..aee5d8ec 100644
--- a/fractal-gtk/src/actions/account_settings.rs
+++ b/fractal-gtk/src/actions/account_settings.rs
@@ -10,7 +10,7 @@ use std::thread;
 
 use crate::app::dispatch_error;
 use crate::app::App;
-use crate::backend::BKResponse;
+use crate::error::BKError;
 
 use crate::widgets::FileDialog::open;
 
@@ -47,7 +47,7 @@ pub fn new(
                         APPOP!(show_new_avatar, (path));
                     }
                     Err(err) => {
-                        dispatch_error(BKResponse::SetUserAvatarError(err));
+                        dispatch_error(BKError::SetUserAvatarError(err));
                     }
                 }
             });
diff --git a/fractal-gtk/src/actions/message.rs b/fractal-gtk/src/actions/message.rs
index d4dcb603..8c5f2873 100644
--- a/fractal-gtk/src/actions/message.rs
+++ b/fractal-gtk/src/actions/message.rs
@@ -1,8 +1,7 @@
-use crate::backend::{media, room, ThreadPool};
+use crate::backend::{dw_media, media, room, ContentType, ThreadPool};
 use fractal_api::clone;
 use fractal_api::identifiers::RoomId;
 use fractal_api::r0::AccessToken;
-use fractal_api::util::{dw_media, ContentType};
 use log::error;
 use std::cell::RefCell;
 use std::fs;
@@ -15,7 +14,7 @@ use std::thread;
 
 use crate::actions::AppState;
 use crate::app::dispatch_error;
-use crate::backend::BKResponse;
+use crate::error::BKError;
 use crate::error::Error;
 use crate::i18n::i18n;
 use crate::types::Message;
@@ -132,7 +131,7 @@ pub fn new(
                             .expect("failed to execute process");
                     }
                     Err(err) => {
-                        dispatch_error(BKResponse::MediaError(err));
+                        dispatch_error(BKError::MediaError(err));
                     }
                 }
             });
@@ -249,7 +248,7 @@ pub fn new(
             thread::spawn(move || {
                 let query = room::redact_msg(server, access_token, msg);
                 if let Err(err) = query {
-                    dispatch_error(BKResponse::SentMsgRedactionError(err));
+                    dispatch_error(BKError::SentMsgRedactionError(err));
                 }
             });
         }
@@ -283,7 +282,7 @@ fn request_more_messages(
                     APPOP!(show_room_messages_top, (msgs, room, prev_batch));
                 }
                 Err(err) => {
-                    dispatch_error(BKResponse::RoomMessagesToError(err));
+                    dispatch_error(BKError::RoomMessagesToError(err));
                 }
             }
         });
@@ -295,7 +294,7 @@ fn request_more_messages(
                     APPOP!(show_room_messages_top, (msgs, room, prev_batch));
                 }
                 Err(err) => {
-                    dispatch_error(BKResponse::RoomMessagesToError(err));
+                    dispatch_error(BKError::RoomMessagesToError(err));
                 }
             }
         });
@@ -307,7 +306,7 @@ fn request_more_messages(
                     APPOP!(show_room_messages_top, (msgs, room, prev_batch));
                 }
                 Err(err) => {
-                    dispatch_error(BKResponse::RoomMessagesToError(err));
+                    dispatch_error(BKError::RoomMessagesToError(err));
                 }
             },
         );
diff --git a/fractal-gtk/src/actions/room_settings.rs b/fractal-gtk/src/actions/room_settings.rs
index f6f8d2a6..263dba53 100644
--- a/fractal-gtk/src/actions/room_settings.rs
+++ b/fractal-gtk/src/actions/room_settings.rs
@@ -10,7 +10,7 @@ use std::thread;
 
 use crate::app::dispatch_error;
 use crate::app::App;
-use crate::backend::BKResponse;
+use crate::error::BKError;
 use crate::i18n::i18n;
 
 use crate::widgets::ErrorDialog;
@@ -55,7 +55,7 @@ pub fn new(
                                 APPOP!(show_new_room_avatar);
                             }
                             Err(err) => {
-                                dispatch_error(BKResponse::SetRoomAvatarError(err));
+                                dispatch_error(BKError::SetRoomAvatarError(err));
                             }
                         }
                     });
diff --git a/fractal-gtk/src/app/backend_loop.rs b/fractal-gtk/src/app/backend_loop.rs
index 81f1657e..bacb1efe 100644
--- a/fractal-gtk/src/app/backend_loop.rs
+++ b/fractal-gtk/src/app/backend_loop.rs
@@ -6,12 +6,12 @@ use regex::Regex;
 
 use crate::actions::{activate_action, AppState};
 
-use crate::backend::BKResponse;
+use crate::error::BKError;
 use crate::error::Error;
 
-pub fn dispatch_error(error: BKResponse) {
+pub fn dispatch_error(error: BKError) {
     match error {
-        BKResponse::AccountDestructionError(err) => {
+        BKError::AccountDestructionError(err) => {
             let error = i18n("Couldn’t delete the account");
             let err_str = format!("{:?}", err);
             error!(
@@ -20,7 +20,7 @@ pub fn dispatch_error(error: BKResponse) {
             );
             APPOP!(show_error_dialog_in_settings, (error));
         }
-        BKResponse::ChangePasswordError(err) => {
+        BKError::ChangePasswordError(err) => {
             let error = i18n("Couldn’t change the password");
             let err_str = format!("{:?}", err);
             error!(
@@ -29,7 +29,7 @@ pub fn dispatch_error(error: BKResponse) {
             );
             APPOP!(show_password_error_dialog, (error));
         }
-        BKResponse::GetThreePIDError(_) => {
+        BKError::GetThreePIDError(_) => {
             let error = i18n("Sorry, account settings can’t be loaded.");
             APPOP!(show_load_settings_error_dialog, (error));
             let ctx = glib::MainContext::default();
@@ -37,15 +37,15 @@ pub fn dispatch_error(error: BKResponse) {
                 activate_action("app", "back");
             })
         }
-        BKResponse::GetTokenEmailError(Error::TokenUsed) => {
+        BKError::GetTokenEmailError(Error::TokenUsed) => {
             let error = i18n("Email is already in use");
             APPOP!(show_error_dialog_in_settings, (error));
         }
-        BKResponse::GetTokenEmailError(Error::Denied) => {
+        BKError::GetTokenEmailError(Error::Denied) => {
             let error = i18n("Please enter a valid email address.");
             APPOP!(show_error_dialog_in_settings, (error));
         }
-        BKResponse::GetTokenEmailError(err) => {
+        BKError::GetTokenEmailError(err) => {
             let error = i18n("Couldn’t add the email address.");
             let err_str = format!("{:?}", err);
             error!(
@@ -54,17 +54,17 @@ pub fn dispatch_error(error: BKResponse) {
             );
             APPOP!(show_error_dialog_in_settings, (error));
         }
-        BKResponse::GetTokenPhoneError(Error::TokenUsed) => {
+        BKError::GetTokenPhoneError(Error::TokenUsed) => {
             let error = i18n("Phone number is already in use");
             APPOP!(show_error_dialog_in_settings, (error));
         }
-        BKResponse::GetTokenPhoneError(Error::Denied) => {
+        BKError::GetTokenPhoneError(Error::Denied) => {
             let error = i18n(
                 "Please enter your phone number in the format: \n + your country code and your phone 
number.",
             );
             APPOP!(show_error_dialog_in_settings, (error));
         }
-        BKResponse::GetTokenPhoneError(err) => {
+        BKError::GetTokenPhoneError(err) => {
             let error = i18n("Couldn’t add the phone number.");
             let err_str = format!("{:?}", err);
             error!(
@@ -73,7 +73,7 @@ pub fn dispatch_error(error: BKResponse) {
             );
             APPOP!(show_error_dialog_in_settings, (error));
         }
-        BKResponse::NewRoomError(err, internal_id) => {
+        BKError::NewRoomError(err, internal_id) => {
             let err_str = format!("{:?}", err);
             error!(
                 "{}",
@@ -86,7 +86,7 @@ pub fn dispatch_error(error: BKResponse) {
             APPOP!(show_error, (error));
             APPOP!(set_state, (state));
         }
-        BKResponse::JoinRoomError(err) => {
+        BKError::JoinRoomError(err) => {
             let err_str = format!("{:?}", err);
             error!(
                 "{}",
@@ -97,21 +97,21 @@ pub fn dispatch_error(error: BKResponse) {
             APPOP!(show_error, (error));
             APPOP!(set_state, (state));
         }
-        BKResponse::ChangeLanguageError(err) => {
+        BKError::ChangeLanguageError(err) => {
             let err_str = format!("{:?}", err);
             error!(
                 "Error forming url to set room language: {}",
                 remove_matrix_access_token_if_present(&err_str).unwrap_or(err_str)
             );
         }
-        BKResponse::LoginError(_) => {
+        BKError::LoginError(_) => {
             let error = i18n("Can’t login, try again");
             let st = AppState::Login;
             APPOP!(show_error, (error));
             APPOP!(logout);
             APPOP!(set_state, (st));
         }
-        BKResponse::AttachedFileError(err) => {
+        BKError::AttachedFileError(err) => {
             let err_str = format!("{:?}", err);
             error!(
                 "attaching {}: retrying send",
@@ -119,24 +119,24 @@ pub fn dispatch_error(error: BKResponse) {
             );
             APPOP!(retry_send);
         }
-        BKResponse::SentMsgError(Error::SendMsgError(txid)) => {
+        BKError::SentMsgError(Error::SendMsgError(txid)) => {
             error!("sending {}: retrying send", txid);
             APPOP!(retry_send);
         }
-        BKResponse::SentMsgError(_) => {
+        BKError::SentMsgError(_) => {
             let error = i18n("Error sending message");
             APPOP!(show_error, (error));
         }
-        BKResponse::SentMsgRedactionError(_) => {
+        BKError::SentMsgRedactionError(_) => {
             let error = i18n("Error deleting message");
             APPOP!(show_error, (error));
         }
-        BKResponse::DirectoryProtocolsError(_) | BKResponse::DirectorySearchError(_) => {
+        BKError::DirectoryProtocolsError(_) | BKError::DirectorySearchError(_) => {
             let error = i18n("Error searching for rooms");
             APPOP!(reset_directory_state);
             APPOP!(show_error, (error));
         }
-        BKResponse::SyncError(err, number_tries) => {
+        BKError::SyncError(err, number_tries) => {
             let err_str = format!("{:?}", err);
             error!(
                 "SYNC Error: {}",
diff --git a/fractal-gtk/src/app/connect/language.rs b/fractal-gtk/src/app/connect/language.rs
index c7fe01f1..0f8a3145 100644
--- a/fractal-gtk/src/app/connect/language.rs
+++ b/fractal-gtk/src/app/connect/language.rs
@@ -1,6 +1,6 @@
 use crate::app::dispatch_error;
 use crate::app::App;
-use crate::backend::BKResponse;
+use crate::error::BKError;
 
 use crate::backend::room;
 use glib::object::Cast;
@@ -37,7 +37,7 @@ impl App {
                             thread::spawn(move || {
                                 let query = room::set_language(access_token, server, uid, room_id, 
lang_code);
                                 if let Err(err) = query {
-                                    dispatch_error(BKResponse::ChangeLanguageError(err));
+                                    dispatch_error(BKError::ChangeLanguageError(err));
                                 }
                             });
                         }
diff --git a/fractal-gtk/src/appop/account.rs b/fractal-gtk/src/appop/account.rs
index abaf6bcf..15f73310 100644
--- a/fractal-gtk/src/appop/account.rs
+++ b/fractal-gtk/src/appop/account.rs
@@ -9,7 +9,7 @@ use crate::app::App;
 use crate::appop::AppOp;
 use crate::appop::AppState;
 
-use crate::backend::BKResponse;
+use crate::error::BKError;
 use crate::i18n::i18n;
 use crate::widgets;
 use crate::widgets::AvatarExt;
@@ -34,7 +34,7 @@ impl AppOp {
                     APPOP!(set_three_pid, (l));
                 }
                 Err(err) => {
-                    dispatch_error(BKResponse::GetThreePIDError(err));
+                    dispatch_error(BKError::GetThreePIDError(err));
                 }
             }
         });
@@ -60,7 +60,7 @@ impl AppOp {
                             APPOP!(added_three_pid);
                         }
                         Err(err) => {
-                            dispatch_error(BKResponse::AddThreePIDError(err));
+                            dispatch_error(BKError::AddThreePIDError(err));
                         }
                     }
                 });
@@ -127,7 +127,7 @@ impl AppOp {
                                 APPOP!(valid_phone_token, (sid, secret));
                             }
                             Err(err) => {
-                                dispatch_error(BKResponse::SubmitPhoneTokenError(err));
+                                dispatch_error(BKError::SubmitPhoneTokenError(err));
                             }
                         }
                     });
@@ -175,7 +175,7 @@ impl AppOp {
                             APPOP!(added_three_pid);
                         }
                         Err(err) => {
-                            dispatch_error(BKResponse::AddThreePIDError(err));
+                            dispatch_error(BKError::AddThreePIDError(err));
                         }
                     }
                 });
@@ -618,7 +618,7 @@ impl AppOp {
                         APPOP!(show_new_username, (u));
                     }
                     Err(err) => {
-                        dispatch_error(BKResponse::SetUserNameError(err));
+                        dispatch_error(BKError::SetUserNameError(err));
                     }
                 }
             });
@@ -689,7 +689,7 @@ impl AppOp {
                                 APPOP!(password_changed);
                             }
                             Err(err) => {
-                                dispatch_error(BKResponse::ChangePasswordError(err));
+                                dispatch_error(BKError::ChangePasswordError(err));
                             }
                         }
                     });
@@ -805,7 +805,7 @@ impl AppOp {
                                 APPOP!(account_destruction_logoff);
                             }
                             Err(err) => {
-                                dispatch_error(BKResponse::AccountDestructionError(err));
+                                dispatch_error(BKError::AccountDestructionError(err));
                             }
                         }
                     });
diff --git a/fractal-gtk/src/appop/directory.rs b/fractal-gtk/src/appop/directory.rs
index 397ab860..0220b0ce 100644
--- a/fractal-gtk/src/appop/directory.rs
+++ b/fractal-gtk/src/appop/directory.rs
@@ -8,7 +8,7 @@ use crate::app::dispatch_error;
 use crate::app::App;
 use crate::appop::AppOp;
 
-use crate::backend::BKResponse;
+use crate::error::BKError;
 use crate::widgets;
 
 use super::RoomSearchPagination;
@@ -24,7 +24,7 @@ impl AppOp {
                     APPOP!(set_protocols, (protocols));
                 }
                 Err(err) => {
-                    dispatch_error(BKResponse::DirectoryProtocolsError(err));
+                    dispatch_error(BKError::DirectoryProtocolsError(err));
                 }
             }
         });
@@ -152,7 +152,7 @@ impl AppOp {
                     APPOP!(append_directory_rooms, (rooms, rooms_since));
                 }
                 Err(err) => {
-                    dispatch_error(BKResponse::DirectorySearchError(err));
+                    dispatch_error(BKError::DirectorySearchError(err));
                 }
             }
         });
diff --git a/fractal-gtk/src/appop/invite.rs b/fractal-gtk/src/appop/invite.rs
index fd0345cf..cd6c66d5 100644
--- a/fractal-gtk/src/appop/invite.rs
+++ b/fractal-gtk/src/appop/invite.rs
@@ -10,7 +10,7 @@ use crate::app::App;
 use crate::appop::member::SearchType;
 use crate::appop::AppOp;
 
-use crate::backend::BKResponse;
+use crate::error::BKError;
 
 use crate::globals;
 
@@ -174,7 +174,7 @@ impl AppOp {
                 thread::spawn(move || {
                     let query = room::invite(server, access_token, room_id, user_id);
                     if let Err(err) = query {
-                        dispatch_error(BKResponse::InviteError(err));
+                        dispatch_error(BKError::InviteError(err));
                     }
                 });
             }
@@ -237,7 +237,7 @@ impl AppOp {
                             APPOP!(reload_rooms);
                         }
                         Err(err) => {
-                            dispatch_error(BKResponse::JoinRoomError(err));
+                            dispatch_error(BKError::JoinRoomError(err));
                         }
                     }
                 });
@@ -246,7 +246,7 @@ impl AppOp {
                     let query =
                         room::leave_room(login_data.server_url, login_data.access_token, room_id);
                     if let Err(err) = query {
-                        dispatch_error(BKResponse::LeaveRoomError(err));
+                        dispatch_error(BKError::LeaveRoomError(err));
                     }
                 });
             }
diff --git a/fractal-gtk/src/appop/login.rs b/fractal-gtk/src/appop/login.rs
index 416071c4..78a67656 100644
--- a/fractal-gtk/src/appop/login.rs
+++ b/fractal-gtk/src/appop/login.rs
@@ -10,8 +10,8 @@ use crate::app::dispatch_error;
 use crate::app::App;
 use crate::appop::AppOp;
 
-use crate::backend::BKResponse;
 use crate::cache;
+use crate::error::BKError;
 
 use std::thread;
 
@@ -85,7 +85,7 @@ impl AppOp {
                     APPOP!(bk_login, (uid, tk, dev, server, identity));
                 }
                 Err(err) => {
-                    dispatch_error(BKResponse::LoginError(err));
+                    dispatch_error(BKError::LoginError(err));
                 }
             },
         );
@@ -103,7 +103,7 @@ impl AppOp {
                     APPOP!(bk_logout);
                 }
                 Err(err) => {
-                    dispatch_error(BKResponse::LogoutError(err));
+                    dispatch_error(BKError::LogoutError(err));
                 }
             }
         });
diff --git a/fractal-gtk/src/appop/member.rs b/fractal-gtk/src/appop/member.rs
index beb78b34..a2a41a50 100644
--- a/fractal-gtk/src/appop/member.rs
+++ b/fractal-gtk/src/appop/member.rs
@@ -10,7 +10,7 @@ use std::thread;
 use crate::actions::AppState;
 use crate::app::dispatch_error;
 use crate::appop::AppOp;
-use crate::backend::BKResponse;
+use crate::error::BKError;
 use crate::widgets;
 use crate::App;
 
@@ -197,7 +197,7 @@ impl AppOp {
                     APPOP!(user_search_finished, (users));
                 }
                 Err(err) => {
-                    dispatch_error(BKResponse::UserSearchError(err));
+                    dispatch_error(BKError::UserSearchError(err));
                 }
             }
         });
diff --git a/fractal-gtk/src/appop/message.rs b/fractal-gtk/src/appop/message.rs
index ffa859da..72214461 100644
--- a/fractal-gtk/src/appop/message.rs
+++ b/fractal-gtk/src/appop/message.rs
@@ -24,7 +24,7 @@ use crate::appop::room::Force;
 use crate::appop::AppOp;
 use crate::App;
 
-use crate::backend::BKResponse;
+use crate::error::BKError;
 use crate::uitypes::MessageContent;
 use crate::uitypes::RowType;
 use crate::widgets;
@@ -169,7 +169,7 @@ impl AppOp {
                         APPOP!(clear_room_notifications, (r));
                     }
                     Err(err) => {
-                        dispatch_error(BKResponse::MarkedAsReadError(err));
+                        dispatch_error(BKError::MarkedAsReadError(err));
                     }
                 }
             });
@@ -227,7 +227,7 @@ impl AppOp {
                                 APPOP!(sync, (initial, number_tries));
                             }
                             Err(err) => {
-                                dispatch_error(BKResponse::SentMsgError(err));
+                                dispatch_error(BKError::SentMsgError(err));
                             }
                         }
                     });
@@ -661,7 +661,7 @@ fn attach_file(baseu: Url, tk: AccessToken, mut msg: Message) {
                 msg.extra_content = serde_json::to_value(&extra_content).ok();
             }
             Err(err) => {
-                dispatch_error(BKResponse::AttachedFileError(err));
+                dispatch_error(BKError::AttachedFileError(err));
             }
         }
 
@@ -682,7 +682,7 @@ fn attach_file(baseu: Url, tk: AccessToken, mut msg: Message) {
             APPOP!(attached_file, (msg));
         }
         Err(err) => {
-            dispatch_error(BKResponse::AttachedFileError(err));
+            dispatch_error(BKError::AttachedFileError(err));
         }
     };
 }
@@ -696,7 +696,7 @@ fn send_msg_and_manage(baseu: Url, tk: AccessToken, msg: Message) {
             APPOP!(sync, (initial, number_tries));
         }
         Err(err) => {
-            dispatch_error(BKResponse::SentMsgError(err));
+            dispatch_error(BKError::SentMsgError(err));
         }
     };
 }
diff --git a/fractal-gtk/src/appop/room.rs b/fractal-gtk/src/appop/room.rs
index ce47102e..94fc4e1a 100644
--- a/fractal-gtk/src/appop/room.rs
+++ b/fractal-gtk/src/appop/room.rs
@@ -14,7 +14,7 @@ use crate::app::dispatch_error;
 use crate::app::App;
 use crate::appop::AppOp;
 
-use crate::backend::BKResponse;
+use crate::error::BKError;
 use fractal_api::util::cache_dir_path;
 
 use crate::actions;
@@ -86,7 +86,7 @@ impl AppOp {
                             APPOP!(set_room_members, (room, members));
                         }
                         Err(err) => {
-                            dispatch_error(BKResponse::RoomMembersError(err));
+                            dispatch_error(BKError::RoomMembersError(err));
                         }
                     }
                 });
@@ -101,7 +101,7 @@ impl AppOp {
                             APPOP!(set_room_avatar, (room, avatar));
                         }
                         Err(err) => {
-                            dispatch_error(BKResponse::RoomAvatarError(err));
+                            dispatch_error(BKError::RoomAvatarError(err));
                         }
                     },
                 );
@@ -154,7 +154,7 @@ impl AppOp {
                             APPOP!(added_to_fav, (r, tofav));
                         }
                         Err(err) => {
-                            dispatch_error(BKResponse::AddedToFavError(err));
+                            dispatch_error(BKError::AddedToFavError(err));
                         }
                     }
                 });
@@ -252,7 +252,7 @@ impl AppOp {
                     APPOP!(set_room_avatar, (room, avatar));
                 }
                 Err(err) => {
-                    dispatch_error(BKResponse::RoomAvatarError(err));
+                    dispatch_error(BKError::RoomAvatarError(err));
                 }
             },
         );
@@ -267,7 +267,7 @@ impl AppOp {
                     APPOP!(set_room_detail, (room, key, v));
                 }
                 Err(err) => {
-                    dispatch_error(BKResponse::RoomDetailError(err));
+                    dispatch_error(BKError::RoomDetailError(err));
                 }
             }
         });
@@ -333,7 +333,7 @@ impl AppOp {
         thread::spawn(move || {
             let query = room::leave_room(login_data.server_url, login_data.access_token, room_id);
             if let Err(err) = query {
-                dispatch_error(BKResponse::LeaveRoomError(err));
+                dispatch_error(BKError::LeaveRoomError(err));
             }
         });
         self.rooms.remove(&r);
@@ -414,7 +414,7 @@ impl AppOp {
                     APPOP!(new_room, (r, id));
                 }
                 Err(err) => {
-                    dispatch_error(BKResponse::NewRoomError(err, int_id));
+                    dispatch_error(BKError::NewRoomError(err, int_id));
                 }
             }
         });
@@ -570,7 +570,7 @@ impl AppOp {
                     APPOP!(reload_rooms);
                 }
                 Err(err) => {
-                    dispatch_error(BKResponse::JoinRoomError(err));
+                    dispatch_error(BKError::JoinRoomError(err));
                 }
             }
         });
@@ -714,7 +714,7 @@ impl AppOp {
                     APPOP!(set_room_avatar, (room, avatar));
                 }
                 Err(err) => {
-                    dispatch_error(BKResponse::RoomAvatarError(err));
+                    dispatch_error(BKError::RoomAvatarError(err));
                 }
             }
         });
@@ -768,7 +768,7 @@ impl AppOp {
                 active_room,
             );
             if let Err(err) = query {
-                dispatch_error(BKResponse::SendTypingError(err));
+                dispatch_error(BKError::SendTypingError(err));
             }
         });
     }
diff --git a/fractal-gtk/src/appop/start_chat.rs b/fractal-gtk/src/appop/start_chat.rs
index 8eac5c0b..0e280ea7 100644
--- a/fractal-gtk/src/appop/start_chat.rs
+++ b/fractal-gtk/src/appop/start_chat.rs
@@ -9,7 +9,7 @@ use crate::app::App;
 use crate::appop::AppOp;
 use crate::appop::SearchType;
 
-use crate::backend::BKResponse;
+use crate::error::BKError;
 use crate::types::{Room, RoomMembership, RoomTag};
 
 impl AppOp {
@@ -38,7 +38,7 @@ impl AppOp {
                     APPOP!(new_room, (r, id));
                 }
                 Err(err) => {
-                    dispatch_error(BKResponse::NewRoomError(err, int_id));
+                    dispatch_error(BKError::NewRoomError(err, int_id));
                 }
             }
         });
diff --git a/fractal-gtk/src/appop/sync.rs b/fractal-gtk/src/appop/sync.rs
index 5fe288fd..79fe77ce 100644
--- a/fractal-gtk/src/appop/sync.rs
+++ b/fractal-gtk/src/appop/sync.rs
@@ -6,11 +6,8 @@ use crate::i18n::i18n;
 use crate::app::dispatch_error;
 use crate::app::App;
 use crate::appop::AppOp;
-
-use crate::backend::{
-    sync::{self, RoomElement, SyncRet},
-    BKResponse,
-};
+use crate::backend::sync::{self, RoomElement, SyncRet};
+use crate::error::BKError;
 
 impl AppOp {
     pub fn initial_sync(&self, show: bool) {
@@ -54,7 +51,7 @@ impl AppOp {
                                 }
                             }
                             Err(err) => {
-                                dispatch_error(BKResponse::RoomsError(err));
+                                dispatch_error(BKError::RoomsError(err));
                             }
                         };
 
@@ -76,7 +73,7 @@ impl AppOp {
                                 APPOP!(set_rooms, (rooms, clear_room_list));
                             }
                             Err(err) => {
-                                dispatch_error(BKResponse::UpdateRoomsError(err));
+                                dispatch_error(BKError::UpdateRoomsError(err));
                             }
                         }
 
@@ -85,7 +82,7 @@ impl AppOp {
                                 APPOP!(show_room_messages, (msgs));
                             }
                             Err(err) => {
-                                dispatch_error(BKResponse::RoomMessagesError(err));
+                                dispatch_error(BKError::RoomMessagesError(err));
                             }
                         }
 
@@ -95,7 +92,7 @@ impl AppOp {
                                 APPOP!(set_rooms, (rooms, clear_room_list));
                             }
                             Err(err) => {
-                                dispatch_error(BKResponse::UpdateRoomsError(err));
+                                dispatch_error(BKError::UpdateRoomsError(err));
                             }
                         }
 
@@ -131,7 +128,7 @@ impl AppOp {
                                 }
                             }
                             Err(err) => {
-                                dispatch_error(BKResponse::RoomElementError(err));
+                                dispatch_error(BKError::RoomElementError(err));
                             }
                         }
 
@@ -140,7 +137,7 @@ impl AppOp {
                         APPOP!(synced, (s));
                     }
                     Err((err, n_tries)) => {
-                        dispatch_error(BKResponse::SyncError(err, n_tries));
+                        dispatch_error(BKError::SyncError(err, n_tries));
                     }
                 }
             });
diff --git a/fractal-gtk/src/appop/user.rs b/fractal-gtk/src/appop/user.rs
index 0feb54bb..dd83d451 100644
--- a/fractal-gtk/src/appop/user.rs
+++ b/fractal-gtk/src/appop/user.rs
@@ -12,7 +12,7 @@ use crate::appop::AppOp;
 
 use crate::cache::download_to_cache;
 
-use crate::backend::BKResponse;
+use crate::error::BKError;
 use crate::widgets;
 use crate::widgets::AvatarExt;
 
@@ -28,7 +28,7 @@ impl AppOp {
                     APPOP!(set_username, (username));
                 }
                 Err(err) => {
-                    dispatch_error(BKResponse::NameError(err));
+                    dispatch_error(BKError::NameError(err));
                 }
             }
         }));
@@ -39,7 +39,7 @@ impl AppOp {
                     APPOP!(set_avatar, (path));
                 }
                 Err(err) => {
-                    dispatch_error(BKResponse::AvatarError(err));
+                    dispatch_error(BKError::AvatarError(err));
                 }
             }
         }));
diff --git a/fractal-gtk/src/widgets/address.rs b/fractal-gtk/src/widgets/address.rs
index 3eb09833..f8b739ff 100644
--- a/fractal-gtk/src/widgets/address.rs
+++ b/fractal-gtk/src/widgets/address.rs
@@ -11,7 +11,7 @@ use std::thread;
 use crate::app::dispatch_error;
 use crate::app::App;
 use crate::appop::AppOp;
-use crate::backend::BKResponse;
+use crate::error::BKError;
 
 #[derive(Debug, Clone)]
 pub enum AddressType {
@@ -213,7 +213,7 @@ fn delete_address(medium: Medium, address: String, server_url: Url, access_token
                 APPOP!(get_three_pid);
             }
             Err(err) => {
-                dispatch_error(BKResponse::DeleteThreePIDError(err));
+                dispatch_error(BKError::DeleteThreePIDError(err));
             }
         }
     });
@@ -236,7 +236,7 @@ fn add_address(
                     APPOP!(get_token_phone, (sid, secret))
                 }
                 Err(err) => {
-                    dispatch_error(BKResponse::GetTokenPhoneError(err));
+                    dispatch_error(BKError::GetTokenPhoneError(err));
                 }
             }
         }
@@ -248,7 +248,7 @@ fn add_address(
                     APPOP!(get_token_email, (sid, secret));
                 }
                 Err(err) => {
-                    dispatch_error(BKResponse::GetTokenEmailError(err));
+                    dispatch_error(BKError::GetTokenEmailError(err));
                 }
             }
         }
diff --git a/fractal-gtk/src/widgets/room.rs b/fractal-gtk/src/widgets/room.rs
index 8a62392d..fcac53b0 100644
--- a/fractal-gtk/src/widgets/room.rs
+++ b/fractal-gtk/src/widgets/room.rs
@@ -6,7 +6,7 @@ use std::thread;
 
 use crate::types::Room;
 
-use crate::backend::BKResponse;
+use crate::error::BKError;
 
 use crate::util::markup_text;
 
@@ -136,7 +136,7 @@ impl<'a> RoomBox<'a> {
                             APPOP!(set_join_to_room, (jtr));
                             APPOP!(reload_rooms);
                         }
-                        Err(err) => dispatch_error(BKResponse::JoinRoomError(err)),
+                        Err(err) => dispatch_error(BKError::JoinRoomError(err)),
                     }
                 });
             });
diff --git a/fractal-gtk/src/widgets/room_settings.rs b/fractal-gtk/src/widgets/room_settings.rs
index 12407020..c2964257 100644
--- a/fractal-gtk/src/widgets/room_settings.rs
+++ b/fractal-gtk/src/widgets/room_settings.rs
@@ -15,7 +15,7 @@ use crate::actions;
 use crate::actions::{ButtonState, StateExt};
 use crate::app::dispatch_error;
 use crate::app::App;
-use crate::backend::BKResponse;
+use crate::error::BKError;
 use crate::types::Member;
 use crate::types::Room;
 use crate::util::markup_text;
@@ -434,7 +434,7 @@ impl RoomSettings {
                     APPOP!(set_room_avatar, (room, avatar));
                 }
                 Err(err) => {
-                    dispatch_error(BKResponse::RoomAvatarError(err));
+                    dispatch_error(BKError::RoomAvatarError(err));
                 }
             },
         );
@@ -505,7 +505,7 @@ impl RoomSettings {
                     APPOP!(show_new_room_name);
                 }
                 Err(err) => {
-                    dispatch_error(BKResponse::SetRoomNameError(err));
+                    dispatch_error(BKError::SetRoomNameError(err));
                 }
             },
         );
@@ -563,7 +563,7 @@ impl RoomSettings {
                     APPOP!(show_new_room_topic);
                 }
                 Err(err) => {
-                    dispatch_error(BKResponse::SetRoomTopicError(err));
+                    dispatch_error(BKError::SetRoomTopicError(err));
                 }
             },
         );
diff --git a/fractal-matrix-api/src/backend/directory.rs b/fractal-matrix-api/src/backend/directory.rs
index 41d2fcd1..a482cdfc 100644
--- a/fractal-matrix-api/src/backend/directory.rs
+++ b/fractal-matrix-api/src/backend/directory.rs
@@ -5,8 +5,6 @@ use crate::globals;
 use crate::error::Error;
 
 use crate::util::cache_dir_path;
-use crate::util::dw_media;
-use crate::util::ContentType;
 use crate::util::HTTP_CLIENT;
 
 use crate::r0::directory::post_public_rooms::request as post_public_rooms;
@@ -22,6 +20,8 @@ use crate::r0::thirdparty::get_supported_protocols::Response as SupportedProtoco
 use crate::r0::AccessToken;
 use crate::types::Room;
 
+use super::{dw_media, ContentType};
+
 pub fn protocols(base: Url, access_token: AccessToken) -> Result<Vec<ProtocolInstance>, Error> {
     let params = SupportedProtocolsParameters { access_token };
     let request = get_supported_protocols(base, &params)?;
diff --git a/fractal-matrix-api/src/backend/media.rs b/fractal-matrix-api/src/backend/media.rs
index f41ca378..f51f7fff 100644
--- a/fractal-matrix-api/src/backend/media.rs
+++ b/fractal-matrix-api/src/backend/media.rs
@@ -5,9 +5,6 @@ use std::sync::mpsc::Sender;
 use url::Url;
 
 use crate::r0::AccessToken;
-use crate::util::dw_media;
-use crate::util::get_prev_batch_from;
-use crate::util::ContentType;
 use crate::util::ResultExpectLog;
 use crate::util::HTTP_CLIENT;
 
@@ -18,7 +15,7 @@ use crate::r0::message::get_message_events::Parameters as GetMessagesEventsParam
 use crate::r0::message::get_message_events::Response as GetMessagesEventsResponse;
 use crate::types::Message;
 
-use super::ThreadPool;
+use super::{dw_media, get_prev_batch_from, ContentType, ThreadPool};
 
 pub fn get_thumb_async(
     thread_pool: ThreadPool,
diff --git a/fractal-matrix-api/src/backend/mod.rs b/fractal-matrix-api/src/backend/mod.rs
index d77c58d4..3bcb9540 100644
--- a/fractal-matrix-api/src/backend/mod.rs
+++ b/fractal-matrix-api/src/backend/mod.rs
@@ -1,8 +1,24 @@
-use ruma_identifiers::RoomId;
+use lazy_static::lazy_static;
+use ruma_identifiers::{EventId, RoomId};
+use std::fs::write;
+use std::io::Read;
+use std::path::Path;
 use std::sync::{Arc, Condvar, Mutex};
 use std::thread;
+use url::Url;
 
+use crate::client::Client;
 use crate::error::Error;
+use crate::r0::context::get_context::request as get_context;
+use crate::r0::context::get_context::Parameters as GetContextParameters;
+use crate::r0::context::get_context::Response as GetContextResponse;
+use crate::r0::media::get_content::request as get_content;
+use crate::r0::media::get_content::Parameters as GetContentParameters;
+use crate::r0::media::get_content_thumbnail::request as get_content_thumbnail;
+use crate::r0::media::get_content_thumbnail::Method;
+use crate::r0::media::get_content_thumbnail::Parameters as GetContentThumbnailParameters;
+use crate::r0::AccessToken;
+use crate::util::{cache_dir_path, HTTP_CLIENT};
 
 pub mod directory;
 pub mod media;
@@ -11,52 +27,8 @@ pub mod room;
 pub mod sync;
 pub mod user;
 
-#[derive(Debug)]
-pub enum BKResponse {
-    //errors
-    LoginError(Error),
-    GuestLoginError(Error),
-    SendTypingError(Error),
-    SetRoomError(Error),
-    InviteError(Error),
-    ChangeLanguageError(Error),
-    NameError(Error),
-    AvatarError(Error),
-    MarkedAsReadError(Error),
-    UserSearchError(Error),
-    LogoutError(Error),
-    LeaveRoomError(Error),
-    DirectoryProtocolsError(Error),
-    RoomMembersError(Error),
-    AddedToFavError(Error),
-    GetThreePIDError(Error),
-    AddThreePIDError(Error),
-    SubmitPhoneTokenError(Error),
-    SetUserNameError(Error),
-    ChangePasswordError(Error),
-    AccountDestructionError(Error),
-    DeleteThreePIDError(Error),
-    GetTokenPhoneError(Error),
-    GetTokenEmailError(Error),
-    SetRoomNameError(Error),
-    SetRoomTopicError(Error),
-    SetUserAvatarError(Error),
-    SetRoomAvatarError(Error),
-    RoomMessagesToError(Error),
-    MediaError(Error),
-    SentMsgRedactionError(Error),
-    JoinRoomError(Error),
-    DirectorySearchError(Error),
-    NewRoomError(Error, RoomId),
-    RoomDetailError(Error),
-    RoomAvatarError(Error),
-    SentMsgError(Error),
-    AttachedFileError(Error),
-    RoomsError(Error),
-    UpdateRoomsError(Error),
-    RoomMessagesError(Error),
-    RoomElementError(Error),
-    SyncError(Error, u64),
+lazy_static! {
+    pub static ref HTTP_CLIENT: Client = Client::new();
 }
 
 #[derive(Clone, Debug)]
@@ -101,3 +73,97 @@ impl ThreadPool {
         });
     }
 }
+
+pub enum ContentType {
+    Download,
+    Thumbnail(u64, u64),
+}
+
+impl ContentType {
+    pub fn default_thumbnail() -> Self {
+        ContentType::Thumbnail(128, 128)
+    }
+
+    pub fn is_thumbnail(&self) -> bool {
+        match self {
+            ContentType::Download => false,
+            ContentType::Thumbnail(_, _) => true,
+        }
+    }
+}
+
+pub fn get_prev_batch_from(
+    base: Url,
+    access_token: AccessToken,
+    room_id: &RoomId,
+    event_id: &EventId,
+) -> Result<String, Error> {
+    let params = GetContextParameters {
+        access_token,
+        limit: 0,
+        filter: Default::default(),
+    };
+
+    let request = get_context(base, &params, room_id, event_id)?;
+    let response: GetContextResponse = HTTP_CLIENT.get_client()?.execute(request)?.json()?;
+    let prev_batch = response.start.unwrap_or_default();
+
+    Ok(prev_batch)
+}
+
+pub fn dw_media(
+    base: Url,
+    mxc: &str,
+    media_type: ContentType,
+    dest: Option<String>,
+) -> Result<String, Error> {
+    let mxc_url = Url::parse(mxc)?;
+
+    if mxc_url.scheme() != "mxc" {
+        return Err(Error::BackendError);
+    }
+
+    let server = mxc_url.host().ok_or(Error::BackendError)?.to_owned();
+    let media_id = mxc_url
+        .path_segments()
+        .and_then(|mut ps| ps.next())
+        .filter(|s| !s.is_empty())
+        .ok_or(Error::BackendError)?;
+
+    let request = if let ContentType::Thumbnail(width, height) = media_type {
+        let params = GetContentThumbnailParameters {
+            width,
+            height,
+            method: Some(Method::Crop),
+            allow_remote: true,
+        };
+        get_content_thumbnail(base, &params, &server, &media_id)
+    } else {
+        let params = GetContentParameters::default();
+        get_content(base, &params, &server, &media_id)
+    }?;
+
+    let fname = match dest {
+        None if media_type.is_thumbnail() => cache_dir_path(Some("thumbs"), &media_id)?,
+        None => cache_dir_path(Some("medias"), &media_id)?,
+        Some(ref d) => d.clone(),
+    };
+
+    let fpath = Path::new(&fname);
+
+    // If the file is already cached and recent enough, don't download it
+    if fpath.is_file()
+        && (dest.is_none() || fpath.metadata()?.modified()?.elapsed()?.as_secs() < 60)
+    {
+        Ok(fname)
+    } else {
+        HTTP_CLIENT
+            .get_client()?
+            .execute(request)?
+            .bytes()
+            .collect::<Result<Vec<u8>, std::io::Error>>()
+            .and_then(|media| write(&fname, media))
+            .and(Ok(fname))
+            .map_err(Into::into)
+    }
+}
diff --git a/fractal-matrix-api/src/backend/room.rs b/fractal-matrix-api/src/backend/room.rs
index 065d514f..f50e05ba 100644
--- a/fractal-matrix-api/src/backend/room.rs
+++ b/fractal-matrix-api/src/backend/room.rs
@@ -13,9 +13,6 @@ use crate::error::Error;
 use crate::globals;
 
 use crate::util::cache_dir_path;
-use crate::util::dw_media;
-use crate::util::get_prev_batch_from;
-use crate::util::ContentType;
 use crate::util::HTTP_CLIENT;
 
 use crate::r0::config::get_global_account_data::request as get_global_account_data;
@@ -78,6 +75,8 @@ use crate::types::{Room, RoomMembership, RoomTag};
 
 use serde_json::Value as JsonValue;
 
+use super::{dw_media, get_prev_batch_from, ContentType};
+
 pub fn get_room_detail(
     base: Url,
     access_token: AccessToken,
diff --git a/fractal-matrix-api/src/backend/sync.rs b/fractal-matrix-api/src/backend/sync.rs
index 08bb1d01..686e6204 100644
--- a/fractal-matrix-api/src/backend/sync.rs
+++ b/fractal-matrix-api/src/backend/sync.rs
@@ -1,5 +1,5 @@
 use crate::client::ProxySettings;
-use crate::error::Error;
+use crate::error::{Error, StandardErrorResponse};
 use crate::globals;
 use crate::r0::filter::EventFilter;
 use crate::r0::filter::Filter;
@@ -17,11 +17,11 @@ use crate::types::Message;
 use crate::types::Room;
 use crate::types::RoomMembership;
 use crate::types::RoomTag;
-use crate::util::matrix_response;
 
 use log::error;
-use reqwest::blocking::Client;
+use reqwest::blocking::{Client, Response};
 use ruma_identifiers::{EventId, RoomId, UserId};
+use serde::de::DeserializeOwned;
 use serde_json::value::from_value;
 use std::{
     collections::HashMap,
@@ -298,3 +298,16 @@ pub fn sync(
         }
     }
 }
+
+/// Returns the deserialized response to the given request. Handles Matrix errors.
+fn matrix_response<T: DeserializeOwned>(response: Response) -> Result<T, Error> {
+    if !response.status().is_success() {
+        let status = response.status();
+        return match response.json::<StandardErrorResponse>() {
+            Ok(error_response) => Err(Error::from(error_response)),
+            Err(_) => Err(Error::NetworkError(status)),
+        };
+    }
+
+    response.json::<T>().map_err(Into::into)
+}
diff --git a/fractal-matrix-api/src/backend/user.rs b/fractal-matrix-api/src/backend/user.rs
index 10236686..1e024ea7 100644
--- a/fractal-matrix-api/src/backend/user.rs
+++ b/fractal-matrix-api/src/backend/user.rs
@@ -5,7 +5,7 @@ use url::Url;
 use crate::backend::ThreadPool;
 use crate::cache::CacheMap;
 use crate::error::Error;
-use crate::util::get_user_avatar;
+use crate::util::cache_dir_path;
 use crate::util::ResultExpectLog;
 use crate::util::HTTP_CLIENT;
 use std::convert::TryInto;
@@ -49,6 +49,8 @@ use crate::r0::media::create_content::Parameters as CreateContentParameters;
 use crate::r0::media::create_content::Response as CreateContentResponse;
 use crate::r0::profile::get_display_name::request as get_display_name;
 use crate::r0::profile::get_display_name::Response as GetDisplayNameResponse;
+use crate::r0::profile::get_profile::request as get_profile;
+use crate::r0::profile::get_profile::Response as GetProfileResponse;
 use crate::r0::profile::set_avatar_url::request as set_avatar_url;
 use crate::r0::profile::set_avatar_url::Body as SetAvatarUrlBody;
 use crate::r0::profile::set_avatar_url::Parameters as SetAvatarUrlParameters;
@@ -64,6 +66,8 @@ use crate::r0::Medium;
 use crate::r0::ThreePIDCredentials;
 use crate::types::Member;
 
+use super::{dw_media, ContentType};
+
 pub fn get_username(base: Url, uid: UserId) -> Result<Option<String>, Error> {
     let request = get_display_name(base, &uid)?;
     let response: GetDisplayNameResponse = HTTP_CLIENT.get_client()?.execute(request)?.json()?;
@@ -353,3 +357,35 @@ pub fn search(
 
     Ok(response.results.into_iter().map(Into::into).collect())
 }
+
+pub fn get_user_avatar(base: Url, user_id: &UserId) -> Result<(String, String), Error> {
+    let response = get_profile(base.clone(), user_id)
+        .map_err::<Error, _>(Into::into)
+        .and_then(|request| {
+            HTTP_CLIENT
+                .get_client()?
+                .execute(request)?
+                .json::<GetProfileResponse>()
+                .map_err(Into::into)
+        })?;
+
+    let name = response
+        .displayname
+        .filter(|n| !n.is_empty())
+        .unwrap_or_else(|| user_id.to_string());
+
+    let img = response
+        .avatar_url
+        .map(|url| {
+            let dest = cache_dir_path(None, &user_id.to_string())?;
+            dw_media(
+                base,
+                url.as_str(),
+                ContentType::default_thumbnail(),
+                Some(dest),
+            )
+        })
+        .unwrap_or_else(|| Ok(Default::default()))?;
+
+    Ok((name, img))
+}
diff --git a/fractal-matrix-api/src/error.rs b/fractal-matrix-api/src/error.rs
index e6c19cc0..02086a5a 100644
--- a/fractal-matrix-api/src/error.rs
+++ b/fractal-matrix-api/src/error.rs
@@ -1,4 +1,4 @@
-use ruma_identifiers::EventId;
+use ruma_identifiers::{EventId, RoomId};
 use std::io;
 use std::time::SystemTimeError;
 
@@ -57,3 +57,50 @@ derror!(ruma_identifiers::Error, Error::BackendError);
 derror!(SystemTimeError, Error::BackendError);
 
 derror!(serde_json::Error, Error::CacheError);
+
+#[derive(Debug)]
+pub enum BKError {
+    LoginError(Error),
+    GuestLoginError(Error),
+    SendTypingError(Error),
+    SetRoomError(Error),
+    InviteError(Error),
+    ChangeLanguageError(Error),
+    NameError(Error),
+    AvatarError(Error),
+    MarkedAsReadError(Error),
+    UserSearchError(Error),
+    LogoutError(Error),
+    LeaveRoomError(Error),
+    DirectoryProtocolsError(Error),
+    RoomMembersError(Error),
+    AddedToFavError(Error),
+    GetThreePIDError(Error),
+    AddThreePIDError(Error),
+    SubmitPhoneTokenError(Error),
+    SetUserNameError(Error),
+    ChangePasswordError(Error),
+    AccountDestructionError(Error),
+    DeleteThreePIDError(Error),
+    GetTokenPhoneError(Error),
+    GetTokenEmailError(Error),
+    SetRoomNameError(Error),
+    SetRoomTopicError(Error),
+    SetUserAvatarError(Error),
+    SetRoomAvatarError(Error),
+    RoomMessagesToError(Error),
+    MediaError(Error),
+    SentMsgRedactionError(Error),
+    JoinRoomError(Error),
+    DirectorySearchError(Error),
+    NewRoomError(Error, RoomId),
+    RoomDetailError(Error),
+    RoomAvatarError(Error),
+    SentMsgError(Error),
+    AttachedFileError(Error),
+    RoomsError(Error),
+    UpdateRoomsError(Error),
+    RoomMessagesError(Error),
+    RoomElementError(Error),
+    SyncError(Error, u64),
+}
diff --git a/fractal-matrix-api/src/globals.rs b/fractal-matrix-api/src/globals.rs
index 924c85df..6adb51cc 100644
--- a/fractal-matrix-api/src/globals.rs
+++ b/fractal-matrix-api/src/globals.rs
@@ -1,5 +1,7 @@
+use directories::ProjectDirs;
 use lazy_static::lazy_static;
 use regex::Regex;
+use std::path::PathBuf;
 
 pub static TIMEOUT: u64 = 80;
 pub static PAGE_LIMIT: i32 = 40;
@@ -11,4 +13,9 @@ lazy_static! {
         r"^([0-9a-zA-Z]([-\.\w]*[0-9a-zA-Z])+@([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9})$"
     )
     .unwrap();
+    pub static ref CACHE_PATH: PathBuf = ProjectDirs::from("org", "GNOME", "Fractal")
+        .as_ref()
+        .map(ProjectDirs::cache_dir)
+        .map(Into::into)
+        .unwrap_or_else(|| std::env::temp_dir().join("fractal"));
 }
diff --git a/fractal-matrix-api/src/model/room.rs b/fractal-matrix-api/src/model/room.rs
index 4a5293e4..8ecfb8bd 100644
--- a/fractal-matrix-api/src/model/room.rs
+++ b/fractal-matrix-api/src/model/room.rs
@@ -1,12 +1,11 @@
 use serde_json::Value as JsonValue;
 
+use crate::backend::user::get_user_avatar;
 use crate::model::member::Member;
 use crate::model::member::MemberList;
 use crate::model::message::Message;
 use crate::r0::directory::post_public_rooms::Chunk as PublicRoomsChunk;
 use crate::r0::sync::sync_events::Response as SyncResponse;
-use crate::util::get_user_avatar;
-use crate::util::parse_m_direct;
 use log::{debug, info};
 use ruma_identifiers::{Error as IdError, EventId, RoomId, UserId};
 use serde::{Deserialize, Serialize};
@@ -433,3 +432,27 @@ fn parse_room_member(msg: &JsonValue) -> Option<Member> {
         avatar: c["avatar_url"].as_str().map(Into::into),
     })
 }
+
+fn parse_m_direct(events: &[JsonValue]) -> HashMap<UserId, Vec<RoomId>> {
+    events
+        .iter()
+        .find(|x| x["type"] == "m.direct")
+        .and_then(|js| js["content"].as_object())
+        .cloned()
+        .unwrap_or_default()
+        .iter()
+        // Synapse sometimes sends an object with the key "[object Object]"
+        // instead of a user ID, so we have to skip those invalid objects
+        // in the array in order to avoid discarding everything
+        .filter_map(|(uid, rid)| {
+            let value = rid
+                .as_array()
+                .unwrap_or(&vec![])
+                .iter()
+                .map(|rid| RoomId::try_from(rid.as_str().unwrap_or_default()))
+                .collect::<Result<Vec<RoomId>, IdError>>()
+                .ok()?;
+            Some((UserId::try_from(uid.as_str()).ok()?, value))
+        })
+        .collect()
+}
diff --git a/fractal-matrix-api/src/util.rs b/fractal-matrix-api/src/util.rs
index 41cad88d..2095ae6a 100644
--- a/fractal-matrix-api/src/util.rs
+++ b/fractal-matrix-api/src/util.rs
@@ -1,46 +1,11 @@
-use lazy_static::lazy_static;
 use log::error;
 
-use reqwest::blocking::Response;
-use serde::de::DeserializeOwned;
-use serde_json::Value as JsonValue;
-
-use directories::ProjectDirs;
-use ruma_identifiers::{Error as IdError, EventId, RoomId, UserId};
-use std::collections::HashMap;
-use std::convert::TryFrom;
-use std::io::Read;
-use std::path::Path;
-use std::path::PathBuf;
-use url::Url;
-
-use std::fs::{create_dir_all, write};
+use std::fs::create_dir_all;
 
 use std::sync::mpsc::SendError;
 
-use crate::client::Client;
 use crate::error::Error;
-use crate::error::StandardErrorResponse;
-use crate::r0::context::get_context::request as get_context;
-use crate::r0::context::get_context::Parameters as GetContextParameters;
-use crate::r0::context::get_context::Response as GetContextResponse;
-use crate::r0::media::get_content::request as get_content;
-use crate::r0::media::get_content::Parameters as GetContentParameters;
-use crate::r0::media::get_content_thumbnail::request as get_content_thumbnail;
-use crate::r0::media::get_content_thumbnail::Method;
-use crate::r0::media::get_content_thumbnail::Parameters as GetContentThumbnailParameters;
-use crate::r0::profile::get_profile::request as get_profile;
-use crate::r0::profile::get_profile::Response as GetProfileResponse;
-use crate::r0::AccessToken;
-
-lazy_static! {
-    pub static ref HTTP_CLIENT: Client = Client::new();
-    static ref CACHE_PATH: PathBuf = ProjectDirs::from("org", "GNOME", "Fractal")
-        .as_ref()
-        .map(ProjectDirs::cache_dir)
-        .map(Into::into)
-        .unwrap_or_else(|| std::env::temp_dir().join("fractal"));
-}
+use crate::globals::CACHE_PATH;
 
 // from https://stackoverflow.com/a/43992218/1592377
 #[macro_export]
@@ -61,178 +26,6 @@ macro_rules! clone {
     );
 }
 
-#[macro_export]
-macro_rules! bkerror {
-    ($result: expr, $tx: ident, $type: expr) => {
-        if let Err(e) = $result {
-            let _ = $tx.send($type(Err(e)));
-        }
-    };
-}
-
-pub enum ContentType {
-    Download,
-    Thumbnail(u64, u64),
-}
-
-impl ContentType {
-    pub fn default_thumbnail() -> Self {
-        ContentType::Thumbnail(128, 128)
-    }
-
-    pub fn is_thumbnail(&self) -> bool {
-        match self {
-            ContentType::Download => false,
-            ContentType::Thumbnail(_, _) => true,
-        }
-    }
-}
-
-pub fn parse_m_direct(events: &[JsonValue]) -> HashMap<UserId, Vec<RoomId>> {
-    events
-        .iter()
-        .find(|x| x["type"] == "m.direct")
-        .and_then(|js| js["content"].as_object())
-        .cloned()
-        .unwrap_or_default()
-        .iter()
-        // Synapse sometimes sends an object with the key "[object Object]"
-        // instead of a user ID, so we have to skip those invalid objects
-        // in the array in order to avoid discarding everything
-        .filter_map(|(uid, rid)| {
-            let value = rid
-                .as_array()
-                .unwrap_or(&vec![])
-                .iter()
-                .map(|rid| RoomId::try_from(rid.as_str().unwrap_or_default()))
-                .collect::<Result<Vec<RoomId>, IdError>>()
-                .ok()?;
-            Some((UserId::try_from(uid.as_str()).ok()?, value))
-        })
-        .collect()
-}
-
-pub fn get_prev_batch_from(
-    base: Url,
-    access_token: AccessToken,
-    room_id: &RoomId,
-    event_id: &EventId,
-) -> Result<String, Error> {
-    let params = GetContextParameters {
-        access_token,
-        limit: 0,
-        filter: Default::default(),
-    };
-
-    let request = get_context(base, &params, room_id, event_id)?;
-    let response: GetContextResponse = HTTP_CLIENT.get_client()?.execute(request)?.json()?;
-    let prev_batch = response.start.unwrap_or_default();
-
-    Ok(prev_batch)
-}
-
-pub fn dw_media(
-    base: Url,
-    mxc: &str,
-    media_type: ContentType,
-    dest: Option<String>,
-) -> Result<String, Error> {
-    let mxc_url = Url::parse(mxc)?;
-
-    if mxc_url.scheme() != "mxc" {
-        return Err(Error::BackendError);
-    }
-
-    let server = mxc_url.host().ok_or(Error::BackendError)?.to_owned();
-    let media_id = mxc_url
-        .path_segments()
-        .and_then(|mut ps| ps.next())
-        .filter(|s| !s.is_empty())
-        .ok_or(Error::BackendError)?;
-
-    let request = if let ContentType::Thumbnail(width, height) = media_type {
-        let params = GetContentThumbnailParameters {
-            width,
-            height,
-            method: Some(Method::Crop),
-            allow_remote: true,
-        };
-        get_content_thumbnail(base, &params, &server, &media_id)
-    } else {
-        let params = GetContentParameters::default();
-        get_content(base, &params, &server, &media_id)
-    }?;
-
-    let fname = match dest {
-        None if media_type.is_thumbnail() => cache_dir_path(Some("thumbs"), &media_id)?,
-        None => cache_dir_path(Some("medias"), &media_id)?,
-        Some(ref d) => d.clone(),
-    };
-
-    let fpath = Path::new(&fname);
-
-    // If the file is already cached and recent enough, don't download it
-    if fpath.is_file()
-        && (dest.is_none() || fpath.metadata()?.modified()?.elapsed()?.as_secs() < 60)
-    {
-        Ok(fname)
-    } else {
-        HTTP_CLIENT
-            .get_client()?
-            .execute(request)?
-            .bytes()
-            .collect::<Result<Vec<u8>, std::io::Error>>()
-            .and_then(|media| write(&fname, media))
-            .and(Ok(fname))
-            .map_err(Into::into)
-    }
-}
-
-/// Returns the deserialized response to the given request. Handles Matrix errors.
-pub fn matrix_response<T: DeserializeOwned>(response: Response) -> Result<T, Error> {
-    if !response.status().is_success() {
-        let status = response.status();
-        return match response.json::<StandardErrorResponse>() {
-            Ok(error_response) => Err(Error::from(error_response)),
-            Err(_) => Err(Error::NetworkError(status)),
-        };
-    }
-
-    response.json::<T>().map_err(Into::into)
-}
-
-pub fn get_user_avatar(base: Url, user_id: &UserId) -> Result<(String, String), Error> {
-    let response = get_profile(base.clone(), user_id)
-        .map_err::<Error, _>(Into::into)
-        .and_then(|request| {
-            HTTP_CLIENT
-                .get_client()?
-                .execute(request)?
-                .json::<GetProfileResponse>()
-                .map_err(Into::into)
-        })?;
-
-    let name = response
-        .displayname
-        .filter(|n| !n.is_empty())
-        .unwrap_or_else(|| user_id.to_string());
-
-    let img = response
-        .avatar_url
-        .map(|url| {
-            let dest = cache_dir_path(None, &user_id.to_string())?;
-            dw_media(
-                base,
-                url.as_str(),
-                ContentType::default_thumbnail(),
-                Some(dest),
-            )
-        })
-        .unwrap_or_else(|| Ok(Default::default()))?;
-
-    Ok((name, img))
-}
-
 pub fn cache_dir_path(dir: Option<&str>, name: &str) -> Result<String, Error> {
     let path = CACHE_PATH.join(dir.unwrap_or_default());
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]