Electrolysis/Jetpack: Difference between revisions

Jump to navigation Jump to search
New implementation proposal
(added link to MDC page on multi-process jetpack)
(New implementation proposal)
Line 1: Line 1:
In order to move [[Labs/Jetpack|Jetpack]] to an out-of-process implementation, a mixture of [[Electrolysis/CPOW|CPOWs]] and proxying appears to be necessary.  I've encountered one main issue that must be considered:
In order to move [[Labs/Jetpack|Jetpack]] to an out-of-process implementation, a mixture of [[Electrolysis/CPOW|CPOWs]] and proxying appears to be necessary.   
 
== Three contexts ==
 
When a Jetpack is implemented in a separate process, there will be at least three kinds of JS execution contexts:
 
=== Jetpack context ===
 
The jetpack JS itself will run in the content process.
 
Predefined globals:
* require()
 
=== implementation-jetpack context ===
 
Part of the jetpack implementation runs in the jetpack process. It uses COW-type wrappers to expose functions and properties to the jetpack context. It also has some core functions which allow it to send synchronous or asynchronous messages to the browser process.
 
Predefined globals:
* jetpack // the jetpack context global, used to create jetpack.require
* sendMessage("messageName" [, data]); // sends asynchronously, no return value
* callMessage("messageName" [, data]); // sends synchronously, has return value
* createHandle(object[, parentHandle]); // returns handle object
* other special globals as necessary, e.g. ctypes would be exposed entirely within the jetpack process and wouldn't need to communicate with chrome
* registerReceiver(messageName, func) // incoming messages of the specified name
* wrap(object) // create a COW
 
=== implementation-chrome context ===
 
The rest of the jetpack implementation would live in the chrome process, primarily in a JS module. A method would exist (via XPCOM?) to bootstrap a jetpack:
 
var ajetpack = createJetpackProcess();
 
* ajetpack.sendMessage("messageName" [, data]); // only async messages are allowed
* ajetpack.createHandle(object [, parentHandle]);
* ajetpack.loadImplementation(uri); // load a script into the jetpack implementation context
* ajetpack.loadUserScript(uri); // load a script into the jetpack context
* ajetpack.registerReceiver(messageName, func)
 
=== Messages and Handles ===
 
Messages that communicate between the browser and jetpack process may contain only serializable (JSON) data and "handles". A handle can be used to provide context for messages. Either the browser or the jetpack implementation may create a handle. A handle keeps its associated JS object alive, and has the following properties:
 
* handle.object // the JS object associated with the handle
* handle.parent // the parent handle of the object, if any
* handle.destroy() // destroy the handle so that is is no longer valid
* handle.isValid // boolean, is this handle still valid?
 
A handle that is created without a parent stays alive until it is explicitly destroyed.
 
When a handle is created, a "parent handle" may be specified: a handle becomes invalid when its parent is destroyed. This is useful for associating handles to the lifetime of a particular window, context menu, or other element, and helping ensure that they do not leak.
 
Either process may destroy a handle when it is no longer useful. For each handle type jetpack uses, the jetpack implementation should decide which side of the conversation is typically responsible for destroying a handle.
 
=== Example ===
 
This is a barebones example of how [[Labs/Jetpack/Reboot/JEP/109|JEP 109]], the request module, could be implemented:
 
Jetpack:
<pre>const Request = require("request").Request;
new Request({
url:      "http://example.com/",
onComplete: function() console.log(this.response.text)
}).get();</pre>
 
implementation-jetpack:
<pre>function jp_request(r)
{
  this._onComplete = r.onComplete;
  // ... set up the rest of this._stuff
}
jp_request.prototype = {
  __exposedProps__ = {'__call__': 'r', 'get': 'r', 'response': 'r'},
 
  get: function() {
    // create a cross-process handle for messsages relating to this request
    this._handle = createHandle(this);
    // send the browser a message to kick things off
    sendMessage("request_get", {url: this._url, handle: this._handle});
  },
 
  _handleResponse: function(data) {
    // Firefox just sent us data. Save it in this.response and then...
    this._onComplete();
  },
};
registerReceiver("request_done", function(data) {
  data.handle.object._handleResponse(data);
});
 
// Now hook up jetpack.require
jetpack.require = function(package) {
  switch (package) {
  "request":
    return { Request: jp_request };
  }
};</pre>
 
implementation-chrome:
<pre>var ajetpack = createJetpackProcess();
 
ajetpack.registerReceiver("request_get", function(data) {
  // perhaps do some kind of domain validation here based on jetpack metadata?
  var r = new XMLHttpRequest(data.uri, ...);
  r.addEventListener("load", function() {
    ajetpack.sendMessage("request_done", {
    responseText: r.responseText,
    handle: data.handle,
    });
  });
});
 
ajetpack.loadImplementation("chrome://jetpack/content/jetpack-implementation.js");
ajetpack.loadUserScript("resource://jetpack-repository/myjetpack.js");
</pre>
 
== Older Notes ==
 
<div class="note">The following content is older notes from jdm that may no longer be relevant.</div>
 
I've encountered one main issue that must be considered:


<h3>Using callbacks</h3>
<h3>Using callbacks</h3>
Confirmed users, Bureaucrats and Sysops emeriti
1,217

edits

Navigation menu