diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index d079b235..a41e1dbc 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -10,7 +10,7 @@ jobs:
steps:
- uses: actions/checkout@v1
- name: Install Dependencies
- run: sudo apt install lua-check
+ run: sudo apt-get -y update && sudo apt-get -y install lua-check
- name: Install example site
run: ln -s ./docs/site-example ./site
- name: Lint Lua code
@@ -22,7 +22,7 @@ jobs:
steps:
- uses: actions/checkout@v1
- name: Install Dependencies
- run: sudo apt install shellcheck
+ run: sudo apt-get -y update && sudo apt-get -y install shellcheck
- name: Install example site
run: ln -s ./docs/site-example ./site
- name: Lint shell code
diff --git a/Makefile b/Makefile
index 4ff9f0c6..76aa9cb2 100644
--- a/Makefile
+++ b/Makefile
@@ -19,8 +19,9 @@ escape = '$(subst ','\'',$(1))'
GLUON_SITEDIR ?= site
$(eval $(call mkabspath,GLUON_SITEDIR))
-$(GLUON_SITEDIR)/site.mk:
- $(error No site configuration was found. Please check out a site configuration to $(GLUON_SITEDIR))
+ifeq ($(realpath $(GLUON_SITEDIR)/site.mk),)
+$(error No site configuration was found. Please check out a site configuration to $(GLUON_SITEDIR))
+endif
include $(GLUON_SITEDIR)/site.mk
diff --git a/docs/user/site.rst b/docs/user/site.rst
index 408cf455..31fb2653 100644
--- a/docs/user/site.rst
+++ b/docs/user/site.rst
@@ -478,7 +478,7 @@ config_mode \: optional
*openlayers_url* allows to override the base URL of the
*build/ol.js* and *css/ol.css* files (the default is
- ``https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.2.0``).
+ ``https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@35ffe7626ce16c372143f3c903950750075e7068/en/v5.3.0``).
It is also possible to replace the default tile layer (which is OpenStreetMap)
with a custom one using the *tile_layer* section. Only XYZ layers are supported
at this point.
diff --git a/package/gluon-config-mode-core/luasrc/lib/gluon/config-mode/model/gluon-config-mode/wizard.lua b/package/gluon-config-mode-core/luasrc/lib/gluon/config-mode/model/gluon-config-mode/wizard.lua
index dfc4ab4c..edfe0bc3 100644
--- a/package/gluon-config-mode-core/luasrc/lib/gluon/config-mode/model/gluon-config-mode/wizard.lua
+++ b/package/gluon-config-mode-core/luasrc/lib/gluon/config-mode/model/gluon-config-mode/wizard.lua
@@ -22,7 +22,7 @@ function f:write()
uci:set("gluon-setup-mode", uci:get_first("gluon-setup-mode", "setup_mode"), "configured", true)
uci:save("gluon-setup-mode")
- os.execute('gluon-reconfigure')
+ os.execute('exec gluon-reconfigure >/dev/null')
f.template = "wizard/reboot"
f.package = "gluon-config-mode-core"
diff --git a/package/gluon-neighbour-info/src/gluon-neighbour-info.c b/package/gluon-neighbour-info/src/gluon-neighbour-info.c
index 6470508c..119aaddc 100644
--- a/package/gluon-neighbour-info/src/gluon-neighbour-info.c
+++ b/package/gluon-neighbour-info/src/gluon-neighbour-info.c
@@ -69,8 +69,23 @@ void tv_subtract (struct timeval *r, const struct timeval *a, const struct timev
}
}
-ssize_t recvtimeout(int socket, void *buffer, size_t length, int flags, const struct timeval *timeout) {
+void resize_recvbuffer(char **recvbuffer, size_t *recvbuffer_len, size_t recvlen)
+{
+ free(*recvbuffer);
+ *recvbuffer = malloc(recvlen);
+
+ if (!(*recvbuffer)) {
+ perror("Could not resize recvbuffer");
+ exit(EXIT_FAILURE);
+ }
+
+ *recvbuffer_len = recvlen;
+}
+
+ssize_t recvtimeout(int socket, char **recvbuffer, size_t *recvbuffer_len,
+ const struct timeval *timeout) {
struct timeval now, timeout_left;
+ ssize_t recvlen;
getclock(&now);
tv_subtract(&timeout_left, timeout, &now);
@@ -79,18 +94,28 @@ ssize_t recvtimeout(int socket, void *buffer, size_t length, int flags, const st
return -1;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &timeout_left, sizeof(timeout_left));
- return recv(socket, buffer, length, flags);
+
+ recvlen = recv(socket, NULL, 0, MSG_PEEK | MSG_TRUNC);
+ if (recvlen < 0)
+ return recvlen;
+
+ if (recvlen > *recvbuffer_len)
+ resize_recvbuffer(recvbuffer, recvbuffer_len, recvlen);
+
+ return recv(socket, *recvbuffer, *recvbuffer_len, 0);
}
-int request(const int sock, const struct sockaddr_in6 *client_addr, const char *request, const char *sse, double timeout, unsigned int max_count) {
+int request(const int sock, char **recvbuffer, size_t *recvbuffer_len,
+ const struct sockaddr_in6 *client_addr, const char *request,
+ const char *sse, double timeout, unsigned int max_count) {
ssize_t ret;
- char buffer[8192];
unsigned int count = 0;
ret = sendto(sock, request, strlen(request), 0, (struct sockaddr *)client_addr, sizeof(struct sockaddr_in6));
if (ret < 0) {
perror("Error in sendto()");
+ free(*recvbuffer);
exit(EXIT_FAILURE);
}
@@ -105,7 +130,7 @@ int request(const int sock, const struct sockaddr_in6 *client_addr, const char *
}
do {
- ret = recvtimeout(sock, buffer, sizeof(buffer), 0, &tv_timeout);
+ ret = recvtimeout(sock, recvbuffer, recvbuffer_len, &tv_timeout);
if (ret < 0)
break;
@@ -116,7 +141,7 @@ int request(const int sock, const struct sockaddr_in6 *client_addr, const char *
fputs("data: ", stdout);
}
- fwrite(buffer, sizeof(char), ret, stdout);
+ fwrite(*recvbuffer, sizeof(char), ret, stdout);
if (sse)
fputs("\n\n", stdout);
@@ -137,6 +162,8 @@ int main(int argc, char **argv) {
int sock;
struct sockaddr_in6 client_addr = {};
char *request_string = NULL;
+ char *recvbuffer = NULL;
+ size_t recvbuffer_len = 0;
sock = socket(PF_INET6, SOCK_DGRAM, 0);
@@ -243,11 +270,13 @@ int main(int argc, char **argv) {
}
do {
- ret = request(sock, &client_addr, request_string, sse, timeout, max_count);
+ ret = request(sock, &recvbuffer, &recvbuffer_len, &client_addr,
+ request_string, sse, timeout, max_count);
} while(loop);
if (sse)
fputs("event: eot\ndata: null\n\n", stdout);
+ free(recvbuffer);
return ret;
}
diff --git a/package/gluon-status-page/files/lib/gluon/status-page/view/status-page.html b/package/gluon-status-page/files/lib/gluon/status-page/view/status-page.html
index 861c13a4..6957599f 100644
--- a/package/gluon-status-page/files/lib/gluon/status-page/view/status-page.html
+++ b/package/gluon-status-page/files/lib/gluon/status-page/view/status-page.html
@@ -1,7 +1,11 @@
<%-
+ local iwinfo = require 'iwinfo'
local ubus = require 'ubus'
local unistd = require 'posix.unistd'
local util = require 'gluon.util'
+ local wireless = require 'gluon.wireless'
+
+ local uci = require('simple-uci').cursor()
local translations = {}
local site_i18n = i18n 'gluon-site'
@@ -29,17 +33,31 @@
local mesh = get_mesh()
- local function get_interfaces()
- local uconn = ubus.connect()
- if not uconn then
- error('failed to connect to ubus')
- end
+ local function get_interfaces(uconn)
local interfaces = util.get_mesh_devices(uconn)
- ubus.close(uconn)
table.sort(interfaces)
return interfaces
end
+ local function get_radios()
+ local ret = {}
+
+ wireless.foreach_radio(uci, function(radio)
+ local channel = iwinfo.nl80211.channel(wireless.find_phy(radio))
+ if channel then
+ table.insert(ret, {
+ name = radio['.name'],
+ channel = channel,
+ })
+ end
+ end)
+ table.sort(ret, function(a, b)
+ return a.name < b.name
+ end)
+
+ return ret
+ end
+
local function is_wireless(iface)
while true do
local pattern = '/sys/class/net/' .. iface .. '/lower_*'
@@ -52,7 +70,16 @@
return unistd.access('/sys/class/net/' .. iface .. '/wireless') ~= nil
end
- local interfaces = get_interfaces()
+ local uconn = ubus.connect()
+ if not uconn then
+ error('failed to connect to ubus')
+ end
+
+ local interfaces = get_interfaces(uconn)
+
+ ubus.close(uconn)
+
+ local radios = get_radios()
local function sorted(t)
t = {unpack(t)}
@@ -66,12 +93,17 @@
local function formatBits(bits)
local units = {[0]='', 'k', 'M', 'G'}
+ local unit = 0
- local pow = math.floor(math.log(math.max(math.abs(bits), 1)) / math.log(1000))
- local known_pow = math.min(pow, #units)
+ for i = 1, #units do
+ if math.abs(bits) < 1000 then
+ break
+ end
+ unit = i
+ bits = bits / 1000
+ end
- local significand = bits/(1000^known_pow)
- return string.format('%g %sbit', significand, units[known_pow])
+ return string.format('%g %sbit', bits, units[unit])
end
local function statistics(key, format)
@@ -135,11 +167,11 @@
<% if nodeinfo.network.mesh_vpn.bandwidth_limit.enabled then -%>
<%:Bandwidth limit%>
- <% if nodeinfo.network.mesh_vpn.bandwidth_limit.egress then -%>
- ▲ <%| formatBits(nodeinfo.network.mesh_vpn.bandwidth_limit.egress*1000) %>/s <%:upstream%>
- <%- end %>
<% if nodeinfo.network.mesh_vpn.bandwidth_limit.ingress then -%>
- ▼ <%| formatBits(nodeinfo.network.mesh_vpn.bandwidth_limit.ingress*1000) %>/s <%:downstream%>
+ ▼ <%| formatBits(nodeinfo.network.mesh_vpn.bandwidth_limit.ingress*1000) %>/s <%:downstream%>
+ <%- end %>
+ <% if nodeinfo.network.mesh_vpn.bandwidth_limit.egress then -%>
+ ▲ <%| formatBits(nodeinfo.network.mesh_vpn.bandwidth_limit.egress*1000) %>/s <%:upstream%>
<%- end %>
<%- end %>
@@ -190,11 +222,17 @@
<%:Wireless 2.4 GHz%> <%= statistics('clients/wifi24') %>
<%:Wireless 5 GHz%> <%= statistics('clients/wifi5') %>
-
+ <% if radios[1] then -%>
<%:Radios%>
-
+
+ <% for _, radio in ipairs(radios) do -%>
+
+ <%| radio.name %>
+ <%| translatef('Channel %u', radio.channel) %>
+
+ <%- end %>
-
+ <%- end %>
<%:Traffic%>
diff --git a/package/gluon-status-page/files/lib/gluon/status-page/www/static/status-page.js b/package/gluon-status-page/files/lib/gluon/status-page/www/static/status-page.js
index 3fe35c37..21c3c692 100644
--- a/package/gluon-status-page/files/lib/gluon/status-page/www/static/status-page.js
+++ b/package/gluon-status-page/files/lib/gluon/status-page/www/static/status-page.js
@@ -1 +1 @@
-"use strict";!function(){var r=JSON.parse(document.body.getAttribute("data-translations"));function i(t,e){return t.toFixed(e).replace(/\./,r["."])}function o(t,e){e--;for(var n=t;10<=n&&0 Channel "+(2484===(t=t.frequency)?14:2412<=t&&t<=2472?(t-2407)/5:5160<=t&&t<=5885?(t-5e3)/5:"unknown"),e.appendChild(n),i.appendChild(e)})}else e.style.display="none"}var n=document.querySelectorAll("[data-statistics]");d("/cgi-bin/dyn/statistics",function(o,a){var c=o.uptime-a.uptime;n.forEach(function(t){var e=t.getAttribute("data-statistics"),n=t.getAttribute("data-format"),i=l(a,e),e=l(o,e);try{var r=s[n](e,i,c);void 0!==r&&(t.textContent=r)}catch(t){console.error(t)}});try{t(o.mesh_vpn)}catch(t){console.error(t)}try{e(o.wireless)}catch(t){console.error(t)}});var c={};function A(n){var i=document.createElement("canvas"),r=i.getContext("2d"),o=null;return{canvas:i,highlight:!1,resize:function(t,e){try{r.getImageData(0,0,t,e)}catch(t){}i.width=t,i.height=e},draw:function(t,e){e=e(o);r.clearRect(t,0,5,i.height),e&&(t=t,e=e,r.beginPath(),r.fillStyle=n,r.arc(t,e,1.2,0,2*Math.PI,!1),r.closePath(),r.fill())},set:function(t){o=t}}}function h(){var c=-100,s=0,n=0,i=[],l=document.createElement("canvas");l.className="signalgraph",l.height=200;var u=l.getContext("2d");function t(){l.width=l.clientWidth,i.forEach(function(t){t.resize(l.width,l.height)})}function r(){var e;0!==l.clientWidth&&(l.width!==l.clientWidth&&t(),u.clearRect(0,0,l.width,l.height),e=!1,i.forEach(function(t){t.highlight&&(e=!0)}),u.save(),i.forEach(function(t){e&&(u.globalAlpha=.2),t.highlight&&(u.globalAlpha=1),t.draw(n,function(t){return e=t,n=c,i=s,t=l.height,(1-(e-n)/(i-n))*t;var e,n,i}),u.drawImage(t.canvas,0,0)}),u.restore(),u.save(),u.beginPath(),u.strokeStyle="rgba(255, 180, 0, 0.15)",u.lineWidth=5,u.moveTo(n+2.5,0),u.lineTo(n+2.5,l.height),u.stroke(),function(){var t=Math.floor(l.height/40);u.save(),u.lineWidth=.5,u.strokeStyle="rgba(0, 0, 0, 0.25)",u.fillStyle="rgba(0, 0, 0, 0.5)",u.textAlign="end",u.textBaseline="bottom",u.beginPath();for(var e,n,i,r=0;re[0]||t[1]e[1]?1:0});t=t[0][2];return t&&!/^fe80:/i.test(t)?t:void 0}}return t.wireless&&((g=a.insertCell()).textContent="-",g.setAttribute("data-label",o.children[Object.keys(l).length+1].textContent),(v=a.insertCell()).textContent="-",v.setAttribute("data-label",o.children[Object.keys(l).length+2].textContent),(m=a.insertCell()).textContent="-",m.setAttribute("data-label",o.children[Object.keys(l).length+3].textContent),p=A(n),t.signalgraph.addSignal(p)),a.onmouseenter=function(){a.classList.add("highlight"),p&&(p.highlight=!0)},a.onmouseleave=function(){a.classList.remove("highlight"),p&&(p.highlight=!1)},C(),{get_hostname:function(){return s.textContent},update_nodeinfo:function(t){var e,n,i,r,o=w(t.network.addresses);o&&("span"===s.nodeName.toLowerCase()&&(r=s,s=document.createElement("a"),r.parentNode.replaceChild(s,r)),s.href="http://["+o+"]/"),s.textContent=t.hostname,x&&t.location&&(e=x.latitude,n=x.longitude,i=t.location.latitude,r=t.location.longitude,o=Math.PI/180,t=(i*=o)-(e*=o),n=(r*=o)-(n*=o),i=Math.sin(t/2)*Math.sin(t/2)+Math.sin(n/2)*Math.sin(n/2)*Math.cos(e)*Math.cos(i),i=6372.8*(2*Math.asin(Math.sqrt(i))),v.textContent=Math.round(1e3*i)+" m"),C()},update_mesh:function(n){Object.keys(l).forEach(function(t){var e=l[t];e.td.textContent=n[t]+e.suffix}),C()},update_wifi:function(t){g.textContent=t.signal,m.textContent=Math.round(t.inactive/1e3)+" s",a.classList.toggle("inactive",200e[0]||t[1]e[1]?1:0});t=t[0][2];return t&&!/^fe80:/i.test(t)?t:void 0}}return t.wireless&&((g=a.insertCell()).textContent="-",g.setAttribute("data-label",i.children[Object.keys(s).length+1].textContent),(v=a.insertCell()).textContent="-",v.setAttribute("data-label",i.children[Object.keys(s).length+2].textContent),(p=a.insertCell()).textContent="-",p.setAttribute("data-label",i.children[Object.keys(s).length+3].textContent),m=A(e),t.signalgraph.addSignal(m)),a.onmouseenter=function(){a.classList.add("highlight"),m&&(m.highlight=!0)},a.onmouseleave=function(){a.classList.remove("highlight"),m&&(m.highlight=!1)},y(),{get_hostname:function(){return u.textContent},get_addr:function(){return o},update_nodeinfo:function(t){var e,n,r,i,a;(o=E(t.network.addresses))&&("span"===u.nodeName.toLowerCase()&&(a=u,u=document.createElement("a"),a.parentNode.replaceChild(u,a)),u.href="http://["+o+"]/"),u.textContent=t.hostname,x&&t.location&&(e=x.latitude,n=x.longitude,r=t.location.latitude,i=t.location.longitude,a=Math.PI/180,t=(r*=a)-(e*=a),n=(i*=a)-(n*=a),r=Math.sin(t/2)*Math.sin(t/2)+Math.sin(n/2)*Math.sin(n/2)*Math.cos(e)*Math.cos(r),r=6372.8*(2*Math.asin(Math.sqrt(r))),v.textContent=Math.round(1e3*r)+" m"),y()},update_mesh:function(n){Object.keys(s).forEach(function(t){var e=s[t];e.td.textContent=n[t]+e.suffix}),y()},update_wifi:function(t){g.textContent=t.signal,p.textContent=Math.round(t.inactive/1e3)+" s",a.classList.toggle("inactive",200 Channel " + channel(radio.frequency);
- tr.appendChild(td);
-
- table.appendChild(tr);
- });
- }
-
var statisticsElems = document.querySelectorAll('[data-statistics]');
add_event_source('/cgi-bin/dyn/statistics', function(data, dataPrev) {
@@ -264,9 +228,16 @@
var valuePrev = resolve_key(dataPrev, stat);
var value = resolve_key(data, stat);
try {
- var text = formats[format](value, valuePrev, diff);
- if (text !== undefined)
- elem.textContent = text;
+ var format_result = formats[format](value, valuePrev, diff);
+ switch (typeof format_result) {
+ case "object":
+ if (elem.lastChild)
+ elem.removeChild(elem.lastChild);
+ elem.appendChild(format_result);
+ break;
+ default:
+ elem.textContent = format_result;
+ }
} catch (e) {
console.error(e);
}
@@ -277,11 +248,6 @@
} catch (e) {
console.error(e);
}
- try {
- update_radios(data.wireless);
- } catch (e) {
- console.error(e);
- }
})
function haversine(lat1, lon1, lat2, lon2) {
@@ -319,7 +285,7 @@
'resize': function(w, h) {
var lastImage;
try {
- ctx.getImageData(0, 0, w, h);
+ lastImage = ctx.getImageData(0, 0, w, h);
} catch (e) {}
canvas.width = w;
canvas.height = h;
@@ -492,6 +458,7 @@
}
var hostname = document.createElement("span");
+ var addr;
hostname.textContent = addr;
tdHostname.appendChild(hostname);
@@ -552,13 +519,13 @@
el.classList.add("highlight");
if (signal)
signal.highlight = true;
- }
+ };
el.onmouseleave = function () {
- el.classList.remove("highlight")
+ el.classList.remove("highlight");
if (signal)
signal.highlight = false;
- }
+ };
var timeout;
@@ -586,7 +553,8 @@
var n = parts.length;
var groups = [];
- parts.forEach(function(part, i) {
+ for (var i = 0; i < parts.length; i++) {
+ var part = parts[i];
if (part === '') {
while (n++ <= 8)
groups.push(0);
@@ -596,7 +564,7 @@
groups.push(parseInt(part, 16));
}
- });
+ };
return groups;
}
@@ -664,8 +632,11 @@
'get_hostname': function() {
return hostname.textContent;
},
+ 'get_addr': function() {
+ return addr;
+ },
'update_nodeinfo': function(nodeinfo) {
- var addr = choose_address(nodeinfo.network.addresses);
+ addr = choose_address(nodeinfo.network.addresses);
if (addr) {
if (hostname.nodeName.toLowerCase() === 'span') {
var oldHostname = hostname;
diff --git a/package/gluon-status-page/luasrc/lib/gluon/status-page/controller/status-page.lua b/package/gluon-status-page/luasrc/lib/gluon/status-page/controller/status-page.lua
index ceb5d855..80c5e50a 100644
--- a/package/gluon-status-page/luasrc/lib/gluon/status-page/controller/status-page.lua
+++ b/package/gluon-status-page/luasrc/lib/gluon/status-page/controller/status-page.lua
@@ -61,7 +61,7 @@ local function match(a, b, n)
end
entry({}, call(function(http, renderer)
- local nodeinfo = json.parse(util.exec('exec gluon-neighbour-info -d ::1 -p 1001 -t 1 -c 1 -r nodeinfo'))
+ local nodeinfo = json.parse(util.exec('exec gluon-neighbour-info -d ::1 -p 1001 -t 3 -c 1 -r nodeinfo'))
local node_ip = parse_ip(http:getenv('SERVER_ADDR'))
if node_ip and (
diff --git a/package/gluon-web-admin/files/lib/gluon/config-mode/view/admin/upgrade.html b/package/gluon-web-admin/files/lib/gluon/config-mode/view/admin/upgrade.html
index 31555f16..7778be4a 100644
--- a/package/gluon-web-admin/files/lib/gluon/config-mode/view/admin/upgrade.html
+++ b/package/gluon-web-admin/files/lib/gluon/config-mode/view/admin/upgrade.html
@@ -44,7 +44,6 @@ $Id$
-
diff --git a/package/gluon-web-admin/files/lib/gluon/config-mode/view/admin/upgrade_confirm.html b/package/gluon-web-admin/files/lib/gluon/config-mode/view/admin/upgrade_confirm.html
index 92c25a63..9733132f 100644
--- a/package/gluon-web-admin/files/lib/gluon/config-mode/view/admin/upgrade_confirm.html
+++ b/package/gluon-web-admin/files/lib/gluon/config-mode/view/admin/upgrade_confirm.html
@@ -49,13 +49,11 @@ You may obtain a copy of the License at
diff --git a/package/gluon-web-model/files/lib/gluon/web/view/model/form.html b/package/gluon-web-model/files/lib/gluon/web/view/model/form.html
index 06270be3..d222dde2 100644
--- a/package/gluon-web-model/files/lib/gluon/web/view/model/form.html
+++ b/package/gluon-web-model/files/lib/gluon/web/view/model/form.html
@@ -1,5 +1,4 @@