Files
MeowOS-For-R3P2/patch_v2/meowpanel
..

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 静态,可用)。

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, 体积约 202 KB(固件阈值内)。md5:e98aec6682b7387a035ab5f63c6777e7。
    • meowpanel_host:aarch64 动态链接(宿主编译,仅供调试),体积约 146 KB。
  • 依赖:仅 libc + Linux 内核头(linux/input.h),零第三方库(设备无 python3/lua)。鉴权用内联 SHA-256(拷贝自 meow_verify/sha256.c 公有领域参考写法,前缀 mp_sha256_* 避免符号冲突;未改 meow_verify/ 目录)。 阶段 C 实时画面用自研最小 baseline JPEG 编码器 mp_jpeg.c(顺序 DCT + 4:2:0 + 标准 Huffman 表 Annex K; 无 libm、零依赖,仅 malloc/realloc),质量 70 下 480×720 帧约 24 KB。
  • 头文件引用:-I patch_v2/meow_launcherd(meow_ipc.h 帧格式 / m_perf_*/m_power_*/POWER_*, header 为权威源,结构体字段以它为准)。

2. 部署到 TF 卡

# 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/<file>(映射到同目录文件),前端当前用根相对路径。
  • 服务启动后整卡由 meow_svcd 按 trigger=boot 拉起;meow_sysui 监管(restart/backoff/max_restart)。
  • 无卡:MeowOS/services.d/ 不可读 → svcd 跳过本服务;系统核心照常。

3. 访问

浏览器(同局域网):

