zotero/chrome/content/zotero/xpcom/connector/repo.js
Adomas Venčkauskas e83bbbad4e Fix getTranslatorCode bugs
- /connector/getTranslatorCode used to respond with empty content
- CodeGetter froze connectors by issuing hundreds of simultanious XHR
  requests
2016-09-20 15:55:58 +03:00

210 lines
6.1 KiB
JavaScript

/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2011 Center for History and New Media
George Mason University, Fairfax, Virginia, USA
http://zotero.org
This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK *****
*/
const TRANSLATOR_CODE_PREFIX = "translatorCode-";
Zotero.Repo = new function() {
var _nextCheck;
var _timeoutID;
const infoRe = /^\s*{[\S\s]*?}\s*?[\r\n]/;
this.SOURCE_ZOTERO_STANDALONE = 1;
this.SOURCE_REPO = 2;
/**
* Try to retrieve translator metadata from Zotero Standalone and initialize repository check
* timer
*/
this.init = function() {
// get time of next check
_nextCheck = Zotero.Prefs.get("connector.repo.lastCheck.localTime")
+ZOTERO_CONFIG.REPOSITORY_CHECK_INTERVAL*1000;
// update from standalone, but only cascade to repo if we are overdue
_updateFromStandalone(_nextCheck <= Date.now());
};
/**
* Force updating translators
*/
var update = this.update = function(reset) {
_updateFromStandalone(true, reset);
};
/**
* Get translator code from repository
* @param {String} translatorID ID of the translator to retrieve code for
*/
this.getTranslatorCode = Zotero.Promise.method(function (translatorID, debugMode) {
var deferred = Zotero.Promise.defer();
// try standalone
Zotero.Connector.callMethod("getTranslatorCode", {"translatorID":translatorID}, function(result) {
if(result) {
deferred.resolve(
Zotero.Promise.all(
[
_haveCode(result, translatorID),
Zotero.Repo.SOURCE_ZOTERO_STANDALONE
]
)
);
return;
}
// Don't fetch from repo in debug mode
if (debugMode) {
deferred.resolve([false, Zotero.Repo.SOURCE_ZOTERO_STANDALONE]);
return;
}
// then try repo
Zotero.HTTP.doGet(
ZOTERO_CONFIG.REPOSITORY_URL + "code/" + translatorID + "?version=" + Zotero.version,
function(xmlhttp) {
deferred.resolve(
Zotero.Promise.all(
[
_haveCode(
xmlhttp.status === 200 ? xmlhttp.responseText : false,
translatorID
),
Zotero.Repo.SOURCE_REPO
]
)
);
}
);
});
return deferred.promise;
});
/**
* Called when code has been retrieved from standalone or repo
*/
function _haveCode(code, translatorID) {
if(!code) {
Zotero.logError(new Error("Code could not be retrieved for " + translatorID));
return false;
}
if(!Zotero.isFx) {
code = Zotero.Translators.preprocessCode(code);
var m = infoRe.exec(code);
if (!m) {
Zotero.logError(new Error("Invalid or missing translator metadata JSON object for " + translatorID));
return false;
}
try {
var metadata = JSON.parse(m[0]);
} catch(e) {
Zotero.logError(new Error("Invalid or missing translator metadata JSON object for " + translatorID));
return false;
}
var translator = Zotero.Translators.getWithoutCode(translatorID);
if(metadata.lastUpdated !== translator.lastUpdated) {
if(Zotero.Date.sqlToDate(metadata.lastUpdated) > Zotero.Date.sqlToDate(translator.lastUpdated)) {
Zotero.debug("Repo: Retrieved code for "+metadata.label+" newer than stored metadata; updating");
Zotero.Translators.update([metadata]);
} else {
Zotero.debug("Repo: Retrieved code for "+metadata.label+" older than stored metadata; not caching");
}
}
}
return code;
}
/**
* Retrieve translator metadata from Zotero Standalone
* @param {Boolean} [tryRepoOnFailure] If true, run _updateFromRepo() if standalone cannot be
* contacted
*/
function _updateFromStandalone(tryRepoOnFailure, reset, callback) {
Zotero.Connector.callMethod("getTranslators", {}, function(result) {
if(!result && tryRepoOnFailure) {
_updateFromRepo(reset, callback);
} else {
_handleResponse(result, reset);
if(callback) callback(!!result);
}
});
}
/**
* Retrieve metadata from repository
*/
function _updateFromRepo(reset, callback) {
var url = ZOTERO_CONFIG.REPOSITORY_URL + "metadata?version=" + Zotero.version + "&last="+
(reset ? "0" : Zotero.Prefs.get("connector.repo.lastCheck.repoTime"));
Zotero.HTTP.doGet(url, function(xmlhttp) {
var success = xmlhttp.status === 200;
_handleResponse(success ? JSON.parse(xmlhttp.responseText) : false, reset);
if(success) {
var date = xmlhttp.getResponseHeader("Date");
Zotero.Prefs.set("connector.repo.lastCheck.repoTime",
Math.floor(Date.parse(date)/1000));
}
if(callback) callback(!!result);
});
}
/**
* Handle response from Zotero Standalone or repository and set timer for next update
*/
function _handleResponse(result, reset) {
// set up timer
var now = Date.now();
if(result) {
Zotero.Translators.update(result, reset);
Zotero.Prefs.set("connector.repo.lastCheck.localTime", now);
Zotero.debug("Repo: Check succeeded");
} else {
Zotero.debug("Repo: Check failed");
}
if(result || _nextCheck <= now) {
// if we failed a scheduled check, then use retry interval
_nextCheck = now+(result
? ZOTERO_CONFIG.REPOSITORY_CHECK_INTERVAL
: ZOTERO_CONFIG.REPOSITORY_RETRY_INTERVAL)*1000;
} else if(_timeoutID) {
// if we didn't fail a scheduled check and another is already scheduled, leave it
return;
}
// remove old timeout and create a new one
if(_timeoutID) clearTimeout(_timeoutID);
var nextCheckIn = (_nextCheck-now+2000);
_timeoutID = setTimeout(update, nextCheckIn);
Zotero.debug("Repo: Next check in "+nextCheckIn);
}
}