fix(network): auto-detect wired iface and ping via -I for hasInternet
- Scan sysfs for carrier when CLAWD_ETH_IFACE unset (end0/enp* etc.) - Explicit CLAWD_ETH_IFACE still pins a single interface - Ping fallback uses -I wired iface when default route fails (e.g. AP on wlan) - Exclude can/docker/veth/wl* and similar from auto scan - Clarify client log when waiting for WAN Made-with: Cursor
This commit is contained in:
@@ -9,43 +9,91 @@ const AP_SSID_PREFIX = 'ClawBox-';
|
||||
const AP_IP = '10.42.0.1';
|
||||
const AP_PASSWORD = '12345678';
|
||||
const AP_IFACE = process.env.CLAWD_WIFI_IFACE || '';
|
||||
const ETH_IFACE = process.env.CLAWD_ETH_IFACE || 'eth0';
|
||||
const CON_NAME = 'clawd-hotspot';
|
||||
|
||||
/**
|
||||
* 检查有线网卡物理链路是否接通(读 sysfs carrier,无延迟)
|
||||
*/
|
||||
function hasWiredCarrier() {
|
||||
try {
|
||||
const carrier = fs.readFileSync(`/sys/class/net/${ETH_IFACE}/carrier`, 'utf8').trim();
|
||||
return carrier === '1';
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
/** 非 WiFi、非典型虚拟接口,用于自动发现有线口(如 end0、enp*,而非仅 eth0) */
|
||||
function _isExcludedVirtualIface(name) {
|
||||
if (name === 'lo' || name === 'bonding_masters') return true;
|
||||
if (name.startsWith('wl')) return true;
|
||||
if (name.startsWith('docker')) return true;
|
||||
if (name.startsWith('veth')) return true;
|
||||
if (name.startsWith('virbr')) return true;
|
||||
if (name.startsWith('br-')) return true;
|
||||
if (name.startsWith('tun') || name.startsWith('tap')) return true;
|
||||
if (name.startsWith('wg') || name.startsWith('bond')) return true;
|
||||
if (name.startsWith('can')) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测是否有互联网连接(尝试 DNS 解析 + HTTP 连通性)
|
||||
* 返回当前链路 up 的有线网卡名。
|
||||
* 若设置 CLAWD_ETH_IFACE,只认该接口;否则扫描 sysfs(与仅默认 eth0 相比适配更多板型)。
|
||||
*/
|
||||
function hasInternet() {
|
||||
// 物理层快检:无 WiFi STA 且有线 carrier=0 → 立即返回 false(nmcli 有缓存,不可信)
|
||||
if (!isWifiStaConnected() && !hasWiredCarrier()) return false;
|
||||
function getWiredIfaceWithCarrier() {
|
||||
const explicit = process.env.CLAWD_ETH_IFACE;
|
||||
if (explicit) {
|
||||
try {
|
||||
if (fs.readFileSync(`/sys/class/net/${explicit}/carrier`, 'utf8').trim() === '1') {
|
||||
return explicit;
|
||||
}
|
||||
} catch (_) {}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 优先用 nmcli 的 connectivity check
|
||||
try {
|
||||
const out = run('nmcli networking connectivity check').trim();
|
||||
if (out === 'full' || out === 'limited') return true;
|
||||
const names = fs.readdirSync('/sys/class/net');
|
||||
for (const name of names.sort()) {
|
||||
if (_isExcludedVirtualIface(name)) continue;
|
||||
try {
|
||||
if (fs.readFileSync(`/sys/class/net/${name}/carrier`, 'utf8').trim() === '1') {
|
||||
return name;
|
||||
}
|
||||
} catch (_) {}
|
||||
}
|
||||
} catch (_) {}
|
||||
|
||||
// 兜底:ping DNS
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否存在任一带 carrier 的有线接口(无延迟)
|
||||
*/
|
||||
function hasWiredCarrier() {
|
||||
return getWiredIfaceWithCarrier() !== null;
|
||||
}
|
||||
|
||||
function _tryPingInternet() {
|
||||
try {
|
||||
run('ping -c 1 -W 3 8.8.8.8');
|
||||
return true;
|
||||
} catch (_) {}
|
||||
|
||||
// 开热点时默认路由可能走 wlan,无 -I 的 ping 会误判;指定有线口再试
|
||||
const wired = getWiredIfaceWithCarrier();
|
||||
if (wired) {
|
||||
try {
|
||||
run(`ping -c 1 -W 3 -I ${wired} 8.8.8.8`);
|
||||
return true;
|
||||
} catch (_) {}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测是否有互联网连接(nmcli 连通性 + ping 兜底)
|
||||
*/
|
||||
function hasInternet() {
|
||||
// 物理层快检:无 WiFi STA 且无任何有线 carrier → 立即 false(nmcli 有缓存,不可信)
|
||||
if (!isWifiStaConnected() && !hasWiredCarrier()) return false;
|
||||
|
||||
try {
|
||||
const out = run('nmcli networking connectivity check').trim();
|
||||
if (out === 'full' || out === 'limited') return true;
|
||||
} catch (_) {}
|
||||
|
||||
return _tryPingInternet();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取默认 WiFi 接口名(wlan0 等)
|
||||
*/
|
||||
@@ -250,6 +298,7 @@ function getLocalIps() {
|
||||
module.exports = {
|
||||
hasInternet,
|
||||
hasWiredCarrier,
|
||||
getWiredIfaceWithCarrier,
|
||||
hasSavedWifiConnection,
|
||||
isWifiStaConnected,
|
||||
getWifiIface,
|
||||
|
||||
Reference in New Issue
Block a user