WebAPI/SimplePush: Difference between revisions

From MozillaWiki
Jump to navigation Jump to search
(Undo revision 510223 by Jrconlin (talk))
Line 20: Line 20:
;Endpoint
;Endpoint
:Unique URL to be used by the AppServer to initiate a response from the App.<br />This is generated by SimplePush and sent to the App. The App will need to relay this to the AppServer.
:Unique URL to be used by the AppServer to initiate a response from the App.<br />This is generated by SimplePush and sent to the App. The App will need to relay this to the AppServer.


The following are SimplePush hoo-doo things that are probably not important to you. Here, look at this device while I put on my sunglasses.
The following are SimplePush hoo-doo things that are probably not important to you. Here, look at this device while I put on my sunglasses.
Line 37: Line 38:
== Use Cases ==
== Use Cases ==


<p>You're a service. Getting clients to talk to you is pretty easy. All you have to do is sit there and wait for them to call. But, what if you want to tell your clients that there's something interesting for them?
== Messy Details ==
</p><p>SimplePush is a very low cost service that let's servers tell clients "Hey, there's something interesting over here! You ought to do something about that."
</p>
<h2> Definitions </h2>
<p>Before we get into details, it's important that we have a good lexicon.
</p>
<dl><dt>App
</dt><dd>The remote receiver of the SimplePush Notification.<br />The app is what requests things get established, gets pinged when something interesting happens, and connects back to the AppServer.
</dd></dl>
<dl><dt>AppServer
</dt><dd>The third party publisher of update notices.<br />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 dessert.
</dd></dl>
<dl><dt>UserAgent
</dt><dd>The client acting on behalf of the user and consumer of update notices<br />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)
</dd></dl>
<dl><dt>PushServer
</dt><dd>The server managing interactions between AppServers and the UserAgent.<br />This is what the AppServer is talking to when it wants to tickle the client.
</dd></dl>
<dl><dt>Endpoint
</dt><dd>Unique URL to be used by the AppServer to initiate a response from the App.<br />This is generated by SimplePush and sent to the App. The App will need to relay this to the AppServer.
</dd></dl>
<p>The following are SimplePush hoo-doo things that are probably not important to you. Here, look at this device while I put on my sunglasses.
</p>
<dl><dt>Channel
</dt><dd>The flow of information from AppServer through PushServer to UserAgent.
</dd></dl>
<dl><dt>ChannelID
</dt><dd>Unique identifier for a Channel. Generated by UserAgent for a particular application.
</dd></dl>
<dl><dt>UAID
</dt><dd>A globally unique UserAgent ID
</dd></dl>
<p><br />
UserAgent and AppServer will use a RESTful API to interact with the Push Server.
</p>
<h2> Use Cases </h2>
<h2> Messy Details </h2>
<h3> Client Side API </h3>
<pre>
 
partial interface Navigator {
  PushNotification pushNotification;
};
 
interface PushNotification {


  // registers to receive push notifications for a given topic
=== Client Side API ===
  // DOMRequest.result is a PushRegistration in case of success
  DOMRequest register();


  // registers to stop receiving push notifications for a given topic
Apps will need to add the following to their manifests. See our Web App Development Guide for what this means and how to use it.
  // DOMRequest.result is a PushRegistration in case of success
==== App manifest ====
  DOMRequest unregister(DOMString pushEndpoint);
{
  ...
  "messages": [
    {"push": "/view_to_launch.html"}
    {"push-register": "/view_to_launch.html"}
  ]
}
==== JavaScript ====
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.


  // returns the list of all push registrations for this origin
var emailEndpoint, imEndpoint;
  PushRegistration[] registrations();
};
function setupAppRegistrations() {
 
   <i>// Issue a register() call
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 PushEvent
  DOMString version;
};
 
interface PushEvent&#160;: Event {
  PushRegistration target;
}
 
</pre>
<h3> Client Example </h3>
<h4> App manifest </h4>
<pre>
 
{
  ...
  &quot;messages&quot;: [
    {&quot;push&quot;: &quot;/view_to_launch.html&quot;}
    {&quot;push-register&quot;: &quot;/view_to_launch.html&quot;}
  ]
}
 
</pre>
<h4> JavaScript </h4>
<pre>
 
var emailEndpoint, imEndpoint;
 
