зеркало из https://github.com/mozilla/gecko-dev.git
Bug 548066 - JavaScript strict warning: clientData.js, line 194: reference to undefined property this.clients[id] [r=mconnor]
Get rid of get/setInfo on ClientEngine and ClientStore and expose functions to read/modify client data: stats, clearCommands, sendCommand. Also expose the local client information as local[ID,Name,Type,Commands] and rework the storage to use these instead of trying to keep the JS object clients entry in sync with prefs, etc. Update users of the old interface (service/tabs/chrome) to use the new local*. Set the client type based on app id instead of from each app's overlay.
This commit is contained in:
Родитель
1555ba9d3c
Коммит
1cd3c07303
|
@ -34,62 +34,94 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
const EXPORTED_SYMBOLS = ['Clients'];
|
||||
const EXPORTED_SYMBOLS = ["Clients"];
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://weave/constants.js");
|
||||
Cu.import("resource://weave/util.js");
|
||||
Cu.import("resource://weave/engines.js");
|
||||
Cu.import("resource://weave/stores.js");
|
||||
Cu.import("resource://weave/trackers.js");
|
||||
Cu.import("resource://weave/type_records/clientData.js");
|
||||
Cu.import("resource://weave/type_records/clients.js");
|
||||
|
||||
Utils.lazy(this, 'Clients', ClientEngine);
|
||||
Utils.lazy(this, "Clients", ClientEngine);
|
||||
|
||||
function ClientEngine() {
|
||||
SyncEngine.call(this, "Clients");
|
||||
|
||||
// Reset the client on every startup so that we fetch recent clients
|
||||
this._resetClient();
|
||||
Utils.prefs.addObserver("", this, false);
|
||||
}
|
||||
ClientEngine.prototype = {
|
||||
__proto__: SyncEngine.prototype,
|
||||
_storeObj: ClientStore,
|
||||
_trackerObj: ClientTracker,
|
||||
_recordObj: ClientRecord,
|
||||
_recordObj: ClientsRec,
|
||||
|
||||
// get and set info for clients
|
||||
// Aggregate some stats on the composition of clients on this account
|
||||
get stats() {
|
||||
let stats = {
|
||||
hasMobile: this.localType == "mobile",
|
||||
names: [this.localName],
|
||||
numClients: 1,
|
||||
};
|
||||
|
||||
// FIXME: callers must use the setInfo interface or changes won't get synced,
|
||||
// which is unintuitive
|
||||
for each (let {name, type} in this._store._remoteClients) {
|
||||
stats.hasMobile = stats.hasMobile || type == "mobile";
|
||||
stats.names.push(name);
|
||||
stats.numClients++;
|
||||
}
|
||||
|
||||
getClients: function ClientEngine_getClients() {
|
||||
return this._store.clients;
|
||||
return stats;
|
||||
},
|
||||
|
||||
getInfo: function ClientEngine_getInfo(id) {
|
||||
return this._store.getInfo(id);
|
||||
// Remove any commands for the local client and mark it for upload
|
||||
clearCommands: function clearCommands() {
|
||||
delete this.localCommands;
|
||||
this._tracker.addChangedID(this.localID);
|
||||
},
|
||||
|
||||
setInfo: function ClientEngine_setInfo(id, info) {
|
||||
this._store.setInfo(id, info);
|
||||
this._tracker.addChangedID(id);
|
||||
// Send a command+args pair to each remote client
|
||||
sendCommand: function sendCommand(command, args) {
|
||||
// Helper to determine if the client already has this command
|
||||
let notDupe = function(other) other.command != command ||
|
||||
JSON.stringify(other.args) != JSON.stringify(args);
|
||||
|
||||
// Package the command/args pair into an object
|
||||
let action = {
|
||||
command: command,
|
||||
args: args,
|
||||
};
|
||||
|
||||
// Send the command to each remote client
|
||||
for (let [id, client] in Iterator(this._store._remoteClients)) {
|
||||
// Set the action to be a new commands array if none exists
|
||||
if (client.commands == null)
|
||||
client.commands = [action];
|
||||
// Add the new action if there are no duplicates
|
||||
else if (client.commands.every(notDupe))
|
||||
client.commands.push(action);
|
||||
// Must have been a dupe.. skip!
|
||||
else
|
||||
continue;
|
||||
|
||||
this._log.trace("Client " + id + " got a new action: " + [command, args]);
|
||||
this._tracker.addChangedID(id);
|
||||
}
|
||||
},
|
||||
|
||||
// helpers for getting/setting this client's info directly
|
||||
|
||||
get clientID() {
|
||||
if (!Svc.Prefs.get("client.GUID"))
|
||||
Svc.Prefs.set("client.GUID", Utils.makeGUID());
|
||||
return Svc.Prefs.get("client.GUID");
|
||||
get localID() {
|
||||
// Generate a random GUID id we don't have one
|
||||
let localID = Svc.Prefs.get("client.GUID", "");
|
||||
return localID == "" ? this.localID = Utils.makeGUID() : localID;
|
||||
},
|
||||
set localID(value) Svc.Prefs.set("client.GUID", value),
|
||||
|
||||
get clientName() {
|
||||
if (Svc.Prefs.isSet("client.name"))
|
||||
return Svc.Prefs.get("client.name");
|
||||
get localName() {
|
||||
let localName = Svc.Prefs.get("client.name", "");
|
||||
if (localName != "")
|
||||
return localName;
|
||||
|
||||
// Generate a client name if we don't have a useful one yet
|
||||
let user = Svc.Env.get("USER") || Svc.Env.get("USERNAME");
|
||||
|
@ -109,38 +141,26 @@ ClientEngine.prototype = {
|
|||
}
|
||||
}
|
||||
|
||||
return this.clientName = Str.sync.get("client.name", [user, app, host]);
|
||||
return this.localName = Str.sync.get("client.name", [user, app, host]);
|
||||
},
|
||||
set clientName(value) { Svc.Prefs.set("client.name", value); },
|
||||
set localName(value) Svc.Prefs.set("client.name", value),
|
||||
|
||||
get clientType() { return Svc.Prefs.get("client.type", "desktop"); },
|
||||
set clientType(value) { Svc.Prefs.set("client.type", value); },
|
||||
|
||||
updateLocalInfo: function ClientEngine_updateLocalInfo(info) {
|
||||
// Grab data from the store if we weren't given something to start with
|
||||
if (!info)
|
||||
info = this.getInfo(this.clientID);
|
||||
|
||||
// Overwrite any existing values with the ones from the pref
|
||||
info.name = this.clientName;
|
||||
info.type = this.clientType;
|
||||
|
||||
return info;
|
||||
},
|
||||
|
||||
observe: function ClientEngine_observe(subject, topic, data) {
|
||||
switch (topic) {
|
||||
case "nsPref:changed":
|
||||
switch (data) {
|
||||
case "client.name":
|
||||
case "client.type":
|
||||
// Update the store and tracker on pref changes
|
||||
this.setInfo(this.clientID, this.updateLocalInfo());
|
||||
break;
|
||||
get localType() {
|
||||
// Figure out if we have a type previously set
|
||||
let localType = Svc.Prefs.get("client.type", "");
|
||||
if (localType == "") {
|
||||
// Assume we're desktop-like unless the app is for mobiles
|
||||
localType = "desktop";
|
||||
switch (Svc.AppInfo.ID) {
|
||||
case FENNEC_ID:
|
||||
localType = "mobile";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
this.localType = localType;
|
||||
}
|
||||
return localType;
|
||||
},
|
||||
set localType(value) Svc.Prefs.set("client.type", value),
|
||||
|
||||
// Always process incoming items because they might have commands
|
||||
_reconcile: function _reconcile() {
|
||||
|
@ -153,9 +173,6 @@ ClientEngine.prototype = {
|
|||
_wipeClient: function _wipeClient() {
|
||||
SyncEngine.prototype._resetClient.call(this);
|
||||
this._store.wipe();
|
||||
|
||||
// Make sure the local client exists after wiping
|
||||
this.setInfo(this.clientID, this.updateLocalInfo({}));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -163,72 +180,47 @@ function ClientStore(name) {
|
|||
Store.call(this, name);
|
||||
}
|
||||
ClientStore.prototype = {
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// ClientStore Attributes
|
||||
|
||||
clients: {},
|
||||
|
||||
__proto__: Store.prototype,
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// ClientStore Methods
|
||||
create: function create(record) this.update(record),
|
||||
|
||||
/**
|
||||
* Get the client by guid
|
||||
*/
|
||||
getInfo: function ClientStore_getInfo(id) this.clients[id],
|
||||
|
||||
/**
|
||||
* Set the client data for a guid. Use Engine.setInfo to update tracker.
|
||||
*/
|
||||
setInfo: function ClientStore_setInfo(id, info) {
|
||||
this._log.debug("Setting client " + id + ": " + JSON.stringify(info));
|
||||
this.clients[id] = info;
|
||||
},
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Store.prototype Methods
|
||||
|
||||
changeItemID: function ClientStore_changeItemID(oldID, newID) {
|
||||
this._log.debug("Changing id from " + oldId + " to " + newID);
|
||||
this.clients[newID] = this.clients[oldID];
|
||||
delete this.clients[oldID];
|
||||
},
|
||||
|
||||
create: function ClientStore_create(record) {
|
||||
this.update(record);
|
||||
update: function update(record) {
|
||||
// Unpack the individual components of the local client
|
||||
if (record.id == Clients.localID) {
|
||||
Clients.localName = record.name;
|
||||
Clients.localType = record.type;
|
||||
Clients.localCommands = record.commands;
|
||||
}
|
||||
else
|
||||
this._remoteClients[record.id] = record.cleartext;
|
||||
},
|
||||
|
||||
createRecord: function createRecord(guid) {
|
||||
let record = new ClientRecord();
|
||||
record.cleartext = this.clients[guid];
|
||||
let record = new ClientsRec();
|
||||
|
||||
// Package the individual components into a record for the local client
|
||||
if (guid == Clients.localID) {
|
||||
record.name = Clients.localName;
|
||||
record.type = Clients.localType;
|
||||
record.commands = Clients.localCommands;
|
||||
}
|
||||
else
|
||||
record.cleartext = this._remoteClients[guid];
|
||||
|
||||
return record;
|
||||
},
|
||||
|
||||
getAllIDs: function ClientStore_getAllIDs() this.clients,
|
||||
itemExists: function itemExists(id) id in this.getAllIDs(),
|
||||
|
||||
itemExists: function ClientStore_itemExists(id) id in this.clients,
|
||||
|
||||
remove: function ClientStore_remove(record) {
|
||||
this._log.debug("Removing client " + record.id);
|
||||
delete this.clients[record.id];
|
||||
getAllIDs: function getAllIDs() {
|
||||
let ids = {};
|
||||
ids[Clients.localID] = true;
|
||||
for (let id in this._remoteClients)
|
||||
ids[id] = true;
|
||||
return ids;
|
||||
},
|
||||
|
||||
update: function ClientStore_update(record) {
|
||||
this._log.debug("Updating client " + record.id);
|
||||
this.clients[record.id] = record.cleartext;
|
||||
},
|
||||
|
||||
wipe: function ClientStore_wipe() {
|
||||
this._log.debug("Wiping local clients store")
|
||||
this.clients = {};
|
||||
wipe: function wipe() {
|
||||
this._remoteClients = {};
|
||||
},
|
||||
};
|
||||
|
||||
function ClientTracker(name) {
|
||||
Tracker.call(this, name);
|
||||
}
|
||||
ClientTracker.prototype = {
|
||||
__proto__: Tracker.prototype,
|
||||
get score() 100 // always sync
|
||||
};
|
||||
|
|
|
@ -47,7 +47,7 @@ Cu.import("resource://weave/engines.js");
|
|||
Cu.import("resource://weave/stores.js");
|
||||
Cu.import("resource://weave/trackers.js");
|
||||
Cu.import("resource://weave/type_records/tabs.js");
|
||||
Cu.import("resource://weave/engines/clientData.js");
|
||||
Cu.import("resource://weave/engines/clients.js");
|
||||
|
||||
function TabEngine() {
|
||||
SyncEngine.call(this, "Tabs");
|
||||
|
@ -102,13 +102,11 @@ function TabStore(name) {
|
|||
}
|
||||
TabStore.prototype = {
|
||||
__proto__: Store.prototype,
|
||||
_remoteClients: {},
|
||||
|
||||
itemExists: function TabStore_itemExists(id) {
|
||||
return id == Clients.clientID;
|
||||
return id == Clients.localID;
|
||||
},
|
||||
|
||||
|
||||
getAllTabs: function getAllTabs(filter) {
|
||||
let filteredUrls = new RegExp(Svc.Prefs.get("engine.tabs.filteredUrls"), "i");
|
||||
|
||||
|
@ -147,7 +145,7 @@ TabStore.prototype = {
|
|||
|
||||
createRecord: function createRecord(guid) {
|
||||
let record = new TabSetRecord();
|
||||
record.clientName = Clients.clientName;
|
||||
record.clientName = Clients.localName;
|
||||
|
||||
// Sort tabs in descending-used order to grab the most recently used
|
||||
record.tabs = this.getAllTabs(true).sort(function(a, b) {
|
||||
|
@ -162,7 +160,7 @@ TabStore.prototype = {
|
|||
|
||||
getAllIDs: function TabStore_getAllIds() {
|
||||
let ids = {};
|
||||
ids[Clients.clientID] = true;
|
||||
ids[Clients.localID] = true;
|
||||
return ids;
|
||||
},
|
||||
|
||||
|
@ -241,7 +239,7 @@ TabTracker.prototype = {
|
|||
onTab: function onTab(event) {
|
||||
this._log.trace(event.type);
|
||||
this.score += 1;
|
||||
this._changedIDs[Clients.clientID] = true;
|
||||
this._changedIDs[Clients.localID] = true;
|
||||
|
||||
// Store a timestamp in the tab to track when it was last used
|
||||
Svc.Session.setTabValue(event.originalTarget, "weaveLastUsed",
|
||||
|
|
|
@ -62,7 +62,7 @@ Cu.import("resource://weave/base_records/keys.js");
|
|||
Cu.import("resource://weave/engines.js");
|
||||
Cu.import("resource://weave/identity.js");
|
||||
Cu.import("resource://weave/status.js");
|
||||
Cu.import("resource://weave/engines/clientData.js");
|
||||
Cu.import("resource://weave/engines/clients.js");
|
||||
|
||||
// for export
|
||||
let Weave = {};
|
||||
|
@ -78,7 +78,7 @@ Cu.import("resource://weave/stores.js", Weave);
|
|||
Cu.import("resource://weave/engines.js", Weave);
|
||||
|
||||
Cu.import("resource://weave/engines/bookmarks.js", Weave);
|
||||
Cu.import("resource://weave/engines/clientData.js", Weave);
|
||||
Cu.import("resource://weave/engines/clients.js", Weave);
|
||||
Cu.import("resource://weave/engines/forms.js", Weave);
|
||||
Cu.import("resource://weave/engines/history.js", Weave);
|
||||
Cu.import("resource://weave/engines/prefs.js", Weave);
|
||||
|
@ -1143,7 +1143,7 @@ WeaveSvc.prototype = {
|
|||
Clients.sync();
|
||||
|
||||
// Process the incoming commands if we have any
|
||||
if (Clients.getClients()[Clients.clientID].commands) {
|
||||
if (Clients.localCommands) {
|
||||
try {
|
||||
if (!(this.processCommands())) {
|
||||
Status.sync = ABORT_SYNC_COMMAND;
|
||||
|
@ -1189,16 +1189,8 @@ WeaveSvc.prototype = {
|
|||
* Process the locally stored clients list to figure out what mode to be in
|
||||
*/
|
||||
_updateClientMode: function _updateClientMode() {
|
||||
let numClients = 0;
|
||||
let hasMobile = false;
|
||||
|
||||
// Check how many and what type of clients we have
|
||||
for each (let {type} in Clients.getClients()) {
|
||||
numClients++;
|
||||
hasMobile = hasMobile || type == "mobile";
|
||||
}
|
||||
|
||||
// Nothing to do if it's the same amount
|
||||
let {numClients, hasMobile} = Clients.stats;
|
||||
if (this.numClients == numClients)
|
||||
return;
|
||||
|
||||
|
@ -1441,12 +1433,9 @@ WeaveSvc.prototype = {
|
|||
*/
|
||||
processCommands: function WeaveSvc_processCommands()
|
||||
this._notify("process-commands", "", function() {
|
||||
let info = Clients.getInfo(Clients.clientID);
|
||||
let commands = info.commands;
|
||||
|
||||
// Immediately clear out the commands as we've got them locally
|
||||
delete info.commands;
|
||||
Clients.setInfo(Clients.clientID, info);
|
||||
let commands = Clients.localCommands;
|
||||
Clients.clearCommands();
|
||||
|
||||
// Process each command in order
|
||||
for each ({command: command, args: args} in commands) {
|
||||
|
@ -1502,40 +1491,9 @@ WeaveSvc.prototype = {
|
|||
return;
|
||||
}
|
||||
|
||||
// Package the command/args pair into an object
|
||||
let action = {
|
||||
command: command,
|
||||
args: args,
|
||||
};
|
||||
let actionStr = command + "(" + args + ")";
|
||||
|
||||
// Convert args into a string to simplify array comparisons
|
||||
let jsonArgs = JSON.stringify(args);
|
||||
let notDupe = function(action) action.command != command ||
|
||||
JSON.stringify(action.args) != jsonArgs;
|
||||
|
||||
this._log.info("Sending clients: " + actionStr + "; " + commandData.desc);
|
||||
|
||||
// Add the action to each remote client
|
||||
for (let guid in Clients.getClients()) {
|
||||
// Don't send commands to the local client
|
||||
if (guid == Clients.clientID)
|
||||
continue;
|
||||
|
||||
let info = Clients.getInfo(guid);
|
||||
// Set the action to be a new commands array if none exists
|
||||
if (info.commands == null)
|
||||
info.commands = [action];
|
||||
// Add the new action if there are no duplicates
|
||||
else if (info.commands.every(notDupe))
|
||||
info.commands.push(action);
|
||||
// Must have been a dupe.. skip!
|
||||
else
|
||||
continue;
|
||||
|
||||
Clients.setInfo(guid, info);
|
||||
this._log.trace("Client " + guid + " got a new action: " + actionStr);
|
||||
}
|
||||
// Send the command to all remote clients
|
||||
this._log.debug("Sending clients: " + [command, args, commandData.desc]);
|
||||
Clients.sendCommand(command, args);
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
const EXPORTED_SYMBOLS = ['ClientRecord'];
|
||||
const EXPORTED_SYMBOLS = ["ClientsRec"];
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
@ -44,10 +44,12 @@ const Cu = Components.utils;
|
|||
Cu.import("resource://weave/util.js");
|
||||
Cu.import("resource://weave/base_records/crypto.js");
|
||||
|
||||
function ClientRecord(uri) {
|
||||
function ClientsRec(uri) {
|
||||
CryptoWrapper.call(this, uri);
|
||||
}
|
||||
ClientRecord.prototype = {
|
||||
ClientsRec.prototype = {
|
||||
__proto__: CryptoWrapper.prototype,
|
||||
_logName: "Record.Client",
|
||||
_logName: "Record.Clients",
|
||||
};
|
||||
|
||||
Utils.deferGetSet(ClientsRec, "cleartext", ["name", "type", "commands"]);
|
||||
|
|
|
@ -5,7 +5,6 @@ pref("extensions.weave.miscURL", "misc/");
|
|||
pref("extensions.weave.pwChangeURL", "https://auth.services.mozilla.com/weave-password-reset");
|
||||
pref("extensions.weave.termsURL", "https://mozillalabs.com/weave/tos/");
|
||||
|
||||
pref("extensions.weave.client.name", "Firefox");
|
||||
pref("extensions.weave.lastversion", "firstrun");
|
||||
pref("extensions.weave.autoconnect", true);
|
||||
|
||||
|
|
|
@ -1,16 +1,35 @@
|
|||
Cu.import("resource://weave/engines/clientData.js");
|
||||
Cu.import("resource://weave/engines/clients.js");
|
||||
Cu.import("resource://weave/util.js");
|
||||
Cu.import("resource://weave/base_records/keys.js");
|
||||
Cu.import("resource://weave/base_records/crypto.js");
|
||||
|
||||
function run_test() {
|
||||
let passphrase = { password: "passphrase" };
|
||||
let baseUri = "http://fakebase/";
|
||||
let pubUri = baseUri + "pubkey";
|
||||
let privUri = baseUri + "privkey";
|
||||
let cryptoUri = baseUri + "crypto";
|
||||
|
||||
_("Setting up fake pub/priv keypair and symkey for encrypt/decrypt");
|
||||
PubKeys.defaultKeyUri = baseUri + "pubkey";
|
||||
let {pubkey, privkey} = PubKeys.createKeypair(passphrase, pubUri, privUri);
|
||||
PubKeys.set(pubUri, pubkey);
|
||||
PrivKeys.set(privUri, privkey);
|
||||
let cryptoMeta = new CryptoMeta(cryptoUri);
|
||||
cryptoMeta.addUnwrappedKey(pubkey, Svc.Crypto.generateRandomKey());
|
||||
CryptoMetas.set(cryptoUri, cryptoMeta);
|
||||
|
||||
_("Test that serializing client records results in uploadable ascii");
|
||||
Clients.setInfo("ascii", {
|
||||
name: "wéävê"
|
||||
});
|
||||
Clients.__defineGetter__("cryptoMetaURL", function() cryptoUri);
|
||||
Clients.localID = "ascii";
|
||||
Clients.localName = "wéävê";
|
||||
|
||||
_("Make sure we have the expected record");
|
||||
let record = Clients._store.createRecord("ascii");
|
||||
let record = Clients._createRecord("ascii");
|
||||
do_check_eq(record.id, "ascii");
|
||||
do_check_eq(record.payload.name, "wéävê");
|
||||
do_check_eq(record.name, "wéävê");
|
||||
|
||||
record.encrypt(passphrase)
|
||||
let serialized = JSON.stringify(record);
|
||||
let checkCount = 0;
|
||||
_("Checking for all ASCII:", serialized);
|
||||
|
@ -25,11 +44,12 @@ function run_test() {
|
|||
do_check_eq(checkCount, serialized.length);
|
||||
|
||||
_("Making sure the record still looks like it did before");
|
||||
record.decrypt(passphrase)
|
||||
do_check_eq(record.id, "ascii");
|
||||
do_check_eq(record.payload.name, "wéävê");
|
||||
do_check_eq(record.name, "wéävê");
|
||||
|
||||
_("Sanity check that creating the record also gives the same");
|
||||
record = Clients._store.createRecord("ascii");
|
||||
record = Clients._createRecord("ascii");
|
||||
do_check_eq(record.id, "ascii");
|
||||
do_check_eq(record.payload.name, "wéävê");
|
||||
do_check_eq(record.name, "wéävê");
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ const modules = [
|
|||
"base_records/wbo.js",
|
||||
"constants.js",
|
||||
"engines/bookmarks.js",
|
||||
"engines/clientData.js",
|
||||
"engines/clients.js",
|
||||
"engines/forms.js",
|
||||
"engines/history.js",
|
||||
"engines/passwords.js",
|
||||
|
@ -23,7 +23,7 @@ const modules = [
|
|||
"stores.js",
|
||||
"trackers.js",
|
||||
"type_records/bookmark.js",
|
||||
"type_records/clientData.js",
|
||||
"type_records/clients.js",
|
||||
"type_records/forms.js",
|
||||
"type_records/history.js",
|
||||
"type_records/passwords.js",
|
||||
|
|
Загрузка…
Ссылка в новой задаче