WebAPI/Inter App Communication

From MozillaWiki
Jump to: navigation, search

Description

Note: this proposal has a newer version at Inter App Communication API Alt Proposal and is currenly under implementation at Bug 876397.

An application wants to send or get information with another application. For example, some communications related applications (Skype, SMS, dialer) could send communication logs to a logging service that would then show the log of all communications to the user. Otherwise, an application might want to know which music is currently playing and get this information from a music player.

As for Web Activities, the idea is that an application will interact with another application. They will be put in relation through a keyword. Regarding semantic, the main difference with Web Activity is that the interaction is not about delegating an action but about communicating. There is no caller/handler relationship. The relationship is actually 1:n while Web Activity is limited to a 1:1 relationship. Regarding user interaction, the main difference with Web Activity is that the other application will not be shown to perform a task, the entire process will happen in the background.

This API is only there to create a bridge between two applications. The only intended UI is for security reasons, to select communication peers.

TODO

  • Use system messages for port messaging?
  • Do we really need Future for all the methods?
  • Should we use a Connection object that contains a MessagePort and an origin so both sides can filter with origin?
  • Dynamic registration?
  • Should we fire an event on the other port when a port call .close()?

API

Caller

 partial interface Application {
   // The returned Future will contain an array of MessagePort, each of
   // them representing an peer that allowed the connection.
   Promise connect(DOMString keyword);
 
   // The returned Future will contain true if at least a peer has been
   // selected, false otherwise.
   Promise registerConnections(DOMString keyword);
 
   void   unregisterConnections(DOMString keyword);
 
   // The returned Future will contain true if at least a peer is allowed
   // to communicate with the application, false otherwise.
   Promise connectionsRegistered(DOMString keyword);
 };

Receiver

Registration

An entry should be used in the manifest file to register as able to connect with another app requesting it. This entry should be named connect and each keywords should be used in an array:

 {
   'name': 'Foobar application',
   /* ... */
   'connect': [ 'keyword1', 'keyword2' ]
 }

Connection acknowledgement

System messages named 'connect' fired when a connection request is received. The system message contains a ConnectionRequest object as a message.

 Dictionary ConnectionRequest {
   MessagePort accept();
   DOMString   keyword;
   DOMString   origin;
 };

Usage

Setup a connection

First, the caller needs to ask the user to select peers he/she wants the app to communicate with. The list of applications being shown depends on the applications that advertises themselves as able to 'connect' with the given keyword:

 registerConnections('foobar').then(function(result) {
   result ? alert ('peer(s) selected') : alert('no peer selected');
 });

Then, the connect method has to be called. The returned Future will contain an array of MessagePort. Each of them will allow to communicate with a peer.

 connect('foobar').then(function(ports) {
   ports.forEach(function(port) {
     port.onmessage = function(e) { alert(e.data); };
     port.start();
     port.postMessage({ msg: 'hi!'});
   });
 });

Accept a connection request

Only applications that have been previously selected by the user (when registerConnections is called) will get a connection request. Those applications will still be able to reject or accept the connection request. Accepting the connection has to be done explicitly by the receiver by calling accept() on the received object. Not calling accept() will implicitly reject the connection request.

 var port = null;
 navigator.setMessageHandler('connect', function(request) {
   if (request.origin != 'http://foobar.com') {
     return;
   }
   port = request.accept();
   port.onmessage = function(e) { alert(e.data); };
   port.start();
 });

Disconnect

Calling close() on a port from either side will stop the connection.

 port.close();

Similar work

Google Message Passing: https://developer.chrome.com/extensions/messaging.html