aboutsummaryrefslogtreecommitdiffstats
path: root/web/nms.gathering.org/js/nms-data.js
diff options
context:
space:
mode:
authorKristian Lyngstol <kly@kly.no>2016-03-12 17:30:26 +0000
committerKristian Lyngstol <kly@kly.no>2016-03-12 17:30:26 +0000
commita7eb97d873b94cc8fcc5d23dc10e567c42c95a22 (patch)
tree8eabc21b46dce8596204ec064f0e3fed624a7c0e /web/nms.gathering.org/js/nms-data.js
parent8b22ddd85a92eddadd679ac1e51fe1792defb241 (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.js187
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();
}
});
};