[fractal] session: Mark offline when homeserver isn't reachable
- From: Julian Sparber <jsparber src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [fractal] session: Mark offline when homeserver isn't reachable
- Date: Tue, 16 Aug 2022 10:54:08 +0000 (UTC)
commit 8a6a209f54283c5416dc66c87ad429dedeaf3d5b
Author: Julian Sparber <julian sparber net>
Date: Fri Jul 22 19:50:32 2022 +0200
session: Mark offline when homeserver isn't reachable
This also shows a infobar to the user when offline.
This completely ignores the connecticity state since it's unrelaibale
and the server may be reachable even without internet connection.
data/resources/ui/sidebar.ui | 15 +++++++
src/session/mod.rs | 97 +++++++++++++++++++++++++++++++++++++++++++-
src/session/sidebar/mod.rs | 30 +++++++++++++-
3 files changed, 138 insertions(+), 4 deletions(-)
---
diff --git a/data/resources/ui/sidebar.ui b/data/resources/ui/sidebar.ui
index de0353c60..2f3eb9b8f 100644
--- a/data/resources/ui/sidebar.ui
+++ b/data/resources/ui/sidebar.ui
@@ -133,6 +133,20 @@
</accessibility>
</object>
</child>
+ <child>
+ <object class="GtkInfoBar" id="offline_info_bar">
+ <property name="message-type">warning</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="hexpand">True</property>
+ <property name="label" translatable="yes">Offline</property>
+ <style>
+ <class name="heading"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
<child>
<object class="GtkScrolledWindow">
<property name="vexpand">True</property>
@@ -156,3 +170,4 @@
</child>
</template>
</interface>
+
diff --git a/src/session/mod.rs b/src/session/mod.rs
index 040d53547..b3e17d58d 100644
--- a/src/session/mod.rs
+++ b/src/session/mod.rs
@@ -15,7 +15,15 @@ use std::{collections::HashSet, convert::TryFrom, fs, path::PathBuf, time::Durat
use adw::subclass::prelude::BinImpl;
use futures::StreamExt;
use gettextrs::gettext;
-use gtk::{self, gdk, glib, glib::clone, prelude::*, subclass::prelude::*, CompositeTemplate};
+use gtk::{
+ self, gdk, gio,
+ gio::prelude::*,
+ glib,
+ glib::{clone, signal::SignalHandlerId},
+ prelude::*,
+ subclass::prelude::*,
+ CompositeTemplate,
+};
use log::{debug, error, warn};
use matrix_sdk::{
config::{RequestConfig, StoreConfig, SyncSettings},
@@ -63,7 +71,9 @@ use crate::{
secret,
secret::{Secret, StoredSession},
session::sidebar::ItemList,
- spawn, spawn_tokio, toast, UserFacingError, Window,
+ spawn, spawn_tokio, toast,
+ utils::check_if_reachable,
+ UserFacingError, Window,
};
#[derive(Error, Debug)]
@@ -111,9 +121,12 @@ mod imp {
pub item_list: OnceCell<ItemList>,
pub user: OnceCell<User>,
pub is_ready: Cell<bool>,
+ pub prepared: Cell<bool>,
pub logout_on_dispose: Cell<bool>,
pub info: OnceCell<StoredSession>,
pub sync_tokio_handle: RefCell<Option<JoinHandle<()>>>,
+ pub offline_handler_id: RefCell<Option<SignalHandlerId>>,
+ pub offline: Cell<bool>,
}
#[glib::object_subclass]
@@ -208,6 +221,13 @@ mod imp {
User::static_type(),
glib::ParamFlags::READABLE,
),
+ glib::ParamSpecBoolean::new(
+ "offline",
+ "Offline",
+ "Whether this session has a connection to the homeserver",
+ false,
+ glib::ParamFlags::READABLE,
+ ),
]
});
@@ -218,6 +238,7 @@ mod imp {
match pspec.name() {
"item-list" => obj.item_list().to_value(),
"user" => obj.user().to_value(),
+ "offline" => obj.is_offline().to_value(),
_ => unimplemented!(),
}
}
@@ -253,9 +274,23 @@ mod imp {
}
}),
);
+
+ let monitor = gio::NetworkMonitor::default();
+ let handler_id = monitor.connect_network_changed(clone!(@weak obj => move |_, _| {
+ spawn!(clone!(@weak obj => async move {
+ obj.update_offline().await;
+ }));
+ }));
+
+ self.offline_handler_id.replace(Some(handler_id));
}
fn dispose(&self, obj: &Self::Type) {
+ // Needs to be disconnected or else it may restart the sync
+ if let Some(handler_id) = self.offline_handler_id.take() {
+ gio::NetworkMonitor::default().disconnect(handler_id);
+ }
+
if let Some(handle) = self.sync_tokio_handle.take() {
handle.abort();
}
@@ -467,11 +502,13 @@ impl Session {
};
priv_.info.set(session).unwrap();
+ self.update_offline().await;
self.room_list().load();
self.setup_direct_room_handler();
self.setup_room_encrypted_changes();
+ self.set_is_prepared(true);
self.sync();
None
@@ -489,6 +526,10 @@ impl Session {
}
fn sync(&self) {
+ if !self.is_prepared() || self.is_offline() {
+ return;
+ }
+
let client = self.client();
let session_weak: glib::SendWeakRef<Session> = self.downgrade().into();
@@ -587,6 +628,18 @@ impl Session {
self.imp().is_ready.get()
}
+ fn set_is_prepared(&self, prepared: bool) {
+ if self.is_prepared() == prepared {
+ return;
+ }
+
+ self.imp().prepared.set(prepared);
+ }
+
+ fn is_prepared(&self) -> bool {
+ self.imp().prepared.get()
+ }
+
pub fn room_list(&self) -> &RoomList {
self.item_list().room_list()
}
@@ -634,6 +687,46 @@ impl Session {
.expect("The session isn't ready")
}
+ pub fn is_offline(&self) -> bool {
+ self.imp().offline.get()
+ }
+
+ async fn update_offline(&self) {
+ let priv_ = self.imp();
+ let monitor = gio::NetworkMonitor::default();
+
+ let is_offline = if monitor.is_network_available() {
+ if let Some(info) = priv_.info.get() {
+ !check_if_reachable(&info.homeserver).await
+ } else {
+ false
+ }
+ } else {
+ true
+ };
+
+ if self.is_offline() == is_offline {
+ return;
+ }
+
+ if is_offline {
+ debug!("This session is now offline");
+ } else {
+ debug!("This session is now online");
+ }
+
+ priv_.offline.set(is_offline);
+
+ if let Some(handle) = priv_.sync_tokio_handle.take() {
+ handle.abort();
+ }
+
+ // Restart the sync loop when online
+ self.sync();
+
+ self.notify("offline");
+ }
+
/// Connects the prepared signals to the function f given in input
pub fn connect_prepared<F: Fn(&Self, Option<String>) + 'static>(
&self,
diff --git a/src/session/sidebar/mod.rs b/src/session/sidebar/mod.rs
index fbca517c5..843951fc6 100644
--- a/src/session/sidebar/mod.rs
+++ b/src/session/sidebar/mod.rs
@@ -34,6 +34,7 @@ use crate::{
components::Avatar,
session::{
room::{Room, RoomType},
+ user::UserExt,
verification::IdentityVerification,
User,
},
@@ -46,7 +47,7 @@ mod imp {
convert::TryFrom,
};
- use glib::subclass::InitializingObject;
+ use glib::{signal::SignalHandlerId, subclass::InitializingObject};
use once_cell::{sync::Lazy, unsync::OnceCell};
use super::*;
@@ -68,11 +69,14 @@ mod imp {
pub account_switcher_button: TemplateChild<gtk::MenuButton>,
#[template_child]
pub room_row_menu: TemplateChild<gio::MenuModel>,
+ #[template_child]
+ pub offline_info_bar: TemplateChild<gtk::InfoBar>,
pub room_row_popover: OnceCell<gtk::PopoverMenu>,
pub user: RefCell<Option<User>>,
/// The type of the source that activated drop mode.
pub drop_source_type: Cell<Option<RoomType>>,
pub drop_binding: RefCell<Option<glib::Binding>>,
+ pub offline_handler_id: RefCell<Option<SignalHandlerId>>,
}
#[glib::object_subclass]
@@ -367,10 +371,32 @@ impl Sidebar {
}
fn set_user(&self, user: Option<User>) {
- if self.user() == user {
+ let prev_user = self.user();
+ if prev_user == user {
return;
}
+ if let Some(prev_user) = prev_user {
+ if let Some(handler_id) = self.imp().offline_handler_id.take() {
+ prev_user.session().disconnect(handler_id);
+ }
+ }
+
+ if let Some(user) = user.as_ref() {
+ let session = user.session();
+ let handler_id = session.connect_notify_local(
+ Some("offline"),
+ clone!(@weak self as obj => move |session, _| {
+ obj.imp().offline_info_bar.set_revealed(session.is_offline());
+ }),
+ );
+ self.imp()
+ .offline_info_bar
+ .set_revealed(session.is_offline());
+
+ self.imp().offline_handler_id.replace(Some(handler_id));
+ }
+
self.imp().user.replace(user);
self.notify("user");
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]