mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1038811 - Push Notifications - Push implementation changes. r=nsm
This commit is contained in:
parent
1cb1b34095
commit
fc59030cb1
@ -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)
|
||||
|
301
dom/push/Push.js
301
dom/push/Push.js
@ -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]);
|
||||
|
@ -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}
|
||||
|
@ -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);
|
||||
|
||||
|
18
dom/push/PushServiceChildPreload.js
Normal file
18
dom/push/PushServiceChildPreload.js
Normal 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);
|
||||
});
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user