# MeowPanel 后端(`meowpanel.c`) MeowOS(HiBy R3 Pro II 第三方系统,MIPS32 静态交叉编译)的**外置 Web 面板后端**:单进程、零第三方依赖的 C 静态二进制,内嵌 HTTP/JSON 服务器 + 前端静态托管 + 框架专项服务 IPC 客户端 + `settings.conf` 设置镜像。 - **定位**(`MEOWPANEL_DESIGN.md`):外置于 TF 卡 `MeowOS/opt/MeowPanel/` 的系统组件,由 `meow_svcd` 读 TF 卡 `MeowOS/services.d/meowpanel.conf` 启动、`meow_sysui` 监管。**不进固件**;无卡时系统核心 (launcher/sdk/设置/通知)绝不依赖它。 - **协议**:`devdocs/plan/MEOWPANEL_PROTOCOL.md`(HTTP/JSON 端点;本实现以「实现为准,协议/README 记录出入」)。 - **数据路径**(`SYSTEM_FRAMEWORK_SERVICES.md §2/§4`):读侧(`/api/{status,perf,system}`)经 `meow_svc_perf` IPC(`MSG_PERF_QUERY→RESULT`)聚合,**绝不各自爬 /proc**(M2.73 起 perf 聚合含 `network` 段);动作侧(`/api/system/{reboot,shutdown,ota}`)经 `meow_svc_power` IPC(`MSG_POWER_ACTION→STATUS`),不再直连 `poweroff`/写 mtd5。两专项服务为**板载 svcd 托管** (`trigger=boot`),拔卡保留,与无卡依赖最小化自洽。 - **⚠️ OTA 检查升级 ≠ 升级**:前端「检查升级」只读 `GET /api/system` 的 `ota{current,available,latest}`,**勿 `POST /api/system/ota`**(那是触发升级进升级模式)。 --- ## 1. 编译 工具链:交叉编译器 `/home/Aska/Project/R3ProII/.tools/zig-mipsel-cc`(mipsel 32 位、musl 静态,可用)。 ```bash cd /home/Aska/Project/R3ProII/patch_v2/meowpanel ./build_meowpanel.sh # 交叉编译 → meowpanel(mipsel 静态,firmware-ready) ./build_meowpanel.sh host # 宿主编译 → meowpanel_host(本机 ld,仅供调试) ``` - 两分支均以 `-Os -Wall -Wextra` 复核,**0 warning**。 - 产出(本次构建实测): - `meowpanel`:mipsel 静态,`ELF 32-bit LSB executable, MIPS, MIPS32 rel2, statically linked, stripped`, 体积约 **166 KB**(固件阈值内)。md5:`11ed76ecb2e1c5773a01f0fb056a2df5`。 - `meowpanel_host`:aarch64 动态链接(宿主编译,仅供调试),体积约 **77 KB**。 - 依赖:仅 libc + Linux 内核头(`linux/input.h`),零第三方库(设备无 python3/lua)。 - 头文件引用:`-I patch_v2/meow_launcherd`(`meow_ipc.h` 帧格式 / `m_perf_*`/`m_power_*`/`POWER_*`, **header 为权威源**,结构体字段以它为准)。 ## 2. 部署到 TF 卡 ```bash # 1) 后端 + 前端(web/index.html + meowpanel.css + meowpanel.js)放在同一目录 sudo mkdir -p /usr/data/mnt/sd_0/MeowOS/opt/MeowPanel sudo cp patch_v2/meowpanel/meowpanel /usr/data/mnt/sd_0/MeowOS/opt/MeowPanel/ sudo cp patch_v2/meowpanel/web/index.html /usr/data/mnt/sd_0/MeowOS/opt/MeowPanel/ sudo cp patch_v2/meowpanel/web/meowpanel.css /usr/data/mnt/sd_0/MeowOS/opt/MeowPanel/ sudo cp patch_v2/meowpanel/web/meowpanel.js /usr/data/mnt/sd_0/MeowOS/opt/MeowPanel/ # 2) 服务配置(svcd 读 TF 卡 services.d 拉起) sudo mkdir -p /usr/data/mnt/sd_0/MeowOS/services.d sudo cp patch_v2/meowpanel/services.d/meowpanel.conf /usr/data/mnt/sd_0/MeowOS/services.d/ ``` 说明: - 前端资源与后端**同目录**(后端 `GET /` → `index.html`,`GET /meowpanel.css`/`meowpanel.js` 同目录取)。 后端也支持 `GET /assets/`(映射到同目录文件),前端当前用根相对路径。 - 服务启动后整卡由 `meow_svcd` 按 `trigger=boot` 拉起;`meow_sysui` 监管(restart/backoff/max_restart)。 - **无卡**:`MeowOS/services.d/` 不可读 → svcd 跳过本服务;系统核心照常。 ## 3. 访问 浏览器(同局域网): ``` http://.local:8080/ ``` - mDNS 由板载 `meow_mdns` 应答 `.local`。 - 端口默认 **8080**,可用 `-p PORT` / 环境变量 `MEOWPORT` / 与后端同目录 `meowpanel.conf`(`port=N`)覆盖。 (优先级:`-p` > `MEOWPORT` > `meowpanel.conf` > 默认 8080。) - 无鉴权(设备内网信任模型;token 鉴权为 MEOWPANEL_PROTOCOL §1.3 草案项,未实现)。 --- ## 4. 端点实现清单(对照 MEOWPANEL_PROTOCOL §2 端点总览) ### 已实现(返回 200/2xx 或语义错误码) | 方法 | 路径 | 说明 | 实现 | |---|---|---|---| | GET | `/`、`/meowpanel.css`、`/meowpanel.js`、`/assets/` | 静态托管 | ✅ | | GET | `/api/status` | 性能+系统(`meow_svc_perf` IPC subset=all 透传) | ✅ | | GET | `/api/perf` | 仅性能(subset=perf 透传) | ✅ | | GET | `/api/system` | perf IPC + boot/network/ota 局部补全(network 含蓝牙,无网口;`ota` 只读检查,勿误触升级) | ✅ | | POST | `/api/system/reboot`、`/shutdown`、`/ota` | `meow_svc_power` IPC | ✅ | | GET | `/api/settings` | 全量+元数据(items/count/groups) | ✅ | | GET | `/api/settings/:key` | 单项 | ✅ | | PUT | `/api/settings/:key` | 写单项(clamp/枚举校验) | ✅(越界/非法枚举→422) | | POST | `/api/settings` | 批量写 | ✅ | | POST | `/api/settings/restore` | 恢复默认 | ✅ | | GET | `/api/theme` | 读主题 | ✅ | | PUT | `/api/theme` | 写主题(style/theme/background 子集) | ✅(非法→422) | | GET | `/api/files?path=` | 目录列表(白名单) | ✅(无卡→503) | | GET | `/api/files/read?path=` | 读文本(<1MB;二进制→415) | ✅ | | GET | `/api/files/download?path=` | 下载流 | ✅ | | POST | `/api/files/upload` | multipart 上传 | ✅ | | POST | `/api/files/mkdir` | 新建目录(已存在→409) | ✅ | | POST | `/api/files/rename` | 重命名 | ✅ | | DELETE | `/api/files?path=` | 删除(可 recursive=1;非空未 recursive→409) | ✅ | | GET | `/api/apps` | 扫描 `MeowAPPs/` 读 `app.json` | ✅ | | GET | `/api/apps/:pkg` | 应用详情 | ✅ | | POST | `/api/apps/install` | 经 `nyai install`(multipart 或 path) | ✅ | | GET | `/api/apps/:pkg/export` | `nyai export` 下载流 | ✅ | | DELETE | `/api/apps/:pkg` | `nyai remove [--purge]` | ✅ | | POST | `/api/key/:code` | 按键注入(tap/long) | ✅(物理键红线内) | | POST | `/api/key` | 批量/顺序注入 | ✅ | | GET | `/api/logs` | `MeowOS/logs` 文件列表 | ✅(无卡→503) | | GET | `/api/logs/read?file=&lines=` | 读日志(上限 1000 行;`..`/绝对→403;敏感名→403) | ✅ | | GET | `/api/notifications` | 通知列表(读 TF 转储日志;见 §5.8) | ✅(无源→空态 `source:none`,不 503) | | DELETE | `/api/notifications/:id` | 单条删除(重写日志移除该 id) | ✅(不存在→404) | | POST | `/api/notifications/dismiss_all`(别名 `/api/notifications/clear`) | 一键清空:**保留活动中的媒体/进度通知**,移除其余 | ✅ | | GET | `/api/files/read?path=` | 读文本:预览上限 1MB,超限 `truncated:true`(不再 404);二进制→415 | ✅ | ### 返回 501 `NOT_IMPLEMENTED` 的端点(诚实标注) | 端点 | 原因 | |---|---| | `/api/key/:code` 的 `press:"hold"` | `hold` 需常驻持续注入通道(阶段 D),后端未实现;`tap`/`long` 已实现。 | | OTA 升级模式(`/api/system/ota` 带 `url`) | 升级为草案(MEOWPANEL_PROTOCOL §6 待定案);当前 `POST /api/system/ota` 空 body 触发 `meow_svc_power` 的 `POWER_UPGRADE`(写 mtd5 进升级模式),带 `url` 的下载+升级未实现。 | > 通知端点已从 501 落地为「读 TF 卡通知转储日志」实现。因 launcher 侧 **`MSG_NOTIFY_LIST` 为下行推送(守护→App), > 无「客户端查询通知清单」请求类型**(launcher `util.c` `case MSG_NOTIFY_LIST: "not dispatched here"`),后端(svcd 独立进程) > 无法经 IPC 取活跃清单,故回退到 TF 转储文件。详见 §5.8 与输出「需 launcher 侧配合项」。 > 前端对 `501` 显示「该功能后端尚未实现」(`ok:false,error.code=NOT_IMPLEMENTED`)。 --- ## 5. 关键实现说明 ### 5.1 HTTP 路由 / JSON 序列化 - **单线程 + poll 串行**(面板访问量极小)。`accept` → `read_request`(先读头到 `\r\n\r\n`,**在缓冲区内搜索**头边界, 处理「头+body 同段到达」,再按 `Content-Length` 精确读 body)→ `handle` → 写响应 → 关闭连接(`Connection: close`)。 - 读/写均有 `poll` 超时(读头部 5s、body 分段 5s,IPC 2s)。`SIGPIPE` 忽略。 - JSON 响应信封:成功 `{"ok":true,"data":}`;失败 `{"ok":false,"error":{"code","message"}}` (MEOWPANEL_PROTOCOL §1.1/§1.2,HTTP 状态码映射照抄)。 - **无 JSON 库**:手写最小递归下降解析器(对象/数组/字符串转义/数字/bool/null),仅覆盖实际用到的收发。 - 下载/上传用流式(`multipart/form-data` 极简解析:按 boundary 切,取 `path`+`file` 字段)。 ### 5.2 IPC 对接(meow_svc_perf / meow_svc_power) - **帧**:复用 `meow_ipc.h`——16B 头(magic `0x4D4F5701`/version 1/type/req_id/len,全小端)+ 变长负载, `MEOW_IPC_MAX=4096`。帧读写 `x_read_full`/`x_write_full` + `send_frame`/`recv_frame`(与 meow_svc_perf.c 对称)。 - **握手**:连接后先 `MSG_HELLO`(`app_id="os.meow.panel"`,系统面板身份,§5 二期拟名)→ 读 `MSG_ACK(code=0)`。 - **读侧**:`MSG_PERF_QUERY`(`m_perf_query_t.subset`)→ `MSG_PERF_RESULT`(`m_perf_result_t`,`code`/`json_len`/`json`), **直接透传**服务端聚合 JSON(`/api/status`=全部、`/api/perf`=perf 子集、`/api/system`=全量取 uptime/storage/tfcard/system)。 读取防溢出:`json_len` 以 `sizeof(m_perf_result_t.json)-1` 与 `cap` 双钳位。 - **动作侧**:`MSG_POWER_ACTION`(`m_power_action_t.cmd=POWER_REBOOT/SHUTDOWN/UPGRADE`)→ `MSG_POWER_STATUS`(`code`/`msg`)。 收到 `MEOW_OK` → `{"accepted":true}`;否则按 `code`(PERM→403 / NOENT/IO→503 / 其余→500)返回错误信封。 - **失败语义**:socket 不存在/连接拒/超时/应答非 OK → 返回 500 `INTERNAL`(或 503 `NO_CARD` 当缺升级文件) 并带中文 message。**绝不静默失败、绝不降级直连 /proc 或 poweroff**(单一权威源)。 - 连接超时:非阻塞 connect + `poll(POLLOUT)` 2s,`SO_RCVTIMEO`/`SO_SNDTIMEO` 兜底。 ### 5.3 设置镜像(读写板载 `settings.conf`) - **不旁路**:只经 `settings_get_value`(`=` 切分 + key 去首尾空白精确匹配,防 `audio.volume` 误配 `audio.volume_max`, 照 `meow_ui_vol_read`/`meow_svc_power settings_get_int_trim` 同款解析)与 `settings_write_one`(`"key = value\n"`, 保留 `# meow-settings 1` 头、逐行重写、缺键追加;目录缺失自动 `mkdir`)。**不绕过此函数直接改文件**。 - **键表/默认值来源**:`patch_v2/meow_launcherd/meow_settings.c` 的 `g_defs[]`(**权威来源**,逐键一致), 含 type/def/min/max/enum_names/enum_labels;`GET /api/settings` 返回 `items/count/groups`(分组按键前缀, 如 `display.*`→显示、`font.*|ui.*`→字体主题…)。 - 类型:`int`→number(带 min/max/def 字符串)、`bool`→原生布尔、`enum`→`options(name/label)+default_name+def`、 `str`→string。**越界/非法枚举 → 422 `UNSUPPORTED`**。 - 语义 clamp:`display.brightness` 读/写都 clamp 到 `[display.brightness_min(默认1), 100]`(防 101 闪屏, 与 `meow_settings_brightness_clamped`/`clamp_brightness` 同口径);`boot.default` 写后同步 `/data/meow_boot_default` (meow→0/hiby→1,同 `meow_settings_save`)。 - 注:后端为独立进程,无法调用 launcher 进程内的 `meow_settings_*`(那是其内存表),故**直接镜像同一份 `settings.conf`**,保持与实体设置页/CLI 同一存储契约(协议 §3.2 说「经 meow_settings_*」,此处以 「镜像同一文件 + 同款 parse/save 契约」落地,见 §8 出入记录)。 ### 5.4 文件白名单 - 根 `/usr/data/mnt/sd_0`;白名单子目录 `MeowOS/Music/MeowData/MeowAPPs/book`(`allowed` 数组)。 - 路径经 `normalize_path` 规范化(去 `.`/`..`,拒绝逃逸出根)后 `path_in_whitelist` 校验(== 根或属于某一白名单 一级子目录)。**`..`/绝对路径逃逸 → 403 `FORBIDDEN`**;无卡 → 503 `NO_CARD`。 - 读取拒绝敏感名(`settings.conf`/`setting.bak`/`.env`/`passwd`/`shadow`/`meow.conf`/`user.ini`/`config.json`)。 - 列表/上传/下载/读文本(1MB+二进制→415)/mkdir(已存在→409)/rename(new_name 不含 `/`)/delete(递归,非空未 recursive→409)。 ### 5.5 nyai 对接 - 包管理器 CLI 绝对路径 `/usr/data/mnt/sd_0/MeowOS/opt/bin/nyai`(M2.12+ 固件经 `meow_card_path.sh` 前插 PATH,可直接调; 本后端用绝对路径,兼容更早固件)。包名 = `app.json` 的 `package` = `.mpk` 文件名茎。 - `install`:multipart 上传 `.mpk` 落临时文件(`MeowOS/tmp/`)或 JSON `{path}` → `nyai install `;用 `popen` 捕获输出+退出码, 非 0 → 422。`export`:`nyai export ` → 以 `Content-Disposition: attachment` 流式下发。`remove`:`nyai remove [--purge]`。 - `GET /api/apps` / `:pkg` 详情:直接扫描 `MeowAPPs//app.json`(手写 JSON 解析提取 name/version/exec/framework/immersive/fullscreen), 不依赖 nyai(nyai 未部署时列表/详情仍可用)。解析失败项 `invalid:true`。 - `nyai` 未部署 → install/export/remove 返回 500(带 nyai 输出)。 ### 5.6 按键注入通道 - **复用现有先例**:`patch_v2/uinput_tap/uinput_tap.c` 的 `write`-到-evdev 注入机制。launcher 实际轮询 `meow_launcher_internal.h`:`/dev/input/event0`(md-gpio-keys: POWER/PREVIOUS)、`/dev/input/event2` (jz adc keyboard: VOL/PLAY/NEXT)。后端 open `O_WRONLY` 写 `EV_KEY press/release + SYN_REPORT` 即可到达 launcher 按键处理。 - **物理键红线**(APPS.md / 任务约束):只注入音量(114/115)/电源(116)/播放(164)/上下曲(163/165); **禁止注入 返回(158)/主页(172)/确认(28)/退出(96)** → 403 `FORBIDDEN`。 - `tap`(默认,抬起间隔 80ms)、`long`(按住 ms,缺省 3000);`hold` → 501。 - 局限:若 `/dev/input/event0/event2` 在设备上不可写(权限/路径差异),注入失败 → 500;注入为**即时性注入**, 不在 launcher 内维护长按状态机(与实体按键的 `longpressed` 语义近似,见 README 已知边界)。 ### 5.7 日志 - `GET /api/logs`:`MeowOS/logs` 下常规文件列表(跳过敏感名)。 - `GET /api/logs/read?file=&lines=`:`file` 必须相对 `MeowOS/logs/`,**禁 `..`/绝对路径 → 403**,敏感名 → 403; 缺省 `lines=200`,上限 `1000`;返回 `{file,lines[],total,truncated}`。 ### 5.8 通知(数据源 = TF 卡通知转储日志) - **数据源优先级**:① launcher IPC 查询 →② TF 转储文件 →③ 空态。当前 ① 不可用(launcher 侧 `MSG_NOTIFY_LIST` 仅下行推送、 无客户端查询请求类型,见「需 launcher 侧配合项」),故以 ② 为准。 - **TF 转储文件**:`<卡根>/MeowOS/notifications/notifications.log`(launcher `meow_notif_dump_tf` 一行一条 CSV, 字段 `timestamp,id,app_id,app_icon,category,urgency,progress,title,body,target_activity,ongoing,media,dismissed`; `meow_notif_clear_tf` 开机清空 → 会话级归档)。后端逐行流式读取(环形保留最新 `NOTIF_PREVIEW_MAX=200` 条,不全量进内存)。 - **`GET /api/notifications`**:返回 `{count, items:[...], notifications:[...], source}`;`items`= `notifications` 别名 (兼容前端读 `.notifications` 与任务约定空态 `items:[]`)。字段含 `id/app_id/app_name/app_icon/category/summary/body/ urgency/ts/progress/ongoing/media/target_activity/dismissed`。`progress<0`→`null`;`app_name` 对 `system`→`系统`,其余用 `app_id` 兜底。 无源(无卡/文件不存在)→ `{count:0,items:[],notifications:[],source:"none"}`(**不 503、不伪造数据**)。 - **`DELETE /api/notifications/:id`**:从日志移除该行(重写临时文件后 rename)。不存在 → 404。 - **`POST /api/notifications/dismiss_all`(别名 `/api/notifications/clear`)**:重写日志,**只保留活动中的媒体/进度通知** (`ongoing||media||progress>=0||category=="media"`),移除其余;返回 `{dismissed:<移除数>}`。 - **语义边界**:日志是**归档快照**(归档时 `dismissed` 尚未置 1,故该列恒 ≈0 不可靠),非活跃快照;且面板清空只改 日志视图,**不联动 launcher 进程内存**(launcher 通知中心仍显示其内存活跃集)。无 launcher 查询/清撤 IPC 前的诚实降级。 - **并发**:面板清空/删除用「写临时 + rename」重写日志;launcher 侧仍以 `O_APPEND` 追加,二者为竞写(低并发、会话级日志, 可接受),已写入「已知边界」(§7)。 --- ## 6. 与协议的出入(「实现为准 + 原因」,供回改 MEOWPANEL_PROTOCOL.md) 1. **`ui.style` 值域**:`meow_settings.c g_defs` 源码为 `"md3,miui"`(label "Material You,MIUI"),但 SYSTEM_SETTINGS.md 定案 + MEOWPANEL_PROTOCOL §5 一致行为 **`miuix`**(对应 `MEOW_STYLE_MIUIX`),前端 `data-style` 也用 `miuix`。 → 本表对齐为 `"md3,miuix"` / "Material You,MIUIx"。**建议**同步改回 `meow_settings.c g_defs`(否则实体设置页与面板值域漂移)。 2. **设置项映射**:协议 §3.2 称后端经 `meow_settings_*` 读写;因后端为独立进程,无法链接 launcher 内 API, **改为直接镜像同一份 `settings.conf`**(同款 parse/save 契约)。改哪边都会落同一文件,实体/网页/CLI 仍同步(listener/落盘)。 3. **`display.brightness` 元数据**:`g_defs` 为 `min=0 max=255 def=101`;但语义 clamp 到 `[brightness_min(1),100]` (防 101 闪屏)。后端给前端 `min=1 max=100`(协议 §3.2 期望),读值经 clamp 后返回(默认→100)。若回改协议可注明「原始表 0-255,面板展示语义 1-100」。 4. **`/api/system` 的 `network`/`ota`**:**M2.73** 起 perf 服务已聚合 `network` 段(真实 WiFi `wpa_cli`/`ip` + 蓝牙 `hci0`/sysfs + `hostname_local`,SYSTEM 子集),后端直接透传;只补 `boot.default`(读 `/data/meow_boot_default`)与 `ota{current=version,available:false,url:null}`。**网络栏以「蓝牙」为准**(设备无网口,无 `以太网` 一行,`bluetooth.available=false` 显示「无蓝牙」)。若回改协议可注明「network 已并入 perf 服务,ota 为面板占位」。 5. **`/api/files` 上传/删除/重命名等 path**:前端对这些操作传**绝对路径**(`d.path/子项`),列表传**相对 root**; 后端 `normalize_path` 对两者均容错(相对则拼 root,绝对则直用),符合协议「白名单根 + 规范化」。 6. **`GET /api/files` 返回值**:`files_list` 返回 `500` 语义时以 500 封装(协议未定义 `root` 之外错误枚举,用通用错误信封)。 7. **通知清单数据源**:协议 §3.8 称后端「经通知后端读取」;因 launcher 无「客户端查询通知清单」IPC(`MSG_NOTIFY_LIST` 仅下行), 后端**改读 TF 卡通知转储日志**(`MeowOS/notifications/notifications.log`)。响应额外带 `source`(`tf`/`none`)与 `items` 别名 (与 `notifications` 同内容);`items` 为任务约定空态形状,`notifications` 为前端实际读取字段,二者并存。`clear` 语义为 「保留活动中的媒体/进度通知」(`ongoing||media||progress>=0`),对应通知中心既定语义。 8. **`/api/files/read` 文本截断**:协议 §3.4 称「仅文本(<1MB)→ 二进制 415」;现实现为「预览上限 1MB,超限 `truncated:true`, 不再整体 404」,二进制仍 415(比协议更友好,返回文件真实 `size` + `truncated`)。 9. **`/api/files/upload`/`rename` 修正**:上传文件名经 `safe_filename` 取 basename、拒绝 `..`/分隔符(防 `../../etc/passwd` 逃逸), 落盘前对 dir 与拼接后路径双重 `normalize_path`+白名单校验;rename 的新路径 = **原路径父目录** + `new_name`(原实现误拼到文件尾部, 恒 ENOTDIR 失败)。上传体上限 `MAX_UPLOAD_BODY`=8MB,超限 → 413 `PAYLOAD_TOO_LARGE`。 10. **TF 卡根可覆盖(宿主测试)**:`env MEOW_TF_ROOT` 覆盖卡根(设备上不设,恒用 `/usr/data/mnt/sd_0`);`env MEOW_NOTIF_LOG` 覆盖通知转储日志路径。设 `MEOW_TF_ROOT` 时 `tf_present()` 恒真(测试用)。 --- ## 7. 已知边界 / 风险 - **单线程串行**:面板访问量极小,但并发请求会被排队(长上传/下载期间其它请求等待)。对面板用途可接受。 - **无鉴权**:设备内网信任模型(协议 §1.3 token 鉴权待定案)。**高危端点**(`reboot/shutdown/ota/apps/删除/上传)无鉴权, 请勿把 8080 暴露到不可信网络。`meow_svc_power` 服务端做 `SO_PEERCRED uid==0` 基础校验(root 才受理动作),后端以 root 运行可过;launcher 电源菜单/后端同链路。 - **IPC 服务未起**:`meow_svc_perf`/`meow_svc_power` 为板载 `trigger=boot` 服务,正常恒在;若异常退出,读侧返回 500 `INTERNAL`, 动作侧返回 500/503,绝不静默。请勿拔除这两服务。 - **升级保护**:`POWER_UPGRADE` 由 `meow_svc_power` 在写 mtd5 前校验卡根 `r3proii.upt`(存在/可读/非空/size>0),失败不写 mtd5;期望 md5/hash 校验留二期。 - **文件/日志/应用均依赖 TF 卡**:无卡统一 503 `NO_CARD`(不阻塞系统核心)。`settings`/`system`/`perf`/`key` 无卡也可用(板载/rootfs)。 - **`/api/files/upload` 上传路径**:multipart 需要 `path` 字段(目标目录);缺失时上传文件会被忽略(前端总是带着 `path`)。 - **数据一致性**:设置直接写 `settings.conf`;`display.brightness`/`boot.default` 的 clamp/同步与 launcher `meow_settings_*` 同口径。 若 launcher 未来改 clamp 逻辑,需同步本表。 - **通知视图为「会话级归档」**:TF 转储日志由 launcher 开机清空、每通知归档时追加一次;非活动(非 ongoing/无进度)通知 10s TTL 自动归档后仍留在日志,故面板会**显示已自动过期但未手动清理的历史通知**(直到 clear)。媒体/进度/ongoing 通知 持续保留。无 launcher 查询 IPC 前的诚实降级(见 §5.8)。 - **通知清空不联动 launcher 内存**:面板 clear/delete 只重写日志视图,launcher 通知中心内存活跃集不受影响(两者数据源分离)。 - **上传为「限长缓冲」非全流式**:multipart 请求体整体读入(上限 8MB,超限 413),下载为流式(8KB 分块)。严格「socket 逐字节流式上传 解析」未实现(需增量 multipart 解析器),列为后续;14MB 内存约束下 8MB 上限 + 流式下载已覆盖大文件读侧。 - **存储为 `meowpanel` 编译时刻写死**的 socket/路径会因 `--sock-perf/--sock-power`(qemu sim)可覆盖,但默认走 `/usr/data/meow_*.sock`。 --- ## 8. 文件清单(本目录) ``` patch_v2/meowpanel/ ├── meowpanel.c # 后端源码(单文件,约 3150 行,-Wall -Wextra 0 warning) ├── build_meowpanel.sh # 交叉编译 + host 分支(-Wall -Wextra 0 warning) ├── meowpanel # 交叉产物(mipsel 静态,约 174 KB,md5 58a7b186…) ├── meowpanel_host # 宿主编译(本机 ld,调试用) ├── services.d/ │ └── meowpanel.conf # 部署到 TF 卡 MeowOS/services.d/meowpanel.conf ├── web/ # 前端(已存在;部署时拷到后端同目录) │ ├── index.html │ ├── meowpanel.css │ └── meowpanel.js └── README.md # 本文件 ```