function setupAppRegistrations() {
   // (re)issue register() calls
   // to register to listen for a notification,
   // to register to listen for a notification,
   // you simply call push.register
   // you simply call push.register
  // Here, we'll register a channel for "email" updates. Channels can be for anything the app would like.</i>
   var reqEmail = navigator.pushNotifications.register();
   var reqEmail = navigator.pushNotifications.register();
   reqEmail.onsuccess = function(e) {
   reqEmail.onsuccess = function(e) {
     emailEndpoint = e.result.pushEndpoint;
     emailEndpoint = e.result.pushEndpoint;
     storeOnAppServer(&quot;email&quot;, emailEndpoint);
     storeOnAppServer("email", emailEndpoint); <i>// This is the "Hand wavey" way that the app
                                                // sends the endPoint back to the server</i>
   }
   }
 
  <i>// We'll also register a second channel for "im", because we're social and all about the socialists. Or something.</i>
   var reqIm = navigator.pushNotifications.register();
   var reqIm = navigator.pushNotifications.register();
   reqIm.onsuccess = function(e) {
   reqIm.onsuccess = function(e) {
     imEndpoint = e.result.pushEndpoint;
     imEndpoint = e.result.pushEndpoint;
     storeOnAppServer(&quot;im&quot;, imEndpoint);
     storeOnAppServer("im", imEndpoint);
   }
   }
}
}
<i>// 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.</i>
navigator.mozSetMessageHandler('push', {
  handleMessage: function(e) {
    if (e.target.pushEndpoint == emailEndpoint)  <i>// Yay! New Email! Steve and blue can dance!</i>
      getNewEmailMessagesFromAppServer(e.target.version);
    else if (e.target.pushEndpoint == imEndpoint) <i>// Yay! An IM awaits. I wonder if it's Sam's IM?</i>
      getNewChatMessagesFromAppServer(e.target.version);
  }
});
<i>// The user has logged in, now's a good time to register the channels</i>
AppFramework.addEventListener('user-login', function() {
  setupAppRegistrations();
});
<i>// to unregister, you simply call..</i>
AppFramework.addEventListener('user-logout', function() {
  navigator.pushNotifications.unregister(emailEndpoint);
  navigator.pushNotifications.unregister(imEndpoint);
});
<i>// error recovery mechanism
// will be called very rarely, but application
// should register again when it is called</i>
navigator.mozSetMessageHandler('push-register', {
  handleMessage: function(e) {
    if (AppFramework.isUserLoggedIn) {
      setupAppRegistrations();
    }
    else {
      <i>// since user isn't logged in, when he logs in
      // registrations will be setup due to event handler</i>
    }
  }
});
 
==== Interface ====
partial interface Navigator {
  PushNotification pushNotification;
};
interface PushNotification {
  <i>// registers to receive push notifications for a given topic
  // DOMRequest.result is a PushRegistration in case of success</i>
  DOMRequest register();
  <i>// registers to stop receiving push notifications for a given topic
  // DOMRequest.result is a PushRegistration in case of success</i>
  DOMRequest unregister(DOMString pushEndpoint);
  <i>// returns the list of all push registrations for this origin</i>
  PushRegistration[] registrations();
};
interface PushRegistration {
  <i>// 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.</i>
  DOMString pushEndpoint;
  <i>// undefined when obtained from register().onsuccess.
  // contains version when obtained from PushEvent</i>
  DOMString version;
};
interface PushEvent : Event {
  PushRegistration target;
}
 
==== 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.


// all notifications will be sent to the system message handler.
==== UI ====
// which is up to the U/A to implement
* During app installation, the user agent should notify the user that the app uses push notifications, and possibly deny permission.
navigator.mozSetMessageHandler('push', {
* Web pages using push notification should show a doorhangar notification in the same way (look at geolocation to see how this is done).
  handleMessage: function(e) {
 
    if (e.target.pushEndpoint == emailEndpoint)
=== Server API ===
      getNewEmailMessagesFromAppServer(e.target.version);
[[/ServerAPI|ServerAPI]] has the details of how the ServerAPI works.  
    else if (e.target.pushEndpoint == imEndpoint)
      getNewChatMessagesFromAppServer(e.target.version);
  }
});


AppFramework.addEventListener('user-login', function() {
Chances are, all you want is to send a new version update.
  setupAppRegistrations();
});


