From 8d88802b835fa930337a61ff45f99b88b0de8214 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Wed, 18 Jul 2018 14:43:27 +0200 Subject: [PATCH] luci-mod-admin-full: use incremental background scanning for wireless join The previous approach of synchroneously scanning while building the result page was suboptimal since it frequently led to connection resets when accessing LuCI via wireless. It also exhibited problems when accessed via SSL on recent Firefox versions where the page were only loaded partially. Rework the wireless scanning to gather scan results in a background process and put them into the ubus session data area where they can be readily accessed without causing network interruptions. Subsequently rebuild the wireless join page to use XHR polling to incrementally fetch updated scan results. Signed-off-by: Jo-Philipp Wich (cherry picked from commit 9b4efaefa1b4c94a7d976c8d65169bf056032e09) --- .../luasrc/controller/admin/network.lua | 78 +++++ .../luasrc/view/admin_network/wifi_join.htm | 301 +++++++++++------- 2 files changed, 257 insertions(+), 122 deletions(-) diff --git a/modules/luci-mod-admin-full/luasrc/controller/admin/network.lua b/modules/luci-mod-admin-full/luasrc/controller/admin/network.lua index 31b941625..c45605a98 100644 --- a/modules/luci-mod-admin-full/luasrc/controller/admin/network.lua +++ b/modules/luci-mod-admin-full/luasrc/controller/admin/network.lua @@ -58,6 +58,12 @@ function index() page = entry({"admin", "network", "wireless_reconnect"}, post("wifi_reconnect"), nil) page.leaf = true + page = entry({"admin", "network", "wireless_scan_trigger"}, post("wifi_scan_trigger"), nil) + page.leaf = true + + page = entry({"admin", "network", "wireless_scan_results"}, call("wifi_scan_results"), nil) + page.leaf = true + page = entry({"admin", "network", "wireless"}, arcombine(cbi("admin_network/wifi_overview"), cbi("admin_network/wifi")), _("Wireless"), 15) page.leaf = true page.subindex = true @@ -309,6 +315,78 @@ function wifi_assoclist() luci.http.write_json(s.wifi_assoclist()) end + +local function _wifi_get_scan_results(cache_key) + local results = luci.util.ubus("session", "get", { + ubus_rpc_session = luci.model.uci:get_session_id(), + keys = { cache_key } + }) + + if type(results) == "table" and + type(results.values) == "table" and + type(results.values[cache_key]) == "table" + then + return results.values[cache_key] + end + + return { } +end + +function wifi_scan_trigger(radio, update) + local iw = radio and luci.sys.wifi.getiwinfo(radio) + + if not iw then + luci.http.status(404, "No such radio device") + return + end + + luci.http.status(200, "Scan scheduled") + + if nixio.fork() == 0 then + io.stderr:close() + io.stdout:close() + + local _, bss + local data, bssids = { }, { } + local cache_key = "scan_%s" % radio + + luci.util.ubus("session", "set", { + ubus_rpc_session = luci.model.uci:get_session_id(), + values = { [cache_key] = nil } + }) + + for _, bss in ipairs(iw.scanlist or { }) do + data[_] = bss + bssids[bss.bssid] = bss + end + + if update then + for _, bss in ipairs(_wifi_get_scan_results(cache_key)) do + if not bssids[bss.bssid] then + bss.stale = true + data[#data + 1] = bss + end + end + end + + luci.util.ubus("session", "set", { + ubus_rpc_session = luci.model.uci:get_session_id(), + values = { [cache_key] = data } + }) + end +end + +function wifi_scan_results(radio) + local results = radio and _wifi_get_scan_results("scan_%s" % radio) + + if results and #results > 0 then + luci.http.prepare_content("application/json") + luci.http.write_json(results) + else + luci.http.status(404, "No wireless scan results") + end +end + function lease_status() local s = require "luci.tools.status" diff --git a/modules/luci-mod-admin-full/luasrc/view/admin_network/wifi_join.htm b/modules/luci-mod-admin-full/luasrc/view/admin_network/wifi_join.htm index 9b93942c8..987123642 100644 --- a/modules/luci-mod-admin-full/luasrc/view/admin_network/wifi_join.htm +++ b/modules/luci-mod-admin-full/luasrc/view/admin_network/wifi_join.htm @@ -8,56 +8,6 @@ local sys = require "luci.sys" local utl = require "luci.util" - function guess_wifi_signal(info) - local scale = (100 / (info.quality_max or 100) * (info.quality or 0)) - local icon - - if not info.bssid or info.bssid == "00:00:00:00:00:00" then - icon = resource .. "/icons/signal-none.png" - elseif scale < 15 then - icon = resource .. "/icons/signal-0.png" - elseif scale < 35 then - icon = resource .. "/icons/signal-0-25.png" - elseif scale < 55 then - icon = resource .. "/icons/signal-25-50.png" - elseif scale < 75 then - icon = resource .. "/icons/signal-50-75.png" - else - icon = resource .. "/icons/signal-75-100.png" - end - - return icon - end - - function percent_wifi_signal(info) - local qc = info.quality or 0 - local qm = info.quality_max or 0 - - if info.bssid and qc > 0 and qm > 0 then - return math.floor((100 / qm) * qc) - else - return 0 - end - end - - function format_wifi_encryption(info) - if info.wep == true then - return "WEP" - elseif info.wpa > 0 then - return translatef("%s - %s", - table.concat(info.pair_ciphers, ", "), - table.concat(info.group_ciphers, ", "), - (info.wpa == 3) and translate("mixed WPA/WPA2") - or (info.wpa == 2 and "WPA2" or "WPA"), - table.concat(info.auth_suites, ", ") - ) - elseif info.enabled then - return "%s" % translate("unknown") - else - return "%s" % translate("open") - end - end - local dev = luci.http.formvalue("device") local iw = luci.sys.wifi.getiwinfo(dev) @@ -65,91 +15,198 @@ luci.http.redirect(luci.dispatcher.build_url("admin/network/wireless")) return end - - - function scanlist(times) - local i, k, v - local l = { } - local s = { } - - for i = 1, times do - for k, v in ipairs(iw.scanlist or { }) do - if not s[v.bssid] then - l[#l+1] = v - s[v.bssid] = true - end - end - end - - return l - end -%> <%+header%> + +

<%:Join Network: Wireless Scan%>

-
+
-
<%:Signal%>
-
<%:SSID%>
-
<%:Channel%>
-
<%:Mode%>
-
<%:BSSID%>
-
<%:Encryption%>
+
<%:Signal%>
+
<%:SSID%>
+
<%:Channel%>
+
<%:Mode%>
+
<%:BSSID%>
+
<%:Encryption%>
 
- - <% for i, net in ipairs(scanlist(3)) do net.encryption = net.encryption or { } %> -
-
- -
- <%=percent_wifi_signal(net)%>% -
-
-
- <%=net.ssid and utl.pcdata(net.ssid) or "%s" % translate("hidden")%> -
-
- <%=net.channel%> -
-
- <%=net.mode%> -
-
- <%=net.bssid%> -
-
- <%=format_wifi_encryption(net.encryption)%> -
-
-
- - - - - - - - <% if net.encryption.wpa then %> - - <% for _, v in ipairs(net.encryption.auth_suites) do %> - <% end; for _, v in ipairs(net.encryption.group_ciphers) do %> - <% end; for _, v in ipairs(net.encryption.pair_ciphers) do %> - <% end; end %> - - " /> - - -
+
+
+ + <%:Collecting data...%>
- <% end %> -
@@ -160,7 +217,7 @@
- +
-- 2.25.1