refactor(network): unify sysfs carrier reads and LAN vs wired iface logic
This commit is contained in:
118
lib/network.js
118
lib/network.js
@@ -1,17 +1,41 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { execSync } = require('child_process');
|
const { execSync } = 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');
|
||||||
|
|
||||||
const AP_SSID_PREFIX = 'ClawBox-';
|
const AP_SSID_PREFIX = 'ClawBox-';
|
||||||
const AP_IP = '10.42.0.1';
|
const AP_IP = '10.42.0.1';
|
||||||
const AP_PASSWORD = '12345678';
|
const AP_PASSWORD = '12345678';
|
||||||
const AP_IFACE = process.env.CLAWD_WIFI_IFACE || '';
|
const AP_IFACE = process.env.CLAWD_WIFI_IFACE || '';
|
||||||
const CON_NAME = 'clawd-hotspot';
|
const CON_NAME = 'clawd-hotspot';
|
||||||
|
|
||||||
/** 非 WiFi、非典型虚拟接口,用于自动发现有线口(如 end0、enp*,而非仅 eth0) */
|
/** 产品 RJ45 在 sysfs 中的默认名;等价于检测 `cat /sys/class/net/end0/carrier` */
|
||||||
|
const DEFAULT_ETH_IFACE = 'end0';
|
||||||
|
|
||||||
|
function _ethIfaceEnvOrDefault() {
|
||||||
|
return process.env.CLAWD_ETH_IFACE || DEFAULT_ETH_IFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _netIfaceExists(name) {
|
||||||
|
try {
|
||||||
|
return fs.existsSync(`/sys/class/net/${name}`);
|
||||||
|
} catch (_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 读取 `/sys/class/net/<iface>/carrier`,`1` 为链路 up;缺失或异常视为 down */
|
||||||
|
function _sysfsCarrierUp(iface) {
|
||||||
|
try {
|
||||||
|
return fs.readFileSync(`/sys/class/net/${iface}/carrier`, 'utf8').trim() === '1';
|
||||||
|
} catch (_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 非 WiFi、非典型虚拟接口,用于开发机扫描有线口(enp* 等) */
|
||||||
function _isExcludedVirtualIface(name) {
|
function _isExcludedVirtualIface(name) {
|
||||||
if (name === 'lo' || name === 'bonding_masters') return true;
|
if (name === 'lo' || name === 'bonding_masters') return true;
|
||||||
if (name.startsWith('wl')) return true;
|
if (name.startsWith('wl')) return true;
|
||||||
@@ -26,85 +50,45 @@ function _isExcludedVirtualIface(name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回当前链路 up 的有线网卡名。
|
* 开发机:无 CLAWD_ETH_IFACE 且无 end0 时,扫描 sysfs 找第一个 carrier=1 的有线口。
|
||||||
* 若设置 CLAWD_ETH_IFACE,只认该接口;否则扫描 sysfs(与仅默认 eth0 相比适配更多板型)。
|
|
||||||
*/
|
*/
|
||||||
function getWiredIfaceWithCarrier() {
|
function _firstScanWiredIfaceWithCarrier() {
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const names = fs.readdirSync('/sys/class/net');
|
const names = fs.readdirSync('/sys/class/net');
|
||||||
for (const name of names.sort()) {
|
for (const name of names.sort()) {
|
||||||
if (_isExcludedVirtualIface(name)) continue;
|
if (_isExcludedVirtualIface(name)) continue;
|
||||||
try {
|
if (_sysfsCarrierUp(name)) return name;
|
||||||
if (fs.readFileSync(`/sys/class/net/${name}/carrier`, 'utf8').trim() === '1') {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
} catch (_) {}
|
|
||||||
}
|
}
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否存在任一带 carrier 的有线接口(无延迟)
|
* 返回当前可用于「有线 ping / 路由」的网卡名。
|
||||||
|
* 优先级:CLAWD_ETH_IFACE → 存在 end0 则只用 end0 → 否则扫描 sysfs。
|
||||||
*/
|
*/
|
||||||
|
function getWiredIfaceWithCarrier() {
|
||||||
|
const explicit = process.env.CLAWD_ETH_IFACE;
|
||||||
|
if (explicit) {
|
||||||
|
return _netIfaceExists(explicit) && _sysfsCarrierUp(explicit) ? explicit : null;
|
||||||
|
}
|
||||||
|
if (_netIfaceExists(DEFAULT_ETH_IFACE)) {
|
||||||
|
return _sysfsCarrierUp(DEFAULT_ETH_IFACE) ? DEFAULT_ETH_IFACE : null;
|
||||||
|
}
|
||||||
|
return _firstScanWiredIfaceWithCarrier();
|
||||||
|
}
|
||||||
|
|
||||||
function hasWiredCarrier() {
|
function hasWiredCarrier() {
|
||||||
return getWiredIfaceWithCarrier() !== null;
|
return getWiredIfaceWithCarrier() !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 物理链路是否 up:carrier + operstate 双读,避免单读 carrier 拔线不更新、或与 WiFi 状态不同步的误判。
|
* LAN 面板灯:只反映 RJ45 对应口,与 `cat /sys/class/net/end0/carrier 2>/dev/null` 同源(仅读 carrier)。
|
||||||
*/
|
* 若配置的接口在 sysfs 中不存在(常见为开发机无 end0),则退回与 hasWiredCarrier() 一致,避免灯永远灭。
|
||||||
function _ifacePhysicalLinkUp(iface) {
|
|
||||||
try {
|
|
||||||
const base = `/sys/class/net/${iface}`;
|
|
||||||
const carrier = fs.readFileSync(`${base}/carrier`, 'utf8').trim();
|
|
||||||
if (carrier !== '1') return false;
|
|
||||||
let oper = 'unknown';
|
|
||||||
try {
|
|
||||||
oper = fs.readFileSync(`${base}/operstate`, 'utf8').trim();
|
|
||||||
} catch (_) {}
|
|
||||||
if (oper === 'down' || oper === 'lowerlayerdown') return false;
|
|
||||||
return true;
|
|
||||||
} catch (_) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* LAN 面板灯:只反映指定/板载以太网 RJ45 链路,与 WiFi 无关。
|
|
||||||
* - CLAWD_ETH_IFACE:只读该口
|
|
||||||
* - 否则只认 end0、eth0(存在则仅用其 sysfs,链路 down 即灭,不再退回「任一带 carrier 口」以免跟 WiFi 耦合)
|
|
||||||
* - 无 end0/eth0 节点时(开发机)退回 hasWiredCarrier()
|
|
||||||
*/
|
*/
|
||||||
function hasLanCableCarrier() {
|
function hasLanCableCarrier() {
|
||||||
const explicit = process.env.CLAWD_ETH_IFACE;
|
const iface = _ethIfaceEnvOrDefault();
|
||||||
if (explicit) {
|
if (_netIfaceExists(iface)) return _sysfsCarrierUp(iface);
|
||||||
try {
|
|
||||||
return fs.existsSync(`/sys/class/net/${explicit}`) && _ifacePhysicalLinkUp(explicit);
|
|
||||||
} catch (_) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let hasBoardIface = false;
|
|
||||||
for (const n of ['end0', 'eth0']) {
|
|
||||||
if (!fs.existsSync(`/sys/class/net/${n}`)) continue;
|
|
||||||
hasBoardIface = true;
|
|
||||||
if (_ifacePhysicalLinkUp(n)) return true;
|
|
||||||
}
|
|
||||||
if (hasBoardIface) return false;
|
|
||||||
|
|
||||||
return hasWiredCarrier();
|
return hasWiredCarrier();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user