refactor(panel): 前后端按模块拆分+屏幕/控制合并页 — 后端meowpanel.c 6372行拆src/*.c+mp.h(235函数原型,20端点output byte-identical,0warning)+前端拆mp_shared/mp_pages/meowpanel三层;屏幕·遥控合并(左屏实时画面+右MD3 SVG矢量按钮无emoji);重编后热更TF卡

This commit is contained in:
AskaEth committed 2026-09-04 00:56:13 +08:00
1 parent f3ae06d7cd
commit 2dc4cad454
26 files changed
+9317 -2755

No files matched your search

+192
View File
@@ -0,0 +1,192 @@
/* mp_perf.c — 性能/系统域:/api/perf,/api/system,action,pin-unlock(经 meow_svc_perf IPC 聚合)。 */
#include "mp.h"
int api_perf(int sock, const char *path)
{
char json[4096];
int rc = ipc_perf_query(perf_subset_for_path(path), json, sizeof json);
if (rc != MEOW_OK || !utf8_valid_n(json, strlen(json))) /* 上游坏字节 → 不返回,降级 */
return send_err(sock, 500, "INTERNAL", "性能服务不可用(IPC 连接/应答失败)");
return send_json(sock, 200, json);
}
int perf_extract_network(const char *json, char *out, int cap)
{
const char *p = json;
for (;;) {
p = strstr(p, "\"network\"");
if (!p) return -1;
const char *q = p + 9; /* strlen("\"network\"") */
while (*q == ' ' || *q == '\t') q++;
if (*q == ':') { p = q + 1; break; } /* 顶层 network 键 */
p += 9; /* 嵌套同名键跳过 */
}
while (*p == ' ' || *p == '\t') p++;
if (*p != '{') return -1;
int depth = 0, in_str = 0, esc = 0;
const char *q;
for (q = p; *q; q++) {
char ch = *q;
if (in_str) {
if (esc) esc = 0;
else if (ch == '\\') esc = 1;
else if (ch == '"') in_str = 0;
continue;
}
if (ch == '"') { in_str = 1; continue; }
if (ch == '{') depth++;
else if (ch == '}') { depth--; if (depth == 0) { q++; break; } }
}
if (depth != 0) return -1;
size_t len = (size_t)(q - p);
if (len == 0) return -1;
if (len >= (size_t)cap) len = (size_t)cap - 1;
memcpy(out, p, len); out[len] = 0;
return 0;
}
int api_system(int sock)
{
char json[4096];
int rc = ipc_perf_query(0, json, sizeof json);
if (rc != MEOW_OK) return send_err(sock, 500, "INTERNAL", "性能服务不可用(IPC 连接/应答失败)");
jv_t *root = jv_parse(json, (int)strlen(json));
if (!root) return send_err(sock, 500, "INTERNAL", "性能服务 JSON 解析失败");
jv_t *jsys = jv_obj_get(root, "system");
jv_t *jupt = jv_obj_get(root, "uptime_sec");
jv_t *jst = jv_obj_get(root, "storage");
jv_t *jtf = jv_obj_get(root, "tfcard");
const char *ver = "-", *host = "-", *ker = "-", *arch = "-";
if (jsys && jsys->type == J_OBJ) {
jv_t *v = jv_obj_get(jsys, "version"); if (v && v->type == J_STR) ver = v->str;
v = jv_obj_get(jsys, "hostname"); if (v && v->type == J_STR) host = v->str;
v = jv_obj_get(jsys, "kernel"); if (v && v->type == J_STR) ker = v->str;
v = jv_obj_get(jsys, "arch"); if (v && v->type == J_STR) arch = v->str;
}
long long upt = jupt ? (long long)jupt->dnum : 0;
/* boot default:读权威 /data/meow_boot_default(0=meow 默认, 1=hiby),失败回退 meow */
int bdf = -1;
{
char b[16];
FILE *f = fopen(BOOT_DEFAULT_FILE, "r");
if (f) { if (fgets(b, sizeof b, f)) bdf = atoi(b); fclose(f); }
}
const char *bootname = bdf < 0 ? "meow" : (bdf ? "hiby" : "meow");
/* 当前运行模式:读 /tmp/meow_boot_mode(meow/hiby),缺失回退 default(PANEL_ENHANCE_PLAN 批1 前端读 boot.mode) */
char modebuf[16] = {0};
{
FILE *f = fopen("/tmp/meow_boot_mode", "r");
if (f) {
if (fgets(modebuf, sizeof modebuf, f)) {
char *p = modebuf;
while (*p) { if (*p == '\n' || *p == '\r' || *p == ' ') { *p = 0; break; } p++; }
}
fclose(f);
}
}
const char *bootmode = (modebuf[0] == 'm' || modebuf[0] == 'h') ? modebuf : bootname;
char host_local[80];
snprintf(host_local, sizeof host_local, "%s.local", host);
sbuf_t s = {0};
sA(&s, "{\"version\":");
sA_str(&s, ver);
sA(&s, ",\"hostname\":");
sA_str(&s, host);
sA(&s, ",\"kernel\":");
sA_str(&s, ker);
sA(&s, ",\"arch\":");
sA_str(&s, arch);
sA(&s, ",\"uptime_sec\":%lld,\"boot\":{\"default\":", upt);
sA_str(&s, bootname);
sA(&s, ",\"mode\":");
sA_str(&s, bootmode);
sA(&s, "},\"network\":");
char netbuf[1024];
/* 透传 perf 权威 network 段(wifi/bluetooth/hostname_local);含非法 UTF-8(如坏 ssid)→ 回退,不嵌坏字节 */
if (perf_extract_network(json, netbuf, sizeof netbuf) == 0 && utf8_valid_n(netbuf, strlen(netbuf))) {
sA(&s, "%s", netbuf);
} else {
/* 回退:perf 未含 network 段 → 仅 hostname_local(保持原语义,不崩) */
sA(&s, "{\"hostname_local\":");
sA_str(&s, host_local);
sA(&s, "}");
}
sA(&s, ",\"storage\":{");
if (jst && jst->type == J_OBJ) {
jv_t *t = jv_obj_get(jst, "total"); long long tot = t ? (long long)t->dnum : 0;
jv_t *u = jv_obj_get(jst, "used"); long long usd = u ? (long long)u->dnum : 0;
jv_t *a = jv_obj_get(jst, "avail"); long long ava = a ? (long long)a->dnum : 0;
sA(&s, "\"root\":{\"total\":%lld,\"used\":%lld,\"avail\":%lld}", tot, usd, ava);
} else {
sA(&s, "\"root\":{\"total\":0,\"used\":0,\"avail\":0}");
}
sA(&s, ",\"tfcard\":{");
if (jtf && jtf->type == J_OBJ) {
jv_t *pr = jv_obj_get(jtf, "present"); int present = pr && pr->bval;
long long tot = 0, usd = 0, ava = 0;
jv_t *t = jv_obj_get(jtf, "total"); if (t) tot = (long long)t->dnum;
jv_t *u = jv_obj_get(jtf, "used"); if (u) usd = (long long)u->dnum;
jv_t *a = jv_obj_get(jtf, "avail"); if (a) ava = (long long)a->dnum;
sA(&s, "\"present\":%s,\"total\":%lld,\"used\":%lld,\"avail\":%lld}", present ? "true" : "false", tot, usd, ava);
} else {
sA(&s, "\"present\":false,\"total\":0,\"used\":0,\"avail\":0}");
}
sA(&s, "},\"ota\":{\"current\":");
sA_str(&s, ver);
sA(&s, ",\"latest\":");
sA_str(&s, ver);
sA(&s, ",\"available\":false,\"url\":null}");
/* 重启原因 / 升级状态:svc_power 读级查询(POWER_REBOOT_REASON(8)/POWER_UPGRADE_STATUS(9),只读、
* 任意调用者)。st.msg 分别为 "coldboot=reboot|shutdown|unknown" 与 "upgrade=yes|no"。
* 前端批1-B 已留位(读 d.reboot_reason / d.upgrade_status),此处点亮。查询失败保持空串(不谎报)。 */
char rreason[48] = "", ustatus[32] = "";
{
m_power_status_t st;
memset(&st, 0, sizeof st);
if (ipc_power_action(POWER_REBOOT_REASON, 0, NULL, &st) == MEOW_OK)
svc_msg_kv(st.msg, "coldboot", rreason, sizeof rreason);
memset(&st, 0, sizeof st);
if (ipc_power_action(POWER_UPGRADE_STATUS, 0, NULL, &st) == MEOW_OK)
svc_msg_kv(st.msg, "upgrade", ustatus, sizeof ustatus);
}
sA(&s, ",\"reboot_reason\":");
sA_str(&s, rreason);
sA(&s, ",\"upgrade_status\":");
sA_str(&s, ustatus);
sA(&s, "}");
jv_free(root);
int ret = send_json(sock, 200, s.b ? s.b : "");
sbuf_free(&s);
return ret;
}
int api_pin_unlock_once(int sock)
{
const char *path = "/tmp/meow_pin_unlock_once";
FILE *f = fopen(path, "w");
if (!f) return send_err(sock, 500, "INTERNAL", "无法写入一次性解锁标志");
fputs("1\n", f);
fclose(f);
return send_json(sock, 200, "{\"unlock_once\":true}");
}
int api_system_action(int sock, const char *which, const req_t *r)
{
(void)r;
uint32_t cmd;
if (!strcmp(which, "reboot")) cmd = POWER_REBOOT;
else if (!strcmp(which, "shutdown")) cmd = POWER_SHUTDOWN;
else if (!strcmp(which, "ota")) cmd = POWER_UPGRADE;
else return send_err(sock, 404, "NOT_FOUND", "未知系统动作");
m_power_status_t st;
memset(&st, 0, sizeof st);
int rc = ipc_power_action(cmd, 0, NULL, &st);
if (rc == MEOW_OK) return send_json(sock, 200, "{\"accepted\":true}");
/* 系统动作类服务端通常「先应答受理再执行」;此处若返回非 OK 则说明服务未受理 */
const char *why = st.msg[0] ? st.msg : power_code_str(rc);
if (rc == MEOW_ERR_PERM) return send_err(sock, 403, "FORBIDDEN", "电源服务拒绝(非 root 调用)");
if (rc == MEOW_ERR_NODEV) return send_err(sock, 503, "NO_CARD", "升级文件缺失或服务不可达");
if (rc == MEOW_ERR_NOENT || rc == MEOW_ERR_IO) return send_err(sock, 503, "NO_CARD", why);
return send_err(sock, 500, "INTERNAL", why);
}