fix(network): async connectWifi so systemd watchdog can fire during nmcli wait

This commit is contained in:
stswangzhiping
2026-03-29 08:14:24 +08:00
parent 4c16483ee7
commit e3e9580e46
2 changed files with 41 additions and 9 deletions

View File

@@ -1,6 +1,6 @@
'use strict';
const { execSync, spawnSync } = require('child_process');
const { execSync, spawnSync, spawn } = require('child_process');
const fs = require('fs');
const os = require('os');
const log = require('./logger');
@@ -222,27 +222,59 @@ function nmcliSync(args, timeoutMs = 60000) {
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
* @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();
log.info('network', `尝试连接 WiFi: ${ssid}ifname=${iface}`);
try {
try {
nmcliSync(['connection', 'delete', ssid], 15000);
await nmcliAsync(['connection', 'delete', ssid], 15000);
} catch (_) {}
// 关热点后部分固件需显式保证由 NM 管理、再关联
try {
nmcliSync(['device', 'set', iface, 'managed', 'yes'], 8000);
await nmcliAsync(['device', 'set', iface, 'managed', 'yes'], 8000);
} catch (_) {}
const args = ['device', 'wifi', 'connect', ssid];
if (password) args.push('password', password);
args.push('ifname', iface);
nmcliSync(args, 120000);
await nmcliAsync(args, 120000);
const deadline = Date.now() + CONNECT_WIFI_STA_WAIT_MS;
while (Date.now() < deadline) {
@@ -257,7 +289,7 @@ function connectWifi(ssid, password) {
}
return { success: true };
}
sleep(CONNECT_WIFI_STA_POLL_MS);
await _delay(CONNECT_WIFI_STA_POLL_MS);
}
return { success: false, error: '超时:网卡未进入已连接状态' };
} catch (e) {