Personal tools

WebAPI/SimplePush

From MozillaWiki

Jump to: navigation, search

SimplePush is a way for application developers to send messages to their web applications. Rather than have applications continuously poll your server for the latest information, you can take advantage of the SimplePush API. This is a very low cost service that lets servers tell clients "Hey, there's something interesting over here! You ought to do something about that."

A quick presentation about SimplePush. And if you're looking, the WebAPI page.

Contents

Definitions

Before we get into details, it's important that we have a good lexicon.

App
The remote receiver of the SimplePush Notification.
The app is what requests things get established, gets pinged when something interesting happens, and connects back to the AppServer.
AppServer
The third party publisher of update notices.
This is your application (mail/chat/calendar) server. This is, more than likely, where all the real work of your App is done. It's what has the mail, or the articles, or where someone whacks serpents with farm implements for slices of virtual desert.
UserAgent
The client acting on behalf of the user and consumer of update notices
This is what handles talking back to the PushServer and wakes up the App when there's something of interest. For example: Firefox Desktop, Firefox OS (a service runs in the background)
PushServer
The server managing interactions between AppServers and the UserAgent.
This is what the AppServer is talking to when it wants to tickle the client. This is managed by a third party, and you, the app developer, don't worry about it.
Endpoint
Unique URL to be used by the AppServer to initiate a response from the App.
This is generated by SimplePush and sent to the App. The App will need to relay this to the AppServer.
version

SimplePush does not carry information, only versions. A version is a number that keeps increasing. The AppServer tells the Endpoint about a new version whenever it wants an App to be notified.

Use Cases

An App wishes to be notified when new email arrives. A User installs an App on a mobile device which notifies her when someone adds a note to her bulletin board. The App calls the Registration function, which returns an EndPoint. The App sends the EndPoint to the AppServer using some mechanism not dictated by the protocol. For example, it could use XMLHttpRequest or send an SMS to a special number. The AppServer stores the EndPoint in the User's information. When a new note is added, the AppServer fetches the EndPoint and PUTs a new version value to it. The PushServer then notifies the UserAgent, which wakes the App and sends a "push" event. This causes the App to refresh its messages (again using XHR or some other medium out of the scope of this protocol), and User gets a screen full of adorable kittens.

An AppServer wishes to notify Apps of an update. Since a server doesn't want to be deluged by millions of pings from devices every hour, the developers wisely decide to opt for a Push mechanism. Much like the other example, an App registers with SimplePush, gets an EndPoint which it relays to AppServer. AppServer then PUTs a '0' version to the EndPoint which triggers a "push" event for the App, which silently acknowledges that all is well. At some later time, AppServer PUTs '1' to the EndPoint which SimplePush relays to App which then updates itself.

An incoming request from a WebRTC . Bob uses Ringo’s STAR webrtc service. Bob is using the Desktop browser, but the tab/window isn't open to the Ringo service. Alice makes a webrtc call from work to Bob. Bob sees a notification about an incoming call.

Additional potential scenarios to consider

Bob is on his mobile device at his San Jose home using his Wifi connection to monitor an auction at eBay. As the auction progresses, he is alerted every time he his outbid. The work day approaches and he boards CalTrain north to his office in San Francisco. This causes him to switch to a carrier provided connection. While on the train, he continues to receive updates as bidding becomes more contended. He passes through several counties, multiple grids, at least two "Dead Zones" (where signal is completely unavailable) and has his device IP reassigned more than once. Upon reaching San Francisco he switches over to his corporate network and continues to receive bidding announcements until finally, his Baby Monkey Hatching Out of an Egg sculpture is his.

Kenji works at a powerplant located on the Eastern Shore of an island country. He has set up a service that sends him alerts when the wave levels have increased above a certain threshold. His vacation home is located in a section of town supported by only two cell towers, and is constructed using Stucco walls and a steel roof, which greatly impedes the level of signal that he can receive. His phone may be 4G in his living room, but step down to 3g in the hallway, and only 1x in his office. It's rather important that he receive the alerts indicating that wave levels have begun increasing.

Alice is traveling from Brazil to America. An unexpected storm delays her connections forcing her to overnight in a location with no network or cell access. When she lands, she turns on her phone and connects to the first available network that provides data. Unfortunately, this network routes traffic to an authorization server until she agrees to the network terms, then provides minimal connection capacities. While connecting back to her home server, the connection is proxied and limited to only well known TCP ports, slow and routinely drops providing only partial results to the client.

For App developers

SimplePush WebAPI document

Client (WebApp) code

Apps will need to add the following to their manifest. See our Web App Development Guide for what this means and how to use it.

{
  "permissions": {
    "push": {"description": "To receive notifications about the newest phone releases"}
  },
  "messages": [
    {"push": "/view_to_launch.html"},
    {"push-register": "/view_to_launch.html"}
  ]
}

Websites are likely to present a doorhanger to the user the first time they attempt to use the push notification API. The user experience on Firefox Desktop has not been drawn out yet.

We've tried to make the client code as simple as possible. While the following may not be what you use, it shows the general idea. This code will be in view_to_launch.html.

var emailEndpoint, imEndpoint;

// The user has logged in, now's a good time to register the channels
MyAppFramework.addEventListener('user-login', function() {
  setupAppRegistrations();
});

