Web Push notifications from Irssi

Our main communication tool at Mozilla is IRC. I’m running an IRC client called Irssi under screen on a server constantly connected to the network. It’s a close-to-perfect solution with only two outstanding issues for me. One is the lack of emoji characters (I can live with that). The other is more important: there is no easy way to install a solution to receive notifications. This gave us the idea for a small project — to build a generic server for sending notifications that could work alongside the Irssi client.

Overview of the application

Mercurius is a generic push server that lets developers bring Web Push into their own native/web applications. Subscription management is entirely handled by Mercurius; the user registers on the Mercurius website and receives a token that other applications can use to send customized push notifications via a REST API.
Mercurius uses the web-push Node.js library to handle communication with the push service and takes care of the necessary payload encryption.
You can find the code on GitHub.

There are four actors in our application:

The user agent (browser), which subscribes for push notifications on a push service and sends the subscription information to the application server (Mercurius);

The push service;

The Mercurius application server, which maintains a list of the user subscriptions and sends push notifications to users via the push service;

A Mercurius client (in this case it’s an Irssi plugin), which uses a token (given to the user by the Mercurius server) to send the user push notifications via the Mercurius server.

Subscribing to push notifications

We needed to build a web page to allow users to subscribe for push notifications. The PushManager interface of the Push API comes to our aid. It can be accessed through a service worker registration:

Once we have the subscription (comprised of an endpoint URL on the push service and a user’s public key), we can send its info to the server, which will then use it to send the user a notification.
The Fetch API sends the POST request to the server (just to spice up the demo a bit):

Keeping the subscription up to date

The user’s subscription to the push service is periodically refreshed, or, in some cases invalidated (see the Push Quota recipe in the ServiceWorker Cookbook for an in-depth look), so we need to always keep the server up to date with the user subscription information.
To do so, we’ll add an event listener in the service worker for the ‘pushsubscriptionchange‘ event:

self.addEventListener('pushsubscriptionchange', function(event) {
// Handle the event by re-subscribing the user and sending the new info to the server

This way, when the subscription changes, we notify the server of the new endpoint URL and the new key.

Showing visual notifications

Once our user is subscribed to the push service and to the Mercurial server, we can send push messages and show visual notifications. The Irssi plugin will send a POST request to the Mercurius server, asking it to send the notification to the user. The Mercurius server sends the notification to the push service, which then delivers the notification to the browser. The payload of the push notification is sent to the endpoint URL with some clever crypto. It provides the actual parameters for displaying the notification. (You can read more here about the encryption: https://tools.ietf.org/html/draft-thomson-webpush-encryption-01).
The push notification triggers a ‘push‘ event in the service worker registered for the page, re-launching the service worker if it it is no longer active.
So, to show something to the user, we just need to handle the ‘push‘ event in our service worker:

As we mentioned earlier, we’re using the payload of the push message (for reference, see the Push Payload recipe in Mozilla’s Service Worker Cookbook) to pass the parameters of the notification from the Irssi plugin (or any other Mercurius client) to the service worker.

Testing with Mocha

We have implemented a few BDD tests with the Mocha framework to verify that the Mercurius server works correctly. We’ve also employed istanbul to measure code coverage and guide our test writing activity.
Simply run npm test to see its output.

Deployment

Deploying the server to Heroku is really simple. We have chosen to make Travis CI, our continuous integration service, perform the deploy after building Mercurius and a successful test run. Here’s our self-explanatory YAML configuration file for Travis CI:

We use skip_cleanup because we want to publish our build artifacts to Heroku.
The (encrypted) API key is specific to your user account and can be created using the Heroku and Travis CI command line clients:

Irssi client

The role of the Irssi Mercurius client is to send a notification to the Mercurius server every time the user is mentioned. I've modified an existing script, which saves this info to a file, so that it now saves and sends the request to the Mercurius server. After loading the script, a new command is registered in Irssi. It's called /mercurius, and it sets the token, host (if you decide to run your own), and intensity of the notifications. There is also a method to stop and start again notifications at will.

The plugin is written in Perl. Sending requests to the Mercurius server happens in the sub notify using the built-in HTTP::Tiny module. I've used the request method instead of post for backwards compatibility with older Perl versions.
The subroutine responsible for sending the notification request is called notify. Description is given here inside the comments.

Usage

/mercurius set_token {TOKEN}
Use it to set the token. You will receive a notification confirming that it has been set.

/mercurius set_host {HOST}
Default value is "https://mozcurius.herokuapp.com". Please note that the trailing slash has been removed.

/mercurius set_intense {0/1}
Switches on/off intense mode (default 0). With intense mode (1) all of the notifications are sent. Otherwise (default) if the user is in an active private window only the first message from that window will send a notification.

What’s Inside

As a member of the SchoolofWeb.org you will have access to:

* Web design, Web development and Web business resources including educational content, custom curriculum and training resources covering advanced techniques, and the most up-to-date best practices and methods
* Lesson plans for those that teach
* How-to guides to establish a Web professional program at your school or college
* Web professional directories
* Web professional job boards
* Web professional career guides

National Web Design Contest HTML and CSS Training Video

2018 Summer Class

WebProfessionals.org (aka the World Organization of Webmasters) has a 20+ year history of supporting practicing professionals and those that teach them. We also support aspiring web professionals. To that end, we are offering a summer class fro high school students and adult learners who would like to know more about creating web pages. This two week online course can be started any time from June 1, 2018, through late July, 2018. All assignments must be completed before August 10, 2018. Learners will have direct access to a teacher (who is available to answer questions and provide support and encouragement).