[fractal] App: remove backend loop



commit 8ffa747bee6759ebfc607fbcdab98a0cf3bf9b4e
Author: Alejandro Domínguez <adomu net-c com>
Date:   Wed Jun 24 08:51:55 2020 +0200

    App: remove backend loop

 fractal-gtk/src/actions/account_settings.rs |  8 ++---
 fractal-gtk/src/actions/message.rs          | 26 +++++------------
 fractal-gtk/src/actions/room_settings.rs    |  9 ++----
 fractal-gtk/src/app/backend_loop.rs         | 14 ---------
 fractal-gtk/src/app/connect/account.rs      |  3 --
 fractal-gtk/src/app/connect/language.rs     |  6 ++--
 fractal-gtk/src/app/mod.rs                  | 11 ++-----
 fractal-gtk/src/appop/account.rs            | 33 +++++----------------
 fractal-gtk/src/appop/directory.rs          | 10 ++-----
 fractal-gtk/src/appop/invite.rs             | 14 +++------
 fractal-gtk/src/appop/login.rs              | 27 ++++-------------
 fractal-gtk/src/appop/media_viewer.rs       |  2 --
 fractal-gtk/src/appop/member.rs             |  6 ++--
 fractal-gtk/src/appop/message.rs            | 45 +++++++++++------------------
 fractal-gtk/src/appop/mod.rs                |  7 +----
 fractal-gtk/src/appop/room.rs               | 44 +++++++---------------------
 fractal-gtk/src/appop/room_settings.rs      |  1 -
 fractal-gtk/src/appop/start_chat.rs         |  6 ++--
 fractal-gtk/src/appop/sync.rs               | 21 +++++---------
 fractal-gtk/src/appop/user.rs               | 13 ++++-----
 fractal-gtk/src/widgets/address.rs          | 31 ++++----------------
 fractal-gtk/src/widgets/image.rs            |  7 ++---
 fractal-gtk/src/widgets/media_viewer.rs     | 31 +++++---------------
 fractal-gtk/src/widgets/message.rs          | 11 ++-----
 fractal-gtk/src/widgets/room.rs             |  9 ++----
 fractal-gtk/src/widgets/room_history.rs     | 10 +------
 fractal-gtk/src/widgets/room_settings.rs    | 21 ++++----------
 fractal-matrix-api/src/backend/types.rs     |  2 --
 28 files changed, 108 insertions(+), 320 deletions(-)
---
diff --git a/fractal-gtk/src/actions/account_settings.rs b/fractal-gtk/src/actions/account_settings.rs
index 6a8a1c52..6181765f 100644
--- a/fractal-gtk/src/actions/account_settings.rs
+++ b/fractal-gtk/src/actions/account_settings.rs
@@ -3,13 +3,12 @@ use fractal_api::backend::user;
 use fractal_api::identifiers::UserId;
 use fractal_api::r0::AccessToken;
 use fractal_api::url::Url;
-use fractal_api::util::ResultExpectLog;
 use gio::prelude::*;
 use gio::SimpleAction;
 use gio::SimpleActionGroup;
-use std::sync::mpsc::Sender;
 use std::thread;
 
+use crate::app::dispatch_error;
 use crate::app::App;
 use crate::backend::BKResponse;
 
@@ -20,7 +19,6 @@ use crate::actions::ButtonState;
 // This creates all actions a user can perform in the account settings
 pub fn new(
     window: &gtk::Window,
-    tx: Sender<BKResponse>,
     server_url: Url,
     access_token: AccessToken,
     uid: UserId,
@@ -40,7 +38,6 @@ pub fn new(
         filter.set_name(Some(i18n("Images").as_str()));
         if let Some(path) = open(&window, i18n("Select a new avatar").as_str(), &[filter]) {
             a.change_state(&ButtonState::Insensitive.into());
-            let tx = tx.clone();
             let server_url = server_url.clone();
             let access_token = access_token.clone();
             let uid = uid.clone();
@@ -50,8 +47,7 @@ pub fn new(
                         APPOP!(show_new_avatar, (path));
                     }
                     Err(err) => {
-                        tx.send(BKResponse::SetUserAvatarError(err))
-                            .expect_log("Connection closed");
+                        dispatch_error(BKResponse::SetUserAvatarError(err));
                     }
                 }
             });
diff --git a/fractal-gtk/src/actions/message.rs b/fractal-gtk/src/actions/message.rs
index e3125408..dce59bde 100644
--- a/fractal-gtk/src/actions/message.rs
+++ b/fractal-gtk/src/actions/message.rs
@@ -2,7 +2,7 @@ use fractal_api::backend::{media, room, ThreadPool};
 use fractal_api::clone;
 use fractal_api::identifiers::RoomId;
 use fractal_api::r0::AccessToken;
-use fractal_api::util::{dw_media, ContentType, ResultExpectLog};
+use fractal_api::util::{dw_media, ContentType};
 use log::error;
 use std::cell::RefCell;
 use std::fs;
@@ -14,6 +14,7 @@ use std::sync::mpsc::{Receiver, Sender};
 use std::thread;
 
 use crate::actions::AppState;
+use crate::app::dispatch_error;
 use crate::backend::BKResponse;
 use crate::error::Error;
 use crate::i18n::i18n;
@@ -37,7 +38,6 @@ use crate::widgets::SourceDialog;
 /* This creates all actions the room history can perform */
 pub fn new(
     thread_pool: ThreadPool,
-    backend: Sender<BKResponse>,
     server_url: Url,
     access_token: AccessToken,
     ui: UI,
@@ -119,12 +119,10 @@ pub fn new(
         }
     });
 
-    let b = backend.clone();
     open_with.connect_activate(clone!(server_url => move |_, data| {
         if let Some(m) = get_message(data) {
             let url = m.url.unwrap_or_default();
             let server_url = server_url.clone();
-            let tx = b.clone();
             thread::spawn(move || {
                 match dw_media(server_url, &url, ContentType::Download, None) {
                     Ok(fname) => {
@@ -134,8 +132,7 @@ pub fn new(
                             .expect("failed to execute process");
                     }
                     Err(err) => {
-                        tx.send(BKResponse::MediaError(err))
-                            .expect_log("Connection closed");
+                        dispatch_error(BKResponse::MediaError(err));
                     }
                 }
             });
@@ -227,7 +224,6 @@ pub fn new(
         }
     });
 
-    let b = backend.clone();
     let s = server_url.clone();
     let tk = access_token.clone();
     let back_weak = Rc::downgrade(&back_history);
@@ -250,12 +246,10 @@ pub fn new(
         if let Some(msg) = get_message(data) {
             let server = s.clone();
             let access_token = tk.clone();
-            let tx = b.clone();
             thread::spawn(move || {
                 let query = room::redact_msg(server, access_token, msg);
                 if let Err(err) = query {
-                    tx.send(BKResponse::SentMsgRedactionError(err))
-                        .expect_log("Connection closed");
+                    dispatch_error(BKResponse::SentMsgRedactionError(err));
                 }
             });
         }
@@ -263,7 +257,7 @@ pub fn new(
 
     load_more_messages.connect_activate(clone!(server_url, access_token => move |_, data| {
         let id = get_room_id(data);
-        request_more_messages(backend.clone(), server_url.clone(), access_token.clone(), id);
+        request_more_messages(server_url.clone(), access_token.clone(), id);
     }));
 
     actions
@@ -274,7 +268,6 @@ fn get_message(id: Option<&glib::Variant>) -> Option<Message> {
 }
 
 fn request_more_messages(
-    tx: Sender<BKResponse>,
     server_url: Url,
     access_token: AccessToken,
     id: Option<RoomId>,
@@ -290,8 +283,7 @@ fn request_more_messages(
                     APPOP!(show_room_messages_top, (msgs, room, prev_batch));
                 }
                 Err(err) => {
-                    tx.send(BKResponse::RoomMessagesToError(err))
-                        .expect_log("Connection closed");
+                    dispatch_error(BKResponse::RoomMessagesToError(err));
                 }
             }
         });
@@ -303,8 +295,7 @@ fn request_more_messages(
                     APPOP!(show_room_messages_top, (msgs, room, prev_batch));
                 }
                 Err(err) => {
-                    tx.send(BKResponse::RoomMessagesToError(err))
-                        .expect_log("Connection closed");
+                    dispatch_error(BKResponse::RoomMessagesToError(err));
                 }
             }
         });
@@ -316,8 +307,7 @@ fn request_more_messages(
                     APPOP!(show_room_messages_top, (msgs, room, prev_batch));
                 }
                 Err(err) => {
-                    tx.send(BKResponse::RoomMessagesToError(err))
-                        .expect_log("Connection closed");
+                    dispatch_error(BKResponse::RoomMessagesToError(err));
                 }
             },
         );
diff --git a/fractal-gtk/src/actions/room_settings.rs b/fractal-gtk/src/actions/room_settings.rs
index 487d4238..3e307389 100644
--- a/fractal-gtk/src/actions/room_settings.rs
+++ b/fractal-gtk/src/actions/room_settings.rs
@@ -2,14 +2,13 @@ use fractal_api::backend::room;
 use fractal_api::identifiers::RoomId;
 use fractal_api::r0::AccessToken;
 use fractal_api::url::Url;
-use fractal_api::util::ResultExpectLog;
 use gio::prelude::*;
 use gio::SimpleAction;
 use gio::SimpleActionGroup;
 use std::convert::TryFrom;
-use std::sync::mpsc::Sender;
 use std::thread;
 
+use crate::app::dispatch_error;
 use crate::app::App;
 use crate::backend::BKResponse;
 use crate::i18n::i18n;
