mirror of https://github.com/aredn/aredn.git
Scan cache (#1160)
* Cache the last wifi scan and update it when a re-scan is requested. This change was suggested as a way of handling Ubiquiti AC devices which disconnect while scanning and making retrieving the results problematic if that was your connection. Now we scan and store the results so they can be retrieved later. In fact we no longer scan when navigating to this page but require an explicity scan button push. This make the page generally more responsive when initially navigated to.
This commit is contained in:
parent
c25be28b97
commit
86271040a0
|
@ -36,6 +36,7 @@
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
require("nixio")
|
require("nixio")
|
||||||
|
require("luci.jsonc")
|
||||||
require("aredn.http")
|
require("aredn.http")
|
||||||
require("aredn.hardware")
|
require("aredn.hardware")
|
||||||
require("aredn.utils")
|
require("aredn.utils")
|
||||||
|
@ -55,19 +56,32 @@ if board_type:match("^ubnt,") and board_type:match("ac") then
|
||||||
ubnt_ac = true
|
ubnt_ac = true
|
||||||
end
|
end
|
||||||
|
|
||||||
local channels = aredn.hardware.get_rfchannels(wifiiface)
|
local rescan = string.find((nixio.getenv("QUERY_STRING") or ""):lower(),"rescan=1")
|
||||||
local scan_list = ""
|
|
||||||
for _, channel in ipairs(channels)
|
local scanlist = {}
|
||||||
do
|
-- Show the last scan if we have one, it's not too old, and we're not rescanning
|
||||||
scan_list = scan_list .. " " .. channel.frequency
|
if not rescan then
|
||||||
|
local lscan = io.open("/tmp/last-scan.json")
|
||||||
|
if lscan then
|
||||||
|
scanlist = luci.jsonc.parse(lscan:read("*a") or "")
|
||||||
|
lscan:close()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- scan start
|
if rescan then
|
||||||
|
local channels = aredn.hardware.get_rfchannels(wifiiface)
|
||||||
|
local scan_list = ""
|
||||||
|
for _, channel in ipairs(channels)
|
||||||
|
do
|
||||||
|
scan_list = scan_list .. " " .. channel.frequency
|
||||||
|
end
|
||||||
|
|
||||||
local scanned = {}
|
-- scan start
|
||||||
|
|
||||||
local f = io.popen("iw dev " .. wifiiface .. " station dump")
|
local scanned = {}
|
||||||
if f then
|
|
||||||
|
local f = io.popen("iw dev " .. wifiiface .. " station dump")
|
||||||
|
if f then
|
||||||
local scan = {}
|
local scan = {}
|
||||||
local myssid = aredn.info.getSSID()
|
local myssid = aredn.info.getSSID()
|
||||||
for line in f:lines()
|
for line in f:lines()
|
||||||
|
@ -87,7 +101,7 @@ if f then
|
||||||
end
|
end
|
||||||
scan.mode = "Connected Ad-Hoc Station"
|
scan.mode = "Connected Ad-Hoc Station"
|
||||||
scan.ssid = myssid
|
scan.ssid = myssid
|
||||||
scan.freq[myfreq] = true
|
scan.freq[tostring(myfreq)] = true
|
||||||
end
|
end
|
||||||
m = line:match("signal avg:%s+([%d%-]+)")
|
m = line:match("signal avg:%s+([%d%-]+)")
|
||||||
if m then
|
if m then
|
||||||
|
@ -95,10 +109,10 @@ if f then
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
f:close()
|
f:close()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Ubiquiti AC device workaround
|
-- Ubiquiti AC device workaround
|
||||||
if ubnt_ac then
|
if ubnt_ac then
|
||||||
os.execute("iw dev " .. wifiiface .. " ibss leave > /dev/null 2>&1")
|
os.execute("iw dev " .. wifiiface .. " ibss leave > /dev/null 2>&1")
|
||||||
os.execute("wifi up > /dev/null 2>&1")
|
os.execute("wifi up > /dev/null 2>&1")
|
||||||
local attempt = 10
|
local attempt = 10
|
||||||
|
@ -114,10 +128,10 @@ if ubnt_ac then
|
||||||
end
|
end
|
||||||
nixio.nanosleep(2, 0)
|
nixio.nanosleep(2, 0)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local f = io.popen("iw dev " .. wifiiface .. " scan freq" .. scan_list .. " passive")
|
local f = io.popen("iw dev " .. wifiiface .. " scan freq" .. scan_list .. " passive")
|
||||||
if f then
|
if f then
|
||||||
local scan = {}
|
local scan = {}
|
||||||
for line in f:lines()
|
for line in f:lines()
|
||||||
do
|
do
|
||||||
|
@ -170,69 +184,26 @@ if f then
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
f:close()
|
f:close()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- scan end
|
-- scan end
|
||||||
|
|
||||||
-- generate page
|
-- load arp cache
|
||||||
http_header()
|
local arpcache = {}
|
||||||
html.header(node .. " WiFi scan", false)
|
arptable(function(a)
|
||||||
local autoscan = string.find((nixio.getenv("QUERY_STRING") or ""):lower(),"autoscan=1")
|
|
||||||
if autoscan then
|
|
||||||
html.print("<script>setTimeout(function(){ window.location.reload(); }, 10000);</script>")
|
|
||||||
end
|
|
||||||
html.print([[
|
|
||||||
<script src="/js/sorttable-min.js"></script>
|
|
||||||
<style>
|
|
||||||
table {
|
|
||||||
border-collapse:collapse;
|
|
||||||
}
|
|
||||||
table.sortable thead {
|
|
||||||
background-color:#eee;
|
|
||||||
color:#666666;
|
|
||||||
font-weight: bold;
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body><form method=post action=/cgi-bin/scan enctype='multipart/form-data'>
|
|
||||||
<center>
|
|
||||||
]])
|
|
||||||
|
|
||||||
html.alert_banner()
|
|
||||||
html.print("<h1>" .. node .. " WiFi scan</h1><hr>")
|
|
||||||
|
|
||||||
if autoscan then
|
|
||||||
html.print("<input type=button name=stop value=Stop title='Abort continuous scan' onclick='window.location = window.location.origin + window.location.pathname'>")
|
|
||||||
else
|
|
||||||
html.print("<input type=button name=refresh value=Refresh title='Refresh this page' onclick='window.location.reload();'>")
|
|
||||||
html.print(" ")
|
|
||||||
html.print([[<input type=button name=auto value=Auto title='Begin continuous scan' onclick='window.location = window.location.origin + window.location.pathname + "?autoscan=1"'>]])
|
|
||||||
end
|
|
||||||
|
|
||||||
html.print(" ")
|
|
||||||
html.print("<button type=button onClick='window.location=\"status\"' title='Return to status page'>Quit</button><br><br>")
|
|
||||||
|
|
||||||
-- display scan
|
|
||||||
html.print("<table class=sortable border=1 cellpadding=5>")
|
|
||||||
html.print("<tr><th>SNR</th><th>Signal</th><th>Chan</th><th>Enc</th><th>SSID</th><th>Hostname</th><th>MAC/BSSID</th><th>802.11 Mode</th></tr>")
|
|
||||||
|
|
||||||
-- load arp cache
|
|
||||||
local arpcache = {}
|
|
||||||
arptable(function(a)
|
|
||||||
arpcache[a["HW address"]] = a["IP address"]
|
arpcache[a["HW address"]] = a["IP address"]
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local scanlist = {}
|
scanlist = {}
|
||||||
for _, v in pairs(scanned)
|
for _, v in pairs(scanned)
|
||||||
do
|
do
|
||||||
if v.signal ~= 9999 or v.joined then
|
if v.signal ~= 9999 or v.joined then
|
||||||
scanlist[#scanlist + 1] = v
|
scanlist[#scanlist + 1] = v
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
table.sort(scanlist, function(a, b) return a.signal > b.signal end)
|
table.sort(scanlist, function(a, b) return a.signal > b.signal end)
|
||||||
for _, scan in ipairs(scanlist)
|
for _, scan in ipairs(scanlist)
|
||||||
do
|
do
|
||||||
-- freq to chan
|
-- freq to chan
|
||||||
local chan = {}
|
local chan = {}
|
||||||
for f, _ in pairs(scan.freq)
|
for f, _ in pairs(scan.freq)
|
||||||
|
@ -255,39 +226,120 @@ do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
table.sort(chan)
|
table.sort(chan)
|
||||||
chan = table.concat(chan, " ")
|
scan.chan = table.concat(chan, " ")
|
||||||
if scan.joined then
|
if scan.joined then
|
||||||
hostname = node
|
scan.hostname = node
|
||||||
else
|
else
|
||||||
-- ip lookup then host lookup
|
-- ip lookup then host lookup
|
||||||
local ip = arpcache[scan.mac]
|
local ip = arpcache[scan.mac]
|
||||||
if ip then
|
if ip then
|
||||||
hostname = ip
|
scan.hostname = ip
|
||||||
local f = io.popen("nslookup " .. ip)
|
local f = io.popen("nslookup " .. ip)
|
||||||
if f then
|
if f then
|
||||||
for line in f:lines()
|
for line in f:lines()
|
||||||
do
|
do
|
||||||
local m = line:match("name = (.*)%.local%.mesh")
|
local m = line:match("name = (.*)%.local%.mesh")
|
||||||
if m then
|
if m then
|
||||||
hostname = m:gsub("^mid[0-9]*%.",""):gsub("^dtdlink%.",""):gsub("%.local%.mesh$","")
|
scan.hostname = m:gsub("^mid[0-9]*%.",""):gsub("^dtdlink%.",""):gsub("%.local%.mesh$","")
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
f:close()
|
f:close()
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
hostname = "-"
|
scan.hostname = "-"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
lscan = io.open("/tmp/last-scan.json", "w")
|
||||||
|
if lscan then
|
||||||
|
lscan:write(luci.jsonc.stringify(scanlist, true))
|
||||||
|
lscan:close()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- generate page
|
||||||
|
http_header()
|
||||||
|
html.header(node .. " WiFi scan", false)
|
||||||
|
local autoscan = string.find((nixio.getenv("QUERY_STRING") or ""):lower(),"autoscan=1")
|
||||||
|
if autoscan then
|
||||||
|
html.print("<script>setTimeout(function(){ window.location.reload(); }, 10000);</script>")
|
||||||
|
end
|
||||||
|
if rescan then
|
||||||
|
html.print([[
|
||||||
|
<script>
|
||||||
|
if (history.replaceState) {
|
||||||
|
history.replaceState(null, "", window.location.origin + window.location.pathname)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
]])
|
||||||
|
end
|
||||||
|
html.print([[
|
||||||
|
<script src="/js/sorttable-min.js"></script>
|
||||||
|
<style>
|
||||||
|
table {
|
||||||
|
border-collapse:collapse;
|
||||||
|
}
|
||||||
|
table.sortable thead {
|
||||||
|
background-color:#eee;
|
||||||
|
color:#666666;
|
||||||
|
font-weight: bold;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<center>
|
||||||
|
]])
|
||||||
|
|
||||||
|
html.alert_banner()
|
||||||
|
html.print("<h1>" .. node .. " WiFi scan</h1><hr>")
|
||||||
|
|
||||||
|
if autoscan then
|
||||||
|
html.print("<input type=button name=stop value=Stop title='Abort continuous scan' onclick='window.location = window.location.origin + window.location.pathname'>")
|
||||||
|
else
|
||||||
|
html.print([[<input type=button name=refresh value=Rescan title='Run a new scan' onclick='window.location = window.location.origin + window.location.pathname + "?rescan=1"'>]])
|
||||||
|
if not ubnt_ac then
|
||||||
|
html.print(" ")
|
||||||
|
html.print([[<input type=button name=auto value=Auto title='Begin continuous scan' onclick='window.location = window.location.origin + window.location.pathname + "?autoscan=1"'>]])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
html.print(" ")
|
||||||
|
html.print("<button type=button onClick='window.location=\"status\"' title='Return to status page'>Quit</button><br><br>")
|
||||||
|
|
||||||
|
-- display scan
|
||||||
|
html.print("<table class=sortable border=1 cellpadding=5>")
|
||||||
|
html.print("<tr><th>SNR</th><th>Signal</th><th>Chan</th><th>Enc</th><th>SSID</th><th>Hostname</th><th>MAC/BSSID</th><th>802.11 Mode</th></tr>")
|
||||||
|
|
||||||
|
for _, scan in ipairs(scanlist)
|
||||||
|
do
|
||||||
if scan.ssid:match("^AREDN-") then
|
if scan.ssid:match("^AREDN-") then
|
||||||
html.print("<tr class=\"wscan-row-node\">")
|
html.print("<tr class=\"wscan-row-node\">")
|
||||||
else
|
else
|
||||||
html.print("<tr>")
|
html.print("<tr>")
|
||||||
end
|
end
|
||||||
html.print("<td>" .. (scan.signal - nf) .. "</td><td>" .. scan.signal .. "</td><td>" .. chan .. "</td><td>" .. scan.key .. "</td><td>" .. scan.ssid .. "</td><td align=center>" .. hostname .. "</td><td>" .. scan.mac:upper() .. "</td><td>" .. scan.mode .. "</td>")
|
html.print("<td>" .. (scan.signal - nf) .. "</td><td>" .. scan.signal .. "</td><td>" .. scan.chan .. "</td><td>" .. scan.key .. "</td><td>" .. scan.ssid .. "</td><td align=center>" .. scan.hostname .. "</td><td>" .. scan.mac:upper() .. "</td><td>" .. scan.mode .. "</td>")
|
||||||
html.print("</tr>")
|
html.print("</tr>")
|
||||||
end
|
end
|
||||||
|
|
||||||
html.print("</table><br></center>")
|
html.print("</table><br>")
|
||||||
|
local lastscan = nixio.fs.stat("/tmp/last-scan.json", "mtime")
|
||||||
|
if lastscan then
|
||||||
|
lastscan = os.time() - lastscan
|
||||||
|
if lastscan == 1 then
|
||||||
|
html.print("<div>Last scan: 1 second ago")
|
||||||
|
elseif lastscan < 60 then
|
||||||
|
html.print("<div>Last scan: " .. lastscan .. " seconds ago")
|
||||||
|
elseif lastscan < 120 then
|
||||||
|
html.print("<div>Last scan: 1 minute ago")
|
||||||
|
elseif lastscan < 3600 then
|
||||||
|
html.print("<div>Last scan: " .. math.floor(lastscan / 60) .. " minutes ago")
|
||||||
|
else
|
||||||
|
html.print("<div>Last scan: a long time ago")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
html.print("<div>Last scan: none")
|
||||||
|
end
|
||||||
html.footer()
|
html.footer()
|
||||||
html.print("</body></html>")
|
html.print("</center></body></html>")
|
||||||
|
|
Loading…
Reference in New Issue