mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
locking fixes (still commented out); better error checking; fail if the remote format version is higher than we can read; refactor generator code, bring back asyncRun()
This commit is contained in:
parent
d05e5bd087
commit
7f9b691df6
@ -272,6 +272,7 @@ BookmarksSyncService.prototype = {
|
|||||||
items[guid] = item;
|
items[guid] = item;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// FIXME: this won't work for deep objects, or objects with optional properties
|
||||||
_getEdits: function BSS__getEdits(a, b) {
|
_getEdits: function BSS__getEdits(a, b) {
|
||||||
// check the type separately, just in case
|
// check the type separately, just in case
|
||||||
if (a.type != b.type)
|
if (a.type != b.type)
|
||||||
@ -447,13 +448,12 @@ BookmarksSyncService.prototype = {
|
|||||||
// [[[dcA1, dcB1], [dcA2. dcB2], ...],
|
// [[[dcA1, dcB1], [dcA2. dcB2], ...],
|
||||||
// [2dcA1, 2dcA2, ...], [2dcB1, 2dcB2, ...]]
|
// [2dcA1, 2dcA2, ...], [2dcB1, 2dcB2, ...]]
|
||||||
|
|
||||||
_reconcile: function BSS__reconcile(onComplete, commandLists) {
|
_reconcile: function BSS__reconcile(onComplete, listA, listB) {
|
||||||
let generator = yield;
|
let generator = yield;
|
||||||
this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||||
let handlers = this._handlersForGenerator(generator);
|
let handlers = generatorHandlers(generator);
|
||||||
let listener = new EventListener(handlers['complete']);
|
let listener = new EventListener(handlers['complete']);
|
||||||
|
|
||||||
let [listA, listB] = commandLists;
|
|
||||||
let propagations = [[], []];
|
let propagations = [[], []];
|
||||||
let conflicts = [[], []];
|
let conflicts = [[], []];
|
||||||
|
|
||||||
@ -514,7 +514,7 @@ BookmarksSyncService.prototype = {
|
|||||||
|
|
||||||
this._timer = null;
|
this._timer = null;
|
||||||
let ret = {propagations: propagations, conflicts: conflicts};
|
let ret = {propagations: propagations, conflicts: conflicts};
|
||||||
this._generatorDone(onComplete, ret);
|
generatorDone(this, onComplete, ret);
|
||||||
|
|
||||||
// shutdown protocol
|
// shutdown protocol
|
||||||
let cookie = yield;
|
let cookie = yield;
|
||||||
@ -724,24 +724,43 @@ BookmarksSyncService.prototype = {
|
|||||||
|
|
||||||
_doSync: function BSS__doSync() {
|
_doSync: function BSS__doSync() {
|
||||||
var generator = yield;
|
var generator = yield;
|
||||||
var handlers = this._handlersForGenerator(generator);
|
var handlers = generatorHandlers(generator);
|
||||||
|
|
||||||
this._os.notifyObservers(null, "bookmarks-sync:start", "");
|
this._os.notifyObservers(null, "bookmarks-sync:start", "");
|
||||||
this.notice("Beginning sync");
|
this.notice("Beginning sync");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
//this._dav.lock(handlers);
|
// if (!asyncRun(this._dav, this._dav.lock, handlers.complete))
|
||||||
//var data = yield;
|
// return;
|
||||||
var data;
|
// let locked = yield;
|
||||||
|
//
|
||||||
|
// if (locked)
|
||||||
|
// this.notice("Lock acquired");
|
||||||
|
// else {
|
||||||
|
// this.notice("Could not acquire lock, aborting");
|
||||||
|
// FIXME
|
||||||
|
// this.notice("Could not acquire lock, attempting to steal it");
|
||||||
|
//
|
||||||
|
// if (!asyncRun(this._dav, this._dav.stealLock, handlers.complete))
|
||||||
|
// return;
|
||||||
|
// let stolen = yield;
|
||||||
|
//
|
||||||
|
// if (stolen)
|
||||||
|
// this.notice("Lock stolen");
|
||||||
|
// else {
|
||||||
|
// this.notice("Could not steal lock, aborting");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
var localJson = this._getBookmarks();
|
var localJson = this._getBookmarks();
|
||||||
//this.notice("local json:\n" + this._mungeNodes(localJson));
|
//this.notice("local json:\n" + this._mungeNodes(localJson));
|
||||||
|
|
||||||
// 1) Fetch server deltas
|
// 1) Fetch server deltas
|
||||||
let gsd_gen = this._getServerData(handlers['complete'], localJson);
|
if (asyncRun(this, this._getServerData, handlers.complete, localJson))
|
||||||
gsd_gen.next(); // must initialize before sending
|
|
||||||
gsd_gen.send(gsd_gen);
|
|
||||||
let server = yield;
|
let server = yield;
|
||||||
|
else
|
||||||
|
return
|
||||||
|
|
||||||
this.notice("Local snapshot version: " + this._snapshotVersion);
|
this.notice("Local snapshot version: " + this._snapshotVersion);
|
||||||
this.notice("Server status: " + server.status);
|
this.notice("Server status: " + server.status);
|
||||||
@ -757,12 +776,6 @@ BookmarksSyncService.prototype = {
|
|||||||
this.notice("Server snapVersion: " + server.snapVersion);
|
this.notice("Server snapVersion: " + server.snapVersion);
|
||||||
this.notice("Server updates: " + this._mungeCommands(server.updates));
|
this.notice("Server updates: " + this._mungeCommands(server.updates));
|
||||||
|
|
||||||
// if (server['status'] == 2) {
|
|
||||||
// this._os.notifyObservers(null, "bookmarks-sync:end", "");
|
|
||||||
// this.notice("Sync complete");
|
|
||||||
// return;
|
|
||||||
// } else
|
|
||||||
|
|
||||||
// 2) Generate local deltas from snapshot -> current client status
|
// 2) Generate local deltas from snapshot -> current client status
|
||||||
|
|
||||||
let localUpdates = this._detectUpdates(this._snapshot, localJson);
|
let localUpdates = this._detectUpdates(this._snapshot, localJson);
|
||||||
@ -778,13 +791,13 @@ BookmarksSyncService.prototype = {
|
|||||||
// 3) Reconcile client/server deltas and generate new deltas for them.
|
// 3) Reconcile client/server deltas and generate new deltas for them.
|
||||||
|
|
||||||
this.notice("Reconciling client/server updates");
|
this.notice("Reconciling client/server updates");
|
||||||
let rec_gen = this._reconcile(handlers.load,
|
if (asyncRun(this, this._reconcile, handlers.complete,
|
||||||
[localUpdates, server.updates]);
|
localUpdates, server.updates))
|
||||||
rec_gen.next(); // must initialize before sending
|
|
||||||
rec_gen.send(rec_gen);
|
|
||||||
let ret = yield;
|
let ret = yield;
|
||||||
|
else
|
||||||
|
return
|
||||||
// FIXME: Need to come up with a closing protocol for generators
|
// FIXME: Need to come up with a closing protocol for generators
|
||||||
rec_gen.close();
|
//rec_gen.close();
|
||||||
|
|
||||||
let clientChanges = [];
|
let clientChanges = [];
|
||||||
let serverChanges = [];
|
let serverChanges = [];
|
||||||
@ -873,8 +886,14 @@ BookmarksSyncService.prototype = {
|
|||||||
this._os.notifyObservers(null, "bookmarks-sync:end", "");
|
this._os.notifyObservers(null, "bookmarks-sync:end", "");
|
||||||
this.notice("Sync complete");
|
this.notice("Sync complete");
|
||||||
} finally {
|
} finally {
|
||||||
//this._dav.unlock(handlers);
|
// FIXME
|
||||||
//data = yield;
|
// if (!asyncRun(this._dav, this._dav.unlock, handlers.complete))
|
||||||
|
// return;
|
||||||
|
// let unlocked = yield;
|
||||||
|
// if (unlocked)
|
||||||
|
// this.notice("Lock released");
|
||||||
|
// else
|
||||||
|
// this.notice("Error: could not unlock DAV collection");
|
||||||
this._os.notifyObservers(null, "bookmarks-sync:end", "");
|
this._os.notifyObservers(null, "bookmarks-sync:end", "");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -899,11 +918,9 @@ BookmarksSyncService.prototype = {
|
|||||||
* the relevant deltas (from our snapshot version to current),
|
* the relevant deltas (from our snapshot version to current),
|
||||||
* combined into a single set.
|
* combined into a single set.
|
||||||
*/
|
*/
|
||||||
// FIXME: this function needs to get check the remote format version and bail out earlier if needed
|
|
||||||
// FIXME: deal with errors!
|
|
||||||
_getServerData: function BSS__getServerData(onComplete, localJson) {
|
_getServerData: function BSS__getServerData(onComplete, localJson) {
|
||||||
let generator = yield;
|
let generator = yield;
|
||||||
let handlers = this._handlersForGenerator(generator);
|
let handlers = generatorHandlers(generator);
|
||||||
|
|
||||||
let ret = {status: -1,
|
let ret = {status: -1,
|
||||||
formatVersion: null, maxVersion: null, snapVersion: null,
|
formatVersion: null, maxVersion: null, snapVersion: null,
|
||||||
@ -920,6 +937,14 @@ BookmarksSyncService.prototype = {
|
|||||||
let status = eval(statusResp.target.responseText);
|
let status = eval(statusResp.target.responseText);
|
||||||
let snap, deltas, allDeltas;
|
let snap, deltas, allDeltas;
|
||||||
|
|
||||||
|
// Bail out if the server has a newer format version than we can parse
|
||||||
|
if (status.formatVersion > STORAGE_FORMAT_VERSION) {
|
||||||
|
this.notice("Error: server uses storage format v" + status.formatVersion +
|
||||||
|
", this client understands up to v" + STORAGE_FORMAT_VERSION);
|
||||||
|
generatorDone(this, onComplete, ret)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (status.guid != this._snapshotGuid) {
|
if (status.guid != this._snapshotGuid) {
|
||||||
this.notice("Remote/local sync guids do not match. " +
|
this.notice("Remote/local sync guids do not match. " +
|
||||||
"Forcing initial sync.");
|
"Forcing initial sync.");
|
||||||
@ -935,19 +960,22 @@ BookmarksSyncService.prototype = {
|
|||||||
this.notice("Downloading server snapshot");
|
this.notice("Downloading server snapshot");
|
||||||
this._dav.GET("bookmarks-snapshot.json", handlers);
|
this._dav.GET("bookmarks-snapshot.json", handlers);
|
||||||
let snapResp = yield;
|
let snapResp = yield;
|
||||||
if (snapResp.target.status == 200)
|
if (snapResp.target.status < 200 || snapResp.target.status >= 300) {
|
||||||
snap = eval(snapResp.target.responseText);
|
|
||||||
else
|
|
||||||
this.notice("Error: could not download server snapshot");
|
this.notice("Error: could not download server snapshot");
|
||||||
|
generatorDone(this, onComplete, ret)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
snap = eval(snapResp.target.responseText);
|
||||||
|
|
||||||
this.notice("Downloading server deltas");
|
this.notice("Downloading server deltas");
|
||||||
this._dav.GET("bookmarks-deltas.json", handlers);
|
this._dav.GET("bookmarks-deltas.json", handlers);
|
||||||
let deltasResp = yield;
|
let deltasResp = yield;
|
||||||
if (deltasResp.target.status == 200)
|
if (deltasResp.target.status < 200 || deltasResp.target.status >= 300) {
|
||||||
allDeltas = eval(deltasResp.target.responseText);
|
|
||||||
else
|
|
||||||
this.notice("Error: could not download server deltas");
|
this.notice("Error: could not download server deltas");
|
||||||
|
generatorDone(this, onComplete, ret)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
allDeltas = eval(deltasResp.target.responseText);
|
||||||
deltas = eval(uneval(allDeltas));
|
deltas = eval(uneval(allDeltas));
|
||||||
|
|
||||||
} else if (this._snapshotVersion >= status.snapVersion &&
|
} else if (this._snapshotVersion >= status.snapVersion &&
|
||||||
@ -957,13 +985,13 @@ BookmarksSyncService.prototype = {
|
|||||||
this.notice("Downloading server deltas");
|
this.notice("Downloading server deltas");
|
||||||
this._dav.GET("bookmarks-deltas.json", handlers);
|
this._dav.GET("bookmarks-deltas.json", handlers);
|
||||||
let deltasResp = yield;
|
let deltasResp = yield;
|
||||||
if (deltasResp.target.status == 200)
|
if (deltasResp.target.status < 200 || deltasResp.target.status >= 300) {
|
||||||
allDeltas = eval(deltasResp.target.responseText);
|
|
||||||
else
|
|
||||||
this.notice("Error: could not download server deltas");
|
this.notice("Error: could not download server deltas");
|
||||||
|
generatorDone(this, onComplete, ret)
|
||||||
let start = this._snapshotVersion - status.snapVersion;
|
return;
|
||||||
deltas = allDeltas.slice(start);
|
}
|
||||||
|
allDeltas = eval(deltasResp.target.responseText);
|
||||||
|
deltas = allDeltas.slice(this._snapshotVersion - status.snapVersion);
|
||||||
|
|
||||||
} else if (this._snapshotVersion == status.maxVersion) {
|
} else if (this._snapshotVersion == status.maxVersion) {
|
||||||
snap = eval(uneval(this._snapshot));
|
snap = eval(uneval(this._snapshot));
|
||||||
@ -972,16 +1000,18 @@ BookmarksSyncService.prototype = {
|
|||||||
this.notice("Downloading server deltas");
|
this.notice("Downloading server deltas");
|
||||||
this._dav.GET("bookmarks-deltas.json", handlers);
|
this._dav.GET("bookmarks-deltas.json", handlers);
|
||||||
let deltasResp = yield;
|
let deltasResp = yield;
|
||||||
if (deltasResp.target.status == 200)
|
if (deltasResp.target.status < 200 || deltasResp.target.status >= 300) {
|
||||||
allDeltas = eval(deltasResp.target.responseText);
|
|
||||||
else
|
|
||||||
this.notice("Error: could not download server deltas");
|
this.notice("Error: could not download server deltas");
|
||||||
|
generatorDone(this, onComplete, ret)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
allDeltas = eval(deltasResp.target.responseText);
|
||||||
deltas = [];
|
deltas = [];
|
||||||
|
|
||||||
} else { // this._snapshotVersion > status.maxVersion
|
} else { // this._snapshotVersion > status.maxVersion
|
||||||
this.notice("Error: server snapshot is older than local snapshot");
|
this.notice("Error: server snapshot is older than local snapshot");
|
||||||
// FIXME: eep?
|
generatorDone(this, onComplete, ret)
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < deltas.length; i++) {
|
for (var i = 0; i < deltas.length; i++) {
|
||||||
@ -1004,14 +1034,22 @@ BookmarksSyncService.prototype = {
|
|||||||
this._snapshotVersion = 0;
|
this._snapshotVersion = 0;
|
||||||
this._snapshotGuid = null; // in case there are other snapshots out there
|
this._snapshotGuid = null; // in case there are other snapshots out there
|
||||||
|
|
||||||
// FIXME: hmm check status for each and bail out earlier on error?
|
|
||||||
|
|
||||||
this._dav.PUT("bookmarks-snapshot.json",
|
this._dav.PUT("bookmarks-snapshot.json",
|
||||||
uneval(this._snapshot), handlers);
|
uneval(this._snapshot), handlers);
|
||||||
let snapPut = yield;
|
let snapPut = yield;
|
||||||
|
if (snapPut.target.status < 200 || snapPut.target.status >= 300) {
|
||||||
|
this.notice("Error: could not upload snapshot to server");
|
||||||
|
generatorDone(this, onComplete, ret)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this._dav.PUT("bookmarks-deltas.json", uneval([]), handlers);
|
this._dav.PUT("bookmarks-deltas.json", uneval([]), handlers);
|
||||||
let deltasPut = yield;
|
let deltasPut = yield;
|
||||||
|
if (deltasPut.target.status < 200 || deltasPut.target.status >= 300) {
|
||||||
|
this.notice("Error: could not upload deltas to server");
|
||||||
|
generatorDone(this, onComplete, ret)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this._dav.PUT("bookmarks-status.json",
|
this._dav.PUT("bookmarks-status.json",
|
||||||
uneval({guid: this._snapshotGuid,
|
uneval({guid: this._snapshotGuid,
|
||||||
@ -1019,16 +1057,14 @@ BookmarksSyncService.prototype = {
|
|||||||
snapVersion: this._snapshotVersion,
|
snapVersion: this._snapshotVersion,
|
||||||
maxVersion: this._snapshotVersion}), handlers);
|
maxVersion: this._snapshotVersion}), handlers);
|
||||||
let statusPut = yield;
|
let statusPut = yield;
|
||||||
|
if (statusPut.target.status < 200 || statusPut.target.status >= 300) {
|
||||||
|
this.notice("Error: could not upload status file to server");
|
||||||
|
generatorDone(this, onComplete, ret)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (snapPut.target.status >= 200 && snapPut.target.status < 300 &&
|
|
||||||
deltasPut.target.status >= 200 && deltasPut.target.status < 300 &&
|
|
||||||
statusPut.target.status >= 200 && statusPut.target.status < 300) {
|
|
||||||
this.notice("Initial upload to server successful");
|
this.notice("Initial upload to server successful");
|
||||||
this._saveSnapshot();
|
this._saveSnapshot();
|
||||||
} else {
|
|
||||||
// FIXME: eep?
|
|
||||||
this.notice("Error: could not upload files to server");
|
|
||||||
}
|
|
||||||
|
|
||||||
ret.status = 0;
|
ret.status = 0;
|
||||||
ret.formatVersion = STORAGE_FORMAT_VERSION;
|
ret.formatVersion = STORAGE_FORMAT_VERSION;
|
||||||
@ -1044,35 +1080,7 @@ BookmarksSyncService.prototype = {
|
|||||||
statusResp.target.status);
|
statusResp.target.status);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
this._generatorDone(onComplete, ret)
|
generatorDone(this, onComplete, ret)
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
_handlersForGenerator: function BSS__handlersForGenerator(generator) {
|
|
||||||
var h = {load: bind2(this, function(data) { continueGenerator(generator, data); }),
|
|
||||||
error: bind2(this, function(data) { this.notice("Request failed: " + uneval(data)); })};
|
|
||||||
h['complete'] = h['load'];
|
|
||||||
return h;
|
|
||||||
},
|
|
||||||
|
|
||||||
// generators called using asyncRun can't simply call the callback
|
|
||||||
// with the return value, since that would cause the calling
|
|
||||||
// function to end up running (after the yield) from inside the
|
|
||||||
// generator. Instead, generators can call this method which sets
|
|
||||||
// up a timer to call the callback from a timer (and cleans up the
|
|
||||||
// timer to avoid leaks).
|
|
||||||
_generatorDone: function BSS__generatorDone(callback, retval) {
|
|
||||||
if (this._timer)
|
|
||||||
throw "Called generatorDone when there is a timer already set."
|
|
||||||
|
|
||||||
let cb = bind2(this, function(event) {
|
|
||||||
this._timer = null;
|
|
||||||
callback(retval);
|
|
||||||
});
|
|
||||||
|
|
||||||
this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
|
||||||
this._timer.initWithCallback(new EventListener(cb),
|
|
||||||
0, this._timer.TYPE_ONE_SHOT);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onLogin: function BSS__onLogin(event) {
|
_onLogin: function BSS__onLogin(event) {
|
||||||
@ -1098,9 +1106,7 @@ BookmarksSyncService.prototype = {
|
|||||||
// nsIBookmarksSyncService
|
// nsIBookmarksSyncService
|
||||||
|
|
||||||
sync: function BSS_sync() {
|
sync: function BSS_sync() {
|
||||||
let sync_gen = this._doSync();
|
asyncRun(this, this._doSync);
|
||||||
sync_gen.next(); // must initialize before sending
|
|
||||||
sync_gen.send(sync_gen);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
login: function BSS_login() {
|
login: function BSS_login() {
|
||||||
@ -1144,10 +1150,26 @@ function bind2(object, method) {
|
|||||||
return function innerBind() { return method.apply(object, arguments); }
|
return function innerBind() { return method.apply(object, arguments); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function asyncRun(object, method, onComplete, extra) {
|
||||||
|
let args = Array.prototype.slice.call(arguments, 2); // onComplete + extra + ...
|
||||||
|
let ret = false;
|
||||||
|
try {
|
||||||
|
let gen = method.apply(object, args);
|
||||||
|
gen.next(); // must initialize before sending
|
||||||
|
gen.send(gen);
|
||||||
|
ret = true;
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof StopIteration)
|
||||||
|
dump("Warning: generator stopped unexpectedly");
|
||||||
|
else
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
function continueGenerator(generator, data) {
|
function continueGenerator(generator, data) {
|
||||||
try { generator.send(data); }
|
try { generator.send(data); }
|
||||||
catch (e) {
|
catch (e) {
|
||||||
//notice("continueGenerator exception! - " + e);
|
|
||||||
if (e instanceof StopIteration)
|
if (e instanceof StopIteration)
|
||||||
generator = null;
|
generator = null;
|
||||||
else
|
else
|
||||||
@ -1155,6 +1177,33 @@ function continueGenerator(generator, data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function generatorHandlers(generator) {
|
||||||
|
let cb = function(data) {
|
||||||
|
continueGenerator(generator, data);
|
||||||
|
};
|
||||||
|
return {load: cb, error: cb, complete: cb};
|
||||||
|
}
|
||||||
|
|
||||||
|
// generators called using asyncRun can't simply call the callback
|
||||||
|
// with the return value, since that would cause the calling
|
||||||
|
// function to end up running (after the yield) from inside the
|
||||||
|
// generator. Instead, generators can call this method which sets
|
||||||
|
// up a timer to call the callback from a timer (and cleans up the
|
||||||
|
// timer to avoid leaks).
|
||||||
|
function generatorDone(object, callback, retval) {
|
||||||
|
if (object._timer)
|
||||||
|
throw "Called generatorDone when there is a timer already set."
|
||||||
|
|
||||||
|
let cb = bind2(object, function(event) {
|
||||||
|
object._timer = null;
|
||||||
|
callback(retval);
|
||||||
|
});
|
||||||
|
|
||||||
|
object._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||||
|
object._timer.initWithCallback(new EventListener(cb),
|
||||||
|
0, object._timer.TYPE_ONE_SHOT);
|
||||||
|
}
|
||||||
|
|
||||||
function EventListener(handler) {
|
function EventListener(handler) {
|
||||||
this._handler = handler;
|
this._handler = handler;
|
||||||
}
|
}
|
||||||
@ -1179,15 +1228,26 @@ EventListener.prototype = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function xpath(xmlDoc, xpathString) {
|
||||||
|
let root = xmlDoc.ownerDocument == null ?
|
||||||
|
xmlDoc.documentElement : xmlDoc.ownerDocument.documentElement
|
||||||
|
let nsResolver = xmlDoc.createNSResolver(root);
|
||||||
|
|
||||||
|
return xmlDoc.evaluate(xpathString, xmlDoc, nsResolver,
|
||||||
|
Ci.nsIDOMXPathResult.ANY_TYPE, null);
|
||||||
|
}
|
||||||
|
|
||||||
function DAVCollection(baseURL) {
|
function DAVCollection(baseURL) {
|
||||||
this._baseURL = baseURL;
|
this._baseURL = baseURL;
|
||||||
this._authProvider = new DummyAuthProvider();
|
this._authProvider = new DummyAuthProvider();
|
||||||
}
|
}
|
||||||
DAVCollection.prototype = {
|
DAVCollection.prototype = {
|
||||||
_loggedIn: false,
|
__dp: null,
|
||||||
|
get _dp() {
|
||||||
get baseURL() {
|
if (!this.__dp)
|
||||||
return this._baseURL;
|
this.__dp = Cc["@mozilla.org/xmlextras/domparser;1"].
|
||||||
|
createInstance(Ci.nsIDOMParser);
|
||||||
|
return this.__dp;
|
||||||
},
|
},
|
||||||
|
|
||||||
__base64: {},
|
__base64: {},
|
||||||
@ -1202,6 +1262,11 @@ DAVCollection.prototype = {
|
|||||||
return this.__base64;
|
return this.__base64;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
get baseURL() {
|
||||||
|
return this._baseURL;
|
||||||
|
},
|
||||||
|
|
||||||
|
_loggedIn: false,
|
||||||
_authString: null,
|
_authString: null,
|
||||||
_currentUserPath: "nobody",
|
_currentUserPath: "nobody",
|
||||||
|
|
||||||
@ -1242,6 +1307,8 @@ DAVCollection.prototype = {
|
|||||||
headers = {'Content-type': 'text/plain'};
|
headers = {'Content-type': 'text/plain'};
|
||||||
if (this._authString)
|
if (this._authString)
|
||||||
headers['Authorization'] = this._authString;
|
headers['Authorization'] = this._authString;
|
||||||
|
if (this._token)
|
||||||
|
headers['If'] = "(<" + this._token + ">)";
|
||||||
|
|
||||||
var request = this._makeRequest("GET", path, handlers, headers);
|
var request = this._makeRequest("GET", path, handlers, headers);
|
||||||
request.send(null);
|
request.send(null);
|
||||||
@ -1252,6 +1319,8 @@ DAVCollection.prototype = {
|
|||||||
headers = {'Content-type': 'text/plain'};
|
headers = {'Content-type': 'text/plain'};
|
||||||
if (this._authString)
|
if (this._authString)
|
||||||
headers['Authorization'] = this._authString;
|
headers['Authorization'] = this._authString;
|
||||||
|
if (this._token)
|
||||||
|
headers['If'] = "(<" + this._token + ">)";
|
||||||
|
|
||||||
var request = this._makeRequest("PUT", path, handlers, headers);
|
var request = this._makeRequest("PUT", path, handlers, headers);
|
||||||
request.send(data);
|
request.send(data);
|
||||||
@ -1352,52 +1421,113 @@ DAVCollection.prototype = {
|
|||||||
|
|
||||||
// Locking
|
// Locking
|
||||||
|
|
||||||
// FIXME: make this function not reentrant
|
_getActiveLock: function DC__getActiveLock(onComplete) {
|
||||||
lock: function DC_lock(handlers) {
|
let generator = yield;
|
||||||
this._lockHandlers = handlers;
|
let handlers = generatorHandlers(generator);
|
||||||
internalHandlers = {load: bind2(this, this._onLock),
|
|
||||||
error: bind2(this, this._onLockError)};
|
let headers = {'Content-Type': 'text/xml; charset="utf-8"',
|
||||||
|
'Depth': '0'};
|
||||||
|
if (this._authString)
|
||||||
|
headers['Authorization'] = this._authString;
|
||||||
|
|
||||||
|
let request = this._makeRequest("PROPFIND", "", handlers, headers);
|
||||||
|
request.send("<?xml version=\"1.0\" encoding=\"utf-8\" ?>" +
|
||||||
|
"<D:propfind xmlns:D='DAV:'>" +
|
||||||
|
"<D:prop><D:lockdiscovery/></D:prop>" +
|
||||||
|
"</D:propfind>");
|
||||||
|
let event = yield;
|
||||||
|
let tokens = xpath(event.target.responseXML, '//D:locktoken');
|
||||||
|
let token = tokens.iterateNext();
|
||||||
|
if (token)
|
||||||
|
generatorDone(this, onComplete, token.textContent);
|
||||||
|
else
|
||||||
|
generatorDone(this, onComplete, null);
|
||||||
|
},
|
||||||
|
|
||||||
|
lock: function DC_lock(onComplete) {
|
||||||
|
let generator = yield;
|
||||||
|
let handlers = generatorHandlers(generator);
|
||||||
|
|
||||||
headers = {'Content-Type': 'text/xml; charset="utf-8"'};
|
headers = {'Content-Type': 'text/xml; charset="utf-8"'};
|
||||||
var request = this._makeRequest("LOCK", "", internalHandlers, headers);
|
if (this._authString)
|
||||||
|
headers['Authorization'] = this._authString;
|
||||||
|
|
||||||
|
let request = this._makeRequest("LOCK", "", handlers, headers);
|
||||||
request.send("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" +
|
request.send("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" +
|
||||||
"<D:lockinfo xmlns:D=\"DAV:\">\n" +
|
"<D:lockinfo xmlns:D=\"DAV:\">\n" +
|
||||||
" <D:locktype><D:write/></D:locktype>\n" +
|
" <D:locktype><D:write/></D:locktype>\n" +
|
||||||
" <D:lockscope><D:exclusive/></D:lockscope>\n" +
|
" <D:lockscope><D:exclusive/></D:lockscope>\n" +
|
||||||
"</D:lockinfo>");
|
"</D:lockinfo>");
|
||||||
|
let event = yield;
|
||||||
|
|
||||||
|
if (event.target.status < 200 || event.target.status >= 300) {
|
||||||
|
generatorDone(this, onComplete, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let tokens = xpath(event.target.responseXML, '//D:locktoken');
|
||||||
|
let token = tokens.iterateNext();
|
||||||
|
if (token) {
|
||||||
|
this._token = token.textContent;
|
||||||
|
this._token = this._token.replace("\n", "").replace("\n", "");
|
||||||
|
generatorDone(this, onComplete, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
generatorDone(this, onComplete, false);
|
||||||
},
|
},
|
||||||
|
|
||||||
// FIXME: make this function not reentrant
|
unlock: function DC_unlock(onComplete) {
|
||||||
unlock: function DC_unlock(handlers) {
|
let generator = yield;
|
||||||
this._lockHandlers = handlers;
|
let handlers = generatorHandlers(generator);
|
||||||
internalHandlers = {load: bind2(this, this._onUnlock),
|
|
||||||
error: bind2(this, this._onUnlockError)};
|
if (!this._token) {
|
||||||
|
generatorDone(this, onComplete, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
headers = {'Lock-Token': "<" + this._token + ">"};
|
headers = {'Lock-Token': "<" + this._token + ">"};
|
||||||
var request = this._makeRequest("UNLOCK", "", internalHandlers, headers);
|
if (this._authString)
|
||||||
|
headers['Authorization'] = this._authString;
|
||||||
|
|
||||||
|
let request = this._makeRequest("UNLOCK", "", handlers, headers);
|
||||||
request.send(null);
|
request.send(null);
|
||||||
},
|
let event = yield;
|
||||||
|
|
||||||
_onLock: function DC__onLock(event) {
|
if (event.target.status < 200 || event.target.status >= 300) {
|
||||||
//notice("acquired lock (" + event.target.status + "):\n" + event.target.responseText + "\n");
|
generatorDone(this, onComplete, false);
|
||||||
this._token = "woo";
|
return;
|
||||||
if (this._lockHandlers && this._lockHandlers.load)
|
}
|
||||||
this._lockHandlers.load(event);
|
|
||||||
},
|
|
||||||
_onLockError: function DC__onLockError(event) {
|
|
||||||
//notice("lock failed (" + event.target.status + "):\n" + event.target.responseText + "\n");
|
|
||||||
if (this._lockHandlers && this._lockHandlers.error)
|
|
||||||
this._lockHandlers.error(event);
|
|
||||||
},
|
|
||||||
|
|
||||||
_onUnlock: function DC__onUnlock(event) {
|
|
||||||
//notice("removed lock (" + event.target.status + "):\n" + event.target.responseText + "\n");
|
|
||||||
this._token = null;
|
this._token = null;
|
||||||
if (this._lockHandlers && this._lockHandlers.load)
|
|
||||||
this._lockHandlers.load(event);
|
generatorDone(this, onComplete, true);
|
||||||
},
|
},
|
||||||
_onUnlockError: function DC__onUnlockError(event) {
|
|
||||||
//notice("unlock failed (" + event.target.status + "):\n" + event.target.responseText + "\n");
|
stealLock: function DC_stealLock(onComplete) {
|
||||||
if (this._lockHandlers && this._lockHandlers.error)
|
let generator = yield;
|
||||||
this._lockHandlers.error(event);
|
let handlers = generatorHandlers(generator);
|
||||||
|
let stolen = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!asyncRun(this, this._getActiveLock, handlers.complete))
|
||||||
|
return;
|
||||||
|
this._token = yield;
|
||||||
|
this._token = this._token.replace("\n", "").replace("\n", "");
|
||||||
|
|
||||||
|
if (!asyncRun(this, this.unlock, handlers.complete))
|
||||||
|
return;
|
||||||
|
let unlocked = yield;
|
||||||
|
|
||||||
|
if (!unlocked)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!asyncRun(this, this.lock, handlers.complete))
|
||||||
|
return;
|
||||||
|
stolen = yield;
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
generatorDone(this, onComplete, stolen);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1413,6 +1543,7 @@ DummyAuthProvider.prototype = {
|
|||||||
Ci.nsIAuthPromptProvider,
|
Ci.nsIAuthPromptProvider,
|
||||||
Ci.nsIAuthPrompt,
|
Ci.nsIAuthPrompt,
|
||||||
Ci.nsIPrompt,
|
Ci.nsIPrompt,
|
||||||
|
Ci.nsIProgressEventSink,
|
||||||
Ci.nsIInterfaceRequestor,
|
Ci.nsIInterfaceRequestor,
|
||||||
Ci.nsISupports],
|
Ci.nsISupports],
|
||||||
|
|
||||||
@ -1534,6 +1665,16 @@ DummyAuthProvider.prototype = {
|
|||||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
// nsIProgressEventSink
|
||||||
|
|
||||||
|
onProgress: function DAP_onProgress(aRequest, aContext,
|
||||||
|
aProgress, aProgressMax) {
|
||||||
|
},
|
||||||
|
|
||||||
|
onStatus: function DAP_onStatus(aRequest, aContext,
|
||||||
|
aStatus, aStatusArg) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user