@@ -22,7 +21,6 @@ use crate::actions::ButtonState;
 // This creates all actions a user can perform in the room settings
 pub fn new(
     window: &gtk::Window,
-    backend: &Sender<BKResponse>,
     server_url: Url,
     access_token: AccessToken,
 ) -> gio::SimpleActionGroup {
@@ -37,7 +35,6 @@ pub fn new(
     actions.add_action(&change_avatar);
 
     let window_weak = window.downgrade();
-    let backend = backend.clone();
     change_avatar.connect_activate(move |a, data| {
         if let Some(room_id) = data
             .and_then(|x| x.get_str())
@@ -50,7 +47,6 @@ pub fn new(
             if let Some(path) = open(&window, i18n("Select a new avatar").as_str(), &[filter]) {
                 if let Some(file) = path.to_str().map(Into::into) {
                     a.change_state(&ButtonState::Insensitive.into());
-                    let tx = backend.clone();
                     let server = server_url.clone();
                     let access_token = access_token.clone();
                     thread::spawn(move || {
@@ -59,8 +55,7 @@ pub fn new(
                                 APPOP!(show_new_room_avatar);
                             }
                             Err(err) => {
-                                tx.send(BKResponse::SetRoomAvatarError(err))
-                                    .expect_log("Connection closed");
+                                dispatch_error(BKResponse::SetRoomAvatarError(err));
                             }
                         }
                     });
diff --git a/fractal-gtk/src/app/backend_loop.rs b/fractal-gtk/src/app/backend_loop.rs
index dfce4942..705e0b59 100644
--- a/fractal-gtk/src/app/backend_loop.rs
+++ b/fractal-gtk/src/app/backend_loop.rs
@@ -6,23 +6,9 @@ use regex::Regex;
 
 use crate::actions::{activate_action, AppState};
 
-use std::sync::mpsc::Receiver;
-use std::thread;
-
 use crate::backend::BKResponse;
 use fractal_api::error::Error;
 
-pub fn backend_loop(rx: Receiver<BKResponse>) {
-    thread::spawn(move || {
-        while let Ok(recv) = rx.recv() {
-            match recv {
-                BKResponse::ShutDown => break,
-                err => dispatch_error(err),
-            };
-        }
-    });
-}
-
 pub fn dispatch_error(error: BKResponse) {
     match error {
         BKResponse::AccountDestructionError(err) => {
diff --git a/fractal-gtk/src/app/connect/account.rs b/fractal-gtk/src/app/connect/account.rs
index b8376bb6..ecea6087 100644
--- a/fractal-gtk/src/app/connect/account.rs
+++ b/fractal-gtk/src/app/connect/account.rs
@@ -72,12 +72,9 @@ impl App {
             .get_object::<gtk::Button>("account_settings_delete_btn")
             .expect("Can't find account_settings_delete_btn in ui file.");
 
-        // FIXME: don't clone the backend
-        let backend = self.op.lock().unwrap().backend.clone();
         let window = self.main_window.upcast_ref::<gtk::Window>();
         let actions = AccountSettings::new(
             &window,
-            backend,
             login_data.server_url,
             login_data.access_token,
             login_data.uid,
diff --git a/fractal-gtk/src/app/connect/language.rs b/fractal-gtk/src/app/connect/language.rs
index f5bfd1db..b033daaa 100644
--- a/fractal-gtk/src/app/connect/language.rs
+++ b/fractal-gtk/src/app/connect/language.rs
@@ -1,8 +1,8 @@
+use crate::app::dispatch_error;
 use crate::app::App;
 use crate::backend::BKResponse;
 
 use fractal_api::backend::room;
-use fractal_api::util::ResultExpectLog;
 use glib::object::Cast;
 use gtk::prelude::*;
 use std::thread;
@@ -34,12 +34,10 @@ impl App {
                             let access_token = login_data.access_token.clone();
                             let uid = login_data.uid.clone();
                             let room_id = active_room.clone();
-                            let tx = op.backend.clone();
                             thread::spawn(move || {
                                 let query = room::set_language(access_token, server, uid, room_id, 
lang_code);
                                 if let Err(err) = query {
-                                    tx.send(BKResponse::ChangeLanguageError(err))
-                                        .expect_log("Connection closed");
+                                    dispatch_error(BKResponse::ChangeLanguageError(err));
                                 }
                             });
                         }
diff --git a/fractal-gtk/src/app/mod.rs b/fractal-gtk/src/app/mod.rs
index 0ae62c77..04128a09 100644
--- a/fractal-gtk/src/app/mod.rs
+++ b/fractal-gtk/src/app/mod.rs
@@ -4,14 +4,11 @@ use gtk::prelude::*;
 use libhandy::prelude::*;
 use std::cell::RefCell;
 use std::rc::Rc;
-use std::sync::mpsc::channel;
-use std::sync::mpsc::{Receiver, Sender};
 use std::sync::{Arc, Mutex, Weak};
 
 use log::error;
 
 use crate::appop::AppOp;
-use crate::backend::BKResponse;
 
 use crate::actions;
 use crate::config;
@@ -42,7 +39,7 @@ macro_rules! APPOP {
 
 mod backend_loop;
 
-pub use self::backend_loop::backend_loop;
+pub use backend_loop::dispatch_error;
 
 // Our application struct for containing all the state we have to carry around.
 // TODO: subclass gtk::Application once possible
@@ -59,8 +56,6 @@ pub type AppRef = Rc<App>;
 
 impl App {
     pub fn new(gtk_app: &gtk::Application) -> AppRef {
-        let (tx, rx): (Sender<BKResponse>, Receiver<BKResponse>) = channel();
-
         // Set up the textdomain for gettext
         setlocale(LocaleCategory::LcAll, "");
         bindtextdomain("fractal", config::LOCALEDIR);
@@ -160,7 +155,7 @@ impl App {
         stack.add_named(&child, "account-settings");
         stack_header.add_named(&child_header, "account-settings");
 
-        let op = Arc::new(Mutex::new(AppOp::new(ui.clone(), tx)));
+        let op = Arc::new(Mutex::new(AppOp::new(ui.clone())));
 
         // Add login view to the main stack
         let login = widgets::LoginWidget::new(&op);
@@ -173,8 +168,6 @@ impl App {
             OP = Some(Arc::downgrade(&op));
         }
 
-        backend_loop(rx);
-
         actions::Global::new(gtk_app, &op);
 
         let app = AppRef::new(Self {
diff --git a/fractal-gtk/src/appop/account.rs b/fractal-gtk/src/appop/account.rs
index 6257d05c..a7505d2a 100644
--- a/fractal-gtk/src/appop/account.rs
+++ b/fractal-gtk/src/appop/account.rs
@@ -1,10 +1,10 @@
 use fractal_api::backend::user;
-use fractal_api::util::ResultExpectLog;
 use gtk::prelude::*;
 use log::info;
 use std::path::PathBuf;
 use std::thread;
 
+use crate::app::dispatch_error;
 use crate::app::App;
 use crate::appop::AppOp;
 use crate::appop::AppState;
@@ -27,7 +27,6 @@ impl AppOp {
 
     pub fn get_three_pid(&self) {
         let login_data = unwrap_or_unit_return!(self.login_data.clone());
-        let tx = self.backend.clone();
         thread::spawn(move || {
             match user::get_threepid(login_data.server_url, login_data.access_token) {
                 Ok(list) => {
@@ -35,8 +34,7 @@ impl AppOp {
                     APPOP!(set_three_pid, (l));
                 }
                 Err(err) => {
-                    tx.send(BKResponse::GetThreePIDError(err))
-                        .expect_log("Connection closed");
+                    dispatch_error(BKResponse::GetThreePIDError(err));
                 }
             }
         });
@@ -50,7 +48,6 @@ impl AppOp {
         let login_data = unwrap_or_unit_return!(self.login_data.clone());
         if let Some(sid) = sid {
             if let Some(secret) = secret {
-                let tx = self.backend.clone();
                 thread::spawn(move || {
                     match user::add_threepid(
                         login_data.server_url,
@@ -63,8 +60,7 @@ impl AppOp {
                             APPOP!(added_three_pid);
                         }
                         Err(err) => {
-                            tx.send(BKResponse::AddThreePIDError(err))
-                                .expect_log("Connection closed");
+                            dispatch_error(BKResponse::AddThreePIDError(err));
                         }
                     }
                 });
@@ -97,7 +93,6 @@ impl AppOp {
                 area.add(&entry);
             }
         }
-        let backend = self.backend.clone();
         dialog.add_button(&i18n("Cancel"), gtk::ResponseType::Cancel);
         let button = dialog.add_button(&i18n("Continue"), gtk::ResponseType::Ok);
         button.set_sensitive(false);
@@ -125,7 +120,6 @@ impl AppOp {
                     let server_url = login_data.server_url.clone();
                     let secret = secret.clone();
                     let sid = sid.clone();
-                    let tx = backend.clone();
                     thread::spawn(move || {
                         match user::submit_phone_token(server_url, secret, sid, token) {
                             Ok((sid, secret)) => {
@@ -133,8 +127,7 @@ impl AppOp {
                                 APPOP!(valid_phone_token, (sid, secret));
                             }
                             Err(err) => {
-                                tx.send(BKResponse::SubmitPhoneTokenError(err))
-                                    .expect_log("Connection closed");
+                                dispatch_error(BKResponse::SubmitPhoneTokenError(err));
                             }
                         }
                     });
@@ -163,7 +156,6 @@ impl AppOp {
             gtk::ButtonsType::None,
             &msg,
         );
-        let backend = self.backend.clone();
         dialog.add_button(&i18n("Cancel"), gtk::ResponseType::Cancel);
         dialog.add_button(&i18n("Continue"), gtk::ResponseType::Ok);
         dialog.connect_response(move |w, r| {
@@ -171,7 +163,6 @@ impl AppOp {
                 let login_data = login_data.clone();
                 let secret = secret.clone();
                 let sid = sid.clone();
-                let tx = backend.clone();
                 thread::spawn(move || {
                     match user::add_threepid(
                         login_data.server_url,
@@ -184,8 +175,7 @@ impl AppOp {
                             APPOP!(added_three_pid);
                         }
                         Err(err) => {
-                            tx.send(BKResponse::AddThreePIDError(err))
-                                .expect_log("Connection closed");
+                            dispatch_error(BKResponse::AddThreePIDError(err));
                         }
                     }
                 });
@@ -594,7 +584,6 @@ impl AppOp {
 
     pub fn update_username_account_settings(&self) {
         let login_data = unwrap_or_unit_return!(self.login_data.clone());
-        let tx = self.backend.clone();
         let name = self
             .ui
             .builder
@@ -629,8 +618,7 @@ impl AppOp {
                         APPOP!(show_new_username, (u));
                     }
                     Err(err) => {
-                        tx.send(BKResponse::SetUserNameError(err))
-                            .expect_log("Connection closed");
+                        dispatch_error(BKResponse::SetUserNameError(err));
                     }
                 }
             });
@@ -689,7 +677,6 @@ impl AppOp {
                 if old != "" && new != "" {
                     password_btn.set_sensitive(false);
                     password_btn_stack.set_visible_child_name("spinner");
-                    let tx = self.backend.clone();
                     thread::spawn(move || {
                         match user::change_password(
                             login_data.server_url,
@@ -702,8 +689,7 @@ impl AppOp {
                                 APPOP!(password_changed);
                             }
                             Err(err) => {
-                                tx.send(BKResponse::ChangePasswordError(err))
-                                    .expect_log("Connection closed");
+                                dispatch_error(BKResponse::ChangePasswordError(err));
                             }
                         }
                     });
@@ -804,10 +790,8 @@ impl AppOp {
 
         let _flag = mark.get_active(); // TODO: This is not used, remove from UI?
         if let Some(password) = entry.get_text().map(|gstr| gstr.to_string()) {
-            let backend = self.backend.clone();
             dialog.connect_response(move |w, r| {
                 if let gtk::ResponseType::Ok = r {
-                    let tx = backend.clone();
                     let password = password.clone();
                     let login_data = login_data.clone();
                     thread::spawn(move || {
@@ -821,8 +805,7 @@ impl AppOp {
                                 APPOP!(account_destruction_logoff);
                             }
                             Err(err) => {
-                                tx.send(BKResponse::AccountDestructionError(err))
-                                    .expect_log("Connection closed");
+                                dispatch_error(BKResponse::AccountDestructionError(err));
                             }
                         }
                     });
diff --git a/fractal-gtk/src/appop/directory.rs b/fractal-gtk/src/appop/directory.rs
index 1dfa70f4..bfc748a2 100644
--- a/fractal-gtk/src/appop/directory.rs
+++ b/fractal-gtk/src/appop/directory.rs
@@ -3,8 +3,8 @@ use libhandy::Column;
 use std::thread;
 
 use fractal_api::backend::directory;
-use fractal_api::util::ResultExpectLog;
 
+use crate::app::dispatch_error;
 use crate::app::App;
 use crate::appop::AppOp;
 
@@ -18,15 +18,13 @@ use fractal_api::r0::thirdparty::get_supported_protocols::ProtocolInstance;
 impl AppOp {
     pub fn init_protocols(&self) {
         let login_data = unwrap_or_unit_return!(self.login_data.clone());
-        let tx = self.backend.clone();
         thread::spawn(move || {
             match directory::protocols(login_data.server_url, login_data.access_token) {
                 Ok(protocols) => {
                     APPOP!(set_protocols, (protocols));
                 }
                 Err(err) => {
-                    tx.send(BKResponse::DirectoryProtocolsError(err))
-                        .expect_log("Connection closed");
+                    dispatch_error(BKResponse::DirectoryProtocolsError(err));
                 }
             }
         });
@@ -139,7 +137,6 @@ impl AppOp {
         }
 
         let rooms_since = self.directory_pagination.clone().into();
-        let tx = self.backend.clone();
         thread::spawn(move || {
             let query = directory::room_search(
                 login_data.server_url,
@@ -155,8 +152,7 @@ impl AppOp {
                     APPOP!(append_directory_rooms, (rooms, rooms_since));
                 }
                 Err(err) => {
-                    tx.send(BKResponse::DirectorySearchError(err))
-                        .expect_log("Connection closed");
+                    dispatch_error(BKResponse::DirectorySearchError(err));
                 }
             }
         });
diff --git a/fractal-gtk/src/appop/invite.rs b/fractal-gtk/src/appop/invite.rs
index ef55b11f..5abae0cc 100644
--- a/fractal-gtk/src/appop/invite.rs
+++ b/fractal-gtk/src/appop/invite.rs
@@ -2,10 +2,10 @@ use crate::i18n::{i18n, i18n_k};
 
 use fractal_api::backend::room;
 use fractal_api::identifiers::{RoomId, UserId};
-use fractal_api::util::ResultExpectLog;
 use gtk::prelude::*;
 use std::thread;
 
+use crate::app::dispatch_error;
 use crate::app::App;
 use crate::appop::member::SearchType;
 use crate::appop::AppOp;
@@ -171,12 +171,10 @@ impl AppOp {
                 let access_token = login_data.access_token.clone();
                 let room_id = r.clone();
                 let user_id = user.0.uid.clone();
-                let tx = self.backend.clone();
                 thread::spawn(move || {
                     let query = room::invite(server, access_token, room_id, user_id);
                     if let Err(err) = query {
-                        tx.send(BKResponse::InviteError(err))
-                            .expect_log("Connection closed");
+                        dispatch_error(BKResponse::InviteError(err));
                     }
                 });
             }
@@ -231,7 +229,6 @@ impl AppOp {
         if let Some(rid) = self.invitation_roomid.take() {
             let room_id = rid.clone();
             if accept {
-                let tx = self.backend.clone();
                 thread::spawn(move || {
                     match room::join_room(login_data.server_url, login_data.access_token, room_id) {
                         Ok(jtr) => {
@@ -240,19 +237,16 @@ impl AppOp {
                             APPOP!(reload_rooms);
                         }
                         Err(err) => {
-                            tx.send(BKResponse::JoinRoomError(err))
-                                .expect_log("Connection closed");
+                            dispatch_error(BKResponse::JoinRoomError(err));
                         }
                     }
                 });
             } else {
-                let tx = self.backend.clone();
                 thread::spawn(move || {
                     let query =
                         room::leave_room(login_data.server_url, login_data.access_token, room_id);
                     if let Err(err) = query {
-                        tx.send(BKResponse::LeaveRoomError(err))
-                            .expect_log("Connection closed");
+                        dispatch_error(BKResponse::LeaveRoomError(err));
                     }
                 });
             }
diff --git a/fractal-gtk/src/appop/login.rs b/fractal-gtk/src/appop/login.rs
index be9499ff..58b22747 100644
--- a/fractal-gtk/src/appop/login.rs
+++ b/fractal-gtk/src/appop/login.rs
@@ -3,22 +3,18 @@ use log::error;
 use fractal_api::backend::register;
 use fractal_api::identifiers::UserId;
 use fractal_api::r0::AccessToken;
-use fractal_api::util::ResultExpectLog;
 
 use fractal_api::url::Url;
 
+use crate::app::dispatch_error;
 use crate::app::App;
 use crate::appop::AppOp;
 
 use crate::backend::BKResponse;
 use crate::cache;
 
-use std::sync::mpsc::channel;
-use std::sync::mpsc::{Receiver, Sender};
 use std::thread;
 
-use crate::app::backend_loop;
-
 use crate::passwd::PasswordStorage;
 
 use crate::actions::AppState;
@@ -69,14 +65,6 @@ impl AppOp {
         self.set_state(AppState::Login);
         self.login_data = None;
         self.device_id = None;
-
-        // stoping the backend and starting again, we don't want to receive more messages from
-        // backend
-        self.backend.send(BKResponse::ShutDown).unwrap();
-
-        let (tx, rx): (Sender<BKResponse>, Receiver<BKResponse>) = channel();
-        self.backend = tx;
-        backend_loop(rx);
     }
 
     pub fn connect(&mut self, username: String, password: String, server: Url, identity: Url) {
@@ -91,36 +79,31 @@ impl AppOp {
             error!("Can't store the password using libsecret");
         });
 
-        let tx = self.backend.clone();
         thread::spawn(
             move || match register::login(username, password, server.clone()) {
                 Ok((uid, tk, dev)) => {
                     APPOP!(bk_login, (uid, tk, dev, server, identity));
                 }
                 Err(err) => {
-                    tx.send(BKResponse::LoginError(err))
-                        .expect_log("Connection closed");
+                    dispatch_error(BKResponse::LoginError(err));
                 }
             },
         );
     }
 
-    pub fn disconnect(&self) {
-        self.backend.send(BKResponse::ShutDown).unwrap();
-    }
+    // TODO: Remove function
+    pub fn disconnect(&self) {}
 
     pub fn logout(&mut self) {
         let login_data = unwrap_or_unit_return!(self.login_data.clone());
         let _ = self.delete_pass("fractal");
-        let tx = self.backend.clone();
         thread::spawn(move || {
             match register::logout(login_data.server_url, login_data.access_token) {
                 Ok(_) => {
                     APPOP!(bk_logout);
                 }
                 Err(err) => {
-                    tx.send(BKResponse::LogoutError(err))
-                        .expect_log("Connection closed");
+                    dispatch_error(BKResponse::LogoutError(err));
                 }
             }
         });
diff --git a/fractal-gtk/src/appop/media_viewer.rs b/fractal-gtk/src/appop/media_viewer.rs
index 036240b5..8a76fee1 100644
--- a/fractal-gtk/src/appop/media_viewer.rs
+++ b/fractal-gtk/src/appop/media_viewer.rs
@@ -36,7 +36,6 @@ impl AppOp {
             let room_id = self.active_room.as_ref()?;
             let room = self.rooms.get(room_id)?;
             let mut panel = widgets::MediaViewer::new(
-                self.backend.clone(),
                 main_window,
                 room,
                 &msg,
@@ -52,7 +51,6 @@ impl AppOp {
                 let back_history = self.room_back_history.clone();
                 let actions = actions::Message::new(
                     self.thread_pool.clone(),
-                    self.backend.clone(),
                     login_data.server_url,
                     login_data.access_token,
                     self.ui.clone(),
diff --git a/fractal-gtk/src/appop/member.rs b/fractal-gtk/src/appop/member.rs
index ebc4439e..25959b3e 100644
--- a/fractal-gtk/src/appop/member.rs
+++ b/fractal-gtk/src/appop/member.rs
@@ -1,7 +1,6 @@
 use fractal_api::backend::user;
 use fractal_api::clone;
 use fractal_api::identifiers::{RoomId, UserId};
-use fractal_api::util::ResultExpectLog;
 use gtk::prelude::*;
 
 use std::collections::HashMap;
@@ -9,6 +8,7 @@ use std::convert::TryFrom;
 use std::thread;
 
 use crate::actions::AppState;
+use crate::app::dispatch_error;
 use crate::appop::AppOp;
 use crate::backend::BKResponse;
 use crate::widgets;
@@ -191,15 +191,13 @@ impl AppOp {
 
     pub fn search_invite_user(&self, term: String) {
         let login_data = unwrap_or_unit_return!(self.login_data.clone());
-        let tx = self.backend.clone();
         thread::spawn(move || {
             match user::search(login_data.server_url, login_data.access_token, term) {
                 Ok(users) => {
                     APPOP!(user_search_finished, (users));
                 }
                 Err(err) => {
-                    tx.send(BKResponse::UserSearchError(err))
-                        .expect_log("Connection closed");
+                    dispatch_error(BKResponse::UserSearchError(err));
                 }
             }
         });
diff --git a/fractal-gtk/src/appop/message.rs b/fractal-gtk/src/appop/message.rs
index 190c6390..c086e28f 100644
--- a/fractal-gtk/src/appop/message.rs
+++ b/fractal-gtk/src/appop/message.rs
@@ -5,7 +5,6 @@ use fractal_api::identifiers::{EventId, RoomId};
 use fractal_api::r0::AccessToken;
 use fractal_api::types::ExtraContent;
 use fractal_api::url::Url;
-use fractal_api::util::ResultExpectLog;
 use gdk_pixbuf::Pixbuf;
 use gio::prelude::FileExt;
 use glib::source::Continue;
@@ -18,9 +17,9 @@ use serde_json::Value as JsonValue;
 use std::env::temp_dir;
 use std::fs;
 use std::path::PathBuf;
-use std::sync::mpsc::Sender;
 use std::thread;
 
+use crate::app::dispatch_error;
 use crate::appop::room::Force;
 use crate::appop::AppOp;
 use crate::App;
@@ -79,8 +78,7 @@ impl AppOp {
         let login_data = self.login_data.clone()?;
         let messages = self.history.as_ref()?.get_listbox();
         if let Some(ui_msg) = self.create_new_room_message(&msg) {
-            let backend = self.backend.clone();
-            let mb = widgets::MessageBox::new(backend, login_data.server_url).tmpwidget(
+            let mb = widgets::MessageBox::new(login_data.server_url).tmpwidget(
                 self.thread_pool.clone(),
                 self.user_info_cache.clone(),
                 &ui_msg,
@@ -118,13 +116,11 @@ impl AppOp {
         let mut widgets = vec![];
         for t in self.msg_queue.iter().rev().filter(|m| m.msg.room == r.id) {
             if let Some(ui_msg) = self.create_new_room_message(&t.msg) {
-                let backend = self.backend.clone();
-                let mb = widgets::MessageBox::new(backend, login_data.server_url.clone())
-                    .tmpwidget(
-                        self.thread_pool.clone(),
-                        self.user_info_cache.clone(),
-                        &ui_msg,
-                    );
+                let mb = widgets::MessageBox::new(login_data.server_url.clone()).tmpwidget(
+                    self.thread_pool.clone(),
+                    self.user_info_cache.clone(),
+                    &ui_msg,
+                );
                 let m = mb.get_listbox_row();
                 messages.add(m);
 
@@ -162,7 +158,6 @@ impl AppOp {
 
             let room_id = last_message.room.clone();
             let event_id = last_message.id.clone()?;
-            let tx = self.backend.clone();
             thread::spawn(move || {
                 match room::mark_as_read(
                     login_data.server_url,
@@ -174,8 +169,7 @@ impl AppOp {
                         APPOP!(clear_room_notifications, (r));
                     }
                     Err(err) => {
-                        tx.send(BKResponse::MarkedAsReadError(err))
-                            .expect_log("Connection closed");
+                        dispatch_error(BKResponse::MarkedAsReadError(err));
                     }
                 }
             });
@@ -217,11 +211,10 @@ impl AppOp {
         self.sending_message = true;
         if let Some(next) = self.msg_queue.last() {
             let msg = next.msg.clone();
-            let tx = self.backend.clone();
             match &next.msg.mtype[..] {
                 "m.image" | "m.file" | "m.audio" | "m.video" => {
                     thread::spawn(move || {
-                        attach_file(tx, login_data.server_url, login_data.access_token, msg)
+                        attach_file(login_data.server_url, login_data.access_token, msg)
                     });
                 }
                 _ => {
@@ -234,8 +227,7 @@ impl AppOp {
                                 APPOP!(sync, (initial, number_tries));
                             }
                             Err(err) => {
-                                tx.send(BKResponse::SentMsgError(err))
-                                    .expect_log("Connection closed");
+                                dispatch_error(BKResponse::SentMsgError(err));
                             }
                         }
                     });
@@ -640,7 +632,7 @@ fn get_file_media_info(file: &str, mimetype: &str) -> Option<JsonValue> {
     Some(info)
 }
 
-fn attach_file(tx: Sender<BKResponse>, baseu: Url, tk: AccessToken, mut msg: Message) {
+fn attach_file(baseu: Url, tk: AccessToken, mut msg: Message) {
     let fname = msg.url.clone().unwrap_or_default();
     let mut extra_content: Option<ExtraContent> = msg
         .clone()
@@ -653,7 +645,7 @@ fn attach_file(tx: Sender<BKResponse>, baseu: Url, tk: AccessToken, mut msg: Mes
         .unwrap_or_default();
 
     if fname.starts_with("mxc://") && thumb.starts_with("mxc://") {
-        send_msg_and_manage(tx, baseu, tk, msg);
+        send_msg_and_manage(baseu, tk, msg);
 
         return;
     }
@@ -669,8 +661,7 @@ fn attach_file(tx: Sender<BKResponse>, baseu: Url, tk: AccessToken, mut msg: Mes
                 msg.extra_content = serde_json::to_value(&extra_content).ok();
             }
             Err(err) => {
-                tx.send(BKResponse::AttachedFileError(err))
-                    .expect_log("Connection closed");
+                dispatch_error(BKResponse::AttachedFileError(err));
             }
         }
 
@@ -681,7 +672,7 @@ fn attach_file(tx: Sender<BKResponse>, baseu: Url, tk: AccessToken, mut msg: Mes
 
     let query = room::upload_file(baseu.clone(), tk.clone(), &fname).map(|response| {
         msg.url = Some(response.content_uri.to_string());
-        thread::spawn(clone!(msg, tx => move || send_msg_and_manage(tx, baseu, tk, msg)));
+        thread::spawn(clone!(msg => move || send_msg_and_manage(baseu, tk, msg)));
 
         msg
     });
@@ -691,13 +682,12 @@ fn attach_file(tx: Sender<BKResponse>, baseu: Url, tk: AccessToken, mut msg: Mes
             APPOP!(attached_file, (msg));
         }
         Err(err) => {
-            tx.send(BKResponse::AttachedFileError(err))
-                .expect_log("Connection closed");
+            dispatch_error(BKResponse::AttachedFileError(err));
         }
     };
 }
 
-fn send_msg_and_manage(tx: Sender<BKResponse>, baseu: Url, tk: AccessToken, msg: Message) {
+fn send_msg_and_manage(baseu: Url, tk: AccessToken, msg: Message) {
     match room::send_msg(baseu, tk, msg) {
         Ok((txid, evid)) => {
             APPOP!(msg_sent, (txid, evid));
@@ -706,8 +696,7 @@ fn send_msg_and_manage(tx: Sender<BKResponse>, baseu: Url, tk: AccessToken, msg:
             APPOP!(sync, (initial, number_tries));
         }
         Err(err) => {
-            tx.send(BKResponse::SentMsgError(err))
-                .expect_log("Connection closed");
+            dispatch_error(BKResponse::SentMsgError(err));
         }
     };
 }
diff --git a/fractal-gtk/src/appop/mod.rs b/fractal-gtk/src/appop/mod.rs
index bd72b1eb..1b2cd82f 100644
--- a/fractal-gtk/src/appop/mod.rs
+++ b/fractal-gtk/src/appop/mod.rs
@@ -2,7 +2,6 @@ use std::cell::RefCell;
 use std::collections::HashMap;
 use std::path::PathBuf;
 use std::rc::Rc;
-use std::sync::mpsc::Sender;
 use std::sync::{Arc, Mutex};
 use std::time::Duration;
 
@@ -15,8 +14,6 @@ use fractal_api::backend::ThreadPool;
 use fractal_api::cache::CacheMap;
 use fractal_api::url::Url;
 
-use crate::backend::{self, BKResponse};
-
 use crate::i18n;
 
 use crate::types::Member;
@@ -85,7 +82,6 @@ pub struct LoginData {
 
 pub struct AppOp {
     pub ui: uibuilder::UI,
-    pub backend: Sender<backend::BKResponse>,
 
     pub syncing: bool, // TODO: Replace with a Mutex
     pub msg_queue: Vec<TmpMsg>,
@@ -126,7 +122,7 @@ pub struct AppOp {
 impl PasswordStorage for AppOp {}
 
 impl AppOp {
-    pub fn new(ui: uibuilder::UI, tx: Sender<BKResponse>) -> AppOp {
+    pub fn new(ui: uibuilder::UI) -> AppOp {
         let leaflet = ui
             .builder
             .get_object::<libhandy::Leaflet>("header_leaflet")
@@ -134,7 +130,6 @@ impl AppOp {
 
         AppOp {
             ui,
-            backend: tx,
             active_room: None,
             join_to_room: None,
             rooms: HashMap::new(),
diff --git a/fractal-gtk/src/appop/room.rs b/fractal-gtk/src/appop/room.rs
index 92c98959..3bc8e1ef 100644
--- a/fractal-gtk/src/appop/room.rs
+++ b/fractal-gtk/src/appop/room.rs
@@ -2,7 +2,6 @@ use crate::i18n::{i18n, i18n_k, ni18n_f};
 use fractal_api::backend::room;
 use fractal_api::identifiers::RoomId;
 use fractal_api::url::Url;
-use fractal_api::util::ResultExpectLog;
 use log::{error, warn};
 use std::convert::TryFrom;
 use std::fs::remove_file;
@@ -11,6 +10,7 @@ use std::thread;
 
 use gtk::prelude::*;
 
+use crate::app::dispatch_error;
 use crate::app::App;
 use crate::appop::AppOp;
 
@@ -81,15 +81,13 @@ impl AppOp {
                 let server = login_data.server_url.clone();
                 let access_token = login_data.access_token.clone();
                 let room_id = room.id.clone();
-                let tx = self.backend.clone();
                 thread::spawn(move || {
                     match room::get_room_members(server, access_token, room_id) {
                         Ok((room, members)) => {
                             APPOP!(set_room_members, (room, members));
                         }
                         Err(err) => {
-                            tx.send(BKResponse::RoomMembersError(err))
-                                .expect_log("Connection closed");
+                            dispatch_error(BKResponse::RoomMembersError(err));
                         }
                     }
                 });
@@ -98,15 +96,13 @@ impl AppOp {
                 let server = login_data.server_url.clone();
                 let access_token = login_data.access_token.clone();
                 let room_id = room.id.clone();
-                let tx = self.backend.clone();
                 thread::spawn(
                     move || match room::get_room_avatar(server, access_token, room_id) {
                         Ok((room, avatar)) => {
                             APPOP!(set_room_avatar, (room, avatar));
                         }
                         Err(err) => {
-                            tx.send(BKResponse::RoomAvatarError(err))
-                                .expect_log("Connection closed");
+                            dispatch_error(BKResponse::RoomAvatarError(err));
                         }
                     },
                 );
@@ -149,9 +145,7 @@ impl AppOp {
             self.roomlist.add_rooms(roomlist);
             container.add(self.roomlist.widget());
 
-            let bk = self.backend.clone();
             self.roomlist.connect_fav(move |room, tofav| {
-                let tx = bk.clone();
                 let server = login_data.server_url.clone();
                 let access_token = login_data.access_token.clone();
                 let uid = login_data.uid.clone();
@@ -161,8 +155,7 @@ impl AppOp {
                             APPOP!(added_to_fav, (r, tofav));
                         }
                         Err(err) => {
-                            tx.send(BKResponse::AddedToFavError(err))
-                                .expect_log("Connection closed");
+                            dispatch_error(BKResponse::AddedToFavError(err));
                         }
                     }
                 });
@@ -254,15 +247,13 @@ impl AppOp {
         let server_url = login_data.server_url.clone();
         let access_token = login_data.access_token.clone();
         let a_room = active_room.clone();
-        let tx = self.backend.clone();
         thread::spawn(
             move || match room::get_room_avatar(server_url, access_token, a_room) {
                 Ok((room, avatar)) => {
                     APPOP!(set_room_avatar, (room, avatar));
                 }
                 Err(err) => {
-                    tx.send(BKResponse::RoomAvatarError(err))
-                        .expect_log("Connection closed");
+                    dispatch_error(BKResponse::RoomAvatarError(err));
                 }
             },
         );
@@ -270,7 +261,6 @@ impl AppOp {
         let server_url = login_data.server_url.clone();
         let access_token = login_data.access_token.clone();
         let a_room = active_room.clone();
-        let tx = self.backend.clone();
         thread::spawn(move || {
             match room::get_room_detail(server_url, access_token, a_room, "m.room.topic".into()) {
                 Ok((room, key, value)) => {
@@ -278,8 +268,7 @@ impl AppOp {
                     APPOP!(set_room_detail, (room, key, v));
                 }
                 Err(err) => {
-                    tx.send(BKResponse::RoomDetailError(err))
-                        .expect_log("Connection closed");
+                    dispatch_error(BKResponse::RoomDetailError(err));
                 }
             }
         });
@@ -312,7 +301,6 @@ impl AppOp {
         let back_history = self.room_back_history.clone();
         let actions = actions::Message::new(
             self.thread_pool.clone(),
-            self.backend.clone(),
             login_data.server_url,
             login_data.access_token,
             self.ui.clone(),
@@ -343,12 +331,10 @@ impl AppOp {
         let login_data = unwrap_or_unit_return!(self.login_data.clone());
         let r = unwrap_or_unit_return!(self.active_room.clone());
         let room_id = r.clone();
-        let tx = self.backend.clone();
         thread::spawn(move || {
             let query = room::leave_room(login_data.server_url, login_data.access_token, room_id);
             if let Err(err) = query {
-                tx.send(BKResponse::LeaveRoomError(err))
-                    .expect_log("Connection closed");
+                dispatch_error(BKResponse::LeaveRoomError(err));
             }
         });
         self.rooms.remove(&r);
@@ -417,7 +403,6 @@ impl AppOp {
             .expect("The server domain should have been validated");
         let int_id = internal_id.clone();
         let name = n.clone();
-        let tx = self.backend.clone();
         thread::spawn(move || {
             match room::new_room(
                 login_data.server_url,
@@ -430,8 +415,7 @@ impl AppOp {
                     APPOP!(new_room, (r, id));
                 }
                 Err(err) => {
-                    tx.send(BKResponse::NewRoomError(err, int_id))
-                        .expect_log("Connection closed");
+                    dispatch_error(BKResponse::NewRoomError(err, int_id));
                 }
             }
         });
@@ -575,7 +559,6 @@ impl AppOp {
             .get_text()
             .map_or(String::new(), |gstr| gstr.to_string());
 
-        let tx = self.backend.clone();
         thread::spawn(move || {
             match RoomId::try_from(name.trim())
                 .map_err(Into::into)
@@ -588,8 +571,7 @@ impl AppOp {
                     APPOP!(reload_rooms);
                 }
                 Err(err) => {
-                    tx.send(BKResponse::JoinRoomError(err))
-                        .expect_log("Connection closed");
+                    dispatch_error(BKResponse::JoinRoomError(err));
                 }
             }
         });
@@ -727,15 +709,13 @@ impl AppOp {
             return;
         }
 
-        let tx = self.backend.clone();
         thread::spawn(move || {
             match room::get_room_avatar(login_data.server_url, login_data.access_token, room_id) {
                 Ok((room, avatar)) => {
                     APPOP!(set_room_avatar, (room, avatar));
                 }
                 Err(err) => {
-                    tx.send(BKResponse::RoomAvatarError(err))
-                        .expect_log("Connection closed");
+                    dispatch_error(BKResponse::RoomAvatarError(err));
                 }
             }
         });
@@ -781,7 +761,6 @@ impl AppOp {
             }
         }
         self.typing.insert(active_room.clone(), now);
-        let tx = self.backend.clone();
         thread::spawn(move || {
             let query = room::send_typing(
                 login_data.server_url,
@@ -790,8 +769,7 @@ impl AppOp {
                 active_room,
             );
             if let Err(err) = query {
-                tx.send(BKResponse::SendTypingError(err))
-                    .expect_log("Connection closed");
+                dispatch_error(BKResponse::SendTypingError(err));
             }
         });
     }
diff --git a/fractal-gtk/src/appop/room_settings.rs b/fractal-gtk/src/appop/room_settings.rs
index 3017168c..01524706 100644
--- a/fractal-gtk/src/appop/room_settings.rs
+++ b/fractal-gtk/src/appop/room_settings.rs
@@ -28,7 +28,6 @@ impl AppOp {
             let room = self.rooms.get(&self.active_room.clone()?)?;
             let mut panel = widgets::RoomSettings::new(
                 &window,
-                self.backend.clone(),
                 login_data.uid,
                 room.clone(),
                 login_data.server_url,
diff --git a/fractal-gtk/src/appop/start_chat.rs b/fractal-gtk/src/appop/start_chat.rs
index 82fd2a8a..63e20653 100644
--- a/fractal-gtk/src/appop/start_chat.rs
+++ b/fractal-gtk/src/appop/start_chat.rs
@@ -1,10 +1,10 @@
 use fractal_api::backend::room;
 use fractal_api::identifiers::RoomId;
-use fractal_api::util::ResultExpectLog;
 use gtk::prelude::*;
 use std::thread;
 
 use crate::actions::AppState;
+use crate::app::dispatch_error;
 use crate::app::App;
 use crate::appop::AppOp;
 use crate::appop::SearchType;
@@ -26,7 +26,6 @@ impl AppOp {
 
         let int_id = internal_id.clone();
         let member = user.0.clone();
-        let tx = self.backend.clone();
         thread::spawn(move || {
             match room::direct_chat(
                 login_data.server_url,
@@ -39,8 +38,7 @@ impl AppOp {
                     APPOP!(new_room, (r, id));
                 }
                 Err(err) => {
-                    tx.send(BKResponse::NewRoomError(err, int_id))
-                        .expect_log("Connection closed");
+                    dispatch_error(BKResponse::NewRoomError(err, int_id));
                 }
             }
         });
diff --git a/fractal-gtk/src/appop/sync.rs b/fractal-gtk/src/appop/sync.rs
index 3b1e658f..5fe288fd 100644
--- a/fractal-gtk/src/appop/sync.rs
+++ b/fractal-gtk/src/appop/sync.rs
@@ -1,9 +1,9 @@
-use fractal_api::util::ResultExpectLog;
 use log::info;
 use std::thread;
 
 use crate::i18n::i18n;
 
+use crate::app::dispatch_error;
 use crate::app::App;
 use crate::appop::AppOp;
 
@@ -30,7 +30,6 @@ impl AppOp {
             // https://matrix.org/docs/spec/client_server/latest.html#syncing
             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,
@@ -55,8 +54,7 @@ impl AppOp {
                                 }
                             }
                             Err(err) => {
-                                tx.send(BKResponse::RoomsError(err))
-                                    .expect_log("Connection closed");
+                                dispatch_error(BKResponse::RoomsError(err));
                             }
                         };
 
@@ -78,8 +76,7 @@ impl AppOp {
                                 APPOP!(set_rooms, (rooms, clear_room_list));
                             }
                             Err(err) => {
-                                tx.send(BKResponse::UpdateRoomsError(err))
-                                    .expect_log("Connection closed");
+                                dispatch_error(BKResponse::UpdateRoomsError(err));
                             }
                         }
 
@@ -88,8 +85,7 @@ impl AppOp {
                                 APPOP!(show_room_messages, (msgs));
                             }
                             Err(err) => {
-                                tx.send(BKResponse::RoomMessagesError(err))
-                                    .expect_log("Connection closed");
+                                dispatch_error(BKResponse::RoomMessagesError(err));
                             }
                         }
 
@@ -99,8 +95,7 @@ impl AppOp {
                                 APPOP!(set_rooms, (rooms, clear_room_list));
                             }
                             Err(err) => {
-                                tx.send(BKResponse::UpdateRoomsError(err))
-                                    .expect_log("Connection closed");
+                                dispatch_error(BKResponse::UpdateRoomsError(err));
                             }
                         }
 
@@ -136,8 +131,7 @@ impl AppOp {
                                 }
                             }
                             Err(err) => {
-                                tx.send(BKResponse::RoomElementError(err))
-                                    .expect_log("Connection closed");
+                                dispatch_error(BKResponse::RoomElementError(err));
                             }
                         }
 
@@ -146,8 +140,7 @@ impl AppOp {
                         APPOP!(synced, (s));
                     }
                     Err((err, n_tries)) => {
-                        tx.send(BKResponse::SyncError(err, n_tries))
-                            .expect_log("Connection closed");
+                        dispatch_error(BKResponse::SyncError(err, n_tries));
                     }
                 }
             });
diff --git a/fractal-gtk/src/appop/user.rs b/fractal-gtk/src/appop/user.rs
index 0ac054fc..f1f3a58a 100644
--- a/fractal-gtk/src/appop/user.rs
+++ b/fractal-gtk/src/appop/user.rs
@@ -2,11 +2,11 @@ use gtk::prelude::*;
 
 use fractal_api::backend::user;
 use fractal_api::clone;
-use fractal_api::util::ResultExpectLog;
 
 use std::path::PathBuf;
 use std::thread;
 
+use crate::app::dispatch_error;
 use crate::app::App;
 use crate::appop::AppOp;
 
@@ -21,28 +21,25 @@ use super::LoginData;
 impl AppOp {
     pub fn get_username(&self) {
         let login_data = unwrap_or_unit_return!(self.login_data.clone());
-        let tx = self.backend.clone();
 
-        thread::spawn(clone!(login_data, tx => move || {
+        thread::spawn(clone!(login_data => move || {
             match user::get_username(login_data.server_url, login_data.uid) {
                 Ok(username) => {
                     APPOP!(set_username, (username));
                 }
                 Err(err) => {
-                    tx.send(BKResponse::NameError(err))
-                        .expect_log("Connection closed");
+                    dispatch_error(BKResponse::NameError(err));
                 }
             }
         }));
 
-        thread::spawn(clone!(login_data, tx => move || {
+        thread::spawn(clone!(login_data => move || {
             match user::get_avatar(login_data.server_url, login_data.uid) {
                 Ok(path) => {
                     APPOP!(set_avatar, (path));
                 }
                 Err(err) => {
-                    tx.send(BKResponse::AvatarError(err))
-                        .expect_log("Connection closed");
+                    dispatch_error(BKResponse::AvatarError(err));
                 }
             }
         }));
diff --git a/fractal-gtk/src/widgets/address.rs b/fractal-gtk/src/widgets/address.rs
index eb0e47e4..f9d2901c 100644
--- a/fractal-gtk/src/widgets/address.rs
+++ b/fractal-gtk/src/widgets/address.rs
@@ -2,14 +2,13 @@ use fractal_api::backend::user;
 use fractal_api::r0::AccessToken;
 use fractal_api::r0::Medium;
 use fractal_api::url::Url;
-use fractal_api::util::ResultExpectLog;
 use glib::signal;
 use gtk::prelude::*;
 use rand::distributions::Alphanumeric;
 use rand::{thread_rng, Rng};
-use std::sync::mpsc::Sender;
 use std::thread;
 
+use crate::app::dispatch_error;
 use crate::app::App;
 use crate::appop::AppOp;
 use crate::backend::BKResponse;
@@ -168,7 +167,6 @@ impl<'a> Address<'a> {
         let access_token = login_data.access_token;
         let server_url = login_data.server_url;
         let id_server = login_data.identity_url;
-        let backend = self.op.backend.clone();
         self.signal_id = Some(self.button.clone().connect_clicked(move |w| {
             if !w.get_sensitive() || !w.is_visible() {
                 return;
@@ -188,19 +186,12 @@ impl<'a> Address<'a> {
             match action {
                 Some(AddressAction::Delete) => {
                     if let Some(address) = address.clone() {
-                        delete_address(
-                            backend.clone(),
-                            medium,
-                            address,
-                            server_url.clone(),
-                            access_token.clone(),
-                        );
+                        delete_address(medium, address, server_url.clone(), access_token.clone());
                     }
                 }
                 Some(AddressAction::Add) => {
                     if let Some(address) = entry.get_text().map(|gstr| gstr.to_string()) {
                         add_address(
-                            backend.clone(),
                             medium,
                             id_server.clone(),
                             address,
@@ -215,28 +206,20 @@ impl<'a> Address<'a> {
     }
 }
 
-fn delete_address(
-    tx: Sender<BKResponse>,
-    medium: Medium,
-    address: String,
-    server_url: Url,
-    access_token: AccessToken,
-) {
+fn delete_address(medium: Medium, address: String, server_url: Url, access_token: AccessToken) {
     thread::spawn(move || {
         match user::delete_three_pid(server_url, access_token, medium, address) {
             Ok(_) => {
                 APPOP!(get_three_pid);
             }
             Err(err) => {
-                tx.send(BKResponse::DeleteThreePIDError(err))
-                    .expect_log("Connection closed");
+                dispatch_error(BKResponse::DeleteThreePIDError(err));
             }
         }
     });
 }
 
 fn add_address(
-    tx: Sender<BKResponse>,
     medium: Medium,
     id_server: Url,
     address: String,
@@ -253,8 +236,7 @@ fn add_address(
                     APPOP!(get_token_phone, (sid, secret))
                 }
                 Err(err) => {
-                    tx.send(BKResponse::GetTokenPhoneError(err))
-                        .expect_log("Connection closed");
+                    dispatch_error(BKResponse::GetTokenPhoneError(err));
                 }
             }
         }
@@ -266,8 +248,7 @@ fn add_address(
                     APPOP!(get_token_email, (sid, secret));
                 }
                 Err(err) => {
-                    tx.send(BKResponse::GetTokenEmailError(err))
-                        .expect_log("Connection closed");
+                    dispatch_error(BKResponse::GetTokenEmailError(err));
                 }
             }
         }
diff --git a/fractal-gtk/src/widgets/image.rs b/fractal-gtk/src/widgets/image.rs
index 7372b6be..99c1192a 100644
--- a/fractal-gtk/src/widgets/image.rs
+++ b/fractal-gtk/src/widgets/image.rs
@@ -15,7 +15,6 @@ use std::sync::mpsc::channel;
 use std::sync::mpsc::{Receiver, Sender};
 use std::sync::{Arc, Mutex};
 
-use crate::backend::BKResponse;
 use crate::error::Error;
 use std::sync::mpsc::TryRecvError;
 
@@ -26,7 +25,6 @@ pub struct Image {
     pub server_url: Url,
     pub max_size: Option<(i32, i32)>,
     pub widget: DrawingArea,
-    pub backend: Sender<BKResponse>,
     pub pixbuf: Arc<Mutex<Option<Pixbuf>>>,
     /// useful to avoid the scale_simple call on every draw
     pub scaled: Arc<Mutex<Option<Pixbuf>>>,
@@ -45,13 +43,13 @@ impl Image {
     /// # Examples
     ///
     /// ```
-    /// let img = Image::new(backend, "mxc://matrix.org/HASDH")
+    /// let img = Image::new("mxc://matrix.org/HASDH")
     ///           .circle(true)
     ///           .fixed(true)
     ///           .size(Some((50, 50)))
     ///           .build();
     /// ```
-    pub fn new(backend: &Sender<BKResponse>, server_url: Url, path: &str) -> Image {
+    pub fn new(server_url: Url, path: &str) -> Image {
         let da = DrawingArea::new();
         da.add_events(gdk::EventMask::ENTER_NOTIFY_MASK);
         da.add_events(gdk::EventMask::LEAVE_NOTIFY_MASK);
@@ -78,7 +76,6 @@ impl Image {
             zoom_level: Arc::new(Mutex::new(None)),
             thumb: false,
             circle: false,
-            backend: backend.clone(),
             fixed_size: false,
             centered: false,
             shrink_to_fit: false,
diff --git a/fractal-gtk/src/widgets/media_viewer.rs b/fractal-gtk/src/widgets/media_viewer.rs
index 498f960f..7e24f35f 100644
--- a/fractal-gtk/src/widgets/media_viewer.rs
+++ b/fractal-gtk/src/widgets/media_viewer.rs
@@ -20,7 +20,6 @@ use gtk::Overlay;
 use crate::types::Message;
 use crate::types::Room;
 
-use crate::backend::BKResponse;
 use crate::uitypes::RowType;
 use crate::widgets::image;
 use crate::widgets::message_menu::MessageMenu;
@@ -38,7 +37,6 @@ pub struct MediaViewer {
     data: Rc<RefCell<Data>>,
     /* gtk widgets we need to have a reference to */
     pub builder: gtk::Builder,
-    backend: Sender<BKResponse>,
 }
 
 #[derive(Debug)]
@@ -127,7 +125,6 @@ enum Widget {
 struct Data {
     builder: gtk::Builder,
     main_window: gtk::Window,
-    backend: Sender<BKResponse>,
     server_url: Url,
     access_token: AccessToken,
     uid: UserId,
@@ -148,7 +145,6 @@ struct Data {
 
 impl Data {
     pub fn new(
-        backend: Sender<BKResponse>,
         server_url: Url,
         access_token: AccessToken,
         media_list: Vec<Message>,
@@ -173,7 +169,6 @@ impl Data {
             no_more_media: false,
             widget: Widget::None,
             builder,
-            backend,
             server_url,
             access_token,
             uid,
@@ -366,7 +361,7 @@ impl Data {
         let url = msg.url.clone().unwrap_or_default();
         match msg.mtype.as_ref() {
             "m.image" => {
-                let image = image::Image::new(&self.backend, self.server_url.clone(), &url)
+                let image = image::Image::new(self.server_url.clone(), &url)
                     .shrink_to_fit(true)
                     .center(true)
                     .build(thread_pool);
@@ -631,7 +626,6 @@ impl Drop for Data {
 
 impl MediaViewer {
     pub fn new(
-        backend: Sender<BKResponse>,
         main_window: gtk::Window,
         room: &Room,
         current_media_msg: &Message,
@@ -658,7 +652,6 @@ impl MediaViewer {
 
         MediaViewer {
             data: Rc::new(RefCell::new(Data::new(
-                backend.clone(),
                 server_url,
                 access_token,
                 media_list,
@@ -669,7 +662,6 @@ impl MediaViewer {
                 room.admins.clone(),
             ))),
             builder,
-            backend,
         }
     }
 
@@ -712,11 +704,10 @@ impl MediaViewer {
         let url = media_msg.url.clone().unwrap_or_default();
         match media_msg.mtype.as_ref() {
             "m.image" => {
-                let image =
-                    image::Image::new(&self.backend, self.data.borrow().server_url.clone(), &url)
-                        .shrink_to_fit(true)
-                        .center(true)
-                        .build(thread_pool);
+                let image = image::Image::new(self.data.borrow().server_url.clone(), &url)
+                    .shrink_to_fit(true)
+                    .center(true)
+                    .build(thread_pool);
 
                 media_viewport.add(&image.widget);
                 media_viewport.show_all();
@@ -897,7 +888,6 @@ impl MediaViewer {
 
         let own_weak = Rc::downgrade(&self.data);
         let builder = self.builder.clone();
-        let backend = self.backend.clone();
         let previous_media_button = self
             .builder
             .get_object::<gtk::Button>("previous_media_button")
@@ -906,7 +896,7 @@ impl MediaViewer {
         previous_media_button.connect_clicked(move |_| {
             if let Some(own) = own_weak.upgrade() {
                 if !own.borrow_mut().previous_media(t_pool.clone()) {
-                    load_more_media(t_pool.clone(), own, builder.clone(), backend.clone());
+                    load_more_media(t_pool.clone(), own, builder.clone());
                 }
             }
         });
@@ -1024,12 +1014,7 @@ fn loading_state(ui: &gtk::Builder, val: bool) -> bool {
     val
 }
 
-fn load_more_media(
-    thread_pool: ThreadPool,
-    data: Rc<RefCell<Data>>,
-    builder: gtk::Builder,
-    backend: Sender<BKResponse>,
-) {
+fn load_more_media(thread_pool: ThreadPool, data: Rc<RefCell<Data>>, builder: gtk::Builder) {
     data.borrow_mut().loading_more_media = loading_state(&builder, true);
 
     let msg = data.borrow().media_list[data.borrow().current_media_index].clone();
@@ -1086,7 +1071,7 @@ fn load_more_media(
                 data.borrow_mut().media_list = new_media_list;
                 data.borrow_mut().prev_batch = Some(prev_batch);
                 if img_msgs_count == 0 {
-                    load_more_media(thread_pool, data, builder.clone(), backend.clone());
+                    load_more_media(thread_pool, data, builder.clone());
                 } else {
                     data.borrow_mut().current_media_index += img_msgs_count;
                     data.borrow_mut().previous_media(thread_pool);
diff --git a/fractal-gtk/src/widgets/message.rs b/fractal-gtk/src/widgets/message.rs
index c9560d69..f5e53bc6 100644
--- a/fractal-gtk/src/widgets/message.rs
+++ b/fractal-gtk/src/widgets/message.rs
@@ -9,10 +9,8 @@ use fractal_api::url::Url;
 use gtk::{prelude::*, ButtonExt, ContainerExt, LabelExt, Overlay, WidgetExt};
 use std::cmp::max;
 use std::rc::Rc;
-use std::sync::mpsc::Sender;
 use std::sync::{Arc, Mutex};
 
-use crate::backend::BKResponse;
 use crate::util::markup_text;
 
 use crate::cache::download_to_cache;
@@ -30,7 +28,6 @@ use crate::widgets::{AudioPlayerWidget, PlayerExt, VideoPlayerWidget};
 /* A message row in the room history */
 #[derive(Clone, Debug)]
 pub struct MessageBox {
-    backend: Sender<BKResponse>,
     server_url: Url,
     username: gtk::Label,
     pub username_event_box: gtk::EventBox,
@@ -43,7 +40,7 @@ pub struct MessageBox {
 }
 
 impl MessageBox {
-    pub fn new(backend: Sender<BKResponse>, server_url: Url) -> MessageBox {
+    pub fn new(server_url: Url) -> MessageBox {
         let username = gtk::Label::new(None);
         let eb = gtk::EventBox::new();
         let eventbox = gtk::EventBox::new();
@@ -55,7 +52,6 @@ impl MessageBox {
         gesture.set_touch_only(true);
 
         MessageBox {
-            backend,
             server_url,
             username,
             username_event_box: eb,
@@ -395,7 +391,7 @@ impl MessageBox {
             Some(ref m) if m.starts_with("mxc:") || m.starts_with("http") => m.clone(),
             _ => msg.url.clone().unwrap_or_default(),
         };
-        let image = widgets::image::Image::new(&self.backend, self.server_url.clone(), &img_path)
+        let image = widgets::image::Image::new(self.server_url.clone(), &img_path)
             .size(Some(globals::MAX_IMAGE_SIZE))
             .build(thread_pool);
 
@@ -411,9 +407,8 @@ impl MessageBox {
 
     fn build_room_msg_sticker(&self, thread_pool: ThreadPool, msg: &Message) -> gtk::Box {
         let bx = gtk::Box::new(gtk::Orientation::Horizontal, 0);
-        let backend = self.backend.clone();
         if let Some(url) = msg.url.as_ref() {
-            let image = widgets::image::Image::new(&backend, self.server_url.clone(), url)
+            let image = widgets::image::Image::new(self.server_url.clone(), url)
                 .size(Some(globals::MAX_STICKER_SIZE))
                 .build(thread_pool);
             image.widget.set_tooltip_text(Some(&msg.body[..]));
diff --git a/fractal-gtk/src/widgets/room.rs b/fractal-gtk/src/widgets/room.rs
index 60f51cdc..b57ff1cf 100644
--- a/fractal-gtk/src/widgets/room.rs
+++ b/fractal-gtk/src/widgets/room.rs
@@ -1,7 +1,6 @@
 use crate::i18n::i18n;
 
 use fractal_api::backend::room;
-use fractal_api::util::ResultExpectLog;
 use gtk::prelude::*;
 use std::thread;
 
@@ -11,6 +10,7 @@ use crate::backend::BKResponse;
 
 use crate::util::markup_text;
 
+use crate::app::dispatch_error;
 use crate::app::App;
 use crate::appop::AppOp;
 
@@ -125,12 +125,10 @@ impl<'a> RoomBox<'a> {
 
             let join_button = gtk::Button::new_with_label(i18n("Join").as_str());
             let room_id = room.id.clone();
-            let tx = self.op.backend.clone();
             join_button.connect_clicked(move |_| {
                 let server_url = login_data.server_url.clone();
                 let access_token = login_data.access_token.clone();
                 let room_id = room_id.clone();
-                let tx = tx.clone();
                 thread::spawn(move || {
                     match room::join_room(server_url, access_token, room_id.clone()) {
                         Ok(jtr) => {
@@ -138,10 +136,7 @@ impl<'a> RoomBox<'a> {
                             APPOP!(set_join_to_room, (jtr));
                             APPOP!(reload_rooms);
                         }
-                        Err(err) => {
-                            tx.send(BKResponse::JoinRoomError(err))
-                                .expect_log("Connection closed");
-                        }
+                        Err(err) => dispatch_error(BKResponse::JoinRoomError(err)),
                     }
                 });
             });
diff --git a/fractal-gtk/src/widgets/room_history.rs b/fractal-gtk/src/widgets/room_history.rs
index 8f474539..11c607c7 100644
--- a/fractal-gtk/src/widgets/room_history.rs
+++ b/fractal-gtk/src/widgets/room_history.rs
@@ -7,11 +7,9 @@ use log::warn;
 use std::cell::RefCell;
 use std::collections::VecDeque;
 use std::rc::Rc;
-use std::sync::mpsc::Sender;
 use std::sync::{Arc, Mutex};
 
 use crate::appop::AppOp;
-use crate::backend::BKResponse;
 use crate::i18n::i18n;
 use crate::uitypes::MessageContent;
 use crate::uitypes::RowType;
@@ -255,7 +253,6 @@ impl Element {
 pub struct RoomHistory {
     /* Contains a list of msg ids to keep track of the displayed messages */
     rows: Rc<RefCell<List>>,
-    backend: Sender<BKResponse>,
     server_url: Url,
     source_id: Rc<RefCell<Option<source::SourceId>>>,
     queue: Rc<RefCell<VecDeque<MessageContent>>>,
@@ -282,7 +279,6 @@ impl RoomHistory {
         listbox.insert_action_group("message", Some(&actions));
         let mut rh = RoomHistory {
             rows: Rc::new(RefCell::new(List::new(scroll, listbox))),
-            backend: op.backend.clone(),
             server_url: op.login_data.clone()?.server_url,
             source_id: Rc::new(RefCell::new(None)),
             queue: Rc::new(RefCell::new(VecDeque::new())),
@@ -439,7 +435,6 @@ impl RoomHistory {
         thread_pool: ThreadPool,
         user_info_cache: Arc<Mutex<CacheMap<UserId, (String, String)>>>,
     ) -> Option<()> {
-        let backend = self.backend.clone();
         let queue = self.queue.clone();
         let rows = self.rows.clone();
 
@@ -495,7 +490,6 @@ impl RoomHistory {
                         user_info_cache.clone(),
                         item.clone(),
                         has_header,
-                        backend.clone(),
                         server_url.clone(),
                         &rows,
                     ));
@@ -567,7 +561,6 @@ impl RoomHistory {
             user_info_cache,
             item.clone(),
             has_header,
-            self.backend.clone(),
             self.server_url.clone(),
             &self.rows,
         );
@@ -680,13 +673,12 @@ fn create_row(
     user_info_cache: Arc<Mutex<CacheMap<UserId, (String, String)>>>,
     row: MessageContent,
     has_header: bool,
-    backend: Sender<BKResponse>,
     server_url: Url,
     rows: &Rc<RefCell<List>>,
 ) -> widgets::MessageBox {
     /* we need to create a message with the username, so that we don't have to pass
      * all information to the widget creating each row */
-    let mut mb = widgets::MessageBox::new(backend, server_url);
+    let mut mb = widgets::MessageBox::new(server_url);
     mb.create(
         thread_pool,
         user_info_cache,
diff --git a/fractal-gtk/src/widgets/room_settings.rs b/fractal-gtk/src/widgets/room_settings.rs
index 50ab379e..56f3e9ed 100644
--- a/fractal-gtk/src/widgets/room_settings.rs
+++ b/fractal-gtk/src/widgets/room_settings.rs
@@ -2,10 +2,8 @@ use fractal_api::backend::room;
 use fractal_api::clone;
 use fractal_api::identifiers::UserId;
 use fractal_api::r0::AccessToken;
-use fractal_api::util::ResultExpectLog;
 use std::cell::RefCell;
 use std::rc::Rc;
-use std::sync::mpsc::Sender;
 use std::thread;
 
 use crate::i18n::ni18n_f;
@@ -15,6 +13,7 @@ use gtk::prelude::*;
 
 use crate::actions;
 use crate::actions::{ButtonState, StateExt};
+use crate::app::dispatch_error;
 use crate::app::App;
 use crate::backend::BKResponse;
 use crate::types::Member;
@@ -31,7 +30,6 @@ pub struct RoomSettings {
     uid: UserId,
     builder: gtk::Builder,
     members_list: Option<MembersList>,
-    backend: Sender<BKResponse>,
     server_url: Url,
     access_token: AccessToken,
 }
@@ -39,7 +37,6 @@ pub struct RoomSettings {
 impl RoomSettings {
     pub fn new(
         window: &gtk::Window,
-        backend: Sender<BKResponse>,
         uid: UserId,
         room: Room,
         server_url: Url,
@@ -55,8 +52,7 @@ impl RoomSettings {
             .get_object::<gtk::Stack>("room_settings_stack")
             .expect("Can't find room_settings_stack in ui file.");
 
-        let actions =
-            actions::RoomSettings::new(&window, &backend, server_url.clone(), access_token.clone());
+        let actions = actions::RoomSettings::new(&window, server_url.clone(), access_token.clone());
         stack.insert_action_group("room-settings", Some(&actions));
 
         RoomSettings {
@@ -65,7 +61,6 @@ impl RoomSettings {
             uid,
             builder,
             members_list: None,
-            backend,
             server_url,
             access_token,
         }
@@ -433,15 +428,13 @@ impl RoomSettings {
         let server = self.server_url.clone();
         let access_token = self.access_token.clone();
         let room_id = self.room.id.clone();
-        let tx = self.backend.clone();
         thread::spawn(
             move || match room::get_room_avatar(server, access_token, room_id) {
                 Ok((room, avatar)) => {
                     APPOP!(set_room_avatar, (room, avatar));
                 }
                 Err(err) => {
-                    tx.send(BKResponse::RoomAvatarError(err))
-                        .expect_log("Connection closed");
+                    dispatch_error(BKResponse::RoomAvatarError(err));
                 }
             },
         );
@@ -506,15 +499,13 @@ impl RoomSettings {
         let server = self.server_url.clone();
         let access_token = self.access_token.clone();
         let room_id = room.id.clone();
-        let tx = self.backend.clone();
         thread::spawn(
             move || match room::set_room_name(server, access_token, room_id, new_name) {
                 Ok(_) => {
                     APPOP!(show_new_room_name);
                 }
                 Err(err) => {
-                    tx.send(BKResponse::SetRoomNameError(err))
-                        .expect_log("Connection closed");
+                    dispatch_error(BKResponse::SetRoomNameError(err));
                 }
             },
         );
@@ -566,15 +557,13 @@ impl RoomSettings {
         let server = self.server_url.clone();
         let access_token = self.access_token.clone();
         let room_id = room.id.clone();
-        let tx = self.backend.clone();
         thread::spawn(
             move || match room::set_room_topic(server, access_token, room_id, topic) {
                 Ok(_) => {
                     APPOP!(show_new_room_topic);
                 }
                 Err(err) => {
-                    tx.send(BKResponse::SetRoomTopicError(err))
-                        .expect_log("Connection closed");
+                    dispatch_error(BKResponse::SetRoomTopicError(err));
                 }
             },
         );
diff --git a/fractal-matrix-api/src/backend/types.rs b/fractal-matrix-api/src/backend/types.rs
index c37a3929..594c82c0 100644
--- a/fractal-matrix-api/src/backend/types.rs
+++ b/fractal-matrix-api/src/backend/types.rs
@@ -6,8 +6,6 @@ use crate::error::Error;
 
 #[derive(Debug)]
 pub enum BKResponse {
-    ShutDown,
-
     //errors
     LoginError(Error),
     GuestLoginError(Error),


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