commit 01ea59491a3c07c558f454227e433df7b753d9b1
parent ec6d38df68681d021a96460f9f83cc42d9dd9715
Author: Dan Stillman <dstillman@zotero.org>
Date: Tue, 11 Oct 2011 16:18:17 +0000
- Fix error handling in syncing when using pumpGenerator()
- Take an optional error handler as the third parameter to pumpGenerator()
Diffstat:
2 files changed, 198 insertions(+), 186 deletions(-)
diff --git a/chrome/content/zotero/xpcom/sync.js b/chrome/content/zotero/xpcom/sync.js
@@ -1460,220 +1460,223 @@ Zotero.Sync.Server = new function () {
);
}
+ var errorHandler = function (e) {
+ Zotero.DB.rollbackTransaction();
+
+ Zotero.UnresponsiveScriptIndicator.enable();
+
+ if (progressMeter) {
+ Zotero.hideZoteroPaneOverlay();
+ }
+ Zotero.suppressUIUpdates = false;
+ _updatesInProgress = false;
+
+ _error(e);
+ }
+
try {
var gen = Zotero.Sync.Server.Data.processUpdatedXML(
- xml.updated, lastLocalSyncDate, syncSession, libraryID, function (xmlstr) {
- try {
- Zotero.UnresponsiveScriptIndicator.enable();
-
- if (progressMeter) {
- Zotero.hideZoteroPaneOverlay();
+ xml.updated,
+ lastLocalSyncDate,
+ syncSession,
+ libraryID,
+ function (xmlstr) {
+ Zotero.UnresponsiveScriptIndicator.enable();
+
+ if (progressMeter) {
+ Zotero.hideZoteroPaneOverlay();
+ }
+ Zotero.suppressUIUpdates = false;
+ _updatesInProgress = false;
+
+ //Zotero.debug(xmlstr);
+ //throw('break');
+
+ if (xmlstr === false) {
+ Zotero.debug("Sync cancelled");
+ Zotero.DB.rollbackTransaction();
+ Zotero.reloadDataObjects();
+ Zotero.Sync.EventListener.resetIgnored();
+ _syncInProgress = false;
+ _callbacks.onStop();
+ return;
+ }
+
+ if (xmlstr) {
+ Zotero.debug(xmlstr);
+ }
+
+ if (!xmlstr) {
+ Zotero.debug("Nothing to upload to server");
+ Zotero.Sync.Server.lastRemoteSyncTime = response.getAttribute('timestamp');
+ Zotero.Sync.Server.lastLocalSyncTime = nextLocalSyncTime;
+ Zotero.Sync.Server.nextLocalSyncDate = false;
+ Zotero.DB.commitTransaction();
+ _syncInProgress = false;
+ _callbacks.onSuccess();
+ return;
+ }
+
+ Zotero.DB.commitTransaction();
+
+ Zotero.Sync.Runner.setSyncStatus(Zotero.getString('sync.status.uploadingData'));
+
+ var url = _serverURL + 'upload';
+ var body = _apiVersionComponent
+ + '&' + Zotero.Sync.Server.sessionIDComponent
+ + '&updateKey=' + updateKey
+ + '&data=' + encodeURIComponent(xmlstr);
+
+ //var file = Zotero.getZoteroDirectory();
+ //file.append('lastupload.txt');
+ //Zotero.File.putContents(file, body);
+
+ var uploadCallback = function (xmlhttp) {
+ if (xmlhttp.status == 409) {
+ Zotero.debug("Upload key is no longer valid -- restarting sync");
+ setTimeout(function () {
+ Zotero.Sync.Server.sync(_callbacks, true, true);
+ }, 1);
+ return;
}
- Zotero.suppressUIUpdates = false;
- _updatesInProgress = false;
- //Zotero.debug(xmlstr);
- //throw('break');
+ _checkResponse(xmlhttp);
- if (xmlstr === false) {
- Zotero.debug("Sync cancelled");
- Zotero.DB.rollbackTransaction();
- Zotero.reloadDataObjects();
- Zotero.Sync.EventListener.resetIgnored();
- _syncInProgress = false;
- _callbacks.onStop();
- return;
- }
+ Zotero.debug(xmlhttp.responseText);
+ var response = xmlhttp.responseXML.childNodes[0];
+
+ if (_checkServerLock(response, function (mode) {
+ switch (mode) {
+ // If the upload was queued, keep checking back
+ case 'queued':
+ Zotero.Sync.Runner.setSyncStatus(Zotero.getString('sync.status.uploadAccepted'));
+
+ var url = _serverURL + 'uploadstatus';
+ var body = _apiVersionComponent
+ + '&' + Zotero.Sync.Server.sessionIDComponent;
+ Zotero.HTTP.doPost(url, body, function (xmlhttp) {
+ uploadCallback(xmlhttp);
+ });
+ break;
+
+ // If affected libraries were locked, restart sync,
+ // since the upload key would be out of date anyway
+ case 'locked':
+ setTimeout(function () {
+ Zotero.Sync.Server.sync(_callbacks, true, true);
+ }, 1);
+ break;
+
+ default:
+ throw ("Unexpected server lock mode '" + mode + "' in Zotero.Sync.Server.upload()");
+ }
+ })) { return; }
- if (xmlstr) {
- Zotero.debug(xmlstr);
+ if (response.firstChild.tagName == 'error') {
+ // handle error
+ _error(response.firstChild.firstChild.nodeValue);
}
- if (!xmlstr) {
- Zotero.debug("Nothing to upload to server");
- Zotero.Sync.Server.lastRemoteSyncTime = response.getAttribute('timestamp');
- Zotero.Sync.Server.lastLocalSyncTime = nextLocalSyncTime;
- Zotero.Sync.Server.nextLocalSyncDate = false;
- Zotero.DB.commitTransaction();
- _syncInProgress = false;
- _callbacks.onSuccess();
- return;
+ if (response.firstChild.localName != 'uploaded') {
+ _error("Unexpected upload response '" + response.firstChild.localName
+ + "' in Zotero.Sync.Server.sync()");
}
- Zotero.DB.commitTransaction();
+ Zotero.DB.beginTransaction();
+ Zotero.Sync.purgeDeletedObjects(nextLocalSyncTime);
+ Zotero.Sync.Server.lastLocalSyncTime = nextLocalSyncTime;
+ Zotero.Sync.Server.nextLocalSyncDate = false;
+ Zotero.Sync.Server.lastRemoteSyncTime = response.getAttribute('timestamp');
- Zotero.Sync.Runner.setSyncStatus(Zotero.getString('sync.status.uploadingData'));
+ //throw('break2');
- var url = _serverURL + 'upload';
- var body = _apiVersionComponent
- + '&' + Zotero.Sync.Server.sessionIDComponent
- + '&updateKey=' + updateKey
- + '&data=' + encodeURIComponent(xmlstr);
+ Zotero.DB.commitTransaction();
- //var file = Zotero.getZoteroDirectory();
- //file.append('lastupload.txt');
- //Zotero.File.putContents(file, body);
+ // Check if any items were modified during /upload,
+ // and restart the sync if so
+ if (Zotero.Items.getNewer(nextLocalSyncDate, true)) {
+ Zotero.debug("Items were modified during upload -- restarting sync");
+ Zotero.Sync.Server.sync(_callbacks, true, true);
+ return;
+ }
- var uploadCallback = function (xmlhttp) {
- if (xmlhttp.status == 409) {
- Zotero.debug("Upload key is no longer valid -- restarting sync");
- setTimeout(function () {
- Zotero.Sync.Server.sync(_callbacks, true, true);
- }, 1);
- return;
- }
-
- _checkResponse(xmlhttp);
-
- Zotero.debug(xmlhttp.responseText);
- var response = xmlhttp.responseXML.childNodes[0];
-
- if (_checkServerLock(response, function (mode) {
- switch (mode) {
- // If the upload was queued, keep checking back
- case 'queued':
- Zotero.Sync.Runner.setSyncStatus(Zotero.getString('sync.status.uploadAccepted'));
-
- var url = _serverURL + 'uploadstatus';
- var body = _apiVersionComponent
- + '&' + Zotero.Sync.Server.sessionIDComponent;
- Zotero.HTTP.doPost(url, body, function (xmlhttp) {
- uploadCallback(xmlhttp);
- });
- break;
-
- // If affected libraries were locked, restart sync,
- // since the upload key would be out of date anyway
- case 'locked':
- setTimeout(function () {
- Zotero.Sync.Server.sync(_callbacks, true, true);
- }, 1);
- break;
-
- default:
- throw ("Unexpected server lock mode '" + mode + "' in Zotero.Sync.Server.upload()");
- }
- })) { return; }
+ _syncInProgress = false;
+ _callbacks.onSuccess();
+ }
+
+ var compress = Zotero.Prefs.get('sync.server.compressData');
+ // Compress upload data
+ if (compress) {
+ // Callback when compressed data is available
+ var bufferUploader = function (data) {
+ var gzurl = url + '?gzip=1';
- if (response.firstChild.tagName == 'error') {
- // handle error
- _error(response.firstChild.firstChild.nodeValue);
- }
+ var oldLen = body.length;
+ var newLen = data.length;
+ var savings = Math.round(((oldLen - newLen) / oldLen) * 100)
+ Zotero.debug("HTTP POST " + newLen + " bytes to " + gzurl
+ + " (gzipped from " + oldLen + " bytes; "
+ + savings + "% savings)");
- if (response.firstChild.localName != 'uploaded') {
- _error("Unexpected upload response '" + response.firstChild.localName
- + "' in Zotero.Sync.Server.sync()");
+ if (Zotero.HTTP.browserIsOffline()) {
+ Zotero.debug('Browser is offline');
+ return false;
}
- Zotero.DB.beginTransaction();
- Zotero.Sync.purgeDeletedObjects(nextLocalSyncTime);
- Zotero.Sync.Server.lastLocalSyncTime = nextLocalSyncTime;
- Zotero.Sync.Server.nextLocalSyncDate = false;
- Zotero.Sync.Server.lastRemoteSyncTime = response.getAttribute('timestamp');
+ var req =
+ Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"].
+ createInstance();
+ req.open('POST', gzurl, true);
+ req.setRequestHeader('Content-Type', "application/octet-stream");
+ req.setRequestHeader('Content-Encoding', 'gzip');
- //throw('break2');
-
- Zotero.DB.commitTransaction();
-
- // Check if any items were modified during /upload,
- // and restart the sync if so
- if (Zotero.Items.getNewer(nextLocalSyncDate, true)) {
- Zotero.debug("Items were modified during upload -- restarting sync");
- Zotero.Sync.Server.sync(_callbacks, true, true);
- return;
- }
-
- _syncInProgress = false;
- _callbacks.onSuccess();
- }
-
- var compress = Zotero.Prefs.get('sync.server.compressData');
- // Compress upload data
- if (compress) {
- // Callback when compressed data is available
- var bufferUploader = function (data) {
- var gzurl = url + '?gzip=1';
-
- var oldLen = body.length;
- var newLen = data.length;
- var savings = Math.round(((oldLen - newLen) / oldLen) * 100)
- Zotero.debug("HTTP POST " + newLen + " bytes to " + gzurl
- + " (gzipped from " + oldLen + " bytes; "
- + savings + "% savings)");
-
- if (Zotero.HTTP.browserIsOffline()) {
- Zotero.debug('Browser is offline');
- return false;
- }
-
- var req =
- Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"].
- createInstance();
- req.open('POST', gzurl, true);
- req.setRequestHeader('Content-Type', "application/octet-stream");
- req.setRequestHeader('Content-Encoding', 'gzip');
-
- req.onreadystatechange = function () {
- if (req.readyState == 4) {
- uploadCallback(req);
- }
- };
- try {
- req.sendAsBinary(data);
- }
- catch (e) {
- _error(e);
+ req.onreadystatechange = function () {
+ if (req.readyState == 4) {
+ uploadCallback(req);
}
+ };
+ try {
+ req.sendAsBinary(data);
+ }
+ catch (e) {
+ _error(e);
}
-
- // Get input stream from POST data
- var unicodeConverter =
- Components.classes["@mozilla.org/intl/scriptableunicodeconverter"]
- .createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
- unicodeConverter.charset = "UTF-8";
- var bodyStream = unicodeConverter.convertToInputStream(body);
-
- // Get listener for when compression is done
- var listener = new Zotero.BufferedInputListener(bufferUploader);
-
- // Initialize stream converter
- var converter =
- Components.classes["@mozilla.org/streamconv;1?from=uncompressed&to=gzip"]
- .createInstance(Components.interfaces.nsIStreamConverter);
- converter.asyncConvertData("uncompressed", "gzip", listener, null);
-
- // Send input stream to stream converter
- var pump = Components.classes["@mozilla.org/network/input-stream-pump;1"].
- createInstance(Components.interfaces.nsIInputStreamPump);
- pump.init(bodyStream, -1, -1, 0, 0, true);
- pump.asyncRead(converter, null);
}
- // Don't compress upload data
- else {
- Zotero.HTTP.doPost(url, body, uploadCallback);
- }
+ // Get input stream from POST data
+ var unicodeConverter =
+ Components.classes["@mozilla.org/intl/scriptableunicodeconverter"]
+ .createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
+ unicodeConverter.charset = "UTF-8";
+ var bodyStream = unicodeConverter.convertToInputStream(body);
+
+ // Get listener for when compression is done
+ var listener = new Zotero.BufferedInputListener(bufferUploader);
+
+ // Initialize stream converter
+ var converter =
+ Components.classes["@mozilla.org/streamconv;1?from=uncompressed&to=gzip"]
+ .createInstance(Components.interfaces.nsIStreamConverter);
+ converter.asyncConvertData("uncompressed", "gzip", listener, null);
+
+ // Send input stream to stream converter
+ var pump = Components.classes["@mozilla.org/network/input-stream-pump;1"].
+ createInstance(Components.interfaces.nsIInputStreamPump);
+ pump.init(bodyStream, -1, -1, 0, 0, true);
+ pump.asyncRead(converter, null);
}
- catch (e) {
- _error(e);
+
+ // Don't compress upload data
+ else {
+ Zotero.HTTP.doPost(url, body, uploadCallback);
}
}
);
- Zotero.pumpGenerator(gen);
+ Zotero.pumpGenerator(gen, false, errorHandler);
}
catch (e) {
- Zotero.DB.rollbackTransaction();
-
- Zotero.UnresponsiveScriptIndicator.enable();
-
- if (progressMeter) {
- Zotero.hideZoteroPaneOverlay();
- }
- Zotero.suppressUIUpdates = false;
- _updatesInProgress = false;
-
- throw (e);
+ errorHandler(e);
}
}
catch (e) {
diff --git a/chrome/content/zotero/xpcom/zotero.js b/chrome/content/zotero/xpcom/zotero.js
@@ -1498,8 +1498,11 @@ const ZOTERO_CONFIG = {
/**
* Pumps a generator until it yields false. See itemTreeView.js for an example.
+ *
+ * If errorHandler is specified, exceptions in the generator will be caught
+ * and passed to the callback
*/
- this.pumpGenerator = function(generator, ms) {
+ this.pumpGenerator = function(generator, ms, errorHandler) {
_waiting++;
var timer = Components.classes["@mozilla.org/timer;1"].
@@ -1528,7 +1531,13 @@ const ZOTERO_CONFIG = {
_waitTimers = [];
_waitTimerCallbacks = [];
- if(err) throw err;
+ if(err) {
+ if(errorHandler) {
+ errorHandler(err);
+ } else {
+ throw err;
+ }
+ }
}}
timer.initWithCallback(timerCallback, ms ? ms : 0, Components.interfaces.nsITimer.TYPE_REPEATING_SLACK);
// add timer to global scope so that it doesn't get garbage collected before it completes