Skip to content

Commit

Permalink
introduce proper error boundary
Browse files Browse the repository at this point in the history
  • Loading branch information
ranfdev committed Feb 13, 2024
1 parent 75c59df commit 29377dc
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 62 deletions.
50 changes: 50 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use futures::Future;
use glib::subclass::prelude::*;
use gtk::prelude::*;
use gtk::{self, glib};

use crate::widgets::NotifyWindow;

pub type Error = anyhow::Error;

pub trait ErrorBoundaryProvider {
fn error_boundary(&self) -> ErrorBoundary;
}

impl<W: IsA<gtk::Widget>> ErrorBoundaryProvider for W {
fn error_boundary(&self) -> ErrorBoundary {
let direct_ancestor: Option<adw::ToastOverlay> = self
.ancestor(adw::ToastOverlay::static_type())
.and_downcast();
let win: Option<adw::ToastOverlay> = self
.ancestor(NotifyWindow::static_type())
.and_downcast()
.map(|win: NotifyWindow| win.imp().toast_overlay.clone());
let toast_overlay = direct_ancestor.or(win);
ErrorBoundary {
source: self.clone().into(),
boundary: toast_overlay,
}
}
}

pub struct ErrorBoundary {
source: gtk::Widget,
boundary: Option<adw::ToastOverlay>,
}

impl ErrorBoundary {
pub fn spawn<T>(self, f: impl Future<Output = Result<T, Error>> + 'static) {
glib::MainContext::ref_thread_default().spawn_local_with_priority(
glib::Priority::DEFAULT_IDLE,
async move {
if let Err(e) = f.await {
if let Some(boundary) = self.boundary {
boundary.add_toast(adw::Toast::builder().title(&e.to_string()).build());
}
tracing::error!(source=?self.source.type_().name(), error=?e);
}
},
);
}
}
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod application;
#[rustfmt::skip]
mod config;
mod async_utils;
pub mod error;
mod subscription;
pub mod widgets;

