diff options
Diffstat (limited to 'toolkit/components/contentprefs/ContentPrefServiceChild.jsm')
-rw-r--r-- | toolkit/components/contentprefs/ContentPrefServiceChild.jsm | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/toolkit/components/contentprefs/ContentPrefServiceChild.jsm b/toolkit/components/contentprefs/ContentPrefServiceChild.jsm new file mode 100644 index 000000000..7faca8970 --- /dev/null +++ b/toolkit/components/contentprefs/ContentPrefServiceChild.jsm @@ -0,0 +1,182 @@ +/* vim: set ts=2 sw=2 sts=2 et tw=80: */ +/* 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/. */ + +"use strict"; + +this.EXPORTED_SYMBOLS = [ "ContentPrefServiceChild" ]; + +const Ci = Components.interfaces; +const Cc = Components.classes; +const Cu = Components.utils; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/ContentPrefUtils.jsm"); +Cu.import("resource://gre/modules/ContentPrefStore.jsm"); + +// We only need one bit of information out of the context. +function contextArg(context) { + return (context && context.usePrivateBrowsing) ? + { usePrivateBrowsing: true } : + null; +} + +function NYI() { + throw new Error("Do not add any new users of these functions"); +} + +function CallbackCaller(callback) { + this._callback = callback; +} + +CallbackCaller.prototype = { + handleResult: function(contentPref) { + cbHandleResult(this._callback, + new ContentPref(contentPref.domain, + contentPref.name, + contentPref.value)); + }, + + handleError: function(result) { + cbHandleError(this._callback, result); + }, + + handleCompletion: function(reason) { + cbHandleCompletion(this._callback, reason); + }, +}; + +var ContentPrefServiceChild = { + QueryInterface: XPCOMUtils.generateQI([ Ci.nsIContentPrefService2 ]), + + // Map from pref name -> set of observers + _observers: new Map(), + + _mm: Cc["@mozilla.org/childprocessmessagemanager;1"] + .getService(Ci.nsIMessageSender), + + _getRandomId: function() { + return Cc["@mozilla.org/uuid-generator;1"] + .getService(Ci.nsIUUIDGenerator).generateUUID().toString(); + }, + + // Map from random ID string -> CallbackCaller, per request + _requests: new Map(), + + init: function() { + this._mm.addMessageListener("ContentPrefs:HandleResult", this); + this._mm.addMessageListener("ContentPrefs:HandleError", this); + this._mm.addMessageListener("ContentPrefs:HandleCompletion", this); + }, + + receiveMessage: function(msg) { + let data = msg.data; + let callback; + switch (msg.name) { + case "ContentPrefs:HandleResult": + callback = this._requests.get(data.requestId); + callback.handleResult(data.contentPref); + break; + + case "ContentPrefs:HandleError": + callback = this._requests.get(data.requestId); + callback.handleError(data.error); + break; + + case "ContentPrefs:HandleCompletion": + callback = this._requests.get(data.requestId); + this._requests.delete(data.requestId); + callback.handleCompletion(data.reason); + break; + + case "ContentPrefs:NotifyObservers": { + let observerList = this._observers.get(data.name); + if (!observerList) + break; + + for (let observer of observerList) { + safeCallback(observer, data.callback, data.args); + } + + break; + } + } + }, + + _callFunction: function(call, args, callback) { + let requestId = this._getRandomId(); + let data = { call: call, args: args, requestId: requestId }; + + this._mm.sendAsyncMessage("ContentPrefs:FunctionCall", data); + + this._requests.set(requestId, new CallbackCaller(callback)); + }, + + getCachedByDomainAndName: NYI, + getCachedBySubdomainAndName: NYI, + getCachedGlobal: NYI, + + addObserverForName: function(name, observer) { + let set = this._observers.get(name); + if (!set) { + set = new Set(); + if (this._observers.size === 0) { + // This is the first observer of any kind. Start listening for changes. + this._mm.addMessageListener("ContentPrefs:NotifyObservers", this); + } + + // This is the first observer for this name. Start listening for changes + // to it. + this._mm.sendAsyncMessage("ContentPrefs:AddObserverForName", { name: name }); + this._observers.set(name, set); + } + + set.add(observer); + }, + + removeObserverForName: function(name, observer) { + let set = this._observers.get(name); + if (!set) + return; + + set.delete(observer); + if (set.size === 0) { + // This was the last observer for this name. Stop listening for changes. + this._mm.sendAsyncMessage("ContentPrefs:RemoveObserverForName", { name: name }); + + this._observers.delete(name); + if (this._observers.size === 0) { + // This was the last observer for this process. Stop listing for all + // changes. + this._mm.removeMessageListener("ContentPrefs:NotifyObservers", this); + } + } + }, + + extractDomain: NYI +}; + +function forwardMethodToParent(method, signature, ...args) { + // Ignore superfluous arguments + args = args.slice(0, signature.length); + + // Process context argument for forwarding + let contextIndex = signature.indexOf("context"); + if (contextIndex > -1) { + args[contextIndex] = contextArg(args[contextIndex]); + } + // Take out the callback argument, if present. + let callbackIndex = signature.indexOf("callback"); + let callback = null; + if (callbackIndex > -1 && args.length > callbackIndex) { + callback = args.splice(callbackIndex, 1)[0]; + } + this._callFunction(method, args, callback); +} + +for (let [method, signature] of _methodsCallableFromChild) { + ContentPrefServiceChild[method] = forwardMethodToParent.bind(ContentPrefServiceChild, method, signature); +} + +ContentPrefServiceChild.init(); |