Bug 1038811 - Push Notifications - Push implementation changes. r=nsm

This commit is contained in:
Doug Turner 2015-04-10 20:19:28 -07:00
parent 1cb1b34095
commit fc59030cb1
6 changed files with 398 additions and 179 deletions

View File

@ -9,5 +9,6 @@ toolkit.jar:
content/global/BrowserElementChildPreload.js (../browser-element/BrowserElementChildPreload.js)
content/global/BrowserElementPanning.js (../browser-element/BrowserElementPanning.js)
* content/global/BrowserElementPanningAPZDisabled.js (../browser-element/BrowserElementPanningAPZDisabled.js)
content/global/PushServiceChildPreload.js (../push/PushServiceChildPreload.js)
content/global/preload.js (preload.js)
content/global/post-fork-preload.js (post-fork-preload.js)

View File

@ -4,8 +4,8 @@
"use strict";
// Don't modify this, instead set services.push.debug.
let gDebuggingEnabled = false;
// Don't modify this, instead set dom.push.debug.
let gDebuggingEnabled = true;
function debug(s) {
if (gDebuggingEnabled)
@ -21,6 +21,94 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
Cu.import("resource://gre/modules/AppsUtils.jsm");
const PUSH_SUBSCRIPTION_CID = Components.ID("{CA86B665-BEDA-4212-8D0F-5C9F65270B58}");
function PushSubscription(pushEndpoint, scope, pageURL) {
debug("PushSubscription Constructor");
this._pushEndpoint = pushEndpoint;
this._scope = scope;
this._pageURL = pageURL;
}
PushSubscription.prototype = {
__proto__: DOMRequestIpcHelper.prototype,
contractID: "@mozilla.org/push/PushSubscription;1",
classID : PUSH_SUBSCRIPTION_CID,
QueryInterface : XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer,
Ci.nsISupportsWeakReference,
Ci.nsIObserver]),
init: function(aWindow) {
debug("PushSubscription init()");
this.initDOMRequestHelper(aWindow, [
"PushService:Unregister:OK",
"PushService:Unregister:KO",
]);
this._cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
.getService(Ci.nsISyncMessageSender);
},
__init: function(endpoint, scope, pageURL) {
this._pushEndpoint = endpoint;
this._scope = scope;
this._pageURL = pageURL;
},
get endpoint() {
return this._pushEndpoint;
},
get subscriptionId() {
// TODO bug 1149271. Not sure what this is about.
return "The twins of Mammon quarrelled.";
},
unsubscribe: function() {
debug("unsubscribe! ")
let promiseInit = function(resolve, reject) {
let resolverId = this.getPromiseResolverId({resolve: resolve,
reject: reject });
this._cpmm.sendAsyncMessage("Push:Unregister", {
pageURL: this._pageURL,
scope: this._scope,
pushEndpoint: this._pushEndpoint,
requestID: resolverId
});
}.bind(this);
return this.createPromise(promiseInit);
},
receiveMessage: function(aMessage) {
debug("push subscription receiveMessage(): " + JSON.stringify(aMessage))
let json = aMessage.data;
let resolver = this.takePromiseResolver(json.requestID);
if (resolver == null) {
return;
}
switch (aMessage.name) {
case "PushService:Unregister:OK":
resolver.resolve(false);
break;
case "PushService:Unregister:KO":
resolver.reject(true);
break;
default:
debug("NOT IMPLEMENTED! receiveMessage for " + aMessage.name);
}
},
};
const PUSH_CID = Components.ID("{cde1d019-fad8-4044-b141-65fb4fb7a245}");
/**
@ -47,101 +135,186 @@ Push.prototype = {
// Set debug first so that all debugging actually works.
// NOTE: We don't add an observer here like in PushService. Flipping the
// pref will require a reload of the app/page, which seems acceptable.
gDebuggingEnabled = Services.prefs.getBoolPref("services.push.debug");
gDebuggingEnabled = Services.prefs.getBoolPref("dom.push.debug");
debug("init()");
let principal = aWindow.document.nodePrincipal;
let appsService = Cc["@mozilla.org/AppsService;1"]
.getService(Ci.nsIAppsService);
this._manifestURL = appsService.getManifestURLByLocalId(principal.appId);
this._pageURL = principal.URI;
this._pageURL = aWindow.document.nodePrincipal.URI;
this._window = aWindow;
this.initDOMRequestHelper(aWindow, [
"PushService:Register:OK",
"PushService:Register:KO",
"PushService:Unregister:OK",
"PushService:Unregister:KO",
"PushService:Registrations:OK",
"PushService:Registrations:KO"
"PushService:Registration:OK",
"PushService:Registration:KO"
]);
this._cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
.getService(Ci.nsISyncMessageSender);
},
setScope: function(scope){
debug('setScope ' + scope);
this._scope = scope;
},
askPermission: function (aAllowCallback, aCancelCallback) {
debug("askPermission");
let principal = this._window.document.nodePrincipal;
let type = "push";
let permValue =
Services.perms.testExactPermissionFromPrincipal(principal, type);
debug("Existing permission " + permValue);
if (permValue == Ci.nsIPermissionManager.ALLOW_ACTION) {
aAllowCallback();
return;
}
if (permValue == Ci.nsIPermissionManager.DENY_ACTION) {
aCancelCallback();
return;
}
// Create an array with a single nsIContentPermissionType element.
type = {
type: "push",
access: null,
options: [],
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionType])
};
let typeArray = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
typeArray.appendElement(type, false);
// create a nsIContentPermissionRequest
let request = {
types: typeArray,
principal: principal,
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionRequest]),
allow: function() {
aAllowCallback();
},
cancel: function() {
aCancelCallback();
},
window: this._window
};
debug("asking the window utils about permission...")
// Using askPermission from nsIDOMWindowUtils that takes care of the
// remoting if needed.
let windowUtils = this._window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
windowUtils.askPermission(request);
},
receiveMessage: function(aMessage) {
debug("receiveMessage()");
let request = this.getRequest(aMessage.data.requestID);
debug("push receiveMessage(): " + JSON.stringify(aMessage))
let json = aMessage.data;
if (!request) {
debug("No request " + json.requestID);
let resolver = this.takePromiseResolver(json.requestID);
if (!resolver) {
return;
}
switch (aMessage.name) {
case "PushService:Register:OK":
Services.DOMRequest.fireSuccess(request, json.pushEndpoint);
{
let subscription = new this._window.PushSubscription(json.pushEndpoint,
this._scope,
this._pageURL.spec);
resolver.resolve(subscription);
break;
}
case "PushService:Register:KO":
Services.DOMRequest.fireError(request, json.error);
resolver.reject(null);
break;
case "PushService:Unregister:OK":
Services.DOMRequest.fireSuccess(request, json.pushEndpoint);
case "PushService:Registration:OK":
{
let subscription = null;
try {
subscription = new this._window.PushSubscription(json.registration.pushEndpoint,
this._scope, this._pageURL.spec);
} catch(error) {
}
resolver.resolve(subscription);
break;
case "PushService:Unregister:KO":
Services.DOMRequest.fireError(request, json.error);
break;
case "PushService:Registrations:OK":
Services.DOMRequest.fireSuccess(request, json.registrations);
break;
case "PushService:Registrations:KO":
Services.DOMRequest.fireError(request, json.error);
}
case "PushService:Registration:KO":
resolver.reject(null);
break;
default:
debug("NOT IMPLEMENTED! receiveMessage for " + aMessage.name);
}
},
register: function() {
debug("register()");
let req = this.createRequest();
if (!Services.prefs.getBoolPref("services.push.connection.enabled")) {
// If push socket is disabled by the user, immediately error rather than
// timing out.
Services.DOMRequest.fireErrorAsync(req, "NetworkError");
return req;
}
subscribe: function() {
debug("subscribe()");
let p = this.createPromise(function(resolve, reject) {
let resolverId = this.getPromiseResolverId({ resolve: resolve, reject: reject });
this._cpmm.sendAsyncMessage("Push:Register", {
pageURL: this._pageURL.spec,
manifestURL: this._manifestURL,
requestID: this.getRequestId(req)
});
return req;
this.askPermission(
function() {
this._cpmm.sendAsyncMessage("Push:Register", {
pageURL: this._pageURL.spec,
scope: this._scope,
requestID: resolverId
});
}.bind(this),
function() {
reject("denied");
}
);
}.bind(this));
return p;
},
unregister: function(aPushEndpoint) {
debug("unregister(" + aPushEndpoint + ")");
let req = this.createRequest();
this._cpmm.sendAsyncMessage("Push:Unregister", {
pageURL: this._pageURL.spec,
manifestURL: this._manifestURL,
requestID: this.getRequestId(req),
pushEndpoint: aPushEndpoint
});
return req;
getSubscription: function() {
debug("getSubscription()" + this._scope);
let p = this.createPromise(function(resolve, reject) {
let resolverId = this.getPromiseResolverId({ resolve: resolve, reject: reject });
this.askPermission(
function() {
this._cpmm.sendAsyncMessage("Push:Registration", {
pageURL: this._pageURL.spec,
scope: this._scope,
requestID: resolverId
});
}.bind(this),
function() {
reject("denied");
}
);
}.bind(this));
return p;
},
registrations: function() {
debug("registrations()");
let req = this.createRequest();
this._cpmm.sendAsyncMessage("Push:Registrations", {
manifestURL: this._manifestURL,
requestID: this.getRequestId(req)
});
return req;
}
hasPermission: function() {
debug("getSubscription()" + this._scope);
let p = this.createPromise(function(resolve, reject) {
let permissionManager = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager);
let permission = permissionManager.testExactPermission(this._pageURL, "push");
let pushPermissionStatus = "default";
if (permission == Ci.nsIPermissionManager.ALLOW_ACTION) {
pushPermissionStatus = "granted";
} else if (permission == Ci.nsIPermissionManager.DENY_ACTION) {
pushPermissionStatus = "denied";
}
resolve(pushPermissionStatus);
}.bind(this));
return p;
},
}
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([Push]);
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([Push, PushSubscription]);

View File

@ -2,6 +2,9 @@
component {cde1d019-fad8-4044-b141-65fb4fb7a245} Push.js
contract @mozilla.org/push/PushManager;1 {cde1d019-fad8-4044-b141-65fb4fb7a245}
component {CA86B665-BEDA-4212-8D0F-5C9F65270B58} Push.js
contract @mozilla.org/push/PushSubscription;1 {CA86B665-BEDA-4212-8D0F-5C9F65270B58}
# Component to initialize PushService on startup.
component {4b8caa3b-3c58-4f3c-a7f5-7bd9cb24c11d} PushServiceLauncher.js
contract @mozilla.org/push/ServiceLauncher;1 {4b8caa3b-3c58-4f3c-a7f5-7bd9cb24c11d}

View File

@ -5,8 +5,8 @@
"use strict";
// Don't modify this, instead set services.push.debug.
let gDebuggingEnabled = false;
// Don't modify this, instead set dom.push.debug.
let gDebuggingEnabled = true;
function debug(s) {
if (gDebuggingEnabled)
@ -41,7 +41,7 @@ var threadManager = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadM
this.EXPORTED_SYMBOLS = ["PushService"];
const prefs = new Preferences("services.push.");
const prefs = new Preferences("dom.push.");
// Set debug first so that all debugging actually works.
gDebuggingEnabled = prefs.get("debug");
@ -54,7 +54,7 @@ const kUDP_WAKEUP_WS_STATUS_CODE = 4774; // WebSocket Close status code sent
// wake client up using UDP.
const kCHILD_PROCESS_MESSAGES = ["Push:Register", "Push:Unregister",
"Push:Registrations"];
"Push:Registration"];
const kWS_MAX_WENTDOWN = 2;
@ -79,10 +79,9 @@ this.PushDB.prototype = {
// index to fetch records based on endpoints. used by unregister
objectStore.createIndex("pushEndpoint", "pushEndpoint", { unique: true });
// index to fetch records per manifest, so we can identify endpoints
// associated with an app. Since an app can have multiple endpoints
// uniqueness cannot be enforced
objectStore.createIndex("manifestURL", "manifestURL", { unique: false });
// index to fetch records per scope, so we can identify endpoints
// associated with an app.
objectStore.createIndex("scope", "scope", { unique: true });
},
/*
@ -94,7 +93,7 @@ this.PushDB.prototype = {
* Callback function to invoke when there was an error.
*/
put: function(aChannelRecord, aSuccessCb, aErrorCb) {
debug("put()");
debug("put()" + JSON.stringify(aChannelRecord));
this.newTxn(
"readwrite",
@ -173,30 +172,20 @@ this.PushDB.prototype = {
);
},
getAllByManifestURL: function(aManifestURL, aSuccessCb, aErrorCb) {
debug("getAllByManifestURL()");
if (!aManifestURL) {
if (typeof aErrorCb == "function") {
aErrorCb("PushDB.getAllByManifestURL: Got undefined aManifestURL");
}
return;
}
let self = this;
getByScope: function(aScope, aSuccessCb, aErrorCb) {
debug("getByScope() " + aScope);
this.newTxn(
"readonly",
kPUSHDB_STORE_NAME,
function txnCb(aTxn, aStore) {
let index = aStore.index("manifestURL");
let range = IDBKeyRange.only(aManifestURL);
aTxn.result = [];
index.openCursor(range).onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
debug(cursor.value.manifestURL + " " + cursor.value.channelID);
aTxn.result.push(cursor.value);
cursor.continue();
}
aTxn.result = undefined;
let index = aStore.index("scope");
index.get(aScope).onsuccess = function setTxnResult(aEvent) {
aTxn.result = aEvent.target.result;
debug("Fetch successful " + aEvent.target.result);
}
},
aSuccessCb,
@ -325,17 +314,17 @@ this.PushService = {
}
break;
case "nsPref:changed":
if (aData == "services.push.serverURL") {
debug("services.push.serverURL changed! websocket. new value " +
if (aData == "dom.push.serverURL") {
debug("dom.push.serverURL changed! websocket. new value " +
prefs.get("serverURL"));
this._shutdownWS();
} else if (aData == "services.push.connection.enabled") {
} else if (aData == "dom.push.connection.enabled") {
if (prefs.get("connection.enabled")) {
this._startListeningIfChannelsPresent();
} else {
this._shutdownWS();
}
} else if (aData == "services.push.debug") {
} else if (aData == "dom.push.debug") {
gDebuggingEnabled = prefs.get("debug");
}
break;
@ -382,35 +371,30 @@ this.PushService = {
return;
}
// Only remove push registrations for apps.
if (data.browserOnly) {
return;
}
// TODO 1149274. We should support site permissions as well as a way to go from manifest
// url to 'all scopes registered for push in this app'
let appsService = Cc["@mozilla.org/AppsService;1"]
.getService(Ci.nsIAppsService);
let manifestURL = appsService.getManifestURLByLocalId(data.appId);
if (!manifestURL) {
debug("webapps-clear-data: No manifest URL found for " + data.appId);
let scope = appsService.getScopeByLocalId(data.appId);
if (!scope) {
debug("webapps-clear-data: No scope found for " + data.appId);
return;
}
this._db.getAllByManifestURL(manifestURL, function(records) {
debug("Got " + records.length);
for (let i = 0; i < records.length; i++) {
this._db.delete(records[i].channelID, null, function() {
debug("webapps-clear-data: " + manifestURL +
" Could not delete entry " + records[i].channelID);
});
this._db.getByScope(scope, function(record) {
this._db.delete(records.channelID, null, function() {
debug("webapps-clear-data: " + scope +
" Could not delete entry " + records.channelID);
// courtesy, but don't establish a connection
// just for it
if (this._ws) {
debug("Had a connection, so telling the server");
this._send("unregister", {channelID: records[i].channelID});
this._send("unregister", {channelID: records.channelID});
}
}
}.bind(this), function() {
debug("webapps-clear-data: Error in getAllByManifestURL(" + manifestURL + ")");
}.bind(this), function() {
debug("webapps-clear-data: Error in getByScope(" + scope + ")");
});
});
break;
@ -465,7 +449,7 @@ this.PushService = {
* 1) the gap between the maximum working ping and the first ping that
* gives an error (timeout) OR
* 2) we have reached the pref of the maximum value we allow for a ping
* (services.push.adaptive.upperLimit)
* (dom.push.adaptive.upperLimit)
*/
_recalculatePing: true,
@ -512,6 +496,11 @@ this.PushService = {
if (!prefs.get("enabled"))
return null;
var globalMM = Cc["@mozilla.org/globalmessagemanager;1"]
.getService(Ci.nsIFrameScriptLoader);
globalMM.loadFrameScript("chrome://global/content/PushServiceChildPreload.js", true);
this._db = new PushDB();
let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"]
@ -672,7 +661,7 @@ this.PushService = {
* This algorithm tries to search the best value between a disconnection and a
* valid ping, to ensure better battery life and network resources usage.
*
* The value is saved in services.push.pingInterval
* The value is saved in dom.push.pingInterval
* @param wsWentDown [Boolean] if the WebSocket was closed or it is still alive
*
*/
@ -842,7 +831,7 @@ this.PushService = {
let serverURL = prefs.get("serverURL");
if (!serverURL) {
debug("No services.push.serverURL found!");
debug("No dom.push.serverURL found!");
return;
}
@ -850,7 +839,7 @@ this.PushService = {
try {
uri = Services.io.newURI(serverURL, null, null);
} catch(e) {
debug("Error creating valid URI from services.push.serverURL (" +
debug("Error creating valid URI from dom.push.serverURL (" +
serverURL + ")");
return;
}
@ -1090,7 +1079,7 @@ this.PushService = {
debug("got new UAID: all re-register");
this._notifyAllAppsRegister()
.then(this._dropRegistrations.bind(this))
.then(this._dropRegistration.bind(this))
.then(finishHandshake.bind(this));
return;
@ -1279,35 +1268,32 @@ this.PushService = {
},
// Fires a push-register system message to all applications that have
// registrations.
// registration.
_notifyAllAppsRegister: function() {
debug("notifyAllAppsRegister()");
let deferred = Promise.defer();
// records are objects describing the registrations as stored in IndexedDB.
// records are objects describing the registration as stored in IndexedDB.
function wakeupRegisteredApps(records) {
// Pages to be notified.
// wakeupTable[manifestURL] -> [ pageURL ]
// wakeupTable[scope] -> [ pageURL ]
let wakeupTable = {};
for (let i = 0; i < records.length; i++) {
let record = records[i];
if (!(record.manifestURL in wakeupTable))
wakeupTable[record.manifestURL] = [];
if (!(record.scope in wakeupTable))
wakeupTable[record.scope] = [];
wakeupTable[record.manifestURL].push(record.pageURL);
wakeupTable[record.scope].push(record.pageURL);
}
let messenger = Cc["@mozilla.org/system-message-internal;1"]
.getService(Ci.nsISystemMessagesInternal);
// TODO -- test needed. E10s support needed.
for (let manifestURL in wakeupTable) {
wakeupTable[manifestURL].forEach(function(pageURL) {
messenger.sendMessage('push-register', {},
Services.io.newURI(pageURL, null, null),
Services.io.newURI(manifestURL, null, null));
let globalMM = Cc['@mozilla.org/globalmessagemanager;1'].getService(Ci.nsIMessageListenerManager);
for (let scope in wakeupTable) {
wakeupTable[scope].forEach(function(pageURL) {
globalMM.broadcastAsyncMessage('pushsubscriptionchanged', aPushRecord.scope);
});
}
deferred.resolve();
}
@ -1317,22 +1303,36 @@ this.PushService = {
},
_notifyApp: function(aPushRecord) {
if (!aPushRecord || !aPushRecord.pageURL || !aPushRecord.manifestURL) {
debug("notifyApp() something is undefined. Dropping notification");
if (!aPushRecord || !aPushRecord.pageURL || !aPushRecord.scope) {
debug("notifyApp() something is undefined. Dropping notification: "
+ JSON.stringify(aPushRecord) );
return;
}
debug("notifyApp() " + aPushRecord.pageURL +
" " + aPushRecord.manifestURL);
" " + aPushRecord.scope);
let pageURI = Services.io.newURI(aPushRecord.pageURL, null, null);
let manifestURI = Services.io.newURI(aPushRecord.manifestURL, null, null);
let scopeURI = Services.io.newURI(aPushRecord.scope, null, null);
let message = {
pushEndpoint: aPushRecord.pushEndpoint,
version: aPushRecord.version
};
let messenger = Cc["@mozilla.org/system-message-internal;1"]
.getService(Ci.nsISystemMessagesInternal);
messenger.sendMessage('push', message, pageURI, manifestURI);
// If permission has been revoked, trash the message.
if(Services.perms.testExactPermission(scopeURI, "push") != Ci.nsIPermissionManager.ALLOW_ACTION) {
debug("Does not have permission for push.")
return;
}
// TODO data.
let data = {
payload: "Short as life is, we make it still shorter by the careless waste of time.",
scope: aPushRecord.scope
};
let globalMM = Cc['@mozilla.org/globalmessagemanager;1']
.getService(Ci.nsIMessageListenerManager);
globalMM.broadcastAsyncMessage('push', data);
},
_updatePushRecord: function(aPushRecord) {
@ -1342,7 +1342,7 @@ this.PushService = {
return deferred.promise;
},
_dropRegistrations: function() {
_dropRegistration: function() {
let deferred = Promise.defer();
this._db.drop(deferred.resolve, deferred.reject);
return deferred.promise;
@ -1365,9 +1365,8 @@ this.PushService = {
* Called on message from the child process. aPageRecord is an object sent by
* navigator.push, identifying the sending page and other fields.
*/
register: function(aPageRecord, aMessageManager) {
debug("register()");
_registerWithServer: function(aPageRecord, aMessageManager) {
let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"]
.getService(Ci.nsIUUIDGenerator);
// generateUUID() gives a UUID surrounded by {...}, slice them off.
@ -1384,7 +1383,26 @@ this.PushService = {
},
function(message) {
aMessageManager.sendAsyncMessage("PushService:Register:KO", message);
});
}
);
},
register: function(aPageRecord, aMessageManager) {
debug("register(): " + JSON.stringify(aPageRecord));
this._db.getByScope(aPageRecord.scope,
function(aPageRecord, aMessageManager, pushRecord) {
if (pushRecord == null) {
this._registerWithServer(aPageRecord, aMessageManager);
}
else {
this._onRegistrationSuccess(aPageRecord, aMessageManager, pushRecord);
}
}.bind(this, aPageRecord, aMessageManager),
function () {
debug("getByScope failed");
}
);
},
/**
@ -1421,10 +1439,12 @@ this.PushService = {
channelID: data.channelID,
pushEndpoint: data.pushEndpoint,
pageURL: aPageRecord.pageURL,
manifestURL: aPageRecord.manifestURL,
scope: aPageRecord.scope,
version: null
};
debug("scope in _onRegisterSuccess: " + aPageRecord.scope)
this._updatePushRecord(record)
.then(
function() {
@ -1436,7 +1456,7 @@ this.PushService = {
this._send("unregister", {channelID: record.channelID});
message["error"] = error;
deferred.reject(message);
}
}.bind(this)
);
return deferred.promise;
@ -1479,7 +1499,7 @@ this.PushService = {
* data is cheap, reliable notification is not.
*/
unregister: function(aPageRecord, aMessageManager) {
debug("unregister()");
debug("unregister() " + JSON.stringify(aPageRecord));
let fail = function(error) {
debug("unregister() fail() error " + error);
@ -1495,7 +1515,7 @@ this.PushService = {
}
// Non-owner tried to unregister, say success, but don't do anything.
if (record.manifestURL !== aPageRecord.manifestURL) {
if (record.scope !== aPageRecord.scope) {
aMessageManager.sendAsyncMessage("PushService:Unregister:OK", {
requestID: aPageRecord.requestID,
pushEndpoint: aPageRecord.pushEndpoint
@ -1518,38 +1538,35 @@ this.PushService = {
/**
* Called on message from the child process
*/
registrations: function(aPageRecord, aMessageManager) {
debug("registrations()");
if (aPageRecord.manifestURL) {
this._db.getAllByManifestURL(aPageRecord.manifestURL,
this._onRegistrationsSuccess.bind(this, aPageRecord, aMessageManager),
this._onRegistrationsError.bind(this, aPageRecord, aMessageManager));
}
else {
this._onRegistrationsError(aPageRecord, aMessageManager);
}
registration: function(aPageRecord, aMessageManager) {
debug("registration()");
this._db.getByScope(aPageRecord.scope,
this._onRegistrationSuccess.bind(this, aPageRecord, aMessageManager),
this._onRegistrationError.bind(this, aPageRecord, aMessageManager));
},
_onRegistrationsSuccess: function(aPageRecord,
aMessageManager,
pushRecords) {
let registrations = [];
pushRecords.forEach(function(pushRecord) {
registrations.push({
__exposedProps__: { pushEndpoint: 'r', version: 'r' },
pushEndpoint: pushRecord.pushEndpoint,
version: pushRecord.version
});
});
aMessageManager.sendAsyncMessage("PushService:Registrations:OK", {
_onRegistrationSuccess: function(aPageRecord,
aMessageManager,
pushRecord) {
let registration = null;
if (pushRecord) {
registration = {
pushEndpoint: pushRecord.pushEndpoint,
version: pushRecord.version
};
}
aMessageManager.sendAsyncMessage("PushService:Registration:OK", {
requestID: aPageRecord.requestID,
registrations: registrations
registration: registration
});
},
_onRegistrationsError: function(aPageRecord, aMessageManager) {
aMessageManager.sendAsyncMessage("PushService:Registrations:KO", {
_onRegistrationError: function(aPageRecord, aMessageManager) {
aMessageManager.sendAsyncMessage("PushService:Registration:KO", {
requestID: aPageRecord.requestID,
error: "Database error"
});
@ -1733,7 +1750,7 @@ this.PushService = {
this._udpServer = Cc["@mozilla.org/network/udp-socket;1"]
.createInstance(Ci.nsIUDPSocket);
this._udpServer.init(-1, false, Services.scriptSecurityManager.getSystemPrincipal());
this._udpServer.init(-1, false);
this._udpServer.asyncListen(this);
debug("listenForUDPWakeup listening on " + this._udpServer.port);

View File

@ -0,0 +1,18 @@
/* 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";
XPCOMUtils.defineLazyServiceGetter(this,
"swm",
"@mozilla.org/serviceworkers/manager;1",
"nsIServiceWorkerManager");
addMessageListener("push", function (aMessage) {
swm.sendPushEvent(aMessage.data.scope, aMessage.data.payload);
});
addMessageListener("pushsubscriptionchanged", function (aMessage) {
swm.sendPushSubscriptionChangedEvent(aMessage.data);
});

View File

@ -30,11 +30,18 @@ PushServiceLauncher.prototype = {
break;
case "final-ui-startup":
Services.obs.removeObserver(this, "final-ui-startup");
if (!Services.prefs.getBoolPref("services.push.enabled")) {
if (!Services.prefs.getBoolPref("dom.push.enabled")) {
return;
}
Cu.import("resource://gre/modules/PushService.jsm");
PushService.init();
let isParent = Cc["@mozilla.org/xre/runtime;1"]
.getService(Ci.nsIXULRuntime)
.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
if (isParent) {
Cu.import("resource://gre/modules/PushService.jsm");
PushService.init();
}
break;
}
}