http://<host>.local:8080/
  • mDNS 由板载 meow_mdns 应答 <host>.local。
  • 端口默认 8080,可用 -p PORT / 环境变量 MEOWPORT / 与后端同目录 meowpanel.conf(port=N)覆盖。 (优先级:-p > MEOWPORT > meowpanel.conf > 默认 8080。)
  • 无鉴权(设备内网信任模型;可选密码鉴权已实现,见 §5.9)。默认关=零回归;开启后除登录/登出/状态外 /api/* 需会话。
    • 上传/下载/管理类请求统一带 X-MeowToken: <token>(或 Authorization: Bearer <token> / Cookie: meow_token=<token>); 缺/错/过期 → 401 UNAUTHORIZED。默认无鉴权时请勿把 8080 暴露公网。

4. 端点实现清单(对照 MEOWPANEL_PROTOCOL §2 端点总览)

已实现(返回 200/2xx 或语义错误码)

方法 路径 说明 实现
GET /、/meowpanel.css、/meowpanel.js、/assets/<f> 静态托管 ✅
GET /api/screen.jpeg 实时画面:fb0 当前帧 → RGB565→JPEG(?q=1-100 质量,默认 70) ✅(阶段 C)
POST /api/input/tap 触摸注入:{x,y}(480×720 原生坐标;write 进 goodix event1,本机实测可投递);本机触摸后 5s 内忽略注入 ✅(阶段 C)
GET /api/auth/status 鉴权状态(enabled/会话有效) ✅(公开)
POST /api/auth/login 密码登录发 token(sha256 带盐校验) ✅(公开;错→401)
POST /api/auth/logout 登出失效 token ✅(公开;幂等)
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":<payload>};失败 {"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 <file>;用 popen 捕获输出+退出码, 非 0 → 422。export:nyai export <pkg> <tmp> → 以 Content-Disposition: attachment 流式下发。remove:nyai remove <pkg> [--purge]。
  • GET /api/apps / :pkg 详情:直接扫描 MeowAPPs/<dir>/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)。

5.9 可选鉴权(panel.auth_enabled / panel.auth_pass)

  • 设置键:panel.auth_enabled(bool,默认 0=关)+ panel.auth_pass(str,存 salt:hex)。两者写 settings.conf, 与实体设置页/CLI 同一存储契约(面板为独立进程,直接镜像文件)。panel.auth_pass 的 GET /api/settings 恒回 "value":"" + "set":<bool>,绝不回传存量哈希/明文。
  • 门禁:require_auth 在路由分发前执行——未启用直接放行(零回归);启用后除 /api/auth/{login,logout,status} 外全部 /api/ 需有效会话(token 头 / X-MeowToken / Cookie meow_token),缺/错/过期 → 401 UNAUTHORIZED。 危险端点(reboot/shutdown/ota、key 注入)在未开启时不额外限制(保持内网模型),开启后亦统一纳入会话校验。
  • 密码:PUT /api/settings/panel.auth_pass 传明文,后端生成 16B 盐(/dev/urandom)→ salt:hex(sha256(salt||password)) 落盘;空串=清除。校验时重算并恒定比较。哈希/明文绝不进日志/响应。panel.auth_enabled 置 1 时若未设密码 → 422 请先设置面板密码。
  • 会话:POST /api/auth/login 校验后发 token(32B → 64 hex),存内存(AUTH_MAX_SESS=8,满淘汰最早过期)+ 卡上 <web_root>/meowpanel.session(<token> <expires_at>,重启加载、防吊销失效),有效期 12h。logout 失效当前 token。
  • 静态屏蔽:serve_static 额外拒绝后端可执行文件与 meowpanel.session(403),防 token 文件被 HTTP 读取。
  • 前端:api 客户端统一带 X-MeowToken,收到 401 → 弹登录页(#login overlay);登录成功 token 存 localStorage; 首次进入以 /api/auth/status 决定是否弹登录。设置页「面板鉴权」卡片含开关(panel.auth_enabled)+「设置/修改密码」 按钮(panel.auth_pass,走 passwordDlg 输入)。

5.10 实时画面(/api/screen.jpeg)+ 触摸注入(/api/input/tap)— 阶段 C

  • 实时画面:GET /api/screen.jpeg 读 /dev/fb0 当前显示帧(FBIOGET_VSCREENINFO 取 yoffset/xres/yres/bpp, FBIOGET_FSCREENINFO 取 line_length,pread 活动缓冲,只读,不影响渲染;16bpp RGB565)→ mp_jpeg_encode_rgb565() 编码为内存 JPEG(自研最小 baseline 编码器,见 §1),返回 Content-Type: image/jpeg。 ?q=1-100 控制质量(默认 70)。恢复 line_length != xres*2(行尾填充)时先压缩为紧凑 RGB565。
  • 触摸注入:POST /api/input/tap,body {x,y}(0..479 × 0..719 原生像素坐标,前端按 480×720 映射,后端再 clamp)。 机制 = write 进 goodix evdev(/dev/input/event1)——本机实测 write 注入可投递(见 §7 修正历史结论), 事件序列与真实 goodix 一致:先 BTN_TOUCH=1(按下边沿)后 ABS_MT_*/ABS_X/Y(坐标),SYN → 按住 100ms → BTN_TOUCH=0 + ABS_MT_TRACKING_ID=-1 + SYN。关键:launcher/meow_touch 在按下边沿会重置坐标 -1, 只在 down 之后到来的首个有效 ABS 才锁原点(goodix 时序免疫)——故坐标必须在 BTN_TOUCH=1 之后,否则原点永不 锁定 → 抬手被判无效 tap(只高亮不启动)。注入前不写 uinput(本设备厂商内核 write 进 goodix 即可投递,逐 UB 少)。
  • 仲裁(本机优先打断):注入前 touch_last_local_ms() 排空 event1,取「最近一次本机真实触摸」的单调毫秒时间 (剔除本进程自注入事件:事件时间 ≤ 上次注入时刻+200ms),若 now-last < 5000 → 忽略注入,返回 {"dispatched":false,"reason":"local_touch_active","cooldown_ms":N};否则注入并返回 {"dispatched":true,"x","y"}。 MIPS 的 struct input_event 无 time 成员(ABI),按 launcher 同款读裸 16 字节取偏移 0/4 的 tv_sec/tv_usec(单调时钟)。
  • 前端「屏幕」页(web/#/screen,导航「屏幕」):<img> 轮询 GET /api/screen.jpeg?t=…&q=70(fetch→blob→objectURL, 防重叠 + 旧 URL 回收;后端不可达提示「后端未连接」);默认 1fps,滑条 0.2–2fps(存 screen.fps,页面隐藏/切走即停刷, visibilitychange 回前台续刷);点击画面按 480×720 比例换算坐标 → POST /api/input/tap,dispatched:false 时 toast「本机触摸中」。

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() 恒真(测试用)。
  11. 实时画面/触摸注入(阶段 C):协议 §6 待定案项称「实时画面(/api/frame 等,本文件暂未定义)」。本面板落地为 GET /api/screen.jpeg + POST /api/input/tap(命名自定:.jpeg 表达二进制帧 + input/tap 表达触摸注入), 见 §5.10。回改协议时可补这两端点(以及 frames 语义、/api/input/tap 的 dispatched:false/reason 软失败约定)。

7. 已知边界 / 风险

  • 单线程串行:面板访问量极小,但并发请求会被排队(长上传/下载期间其它请求等待)。对面板用途可接受。
  • 无鉴权(默认):设备内网信任模型(协议 §1.3)。高危端点(reboot/shutdown/ota/apps/删除/上传)在默认关鉴权时无鉴权, 请勿把 8080 暴露到不可信网络。meow_svc_power服务端做SO_PEERCRED uid==0` 基础校验(root 才受理动作),后端以 root 运行可过;launcher 电源菜单/后端同链路。 可选鉴权(§5.9)开启后可对内网作加固(登录密码 + 会话),但密码经局域网明文 HTTP 传输,不提供 TLS。
  • 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。
  • 触摸注入在设备息屏时不生效:launcher 主界面在 meow_screen_on==0 时不处理触摸(main_menu.c,息屏防误触);设备自动息屏 (30s 空闲)后注入的 tap 会被 launcher 忽略——面板无法用触摸唤醒(需先电源键点亮)。前端「屏幕」页已提示「设备息屏请先点亮」; 对「正在看」设备的正常使用场景(屏幕亮着)注入即有效。
  • 实时画面读取 fb0 当前帧(只读):双层缓冲下 pread 活动缓冲,存在翻页瞬间撕裂一行的可能(1fps 预览可接受); /dev/fb0 不可读/非 16bpp → 500 INTERNAL(绝不静默)。
  • JPEG 编码器为 baseline 4:2:0:质量 70 下 480×720 ≈ 24KB;质量越高体积越大(q=100 约 60-80KB)。编码为单线程 串行(面板本就单线程),一帧编码约几十 ms(MIPS 单核),1fps 轮询无压力。
  • 触摸注入为即时性注入:不维护长按/多指手势状态机(与按键注入一致);dispatched:false(本机触摸仲裁)属软失败, 前端可按 reason 提示,不视为错误。

8. 文件清单(本目录)

patch_v2/meowpanel/
├── meowpanel.c             # 后端源码(约 3650 行,-Wall -Wextra 0 warning;含可选鉴权/内联 SHA-256/实时画面/触摸注入)
├── mp_jpeg.c               # 最小 baseline JPEG 编码器(顺序 DCT + 4:2:0 + 标准 Huffman,无 libm,-Wall -Wextra 0 warning)
├── mp_jpeg.h               # mp_jpeg.c 接口(RGB565 → 内存 JPEG)
├── build_meowpanel.sh      # 交叉编译 + host 分支(-Wall -Wextra 0 warning)
├── meowpanel               # 交叉产物(mipsel 静态,约 202 KB,md5 e98aec66…)
├── meowpanel_host          # 宿主编译(本机 ld,调试用)
├── services.d/
│   └── meowpanel.conf      # 部署到 TF 卡 MeowOS/services.d/meowpanel.conf
├── web/                    # 前端(已存在;部署时拷到后端同目录)
│   ├── index.html          # 含登录页 overlay + 设置密码对话框
│   ├── meowpanel.css       # 含登录页样式
│   └── meowpanel.js        # API 客户端带 token/401 登录、设置页鉴权卡片
└── README.md               # 本文件