summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2019-04-05 07:55:54 +0200
committerJo-Philipp Wich <jo@mein.io>2019-07-07 15:36:24 +0200
commiteee323cb6683e6f1f1da7059e49eb8f4498bedf6 (patch)
tree3f319f5f18f62dcbdc65e15888dcf166cc666f54
parent8a8e8e0aac356d03273caf20df80736a2daa339e (diff)
luci-base: luci.js: introduce generic LuCI.Poll
Introduce a new LuCI.Poll class which is able to repeat any promise based function and not strictly tied to HTTP request semantics. Also rework LuCI.Request.Poll and XHR.Poll as well as LuCI.start(), LuCI.stop(), LuCI.halt() etc. to redirect to the new api. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-rw-r--r--modules/luci-base/htdocs/luci-static/resources/luci.js172
1 files changed, 102 insertions, 70 deletions
diff --git a/modules/luci-base/htdocs/luci-static/resources/luci.js b/modules/luci-base/htdocs/luci-static/resources/luci.js
index 19f4a54c7..fbbb23054 100644
--- a/modules/luci-base/htdocs/luci-static/resources/luci.js
+++ b/modules/luci-base/htdocs/luci-static/resources/luci.js
@@ -331,97 +331,127 @@
return (this.interceptors.length < oldlen);
},
- poll: Class.singleton({
- __name__: 'LuCI.Request.Poll',
-
- queue: [],
-
+ poll: {
add: function(interval, url, options, callback) {
if (isNaN(interval) || interval <= 0)
throw new TypeError('Invalid poll interval');
- var e = {
- interval: interval,
- url: url,
- options: options,
- callback: callback
- };
+ var ival = interval >>> 0,
+ opts = Object.assign({}, options, { timeout: ival * 1000 - 5 });
+
+ return Poll.add(function() {
+ return Request.request(url, options).then(function(res) {
+ if (!Poll.active())
+ return;
- this.queue.push(e);
- return e;
+ try {
+ callback(res, res.json(), res.duration);
+ }
+ catch (err) {
+ callback(res, null, res.duration);
+ }
+ });
+ }, ival);
},
- remove: function(entry) {
- var oldlen = this.queue.length, i = oldlen;
+ remove: function(entry) { return Poll.remove(entry) },
+ start: function() { return Poll.start() },
+ stop: function() { return Poll.stop() },
+ active: function() { return Poll.active() }
+ }
+ });
- while (i--)
- if (this.queue[i] === entry) {
- delete this.queue[i].running;
- this.queue.splice(i, 1);
- }
+ var Poll = Class.singleton({
+ __name__: 'LuCI.Poll',
- if (!this.queue.length)
- this.stop();
+ queue: [],
- return (this.queue.length < oldlen);
- },
+ add: function(fn, interval) {
+ if (interval == null || interval <= 0)
+ interval = window.L ? window.L.env.pollinterval : null;
+
+ if (isNaN(interval) || typeof(fn) != 'function')
+ throw new TypeError('Invalid argument to LuCI.Poll.add()');
- start: function() {
- if (!this.queue.length || this.active())
+ for (var i = 0; i < this.queue.length; i++)
+ if (this.queue[i].fn === fn)
return false;
+ var e = {
+ r: true,
+ i: interval >>> 0,
+ fn: fn
+ };
+
+ this.queue.push(e);
+
+ if (this.tick != null && !this.active())
+ this.start();
+
+ return true;
+ },
+
+ remove: function(entry) {
+ if (typeof(fn) != 'function')
+ throw new TypeError('Invalid argument to LuCI.Poll.remove()');
+
+ var len = this.queue.length;
+
+ for (var i = len; i > 0; i--)
+ if (this.queue[i-1].fn === fn)
+ this.queue.splice(i-1, 1);
+
+ if (!this.queue.length && this.stop())
this.tick = 0;
+
+ return (this.queue.length != len);
+ },
+
+ start: function() {
+ if (this.active())
+ return false;
+
+ this.tick = 0;
+
+ if (this.queue.length) {
this.timer = window.setInterval(this.step, 1000);
this.step();
document.dispatchEvent(new CustomEvent('poll-start'));
- return true;
- },
+ }
- stop: function() {
- if (!this.active())
- return false;
+ return true;
+ },
- document.dispatchEvent(new CustomEvent('poll-stop'));
- window.clearInterval(this.timer);
- delete this.timer;
- delete this.tick;
- return true;
- },
+ stop: function() {
+ if (!this.active())
+ return false;
- step: function() {
- Request.poll.queue.forEach(function(e) {
- if ((Request.poll.tick % e.interval) != 0)
- return;
+ document.dispatchEvent(new CustomEvent('poll-stop'));
+ window.clearInterval(this.timer);
+ delete this.timer;
+ delete this.tick;
+ return true;
+ },
- if (e.running)
- return;
+ step: function() {
+ for (var i = 0, e = null; (e = Poll.queue[i]) != null; i++) {
+ if ((Poll.tick % e.i) != 0)
+ continue;
- var opts = Object.assign({}, e.options,
- { timeout: e.interval * 1000 - 5 });
+ if (!e.r)
+ continue;
- e.running = true;
- Request.request(e.url, opts)
- .then(function(res) {
- if (!e.running || !Request.poll.active())
- return;
+ e.r = false;
- try {
- e.callback(res, res.json(), res.duration);
- }
- catch (err) {
- e.callback(res, null, res.duration);
- }
- })
- .finally(function() { delete e.running });
- });
+ Promise.resolve(e.fn()).finally((function() { this.r = true }).bind(e));
+ }
- Request.poll.tick = (Request.poll.tick + 1) % Math.pow(2, 32);
- },
+ Poll.tick = (Poll.tick + 1) % Math.pow(2, 32);
+ },
- active: function() {
- return (this.timer != null);
- }
- })
+ active: function() {
+ return (this.timer != null);
+ }
});
@@ -635,7 +665,7 @@
if (res.status != 403 || res.headers.get('X-LuCI-Login-Required') != 'yes')
return;
- Request.poll.stop();
+ Poll.stop();
L.ui.showModal(_('Session expired'), [
E('div', { class: 'alert-message warning' },
@@ -654,7 +684,8 @@
});
originalCBIInit();
- Request.poll.start();
+
+ Poll.start();
document.dispatchEvent(new CustomEvent('luci-loaded'));
},
@@ -722,9 +753,9 @@
});
},
- stop: function(entry) { return Request.poll.remove(entry) },
- halt: function() { return Request.poll.stop() },
- run: function() { return Request.poll.start() },
+ stop: function(entry) { return Poll.remove(entry) },
+ halt: function() { return Poll.stop() },
+ run: function() { return Poll.start() },
/* DOM manipulation */
dom: Class.singleton({
@@ -965,6 +996,7 @@
}
}),
+ Poll: Poll,
Class: Class,
Request: Request,