function setupAppRegistrations() {
 // Issue a register() call
 // to register to listen for a notification,
 // you simply call push.register
 // Here, we'll register a channel for "email" updates.
 // Channels can be for anything the app would like to get notifications for.
 var reqEmail = navigator.push.register();
 reqEmail.onsuccess = function(e) {
   emailEndpoint = e.target.result;
   storeOnAppServer("email", emailEndpoint); // This is the "Hand wavey" way that the App 
                                                // sends the endPoint back to the AppServer
 }

 // We'll also register a second channel for "im", because we're social and all about the socialists. Or something.
 var reqIm = navigator.push.register();
 reqIm.onsuccess = function(e) {
   imEndpoint = e.target.result;
   storeOnAppServer("im", imEndpoint);
 }
}

// Once we've registered, the AppServer can send version pings to the EndPoint.
// This will trigger a 'push' message to be sent to this handler.
navigator.mozSetMessageHandler('push', function(message) {
    if (message.pushEndpoint == emailEndpoint)   // Yay! New Email! Steve and blue can dance!
      getNewEmailMessagesFromAppServer(message.version);
    else if (message.pushEndpoint == imEndpoint) // Yay! An IM awaits. I wonder if it's Sam's IM?
      getNewChatMessagesFromAppServer();
  });

// to unregister, you simply call..
AppFramework.addEventListener('user-logout', function() {
  navigator.push.unregister(emailEndpoint);
  navigator.push.unregister(imEndpoint);
});

// error recovery mechanism
// will be called very rarely, but application
// should register again when it is called
navigator.mozSetMessageHandler('push-register', function(e) {
    if (AppFramework.isUserLoggedIn) {
      setupAppRegistrations();
    }
    else {
      // since user isn't logged in, when he logs in
      // registrations will be setup due to event handler
    }
  });

On the AppServer

When the application server makes some change to its state, which it feels is important to a certain user, it should use the associated Endpoint to notify the PushServer. For example, when an email server receives a new email whose recipients have MyAmazingEmailApp installed on their devices, every user will have an associated Endpoint. So the server should send a PUT request to every one of those endpoints, with 'version=<version>' in the body of the HTTP request (that is, as form data). Here is a curl example:

 curl -X PUT --data 'version=5' 'http://mypushserver.com/notificaton/forUserBob'

where 'http://mypushserver.com/notification/forUserBob' is the Endpoint sent by the App.

IMPORTANT NOTE: It is very likely that users will install their apps on multiple devices. In this case, each installation of the app has a different Endpoint. You should design your server side storage so that each piece of information may have multiple Endpoints to be notified when it changes. For example, Bob may have MyAmazingEmailApp installed on his Firefox OS phone, he may run it on Firefox for Android and also in his car entertainment system (in some future). In that case, on a new email to Bob, the AppServer should PUT to 3 different endpoints.

 curl -X PUT --data 'version=5' 'http://mypushserver.com/notificaton/forUserBobFirefoxOSDevice'
 curl -X PUT --data 'version=5' 'http://mypushserver.com/notificaton/forUserBobAndroidFirefox'
 curl -X PUT --data 'version=5' 'http://mypushserver.com/notificaton/forUserBobBMWBoombox'

How you associate endpoints to a given user is out of scope for this. You could have your own UserID that you use to map endpoints. Your client app could send both the old and new endpoints for an update, and you swap them in your data store.

DOM Interface

partial interface Navigator {
  PushNotification pushNotification;
};

interface PushManager { 

  // registers to receive push notifications for a given topic
  // DOMRequest.result is a string URL (the endpoint) in case of success
  DOMRequest register();

  // registers to stop receiving push notifications for a given topic 
  // DOMRequest.result is a string URL (the endpoint) on success.
  DOMRequest unregister(DOMString pushEndpoint);

  // the list of all push registrations for this app
  // DOMRequest.result is an Array of PushRegistration
  DOMRequest registrations();
};

interface PushRegistration {
  // this is the URL to which push notifications from the AppServer
  // must be sent to.
  // This is how the AppServer alerts the UserAgent that new data exists.
  DOMString pushEndpoint;

  // undefined when obtained from register().onsuccess
  // contains version when obtained from mozSetMessageHandler or registrations().onsuccess
  DOMString version;
};

Notes

The current spec works for apps. Ideally it should work for web pages loaded in browsers as well. Current issues blocking this:

  • mozSetMessageHandler indexes by app manifest. Web pages don't have app manifests.
  • The lifetime of registrations for web pages needs specification.
  • Every instance of a web page should be treated differently. So the same URL in two tabs should have different channels (and ask permission?). Again geolocation, desktop-notification and others may provide clues)
  • In the case of the b2g browser, the browser is an app and so mozSetMessageHandler gets its manifest, and not access to the pages. We might want to bypass the browser and plug directly into the mozbrowseriframe of each tab. Again within each tab, user might navigate away from page, which may need invalidation.

UI

  • During app installation, the user agent should notify the user that the app uses push notifications, and possibly deny permission.
  • Web pages using push notification should show a doorhangar notification in the same way (look at geolocation to see how this is done).

Protocol

Protocol has the details of how the UserAgent and PushServer communicate.

Chances are, all you want is to send a new version update.

The simplest way to do that is to call

POST endpoint
version=newversion

Where endpoint is the value that was returned during App's registration.

Unified Push Integration

For folks interested in using Java, Aerogear has graciously incorporated SimplePush into their Unified Push Server.

In addition, Matthias Wessendorf has provided a quick hack showing how to call the server by hand.

In addition, Sebastian Blanc provides a handy video showing how to send messages to mobile devices and a Raspberry Pi using SimplePush.

Meetings

Meetings Notes