feat(svc_perf): network 采集并入 perf 聚合 — 真实 WiFi(wpa_cli/ip) + 蓝牙(hci0/sysfs) + hostname_local, SYSTEM 子集输出, /api/perf 保持轻量 (agent-165)
This commit is contained in:
1 parent
c9a1d0e6af
commit
365cf0f1c0
1 file changed
+125
@@ -312,6 +312,129 @@ static void sys_kernel(char *out, int cap)
|
|||||||
out[rl] = 0;
|
out[rl] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---------------- 网络(wifi/bluetooth/hostname_local,SYSTEM 子集) ----------------
|
||||||
|
* 单一权威源:/api/system、/api/status 的 network 段由 meow_svc_perf 聚合(SYSTEM_FRAMEWORK_SERVICES §4.1)。
|
||||||
|
* 采集只走 popen(wpa_cli/ip/hciconfig) + /sys 只读,带超时防挂;拿不到的真实值回 null/占位,绝不编造。
|
||||||
|
*/
|
||||||
|
/* wifi:解析 wpa_cli status;返回 connected(1/0)。ssid/ip 失败置空串(→ null)。 */
|
||||||
|
static int net_wifi(char *ssid, size_t sscap, char *ip, size_t ipcap)
|
||||||
|
{
|
||||||
|
ssid[0] = 0; ip[0] = 0;
|
||||||
|
int connected = 0;
|
||||||
|
char *o = popen_read_tmo(MEOW_TIMEOUT_MS,
|
||||||
|
"PATH=/bin:/sbin:/usr/bin:/usr/sbin wpa_cli status 2>/dev/null");
|
||||||
|
if (o) {
|
||||||
|
char *ln = o;
|
||||||
|
while (ln && *ln) {
|
||||||
|
char *nl = strchr(ln, '\n');
|
||||||
|
if (nl) *nl = 0;
|
||||||
|
if (!strncmp(ln, "wpa_state=", 10)) { if (!strcmp(ln + 10, "COMPLETED")) connected = 1; }
|
||||||
|
else if (!strncmp(ln, "ssid=", 5)) { snprintf(ssid, sscap, "%s", ln + 5); }
|
||||||
|
if (!nl) break;
|
||||||
|
ln = nl + 1;
|
||||||
|
}
|
||||||
|
free(o);
|
||||||
|
}
|
||||||
|
/* IP:ip -o -4 addr show wlan0 → "2: wlan0 inet 10.78.193.50/24 ...",取含 '.'+'/' 的 token 的 '/' 前段 */
|
||||||
|
char *o2 = popen_read_tmo(MEOW_TIMEOUT_MS,
|
||||||
|
"PATH=/bin:/sbin:/usr/bin:/usr/sbin ip -o -4 addr show wlan0 2>/dev/null");
|
||||||
|
if (o2) {
|
||||||
|
for (char *tk = strtok(o2, " \t"); tk; tk = strtok(NULL, " \t")) {
|
||||||
|
char *dot = strchr(tk, '.'); if (!dot) continue;
|
||||||
|
char *sl = strchr(tk, '/'); if (!sl || sl < dot) continue;
|
||||||
|
size_t len = (size_t)(sl - tk);
|
||||||
|
if (len >= ipcap) len = ipcap - 1;
|
||||||
|
memcpy(ip, tk, len); ip[len] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
free(o2);
|
||||||
|
}
|
||||||
|
return connected;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* bluetooth 段字段(不含外层 {}):available/powered/address/connected/devices。 */
|
||||||
|
static void net_bluetooth_json(sbuf_t *s)
|
||||||
|
{
|
||||||
|
int available = 0;
|
||||||
|
struct stat st;
|
||||||
|
if (stat("/sys/class/bluetooth/hci0", &st) == 0) available = 1;
|
||||||
|
sA(s, "\"available\":%s", available ? "true" : "false");
|
||||||
|
/* address:/sys/class/bluetooth/hci0/address 优先,回退 hciconfig 的 BD Address */
|
||||||
|
char addr[32] = "";
|
||||||
|
if (available) {
|
||||||
|
read_file_txt("/sys/class/bluetooth/hci0/address", addr, sizeof addr);
|
||||||
|
if (!addr[0]) {
|
||||||
|
char *o = popen_read_tmo(MEOW_TIMEOUT_MS,
|
||||||
|
"PATH=/bin:/sbin:/usr/bin:/usr/sbin hciconfig hci0 2>/dev/null");
|
||||||
|
if (o) {
|
||||||
|
char *p = strstr(o, "BD Address:");
|
||||||
|
if (p) {
|
||||||
|
p += 11; /* "BD Address:" 长 11 */
|
||||||
|
while (*p == ' ') p++;
|
||||||
|
int i = 0;
|
||||||
|
while (*p && *p != ' ' && *p != '\n' && i < (int)sizeof addr - 1) addr[i++] = *p++;
|
||||||
|
addr[i] = 0;
|
||||||
|
}
|
||||||
|
free(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sA(s, ",\"address\":");
|
||||||
|
if (addr[0]) sA_str(s, addr); else sA(s, "null");
|
||||||
|
/* powered:/sys/.../power(on/off)优先,文件不可读回退 hciconfig 行首 UP/DOWN */
|
||||||
|
int powered = 0;
|
||||||
|
char pw[8] = "";
|
||||||
|
int pwok = 0;
|
||||||
|
if (available) {
|
||||||
|
pwok = read_file_txt("/sys/class/bluetooth/hci0/power", pw, sizeof pw);
|
||||||
|
if (pwok > 0 && pw[0]) {
|
||||||
|
powered = (!strcmp(pw, "on"));
|
||||||
|
} else {
|
||||||
|
char *o = popen_read_tmo(MEOW_TIMEOUT_MS,
|
||||||
|
"PATH=/bin:/sbin:/usr/bin:/usr/sbin hciconfig hci0 2>/dev/null");
|
||||||
|
if (o) {
|
||||||
|
char *ln = o;
|
||||||
|
while (ln && *ln) {
|
||||||
|
char *nl = strchr(ln, '\n');
|
||||||
|
if (nl) *nl = 0;
|
||||||
|
char *q = ln;
|
||||||
|
while (*q == ' ' || *q == '\t') q++;
|
||||||
|
if (!strncmp(q, "UP", 2)) { powered = 1; break; }
|
||||||
|
if (!strncmp(q, "DOWN", 4)) { powered = 0; break; }
|
||||||
|
if (!nl) break;
|
||||||
|
ln = nl + 1;
|
||||||
|
}
|
||||||
|
free(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sA(s, ",\"powered\":%s", powered ? "true" : "false");
|
||||||
|
/* connected/devices:无配对记录可查(/var/lib/bluetooth 空/未知)→ false/[],不编造 */
|
||||||
|
sA(s, ",\"connected\":false,\"devices\":[]");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* network 完整对象(含外层 {})。hostname 无效(空/"-")时 hostname_local=null。 */
|
||||||
|
static void net_json(sbuf_t *s, const char *hostname)
|
||||||
|
{
|
||||||
|
char ssid[64] = "", ip[64] = "";
|
||||||
|
int wc = net_wifi(ssid, sizeof ssid, ip, sizeof ip);
|
||||||
|
sA(s, "{\"wifi\":{\"connected\":%s", wc ? "true" : "false");
|
||||||
|
sA(s, ",\"ssid\":");
|
||||||
|
if (ssid[0]) sA_str(s, ssid); else sA(s, "null");
|
||||||
|
sA(s, ",\"ip\":");
|
||||||
|
if (ip[0]) sA_str(s, ip); else sA(s, "null");
|
||||||
|
sA(s, ",\"rssi\":null,\"bitrate_mbps\":null},\"bluetooth\":{");
|
||||||
|
net_bluetooth_json(s);
|
||||||
|
sA(s, "},\"hostname_local\":");
|
||||||
|
const char *hn = (hostname && hostname[0] && strcmp(hostname, "-")) ? hostname : NULL;
|
||||||
|
if (!hn) { sA(s, "null"); return; }
|
||||||
|
char hl[96];
|
||||||
|
size_t l = strlen(hn);
|
||||||
|
if (l >= 6 && !strcmp(hn + l - 6, ".local")) snprintf(hl, sizeof hl, "%s", hn);
|
||||||
|
else snprintf(hl, sizeof hl, "%s.local", hn);
|
||||||
|
sA_str(s, hl);
|
||||||
|
}
|
||||||
|
|
||||||
/* ---------------- 聚合 JSON(subset 位掩码;与 MEOWPANEL_PROTOCOL §3.1 .data 对齐) ---------------- */
|
/* ---------------- 聚合 JSON(subset 位掩码;与 MEOWPANEL_PROTOCOL §3.1 .data 对齐) ---------------- */
|
||||||
static int agg_json(int subset, char *out, int cap)
|
static int agg_json(int subset, char *out, int cap)
|
||||||
{
|
{
|
||||||
@@ -369,6 +492,8 @@ static int agg_json(int subset, char *out, int cap)
|
|||||||
sA(&s, ",\"kernel\":"); sA_str(&s, ker);
|
sA(&s, ",\"kernel\":"); sA_str(&s, ker);
|
||||||
sA(&s, ",\"arch\":"); sA_str(&s, arch);
|
sA(&s, ",\"arch\":"); sA_str(&s, arch);
|
||||||
sA(&s, "}");
|
sA(&s, "}");
|
||||||
|
/* network(wifi/bluetooth/hostname_local):SYSTEM 子集,/api/system 与 /api/status 透传 */
|
||||||
|
SEP(); sA(&s, "\"network\":"); net_json(&s, host);
|
||||||
}
|
}
|
||||||
sA(&s, "}"); /* 外层闭合 */
|
sA(&s, "}"); /* 外层闭合 */
|
||||||
#undef SEP
|
#undef SEP
|
||||||
|
|||||||
Reference in new issue
Block a user