2022-01-19 06:42:31 -07:00
|
|
|
#!/usr/bin/lua
|
|
|
|
--[[
|
|
|
|
|
|
|
|
Part of AREDN -- Used for creating Amateur Radio Emergency Data Networks
|
|
|
|
Copyright (C) 2021 Tim Wilkinson
|
|
|
|
Original Perl Copyright (C) 2015 Conrad Lara
|
|
|
|
See Contributors file for additional contributors
|
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation version 3 of the License.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
Additional Terms:
|
|
|
|
|
|
|
|
Additional use restrictions exist on the AREDN(TM) trademark and logo.
|
|
|
|
See AREDNLicense.txt for more info.
|
|
|
|
|
|
|
|
Attributions to the AREDN Project must be retained in the source code.
|
|
|
|
If importing this code into a new or existing project attribution
|
|
|
|
to the AREDN project must be added to the source code.
|
|
|
|
|
|
|
|
You must not misrepresent the origin of the material contained within.
|
|
|
|
|
|
|
|
Modified versions must be modified to attribute to the original source
|
|
|
|
and be marked in reasonable ways as differentiate it from the original
|
|
|
|
version
|
|
|
|
|
|
|
|
--]]
|
|
|
|
|
|
|
|
require("nixio")
|
|
|
|
require("aredn.hardware")
|
|
|
|
require("aredn.http")
|
|
|
|
require("aredn.utils")
|
|
|
|
require("aredn.html")
|
|
|
|
require("uci")
|
|
|
|
aredn.info = require("aredn.info")
|
|
|
|
aredn.olsr = require("aredn.olsr")
|
|
|
|
require("iwinfo")
|
|
|
|
|
|
|
|
local html = aredn.html
|
|
|
|
|
|
|
|
local rateL = {
|
|
|
|
["1.0M"] = 1, -- CCP LP
|
|
|
|
["2.0M"] = 2, -- CCP LP
|
|
|
|
["5.5M"] = 5.5, -- CCP LP
|
|
|
|
MCS0 = 6.5, -- HT20 LGI
|
|
|
|
["11.0M"] = 11, -- CCP LP
|
|
|
|
MCS1 = 13, -- HT20 LGI...
|
|
|
|
MCS2 = 19.5,
|
|
|
|
MCS3 = 26,
|
|
|
|
MCS4 = 39,
|
|
|
|
MCS5 = 52,
|
|
|
|
MCS6 = 58.5,
|
|
|
|
MCS7 = 65,
|
|
|
|
MCS8 = 13,
|
|
|
|
MCS9 = 26,
|
|
|
|
MCS10 = 39,
|
|
|
|
MCS11 = 52,
|
|
|
|
MCS12 = 78,
|
|
|
|
MCS13 = 104,
|
|
|
|
MCS14 = 117,
|
|
|
|
MCS15 = 130
|
2021-11-02 22:35:39 -06:00
|
|
|
}
|
2022-01-19 06:42:31 -07:00
|
|
|
local rateS = {
|
|
|
|
MCS0 = 7.2,
|
|
|
|
MCS1 = 14.4,
|
|
|
|
MCS2 = 21.7,
|
|
|
|
MCS3 = 28.9,
|
|
|
|
MCS4 = 43.3,
|
|
|
|
MCS5 = 57.8,
|
|
|
|
MCS6 = 65,
|
|
|
|
MCS7 = 72.2,
|
|
|
|
MCS8 = 14.4,
|
|
|
|
MCS9 = 28.9,
|
|
|
|
MCS10 = 43.3,
|
|
|
|
MCS11 = 57.8,
|
|
|
|
MCS12 = 86.7,
|
|
|
|
MCS13 = 115.6,
|
|
|
|
MCS14 = 130,
|
|
|
|
MCS15 = 144.4
|
2013-11-14 23:11:16 -07:00
|
|
|
}
|
|
|
|
|
2022-01-19 06:42:31 -07:00
|
|
|
local node = aredn.info.get_nvram("node")
|
|
|
|
if node == "" then
|
|
|
|
node = "NOCALL"
|
|
|
|
end
|
|
|
|
local tactical = aredn.info.get_nvram("tactical")
|
|
|
|
local config = aredn.info.get_nvram("config")
|
|
|
|
if config == "" or nixio.fs.stat("/etc/config.mesh", "type") ~= "dir" then
|
|
|
|
config = "not set"
|
|
|
|
end
|
|
|
|
local wifiif = aredn.hardware.get_iface_name("wifi")
|
|
|
|
local my_ip = aredn.hardware.get_interface_ip4(wifiif)
|
|
|
|
if not my_ip then
|
|
|
|
my_ip = "none"
|
|
|
|
end
|
|
|
|
local phy = iwinfo.nl80211.phyname(wifiif)
|
|
|
|
if not phy then
|
|
|
|
phy = 0
|
|
|
|
end
|
|
|
|
|
|
|
|
local chanbw = 1
|
|
|
|
local cb = "/sys/kernel/debug/ieee80211/" .. phy .. "/ath9k/chanbw"
|
|
|
|
if nixio.fs.stat(cb) then
|
|
|
|
for line in io.lines(cb)
|
|
|
|
do
|
|
|
|
if line == "0x00000005" then
|
|
|
|
chanbw = 4
|
|
|
|
elseif line == "0x0000000a" then
|
|
|
|
chanbw = 2
|
|
|
|
end
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if not nixio.fs.stat("/tmp/web") then
|
|
|
|
nixio.fs.mkdir("/tmp/web")
|
|
|
|
end
|
|
|
|
|
|
|
|
-- post data
|
|
|
|
|
|
|
|
if os.getenv("REQUEST_METHOD") == "POST" then
|
|
|
|
require('luci.http')
|
|
|
|
require('luci.sys')
|
|
|
|
local request = luci.http.Request(luci.sys.getenv(),
|
|
|
|
function()
|
|
|
|
local v = io.read(1024)
|
|
|
|
if not v then
|
|
|
|
io.close()
|
|
|
|
end
|
|
|
|
return v
|
|
|
|
end
|
|
|
|
)
|
|
|
|
if request:formvalue("auto") then
|
|
|
|
io.open("/tmp/web/automesh", "w"):close()
|
|
|
|
end
|
|
|
|
if request:formvalue("stop") then
|
|
|
|
os.remove("/tmp/web/automesh")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local cursor = uci.cursor()
|
|
|
|
local node_desc = cursor:get("system", "@system[0]", "description")
|
|
|
|
local lat_lon = "<strong>Location Not Available</strong>"
|
|
|
|
local lat = cursor:get("aredn", "@location[0]", "lat")
|
|
|
|
local lon = cursor:get("aredn", "@location[0]", "lon")
|
|
|
|
if lat and lon then
|
|
|
|
lat_lon = string.format("<center><strong>Location: </strong> %s %s</center>", lat, lon)
|
|
|
|
end
|
|
|
|
-- low memory mitigation
|
|
|
|
local lowmemory = cursor:get("aredn", "@meshstatus[0]", "lowmem")
|
|
|
|
if not lowmemory then
|
|
|
|
lowmemory = 10000
|
|
|
|
end
|
2022-10-11 21:22:11 -06:00
|
|
|
lowmemory = 1024 * tonumber(lowmemory)
|
2022-01-19 06:42:31 -07:00
|
|
|
local lowroutes = cursor:get("aredn", "@meshstatus[0]", "lowroutes")
|
|
|
|
if not lowroutes then
|
|
|
|
lowroutes = 1000
|
|
|
|
else
|
|
|
|
lowroutes = tonumber(lowroutes)
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
local routes = {}
|
|
|
|
local links = {}
|
|
|
|
local neighbor = {}
|
|
|
|
local wangateway = {}
|
|
|
|
local ipalias = {}
|
|
|
|
local localhosts = {}
|
|
|
|
local dtd = {}
|
|
|
|
local midcount = {}
|
|
|
|
local hosts = {}
|
|
|
|
local services = {}
|
|
|
|
local history = {}
|
|
|
|
|
|
|
|
local olsr_total = 0
|
|
|
|
local olsr_nodes = 0
|
|
|
|
local olsr_routes = 0
|
|
|
|
for i, node in ipairs(aredn.olsr.getOLSRRoutes())
|
|
|
|
do
|
2022-01-31 07:45:05 -07:00
|
|
|
if node.genmask ~= 0 then -- don't count default route
|
|
|
|
olsr_total = olsr_total + 1
|
|
|
|
if node.genmask ~= 32 then
|
|
|
|
olsr_nodes = olsr_nodes + 1
|
|
|
|
end
|
|
|
|
if node.etx <= 50 then
|
|
|
|
routes[node.destination] = { etx = node.etx }
|
|
|
|
olsr_routes = olsr_routes + 1
|
|
|
|
end
|
2022-01-19 06:42:31 -07:00
|
|
|
end
|
|
|
|
end
|
|
|
|
-- low memory route reduction
|
|
|
|
if olsr_routes > lowroutes and nixio.sysinfo().freeram < lowmemory then
|
|
|
|
local list = {}
|
|
|
|
for k,v in pairs(routes)
|
|
|
|
do
|
|
|
|
list[#list + 1] = { key = k, etx = v.etx }
|
|
|
|
end
|
|
|
|
table.sort(list, function (a, b) return a.etx < b.etx end)
|
|
|
|
for i = lowroutes,olsr_routes
|
|
|
|
do
|
2022-10-11 21:22:11 -06:00
|
|
|
routes[list[i].key] = nil
|
2022-01-19 06:42:31 -07:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- load up arpcache
|
|
|
|
local arpcache = {}
|
|
|
|
arptable(function(a)
|
|
|
|
arpcache[a["IP address"]] = a
|
|
|
|
end)
|
|
|
|
|
|
|
|
local prefix = "/sys/kernel/debug/ieee80211/" .. phy .. "/netdev:" .. wifiif .. "/stations/"
|
|
|
|
for i, node in ipairs(aredn.olsr.getOLSRLinks())
|
|
|
|
do
|
|
|
|
links[node.remoteIP] = { lq = node.linkQuality, nlq = node.neighborLinkQuality, mbps = "" }
|
|
|
|
neighbor[node.remoteIP] = true
|
|
|
|
local mac = arpcache[node.remoteIP]
|
|
|
|
if mac then
|
|
|
|
local f = io.open(prefix .. mac["HW address"] .. "/rc_stats_csv", "r")
|
|
|
|
if f then
|
|
|
|
for line in f:lines()
|
|
|
|
do
|
|
|
|
local gi, rate, ewma = line:match("^[^,]*,([^,]*),[^,]*,A[^,]*,([^,%s]*)%s*,[^,]*,[^,]*,[^,]*,[^,]*,([^,]*),")
|
2022-03-08 16:47:08 -07:00
|
|
|
ewma = tonumber(ewma)
|
|
|
|
if gi and ewma then
|
2022-01-19 06:42:31 -07:00
|
|
|
-- 802.11b/n
|
|
|
|
if gi == "SGI" then
|
2022-03-08 16:47:08 -07:00
|
|
|
links[node.remoteIP].mbps = string.format("%.1f", rateS[rate] * ewma / 100 / chanbw)
|
2022-01-19 06:42:31 -07:00
|
|
|
else
|
2022-03-08 16:47:08 -07:00
|
|
|
links[node.remoteIP].mbps = string.format("%.1f", rateL[rate] * ewma / 100 / chanbw)
|
2022-01-19 06:42:31 -07:00
|
|
|
end
|
|
|
|
else
|
|
|
|
rate, ewma = line:match("^A[^,]*,([^,]*),[^,]*,[^,]*,([^,]*,)")
|
2022-03-08 16:47:08 -07:00
|
|
|
rate = tonumber(rate)
|
|
|
|
ewma = tonumber(ewma)
|
|
|
|
if rate and ewma then
|
2022-01-19 06:42:31 -07:00
|
|
|
-- 802.11a/b/g
|
2022-03-08 16:47:08 -07:00
|
|
|
links[node.remoteIP].mbps = string.format("%.1f", rate * ewma / 100 / chanbw)
|
2022-01-19 06:42:31 -07:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
f:close()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- discard
|
|
|
|
arpcache = nil
|
|
|
|
|
|
|
|
for i, node in ipairs(aredn.olsr.getOLSRHNA())
|
|
|
|
do
|
|
|
|
if node.destination == "0.0.0.0" then
|
|
|
|
wangateway[node.gateway] = true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
for i, node in ipairs(aredn.olsr.getOLSRMid())
|
|
|
|
do
|
|
|
|
local ip = node.main.ipAddress
|
|
|
|
for _, alias in ipairs(node.aliases)
|
|
|
|
do
|
|
|
|
local aip = alias.ipAddress
|
|
|
|
ipalias[aip] = ip
|
|
|
|
neighbor[aip] = true
|
|
|
|
if links[aip] then
|
|
|
|
neighbor[ip] = true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- load the local hosts file
|
|
|
|
for line in io.lines("/etc/hosts")
|
|
|
|
do
|
|
|
|
if line:match("^10%.") then
|
|
|
|
local ip, name = line:match("([%d%.]+)%s+(%S+)")
|
|
|
|
if name then
|
|
|
|
local name9 = name:sub(1, 9)
|
|
|
|
if name9 ~= "localhost" and name9 ~= "localnode" then
|
|
|
|
local name7 = name:sub(1, 7)
|
|
|
|
if name7 ~= "localap" and name7 ~= "dtdlink" then
|
|
|
|
if not name:match("%.") then
|
|
|
|
name = name .. ".local.mesh"
|
|
|
|
end
|
2022-03-02 16:27:39 -07:00
|
|
|
local tac = line:match("[%d%.]+%s+%S+%s+(%S+)")
|
2022-01-19 06:42:31 -07:00
|
|
|
if not tac then
|
|
|
|
tac = ""
|
|
|
|
end
|
|
|
|
if not localhosts[my_ip] then
|
|
|
|
localhosts[my_ip] = { hosts = {}, noprops = {}, aliases = {}, name = name, tactical = tac }
|
|
|
|
end
|
|
|
|
local host = localhosts[my_ip]
|
|
|
|
if ip == my_ip then
|
|
|
|
host.tactical = tac
|
|
|
|
host.name = name
|
|
|
|
else
|
|
|
|
host.hosts[#host.hosts + 1] = name
|
|
|
|
end
|
|
|
|
if tac == "#NOPROP" then
|
|
|
|
host.noprops[#host.noprops + 1] = name
|
|
|
|
end
|
|
|
|
if tac == "#ALIAS" then
|
|
|
|
host.aliases[#host.aliases + 1] = name
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- load the olsr hosts file
|
2022-10-14 14:31:09 -06:00
|
|
|
if nixio.fs.stat("/var/run/hosts_olsr.stable") then
|
|
|
|
for line in io.lines("/var/run/hosts_olsr.stable")
|
|
|
|
do
|
|
|
|
local ip, name, originator = line:match("^([%d%.]+)%s+(%S+)%s+%S+%s+(%S+)")
|
|
|
|
if ip and originator and originator ~= "myself" and (routes[ip] or routes[originator]) then
|
|
|
|
local etx = routes[ip]
|
|
|
|
if not etx then
|
|
|
|
etx = routes[originator]
|
2022-01-19 06:42:31 -07:00
|
|
|
end
|
2022-10-14 14:31:09 -06:00
|
|
|
etx = etx.etx
|
|
|
|
if not name:match("%.") or name:match("^mid%.[^%.]*$") then
|
|
|
|
name = name .. ".local.mesh"
|
2022-01-19 06:42:31 -07:00
|
|
|
end
|
2022-10-14 14:31:09 -06:00
|
|
|
if ip == originator then
|
|
|
|
if not hosts[originator] then
|
|
|
|
hosts[originator] = { hosts = {} }
|
|
|
|
end
|
|
|
|
local host = hosts[originator]
|
|
|
|
if host.name then
|
|
|
|
host.tactical = name
|
|
|
|
else
|
|
|
|
host.name = name
|
|
|
|
host.etx = etx
|
|
|
|
end
|
|
|
|
elseif name:match("^dtdlink%.") then
|
|
|
|
dtd[originator] = true
|
|
|
|
if links[ip] then
|
|
|
|
links[ip].dtd = true
|
|
|
|
end
|
|
|
|
elseif name:match("^mid%d+%.") then
|
|
|
|
if not midcount[originator] then
|
|
|
|
midcount[originator] = 1
|
|
|
|
else
|
|
|
|
midcount[originator] = midcount[originator] + 1
|
|
|
|
end
|
|
|
|
if links[ip] then
|
|
|
|
links[ip].tun = true
|
|
|
|
end
|
2022-01-19 06:42:31 -07:00
|
|
|
else
|
2022-10-14 14:31:09 -06:00
|
|
|
if not hosts[originator] then
|
|
|
|
hosts[originator] = { hosts = {} }
|
|
|
|
end
|
|
|
|
local host = hosts[originator]
|
|
|
|
host.hosts[#host.hosts + 1] = name
|
2022-01-19 06:42:31 -07:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- discard
|
|
|
|
routes = nil
|
|
|
|
|
|
|
|
for line in io.lines("/var/run/services_olsr")
|
|
|
|
do
|
|
|
|
if line:match("^%w") then
|
|
|
|
local url, name = line:match("^(.*)|.*|(.*)$")
|
|
|
|
if name then
|
|
|
|
local protocol, host, port, path = url:match("^([%w][%w%+%-%.]+)%://(.+):(%d+)/(.*)")
|
|
|
|
if path then
|
|
|
|
local name, originator = name:match("(.*%S)%s*#(.*)")
|
|
|
|
if originator == " my own service" or (hosts[originator] and hosts[originator].name) then
|
|
|
|
if not host:match("%.") then
|
|
|
|
host = host .. ".local.mesh"
|
|
|
|
end
|
|
|
|
if not services[host] then
|
|
|
|
services[host] = {}
|
|
|
|
end
|
|
|
|
if not services[host][name] then
|
|
|
|
if port ~= "0" then
|
|
|
|
services[host][name] = "<a href='" .. protocol .. "://" .. host .. ":" .. port .. "/" .. path .. "' target='_blank'>" .. name .. "</a>"
|
|
|
|
else
|
|
|
|
services[host][name] = name
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- load the node history
|
|
|
|
if nixio.fs.stat("/tmp/node.history") then
|
|
|
|
for line in io.lines("/tmp/node.history")
|
|
|
|
do
|
2022-04-04 20:16:35 -06:00
|
|
|
local ip, age, host = line:match("^(%S+) (%d+) (%S+)")
|
2022-03-19 08:21:22 -06:00
|
|
|
if ip and age and host then
|
2022-01-19 06:42:31 -07:00
|
|
|
history[ip] = { age = age, host = host:gsub("/", " / ") }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-10-18 20:37:34 -06:00
|
|
|
------------------
|
|
|
|
-- generate page
|
|
|
|
------------------
|
2022-01-19 06:42:31 -07:00
|
|
|
http_header()
|
|
|
|
html.header(node .. " mesh status", false)
|
|
|
|
local automesh = nixio.fs.stat("/tmp/web/automesh");
|
|
|
|
if automesh then
|
|
|
|
html.print("<meta http-equiv='refresh' content='10;url=/cgi-bin/mesh'>")
|
|
|
|
end
|
2022-10-18 20:37:34 -06:00
|
|
|
html.print([[
|
|
|
|
<style>
|
|
|
|
table {
|
|
|
|
cellspacing:5px;
|
2022-11-01 08:47:52 -06:00
|
|
|
width:80%;
|
2022-10-18 20:37:34 -06:00
|
|
|
border-collapse:collapse;
|
|
|
|
}
|
2022-11-01 08:47:52 -06:00
|
|
|
td {
|
|
|
|
padding-left:5px;
|
2022-10-18 20:37:34 -06:00
|
|
|
}
|
|
|
|
tr {
|
|
|
|
vertical-align:top;
|
|
|
|
text-align:left;
|
|
|
|
}
|
|
|
|
tr.spaceUnder>td {
|
|
|
|
padding-bottom:2em;
|
|
|
|
}
|
2022-11-01 08:47:52 -06:00
|
|
|
tr:hover {
|
|
|
|
background-color:gainsboro;
|
|
|
|
}
|
2022-10-18 20:37:34 -06:00
|
|
|
th {
|
|
|
|
font-weight:bold;
|
|
|
|
background-color:lightseagreen;
|
|
|
|
white-space:nowrap;
|
|
|
|
vertical-align:middle;
|
|
|
|
padding:5px;
|
|
|
|
}
|
|
|
|
input.search {
|
|
|
|
width:150px;
|
|
|
|
}
|
2022-11-01 08:47:52 -06:00
|
|
|
// table header alignment
|
2022-10-26 19:55:36 -06:00
|
|
|
#nTable th:nth-child(1) {
|
|
|
|
width: 25%;
|
|
|
|
}
|
2022-11-01 08:47:52 -06:00
|
|
|
#nTable th:nth-child(2) {
|
|
|
|
width: 45%;
|
2022-10-26 19:55:36 -06:00
|
|
|
}
|
2022-11-01 08:47:52 -06:00
|
|
|
#nTable th:nth-child(3)
|
|
|
|
width: 30%;
|
2022-10-26 19:55:36 -06:00
|
|
|
}
|
|
|
|
#cTable th:nth-child(1), #rTable th:nth-child(1) {
|
|
|
|
width: 25%;
|
|
|
|
}
|
|
|
|
#cTable th:nth-child(2), #rTable th:nth-child(2) {
|
2022-11-01 08:47:52 -06:00
|
|
|
width: 25%;
|
2022-10-26 19:55:36 -06:00
|
|
|
}
|
2022-11-01 08:47:52 -06:00
|
|
|
#cTable th:nth-child(3), #cTable th:nth-child(4) {
|
|
|
|
width: 6%;
|
2022-10-26 19:55:36 -06:00
|
|
|
}
|
2022-11-01 08:47:52 -06:00
|
|
|
#cTable th:nth-child(5) {
|
|
|
|
width: 8%;
|
2022-10-26 19:55:36 -06:00
|
|
|
}
|
|
|
|
#rTable th:nth-child(3) {
|
2022-11-01 08:47:52 -06:00
|
|
|
width: 20%;
|
2022-10-26 19:55:36 -06:00
|
|
|
}
|
2022-11-01 08:47:52 -06:00
|
|
|
#rTable th:nth-child(4) {
|
|
|
|
width: 30%;
|
2022-10-26 19:55:36 -06:00
|
|
|
}
|
2022-10-18 20:37:34 -06:00
|
|
|
</style>
|
|
|
|
]])
|
2022-01-19 06:42:31 -07:00
|
|
|
html.print("</head>")
|
|
|
|
|
2022-10-18 20:37:34 -06:00
|
|
|
html.print("<body><form method=post action=/cgi-bin/mesh accept-charset=utf-8 enctype='multipart/form-data'>")
|
2022-01-19 06:42:31 -07:00
|
|
|
html.print("<input type=hidden name=reload value=1>")
|
|
|
|
html.print("<center>")
|
|
|
|
html.alert_banner()
|
|
|
|
html.print("<h1>" .. node .. " mesh status</h1>")
|
|
|
|
html.print(lat_lon)
|
|
|
|
if node_desc then
|
2022-10-23 13:49:03 -06:00
|
|
|
html.print("<table id='node_description_display'><tr><td align=center>" .. node_desc .. "</td></tr></table>")
|
2022-01-19 06:42:31 -07:00
|
|
|
end
|
|
|
|
html.print("<hr><nobr>")
|
|
|
|
|
2022-10-03 19:49:26 -06:00
|
|
|
html.print("<a href='/help.html#meshstatus' target='_blank'>Help</a> ")
|
|
|
|
|
2022-01-19 06:42:31 -07:00
|
|
|
if nixio.fs.stat("/tmp/web/automesh") then
|
|
|
|
html.print("<input type=submit name=stop value=Stop title='Abort continuous status'>")
|
2016-06-29 20:43:43 -06:00
|
|
|
else
|
2022-01-19 06:42:31 -07:00
|
|
|
html.print("<input type=submit name=refresh value=Refresh title='Refresh this page'>")
|
|
|
|
html.print(" ")
|
|
|
|
html.print("<input type=submit name=auto value=Auto title='Automatic page refresh'>")
|
|
|
|
end
|
|
|
|
|
|
|
|
html.print(" ")
|
|
|
|
html.print("<button type=button onClick='window.location=\"status\"' title='Return to the status page'>Quit</button>")
|
|
|
|
html.print("</nobr><br><br>")
|
|
|
|
|
|
|
|
if not next(localhosts) and not next(links) then
|
|
|
|
html.print("No other nodes are available.")
|
|
|
|
html.print("</center></form>")
|
|
|
|
html.footer()
|
|
|
|
html.print("</body></html>")
|
|
|
|
os.exit(0)
|
|
|
|
end
|
|
|
|
|
2022-11-01 08:47:52 -06:00
|
|
|
-- show local node table
|
2022-11-09 20:15:25 -07:00
|
|
|
|
2022-10-26 19:55:36 -06:00
|
|
|
html.print("<table id=nTable>")
|
2022-11-01 08:47:52 -06:00
|
|
|
html.print("<tr>")
|
|
|
|
html.print("<th width=25%><input class=search type=text id='inNN' onkeyup=nSearch('inNN','nTable',0) placeholder='Node Name'></th>")
|
|
|
|
html.print("<th><input class=search type=text id='inNH' onkeyup=nSearch('inNH','nTable',1) placeholder='Lan Hostname'></th>")
|
|
|
|
html.print("<th><input class=search type=text id='inNS' onkeyup=nSearch('inNS','nTable',2) placeholder='Service Name'></th>")
|
|
|
|
html.print("</tr>")
|
2022-01-19 06:42:31 -07:00
|
|
|
|
|
|
|
if next(localhosts) then
|
|
|
|
local rows = {}
|
|
|
|
for ip, host in pairs(localhosts)
|
|
|
|
do
|
2022-11-09 20:15:25 -07:00
|
|
|
local c1, c2, c3
|
2022-01-19 06:42:31 -07:00
|
|
|
local localpart = host.name:match("([^.]*)%.")
|
2022-10-20 14:43:55 -06:00
|
|
|
if localpart then
|
|
|
|
local tactical = ""
|
|
|
|
if host.tactical ~= "" then
|
|
|
|
tactical = " / " .. host.tactical
|
2022-01-19 06:42:31 -07:00
|
|
|
end
|
2022-11-09 20:15:25 -07:00
|
|
|
c1 = localpart .. tactical
|
2022-10-20 14:43:55 -06:00
|
|
|
if wangateway[ip] then
|
2022-11-09 20:15:25 -07:00
|
|
|
c1 = c1 .. " <small>(wan)</small>"
|
2022-10-20 14:43:55 -06:00
|
|
|
end
|
2022-11-09 20:15:25 -07:00
|
|
|
c2 = "<br>"
|
2022-10-20 14:43:55 -06:00
|
|
|
if services[host.name] then
|
2022-11-09 20:15:25 -07:00
|
|
|
local i=1
|
|
|
|
for _, v in pairs(services[host.name])
|
2022-10-20 14:43:55 -06:00
|
|
|
do
|
2022-11-09 20:15:25 -07:00
|
|
|
if c3 then
|
|
|
|
c3 = c3 .. v .. "<br>"
|
|
|
|
else
|
|
|
|
c3 = v .. "<br>"
|
|
|
|
end
|
|
|
|
if i > 1 then c2 = c2 .. "<br>" end
|
|
|
|
i=i+1
|
|
|
|
end
|
|
|
|
else
|
|
|
|
if c3 then
|
|
|
|
c3 = c3 .. "<br>"
|
|
|
|
else
|
|
|
|
c3 = "<br>"
|
2022-01-19 06:42:31 -07:00
|
|
|
end
|
|
|
|
end
|
2022-10-20 14:43:55 -06:00
|
|
|
|
|
|
|
-- add locally advertised dmz hosts
|
|
|
|
for i, dmzhost in ipairs(host.hosts)
|
2022-01-19 06:42:31 -07:00
|
|
|
do
|
2022-10-20 14:43:55 -06:00
|
|
|
local nopropd = false
|
|
|
|
local aliased = false
|
|
|
|
for _, v in ipairs(host.noprops)
|
|
|
|
do
|
|
|
|
if v == dmzhost then
|
|
|
|
nopropd = true;
|
|
|
|
break
|
|
|
|
end
|
2022-01-19 06:42:31 -07:00
|
|
|
end
|
2022-10-20 14:43:55 -06:00
|
|
|
for _, v in ipairs(host.aliases)
|
2022-01-19 06:42:31 -07:00
|
|
|
do
|
2022-10-20 14:43:55 -06:00
|
|
|
if v == dmzhost then
|
|
|
|
aliased = true;
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
local localpart = dmzhost:match("(.*)%.local%.mesh")
|
|
|
|
if localpart then
|
|
|
|
if not nopropd and not aliased then
|
2022-11-09 20:15:25 -07:00
|
|
|
c2 = c2 .. localpart .. "<br>"
|
2022-10-20 14:43:55 -06:00
|
|
|
elseif aliased then
|
2022-11-09 20:15:25 -07:00
|
|
|
c2 = c2 .. "<span class=aliased-hosts>" .. localpart .. "</span><br>"
|
2022-10-20 14:43:55 -06:00
|
|
|
else
|
2022-11-09 20:15:25 -07:00
|
|
|
c2 = c2 .. "<span class=hidden-hosts>" .. localpart .. "</span><br>"
|
2022-10-20 14:43:55 -06:00
|
|
|
end
|
|
|
|
if services[dmzhost] then
|
2022-11-09 20:15:25 -07:00
|
|
|
local i=1
|
2022-10-20 14:43:55 -06:00
|
|
|
for n, v in pairs(services[dmzhost])
|
|
|
|
do
|
2022-11-09 20:15:25 -07:00
|
|
|
if c3 then
|
|
|
|
c3 = c3 .. v .. "<br>"
|
|
|
|
else
|
|
|
|
c3 = v .. "<br>"
|
|
|
|
end
|
|
|
|
if i > 1 then c2 = c2 .. "<br>" end
|
|
|
|
i=i+1
|
2022-10-20 14:43:55 -06:00
|
|
|
end
|
|
|
|
end
|
2022-01-19 06:42:31 -07:00
|
|
|
end
|
|
|
|
end
|
2022-11-09 20:15:25 -07:00
|
|
|
-- Build this row
|
|
|
|
local row = "<tr><td>" .. c1 .. "</td><td>" .. c2 .. "</td><td>" .. c3 .. "</td></tr>"
|
2022-10-20 14:43:55 -06:00
|
|
|
rows[#rows + 1] = { key = host.name, row = row }
|
2022-01-19 06:42:31 -07:00
|
|
|
end
|
|
|
|
end
|
|
|
|
table.sort(rows, function(a,b) return a.key < b.key end)
|
|
|
|
for _, row in ipairs(rows)
|
|
|
|
do
|
|
|
|
html.print(row.row)
|
|
|
|
end
|
|
|
|
-- discard
|
|
|
|
rows = nil
|
2013-11-14 23:11:16 -07:00
|
|
|
else
|
2022-01-19 06:42:31 -07:00
|
|
|
html.print("<tr><td>none</td></tr>")
|
|
|
|
end
|
|
|
|
|
|
|
|
-- discard
|
|
|
|
localhosts = nil
|
2022-11-01 08:47:52 -06:00
|
|
|
-- end local node table
|
|
|
|
html.print("</table>")
|
2022-01-19 06:42:31 -07:00
|
|
|
|
2022-10-18 20:37:34 -06:00
|
|
|
-- show current neighbors table
|
2022-11-09 20:15:25 -07:00
|
|
|
|
2022-10-18 20:37:34 -06:00
|
|
|
html.print("<br><table id='cTable'><tr>")
|
2022-11-01 08:47:52 -06:00
|
|
|
html.print("<th width=25%><input class=search type=text id='inCN' onkeyup=nSearch('inCN','cTable',0) placeholder='Current Neighbor'></th>")
|
2022-10-18 20:37:34 -06:00
|
|
|
html.print("<th><input class=search type=text id='inCH' onkeyup=nSearch('inCH','cTable',1) placeholder='Lan Hostname'></th>")
|
|
|
|
html.print("<th>LQ</th><th>NLQ</th><th>TxMbps</th>")
|
2022-11-01 08:47:52 -06:00
|
|
|
html.print("<th><input class=search type=text id='inCS' onkeyup=nSearch('inCS','cTable',5) placeholder='Service Name'></th>")
|
2022-10-18 20:37:34 -06:00
|
|
|
html.print("</tr>")
|
2022-01-19 06:42:31 -07:00
|
|
|
|
|
|
|
local rows = {}
|
|
|
|
local neighservices = {}
|
|
|
|
for ip, link in pairs(links)
|
|
|
|
do
|
2022-11-09 20:15:25 -07:00
|
|
|
local c1,c2,c3,c4,c5,c6
|
2022-01-19 06:42:31 -07:00
|
|
|
local ipmain = ipalias[ip]
|
|
|
|
if not ipmain then
|
|
|
|
ipmain = ip
|
|
|
|
end
|
|
|
|
local name = ipmain
|
|
|
|
local localpart = ipmain
|
|
|
|
local tactical = ""
|
|
|
|
local host = hosts[ipmain]
|
|
|
|
if host then
|
|
|
|
if host.name then
|
|
|
|
name = host.name
|
|
|
|
localpart = name:match("(.*)%.local%.mesh")
|
|
|
|
if not localpart then
|
|
|
|
localpart = name
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if host.tactical then
|
|
|
|
tactical = " / " .. host.tactical
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if rows[name] then
|
|
|
|
name = name .. " " -- avoid collision 2 links to same host {rf, dtd}
|
|
|
|
end
|
|
|
|
local no_space_host = name:match("(.*%S)%s*$")
|
2022-11-09 20:15:25 -07:00
|
|
|
c1 = "<a href='http://" .. no_space_host .. ":8080/'>" .. localpart .. tactical .. "</a>"
|
2022-01-19 06:42:31 -07:00
|
|
|
local nodeiface
|
|
|
|
if ipmain ~= ip then
|
|
|
|
if links[ip].dtd then
|
|
|
|
nodeiface = "dtd"
|
|
|
|
elseif links[ip].tun then
|
|
|
|
nodeiface = "tun"
|
|
|
|
else
|
|
|
|
nodeiface = "?"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if wangateway[ip] or wangateway[ipmain] then
|
|
|
|
if nodeiface then
|
|
|
|
nodeiface = nodeiface .. ",wan"
|
|
|
|
else
|
|
|
|
nodeiface = "wan"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if nodeiface then
|
2022-11-09 20:15:25 -07:00
|
|
|
c1 = c1 .. " <small>(" .. nodeiface .. ")</small>"
|
2022-01-19 06:42:31 -07:00
|
|
|
end
|
2022-11-09 20:15:25 -07:00
|
|
|
c2 = "<br>"
|
|
|
|
c3 = string.format("%.0f%%", 100 * link.lq)
|
|
|
|
c4 = string.format("%.0f%%", 100 * link.nlq)
|
|
|
|
c5 = string.format("%s", link.mbps)
|
2022-01-19 06:42:31 -07:00
|
|
|
|
2022-11-09 20:15:25 -07:00
|
|
|
-- print node services if any
|
2022-01-19 06:42:31 -07:00
|
|
|
if not neighservices[name] then
|
|
|
|
neighservices[name] = true
|
|
|
|
if services[name] then
|
2022-11-09 20:15:25 -07:00
|
|
|
local i=1
|
2022-01-19 06:42:31 -07:00
|
|
|
for _, v in pairs(services[name])
|
|
|
|
do
|
2022-11-09 20:15:25 -07:00
|
|
|
if c6 then
|
|
|
|
c6 = c6 .. v .. "<br>"
|
|
|
|
else
|
|
|
|
c6 = v .. "<br>"
|
|
|
|
end
|
|
|
|
if i > 1 then c2 = c2 .. "<br>" end
|
|
|
|
i=i+1
|
|
|
|
end
|
|
|
|
else
|
|
|
|
if c6 then
|
|
|
|
c6 = c6 .. "<br>"
|
|
|
|
else
|
|
|
|
c6 = "<br>"
|
2022-01-19 06:42:31 -07:00
|
|
|
end
|
|
|
|
end
|
2022-10-18 20:37:34 -06:00
|
|
|
|
2022-01-19 06:42:31 -07:00
|
|
|
-- add advertised dmz hosts
|
|
|
|
if host then
|
|
|
|
for _, dmzhost in ipairs(host.hosts)
|
|
|
|
do
|
|
|
|
local localpart = dmzhost:match("(.*)%.local%.mesh")
|
2022-10-20 14:43:55 -06:00
|
|
|
if localpart then
|
2022-11-09 20:15:25 -07:00
|
|
|
c2 = c2 .. localpart .. "<br>"
|
2022-10-20 14:43:55 -06:00
|
|
|
if services[dmzhost] then
|
2022-11-09 20:15:25 -07:00
|
|
|
local i=1
|
2022-10-20 14:43:55 -06:00
|
|
|
for _, v in pairs(services[dmzhost])
|
|
|
|
do
|
2022-11-09 20:15:25 -07:00
|
|
|
if c6 then
|
|
|
|
c6 = c6 .. v .. "<br>"
|
|
|
|
else
|
|
|
|
c6 = v .. "<br>"
|
|
|
|
end
|
|
|
|
if i > 1 then c2 = c2 .. "<br>" end
|
|
|
|
i=i+1
|
|
|
|
end
|
|
|
|
else
|
|
|
|
if c6 then
|
|
|
|
c6 = c6 .. "<br>"
|
|
|
|
else
|
|
|
|
c6 = "<br>"
|
2022-10-20 14:43:55 -06:00
|
|
|
end
|
2022-01-19 06:42:31 -07:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2022-11-09 20:15:25 -07:00
|
|
|
-- Build this row
|
|
|
|
local row = "<tr><td>" .. c1 .. "</td><td>" .. c2 .. "</td><td>" .. c3 .. "</td><td>" .. c4 .. "</td><td>" .. c5 .. "</td><td>" .. c6 .. "</td></tr>"
|
2022-01-19 06:42:31 -07:00
|
|
|
rows[#rows + 1] = { key = name, row = row }
|
|
|
|
end
|
|
|
|
if #rows > 0 then
|
|
|
|
table.sort(rows, function(a,b) return a.key < b.key end)
|
|
|
|
for _, row in ipairs(rows)
|
|
|
|
do
|
|
|
|
html.print(row.row)
|
|
|
|
end
|
|
|
|
-- discard
|
|
|
|
rows = nil
|
2013-11-14 23:11:16 -07:00
|
|
|
else
|
2022-01-19 06:42:31 -07:00
|
|
|
html.print("<tr><td>none</td></tr>")
|
|
|
|
end
|
|
|
|
|
2022-11-01 08:47:52 -06:00
|
|
|
--add previous neighbors
|
|
|
|
local rows = {}
|
|
|
|
local uptime = nixio.sysinfo().uptime
|
|
|
|
for ip, node in pairs(history)
|
|
|
|
do
|
|
|
|
if not (links[ip] or links[ipalias[ip]]) then
|
|
|
|
local age = uptime - tonumber(node.age)
|
|
|
|
local host = node.host
|
|
|
|
if host == "" then
|
|
|
|
host = ip
|
|
|
|
else
|
|
|
|
host = host:gsub("^mid%d+%.", ""):gsub("^dtdlink%.", "")
|
|
|
|
end
|
|
|
|
local row = "<tr><td style='color:sienna;'>" .. host
|
|
|
|
if hosts[ip] and hosts[ip].hosts then
|
|
|
|
for _, v in ipairs(hosts[ip].hosts)
|
|
|
|
do
|
|
|
|
row = row .. "<br>" .. v
|
|
|
|
end
|
|
|
|
end
|
|
|
|
row = row .. "</td><td style='color:sienna;'>"
|
|
|
|
if age < 3600 then
|
|
|
|
local val = math.floor(age / 60)
|
|
|
|
if val == 1 then
|
|
|
|
row = row .. "1 minute ago"
|
|
|
|
else
|
|
|
|
row = row .. val .. " minutes ago"
|
|
|
|
end
|
|
|
|
else
|
|
|
|
local val = string.format("%.1f", age / 3600)
|
|
|
|
if val == "1.0" then
|
|
|
|
row = row .. "1 hour ago"
|
|
|
|
else
|
|
|
|
row = row .. val .. " hours ago"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
row = row .. "</td></tr>"
|
|
|
|
rows[#rows + 1] = { key = age, row = row }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if #rows > 0 then
|
2022-11-09 20:15:25 -07:00
|
|
|
html.print("<tr><td style='color:sienna;font-weight:bold;padding-top:10px;'>Previous Neighbors</td></tr>")
|
2022-11-01 08:47:52 -06:00
|
|
|
table.sort(rows, function(a,b) return a.key < b.key end)
|
|
|
|
for _, row in ipairs(rows)
|
|
|
|
do
|
|
|
|
html.print(row.row)
|
|
|
|
end
|
|
|
|
-- discard
|
|
|
|
rows = nil
|
|
|
|
end
|
|
|
|
-- end current neighbors table
|
|
|
|
html.print("</table>")
|
2022-10-18 20:37:34 -06:00
|
|
|
|
|
|
|
-- show remote node table
|
2022-11-09 20:15:25 -07:00
|
|
|
|
2022-10-18 20:37:34 -06:00
|
|
|
html.print("<br><table id='rTable'><tr>")
|
2022-11-01 08:47:52 -06:00
|
|
|
html.print("<th width=25%><input class=search type=text id='inRN' onkeyup=nSearch('inRN','rTable',0) placeholder='Remote Nodes'></th>")
|
2022-10-18 20:37:34 -06:00
|
|
|
html.print("<th><input class=search type=text id='inRH' onkeyup=nSearch('inRH','rTable',1) placeholder='LAN Hostname'</th>")
|
|
|
|
html.print("<th>ETX</th>")
|
|
|
|
html.print("<th><input class=search type=text id='inRS' onkeyup=nSearch('inRS','rTable',3) placeholder='Service Name'</th>")
|
|
|
|
html.print("</tr>")
|
2022-01-19 06:42:31 -07:00
|
|
|
|
|
|
|
local rows = {}
|
2022-10-18 20:37:34 -06:00
|
|
|
for ip, host in pairs(hosts)
|
2022-01-19 06:42:31 -07:00
|
|
|
do
|
2022-11-09 20:15:25 -07:00
|
|
|
local c1,c2,c3,c4
|
2022-10-18 20:37:34 -06:00
|
|
|
if not neighbor[ip] and host.name then
|
|
|
|
local localpart = host.name:match("(.*)%.local%.mesh")
|
2022-10-20 14:43:55 -06:00
|
|
|
if localpart then
|
|
|
|
local tactical = ""
|
|
|
|
if host.tactical then
|
|
|
|
tactical = " / " .. host.tactical
|
2022-01-19 06:42:31 -07:00
|
|
|
end
|
2022-10-20 14:43:55 -06:00
|
|
|
local etx = string.format("%.2f", host.etx)
|
2022-11-09 20:15:25 -07:00
|
|
|
c1 = "<a href='http://" .. host.name .. ":8080/'>" .. localpart .. tactical .. "</a>"
|
2022-10-20 14:43:55 -06:00
|
|
|
local nodeiface
|
|
|
|
local mycount = 0
|
|
|
|
if midcount[ip] then
|
|
|
|
mycount = midcount[ip]
|
2022-01-19 06:42:31 -07:00
|
|
|
end
|
2022-10-20 14:43:55 -06:00
|
|
|
if dtd[ip] then
|
|
|
|
mycount = mycount - 1
|
|
|
|
end
|
|
|
|
if hosts[ip].tactical then
|
|
|
|
mycount = mycount - 1
|
|
|
|
end
|
|
|
|
if mycount > 0 then
|
|
|
|
nodeiface = "tun*" .. mycount
|
|
|
|
end
|
|
|
|
if wangateway[ip] then
|
|
|
|
if nodeiface then
|
|
|
|
nodeiface = nodeiface .. ",wan"
|
|
|
|
else
|
|
|
|
nodeiface = "wan"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if nodeiface then
|
2022-11-09 20:15:25 -07:00
|
|
|
c1 = c1 .. " <small>(" .. nodeiface .. ")</small>"
|
2022-10-20 14:43:55 -06:00
|
|
|
end
|
2022-11-09 20:15:25 -07:00
|
|
|
c2 = "<br>"
|
|
|
|
c3 = string.format("%s", etx)
|
|
|
|
|
|
|
|
-- print node services if any
|
2022-10-20 14:43:55 -06:00
|
|
|
if services[host.name] then
|
2022-11-09 20:15:25 -07:00
|
|
|
local i=1
|
2022-10-20 14:43:55 -06:00
|
|
|
for _, v in pairs(services[host.name])
|
2022-10-18 20:37:34 -06:00
|
|
|
do
|
2022-11-09 20:15:25 -07:00
|
|
|
if c4 then
|
|
|
|
c4 = c4 .. v .. "<br>"
|
|
|
|
else
|
|
|
|
c4 = v .. "<br>"
|
|
|
|
end
|
|
|
|
if i > 1 then c2 = c2 .. "<br>" end
|
|
|
|
i=i+1
|
|
|
|
end
|
|
|
|
else
|
|
|
|
if c4 then
|
|
|
|
c4 = c4 .. "<br>"
|
|
|
|
else
|
|
|
|
c4 = "<br>"
|
2022-10-18 20:37:34 -06:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-10-20 14:43:55 -06:00
|
|
|
-- add locally advertised dmz hosts
|
|
|
|
for _, dmzhost in ipairs(host.hosts)
|
|
|
|
do
|
|
|
|
local localpart = dmzhost:match("(.*)%.local%.mesh")
|
|
|
|
if localpart then
|
2022-11-09 20:15:25 -07:00
|
|
|
c2 = c2 .. localpart .. "<br>"
|
2022-10-20 14:43:55 -06:00
|
|
|
if services[dmzhost] then
|
2022-11-09 20:15:25 -07:00
|
|
|
local i=1
|
2022-10-20 14:43:55 -06:00
|
|
|
for _, v in pairs(services[dmzhost])
|
|
|
|
do
|
2022-11-09 20:15:25 -07:00
|
|
|
if c4 then
|
|
|
|
c4 = c4 .. v .. "<br>"
|
|
|
|
else
|
|
|
|
c4 = v .. "<br>"
|
|
|
|
end
|
|
|
|
if i > 1 then c2 = c2 .. "<br>" end
|
|
|
|
i=i+1
|
|
|
|
end
|
|
|
|
else
|
|
|
|
if c4 then
|
|
|
|
c4 = c4 .. "<br>"
|
|
|
|
else
|
|
|
|
c4 = "<br>"
|
2022-10-20 14:43:55 -06:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2022-11-09 20:15:25 -07:00
|
|
|
-- Build this row
|
|
|
|
local row = "<tr><td>" .. c1 .. "</td><td>" .. c2 .. "</td><td>" .. c3 .. "</td><td>" .. c4 .. "</td></tr>"
|
2022-10-20 14:43:55 -06:00
|
|
|
rows[#rows + 1] = { key = host.etx, row = row }
|
|
|
|
end
|
2022-01-19 06:42:31 -07:00
|
|
|
end
|
|
|
|
end
|
2022-10-18 20:37:34 -06:00
|
|
|
|
2022-01-19 06:42:31 -07:00
|
|
|
if #rows > 0 then
|
|
|
|
table.sort(rows, function(a,b) return a.key < b.key end)
|
|
|
|
for _, row in ipairs(rows)
|
|
|
|
do
|
|
|
|
html.print(row.row)
|
|
|
|
end
|
|
|
|
-- discard
|
|
|
|
rows = nil
|
|
|
|
else
|
|
|
|
html.print("<tr><td>none</td></tr>")
|
|
|
|
end
|
2022-10-18 20:37:34 -06:00
|
|
|
-- discard
|
|
|
|
neighbor = nil
|
|
|
|
dtd = nil
|
|
|
|
midcount = nil
|
|
|
|
wangateway = nil
|
|
|
|
services = nil
|
|
|
|
|
2022-01-19 06:42:31 -07:00
|
|
|
-- discard
|
|
|
|
links = nil
|
|
|
|
ipalias = nil
|
|
|
|
hosts = nil
|
|
|
|
history = nil
|
2022-11-01 08:47:52 -06:00
|
|
|
-- end remote nodes table
|
2022-10-18 20:37:34 -06:00
|
|
|
html.print("</table>")
|
2022-01-19 06:42:31 -07:00
|
|
|
|
|
|
|
html.print("</center>")
|
|
|
|
html.print("</form>")
|
|
|
|
|
2022-10-18 20:37:34 -06:00
|
|
|
html.print([[
|
|
|
|
<script>
|
|
|
|
function nSearch(inputId,tableId,colId) {
|
|
|
|
var input, filter, table, tr, td, i, txtval;
|
|
|
|
input = document.getElementById(inputId);
|
|
|
|
filter = input.value.toUpperCase();
|
|
|
|
table = document.getElementById(tableId);
|
|
|
|
tr = table.getElementsByTagName("tr");
|
|
|
|
for (i=0; i < tr.length; i++) {
|
|
|
|
td = tr[i].getElementsByTagName("td")[colId];
|
|
|
|
if (td) {
|
|
|
|
txtval = td.textContent || td.innerText;
|
|
|
|
if (txtval.toUpperCase().indexOf(filter) > -1 ) {
|
|
|
|
tr[i].style.display = "";
|
|
|
|
} else {
|
|
|
|
tr[i].style.display = "none";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</script>
|
|
|
|
]])
|
2022-01-19 06:42:31 -07:00
|
|
|
html.footer();
|
|
|
|
html.print("</body>")
|
|
|
|
html.print("</html>")
|