// to unregister, you simply call..
The simplest way to do that is to call
AppFramework.addEventListener('user-logout', function() {
  navigator.pushNotifications.unregister(emailEndpoint);
  navigator.pushNotifications.unregister(imEndpoint);
});


// error recovery mechanism
POST <i>endpoint</i>
// will be called very rarely, but application
version=<i>newversion</i>
// should register again when it is called
navigator.mozSetMessageHandler('push-register', {
  handleMessage: 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
    }
  }
});


</pre>
Where <i>endpoint</i> is the value that was returned during App's registration.
<h4> Notes </h4>
<p>The current spec works for apps. Ideally it should work for web pages loaded in browsers as well.
Current issues blocking this:
</p>
<ul><li> mozSetMessageHandler indexes by app manifest. Web pages don't have app manifests.
</li><li> The lifetime of registrations for web pages needs specification.
</li><li> 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)
</li><li> 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.
</li></ul>
<h4> UI </h4>
<ul><li> During app installation, the user agent should notify the user that the app uses push notifications, and possibly deny permission.
</li><li> Web pages using push notification should show a doorhangar notification in the same way (look at geolocation to see how this is done).
</li></ul>
<h3> Server API </h3>
<p><a href="/ServerAPI">ServerAPI</a> has the details of how the ServerAPI works.
</p><p>Chances are, all you want is to send a new version update.
</p><p>The simplest way to do that is to call
</p>
<pre class="_fck_mw_lspace">POST <i>endpoint</i>
version=<i>newversion</i>
</pre>
<p>Where <i>endpoint</i> is the value that was returned during App's registration.
</p>

Revision as of 18:45, 31 January 2013

You're a service. Getting clients to talk to you is pretty easy. All you have to do is sit there and wait for them to call. But, what if you want to tell your clients that there's something interesting for them?

SimplePush is a very low cost service that let's servers tell clients "Hey, there's something interesting over here! You ought to do something about that."

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, 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 dessert.
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.
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.


The following are SimplePush hoo-doo things that are probably not important to you. Here, look at this device while I put on my sunglasses.

Channel
The flow of information from AppServer through PushServer to UserAgent.
ChannelID
Unique identifier for a Channel. Generated by UserAgent for a particular application.
UAID
A globally unique UserAgent ID


UserAgent and AppServer will use a RESTful API to interact with the Push Server.

Use Cases

Messy Details

Client Side API

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

App manifest

{
  ...
  "messages": [
    {"push": "/view_to_launch.html"}
    {"push-register": "/view_to_launch.html"}
  ]
} 

JavaScript

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.

var emailEndpoint, imEndpoint;

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.
 var reqEmail = navigator.pushNotifications.register();
 reqEmail.onsuccess = function(e) {
   emailEndpoint = e.result.pushEndpoint;
   storeOnAppServer("email", emailEndpoint); // This is the "Hand wavey" way that the app 
                                                // sends the endPoint back to the server
 }

 // We'll also register a second channel for "im", because we're social and all about the socialists. Or something.
 var reqIm = navigator.pushNotifications.register();
 reqIm.onsuccess = function(e) {
   imEndpoint = e.result.pushEndpoint;
   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', {
  handleMessage: function(e) {
    if (e.target.pushEndpoint == emailEndpoint)   // Yay! New Email! Steve and blue can dance!
      getNewEmailMessagesFromAppServer(e.target.version);
    else if (e.target.pushEndpoint == imEndpoint) // Yay! An IM awaits. I wonder if it's Sam's IM?
      getNewChatMessagesFromAppServer(e.target.version);
  }
});

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

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

// error recovery mechanism
// will be called very rarely, but application
// should register again when it is called
navigator.mozSetMessageHandler('push-register', {
  handleMessage: 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
    }
  }
});

Interface

partial interface Navigator {
  PushNotification pushNotification;
};

interface PushNotification { 

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

  // registers to stop receiving push notifications for a given topic 
  // DOMRequest.result is a PushRegistration in case of success
  DOMRequest unregister(DOMString pushEndpoint);

  // returns the list of all push registrations for this origin
  PushRegistration[] 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 PushEvent
  DOMString version;
};

interface PushEvent : Event {
  PushRegistration target;
}

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).

Server API

ServerAPI has the details of how the ServerAPI works.

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.