diff options
author | Kristian Lyngstol <kly@kly.no> | 2016-03-12 17:30:26 +0000 |
---|---|---|
committer | Kristian Lyngstol <kly@kly.no> | 2016-03-12 17:30:26 +0000 |
commit | a7eb97d873b94cc8fcc5d23dc10e567c42c95a22 (patch) | |
tree | 8eabc21b46dce8596204ec064f0e3fed624a7c0e /web/nms.gathering.org/js/nms-data.js | |
parent | 8b22ddd85a92eddadd679ac1e51fe1792defb241 (diff) |
NMS: Prototype of nms-data seriously updated
I think it's ready now...
Diffstat (limited to 'web/nms.gathering.org/js/nms-data.js')
-rw-r--r-- | web/nms.gathering.org/js/nms-data.js | 187 |
1 files changed, 134 insertions, 53 deletions
diff --git a/web/nms.gathering.org/js/nms-data.js b/web/nms.gathering.org/js/nms-data.js index 4dda8e4..5f5a2b4 100644 --- a/web/nms.gathering.org/js/nms-data.js +++ b/web/nms.gathering.org/js/nms-data.js @@ -11,6 +11,22 @@ /* + * This will obviously be moved + */ +var nmsCore = nmsCore || { + stats: { + assertErrors:0 + } +} + +nmsCore.assert = function(cb) { + if (!cb) { + nmsCore.stats.assertErrors++; + throw "Assertion failed"; + } +} + +/* * This file/module/whatever is an attempt to gather all data collection in * one place. * @@ -21,7 +37,11 @@ * and callbacks and whatnot, instead of all the custom stuff that we * started out with. * - * Public interfaces: + * Sources are identified by a name, which is then available in + * nmsData[name] in full. A copy of the previous data set is kept in + * nmsData.old[name]. You can use getNow / setNow() to append a 'now=' + * string. + * * nmsData.data[name] - actual data * nmsData.registerSource() - add a source, will be polled periodicall * nmsData.updateSource() - issue a one-off update, outside of whatever @@ -30,48 +50,107 @@ var nmsData = nmsData || { - data: {}, // Actual data - sources: {}, - - // Tracks metdata (hashes/timestamps) - poller: { - hashes:{}, - time:{} - }, - // setInterval handlers (and more?) - pollers: { - - }, + old: {}, // Single copy of previous data. Automatically populated. stats: { identicalFetches:0, outstandingAjaxRequests:0, ajaxOverflow:0, + pollClearsEmpty:0, pollClears:0, - pollSets:0 - } + pollSets:0, + newSource:0, + oldSource:0 + }, + /* + * The last time stamp of any data received, regardless of source. + * + * Used as a fallback for blank now, but can also be used to check + * "freshness", I suppose. + */ + _last: undefined, + _now: undefined, + + /* + * These are provided so we can introduce error checking when we + * have time. + * + * now() represents the data, not the intent. That means that if + * you want to check if we are traveling in time you should not + * check nmsData.now. That will always return a value as long as + * we've had a single piece of data. + */ + get now() { return this._now || this._last; }, + set now(val) { + if (val == undefined) { + this._now = undefined; + } + // FIXME: Check if now is valid syntax. + this._now = now; + }, + /* + * List of sources, name, handler, etc + */ + _sources: {}, + + /* + * Maximum number of AJAX requests in transit before we start + * skipping updates. + */ + _ajaxThreshold: 5 }; + +nmsData._dropData = function (name) { + nmsCore.assert(name); + nmsCore.assert(this[name]); + delete this[name]; + delete this.old[name]; +} + +nmsData.removeSource = function (name) { + if (this._sources[name] == undefined) { + this.stats.pollClearsEmpty++; + return true; + } + if (this._sources[name]['handle']) { + this.stats.pollClears++; + clearInterval(this._sources[name]['handle']); + } + delete this._sources[name]; +} + /* * Register a source. * - * name: "Local" name. Maps to nmsData.data[name] - * remotename: The primary attribute to get from the remote source. + * name: "Local" name. Maps to nmsData[name] * target: URL of the source * cb: Optional callback * cbdata: Optional callback data * - * Update frequency will (eventually) be handled by parsing max-age from - * the source. Right now it's hardcoded. + * This can be called multiple times to add multiple handlers. There's no + * guarantee that they will be run in order, but right now they do. + * + * Update frequency _might_ be adaptive eventually, but since we only + * execute callbacks on change and backend sends cache headers, the browser + * will not issue actual HTTP requests. * * FIXME: Should be unified with nmsTimers() somehow. */ -nmsData.registerSource = function(name, remotename, target, cb, cbdata) { - if(this.pollers[name]) { - clearInterval(this.pollers[name]); - this.stats.pollClears++; +nmsData.registerSource = function(name, target, cb, cbdata) { + var cbob = { + name: name, + cb: cb, + cbdata: cbdata + }; + if (this._sources[name] == undefined) { + this._sources[name] = { target: target, cbs: [] }; + this._sources[name]['handle'] = setInterval(function(){nmsData.updateSource(name)}, 1000); + this.stats.newSource++; + } else { + this.stats.oldSource++; } - this.sources[name] = { remotename: remotename, target: target, cb: cb, cbdata: cbdata }; - this.pollers[name] = setInterval(function(){nmsData.updateSource(name)}, 1000); + this._sources[name].cbs.push(cbob); + this.stats.pollSets++; } @@ -83,52 +162,55 @@ nmsData.registerSource = function(name, remotename, target, cb, cbdata) { * after a comment is posted). */ nmsData.updateSource = function(name) { - nmsData.genericUpdater(name, - this.sources[name].remotename, - this.sources[name].target, - this.sources[name].cb, - this.sources[name].cbdata); + this._genericUpdater(name); +} + +/* + * Reset a source, deleting all data, including old. + * + * Useful if traveling in time, for example. + */ +nmsData.resetSource = function(name) { + this[name] = {}; + this.old[name] = {}; + this.updateSource(name); } /* - * Updates nmsData.data[name] with data fetched from remote target in - * variable "remotename". If a callback is provided, it is called with - * argument meh. + * Updates nmsData[name] and nmsData.old[name], issuing any callbacks where + * relevant. * - * This also populates nms.pollers[name] with the server-provided hash. - * Only if a change is detected is the callback issued. + * Do not use this directly. Use updateSource(). * - * Used by registerSource. */ -nmsData.genericUpdater = function(name, remotename, target, cb, meh) { - if (this.stats.outstandingAjaxRequests > 5) { +nmsData._genericUpdater = function(name) { + if (this.stats.outstandingAjaxRequests++ > this._ajaxThreshold) { + this.stats.outstandingAjaxRequests--; this.stats.ajaxOverflow++; return; } this.stats.outstandingAjaxRequests++; var now = ""; - /* - if (nms.now != false) - now = "now=" + nms.now; + if (this._now != undefined) + now = "now=" + this._now; if (now != "") { - if (target.match("\\?")) + if (this._sources[name].target.match("\\?")) now = "&" + now; else now = "?" + now; } - */ $.ajax({ type: "GET", - url: target + now, - dataType: "text", + url: this._sources[name].target + now, + dataType: "json", success: function (data, textStatus, jqXHR) { - var indata = JSON.parse(data); - if (nmsData.poller.hashes[name] != indata['hash']) { - nmsData.data[name] = indata[remotename]; - nmsData.poller.hashes[name] = indata['hash']; - nmsData.poller.time[name] = indata['time']; - if (cb != undefined) { - cb(meh); + nmsData._last = data['time']; + if (nmsData[name] == undefined || nmsData[name]['hash'] != data['hash']) { + nmsData.old[name] = nmsData[name]; + nmsData[name] = data; + for (var i in nmsData._sources[name].cbs) { + var tmp = nmsData._sources[name].cbs[i]; + tmp.cb(tmp.cbdata); } } else { nmsData.stats.identicalFetches++; @@ -136,7 +218,6 @@ nmsData.genericUpdater = function(name, remotename, target, cb, meh) { }, complete: function(jqXHR, textStatus) { nmsData.stats.outstandingAjaxRequests--; - //updateAjaxInfo(); } }); }; |