<%- 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' local function _(v) translations[v] = translate(v) end -- i18n strings for JavaScript _('.') -- decimal point _('connected') _('not connected') _('1 day') _('%s days') _('%s used') _('%s packets/s') local function get_mesh() local f = loadfile('/lib/gluon/status-page/mesh.lua') if f then return f() end return {} end local mesh = get_mesh() local function get_interfaces(uconn) local interfaces = util.get_mesh_devices(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_*' local lower = util.glob(pattern)[1] if not lower then break end iface = lower:sub(pattern:len()) end return unistd.access('/sys/class/net/' .. iface .. '/wireless') ~= nil end 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)} table.sort(t) return t end local function enabled(v) return v and translate('enabled') or translate('disabled') end local function formatBits(bits) local units = {[0]='', 'k', 'M', 'G'} local unit = 0 for i = 1, #units do if math.abs(bits) < 1000 then break end unit = i bits = bits / 1000 end return string.format('%g %sbit', bits, units[unit]) end local function statistics(key, format) return string.format('', pcdata(key), pcdata(format or 'id')) end local function statisticsTraffic(key) return string.format('%s
%s
%s', statistics(key .. '/packets', 'packetsDiff'), statistics(key .. '/bytes', 'bytesDiff'), statistics(key .. '/bytes', 'bytes') ) end http:prepare_content("application/xhtml+xml") -%> <%| nodeinfo.hostname %> - <%:Status%> >

<%| nodeinfo.hostname %>

<%:Overview%>

<%:Node name%>
<%| nodeinfo.hostname %>
<% if nodeinfo.owner and nodeinfo.owner.contact then -%>
<%:Contact%>
<%| nodeinfo.owner.contact %>
<%- end %> <% if nodeinfo.location then -%>
<%:Location%>
<%| nodeinfo.location.latitude %>, <%| nodeinfo.location.longitude %>
<%- end %>
<%:Model%>
<%| nodeinfo.hardware.model %>
<%:Primary MAC address%>
<%| nodeinfo.network.mac %>
<%:IP address%>
<%= pcdata(table.concat(sorted(nodeinfo.network.addresses), '\n')):gsub('\n', '
') %>
<%:Firmware%>
<%| nodeinfo.software.firmware.release %>
<% if nodeinfo.network.mesh_vpn then -%>
<%:Mesh VPN%>
<%| enabled(nodeinfo.network.mesh_vpn.enabled) %> <% if nodeinfo.network.mesh_vpn.provider then -%>
<%| nodeinfo.network.mesh_vpn.provider %> <%- end %>
<% if nodeinfo.network.mesh_vpn.bandwidth_limit.enabled then -%>
<%:Bandwidth limit%>
<% if nodeinfo.network.mesh_vpn.bandwidth_limit.ingress then -%> ▼ <%| 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 %> <%- end %>
<%:Site%>
<%| site.site_name() %>
<% if nodeinfo.system.domain_code then -%>
<%:Domain%>
<%| site.domain_names[nodeinfo.system.domain_code]() %> <% if nodeinfo.system.domain_code ~= nodeinfo.system.primary_domain_code then %> (<%| site.domain_names[nodeinfo.system.primary_domain_code]() %>) <%- end %>
<%- end %> <% if nodeinfo.system.role then -%>
<%:Role%>
<%| site_i18n._translate('gluon-web-node-role:role:' .. nodeinfo.system.role) %>
<%- end %> <% if nodeinfo.software.autoupdater then -%>
<%:Automatic updates%>
<%| enabled(nodeinfo.software.autoupdater.enabled) %><%| nodeinfo.software.autoupdater.enabled and string.format(' (%s)', nodeinfo.software.autoupdater.branch) %>
<%- end %> <% if nodeinfo.software.babeld or nodeinfo.software['batman-adv'] then -%>
<%:Mesh protocol%>
<% if nodeinfo.software.babeld then -%>
babeld <%| nodeinfo.software.babeld.version %>
<%- end %> <% if nodeinfo.software['batman-adv'] then -%>
batman-adv <%| nodeinfo.software['batman-adv'].version %> (compat<%| nodeinfo.software['batman-adv'].compat %>)
<%- end %> <%- end %>

<%:Monitoring%>

<%:Uptime%><%= statistics('uptime', 'time') %>
<%:Load average%><%= statistics('loadavg', 'decimal') %>
<%:RAM%><%= statistics('memory', 'memory') %>
<%:Filesystem%><%= statistics('rootfs_usage', 'percent') %>
<%:Gateway%><%= statistics('gateway') %>
<%= statistics('gateway_nexthop', 'neighbour') %>

<%:Clients%>

<%:Total%><%= statistics('clients/total') %>
<%:Wireless 2.4 GHz%><%= statistics('clients/wifi24') %>
<%:Wireless 5 GHz%><%= statistics('clients/wifi5') %>
<% if radios[1] then -%>

<%:Radios%>

<% for _, radio in ipairs(radios) do -%> <%- end %>
<%| radio.name %> <%| translatef('Channel %u', radio.channel) %>
<%- end %>

<%:Traffic%>

<%:Transmitted%><%= statisticsTraffic('traffic/tx') %>
<%:Received%><%= statisticsTraffic('traffic/rx') %>
<%:Forwarded%><%= statisticsTraffic('traffic/forward') %>

<%:Neighbors%>

<% for _, iface in ipairs(interfaces) do local wireless = is_wireless(iface) local address = util.readfile('/sys/class/net/' .. iface .. '/address') if address then %>

<%| iface %>

> <% for i, v in ipairs(mesh.attrs or {}) do %> ><%| v[2] %> <% end %> <% if wireless then %> <% end %>
<%:Node%>dBm <%:Distance%> <%:Last seen%>
<% end end %>