Bug 771980: provider must be re-usable, r=jaws

--HG--
extra : transplant_source : s%94%84%C2%7C%27%A3%B0%DB%5B%7F%40%96%A4S%21%FFcSA
This commit is contained in:
Gavin Sharp 2012-07-11 10:43:56 -07:00
parent 2c31655232
commit ed5fdc5f5a
7 changed files with 168 additions and 28 deletions

View File

@ -3621,3 +3621,5 @@ pref("memory.low_memory_notification_interval_ms", 10000);
// likely leak)? This should be longer than it usually takes for an eligible
// window to be collected via the GC/CC.
pref("memory.ghost_window_timeout_seconds", 60);
pref("social.enabled", false);

View File

@ -18,8 +18,9 @@ const EXPORTED_SYMBOLS = ["SocialProvider"];
*
* @constructor
* @param {jsobj} object representing the manifest file describing this provider
* @param {bool} whether the provider should be initially enabled (defaults to true)
*/
function SocialProvider(input) {
function SocialProvider(input, enabled) {
if (!input.name)
throw new Error("SocialProvider must be passed a name");
if (!input.origin)
@ -29,16 +30,53 @@ function SocialProvider(input) {
this.workerURL = input.workerURL;
this.origin = input.origin;
let workerAPIPort = this.getWorkerPort();
if (workerAPIPort)
this.workerAPI = new WorkerAPI(workerAPIPort);
// If enabled is |undefined|, default to true.
this._enabled = !(enabled == false);
if (this._enabled)
this._activate();
}
SocialProvider.prototype = {
/**
* Terminates the provider's FrameWorker, if it has one.
*/
terminate: function terminate() {
// Provider enabled/disabled state. Disabled providers do not have active
// connections to their FrameWorkers.
_enabled: true,
get enabled() {
return this._enabled;
},
set enabled(val) {
let enable = !!val;
if (enable == this._enabled)
return;
this._enabled = enable;
if (enable) {
this._activate();
} else {
this._terminate();
}
},
// Active port to the provider's FrameWorker. Null if the provider has no
// FrameWorker, or is disabled.
port: null,
// Reference to a workerAPI object for this provider. Null if the provider has
// no FrameWorker, or is disabled.
workerAPI: null,
// Internal helper methods
_activate: function _activate() {
// Initialize the workerAPI and its port first, so that its initialization
// occurs before any other messages are processed by other ports.
let workerAPIPort = this._getWorkerPort();
if (workerAPIPort)
this.workerAPI = new WorkerAPI(workerAPIPort);
this.port = this._getWorkerPort();
},
_terminate: function _terminate() {
if (this.workerURL) {
try {
getFrameWorkerHandle(this.workerURL, null).terminate();
@ -46,18 +84,20 @@ SocialProvider.prototype = {
Cu.reportError("SocialProvider FrameWorker termination failed: " + e);
}
}
this.port = null;
this.workerAPI = null;
},
/**
* Instantiates a FrameWorker for the provider if one doesn't exist, and
* returns a reference to a port to that FrameWorker.
* returns a reference to a new port to that FrameWorker.
*
* Returns null if this provider has no workerURL.
* Returns null if this provider has no workerURL, or is disabled.
*
* @param {DOMWindow} window (optional)
*/
getWorkerPort: function getWorkerPort(window) {
if (!this.workerURL)
_getWorkerPort: function _getWorkerPort(window) {
if (!this.workerURL || !this.enabled)
return null;
try {
return getFrameWorkerHandle(this.workerURL, window).port;

View File

@ -10,30 +10,68 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/SocialProvider.jsm");
const MANIFEST_PREFS = Services.prefs.getBranch("social.manifest.");
let SocialServiceInternal = {};
// Internal helper methods and state
let SocialServiceInternal = {
enabled: Services.prefs.getBoolPref("social.enabled"),
get providerArray() {
return [p for ([, p] of Iterator(this.providers))];
}
};
XPCOMUtils.defineLazyGetter(SocialServiceInternal, "providers", function () {
// Initialize the service (add a pref observer)
function prefObserver(subject, topic, data) {
SocialService._setEnabled(Services.prefs.getBoolPref(data));
}
Services.prefs.addObserver("social.enabled", prefObserver, false);
Services.obs.addObserver(function xpcomShutdown() {
Services.obs.removeObserver(xpcomShutdown, "xpcom-shutdown");
Services.prefs.removeObserver("social.enabled", prefObserver);
}, "xpcom-shutdown", false);
// Now retrieve the providers
let providers = {};
let MANIFEST_PREFS = Services.prefs.getBranch("social.manifest.");
let prefs = MANIFEST_PREFS.getChildList("", {});
prefs.forEach(function (pref) {
try {
var manifest = JSON.parse(MANIFEST_PREFS.getCharPref(pref));
if (manifest && typeof(manifest) == "object") {
let provider = new SocialProvider(manifest);
let provider = new SocialProvider(manifest, SocialServiceInternal.enabled);
providers[provider.origin] = provider;
}
} catch (err) {
Cu.reportError("SocialService: failed to load provider: " + pref +
", exception: " + err);
}
}, this);
});
return providers;
});
function schedule(callback) {
Services.tm.mainThread.dispatch(callback, Ci.nsIThread.DISPATCH_NORMAL);
}
// Public API
const SocialService = {
get enabled() {
return SocialServiceInternal.enabled;
},
set enabled(val) {
let enable = !!val;
if (enable == SocialServiceInternal.enabled)
return;
Services.prefs.setBoolPref("social.enabled", enable);
this._setEnabled(enable);
},
_setEnabled: function _setEnabled(enable) {
SocialServiceInternal.providerArray.forEach(function (p) p.enabled = enable);
SocialServiceInternal.enabled = enable;
},
// Returns a single provider object with the specified origin.
getProvider: function getProvider(origin, onDone) {
schedule((function () {
onDone(SocialServiceInternal.providers[origin] || null);
@ -42,13 +80,8 @@ const SocialService = {
// Returns an array of installed provider origins.
getProviderList: function getProviderList(onDone) {
let providers = [p for each (p in SocialServiceInternal.providers)];
schedule((function () {
onDone(providers);
}).bind(this));
schedule(function () {
onDone(SocialServiceInternal.providerArray);
});
}
};
function schedule(callback) {
Services.tm.mainThread.dispatch(callback, Ci.nsIThread.DISPATCH_NORMAL);
}

View File

@ -21,6 +21,7 @@ MOCHITEST_BROWSER_FILES = \
relative_import.js \
browser_workerAPI.js \
worker_social.js \
browser_SocialProvider.js \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,35 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
let SocialProvider = Components.utils.import("resource://gre/modules/SocialProvider.jsm", {}).SocialProvider;
function test() {
// This test creates a SocialProvider object directly - it would be nicer to
// go through the SocialService, but adding a test provider before the service
// has been initialized can be tricky.
let provider = new SocialProvider({
origin: 'http://example.com',
name: "Example Provider",
workerURL: "http://example.com/browser/toolkit/components/social/test/browser/worker_social.js"
});
ok(provider.enabled, "provider is initially enabled");
ok(provider.port, "should be able to get a port from enabled provider");
ok(provider.workerAPI, "should be able to get a workerAPI from enabled provider");
provider.enabled = false;
ok(!provider.enabled, "provider is now disabled");
ok(!provider.port, "shouldn't be able to get a port from disabled provider");
ok(!provider.workerAPI, "shouldn't be able to get a workerAPI from disabled provider");
provider.enabled = true;
ok(provider.enabled, "provider is re-enabled");
ok(provider.port, "should be able to get a port from re-enabled provider");
ok(provider.workerAPI, "should be able to get a workerAPI from re-enabled provider");
// Terminate the provider
provider.enabled = false;
}

View File

@ -19,14 +19,15 @@ function test() {
ok(provider.workerAPI, "provider has a workerAPI");
is(provider.workerAPI.initialized, false, "workerAPI is not yet initialized");
let port = provider.getWorkerPort();
let port = provider.port;
ok(port, "should be able to get a port from the provider");
port.onmessage = function onMessage(event) {
let {topic, data} = event.data;
if (topic == "test-initialization-complete") {
is(provider.workerAPI.initialized, true, "workerAPI is now initialized");
provider.terminate();
// Terminate the provider
provider.enabled = false;
finish();
}
}

View File

@ -2,6 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
Cu.import("resource://gre/modules/Services.jsm");
function run_test() {
let manifests = [
{ // normal provider
@ -18,14 +20,16 @@ function run_test() {
manifests.forEach(function (manifest) {
MANIFEST_PREFS.setCharPref(manifest.origin, JSON.stringify(manifest));
});
do_register_cleanup(function () MANIFEST_PREFS.deleteBranch(""));
// Enable the service for this test
Services.prefs.setBoolPref("social.enabled", true);
Cu.import("resource://gre/modules/SocialService.jsm");
let runner = new AsyncRunner();
let next = runner.next.bind(runner);
runner.appendIterator(testGetProvider(manifests, next));
runner.appendIterator(testGetProviderList(manifests, next));
runner.appendIterator(testEnabled(manifests, next));
runner.next();
}
@ -48,7 +52,31 @@ function testGetProviderList(manifests, next) {
let providerIdx = providers.map(function (p) p.origin).indexOf(manifests[i].origin);
let provider = providers[providerIdx];
do_check_true(!!provider);
do_check_true(provider.enabled);
do_check_eq(provider.workerURL, manifests[i].workerURL);
do_check_eq(provider.name, manifests[i].name);
}
}
function testEnabled(manifests, next) {
let providers = yield SocialService.getProviderList(next);
do_check_true(providers.length >= manifests.length);
do_check_true(SocialService.enabled);
providers.forEach(function (provider) {
do_check_true(provider.enabled);
});
SocialService.enabled = false;
do_check_true(!Services.prefs.getBoolPref("social.enabled"));
do_check_true(!SocialService.enabled);
providers.forEach(function (provider) {
do_check_true(!provider.enabled);
});
// Check that setting the pref directly updates things accordingly
Services.prefs.setBoolPref("social.enabled", true);
do_check_true(SocialService.enabled);
providers.forEach(function (provider) {
do_check_true(provider.enabled);
});
}