Expand Down
14 changes: 7 additions & 7 deletions src/subscription.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ impl Subscription {
self.notify_display_name();
}
#[instrument(skip_all)]
pub fn set_display_name(&self, value: String) -> Promise<(), capnp::Error> {
pub fn set_display_name(&self, value: String) -> Promise<(), anyhow::Error> {
let this = self.clone();
Promise::from_future(async move {
this._set_display_name(value);
Expand All @@ -209,7 +209,7 @@ impl Subscription {
})
}

fn send_updated_info(&self) -> Promise<(), capnp::Error> {
fn send_updated_info(&self) -> Promise<(), anyhow::Error> {
let imp = self.imp();
let mut req = imp.client.get().unwrap().update_info_request();
let mut val = pry!(req.get().get_value());
Expand Down Expand Up @@ -240,7 +240,7 @@ impl Subscription {
self.notify_unread_count();
}

pub fn set_muted(&self, value: bool) -> Promise<(), capnp::Error> {
pub fn set_muted(&self, value: bool) -> Promise<(), anyhow::Error> {
let this = self.clone();
Promise::from_future(async move {
this.imp().muted.replace(value);
Expand All @@ -249,7 +249,7 @@ impl Subscription {
Ok(())
})
}
pub fn flag_all_as_read(&self) -> Promise<(), capnp::Error> {
pub fn flag_all_as_read(&self) -> Promise<(), anyhow::Error> {
let imp = self.imp();
let Some(value) = Self::last_message(&imp.messages)
.map(|last| last.time)
Expand All @@ -268,11 +268,11 @@ impl Subscription {
Ok(())
})
}
pub fn publish_msg(&self, mut msg: models::Message) -> Promise<(), capnp::Error> {
pub fn publish_msg(&self, mut msg: models::Message) -> Promise<(), anyhow::Error> {
let imp = self.imp();
let json = {
msg.topic = self.topic();
serde_json::to_string(&msg).map_err(|e| capnp::Error::failed(e.to_string()))
serde_json::to_string(&msg)
};
let mut req = imp.client.get().unwrap().publish_request();
req.get().set_message(pry!(json).as_str().into());
Expand All @@ -284,7 +284,7 @@ impl Subscription {
})
}
#[instrument(skip_all)]
pub fn clear_notifications(&self) -> Promise<(), capnp::Error> {
pub fn clear_notifications(&self) -> Promise<(), anyhow::Error> {
let imp = self.imp();
let req = imp.client.get().unwrap().clear_notifications_request();
let this = self.clone();
Expand Down
4 changes: 2 additions & 2 deletions src/widgets/advanced_message_dialog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use adw::subclass::prelude::*;
use gsv::prelude::*;
use gtk::{gio, glib};

use crate::error::*;
use crate::subscription::Subscription;
use crate::widgets::*;

mod imp {
use super::*;
Expand Down Expand Up @@ -194,7 +194,7 @@ impl AdvancedMessageDialog {
thisc.imp().subscription.get().unwrap()
.publish_msg(msg).await
};
toast_overlay.spawn_with_near_toast(f);
toast_overlay.error_boundary().spawn(f);
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/widgets/message_row.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use gtk::{gdk, gio, glib};
use ntfy_daemon::models;
use tracing::error;

use crate::widgets::window::SpawnWithToast;
use crate::error::*;

mod imp {
use super::*;
Expand Down Expand Up @@ -177,10 +177,10 @@ impl MessageRow {
picture.set_height_request(350);
let picturec = picture.clone();

self.spawn_with_near_toast(async move {
self.error_boundary().spawn(async move {
let t = r.recv().await?;
picturec.set_paintable(Some(&t));
Ok::<(), anyhow::Error>(())
Ok(())
});

picture
Expand Down
13 changes: 7 additions & 6 deletions src/widgets/preferences.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use adw::subclass::prelude::*;
use gtk::{gio, glib};
use ntfy_daemon::ntfy_capnp::system_notifier;

use crate::widgets::*;
use crate::error::*;

mod imp {
use super::*;
Expand Down Expand Up @@ -90,12 +90,14 @@ impl NotifyPreferences {
let this = obj.clone();
obj.imp().add_btn.connect_clicked(move |btn| {
let this = this.clone();
btn.spawn_with_near_toast(async move { this.add_account().await });
btn.error_boundary()
.spawn(async move { this.add_account().await });
});
let this = obj.clone();
obj.imp()
.added_accounts
.spawn_with_near_toast(async move { this.show_accounts().await });
.error_boundary()
.spawn(async move { this.show_accounts().await });
obj
}

Expand Down Expand Up @@ -128,9 +130,8 @@ impl NotifyPreferences {
let this = this.clone();
let username = username.clone();
let server = server.clone();
btn.spawn_with_near_toast(async move {
this.remove_account(&server, &username).await
});
btn.error_boundary()
.spawn(async move { this.remove_account(&server, &username).await });
});
btn
});
Expand Down
7 changes: 4 additions & 3 deletions src/widgets/subscription_info_dialog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use glib::Properties;
use gtk::gio;
use gtk::glib;

use crate::widgets::*;
use crate::error::*;

mod imp {
pub use super::*;
Expand Down Expand Up @@ -91,7 +91,7 @@ impl SubscriptionInfoDialog {
fn update_display_name(&self, entry: &impl IsA<gtk::Editable>) {
if let Some(sub) = self.subscription() {
let entry = entry.clone();
self.spawn_with_near_toast(async move {
self.error_boundary().spawn(async move {
let res = sub.set_display_name(entry.text().to_string()).await;
res
});
Expand All @@ -100,7 +100,8 @@ impl SubscriptionInfoDialog {
fn update_muted(&self, switch: &adw::SwitchRow) {
if let Some(sub) = self.subscription() {
let switch = switch.clone();
self.spawn_with_near_toast(async move { sub.set_muted(switch.is_active()).await })
self.error_boundary()
.spawn(async move { sub.set_muted(switch.is_active()).await })
}
}
}
55 changes: 14 additions & 41 deletions src/widgets/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,41 +11,10 @@ use tracing::warn;

use crate::application::NotifyApplication;
use crate::config::{APP_ID, PROFILE};
use crate::error::*;
use crate::subscription::Subscription;
use crate::widgets::*;

pub trait SpawnWithToast {
fn spawn_with_near_toast<T, R: std::fmt::Display>(
&self,
f: impl Future<Output = Result<T, R>> + 'static,
);
}

impl<W: IsA<gtk::Widget>> SpawnWithToast for W {
fn spawn_with_near_toast<T, R: std::fmt::Display>(
&self,
f: impl Future<Output = Result<T, R>> + 'static,
) {
let toast_overlay: Option<adw::ToastOverlay> = self
.ancestor(adw::ToastOverlay::static_type())
.and_downcast();
let win: Option<NotifyWindow> = self.ancestor(NotifyWindow::static_type()).and_downcast();
glib::MainContext::ref_thread_default().spawn_local_with_priority(
glib::Priority::DEFAULT_IDLE,
async move {
if let Err(e) = f.await {
if let Some(o) = toast_overlay
.as_ref()
.or_else(|| win.as_ref().map(|win| win.imp().toast_overlay.as_ref()))
{
o.add_toast(adw::Toast::builder().title(&e.to_string()).build())
}
}
},
);
}
}

mod imp {
use super::*;

Expand Down Expand Up @@ -169,7 +138,7 @@ mod imp {
});
klass.install_action("win.clear-notifications", None, |this, _, _| {
this.selected_subscription().map(|sub| {
this.spawn_with_near_toast(sub.clear_notifications());
this.error_boundary().spawn(sub.clear_notifications());
});
});
//klass.bind_template_instance_callbacks();
Expand Down Expand Up @@ -252,7 +221,10 @@ impl NotifyWindow {
..models::Message::default()
});

entry.spawn_with_near_toast(async move { p.await });
entry.error_boundary().spawn(async move {
p.await?;
Ok(())
});
};
let publishc = publish.clone();
imp.entry.connect_activate(move |_| publishc());
Expand Down Expand Up @@ -294,7 +266,7 @@ impl NotifyWindow {
req.get().set_topic(sub.topic.as_str().into());
let res = req.send();
let this = self.clone();
self.spawn_with_near_toast(async move {
self.error_boundary().spawn(async move {
let imp = this.imp();

// Subscription::new will use the pipelined client to retrieve info about the subscription
Expand All @@ -306,7 +278,7 @@ impl NotifyWindow {
let i = imp.subscription_list_model.n_items() - 1;
let row = imp.subscription_list.row_at_index(i as i32);
imp.subscription_list.select_row(row.as_ref());
Ok::<(), capnp::Error>(())
Ok(())
});
}

Expand All @@ -320,14 +292,14 @@ impl NotifyWindow {
let res = req.send();
let this = self.clone();

self.spawn_with_near_toast(async move {
self.error_boundary().spawn(async move {
let imp = this.imp();
res.promise.await?;

if let Some(i) = imp.subscription_list_model.find(&sub) {
imp.subscription_list_model.remove(i);
}
Ok::<(), capnp::Error>(())
Ok(())
});
}
fn notifier(&self) -> &system_notifier::Client {
Expand Down Expand Up @@ -358,14 +330,14 @@ impl NotifyWindow {
let this = self.clone();
let req = self.notifier().list_subscriptions_request();
let res = req.send();
self.spawn_with_near_toast(async move {
self.error_boundary().spawn(async move {
let list = res.promise.await?;
let list = list.get()?.get_list()?;
let imp = this.imp();
for sub in list {
imp.subscription_list_model.append(&Subscription::new(sub?));
}
Ok::<(), capnp::Error>(())
Ok(())
});
}
fn update_banner(&self, sub: Option<&Subscription>) {
Expand Down Expand Up @@ -429,7 +401,8 @@ impl NotifyWindow {
|| ((vadj.page_size() + vadj.value() - vadj.upper()).abs() <= 1.0)
{
self.selected_subscription().map(|sub| {
self.spawn_with_near_toast(sub.flag_all_as_read());
self.error_boundary()
.spawn(sub.flag_all_as_read().map_err(|e| e.into()));
});
}
}
Expand Down

0 comments on commit 29377dc

Please sign in to comment.