Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • firmware/gluon
  • 0x4A6F/gluon
  • patrick/gluon
3 results
Select Git revision
Show changes
Commits on Source (34)
Showing
with 161 additions and 106 deletions
......@@ -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
......
......@@ -19,8 +19,9 @@ escape = '$(subst ','\'',$(1))'
GLUON_SITEDIR ?= site
$(eval $(call mkabspath,GLUON_SITEDIR))
$(GLUON_SITEDIR)/site.mk:
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
......@@ -176,6 +177,10 @@ config: $(LUA) FORCE
$(GLUON_ENV) $(LUA) scripts/target_config_check.lua
container: FORCE
@scripts/container.sh
all: config
+@
$(GLUON_ENV) $(LUA) scripts/clean_output.lua
......
File moved
......@@ -40,6 +40,12 @@ freshly installed Debian Stretch system the following packages are required:
* `time` (built-in `time` doesn't work)
We also provide a container environment that already tracks all these dependencies. It quickly gets you up and running, if you already have either Docker or Podman installed locally.
::
./scripts/container.sh
Building the images
-------------------
......
......@@ -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.
......
......@@ -2,7 +2,7 @@ GLUON_FEEDS='packages routing gluon'
OPENWRT_REPO=https://github.com/openwrt/openwrt.git
OPENWRT_BRANCH=openwrt-19.07
OPENWRT_COMMIT=ffd4452f8b241d1d5b5ea8a56206f51702bbd6c5
OPENWRT_COMMIT=81d0b4a9f431b2b2ca71edca91febedde98994a3
PACKAGES_PACKAGES_REPO=https://github.com/openwrt/packages.git
PACKAGES_PACKAGES_BRANCH=openwrt-19.07
......@@ -13,4 +13,5 @@ PACKAGES_ROUTING_BRANCH=openwrt-19.07
PACKAGES_ROUTING_COMMIT=101632e153b41238bc19dfd96ba2d23339dbcb76
PACKAGES_GLUON_REPO=https://github.com/freifunk-gluon/packages.git
PACKAGES_GLUON_COMMIT=825aa0c093d6c0b4f81a95cd2320331a5b5adae6
PACKAGES_GLUON_BRANCH=v2021.1.x
PACKAGES_GLUON_COMMIT=015408e702a5843310e40c2ca664e1903b601204
......@@ -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"
......
......@@ -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;
}
<%-
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 -%>
<dt><%:Bandwidth limit%></dt>
<dd>
<% if nodeinfo.network.mesh_vpn.bandwidth_limit.egress then -%>
<%| formatBits(nodeinfo.network.mesh_vpn.bandwidth_limit.egress*1000) %>/s <%:upstream%><br />
<%- 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%><br />
<%- end %>
<% if nodeinfo.network.mesh_vpn.bandwidth_limit.egress then -%>
<%| formatBits(nodeinfo.network.mesh_vpn.bandwidth_limit.egress*1000) %>/s <%:upstream%>
<%- end %>
</dd>
<%- end %>
......@@ -190,11 +222,17 @@
<tr><th><%:Wireless 2.4 GHz%></th><td><%= statistics('clients/wifi24') %></td></tr>
<tr><th><%:Wireless 5 GHz%></th><td><%= statistics('clients/wifi5') %></td></tr>
</table>
<div id="radios" style="display: none">
<% if radios[1] then -%>
<h3><%:Radios%></h3>
<table id="radio-devices">
<table>
<% for _, radio in ipairs(radios) do -%>
<tr>
<th><%| radio.name %></th>
<td><%| translatef('Channel %u', radio.channel) %></td>
</tr>
<%- end %>
</table>
</div>
<%- end %>
<h3><%:Traffic%></h3>
<table>
......
"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<e;n/=10)e--;return i(t,e)}function a(t){return function(t,e,n){var i=0;if(void 0===n)return"- ";for(;e<n&&i<t.length-1;)n/=e,i++;return(n=o(n,3))+" "+t[i]}(["","K","M","G","T"],1024,t)}String.prototype.sprintf=function(){var t=0,e=arguments;return this.replace(/%s/g,function(){return e[t++]})};var s={id:function(t){return t},decimal:function(t){return i(t,2)},percent:function(t){return r["%s used"].sprintf(o(100*t,3)+"%")},memory:function(t){t=1-t.available/t.total;return s.percent(t)},time:function(t){var e=Math.round(t/60),n=Math.floor(e/1440),i=Math.floor(e%1440/60),e=Math.floor(e%60),t="";return 1===n?t+=r["1 day"]+", ":1<n&&(t+=r["%s days"].sprintf(n)+", "),t+=i+":",e<10&&(t+="0"),t+=e},packetsDiff:function(t,e,n){if(0<n)return n=(t-e)/n,r["%s packets/s"].sprintf(i(n,0))},bytesDiff:function(t,e,n){if(0<n)return a(8*((t-e)/n))+"bps"},bytes:function(t){return a(t)+"B"},neighbour:function(t){if(!t)return"";for(var e in c){var n=c[e].lookup_neigh(t);if(n)return"via "+n.get_hostname()+" ("+e+")"}return"via "+t+" (unknown iface)"}};function l(e,t){return t.split("/").forEach(function(t){e=e&&e[t]}),e}function d(t,e){var n=new EventSource(t),i={};n.onmessage=function(t){t=JSON.parse(t.data);e(t,i),i=t},n.onerror=function(){n.close(),window.setTimeout(function(){d(t,e)},3e3)}}var x,k=document.body.getAttribute("data-node-address");try{x=JSON.parse(document.body.getAttribute("data-node-location"))}catch(t){}function t(t){var e=document.getElementById("mesh-vpn");if(t){e.style.display="";for(var i=document.getElementById("mesh-vpn-peers");i.lastChild;)i.removeChild(i.lastChild);t=function e(n,i){return Object.keys(i.peers||{}).forEach(function(t){n.push([t,i.peers[t]])}),Object.keys(i.groups||{}).forEach(function(t){e(n,i.groups[t])}),n}([],t);t.sort(),t.forEach(function(t){var e=document.createElement("tr"),n=document.createElement("th");n.textContent=t[0],e.appendChild(n);n=document.createElement("td");t[1]?n.textContent=r.connected+" ("+s.time(t[1].established)+")":n.textContent=r["not connected"],e.appendChild(n),i.appendChild(e)})}else e.style.display="none"}function e(t){var e=document.getElementById("radios");if(t){e.style.display="";for(var i=document.getElementById("radio-devices");i.lastChild;)i.removeChild(i.lastChild);t.sort(function(t,e){return t.phy-e.phy}),t.forEach(function(t){var e=document.createElement("tr"),n=document.createElement("th");n.textContent="phy"+t.phy,e.appendChild(n);n=document.createElement("td");n.innerHTML=t.frequency+" MHz<br />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;r<t;r++){var o=l.height-40*r;u.moveTo(0,o-.5),u.lineTo(l.width,o-.5);var a=Math.round((e=o,n=c,i=s,a=l.height,(n*e+i*(a-e))/a))+" dBm";u.save(),u.strokeStyle="rgba(255, 255, 255, 0.9)",u.lineWidth=4,u.miterLimit=2,u.strokeText(a,l.width-5,o-2.5),u.fillText(a,l.width-5,o-2.5),u.restore()}u.stroke(),u.strokeStyle="rgba(0, 0, 0, 0.83)",u.lineWidth=1.5,u.strokeRect(.5,.5,l.width-1,l.height-1),u.restore()}())}t(),window.addEventListener("resize",r);var o=0;return window.requestAnimationFrame(function t(e){40<e-o&&(r(),n=(n+1)%l.width,o=e),window.requestAnimationFrame(t)}),{el:l,addSignal:function(t){i.push(t),t.resize(l.width,l.height)},removeSignal:function(t){i.splice(i.indexOf(t),1)}}}function f(t,e,n,i){var r,o=t.table.firstElementChild,a=t.table.insertRow(),c=a.insertCell();c.setAttribute("data-label",o.children[0].textContent),t.wireless&&((r=document.createElement("span")).textContent="",r.style.color=n,c.appendChild(r));var s=document.createElement("span");s.textContent=e,c.appendChild(s);var l={};for(var u,d,h,f,g,v,m,p,b,y=0;y<o.children.length;y++)u=o.children[y],f=h=d=void 0,(f=u.getAttribute("data-key"))&&(d=u.getAttribute("data-suffix")||"",(h=a.insertCell()).textContent="-",h.setAttribute("data-label",u.textContent),l[f]={td:h,suffix:d});function C(){b&&window.clearTimeout(b),b=window.setTimeout(function(){p&&t.signalgraph.removeSignal(p),a.parentNode.removeChild(a),i()},6e4)}function E(t){t=function(t){"::"==(t="::"==t.slice(0,2)?"0"+t:t).slice(-2)&&(t+="0");var n=(t=t.split(":")).length,i=[];return t.forEach(function(t,e){if(""===t)for(;n++<=8;)i.push(0);else/^[a-f0-9]{1,4}$/i.test(t)&&i.push(parseInt(t,16))}),i}(t);if(t){var e="";return t.forEach(function(t){e+=("0000000000000000"+t.toString(2)).slice(-16)}),e}}function w(t){var i=E(k);if(t&&t[0]){(t=t.map(function(t){var e=E(t);if(!e)return[-1];var n=0;return[n=i?function(t,e){for(var n=0;n<t.length&&n<e.length&&t[n]===e[n];n++);return n}(i,e):n,e,t]})).sort(function(t,e){return t[0]<e[0]?1:t[0]>e[0]||t[1]<e[1]?-1: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",200<t.inactive),p.set(200<t.inactive?null:t.signal),C()}}}function u(t,e,n){var i,o={};n&&(i=h(),t.appendChild(i.el));var r={table:t.firstElementChild,signalgraph:i,ifname:e,wireless:n},a=!1,c={},s=[];function l(){var t;a||(a=!0,(t=new EventSource("/cgi-bin/dyn/neighbours-nodeinfo?"+encodeURIComponent(e))).addEventListener("neighbour",function(t){try{var n=JSON.parse(t.data);i=[],r=n.network.mesh,Object.keys(r).forEach(function(t){var e=r[t].interfaces;Object.keys(e).forEach(function(t){e[t].forEach(function(t){i.push(t)})})}),i.forEach(function(t){var e=o[t];if(e){delete c[t];try{e.update_nodeinfo(n)}catch(t){console.error(t)}}})}catch(t){console.error(t)}var i,r},!1),t.onerror=function(){t.close(),a=!1,Object.keys(c).forEach(function(t){0<c[t]&&(c[t]--,l())})})}function u(t){var e=o[t];return e||(c[t]=3,e=o[t]=f(r,t,(s=s[0]?s:["#396AB1","#DA7C30","#3E9651","#CC2529","#535154","#6B4C9A","#922428","#948B3D"]).shift(),function(){delete c[t],delete o[t]}),l()),e}return n&&d("/cgi-bin/dyn/stations?"+encodeURIComponent(e),function(n){Object.keys(n).forEach(function(t){var e=n[t];u(t).update_wifi(e)})}),{get_neigh:u,lookup_neigh:function(t){return o[t]}}}document.querySelectorAll("[data-interface]").forEach(function(t){var e=t.getAttribute("data-interface"),n=(t.getAttribute("data-interface-address"),!!t.getAttribute("data-interface-wireless"));c[e]=u(t,e,n)});var g=document.body.getAttribute("data-mesh-provider");g&&d(g,function(i){Object.keys(i).forEach(function(t){var e=i[t],n=c[e.ifname];n&&n.get_neigh(t).update_mesh(e)})})}();
\ No newline at end of file
"use strict";!function(){var i=JSON.parse(document.body.getAttribute("data-translations"));function r(t,e){return t.toFixed(e).replace(/\./,i["."])}function a(t,e){e--;for(var n=t;10<=n&&0<e;n/=10)e--;return r(t,e)}function o(t){return function(t,e,n){var r=0;if(void 0===n)return"- ";for(;e<n&&r<t.length-1;)n/=e,r++;return(n=a(n,3))+" "+t[r]}(["","K","M","G","T"],1024,t)}String.prototype.sprintf=function(){var t=0,e=arguments;return this.replace(/%s/g,function(){return e[t++]})};var u={id:function(t){return t},decimal:function(t){return r(t,2)},percent:function(t){return i["%s used"].sprintf(a(100*t,3)+"%")},memory:function(t){t=1-t.available/t.total;return u.percent(t)},time:function(t){var e=Math.round(t/60),n=Math.floor(e/1440),r=Math.floor(e%1440/60),e=Math.floor(e%60),t="";return 1===n?t+=i["1 day"]+", ":1<n&&(t+=i["%s days"].sprintf(n)+", "),t+=r+":",e<10&&(t+="0"),t+=e},packetsDiff:function(t,e,n){if(0<n)return n=(t-e)/n,i["%s packets/s"].sprintf(r(n,0))},bytesDiff:function(t,e,n){if(0<n)return o(8*((t-e)/n))+"bps"},bytes:function(t){return o(t)+"B"},neighbour:function(t){if(!t)return"";for(var e in c){var n=c[e].lookup_neigh(t);if(n){var r=document.createElement("span");r.appendChild(document.createTextNode("via "));var i=document.createElement("a");return i.href="http://["+n.get_addr()+"]/",i.textContent=n.get_hostname(),r.appendChild(i),r.appendChild(document.createTextNode(" ("+e+")")),r}}return"via "+t+" (unknown iface)"}};function s(e,t){return t.split("/").forEach(function(t){e=e&&e[t]}),e}function d(t,e){var n=new EventSource(t),r={};n.onmessage=function(t){t=JSON.parse(t.data);e(t,r),r=t},n.onerror=function(){n.close(),window.setTimeout(function(){d(t,e)},3e3)}}var x,k=document.body.getAttribute("data-node-address");try{x=JSON.parse(document.body.getAttribute("data-node-location"))}catch(t){}function t(t){var e=document.getElementById("mesh-vpn");if(t){e.style.display="";for(var r=document.getElementById("mesh-vpn-peers");r.lastChild;)r.removeChild(r.lastChild);t=function e(n,r){return Object.keys(r.peers||{}).forEach(function(t){n.push([t,r.peers[t]])}),Object.keys(r.groups||{}).forEach(function(t){e(n,r.groups[t])}),n}([],t);t.sort(),t.forEach(function(t){var e=document.createElement("tr"),n=document.createElement("th");n.textContent=t[0],e.appendChild(n);n=document.createElement("td");t[1]?n.textContent=i.connected+" ("+u.time(t[1].established)+")":n.textContent=i["not connected"],e.appendChild(n),r.appendChild(e)})}else e.style.display="none"}var e=document.querySelectorAll("[data-statistics]");d("/cgi-bin/dyn/statistics",function(a,o){var c=a.uptime-o.uptime;e.forEach(function(t){var e=t.getAttribute("data-statistics"),n=t.getAttribute("data-format"),r=s(o,e),e=s(a,e);try{var i=u[n](e,r,c);"object"==typeof i?(t.lastChild&&t.removeChild(t.lastChild),t.appendChild(i)):t.textContent=i}catch(t){console.error(t)}});try{t(a.mesh_vpn)}catch(t){console.error(t)}});var c={};function A(n){var r=document.createElement("canvas"),i=r.getContext("2d"),a=null;return{canvas:r,highlight:!1,resize:function(t,e){var n;try{n=i.getImageData(0,0,t,e)}catch(t){}r.width=t,r.height=e,n&&i.putImageData(n,0,0)},draw:function(t,e){e=e(a);i.clearRect(t,0,5,r.height),e&&(t=t,e=e,i.beginPath(),i.fillStyle=n,i.arc(t,e,1.2,0,2*Math.PI,!1),i.closePath(),i.fill())},set:function(t){a=t}}}function h(){var i=-100,a=0,n=0,r=[],o=document.createElement("canvas");o.className="signalgraph",o.height=200;var c=o.getContext("2d");function t(){o.width=o.clientWidth,r.forEach(function(t){t.resize(o.width,o.height)})}function u(){var e;0!==o.clientWidth&&(o.width!==o.clientWidth&&t(),c.clearRect(0,0,o.width,o.height),e=!1,r.forEach(function(t){t.highlight&&(e=!0)}),c.save(),r.forEach(function(t){e&&(c.globalAlpha=.2),t.highlight&&(c.globalAlpha=1),t.draw(n,function(t){return e=o.height,(1-(t-i)/(a-i))*e;var e}),c.drawImage(t.canvas,0,0)}),c.restore(),c.save(),c.beginPath(),c.strokeStyle="rgba(255, 180, 0, 0.15)",c.lineWidth=5,c.moveTo(n+2.5,0),c.lineTo(n+2.5,o.height),c.stroke(),function(){var t=Math.floor(o.height/40);c.save(),c.lineWidth=.5,c.strokeStyle="rgba(0, 0, 0, 0.25)",c.fillStyle="rgba(0, 0, 0, 0.5)",c.textAlign="end",c.textBaseline="bottom",c.beginPath();for(var e=0;e<t;e++){var n=o.height-40*e;c.moveTo(0,n-.5),c.lineTo(o.width,n-.5);var r=Math.round((r=o.height,(i*n+a*(r-n))/r))+" dBm";c.save(),c.strokeStyle="rgba(255, 255, 255, 0.9)",c.lineWidth=4,c.miterLimit=2,c.strokeText(r,o.width-5,n-2.5),c.fillText(r,o.width-5,n-2.5),c.restore()}c.stroke(),c.strokeStyle="rgba(0, 0, 0, 0.83)",c.lineWidth=1.5,c.strokeRect(.5,.5,o.width-1,o.height-1),c.restore()}())}t(),window.addEventListener("resize",u);var s=0;return window.requestAnimationFrame(function t(e){40<e-s&&(u(),n=(n+1)%o.width,s=e),window.requestAnimationFrame(t)}),{el:o,addSignal:function(t){r.push(t),t.resize(o.width,o.height)},removeSignal:function(t){r.splice(r.indexOf(t),1)}}}function f(t,o,e,n){var r,i=t.table.firstElementChild,a=t.table.insertRow(),c=a.insertCell();c.setAttribute("data-label",i.children[0].textContent),t.wireless&&((r=document.createElement("span")).textContent="",r.style.color=e,c.appendChild(r));var u=document.createElement("span");u.textContent=o,c.appendChild(u);var s={};for(var l,d,h,f,g,v,p,m,b,C=0;C<i.children.length;C++)l=i.children[C],f=h=d=void 0,(f=l.getAttribute("data-key"))&&(d=l.getAttribute("data-suffix")||"",(h=a.insertCell()).textContent="-",h.setAttribute("data-label",l.textContent),s[f]={td:h,suffix:d});function y(){b&&window.clearTimeout(b),b=window.setTimeout(function(){m&&t.signalgraph.removeSignal(m),a.parentNode.removeChild(a),n()},6e4)}function w(t){t=function(t){"::"==(t="::"==t.slice(0,2)?"0"+t:t).slice(-2)&&(t+="0");for(var e=t.split(":"),n=e.length,r=[],i=0;i<e.length;i++){var a=e[i];if(""===a)for(;n++<=8;)r.push(0);else{if(!/^[a-f0-9]{1,4}$/i.test(a))return;r.push(parseInt(a,16))}}return r}(t);if(t){var e="";return t.forEach(function(t){e+=("0000000000000000"+t.toString(2)).slice(-16)}),e}}function E(t){var r=w(k);if(t&&t[0]){(t=t.map(function(t){var e=w(t);if(!e)return[-1];var n=0;return[n=r?function(t,e){for(var n=0;n<t.length&&n<e.length&&t[n]===e[n];n++);return n}(r,e):n,e,t]})).sort(function(t,e){return t[0]<e[0]?1:t[0]>e[0]||t[1]<e[1]?-1: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<t.inactive),m.set(200<t.inactive?null:t.signal),y()}}}function l(t,e,n){var r,a={};n&&(r=h(),t.appendChild(r.el));var i={table:t.firstElementChild,signalgraph:r,ifname:e,wireless:n},o=!1,c={},u=[];function s(){var t;o||(o=!0,(t=new EventSource("/cgi-bin/dyn/neighbours-nodeinfo?"+encodeURIComponent(e))).addEventListener("neighbour",function(t){try{var n=JSON.parse(t.data);r=[],i=n.network.mesh,Object.keys(i).forEach(function(t){var e=i[t].interfaces;Object.keys(e).forEach(function(t){e[t].forEach(function(t){r.push(t)})})}),r.forEach(function(t){var e=a[t];if(e){delete c[t];try{e.update_nodeinfo(n)}catch(t){console.error(t)}}})}catch(t){console.error(t)}var r,i},!1),t.onerror=function(){t.close(),o=!1,Object.keys(c).forEach(function(t){0<c[t]&&(c[t]--,s())})})}function l(t){var e=a[t];return e||(c[t]=3,e=a[t]=f(i,t,(u=u[0]?u:["#396AB1","#DA7C30","#3E9651","#CC2529","#535154","#6B4C9A","#922428","#948B3D"]).shift(),function(){delete c[t],delete a[t]}),s()),e}return n&&d("/cgi-bin/dyn/stations?"+encodeURIComponent(e),function(n){Object.keys(n).forEach(function(t){var e=n[t];l(t).update_wifi(e)})}),{get_neigh:l,lookup_neigh:function(t){return a[t]}}}document.querySelectorAll("[data-interface]").forEach(function(t){var e=t.getAttribute("data-interface"),n=(t.getAttribute("data-interface-address"),!!t.getAttribute("data-interface-wireless"));c[e]=l(t,e,n)});var n=document.body.getAttribute("data-mesh-provider");n&&d(n,function(r){Object.keys(r).forEach(function(t){var e=r[t],n=c[e.ifname];n&&n.get_neigh(t).update_mesh(e)})})}();
\ No newline at end of file
......@@ -31,8 +31,8 @@ msgstr "Automatische Updates"
msgid "Bandwidth limit"
msgstr "Bandbreitenlimit"
msgid "Channel"
msgstr "Kanal"
msgid "Channel %u"
msgstr "Kanal %u"
msgid "Clients"
msgstr "Clients"
......
......@@ -22,7 +22,7 @@ msgstr ""
msgid "Bandwidth limit"
msgstr ""
msgid "Channel"
msgid "Channel %u"
msgstr ""
msgid "Clients"
......
......@@ -121,7 +121,15 @@
var neigh = iface.lookup_neigh(addr);
if (!neigh)
continue;
return 'via ' + neigh.get_hostname() + ' (' + i + ')';
var span = document.createElement('span');
span.appendChild(document.createTextNode('via '));
var a = document.createElement('a');
a.href = 'http://[' + neigh.get_addr() + ']/';
a.textContent = neigh.get_hostname();
span.appendChild(a);
span.appendChild(document.createTextNode(' (' + i + ')'));
return span;
}
return 'via ' + addr + ' (unknown iface)';
......@@ -208,50 +216,6 @@
});
}
function update_radios(wireless) {
function channel(frequency) {
if (frequency===2484)
return 14
if (2412<=frequency && frequency<=2472)
return (frequency-2407)/5
if (5160<=frequency && frequency<=5885)
return (frequency-5000)/5
return 'unknown'
}
var div = document.getElementById('radios');
if (!wireless) {
div.style.display = 'none';
return;
}
div.style.display = '';
var table = document.getElementById('radio-devices');
while (table.lastChild)
table.removeChild(table.lastChild);
wireless.sort(function (a, b) {
return a.phy - b.phy;
});
wireless.forEach(function (radio) {
var tr = document.createElement('tr');
var th = document.createElement('th');
th.textContent = "phy" + radio.phy;
tr.appendChild(th);
var td = document.createElement('td');
td.innerHTML = radio.frequency + " MHz<br />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;
......
......@@ -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 (
......
......@@ -44,7 +44,6 @@ $Id$
<div class="gluon-page-actions">
<input type="hidden" name="step" value="2" />
<input type="hidden" name="token" value="<%=token%>" />
<input class="gluon-button gluon-button-submit" type="submit" value="<%:Upload image%>" />
</div>
</form>
......@@ -49,13 +49,11 @@ You may obtain a copy of the License at
<form method="post" enctype="multipart/form-data" action="<%|url(request)%>" style="display:inline">
<input type="hidden" name="step" value="3" />
<input type="hidden" name="keepcfg" value="<%=keepconfig and "1" or "0"%>" />
<input type="hidden" name="token" value="<%=token%>" />
<input class="gluon-button gluon-button-submit" type="submit" value="<%:Continue%>" />
</form>
<form method="post" enctype="multipart/form-data" action="<%|url(request)%>" style="display:inline">
<input type="hidden" name="step" value="1" />
<input type="hidden" name="keepcfg" value="<%=keepconfig and "1" or "0"%>" />
<input type="hidden" name="token" value="<%=token%>" />
<input class="gluon-button gluon-button-reset" type="submit" value="<%:Cancel%>" />
</form>
</div>
<form method="post" enctype="multipart/form-data" action="<%|url(request)%>" data-update="reset">
<input type="hidden" name="token" value="<%=token%>" />
<input type="hidden" name="<%=id%>" value="1" />
<div class="gluon-form" id="form-<%=id%>">
......
<div id="<%=id%>" class="gluon-osm-map" style="display: none"></div>
<script type="text/javascript" src="/static/gluon-web-osm.js"></script>
<script type="text/javascript">
//<![CDATA[
(function() {
var elMap = document.getElementById(<%=json(id)%>);
var wrapper = elMap.parentNode;
......@@ -41,4 +42,5 @@
});
});
})();
//]]>
</script>
......@@ -4,7 +4,8 @@ local util = require "gluon.web.util"
local class = util.class
local DEFAULT_URL = 'https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.2.0'
local DEFAULT_URL =
'https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@35ffe7626ce16c372143f3c903950750075e7068/en/v5.3.0'
local M = {}
......
......@@ -184,9 +184,15 @@ local function dispatch(config, http, request)
return
end
http:parse_input(node.filehandler)
local ok, err = pcall(http.parse_input, http, node.filehandler)
if not ok then
http:status(400, "Bad request")
http:prepare_content("text/plain")
http:write(err .. "\r\n")
return
end
local ok, err = pcall(node.target)
ok, err = pcall(node.target)
if not ok then
http:status(500, "Internal Server Error")
renderer.render_layout("error/500", {
......@@ -208,6 +214,6 @@ return function(config, http)
if not ok then
http:status(500, "Internal Server Error")
http:prepare_content("text/plain")
http:write(err)
http:write(err .. "\r\n")
end
end