mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
Bug 1018320 - RequestSync API - patch 6 - Manager API, r=ehsan
This commit is contained in:
parent
d6ae21b741
commit
bf1781a498
48
dom/requestsync/RequestSyncApp.jsm
Normal file
48
dom/requestsync/RequestSyncApp.jsm
Normal file
@ -0,0 +1,48 @@
|
||||
/* 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 = ['RequestSyncApp'];
|
||||
|
||||
function debug(s) {
|
||||
//dump('DEBUG RequestSyncApp: ' + s + '\n');
|
||||
}
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
|
||||
this.RequestSyncApp = function(aData) {
|
||||
debug('created');
|
||||
|
||||
let keys = [ 'origin', 'manifestURL', 'isInBrowserElement' ];
|
||||
for (let i = 0; i < keys.length; ++i) {
|
||||
if (!(keys[i] in aData)) {
|
||||
dump("ERROR - RequestSyncApp must receive a full app object: " + keys[i] + " missing.");
|
||||
throw "ERROR!";
|
||||
}
|
||||
|
||||
this["_" + keys[i]] = aData[keys[i]];
|
||||
}
|
||||
}
|
||||
|
||||
this.RequestSyncApp.prototype = {
|
||||
classDescription: 'RequestSyncApp XPCOM Component',
|
||||
classID: Components.ID('{5a0b64db-a2be-4f08-a6c5-8bf2e3ae0c57}'),
|
||||
contractID: '@mozilla.org/dom/request-sync-manager;1',
|
||||
QueryInterface: XPCOMUtils.generateQI([]),
|
||||
|
||||
get origin() {
|
||||
return this._origin;
|
||||
},
|
||||
|
||||
get manifestURL() {
|
||||
return this._manifestURL;
|
||||
},
|
||||
|
||||
get isInBrowserElement() {
|
||||
return this._isInBrowserElement;
|
||||
}
|
||||
};
|
@ -12,6 +12,8 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
Cu.import('resource://gre/modules/RequestSyncApp.jsm');
|
||||
Cu.import('resource://gre/modules/RequestSyncTask.jsm');
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
"@mozilla.org/childprocessmessagemanager;1",
|
||||
@ -31,7 +33,8 @@ RequestSyncManager.prototype = {
|
||||
Ci.nsIObserver,
|
||||
Ci.nsIDOMGlobalPropertyInitializer]),
|
||||
|
||||
_messages: [ "RequestSyncManager:Registrations:Return" ],
|
||||
_messages: [ "RequestSyncManager:Registrations:Return",
|
||||
"RequestSyncManager:SetPolicy:Return" ],
|
||||
|
||||
init: function(aWindow) {
|
||||
debug("init");
|
||||
@ -55,6 +58,42 @@ RequestSyncManager.prototype = {
|
||||
return this.sendMessage("RequestSyncManager:Registrations", {});
|
||||
},
|
||||
|
||||
setPolicy: function(aTask, aOrigin, aManifestURL, aIsInBrowserElement,
|
||||
aState, aOverwrittenMinInterval) {
|
||||
debug('setPolicy');
|
||||
|
||||
return this.sendMessage("RequestSyncManager:SetPolicy",
|
||||
{ task: aTask,
|
||||
origin: aOrigin,
|
||||
manifestURL: aManifestURL,
|
||||
isInBrowserElement: aIsInBrowserElement,
|
||||
state: aState,
|
||||
overwrittenMinInterval: aOverwrittenMinInterval });
|
||||
},
|
||||
|
||||
registrationsResult: function(aData) {
|
||||
debug("registrationsResult");
|
||||
|
||||
let results = new this._window.Array();
|
||||
for (let i = 0; i < aData.length; ++i) {
|
||||
if (!("app" in aData[i])) {
|
||||
dump("ERROR - Serialization error in RequestSyncManager.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
let app = new RequestSyncApp(aData[i].app);
|
||||
let exposedApp =
|
||||
this._window.RequestSyncApp._create(this._window, app);
|
||||
|
||||
let task = new RequestSyncTask(this, this._window, exposedApp, aData[i]);
|
||||
let exposedTask =
|
||||
this._window.RequestSyncTask._create(this._window, task);
|
||||
|
||||
results.push(exposedTask);
|
||||
}
|
||||
return results;
|
||||
},
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
debug('receiveMessage');
|
||||
|
||||
@ -68,6 +107,11 @@ RequestSyncManager.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aMessage.name == 'RequestSyncManager:Registrations:Return') {
|
||||
req.resolve(this.registrationsResult(aMessage.data.results));
|
||||
return;
|
||||
}
|
||||
|
||||
if ('results' in aMessage.data) {
|
||||
req.resolve(Cu.cloneInto(aMessage.data.results, this._window));
|
||||
return;
|
||||
|
@ -16,6 +16,10 @@ const RSYNC_MIN_INTERVAL = 100;
|
||||
|
||||
const RSYNC_OPERATION_TIMEOUT = 120000 // 2 minutes
|
||||
|
||||
const RSYNC_STATE_ENABLED = "enabled";
|
||||
const RSYNC_STATE_DISABLED = "disabled";
|
||||
const RSYNC_STATE_WIFIONLY = "wifiOnly";
|
||||
|
||||
Cu.import('resource://gre/modules/IndexedDBHelper.jsm');
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
@ -47,9 +51,12 @@ this.RequestSyncService = {
|
||||
|
||||
children: [],
|
||||
|
||||
_messages: [ "RequestSync:Register", "RequestSync:Unregister",
|
||||
"RequestSync:Registrations", "RequestSync:Registration",
|
||||
"RequestSyncManager:Registrations" ],
|
||||
_messages: [ "RequestSync:Register",
|
||||
"RequestSync:Unregister",
|
||||
"RequestSync:Registrations",
|
||||
"RequestSync:Registration",
|
||||
"RequestSyncManager:Registrations",
|
||||
"RequestSyncManager:SetPolicy" ],
|
||||
|
||||
_pendingOperation: false,
|
||||
_pendingMessages: [],
|
||||
@ -316,6 +323,10 @@ this.RequestSyncService = {
|
||||
this.managerRegistrations(aMessage.target, aMessage.data, principal);
|
||||
break;
|
||||
|
||||
case "RequestSyncManager:SetPolicy":
|
||||
this.managerSetPolicy(aMessage.target, aMessage.data, principal);
|
||||
break;
|
||||
|
||||
default:
|
||||
debug("Wrong message: " + aMessage.name);
|
||||
break;
|
||||
@ -370,6 +381,13 @@ this.RequestSyncService = {
|
||||
aData.params.lastSync = 0;
|
||||
aData.params.principal = aPrincipal;
|
||||
|
||||
aData.params.state = RSYNC_STATE_ENABLED;
|
||||
if (aData.params.wifiOnly) {
|
||||
aData.params.state = RSYNC_STATE_WIFIONLY;
|
||||
}
|
||||
|
||||
aData.params.overwrittenMinInterval = 0;
|
||||
|
||||
let dbKey = aData.task + "|" +
|
||||
aPrincipal.appId + '|' +
|
||||
aPrincipal.isInBrowserElement + '|' +
|
||||
@ -478,6 +496,51 @@ this.RequestSyncService = {
|
||||
results: results });
|
||||
},
|
||||
|
||||
// Set a policy to a task.
|
||||
managerSetPolicy: function(aTarget, aData, aPrincipal) {
|
||||
debug("managerSetPolicy");
|
||||
|
||||
let toSave = null;
|
||||
let self = this;
|
||||
this.forEachRegistration(function(aObj) {
|
||||
if (aObj.principal.isInBrowserElement != aData.isInBrowserElement ||
|
||||
aObj.principal.origin != aData.origin) {
|
||||
return;
|
||||
}
|
||||
|
||||
let app = appsService.getAppByLocalId(aObj.principal.appId);
|
||||
if (app && app.manifestURL != aData.manifestURL ||
|
||||
(!app && aData.manifestURL != "")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ("overwrittenMinInterval" in aData) {
|
||||
aObj.data.overwrittenMinInterval = aData.overwrittenMinInterval;
|
||||
}
|
||||
|
||||
aObj.data.state = aData.state;
|
||||
|
||||
if (toSave) {
|
||||
dump("ERROR!! RequestSyncService - SetPolicy matches more than 1 task.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
toSave = aObj;
|
||||
});
|
||||
|
||||
if (!toSave) {
|
||||
aTarget.sendAsyncMessage("RequestSyncManager:SetPolicy:Return",
|
||||
{ requestID: aData.requestID, error: "UnknownTaskError" });
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateObjectInDB(toSave, function() {
|
||||
self.scheduleTimer(toSave);
|
||||
aTarget.sendAsyncMessage("RequestSyncManager:SetPolicy:Return",
|
||||
{ requestID: aData.requestID });
|
||||
});
|
||||
},
|
||||
|
||||
// We cannot expose the full internal object to content but just a subset.
|
||||
// This method creates this subset.
|
||||
createPartialTaskObject: function(aObj) {
|
||||
@ -502,6 +565,8 @@ this.RequestSyncService = {
|
||||
obj.app.manifestURL = app.manifestURL;
|
||||
}
|
||||
|
||||
obj.state = aObj.state;
|
||||
obj.overwrittenMinInterval = aObj.overwrittenMinInterval;
|
||||
return obj;
|
||||
},
|
||||
|
||||
@ -509,21 +574,35 @@ this.RequestSyncService = {
|
||||
scheduleTimer: function(aObj) {
|
||||
debug("scheduleTimer");
|
||||
|
||||
if (aObj.timer) {
|
||||
aObj.timer.cancel();
|
||||
aObj.timer = null;
|
||||
}
|
||||
|
||||
// A registration can be already inactive if it was 1 shot.
|
||||
if (!aObj.active) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aObj.data.state == RSYNC_STATE_DISABLED) {
|
||||
return;
|
||||
}
|
||||
|
||||
// WifiOnly check.
|
||||
if (aObj.data.wifiOnly && !this._wifi) {
|
||||
if (aObj.data.state == RSYNC_STATE_WIFIONLY && !this._wifi) {
|
||||
return;
|
||||
}
|
||||
|
||||
aObj.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
|
||||
let interval = aObj.data.minInterval;
|
||||
if (aObj.data.overwrittenMinInterval > 0) {
|
||||
interval = aObj.data.overwrittenMinInterval;
|
||||
}
|
||||
|
||||
let self = this;
|
||||
aObj.timer.initWithCallback(function() { self.timeout(aObj); },
|
||||
aObj.data.minInterval * 1000,
|
||||
interval * 1000,
|
||||
Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
},
|
||||
|
||||
@ -739,7 +818,7 @@ this.RequestSyncService = {
|
||||
// Disable all the wifiOnly tasks.
|
||||
let self = this;
|
||||
this.forEachRegistration(function(aObj) {
|
||||
if (aObj.data.wifiOnly && aObj.timer) {
|
||||
if (aObj.data.state == RSYNC_STATE_WIFIONLY && aObj.timer) {
|
||||
aObj.timer.cancel();
|
||||
aObj.timer = null;
|
||||
|
||||
|
101
dom/requestsync/RequestSyncTask.jsm
Normal file
101
dom/requestsync/RequestSyncTask.jsm
Normal file
@ -0,0 +1,101 @@
|
||||
/* 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 = ['RequestSyncTask'];
|
||||
|
||||
function debug(s) {
|
||||
//dump('DEBUG RequestSyncTask: ' + s + '\n');
|
||||
}
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
|
||||
this.RequestSyncTask = function(aManager, aWindow, aApp, aData) {
|
||||
debug('created');
|
||||
|
||||
this._manager = aManager;
|
||||
this._window = aWindow;
|
||||
this._app = aApp;
|
||||
|
||||
let keys = [ 'task', 'lastSync', 'oneShot', 'minInterval', 'wakeUpPage',
|
||||
'wifiOnly', 'data', 'state', 'overwrittenMinInterval' ];
|
||||
for (let i = 0; i < keys.length; ++i) {
|
||||
if (!(keys[i] in aData)) {
|
||||
dump("ERROR - RequestSyncTask must receive a fully app object: " + keys[i] + " missing.");
|
||||
throw "ERROR!";
|
||||
}
|
||||
|
||||
this["_" + keys[i]] = aData[keys[i]];
|
||||
}
|
||||
}
|
||||
|
||||
this.RequestSyncTask.prototype = {
|
||||
classDescription: 'RequestSyncTask XPCOM Component',
|
||||
classID: Components.ID('{a1e1c9c6-ce42-49d4-b8b4-fbd686d8fdd9}'),
|
||||
contractID: '@mozilla.org/dom/request-sync-manager;1',
|
||||
QueryInterface: XPCOMUtils.generateQI([]),
|
||||
|
||||
get app() {
|
||||
return this._app;
|
||||
},
|
||||
|
||||
get state() {
|
||||
return this._state;
|
||||
},
|
||||
|
||||
get overwrittenMinInterval() {
|
||||
return this._overwrittenMinInterval;
|
||||
},
|
||||
|
||||
get task() {
|
||||
return this._task;
|
||||
},
|
||||
|
||||
get lastSync() {
|
||||
return this._lastSync;
|
||||
},
|
||||
|
||||
get wakeUpPage() {
|
||||
return this._wakeUpPage;
|
||||
},
|
||||
|
||||
get oneShot() {
|
||||
return this._oneShot;
|
||||
},
|
||||
|
||||
get minInterval() {
|
||||
return this._minInterval;
|
||||
},
|
||||
|
||||
get wifiOnly() {
|
||||
return this._wifiOnly;
|
||||
},
|
||||
|
||||
get data() {
|
||||
return this._data;
|
||||
},
|
||||
|
||||
setPolicy: function(aState, aOverwrittenMinInterval) {
|
||||
debug("setPolicy");
|
||||
let self = this;
|
||||
|
||||
return new this._window.Promise(function(aResolve, aReject) {
|
||||
let p = self._manager.setPolicy(self._task, self._app.origin,
|
||||
self._app.manifestURL,
|
||||
self._app.isInBrowserElement,
|
||||
aState,
|
||||
aOverwrittenMinInterval);
|
||||
|
||||
// Set the new value only when the promise is resolved.
|
||||
p.then(function() {
|
||||
self._state = aState;
|
||||
self._overwrittenMinInterval = aOverwrittenMinInterval;
|
||||
aResolve();
|
||||
}, aReject);
|
||||
});
|
||||
}
|
||||
};
|
@ -17,7 +17,9 @@ EXTRA_COMPONENTS += [
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'RequestSyncApp.jsm',
|
||||
'RequestSyncService.jsm',
|
||||
'RequestSyncTask.jsm',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
|
@ -151,7 +151,7 @@ function test_managerRegistrationsEmpty() {
|
||||
genericError);
|
||||
}
|
||||
|
||||
function test_managerRegistrations() {
|
||||
function test_managerRegistrations(state, overwrittenMinInterval) {
|
||||
navigator.syncManager.registrations().then(
|
||||
function(results) {
|
||||
is(results.length, 1, "navigator.sync.registrations() should not return an empty array.");
|
||||
@ -166,7 +166,22 @@ function test_managerRegistrations() {
|
||||
ok("manifestURL" in results[0].app, "navigator.sync.registrations()[0].app.manifestURL is correct");
|
||||
is(results[0].app.origin, 'http://mochi.test:8888', "navigator.sync.registrations()[0].app.origin is correct");
|
||||
is(results[0].app.isInBrowserElement, false, "navigator.sync.registrations()[0].app.isInBrowserElement is correct");
|
||||
is(results[0].state, state, "navigator.sync.registrations()[0].state is correct");
|
||||
is(results[0].overwrittenMinInterval, overwrittenMinInterval, "navigator.sync.registrations()[0].overwrittenMinInterval is correct");
|
||||
ok("setPolicy" in results[0], "navigator.sync.registrations()[0].setPolicy is correct");
|
||||
runTests();
|
||||
},
|
||||
genericError);
|
||||
}
|
||||
|
||||
function test_managerSetPolicy(state, overwrittenMinInterval) {
|
||||
navigator.syncManager.registrations().then(
|
||||
function(results) {
|
||||
results[0].setPolicy(state, overwrittenMinInterval).then(
|
||||
function() {
|
||||
ok(state, results[0].state, "State matches");
|
||||
ok(overwrittenMinInterval, results[0].overwrittenMinInterval, "OverwrittenMinInterval matches");
|
||||
runTests();
|
||||
}, genericError);
|
||||
}).catch(genericError);
|
||||
}
|
||||
|
@ -38,12 +38,18 @@
|
||||
// overwrite the same registration.
|
||||
test_register,
|
||||
|
||||
test_managerRegistrations,
|
||||
function() { test_managerRegistrations('wifiOnly', 0); },
|
||||
test_registrations,
|
||||
|
||||
test_registrationEmpty,
|
||||
test_registration,
|
||||
|
||||
function() { test_managerSetPolicy('disabled', 123); },
|
||||
function() { test_managerRegistrations('disabled', 123); },
|
||||
|
||||
function() { test_managerSetPolicy('enabled', 42); },
|
||||
function() { test_managerRegistrations('enabled', 42); },
|
||||
|
||||
test_unregister,
|
||||
test_unregisterDuplicate,
|
||||
|
||||
|
@ -1209,6 +1209,10 @@ var interfaceNamesInGlobalScope =
|
||||
"SVGZoomEvent",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "RequestSyncManager", b2g: true, pref: "dom.requestSync.enabled", permission: ["requestsync-manager"] },
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "RequestSyncApp", b2g: true, pref: "dom.requestSync.enabled", permission: ["requestsync-manager"] },
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "RequestSyncTask", b2g: true, pref: "dom.requestSync.enabled", permission: ["requestsync-manager"] },
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "Telephony", b2g: true, pref: "dom.telephony.enabled"},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
@ -4,16 +4,43 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
// Rappresentation of the app in the RequestTaskFull.
|
||||
dictionary RequestTaskApp {
|
||||
USVString origin;
|
||||
USVString manifestURL;
|
||||
boolean isInBrowserElement;
|
||||
[AvailableIn=CertifiedApps,
|
||||
Pref="dom.requestSync.enabled",
|
||||
CheckPermissions="requestsync-manager",
|
||||
JSImplementation="@mozilla.org/dom/request-sync-task-app;1"]
|
||||
interface RequestSyncApp {
|
||||
readonly attribute USVString origin;
|
||||
readonly attribute USVString manifestURL;
|
||||
readonly attribute boolean isInBrowserElement;
|
||||
};
|
||||
|
||||
enum RequestSyncTaskPolicyState { "enabled", "disabled", "wifiOnly" };
|
||||
|
||||
// Like a normal task, but with info about the app.
|
||||
dictionary RequestTaskFull : RequestTask {
|
||||
RequestTaskApp app;
|
||||
[AvailableIn=CertifiedApps,
|
||||
Pref="dom.requestSync.enabled",
|
||||
CheckPermissions="requestsync-manager",
|
||||
JSImplementation="@mozilla.org/dom/request-sync-task-manager;1"]
|
||||
interface RequestSyncTask {
|
||||
// This object describes the app that is owning the task.
|
||||
readonly attribute RequestSyncApp app;
|
||||
|
||||
// Using setPolicy it's possible to owerwrite the state and the minInterval.
|
||||
readonly attribute RequestSyncTaskPolicyState state;
|
||||
readonly attribute long overwrittenMinInterval;
|
||||
|
||||
// These attributes are taken from the configuration of the task:
|
||||
|
||||
readonly attribute USVString task;
|
||||
readonly attribute DOMTimeStamp lastSync;
|
||||
readonly attribute USVString wakeUpPage;
|
||||
readonly attribute boolean oneShot;
|
||||
readonly attribute long minInterval;
|
||||
readonly attribute boolean wifiOnly;
|
||||
readonly attribute any data;
|
||||
|
||||
Promise<void> setPolicy(RequestSyncTaskPolicyState aState,
|
||||
optional long ovewrittenMinInterval);
|
||||
};
|
||||
|
||||
[NavigatorProperty="syncManager",
|
||||
@ -23,5 +50,5 @@ dictionary RequestTaskFull : RequestTask {
|
||||
JSImplementation="@mozilla.org/dom/request-sync-manager;1"]
|
||||
// This interface will be used only by the B2G SystemApp
|
||||
interface RequestSyncManager {
|
||||
Promise<sequence<RequestTaskFull>> registrations();
|
||||
Promise<sequence<RequestSyncTask>> registrations();
|
||||
};
|
||||
|
@ -15,7 +15,7 @@ dictionary RequestTaskParams {
|
||||
|
||||
|
||||
// This is the dictionary you can have back from registration{s}().
|
||||
dictionary RequestTask : RequestTaskParams {
|
||||
dictionary RequestTaskFull : RequestTaskParams {
|
||||
USVString task = "";
|
||||
|
||||
// Last synchonization date.. maybe it's useful to know.
|
||||
@ -33,6 +33,6 @@ interface RequestSyncScheduler {
|
||||
Promise<void> unregister(USVString task);
|
||||
|
||||
// Useful methods to get registrations
|
||||
Promise<sequence<RequestTask>> registrations();
|
||||
Promise<RequestTask> registration(USVString task);
|
||||
Promise<sequence<RequestTaskFull>> registrations();
|
||||
Promise<RequestTaskFull> registration(USVString task);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user