From c6f55c8c15aea0e49653830ef63c1362e529a5c2 Mon Sep 17 00:00:00 2001 From: stswangzhiping <59632378+stswangzhiping@users.noreply.github.com> Date: Mon, 16 Mar 2026 13:04:00 +0800 Subject: [PATCH] fix: pre-scan WiFi before entering AP mode wlan0 cannot scan while in AP mode (hardware limitation). Now scan nearby networks before starting hotspot and cache the results for the captive portal page. Made-with: Cursor --- .commitmsg | 14 ++++---------- lib/captive-server.js | 17 ++++++++++------- lib/provisioning.js | 11 ++++++++--- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/.commitmsg b/.commitmsg index 9043512..5fde0c7 100644 --- a/.commitmsg +++ b/.commitmsg @@ -1,11 +1,5 @@ -fix: EROFS dns config, double WS connection, and watchdog timeout +fix: pre-scan WiFi before entering AP mode -1. EROFS: install.sh pre-writes DNS hijack config to dnsmasq-shared.d - since /etc may be read-only at runtime. dns-hijack.js gracefully - falls back to checking if config already exists. - -2. Double WS: add _connectionStarted guard to prevent _proceedWithConnection - from being called twice (via event + hasInternet check). - -3. Watchdog: move _startSdNotify() to start() beginning so READY=1 - is sent immediately, not delayed until network is ready. +wlan0 cannot scan while in AP mode (hardware limitation). +Now scan nearby networks before starting hotspot and cache +the results for the captive portal page. diff --git a/lib/captive-server.js b/lib/captive-server.js index 467fd95..4348a25 100644 --- a/lib/captive-server.js +++ b/lib/captive-server.js @@ -2,7 +2,7 @@ const http = require('http'); const log = require('./logger'); -const { scanWifi } = require('./network'); +// scanWifi 不再在此调用(AP 模式下无法扫描),改用缓存 const { CAPTIVE_DOMAIN } = require('./dns-hijack'); const PORT = 80; @@ -30,9 +30,10 @@ const CAPTIVE_DETECT_PATHS = new Set([ */ class CaptiveServer { constructor(opts = {}) { - this._server = null; - this._clawId = opts.clawId || '???'; - this._onConnect = opts.onConnect || null; // (ssid, password) => Promise<{success, error?}> + this._server = null; + this._clawId = opts.clawId || '???'; + this._onConnect = opts.onConnect || null; + this._cachedWifiList = opts.cachedWifiList || []; } startListening() { @@ -96,8 +97,8 @@ class CaptiveServer { // ── API ────────────────────────────────────────────────────────────────── _apiScan(req, res) { - const list = scanWifi(); - this._json(res, { wifi: list }); + // AP 模式下 wlan0 无法扫描,返回开 AP 前的缓存结果 + this._json(res, { wifi: this._cachedWifiList, cached: true }); } async _apiConnect(req, res) { @@ -227,7 +228,9 @@ async function doScan(){ o.textContent=w.ssid+' ('+w.signal+'% '+w.security+')'; sel.appendChild(o); }); - setStatus('扫描到 '+d.wifi.length+' 个网络','ok'); + var msg='发现 '+d.wifi.length+' 个网络'; + if(d.wifi.length===0) msg='未发现网络,请手动输入 SSID'; + setStatus(msg,'ok'); }catch(e){setStatus('扫描失败: '+e.message,'err')} $('connectBtn').disabled=false; } diff --git a/lib/provisioning.js b/lib/provisioning.js index 03d6dd5..be28301 100644 --- a/lib/provisioning.js +++ b/lib/provisioning.js @@ -2,7 +2,7 @@ const EventEmitter = require('events'); const log = require('./logger'); -const { hasInternet, hasSavedWifiConnection, isWifiStaConnected, startAP, stopAP, connectWifi, AP_IP } = require('./network'); +const { hasInternet, hasSavedWifiConnection, isWifiStaConnected, scanWifi, startAP, stopAP, connectWifi, AP_IP } = require('./network'); const { DnsHijack } = require('./dns-hijack'); const { CaptiveServer } = require('./captive-server'); @@ -98,8 +98,12 @@ class ProvisionManager extends EventEmitter { if (this._state === 'ap') return; try { - // 先写 DNS 劫持配置,再启动 AP - // NM 启动热点时会加载 dnsmasq-shared.d/ 下的配置 + // AP 模式下无法扫描 WiFi,必须在开 AP 之前扫描并缓存 + log.info('provision', '扫描周边 WiFi...'); + this._cachedWifiList = scanWifi(); + log.info('provision', `扫描到 ${this._cachedWifiList.length} 个网络`); + + // 写 DNS 劫持配置(NM 启动热点时加载) this._dns = new DnsHijack(); this._dns.start('wlan0', AP_IP); @@ -107,6 +111,7 @@ class ProvisionManager extends EventEmitter { this._server = new CaptiveServer({ clawId: this._clawId, + cachedWifiList: this._cachedWifiList, onConnect: (ssid, password) => this._handleWifiConnect(ssid, password), }); this._server.startListening();