From 5b000365dd6ebbc9d1dc0b17c024cdc627289c5e Mon Sep 17 00:00:00 2001 From: Kristian Lyngstol Date: Thu, 10 Mar 2016 23:02:03 +0000 Subject: NMS: front: Prototyping of new generic poller Not used yet --- web/nms.gathering.org/js/nms-data.js | 142 +++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 web/nms.gathering.org/js/nms-data.js (limited to 'web/nms.gathering.org/js/nms-data.js') diff --git a/web/nms.gathering.org/js/nms-data.js b/web/nms.gathering.org/js/nms-data.js new file mode 100644 index 0000000..4dda8e4 --- /dev/null +++ b/web/nms.gathering.org/js/nms-data.js @@ -0,0 +1,142 @@ +"use strict"; + +/************************************************************************** + * * + * THIS IS WORK IN PROGRESS, NOT CURRENTLY USED! * + * * + * It WILL eventually replace large chunks of nms.js. But we're not there * + * yet. * + * * + **************************************************************************/ + + +/* + * This file/module/whatever is an attempt to gather all data collection in + * one place. + * + * It is work in progress. + * + * 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. + * + * Public interfaces: + * nmsData.data[name] - actual data + * nmsData.registerSource() - add a source, will be polled periodicall + * nmsData.updateSource() - issue a one-off update, outside of whatever + * periodic polling might take place + */ + + +var nmsData = nmsData || { + data: {}, // Actual data + sources: {}, + + // Tracks metdata (hashes/timestamps) + poller: { + hashes:{}, + time:{} + }, + // setInterval handlers (and more?) + pollers: { + + }, + stats: { + identicalFetches:0, + outstandingAjaxRequests:0, + ajaxOverflow:0, + pollClears:0, + pollSets:0 + } +}; + +/* + * Register a source. + * + * name: "Local" name. Maps to nmsData.data[name] + * remotename: The primary attribute to get from the remote source. + * 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. + * + * 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++; + } + this.sources[name] = { remotename: remotename, target: target, cb: cb, cbdata: cbdata }; + this.pollers[name] = setInterval(function(){nmsData.updateSource(name)}, 1000); + this.stats.pollSets++; +} + +/* + * 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) { + nmsData.genericUpdater(name, + this.sources[name].remotename, + this.sources[name].target, + this.sources[name].cb, + this.sources[name].cbdata); +} + +/* + * Updates nmsData.data[name] with data fetched from remote target in + * variable "remotename". If a callback is provided, it is called with + * argument meh. + * + * This also populates nms.pollers[name] with the server-provided hash. + * Only if a change is detected is the callback issued. + * + * Used by registerSource. + */ +nmsData.genericUpdater = function(name, remotename, target, cb, meh) { + if (this.stats.outstandingAjaxRequests > 5) { + this.stats.ajaxOverflow++; + return; + } + this.stats.outstandingAjaxRequests++; + var now = ""; + /* + if (nms.now != false) + now = "now=" + nms.now; + if (now != "") { + if (target.match("\\?")) + now = "&" + now; + else + now = "?" + now; + } + */ + $.ajax({ + type: "GET", + url: target + now, + dataType: "text", + 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); + } + } else { + nmsData.stats.identicalFetches++; + } + }, + complete: function(jqXHR, textStatus) { + nmsData.stats.outstandingAjaxRequests--; + //updateAjaxInfo(); + } + }); +}; -- cgit v1.2.3 From a7eb97d873b94cc8fcc5d23dc10e567c42c95a22 Mon Sep 17 00:00:00 2001 From: Kristian Lyngstol Date: Sat, 12 Mar 2016 17:30:26 +0000 Subject: NMS: Prototype of nms-data seriously updated I think it's ready now... --- web/nms.gathering.org/js/nms-data.js | 187 +++++++++++++++++++++++++---------- 1 file changed, 134 insertions(+), 53 deletions(-) (limited to 'web/nms.gathering.org/js/nms-data.js') 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 @@ -10,6 +10,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(); } }); }; -- cgit v1.2.3 From d38e6ba26931cffd6c09128dfeb7321bc224ede3 Mon Sep 17 00:00:00 2001 From: Kristian Lyngstol Date: Sat, 12 Mar 2016 18:14:43 +0000 Subject: NMSjs: Start applying the nmsData logic aka: break * Things are currently somewhat broken, as expected. No handlers are updated. All in all, this isn't a disaster because it reveals a lot of crud that should never have been tied in with this logic to begin with. Will continue working on it after dinner. --- web/nms.gathering.org/js/nms-data.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'web/nms.gathering.org/js/nms-data.js') diff --git a/web/nms.gathering.org/js/nms-data.js b/web/nms.gathering.org/js/nms-data.js index 5f5a2b4..67f71a2 100644 --- a/web/nms.gathering.org/js/nms-data.js +++ b/web/nms.gathering.org/js/nms-data.js @@ -137,6 +137,7 @@ nmsData.removeSource = function (name) { * FIXME: Should be unified with nmsTimers() somehow. */ nmsData.registerSource = function(name, target, cb, cbdata) { + var fresh = false; var cbob = { name: name, cb: cb, @@ -146,12 +147,15 @@ nmsData.registerSource = function(name, target, cb, cbdata) { this._sources[name] = { target: target, cbs: [] }; this._sources[name]['handle'] = setInterval(function(){nmsData.updateSource(name)}, 1000); this.stats.newSource++; + fresh = true; } else { this.stats.oldSource++; } this._sources[name].cbs.push(cbob); this.stats.pollSets++; + if (fresh) + this.updateSource(name); } /* @@ -189,7 +193,6 @@ nmsData._genericUpdater = function(name) { this.stats.ajaxOverflow++; return; } - this.stats.outstandingAjaxRequests++; var now = ""; if (this._now != undefined) now = "now=" + this._now; @@ -210,7 +213,9 @@ nmsData._genericUpdater = function(name) { nmsData[name] = data; for (var i in nmsData._sources[name].cbs) { var tmp = nmsData._sources[name].cbs[i]; - tmp.cb(tmp.cbdata); + if (tmp.cb != undefined) { + tmp.cb(tmp.cbdata); + } } } else { nmsData.stats.identicalFetches++; -- cgit v1.2.3 From 93cf4e90320df21215a081a389cd2ab98a8a2d0d Mon Sep 17 00:00:00 2001 From: Kristian Lyngstol Date: Sat, 12 Mar 2016 23:31:36 +0000 Subject: NMSjs: Bump map handlers and more The idea is that map handlers just register for events instead of this periodic update. --- web/nms.gathering.org/js/nms-data.js | 55 +++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 14 deletions(-) (limited to 'web/nms.gathering.org/js/nms-data.js') diff --git a/web/nms.gathering.org/js/nms-data.js b/web/nms.gathering.org/js/nms-data.js index 67f71a2..7ef11ba 100644 --- a/web/nms.gathering.org/js/nms-data.js +++ b/web/nms.gathering.org/js/nms-data.js @@ -44,6 +44,7 @@ nmsCore.assert = function(cb) { * * nmsData.data[name] - actual 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 */ @@ -124,8 +125,6 @@ nmsData.removeSource = function (name) { * * name: "Local" name. Maps to nmsData[name] * target: URL of the source - * cb: Optional callback - * cbdata: Optional callback data * * 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. @@ -136,26 +135,47 @@ nmsData.removeSource = function (name) { * * FIXME: Should be unified with nmsTimers() somehow. */ -nmsData.registerSource = function(name, target, cb, cbdata) { - var fresh = false; - var cbob = { - name: name, - cb: cb, - cbdata: cbdata - }; +nmsData.registerSource = function(name, target) { if (this._sources[name] == undefined) { - this._sources[name] = { target: target, cbs: [] }; + this._sources[name] = { target: target, cbs: {}, fresh: true }; this._sources[name]['handle'] = setInterval(function(){nmsData.updateSource(name)}, 1000); this.stats.newSource++; - fresh = true; } else { this.stats.oldSource++; } - this._sources[name].cbs.push(cbob); this.stats.pollSets++; - if (fresh) - this.updateSource(name); +} + +nmsData.addHandler = function(name, id, cb, cbdata) { + 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); +} + +/* + * 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]; } /* @@ -218,6 +238,13 @@ nmsData._genericUpdater = function(name) { } } } 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++; } }, -- cgit v1.2.3 From 7ac403641bca2ef24573e3c750ba801dd9b278e1 Mon Sep 17 00:00:00 2001 From: Kristian Lyngstol Date: Sun, 13 Mar 2016 00:58:48 +0000 Subject: NMSjs: Get rid of more cruft. --- web/nms.gathering.org/js/nms-data.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'web/nms.gathering.org/js/nms-data.js') diff --git a/web/nms.gathering.org/js/nms-data.js b/web/nms.gathering.org/js/nms-data.js index 7ef11ba..2d7fc01 100644 --- a/web/nms.gathering.org/js/nms-data.js +++ b/web/nms.gathering.org/js/nms-data.js @@ -82,11 +82,12 @@ var nmsData = nmsData || { */ get now() { return this._now || this._last; }, set now(val) { - if (val == undefined) { - this._now = undefined; + if (val == undefined || !val) { + nmsData._now = undefined; + } else { + // FIXME: Check if now is valid syntax. + nmsData._now = val; } - // FIXME: Check if now is valid syntax. - this._now = now; }, /* * List of sources, name, handler, etc @@ -170,11 +171,11 @@ nmsData.addHandler = function(name, id, cb, cbdata) { */ nmsData.unregisterHandlerWildcard = function(id) { for (var v in nmsData._sources) { - this._unregisterHandler(v, id); + this.unregisterHandler(v, id); } } -nmsData._unregisterHandler = function(name, id) { +nmsData.unregisterHandler = function(name, id) { delete this._sources[name].cbs[id]; } @@ -227,10 +228,11 @@ nmsData._genericUpdater = function(name) { url: this._sources[name].target + now, dataType: "json", success: function (data, textStatus, jqXHR) { - nmsData._last = data['time']; 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) { -- cgit v1.2.3 From f8482d205ea5eaaa0aac33ab3cd450b41126ef39 Mon Sep 17 00:00:00 2001 From: Kristian Lyngstol Date: Sun, 13 Mar 2016 12:08:43 +0000 Subject: NMSjs: Split the info box out and clean further + tweak --- web/nms.gathering.org/js/nms-data.js | 53 ++++++++++++++---------------------- 1 file changed, 20 insertions(+), 33 deletions(-) (limited to 'web/nms.gathering.org/js/nms-data.js') diff --git a/web/nms.gathering.org/js/nms-data.js b/web/nms.gathering.org/js/nms-data.js index 2d7fc01..89d93fd 100644 --- a/web/nms.gathering.org/js/nms-data.js +++ b/web/nms.gathering.org/js/nms-data.js @@ -1,37 +1,9 @@ "use strict"; -/************************************************************************** - * * - * THIS IS WORK IN PROGRESS, NOT CURRENTLY USED! * - * * - * It WILL eventually replace large chunks of nms.js. But we're not there * - * yet. * - * * - **************************************************************************/ - - -/* - * 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. * - * It is work in progress. - * * 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 @@ -42,11 +14,13 @@ nmsCore.assert = function(cb) { * nmsData.old[name]. You can use getNow / setNow() to append a 'now=' * string. * - * nmsData.data[name] - actual data + * 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. */ @@ -103,8 +77,6 @@ var nmsData = nmsData || { nmsData._dropData = function (name) { - nmsCore.assert(name); - nmsCore.assert(this[name]); delete this[name]; delete this.old[name]; } @@ -148,6 +120,12 @@ nmsData.registerSource = function(name, target) { 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) { var cbob = { id: id, @@ -187,9 +165,12 @@ nmsData.unregisterHandler = function(name, id) { * after a comment is posted). */ nmsData.updateSource = function(name) { - this._genericUpdater(name); + this._genericUpdater(name, true); } +nmsData.invalidate = function(name) { + this._genericUpdater(name, false); +} /* * Reset a source, deleting all data, including old. * @@ -208,7 +189,7 @@ nmsData.resetSource = function(name) { * Do not use this directly. Use updateSource(). * */ -nmsData._genericUpdater = function(name) { +nmsData._genericUpdater = function(name, cacheok) { if (this.stats.outstandingAjaxRequests++ > this._ajaxThreshold) { this.stats.outstandingAjaxRequests--; this.stats.ajaxOverflow++; @@ -223,8 +204,14 @@ nmsData._genericUpdater = function(name) { 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) { -- cgit v1.2.3 From e7eb548d99a324048d6fd08cb5a0243e47753451 Mon Sep 17 00:00:00 2001 From: Kristian Lyngstol Date: Sun, 13 Mar 2016 15:54:14 +0000 Subject: NMSjs: Enable interactive movement of switches! Fixes #24 God that felt good. It's not very pretty, but it does seem very functional. --- web/nms.gathering.org/js/nms-data.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'web/nms.gathering.org/js/nms-data.js') diff --git a/web/nms.gathering.org/js/nms-data.js b/web/nms.gathering.org/js/nms-data.js index 89d93fd..ef41a3a 100644 --- a/web/nms.gathering.org/js/nms-data.js +++ b/web/nms.gathering.org/js/nms-data.js @@ -71,8 +71,11 @@ var nmsData = nmsData || { /* * 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: 5 + _ajaxThreshold: 10 }; -- cgit v1.2.3