aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatěj Cepl <mcepl@redhat.com>2011-09-09 15:09:22 +0200
committerMatěj Cepl <mcepl@redhat.com>2011-10-30 11:05:51 +0100
commitcdcd7c4aa1c8027862146e56dcc02cfa9f99b379 (patch)
tree0b8083aac595265c52d920d28efa3893e5a87538
parent1e6d766e5a900973113d747503e2317676c751e0 (diff)
downloadbugzilla-triage-cdcd7c4aa1c8027862146e56dcc02cfa9f99b379.tar.gz
The first version of CachedRequest.
-rw-r--r--lib/cached-request.js159
-rw-r--r--lib/libbugzilla.js40
2 files changed, 196 insertions, 3 deletions
diff --git a/lib/cached-request.js b/lib/cached-request.js
new file mode 100644
index 0000000..fa6c592
--- /dev/null
+++ b/lib/cached-request.js
@@ -0,0 +1,159 @@
+// Released under the MIT/X11 license
+// http://www.opensource.org/licenses/mit-license.php
+
+"use strict";
+var Request = require("request").Request;
+var xhrMod = require("xhr");
+
+// Initialize myStorage if we don't have it.
+var myStorage = require("simple-storage").storage;
+if (!myStorage.cachedRequest) {
+ myStorage.cachedRequest = {};
+}
+
+// https://bugzilla.mozilla.org/582760 is still alive
+var debugOption = true;
+function debug(str) {
+ if (debugOption) {
+ console.log(str);
+ }
+}
+
+/**
+ * Decorating cached response object with a bit of additional
+ * functionality.
+ */
+function CachedResponse (url) {
+ if (!myStorage.cachedRequest[url]) {
+ myStorage.cachedRequest[url] = {};
+ this.url = url;
+ this.text = null;
+ this.status = "";
+ this.statusText = "";
+ this.headers = {};
+ }
+ else {
+ var storedResponse = myStorage.cachedRequest[url];
+ this.url = url;
+ this.text = storedResponse.text;
+ this.status = storedResponse.status;
+ this.statusText = storedResponse.statusText;
+ this.headers = storedResponse.headers;
+ }
+}
+
+/**
+ * getter returning object from this.text
+ * (so we don't save essentially the same object same)
+ *
+ * @return Object from this.text, if this.text isn't JSONable,
+ * return null
+ */
+CachedResponse.prototype.__defineGetter__("json", function() {
+ try {
+ return JSON.parse(this.text);
+ }
+ catch (ex) {
+ if (ex instanceof SyntaxError) {
+ return null;
+ } else {
+ throw ex;
+ }
+ }
+});
+
+/**
+ * save the current object's values to myStorage.
+ */
+CachedResponse.prototype.saveCached = function() {
+ var storedResponse = myStorage.cachedRequest[this.url];
+ storedResponse.text = this.text;
+ storedResponse.status = this.status;
+ storedResponse.statusText = this.statusText;
+ storedResponse.headers = this.headers;
+};
+
+/**
+ * getter returning Last-Modified header as a Date object.
+ *
+ * @return Date when this has Last-Modified header, or null otherwise
+ */
+CachedResponse.prototype.__defineGetter__("lastModified", function() {
+ if (this.headers && (this.headers.hasOwnProperty("Last-Modified"))) {
+ return new Date(this.headers["Last-Modified"]);
+ }
+ return null;
+});
+
+/**
+ * Emulates Request object, but caches the result for speedier access,
+ * and protection when the remote site is down.
+ *
+ * @opts Object with properties same as Request
+ *
+ * Limitations: does only GET requests, so it doesn't even have
+ * .post(), .get() or any other methods.
+ * Contrary to Request() opts can have onError callback, and
+ * getExpiredAnyway property to allow using expired cached value,
+ * if the remote connection returns error.
+ */
+exports.CachedRequest = function CachedRequest(opts) {
+ var crStorage = new CachedResponse(opts.url);
+
+ var req = new xhrMod.XMLHttpRequest();
+ req.open("HEAD", opts.url, true);
+ req.onreadystatechange = function () {
+ if (req.readyState == 4) {
+ if(req.status == 200) {
+ var curETag = req.getResponseHeader("ETag");
+ var curLastModified = new Date(req.getResponseHeader("Last-Modified"));
+ if (crStorage && crStorage.headers &&
+ ((curETag == crStorage.headers.eTag) ||
+ (curLastModified <= crStorage.lastModified))) {
+ debug("Loading from cache!");
+ // use cached values
+ }
+ else { // cache is not up-to-date
+ new Request({
+ url: opts.url,
+ onComplete: function(resp) {
+ if (resp.status == 200) {
+ debug("Too old cache! Reloaded");
+ crStorage.headers = resp.headers;
+ crStorage.text = resp.text;
+ crStorage.status = resp.status;
+ crStorage.statusText = resp.statusText;
+ crStorage.saveCached();
+ }
+ else {
+ // If we cannot get response from the real URL,
+ // we may be happy with getting our fix from
+ // anywhere, including (possibly) expired cache
+ if (opts.getExpiredAnyway && crStorage && crStorage.text) {
+ debug("Nothing better to do! Returning expired cache.");
+ }
+ else {
+ // We definitively lost, just call .onComplete
+ // with what we have.
+ opts.onComplete({
+ text: resp.text,
+ json: null,
+ status: resp.status,
+ statusText: resp.statusText,
+ headers: resp.headers
+ });
+ // to avoid call opts.onComplete below
+ return ;
+ }
+ }
+ }
+ }).get();
+ }
+ opts.onComplete(crStorage);
+ }
+ }
+ };
+ req.send();
+};
+
+//vim: set ts=2 et sw=2 textwidth=80:
diff --git a/lib/libbugzilla.js b/lib/libbugzilla.js
index 03ae6eb..d931a91 100644
--- a/lib/libbugzilla.js
+++ b/lib/libbugzilla.js
@@ -14,6 +14,7 @@ var urlMod = require("url");
var xhrMod = require("xhr");
var panelMod = require("panel");
var myStorage = require("simple-storage");
+var CachedRequest = require("cached-request").CachedRequest;
var JSONURLDefault = "https://fedorahosted.org/released"+
"/bugzilla-triage-scripts/Config_data.json";
@@ -25,7 +26,7 @@ var copiedAttributes = [ "queryButton", "upstreamButton", "parseAbrtBacktraces",
var config = exports.config = {};
-var debugOption = null;
+var debugOption = true;
function Message(cmd, data) {
debug("Message: cmd = " + cmd + ", data = " + data);
@@ -340,8 +341,15 @@ function loginToAllBugzillas(callback) {
// Increment call counter
loginCallsCounter++;
});
+<<<<<<< HEAD
if (loginCallsCounter == 0) {
debug("No credentials!");
+=======
+ // loginCallsCounter is here approx. number of calls which
+ // were started; zero means we have no passwords at
+ // all, thus we have to run callback directly.
+ if (loginCallsCounter == 0) {
+>>>>>>> The first version of CachedRequest.
callback(config);
}
},
@@ -382,6 +390,20 @@ var makeJSONRPCCall = exports.makeJSONRPCCall = function makeJSONRPCCall(url, me
}).post();
};
+<<<<<<< HEAD
+=======
+function processPageModeREs() {
+ var confD = config.configData;
+ if (confD.bugPageMatchStr) {
+ ['bugPageMatch', 'skipMatch'].forEach(function (key) {
+ confD[key] = confD[key+"Str"].map(function (REStr) {
+ return new RegExp(REStr);
+ });
+ });
+ }
+}
+
+>>>>>>> The first version of CachedRequest.
/**
* Preprocess JSON into config data structure.
*
@@ -514,8 +536,20 @@ exports.initialize = function initialize(callback) {
var urlStr = preferences.get(prefJSONURLName, JSONURLDefault);
preferences.set(prefJSONURLName, urlStr);
- debug("Starting initialize!");
- fetchConfigurationJSON(urlStr, callback);
+ CachedRequest({
+ url: urlStr,
+ getExpiredAnyway: true,
+ onComplete: function (response) {
+ if (response.status == 200) {
+ processConfigJSON(response.json);
+ if (("submitsLogging" in config.gJSONData.configData) &&
+ config.gJSONData.configData.submitsLogging) {
+ logger.initialize();
+ }
+ loginToAllBugzillas(callback);
+ }
+ }
+ });
}
//vim: set ts=2 et sw=2 textwidth=80: