fix(network): async connectWifi so systemd watchdog can fire during nmcli wait
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { execSync, spawnSync } = require('child_process');
|
const { execSync, spawnSync, spawn } = require('child_process');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const os = require('os');
|
const os = require('os');
|
||||||
const log = require('./logger');
|
const log = require('./logger');
|
||||||
@@ -222,27 +222,59 @@ function nmcliSync(args, timeoutMs = 60000) {
|
|||||||
return (r.stdout || '').trim();
|
return (r.stdout || '').trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _delay(ms) {
|
||||||
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 异步 nmcli,不阻塞事件循环(systemd Watchdog 依赖 setInterval 在主线程运行) */
|
||||||
|
function nmcliAsync(args, timeoutMs = 60000) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const child = spawn('nmcli', args, { stdio: ['ignore', 'pipe', 'pipe'] });
|
||||||
|
let stdout = '';
|
||||||
|
let stderr = '';
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
child.kill('SIGKILL');
|
||||||
|
reject(new Error('nmcli 超时'));
|
||||||
|
}, timeoutMs);
|
||||||
|
child.stdout.on('data', (d) => { stdout += d; });
|
||||||
|
child.stderr.on('data', (d) => { stderr += d; });
|
||||||
|
child.on('error', (err) => {
|
||||||
|
clearTimeout(timer);
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
child.on('close', (code) => {
|
||||||
|
clearTimeout(timer);
|
||||||
|
if (code !== 0) {
|
||||||
|
const msg = stderr.trim() || stdout.trim() || `nmcli exit ${code}`;
|
||||||
|
reject(new Error(msg));
|
||||||
|
} else {
|
||||||
|
resolve(stdout.trim());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 连接指定 WiFi(配网场景:成功 = NM 显示 STA 已连上目标网,不要求一定能 ping 通 8.8.8.8)
|
* 连接指定 WiFi(配网场景:成功 = NM 显示 STA 已连上目标网,不要求一定能 ping 通 8.8.8.8)
|
||||||
* @returns {{ success: boolean, error?: string }}
|
* 必须异步:同步 spawnSync + execSync(sleep) 会卡住主线程,导致 systemd WatchdogSec 内收不到 WATCHDOG=1。
|
||||||
|
* @returns {Promise<{ success: boolean, error?: string }>}
|
||||||
*/
|
*/
|
||||||
function connectWifi(ssid, password) {
|
async function connectWifi(ssid, password) {
|
||||||
const iface = getWifiIface();
|
const iface = getWifiIface();
|
||||||
log.info('network', `尝试连接 WiFi: ${ssid}(ifname=${iface})`);
|
log.info('network', `尝试连接 WiFi: ${ssid}(ifname=${iface})`);
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
nmcliSync(['connection', 'delete', ssid], 15000);
|
await nmcliAsync(['connection', 'delete', ssid], 15000);
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
|
|
||||||
// 关热点后部分固件需显式保证由 NM 管理、再关联
|
|
||||||
try {
|
try {
|
||||||
nmcliSync(['device', 'set', iface, 'managed', 'yes'], 8000);
|
await nmcliAsync(['device', 'set', iface, 'managed', 'yes'], 8000);
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
|
|
||||||
const args = ['device', 'wifi', 'connect', ssid];
|
const args = ['device', 'wifi', 'connect', ssid];
|
||||||
if (password) args.push('password', password);
|
if (password) args.push('password', password);
|
||||||
args.push('ifname', iface);
|
args.push('ifname', iface);
|
||||||
nmcliSync(args, 120000);
|
await nmcliAsync(args, 120000);
|
||||||
|
|
||||||
const deadline = Date.now() + CONNECT_WIFI_STA_WAIT_MS;
|
const deadline = Date.now() + CONNECT_WIFI_STA_WAIT_MS;
|
||||||
while (Date.now() < deadline) {
|
while (Date.now() < deadline) {
|
||||||
@@ -257,7 +289,7 @@ function connectWifi(ssid, password) {
|
|||||||
}
|
}
|
||||||
return { success: true };
|
return { success: true };
|
||||||
}
|
}
|
||||||
sleep(CONNECT_WIFI_STA_POLL_MS);
|
await _delay(CONNECT_WIFI_STA_POLL_MS);
|
||||||
}
|
}
|
||||||
return { success: false, error: '超时:网卡未进入已连接状态' };
|
return { success: false, error: '超时:网卡未进入已连接状态' };
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ class ProvisionManager extends EventEmitter {
|
|||||||
// 关热点后射频/模式切换需要时间,立刻 connect 在部分板子上会失败
|
// 关热点后射频/模式切换需要时间,立刻 connect 在部分板子上会失败
|
||||||
await new Promise((r) => setTimeout(r, 3500));
|
await new Promise((r) => setTimeout(r, 3500));
|
||||||
|
|
||||||
const result = connectWifi(ssid, password);
|
const result = await connectWifi(ssid, password);
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
this._state = 'sta';
|
this._state = 'sta';
|
||||||
|
|||||||
Reference in New Issue
Block a user