Push Notifications

This document provides a reference to the push notification server.

Components

paster serve etc/push-dev.ini
The main HTTP API server. This is a Pyramid app that stores the mappings for push URLs to users. When a new notification comes in, it is stored in queuey and published to the router for WebSocket distribution.
python router.py etc/push-dev.ini
The pubsub broker between the HTTP server and the WebSocket server. Notifications come in from the HTTP server and are published out to all WebSocket servers.
python websockets.py etc/push-dev.ini
The WebSocket server. Each server holds open connections to many users. Notifications are published to all WebSocket servers; each server picks out and delivers messages to its connected users.
python monitor.py etc/push-dev.ini
A daemon that monitors the status of the WebSocket servers. The number of connections each WebSocket is holding open is stored in the database. If the monitor can’t connect to a server, it removes it from the database so no new WebSocket connections are directed there.

digraph components {
"HTTP API" -> Router -> WebSockets -> Firefox;
Monitor -> WebSockets;
}

An Example

Clients are identified on the push server as an opaque string of characters. If our Firefox has this token:

token = abc123

...and facebook.com asks us to allow push notifications, Firefox will request a new push URL for facebook.com.

POST https://push.mozilla.org/queue/

domain=facebook.com&token=abc123

The API server will create a new queue and return a URL like:

https://push.mozilla.org/queue/xyz

Facebook stores this URL on their backend, associated with our user account.

When that URL is created, the push server maps the queue token to our user token:

queues_to_users = {"xyz": "abc123"}

When Facebook sends us a notification

POST https://push.mozilla.org/queue/xyz/
Content-Type: application/json

{"title": "Thanks for using Facebook."}

...the push server looks up the user token for that queue and delivers the notification to us.

Public API

POST /queue/{queue}/

Send a new notification. This is how third-party sites send notifications to users. The URLs are created through the navigator.notification.requestRemotePermission() API.

POST params:
  • title – Primary text of the notification.
  • body – Secondary text of the notification.
  • actionUrl – URL to be opened if the user clicks on the notification.
  • replaceId – A string which identifies a group of like messages. If the user is offline, only the last message with the same replaceId will be sent when the user comes back online.

title is the only required parameter.

The data can be posted as application/json or application/x-www-form-urlencoded.

Example request:

POST https://push.mozilla.org/queue/5116f9fd4/
Content-Type: application/x-www-form-urlencoded

title=message+one&body=hi

or

POST https://push.mozilla.org/queue/5116f9fd4/
Content-Type: application/json

{"title": "message one", "body": "hi"}

Client HTTP API

The client (e.g. Firefox) is responsible for managing push URLs, reading/streaming messages, and syncing device state.

POST /token/

Create a new authentication token. This token is used to identify the client in all other requests.

Example response:

{"token": "TOKEN",
 "queue": "https://push.mozilla.org/queue/TOKEN/"}

The token is a randomly generated string that should be stored and kept secret by the client. The queue is a URL where the client can check for new messages over HTTP.

POST /queue/

Create a new queue for the given token and domain.

POST params:
  • token – The client token created by POST /token/.
  • domain – The domain of the site creating the queue.

Example response:

{"queue": "https://push.mozilla.org/queue/QUEUE"}

The queue URL is given to the third-party site to send notifications to the user.

GET /queue/?token={token}

Get all of the user’s queues. This can be used for syncing state between clients.

Query params:token – The client token created by POST /token/.

Example response:

{"example.org": "https://push.mozilla.org/queue/QUEUE1",
 "micropipes.com": "https://push.mozilla.org/queue/QUEUE2"}

The object keys are domains and the values are push URLs.

DELETE /queue/{queue}/?token={token}

Delete a queue. The user will no longer receive messages from the site once this push URL is destroyed.

Query params:token – The client token created by POST /token/.
POST /queue/{queue}/?action=read&key={key}

Mark a message as read.

POST params:key – message key extracted from notification metadata.

This will only work on queues created in POST /token/, i.e. the queue directly tied to the user token.

GET /queue/{queue}/

Get all the stored messages for the queue.

Opt. params:since – Only return messages newer than this timestamp or message key. Should be formatted as seconds since epoch in GMT, or the hexadecimal message key.

Example response:

{"messages": [
    {
        "key": "4ae183428d8e11e1a007109add558619",
        "timestamp": "1335217807.899117",
        "queue": "https://push.mozilla.org/queue/5116f9fd48d3c792d0d93df93d889fa3bfada77f",
        "body": {
            "title": "message one",
            "body": "hi"
        }
    },
    {
        "key": "4ae417618d8e11e193d7109add558619",
        "timestamp": "1335217807.916016",
        "queue": "https://push.mozilla.org/queue/5116f9fd48d3c792d0d93df93d889fa3bfada77f",
        "body": {
            "title": "message two",
            "body": "hi"
        }
    },
]}
GET /nodes/

Get a list of WebSocket server IP:port addresses.

Example response:

{"nodes": ["63.245.217.105:8000",
           "63.245.217.105:9000",
           "63.245.217.106:8000"]

To make a WebSocket connection the client should attempt to connect to each address in the order provided.

Client WebSocket API

After connecting to one of the addresses given in GET /nodes/, the client must authenticate:

>>> token: TOKEN

Following authentication the client listens for messages published from the server.

New messages will come down the WebSocket in either the new message or read message format.

Message Formats

Messages are stored on the server and can be retrieved over HTTP or through a WebSocket connection. The format of a single message is the same over either protocol.

New Message

New messages coming from the server have the following format:

{
    "key": "4ae183428d8e11e1a007109add558619",
    "timestamp": "1335217807.899117"
    "queue": "https://push.mozilla.org/queue/5116f9fd48d3c792d0d93df93d889fa3bfada77f",
    "body": {
        "title": "message one",
        "body": "hi",
        "actionUrl": "http://example.com/action",
        "replaceId": "one"
    }
}

The outer layer describes metadata created by the server, with the actual notification inside the body element.

key
string identifier for the message
timestamp
message creation time formatted as seconds since epoch in GMT
queue
push URL that the message was sent to (POST /queue/{queue}/)
body
the message created in POST /queue/{queue}/

Read Message

When a client marks a notification as read a new message is pushed onto the user’s queue in this format:

{
    "key": "4b89c48a8d8e11e18db6109add558619",
    "queue": "https://push.mozilla.org/queue/5116f9fd48d3c792d0d93df93d889fa3bfada77f",
    "timestamp": "1335217809.001793",
    "body": {
        "read": "4ae183428d8e11e1a007109add558619"
    }
}

The outer layer is the same as the new message format.

The body differs in that it contains a single key read, with a value that points to the key of a previous message.

Project Versions

Table Of Contents

This Page