add status notification to sharing dialog; fix async generators in the case where an async method is missing a yield (better error, continue execution in parent); add guts of demo sharing code to engine & store (for bookmarks, with some spillage)

This commit is contained in:
Dan Mills 2008-03-28 03:25:51 -07:00
Родитель 38ed71b0a2
Коммит 26713b0184
6 изменённых файлов: 217 добавлений и 47 удалений

Просмотреть файл

@ -2,6 +2,5 @@
<!ENTITY close.button.label "Close">
<!ENTITY share.button.label "Share">
<!ENTITY description.top "Enter a the ID of the user you wish to share your bookmarks with:">
<!ENTITY description.ok "Weave sharing complete!">
<!ENTITY description.error "Error. Please check the Weave ID and try again.">
<!ENTITY username.label "Weave ID (Email):">
<!ENTITY status.waiting "Waiting...">

Просмотреть файл

@ -0,0 +1,3 @@
status.ok = Weave sharing complete!
status.error = Error. Please check the Weave ID and try again.
status.working = Working...

Просмотреть файл

@ -219,11 +219,12 @@ Generator.prototype = {
_done: function AsyncGen__done(retval) {
if (!this._generator) {
this._log.error("Generator '" + this.name + "' called 'done' after it's finalized");
this._log.error("Async method '" + this.name + "' is missing a 'yield' call " +
"(or called done() after being finalized)");
this._log.trace("Initial stack trace:\n" + this.trace);
return;
} else {
this._generator.close();
}
this._generator.close();
this._generator = null;
this._timer = null;

Просмотреть файл

@ -685,56 +685,83 @@ Engine.prototype = {
this._log.debug("Sharing bookmarks with " + username);
this._getSymKey.async(this, self.cb);
yield;
// copied from getSymKey
this._dav.GET(this.keysFile, self.cb);
let ret = yield;
Utils.ensureStatus(ret.status, "Could not get keys file.");
let keys = this._json.decode(ret.responseText);
// get the other user's pubkey
let hash = Utils.sha1(username);
let serverURL = Utils.prefs.getCharPref("serverURL");
try {
this._getSymKey.async(this, self.cb);
yield;
// copied from getSymKey
this._log.debug("Getting keyring from server");
this._dav.GET(this.keysFile, self.cb);
let ret = yield;
Utils.ensureStatus(ret.status, "Could not get keys file.");
let keys = this._json.decode(ret.responseText);
// get the other user's pubkey
this._log.debug("Constructing other user's URL");
let hash = Utils.sha1(username);
let serverURL = Utils.prefs.getCharPref("serverURL");
this._dav.baseURL = serverURL + "user/" + hash + "/"; //FIXME: very ugly!
this._log.debug("Getting other user's public key");
this._dav.GET("public/pubkey", self.cb);
ret = yield;
Utils.ensureStatus(ret.status,
"Could not get public key for user" + username);
let id = new Identity();
id.pubkey = ret.responseText;
}
catch (e) { throw e; }
finally { this._dav.baseURL = base; }
this._dav.baseURL = base;
Utils.ensureStatus(ret.status, "Could not get public key for " + username);
// now encrypt the symkey with their pubkey and upload the new keyring
this._log.debug("Encrypting symmetric key with other user's public key");
Crypto.RSAencrypt.async(Crypto, self.cb, this._engineId.password, id);
let enckey = yield;
if (!enckey)
throw "Could not encrypt symmetric encryption key";
let id = new Identity();
id.pubkey = ret.responseText;
this._log.debug("Uploading new keyring");
keys.ring[hash] = enckey;
this._dav.PUT(this.keysFile, this._json.encode(keys), self.cb);
ret = yield;
Utils.ensureStatus(ret.status, "Could not upload keyring file.");
// now encrypt the symkey with their pubkey and upload the new keyring
Crypto.RSAencrypt.async(Crypto, self.cb, this._engineId.password, id);
let enckey = yield;
if (!enckey)
throw "Could not encrypt symmetric encryption key";
this._log.debug("All done sharing!");
keys.ring[hash] = enckey;
this._dav.PUT(this.keysFile, this._json.encode(keys), self.cb);
ret = yield;
Utils.ensureStatus(ret.status, "Could not upload keyring file.");
} catch (e) {
throw e;
this._createShare(username, username);
} finally {
this._dav.baseURL = base;
this._log.debug("All done sharing!");
self.done(true);
},
// FIXME: EEK bookmarks specific
_createShare: function Engine__createShare(id, title) {
let bms = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
getService(Ci.nsINavBookmarksService);
let ans = Cc["@mozilla.org/browser/annotation-service;1"].
getService(Ci.nsIAnnotationService);
let root;
let a = ans.getItemsWithAnnotation("weave/mounted-shares-folder", {});
if (a.length == 1)
root = a[0];
if (!root) {
root = bms.createFolder(bms.toolbarFolder, "Shared Folders",
bms.DEFAULT_INDEX);
ans.setItemAnnotation(root, "weave/mounted-shares-folder", true, 0,
ans.EXPIRE_NEVER);
}
self.done();
let item
a = ans.getItemsWithAnnotation("weave/mounted-share-id", {});
for (let i = 0; i < a.length; i++) {
if (ans.getItemAnnotation(a[i], "weave/mounted-share-id") == id) {
item = a[i];
break;
}
}
if (!item) {
let newId = bms.createFolder(root, title, bms.DEFAULT_INDEX);
ans.setItemAnnotation(newId, "weave/mounted-share-id", id, 0,
ans.EXPIRE_NEVER);
}
},
sync: function Engine_sync(onComplete) {
@ -774,6 +801,93 @@ BookmarksEngine.prototype = {
if (!this.__store)
this.__store = new BookmarksStore();
return this.__store;
},
syncMounts: function BmkEngine_syncMounts(onComplete) {
this._syncMounts.async(this, onComplete);
},
_syncMounts: function BmkEngine__syncMounts() {
let self = yield;
let mounts = this._store.findMounts();
for (i = 0; i < mounts.length; i++) {
try {
this._syncOneMount.async(this, self.cb, mounts[i]);
yield;
} catch (e) {
this._log.warn("Could not sync shared folder from " + mounts[i].userid);
this._log.trace(Utils.stackTrace(e));
}
}
},
_syncOneMount: function BmkEngine__syncOneMount(mountData) {
let self = yield;
let user = mountData.userid;
let base = this._dav.baseURL;
let serverURL = Utils.prefs.getCharPref("serverURL");
let snap = new SnapshotStore();
this._log.debug("Syncing shared folder from user " + user);
try {
let hash = Utils.sha1(user);
this._dav.baseURL = serverURL + "user/" + hash + "/"; //FIXME: very ugly!
this._getSymKey.async(this, self.cb);
yield;
this._log.trace("Getting status file for " + user);
this._dav.GET(this.statusFile, self.cb);
let resp = yield;
Utils.ensureStatus(resp.status, "Could not download status file.");
let status = this._json.decode(resp.responseText);
this._log.trace("Downloading server snapshot for " + user);
this._dav.GET(this.snapshotFile, self.cb);
resp = yield;
Utils.ensureStatus(resp.status, "Could not download snapshot.");
Crypto.PBEdecrypt.async(Crypto, self.cb, resp.responseText,
this._engineId, status.snapEncryption);
let data = yield;
snap.data = this._json.decode(data);
this._log.trace("Downloading server deltas for " + user);
this._dav.GET(this.deltasFile, self.cb);
resp = yield;
Utils.ensureStatus(resp.status, "Could not download deltas.");
Crypto.PBEdecrypt.async(Crypto, self.cb, resp.responseText,
this._engineId, status.deltasEncryption);
data = yield;
deltas = this._json.decode(data);
}
catch (e) { throw e; }
finally { this._dav.baseURL = base; }
// apply deltas to get current snapshot
for (var i = 0; i < deltas.length; i++) {
snap.applyCommands.async(snap, self.cb, deltas[i]);
yield;
}
// prune tree / get what we want
for (let guid in snap.data) {
if (snap.data[guid].type != "bookmark")
delete snap.data[guid];
else
snap.data[guid].parentGUID = mountData.rootGUID;
}
this._log.trace("Got bookmarks fror " + user + ", comparing with local copy");
this._core.detectUpdates(self.cb, mountData.snapshot, snap.data);
let diff = yield;
// FIXME: should make sure all GUIDs here live under the mountpoint
this._log.trace("Applying changes to folder from " + user);
this._store.applyCommands.async(this._store, self.cb, diff);
yield;
this._log.trace("Shared folder from " + user + " successfully synced!");
}
};
BookmarksEngine.prototype.__proto__ = new Engine();

Просмотреть файл

@ -512,6 +512,8 @@ WeaveSvc.prototype = {
this._notify(this._bmkEngine.name + ":sync",
engineCb, this._bmkEngine).async(this, innerSelf.cb);
yield;
this._bmkEngine.syncMounts(innerSelf.cb);
yield;
}
if (Utils.prefs.getBoolPref("history")) {
this._notify(this._histEngine.name + ":sync",
@ -569,11 +571,13 @@ WeaveSvc.prototype = {
let cb = function Weave_shareBookmarks() {
let innerSelf = yield;
this._bmkEngine.share(innerSelf.cb, username);
yield;
let ret = yield;
innerSelf.done(ret);
};
this._lock(this._notify("share-bookmarks", cb)).async(this, self.cb);
yield;
let ret = yield;
self.done(ret);
}
};

Просмотреть файл

@ -385,6 +385,15 @@ BookmarksStore.prototype = {
Utils.makeURI(command.data.feedURI),
command.data.index);
break;
case "mounted-share":
this._log.debug(" -> creating share mountpoint \"" + command.data.title + "\"");
newId = this._bms.createFolder(parentId,
command.data.title,
command.data.index);
this._ans.setItemAnnotation(newId, "weave/mounted-share-id",
command.data.mountId, 0, this._ans.EXPIRE_NEVER);
break;
case "separator":
this._log.debug(" -> creating separator");
newId = this._bms.insertSeparator(parentId, command.data.index);
@ -508,7 +517,7 @@ BookmarksStore.prototype = {
return this._hsvc.executeQuery(query, this._hsvc.getNewQueryOptions()).root;
},
__wrap: function BSS__wrap(node, items, parentGUID, index, guidOverride) {
__wrap: function BSS___wrap(node, items, parentGUID, index, guidOverride) {
let GUID, item;
// we override the guid for the root items, "menu", "toolbar", etc.
@ -527,6 +536,14 @@ BookmarksStore.prototype = {
let feedURI = this._ls.getFeedURI(node.itemId);
item.siteURI = siteURI? siteURI.spec : "";
item.feedURI = feedURI? feedURI.spec : "";
} else if (this._ans.itemHasAnnotation(node.itemId,
"weave/mounted-share-id")) {
item.type = "mounted-share";
item.title = node.title;
item.mountId = this._ans.getItemAnnotation(node.itemId,
"weave/mounted-share-id");
} else {
item.type = "folder";
node.QueryInterface(Ci.nsINavHistoryQueryResultNode);
@ -567,10 +584,32 @@ BookmarksStore.prototype = {
},
// helper
_wrap: function BStore_wrap(node, items, rootName) {
_wrap: function BStore__wrap(node, items, rootName) {
return this.__wrap(node, items, null, null, rootName);
},
_wrapMount: function BStore__wrapMount(node, id) {
if (node.type != node.RESULT_TYPE_FOLDER)
throw "Trying to wrap a non-folder mounted share";
let GUID = this._bms.getItemGUID(node.itemId);
let ret = {rootGUID: GUID, userid: id, snapshot: {}};
node.QueryInterface(Ci.nsINavHistoryQueryResultNode);
node.containerOpen = true;
for (var i = 0; i < node.childCount; i++) {
this.__wrap(node.getChild(i), ret.snapshot, GUID, i);
}
// remove any share mountpoints
for (let guid in ret.snapshot) {
if (ret.snapshot[guid].type == "mounted-share")
delete ret.snapshot[guid];
}
return ret;
},
_resetGUIDs: function BSS__resetGUIDs(node) {
if (this._ans.itemHasAnnotation(node.itemId, "placesInternal/GUID"))
this._ans.removeItemAnnotation(node.itemId, "placesInternal/GUID");
@ -585,6 +624,16 @@ BookmarksStore.prototype = {
}
},
findMounts: function BStore_findMounts() {
let ret = [];
let a = this._ans.getItemsWithAnnotation("weave/mounted-share-id", {});
for (let i = 0; i < a.length; i++) {
let id = this._ans.getItemAnnotation(a[i], "weave/mounted-share-id");
ret.push(this._wrapMount(this._getNode(a[i]), id));
}
return ret;
},
wrap: function BStore_wrap() {
var items = {};
this._wrap(this._getNode(this._bms.bookmarksMenuFolder), items, "menu");