diff options
author | Matěj Cepl <mcepl@redhat.com> | 2011-09-09 15:09:22 +0200 |
---|---|---|
committer | Matěj Cepl <mcepl@redhat.com> | 2011-10-30 11:05:51 +0100 |
commit | cdcd7c4aa1c8027862146e56dcc02cfa9f99b379 (patch) | |
tree | 0b8083aac595265c52d920d28efa3893e5a87538 | |
parent | 1e6d766e5a900973113d747503e2317676c751e0 (diff) | |
download | bugzilla-triage-cdcd7c4aa1c8027862146e56dcc02cfa9f99b379.tar.gz |
The first version of CachedRequest.
-rw-r--r-- | lib/cached-request.js | 159 | ||||
-rw-r--r-- | lib/libbugzilla.js | 40 |
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: |