summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Bruhin <me@the-compiler.org>2022-06-20 21:02:07 +0200
committerFlorian Bruhin <me@the-compiler.org>2022-06-21 13:14:19 +0200
commit188a1bfd543a464a9ac63491580116183460c345 (patch)
tree43d1ddea000de353a58af0e5f143725ca14a9b1f
parent998af8eb7ea3bd00b4e0ec7c9b275b58fa3d9acb (diff)
downloadqutebrowser-188a1bfd543a464a9ac63491580116183460c345.tar.gz
qutebrowser-188a1bfd543a464a9ac63491580116183460c345.zip
notificatio: Rethink error handling
The decision in a64c3d0dfc000cbd1a0b1f0f0afda783be245880 to return from _verify_message() when there is a non-fatal error (later expanded to more than just NoReply) was a poor one: While the error signal indeed takes care of swapping out the faulty adapter, the direct caller of _verify_message generally expects the message to be in the verified shape (e.g. having 4 arguments, or an int as argument, etc.). Thus, every caller would have to handle this situation, yet none of them did! With the restructured code, we now *always* raise an exception. It's still the callers responsibility to deal with that happening, but that's much less tricky than just pretending we validated the data when we did not. Thankfully, most caller already handle the situation, or don't need to: - _get_server_info() and _fetch_capabilities() get called from __init__, where any notification.Error is already handled by NotificationBridgePresenter. - _handle_close() and _handle_action() get called as DBus signals by Qt. It's hard to imagine how they would ever get an error reply, as the caller is the other side (the notification server), not us! This only leaves present(), which now handles this case: If it gets a fatal exception it still gets raised, but for any non-fatal ones, we now emit the error signal there and return a dummy value. Fixes #6931 (cherry picked from commit cd43614a62789edcbfbf07e292117ec4718cd86c)
-rw-r--r--qutebrowser/browser/webengine/notification.py83
1 files changed, 49 insertions, 34 deletions
diff --git a/qutebrowser/browser/webengine/notification.py b/qutebrowser/browser/webengine/notification.py
index 85e1eb4fa..39fce032a 100644
--- a/qutebrowser/browser/webengine/notification.py
+++ b/qutebrowser/browser/webengine/notification.py
@@ -103,6 +103,45 @@ class Error(Exception):
"""Raised when something goes wrong with notifications."""
+class DBusError(Error):
+ """Raised when there was an error coming from DBus."""
+
+ _NON_FATAL_ERRORS = {
+ # notification daemon is gone
+ "org.freedesktop.DBus.Error.NoReply",
+
+ # https://gitlab.gnome.org/GNOME/gnome-flashback/-/blob/3.40.0/gnome-flashback/libnotifications/nd-daemon.c#L178-187
+ # Exceeded maximum number of notifications
+ "org.freedesktop.Notifications.MaxNotificationsExceeded",
+
+ # https://bugs.kde.org/show_bug.cgi?id=409157
+ # https://github.com/KDE/plasma-workspace/blob/v5.21.4/libnotificationmanager/server_p.cpp#L227-L237
+ # Created too many similar notifications in quick succession
+ "org.freedesktop.Notifications.Error.ExcessNotificationGeneration",
+
+ # From https://crashes.qutebrowser.org/view/b8c9838a
+ # Process org.freedesktop.Notifications received signal 5
+ # probably when notification daemon crashes?
+ "org.freedesktop.DBus.Error.Spawn.ChildSignaled",
+
+ # https://crashes.qutebrowser.org/view/f76f58ae
+ # Process org.freedesktop.Notifications exited with status 1
+ "org.freedesktop.DBus.Error.Spawn.ChildExited",
+
+ # https://crashes.qutebrowser.org/view/8889d0b5
+ # Could not activate remote peer.
+ "org.freedesktop.DBus.Error.NameHasNoOwner",
+ }
+
+ def __init__(self, msg: QDBusMessage) -> None:
+ assert msg.type() == QDBusMessage.ErrorMessage
+ self.error = msg.errorName()
+ self.error_message = msg.errorMessage()
+ self.is_fatal = self.error not in self._NON_FATAL_ERRORS
+ text = f"{self.error}: {self.error_message}"
+ super().__init__(text)
+
+
class AbstractNotificationAdapter(QObject):
"""An adapter taking notifications and displaying them.
@@ -713,33 +752,6 @@ class DBusNotificationAdapter(AbstractNotificationAdapter):
SPEC_VERSION = "1.2" # Released in January 2011, still current in March 2021.
NAME = "libnotify"
- _NON_FATAL_ERRORS = {
- # notification daemon is gone
- "org.freedesktop.DBus.Error.NoReply",
-
- # https://gitlab.gnome.org/GNOME/gnome-flashback/-/blob/3.40.0/gnome-flashback/libnotifications/nd-daemon.c#L178-187
- # Exceeded maximum number of notifications
- "org.freedesktop.Notifications.MaxNotificationsExceeded",
-
- # https://bugs.kde.org/show_bug.cgi?id=409157
- # https://github.com/KDE/plasma-workspace/blob/v5.21.4/libnotificationmanager/server_p.cpp#L227-L237
- # Created too many similar notifications in quick succession
- "org.freedesktop.Notifications.Error.ExcessNotificationGeneration",
-
- # From https://crashes.qutebrowser.org/view/b8c9838a
- # Process org.freedesktop.Notifications received signal 5
- # probably when notification daemon crashes?
- "org.freedesktop.DBus.Error.Spawn.ChildSignaled",
-
- # https://crashes.qutebrowser.org/view/f76f58ae
- # Process org.freedesktop.Notifications exited with status 1
- "org.freedesktop.DBus.Error.Spawn.ChildExited",
-
- # https://crashes.qutebrowser.org/view/8889d0b5
- # Could not activate remote peer.
- "org.freedesktop.DBus.Error.NameHasNoOwner",
- }
-
def __init__(self, parent: QObject = None) -> None:
super().__init__(parent)
assert _notifications_supported()
@@ -933,12 +945,7 @@ class DBusNotificationAdapter(AbstractNotificationAdapter):
], expected_type
if msg.type() == QDBusMessage.ErrorMessage:
- err = msg.errorName()
- if err in self._NON_FATAL_ERRORS:
- self.error.emit(msg.errorMessage())
- return
-
- raise Error(f"Got DBus error: {err} - {msg.errorMessage()}")
+ raise DBusError(msg)
signature = msg.signature()
if signature != expected_signature:
@@ -1008,7 +1015,15 @@ class DBusNotificationAdapter(AbstractNotificationAdapter):
hints,
-1, # timeout; -1 means 'use default'
)
- self._verify_message(reply, "u", QDBusMessage.ReplyMessage)
+
+ try:
+ self._verify_message(reply, "u", QDBusMessage.ReplyMessage)
+ except DBusError as e:
+ if e.is_fatal:
+ raise
+ self.error.emit(e.error_message)
+ # Return value gets ignored in NotificationBridgePresenter.present
+ return -1
notification_id = reply.arguments()[0]