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();