Skip to content

Add (optional) push notifications using KUnifiedPush

Joshua Goins requested to merge work/redstrate/push-notifications into master

Really? Yes. Does it work? Yes.

image (Showing a notification isn't really interesting 😆)

Reasoning

Reading over BUG: 463696 brings up a common pain point, and one I personally dislike as well. Notifications work in Tokodon when it's open (because of websockets ) but as soon as you close it, no notifications. A common way around this is to stick it in the system tray, but to be honest I don't really think Tokodon belongs there. Instead, I'm implementing #55 (closed)! Push notifications solve this problem perfectly: no system tray, can still keep up to date.

Problems

There is a couple of caveats to keep in mind, to explain some of the uh... questionable design decisions. Mastodon uses Web Push, which encrypts their payloads. Because of reasons, no UnifiedPush client can actually decrypt this data:

Because WebPush messages are encrypted, and Mastodon does not send the keys and IV needed for decryption in the request body, for now the push handler simply acts as a trigger for the pre-existing NotificationWorker which is also used for pull notifications. Nevertheless, I have implemented proper key generation and storage, just in case we would like to implement full decryption support in the future when Mastodon upgrades to the latest WebPush encryption scheme that includes all information in the request body.

Instead, we use the UP message as sort of a "wake-up call". However, since we can't decrypt the payload and WebPush doesn't give us any useful information we can only deduce it could happen to a account. So we must pull notifications for all accounts. See the processes below for an explanation, and how I sort of mitigated it.

Architecture

I originally planned to have a separate notifier daemon that ran under a different D-Bus id, but discovered a very nice way to have the application (who is using KDBusService, meaning that it only wants one instance usually) and still receive UP in the background:

  • A D-bus service file is installed, allowing Tokodon to be woken up by KUnifiedPush.
  • Normally, there is no way to discern why an application has been woken up: except that you can pass command line args in D-Bus service files!
  • So, our D-Bus service file has --notify, a special command line option that tells Tokodon to do the following:
    1. Start the AccountManager as soon as possible, and don't start the rest of the interface.
    2. When the AccountManager is done loading, start refreshing the notification queue.
    3. Load the "last push notification" id, and ask the server to load all notifications newer than that id. We only ask for 1 notification at a time, because naturally we only get one UP message per notification.
    4. If we get a valid notification from the server, store this id for later.

So in theory, we query a single available notification that "sort of" fits in the timeframe of the UP message coming in. This instance of Tokodon should be very short lived, and shouldn't interfere with the main application. Very stupid, but Mastodon clients that implement UP have similar behavior. Once Mastodon fixes it's mess, we can hopefully throw all of this out but it's not too much of a maintenance burden IMO, especially since we get push notifications in return!

TODO

  • Is having Tokodon D-Bus activatible affect anything else?
  • Need to write a UI for updating push notification rules
  • Handle the first startup scenario, when no accounts have a "last notification" id. Should probably pull it off the notification stack on first login?
  • We need to discuss tagging KUnifiedPush proper, I feel like it's usable now (the client library, the KCM not so much yet).
  • Don't show push notifications when Tokodon is open, obviously.
  • Although it would be rare, make sure a Tokodon main instance takes precedence over the notif version when both start up at the same time.
  • Time out the notification daemon if it takes too long.
  • Save the keypair, in case we can actually decrypt the payload at some point in the future.
  • Fix the dependencies/CMake.
  • Use QCoreApplication when in daemon mode, which should reduce memory usage even further.

@vkrause you would be really interested in this 😄

Edited by Joshua Goins

Merge request reports