diff --git a/browser/components/loop/MozLoopAPI.jsm b/browser/components/loop/MozLoopAPI.jsm index 408d483462e..53bae01ad8a 100644 --- a/browser/components/loop/MozLoopAPI.jsm +++ b/browser/components/loop/MozLoopAPI.jsm @@ -33,7 +33,6 @@ function injectLoopAPI(targetWindow) { */ doNotDisturb: { enumerable: true, - configurable: true, get: function() { return MozLoopService.doNotDisturb; }, @@ -49,7 +48,6 @@ function injectLoopAPI(targetWindow) { */ locale: { enumerable: true, - configurable: true, get: function() { return MozLoopService.locale; } @@ -65,7 +63,6 @@ function injectLoopAPI(targetWindow) { */ getStrings: { enumerable: true, - configurable: true, writable: true, value: function(key) { return MozLoopService.getStrings(key); @@ -85,7 +82,6 @@ function injectLoopAPI(targetWindow) { */ ensureRegistered: { enumerable: true, - configurable: true, writable: true, value: function(callback) { // We translate from a promise to a callback, as we can't pass promises from @@ -112,7 +108,6 @@ function injectLoopAPI(targetWindow) { */ noteCallUrlExpiry: { enumerable: true, - configurable: true, writable: true, value: function(expiryTimeSeconds) { MozLoopService.noteCallUrlExpiry(expiryTimeSeconds); @@ -130,7 +125,6 @@ function injectLoopAPI(targetWindow) { */ setLoopCharPref: { enumerable: true, - configurable: true, writable: true, value: function(prefName, value) { MozLoopService.setLoopCharPref(prefName, value); @@ -152,7 +146,6 @@ function injectLoopAPI(targetWindow) { */ getLoopCharPref: { enumerable: true, - configurable: true, writable: true, value: function(prefName) { return MozLoopService.getLoopCharPref(prefName); @@ -164,7 +157,6 @@ function injectLoopAPI(targetWindow) { */ startAlerting: { enumerable: true, - configurable: true, writable: true, value: function() { let chromeWindow = getChromeWindow(targetWindow); @@ -188,7 +180,6 @@ function injectLoopAPI(targetWindow) { */ stopAlerting: { enumerable: true, - configurable: true, writable: true, value: function() { if (ringerStopper) { @@ -224,7 +215,6 @@ function injectLoopAPI(targetWindow) { */ hawkRequest: { enumerable: true, - configurable: true, writable: true, value: function(path, method, payloadObj, callback) { // XXX Should really return a DOM promise here. @@ -239,6 +229,7 @@ function injectLoopAPI(targetWindow) { let contentObj = Cu.createObjectIn(targetWindow); Object.defineProperties(contentObj, api); + Object.seal(contentObj); Cu.makeObjectPropsNormal(contentObj); targetWindow.navigator.wrappedJSObject.__defineGetter__("mozLoop", function() { diff --git a/browser/components/loop/MozLoopService.jsm b/browser/components/loop/MozLoopService.jsm index 3197a5cd3c5..81ae7870c7f 100644 --- a/browser/components/loop/MozLoopService.jsm +++ b/browser/components/loop/MozLoopService.jsm @@ -47,6 +47,16 @@ XPCOMUtils.defineLazyServiceGetter(this, "uuidgen", "@mozilla.org/uuid-generator;1", "nsIUUIDGenerator"); +// The current deferred for the registration process. This is set if in progress +// or the registration was successful. This is null if a registration attempt was +// unsuccessful. +let gRegisteredDeferred = null; +let gPushHandler = null; +let gHawkClient = null; +let gRegisteredLoopServer = false; +let gLocalizedStrings = null; +let gInitializeTimer = null; + /** * Internal helper methods and state * @@ -56,12 +66,7 @@ XPCOMUtils.defineLazyServiceGetter(this, "uuidgen", */ let MozLoopServiceInternal = { // The uri of the Loop server. - loopServerUri: Services.prefs.getCharPref("loop.server"), - - // The current deferred for the registration process. This is set if in progress - // or the registration was successful. This is null if a registration attempt was - // unsuccessful. - _registeredDeferred: null, + get loopServerUri() Services.prefs.getCharPref("loop.server"), /** * The initial delay for push registration. This ensures we don't start @@ -137,18 +142,18 @@ let MozLoopServiceInternal = { * rejected with an error code or string. */ promiseRegisteredWithServers: function(mockPushHandler) { - if (this._registeredDeferred) { - return this._registeredDeferred.promise; + if (gRegisteredDeferred) { + return gRegisteredDeferred.promise; } - this._registeredDeferred = Promise.defer(); + gRegisteredDeferred = Promise.defer(); // We grab the promise early in case .initialize or its results sets // it back to null on error. - let result = this._registeredDeferred.promise; + let result = gRegisteredDeferred.promise; - this._pushHandler = mockPushHandler || MozLoopPushHandler; + gPushHandler = mockPushHandler || MozLoopPushHandler; - this._pushHandler.initialize(this.onPushRegistered.bind(this), + gPushHandler.initialize(this.onPushRegistered.bind(this), this.onHandleNotification.bind(this)); return result; @@ -168,8 +173,8 @@ let MozLoopServiceInternal = { * rejected with this JSON-parsed response. */ hawkRequest: function(path, method, payloadObj) { - if (!this._hawkClient) { - this._hawkClient = new HawkClient(this.loopServerUri); + if (!gHawkClient) { + gHawkClient = new HawkClient(this.loopServerUri); } let sessionToken; @@ -186,7 +191,7 @@ let MozLoopServiceInternal = { 2 * 32, true); } - return this._hawkClient.request(path, method, credentials, payloadObj); + return gHawkClient.request(path, method, credentials, payloadObj); }, /** @@ -205,8 +210,8 @@ let MozLoopServiceInternal = { } else { // XXX Bubble the precise details up to the UI somehow (bug 1013248). console.warn("Loop server sent an invalid session token"); - this._registeredDeferred.reject("session-token-wrong-size"); - this._registeredDeferred = null; + gRegisteredDeferred.reject("session-token-wrong-size"); + gRegisteredDeferred = null; return false; } } @@ -221,8 +226,8 @@ let MozLoopServiceInternal = { */ onPushRegistered: function(err, pushUrl) { if (err) { - this._registeredDeferred.reject(err); - this._registeredDeferred = null; + gRegisteredDeferred.reject(err); + gRegisteredDeferred = null; return; } @@ -239,13 +244,12 @@ let MozLoopServiceInternal = { this.hawkRequest("/registration", "POST", { simple_push_url: pushUrl}) .then((response) => { // If this failed we got an invalid token. storeSessionToken rejects - // the _registeredDeferred promise for us, so here we just need to + // the gRegisteredDeferred promise for us, so here we just need to // early return. if (!this.storeSessionToken(response.headers)) return; - this.registeredLoopServer = true; - this._registeredDeferred.resolve(); + gRegisteredDeferred.resolve(); // No need to clear the promise here, everything was good, so we don't need // to re-register. }, (error) => { @@ -266,8 +270,8 @@ let MozLoopServiceInternal = { // XXX Bubble the precise details up to the UI somehow (bug 1013248). Cu.reportError("Failed to register with the loop server. error: " + error); - this._registeredDeferred.reject(error.errno); - this._registeredDeferred = null; + gRegisteredDeferred.reject(error.errno); + gRegisteredDeferred = null; } ); }, @@ -293,8 +297,8 @@ let MozLoopServiceInternal = { * @returns {Object} a map of element ids with attributes to set. */ get localizedStrings() { - if (this._localizedStrings) - return this._localizedStrings; + if (gLocalizedStrings) + return gLocalizedStrings; var stringBundle = Services.strings.createBundle('chrome://browser/locale/loop/loop.properties'); @@ -316,7 +320,7 @@ let MozLoopServiceInternal = { map[key][property] = string.value; } - return this._localizedStrings = map; + return gLocalizedStrings = map; }, /** @@ -445,11 +449,28 @@ let MozLoopServiceInternal = { Chat.open(contentWindow, origin, title, url, undefined, undefined, callback); } }; +Object.freeze(MozLoopServiceInternal); + +let gInitializeTimerFunc = () => { + // Kick off the push notification service into registering after a timeout + // this ensures we're not doing too much straight after the browser's finished + // starting up. + gInitializeTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + gInitializeTimer.initWithCallback(() => { + MozLoopService.register(); + gInitializeTimer = null; + }, + MozLoopServiceInternal.initialRegistrationDelayMilliseconds, Ci.nsITimer.TYPE_ONE_SHOT); +}; /** * Public API */ this.MozLoopService = { + set initializeTimerFunc(value) { + gInitializeTimerFunc = value; + }, + /** * Initialized the loop service, and starts registration with the * push and loop servers. @@ -462,26 +483,10 @@ this.MozLoopService = { // If expiresTime is in the future then kick-off registration. if (MozLoopServiceInternal.urlExpiryTimeIsInFuture()) { - this._startInitializeTimer(); + gInitializeTimerFunc(); } }, - /** - * Internal function, exposed for testing purposes only. Used to start the - * initialize timer. - */ - _startInitializeTimer: function() { - // Kick off the push notification service into registering after a timeout - // this ensures we're not doing too much straight after the browser's finished - // starting up. - this._initializeTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - this._initializeTimer.initWithCallback(function() { - this.register(); - this._initializeTimer = null; - }.bind(this), - MozLoopServiceInternal.initialRegistrationDelayMilliseconds, Ci.nsITimer.TYPE_ONE_SHOT); - }, - /** * Starts registration of Loop with the push server, and then will register * with the Loop server. It will return early if already registered. @@ -623,3 +628,4 @@ this.MozLoopService = { return MozLoopServiceInternal.hawkRequest(path, method, payloadObj); }, }; +Object.freeze(this.MozLoopService); diff --git a/browser/components/loop/test/xpcshell/test_loopservice_initialize.js b/browser/components/loop/test/xpcshell/test_loopservice_initialize.js index 6dd7e3a8b17..8df92d1ba47 100644 --- a/browser/components/loop/test/xpcshell/test_loopservice_initialize.js +++ b/browser/components/loop/test/xpcshell/test_loopservice_initialize.js @@ -52,7 +52,7 @@ function run_test() { // Override MozLoopService's initializeTimer, so that we can verify the timeout is called // correctly. - MozLoopService._startInitializeTimer = function() { + MozLoopService.initializeTimerFunc = function() { startTimerCalled = true; };