From 727e4ab31aa6d1a754711d4cd29dbcefae2e952a Mon Sep 17 00:00:00 2001 From: Kristian Lyngstol Date: Mon, 21 Mar 2016 20:11:55 +0100 Subject: NMS: NMS Public --- web/nms-public.gathering.org/js/nms-data.js | 262 ++++++++++++++++++++++++++++ 1 file changed, 262 insertions(+) create mode 100644 web/nms-public.gathering.org/js/nms-data.js (limited to 'web/nms-public.gathering.org/js/nms-data.js') diff --git a/web/nms-public.gathering.org/js/nms-data.js b/web/nms-public.gathering.org/js/nms-data.js new file mode 100644 index 0000000..6432a8d --- /dev/null +++ b/web/nms-public.gathering.org/js/nms-data.js @@ -0,0 +1,262 @@ +"use strict"; + +/* + * This file/module/whatever is an attempt to gather all data collection in + * one place. + * + * The basic idea is to have all periodic data updates unified here, with + * stats, tracking of "ajax overflows" and general-purpose error handling + * and callbacks and whatnot, instead of all the custom stuff that we + * started out with. + * + * 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[name] - actual data + * nmsData.old[name] - previous copy of data + * nmsData.registerSource() - add a source, will be polled periodicall + * nmsData.addHandler() + * nmsData.updateSource() - issue a one-off update, outside of whatever + * periodic polling might take place + * nmsData.invalidate() - Invalidate browser-cache. + */ + + +var nmsData = nmsData || { + old: {}, // Single copy of previous data. Automatically populated. + stats: { + identicalFetches:0, + outstandingAjaxRequests:0, + ajaxOverflow:0, + pollClearsEmpty:0, + pollClears: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 || !val) { + nmsData._now = undefined; + } else { + // FIXME: Check if now is valid syntax. + nmsData._now = val; + } + }, + /* + * List of sources, name, handler, etc + */ + _sources: {}, + + /* + * Maximum number of AJAX requests in transit before we start + * skipping updates. + * + * A problem right now is that it will typically always hit the + * same thing since everything starts at the same time... + */ + _ajaxThreshold: 10 +}; + + +nmsData._dropData = function (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[name] + * target: URL of the source + * + * 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, target) { + if (this._sources[name] == undefined) { + this._sources[name] = { target: target, cbs: {}, fresh: true }; + this._sources[name]['handle'] = setInterval(function(){nmsData.updateSource(name)}, 1000); + this.stats.newSource++; + } else { + this.stats.oldSource++; + } + + this.stats.pollSets++; +} + +/* + * Add a handler (callback) for a source, using an id. + * + * This is idempotent: if the id is the same, it will just overwrite the + * old id, not add a copy. + */ +nmsData.addHandler = function(name, id, cb, cbdata) { + try { + var cbob = { + id: id, + name: name, + cb: cb, + fresh: true, + cbdata: cbdata + }; + if (id == undefined) { + return; + } + this._sources[name].cbs[id] = cbob; + this.updateSource(name); + } catch (e) { + } +} + +/* + * Unregister all handlers with the "id" for all sources. + * + * Mainly used to avoid fini() functions in the map handlers. E.g.: just + * reuse "mapHandler" as id. + */ +nmsData.unregisterHandlerWildcard = function(id) { + for (var v in nmsData._sources) { + this.unregisterHandler(v, id); + } +} + +nmsData.unregisterHandler = function(name, id) { + delete this._sources[name].cbs[id]; +} + +/* + * Updates a source. + * + * Called on interval, but can also be used to update a source after a + * known action that updates the underlying data (e.g: update comments + * after a comment is posted). + */ +nmsData.updateSource = function(name) { + /* + * See comment in nms.js nmsINIT(); + */ + if (name == "ticker" ) { + for (var i in nmsData._sources[name].cbs) { + var tmp = nmsData._sources[name].cbs[i]; + if (tmp.cb != undefined) { + tmp.cb(tmp.cbdata); + } + } + return; + } + this._genericUpdater(name, true); +} + +nmsData.invalidate = function(name) { + this._genericUpdater(name, false); +} +/* + * 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[name] and nmsData.old[name], issuing any callbacks where + * relevant. + * + * Do not use this directly. Use updateSource(). + * + */ +nmsData._genericUpdater = function(name, cacheok) { + if (this.stats.outstandingAjaxRequests++ > this._ajaxThreshold) { + this.stats.outstandingAjaxRequests--; + this.stats.ajaxOverflow++; + return; + } + var now = ""; + if (this._now != undefined) + now = "now=" + this._now; + if (now != "") { + if (this._sources[name].target.match("\\?")) + now = "&" + now; + else + now = "?" + now; + } + var heads = {}; + if (cacheok == false) { + heads['Cache-Control'] = "max-age=0, no-cache, stale-while-revalidate=0"; + } + + $.ajax({ + type: "GET", + headers: heads, + url: this._sources[name].target + now, + dataType: "json", + success: function (data, textStatus, jqXHR) { + if (nmsData[name] == undefined || nmsData[name]['hash'] != data['hash']) { + nmsData._last = data['time']; + nmsData.old[name] = nmsData[name]; + nmsData[name] = data; + nmsMap.drawNow(); + for (var i in nmsData._sources[name].cbs) { + var tmp = nmsData._sources[name].cbs[i]; + if (tmp.cb != undefined) { + tmp.cb(tmp.cbdata); + } + } + } else { + for (var i in nmsData._sources[name].cbs) { + var tmp = nmsData._sources[name].cbs[i]; + if (tmp.cb != undefined && tmp.fresh) { + nmsData._sources[name].cbs[i].fresh = false; + tmp.cb(tmp.cbdata); + } + } + nmsData.stats.identicalFetches++; + } + }, + complete: function(jqXHR, textStatus) { + nmsData.stats.outstandingAjaxRequests--; + } + }); +}; -- cgit v1.2.3 From 8e2fb5f3c7fbfbb13224f0cb8a610837bfef364a Mon Sep 17 00:00:00 2001 From: Kristian Lyngstol Date: Tue, 22 Mar 2016 19:54:00 +0100 Subject: Update nms-public code --- web/nms-public.gathering.org/js/nms-data.js | 33 +++++++++++++---------------- 1 file changed, 15 insertions(+), 18 deletions(-) (limited to 'web/nms-public.gathering.org/js/nms-data.js') diff --git a/web/nms-public.gathering.org/js/nms-data.js b/web/nms-public.gathering.org/js/nms-data.js index 6432a8d..14e5fed 100644 --- a/web/nms-public.gathering.org/js/nms-data.js +++ b/web/nms-public.gathering.org/js/nms-data.js @@ -82,7 +82,7 @@ var nmsData = nmsData || { nmsData._dropData = function (name) { delete this[name]; delete this.old[name]; -} +}; nmsData.removeSource = function (name) { if (this._sources[name] == undefined) { @@ -94,7 +94,7 @@ nmsData.removeSource = function (name) { clearInterval(this._sources[name]['handle']); } delete this._sources[name]; -} +}; /* * Register a source. @@ -121,7 +121,7 @@ nmsData.registerSource = function(name, target) { } this.stats.pollSets++; -} +}; /* * Add a handler (callback) for a source, using an id. @@ -130,7 +130,6 @@ nmsData.registerSource = function(name, target) { * old id, not add a copy. */ nmsData.addHandler = function(name, id, cb, cbdata) { - try { var cbob = { id: id, name: name, @@ -143,9 +142,7 @@ nmsData.addHandler = function(name, id, cb, cbdata) { } this._sources[name].cbs[id] = cbob; this.updateSource(name); - } catch (e) { - } -} +}; /* * Unregister all handlers with the "id" for all sources. @@ -157,11 +154,11 @@ nmsData.unregisterHandlerWildcard = function(id) { for (var v in nmsData._sources) { this.unregisterHandler(v, id); } -} +}; nmsData.unregisterHandler = function(name, id) { delete this._sources[name].cbs[id]; -} +}; /* * Updates a source. @@ -184,11 +181,11 @@ nmsData.updateSource = function(name) { return; } this._genericUpdater(name, true); -} +}; nmsData.invalidate = function(name) { this._genericUpdater(name, false); -} +}; /* * Reset a source, deleting all data, including old. * @@ -198,7 +195,7 @@ nmsData.resetSource = function(name) { this[name] = {}; this.old[name] = {}; this.updateSource(name); -} +}; /* * Updates nmsData[name] and nmsData.old[name], issuing any callbacks where @@ -239,16 +236,16 @@ nmsData._genericUpdater = function(name, cacheok) { nmsData[name] = data; nmsMap.drawNow(); for (var i in nmsData._sources[name].cbs) { - var tmp = nmsData._sources[name].cbs[i]; - if (tmp.cb != undefined) { - tmp.cb(tmp.cbdata); + var tmp2 = nmsData._sources[name].cbs[i]; + if (tmp2.cb != undefined) { + tmp2.cb(tmp2.cbdata); } } } else { - for (var i in nmsData._sources[name].cbs) { - var tmp = nmsData._sources[name].cbs[i]; + for (var j in nmsData._sources[name].cbs) { + var tmp = nmsData._sources[name].cbs[j]; if (tmp.cb != undefined && tmp.fresh) { - nmsData._sources[name].cbs[i].fresh = false; + nmsData._sources[name].cbs[j].fresh = false; tmp.cb(tmp.cbdata); } } -- cgit v1.2.3