feat(meowpanel): 通知实时化+屏幕增量帧 (agent-234) — /api/notifications 优先 IPC 读 launcher 活跃集(source:ipc,超时回退TF), dismiss/clear 联动 launcher 内存; /api/screen.jpeg?delta=1 8x8块比对+变化块外接矩形子图(近静态27KB→804B), 前端canvas叠加+开关
meowpanel→24f53b40 已部署真机验证(通知实时出现/撤下联动/增量帧带宽实测)
This commit is contained in:
1 parent
e9b6b690c1
commit
829ac3ba88
6 files changed
+421
-61
No files matched your search
@@ -28,7 +28,7 @@ cd /home/Aska/Project/R3ProII/patch_v2/meowpanel
|
||||
- 两分支均以 `-Os -Wall -Wextra` 复核,**0 warning**(`-Werror` 亦通过)。
|
||||
- 产出(本次构建实测):
|
||||
- `meowpanel`:mipsel 静态,`ELF 32-bit LSB executable, MIPS, MIPS32 rel2, statically linked, stripped`,
|
||||
体积约 **201 KB**(固件阈值内)。md5:`f310a00e11729162e6960f1dd7c85259`。
|
||||
体积约 **206 KB**(固件阈值内)。md5:`24f53b40fd556f758e5eba3417a52c3c`(本次含通知 IPC 实时化 + 增量帧)。
|
||||
- `meowpanel_host`:aarch64 动态链接(宿主编译,仅供调试),体积约 **146 KB**。
|
||||
- 依赖:仅 libc + Linux 内核头(`linux/input.h`),零第三方库(设备无 python3/lua)。鉴权用**内联 SHA-256**(拷贝自
|
||||
`meow_verify/sha256.c` 公有领域参考写法,前缀 `mp_sha256_*` 避免符号冲突;**未改 `meow_verify/` 目录**)。
|
||||
@@ -84,7 +84,7 @@ http://<host>.local:8080/
|
||||
| 方法 | 路径 | 说明 | 实现 |
|
||||
|---|---|---|---|
|
||||
| GET | `/`、`/meowpanel.css`、`/meowpanel.js`、`/assets/<f>` | 静态托管 | ✅ |
|
||||
| GET | `/api/screen.jpeg` | 实时画面:fb0 当前帧 → RGB565→JPEG(`?q=1-100` 质量,默认 70) | ✅(阶段 C) |
|
||||
| GET | `/api/screen.jpeg` | 实时画面:fb0 当前帧 → RGB565→JPEG(`?q=1-100` 质量,默认 70;`?delta=1` 开启增量帧,见 §5.10) | ✅(阶段 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) |
|
||||
@@ -116,9 +116,9 @@ http://<host>.local:8080/
|
||||
| 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/notifications` | 通知列表(**优先 launcher IPC 内存活跃集** `source:"ipc"`;IPC 不可达回退 TF 转储日志 `source:"tf"`;见 §5.8) | ✅(无源→空态 `source:none`,不 503) |
|
||||
| DELETE | `/api/notifications/:id` | 单条删除(**优先 IPC 撤下 launcher 内存**;IPC 不可达回退重写日志移除该 id) | ✅(不存在→404) |
|
||||
| POST | `/api/notifications/dismiss_all`(别名 `/api/notifications/clear`) | 一键清空:**优先 IPC 联动 launcher 内存**,保留活动中的媒体/进度通知;IPC 不可达回退重写日志 | ✅ |
|
||||
| GET | `/api/files/read?path=` | 读文本:预览上限 1MB,超限 `truncated:true`(不再 404);二进制→415 | ✅ |
|
||||
|
||||
### 返回 501 `NOT_IMPLEMENTED` 的端点(诚实标注)
|
||||
@@ -128,9 +128,10 @@ http://<host>.local:8080/
|
||||
| `/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 落地,且现为**实时**:优先经 launcher IPC `MSG_NOTIFY_QUERY(0x25)→QUERY_RESULT(0x27)` 取
|
||||
> **内存活跃集**(`source:"ipc"`);IPC 不可达/超时回退读 TF 卡通知转储日志(`source:"tf"`,会话级归档);两者皆无
|
||||
> `source:"none"`。撤/清(`DELETE` / `dismiss_all`)同样**优先走 IPC**联动 launcher 内存(launcher 撤下时自动归档留档)。
|
||||
> 详见 §5.8。
|
||||
|
||||
> 前端对 `501` 显示「该功能后端尚未实现」(`ok:false,error.code=NOT_IMPLEMENTED`)。
|
||||
|
||||
@@ -207,23 +208,28 @@ http://<host>.local:8080/
|
||||
- `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` 条,不全量进内存)。
|
||||
### 5.8 通知(数据源 = 优先 launcher 内存活跃集,回退 TF 归档)
|
||||
- **数据源优先级**:① launcher IPC 内存活跃集(实时,`source:"ipc"`)→② TF 转储文件(`source:"tf"`)→③ 空态(`source:"none"`)。
|
||||
- ① **launcher IPC**:后端连 `/usr/data/meow_ipc.sock`,`MSG_HELLO` 握手(`app_id=os.meow.panel`)→ `MSG_NOTIFY_QUERY(0x25)`
|
||||
(空 payload=全部 app)→ 期望 `MSG_NOTIFY_QUERY_RESULT(0x27)`(`m_notify_query_result_t`,JSON 数组文本,字段同 TF 归档,
|
||||
`ts` 为 epoch **毫秒**)。launcher 在**主循环单写者**序列化(绝不把通知存储读到 IPC 线程)。后端按 `ms` 升序重排
|
||||
(oldest..newest,与 TF 一致),emit 时倒序= newest first;`ts` 除以 1000 出秒(与 TF 同口径)。
|
||||
- ② **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` 条,不全量进内存)。
|
||||
注意 TF 是**归档快照**(归档时 `dismissed` 尚未置 1,故该列恒 ≈0 不可靠,且非活跃快照)。
|
||||
- **`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)。
|
||||
- **`DELETE /api/notifications/:id`**:**优先 IPC** `MSG_NOTIFY_DISMISS(0x22)`(4B id → `MSG_ACK`;launcher 撤下时自动归档留档);
|
||||
IPC 不可达/未受理 → 回退从日志移除该行(写临时 + rename)。IPC 未受理且日志也无该 id → 404。
|
||||
- **`POST /api/notifications/dismiss_all`**:**优先 IPC** `MSG_NOTIFY_DISMISS_ALL(0x26)`(→ `MSG_ACK.status`=清除数;
|
||||
launcher 保留 ongoing/media/progress 红线项);IPC 不可达 → 回退重写日志(`ongoing||media||progress>=0||category=="media"` 保留)。
|
||||
- **实时性**:IPC 路径直接反映 launcher **内存活跃集**——新通知(含未到期/未归档)**立即**出现在面板(实测:post 一条
|
||||
通知后面板同时刻即见,`source:"ipc"`);撤/清经 IPC 联动 launcher 内存(实测:面板 DELETE 后 launcher 活跃集即无该 id)。
|
||||
TF 路径仅为 launcher 不可达时的诚实降级(会显示自动过期的历史通知,直到 clear)。
|
||||
- **并发**:IPC 可用时面板不写 TF(撤清由 launcher 自行归档),避免与 launcher `O_APPEND` 竞写;仅 IPC 回退到「写临时 + rename」。
|
||||
|
||||
### 5.9 可选鉴权(panel.auth_enabled / panel.auth_pass)
|
||||
- **设置键**:`panel.auth_enabled`(bool,默认 `0`=关)+ `panel.auth_pass`(str,存 `salt:hex`)。两者写 `settings.conf`,
|
||||
@@ -241,11 +247,19 @@ http://<host>.local:8080/
|
||||
首次进入以 `/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`,
|
||||
### 5.10 实时画面(`/api/screen.jpeg`,含增量帧 `?delta=1`)+ 触摸注入(`/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。
|
||||
- **增量帧(`?delta=1`,阶段 C 增强)**:服务端**缓存上一帧紧凑 RGB565**(单线程 accept 循环跨请求持有),按 **8×8 块**逐行
|
||||
`memcmp` 比对(1 块=8×8 像素×2B),只编码**变化块的外接矩形子图**(8 对齐、钳到屏内)为独立 JPEG,并以**响应头**回传偏移/几何
|
||||
(`X-Meow-Delta:1`/`X-Meow-Full:0|1`/`X-Meow-W/H`(整屏)/`X-Meow-Sub-X/Y/W/H`(子图原点与尺寸)/`X-Meow-Changed`/`X-Meow-Blocks`)。
|
||||
- 冷启动/几何变化/变化块覆盖全屏 → 发**整帧**(`X-Meow-Full:1`);帧无变化 → `Content-Length:0` + `X-Meow-Changed:0`(前端跳过叠加)。
|
||||
- 体积:近静态帧(只刷新状态栏时钟等)增量子图可低至数百 B(实测 6 变化块=**804 B**,对比整帧 ~27 KB @q70)。
|
||||
- **不破坏默认**:未带 `?delta=1` 仍为整帧 `image/jpeg`(零回归)。
|
||||
- 前端「屏幕」页新增「增量传输(省流量)」开关:开启后走 `?delta=1`,用 `<canvas>` 叠加(整帧播种/替换,子图 `drawImage(x,y)`);
|
||||
关闭走原 `<img>`+objectURL 整帧。默认关。
|
||||
- **触摸注入**:`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 →
|
||||
@@ -275,10 +289,11 @@ http://<host>.local:8080/
|
||||
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`),对应通知中心既定语义。
|
||||
7. **通知清单数据源**:协议 §3.8 称后端「经通知后端读取」。launcher 现已有**客户端查询/撤/清 IPC**(`MSG_NOTIFY_QUERY(0x25)`/
|
||||
`MSG_NOTIFY_DISMISS(0x22)`/`MSG_NOTIFY_DISMISS_ALL(0x26)`,agent-199 落地),后端改为**优先经这些 IPC** 取 launcher **内存活跃集**
|
||||
(实时,`source:"ipc"`);IPC 不可达/超时回退读 TF 卡通知转储日志(`source:"tf"`,会话级归档)。响应额外带 `source` 与 `items` 别名
|
||||
(与 `notifications` 同内容);`items` 为任务约定空态形状,`notifications` 为前端实际读取字段,二者并存。撤/清同样**优先走 IPC**联动
|
||||
launcher 内存;`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` 逃逸),
|
||||
@@ -305,10 +320,14 @@ http://<host>.local:8080/
|
||||
- **`/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 通知中心内存活跃集不受影响(两者数据源分离)。
|
||||
- **通知 IPC 路径为 launcher 内存活跃集(实时)**:优先 `MSG_NOTIFY_QUERY` 取活跃集;TF 归档日志仅在 launcher 不可达时作为
|
||||
回退(此时才出现「会话级归档」语义——非 activity 通知 10s TTL 自动归档后仍留日志,会显示已过期历史直到 clear;媒体/进度/ongoing 常驻)。
|
||||
IPC 响应为 launcher 的 `m_notify_query_result_t` 单帧文本(≤4KB),活跃通知超限时 launcher 侧 `meow_notif_serialize_json` 保前缀截断
|
||||
(理论上最多 ~30 条,实际通知数远小,可接受)。
|
||||
- **通知撤/清联动 launcher 内存**:面板 delete/dismiss_all **优先走 IPC**(launcher 撤下时自动归档留档);仅 IPC 不可达时回退重写 TF 日志。
|
||||
- **增量帧依赖单线程基线**:`/api/screen.jpeg?delta=1` 用上一帧缓存比对,**面板为单线程 accept 循环**(跨请求持久);对**单面板用户**直接有效。
|
||||
多客户端混用(一全帧+一增量、跨浏览器)时增量基线可能被另一客户端发的全帧刷新,前端「canvas 未播种则整帧取图」兜底自愈;极端并发下增量图
|
||||
可能基于过期基线(可容忍,仅多发一帧整帧即校准)。子图为独立 JPEG(4:2:0 在子图内自采样),与整帧同源同质量,无拼接色差。
|
||||
- **上传为「限长缓冲」非全流式**:multipart 请求体整体读入(上限 8MB,超限 413),下载为流式(8KB 分块)。严格「socket 逐字节流式上传
|
||||
解析」未实现(需增量 multipart 解析器),列为后续;14MB 内存约束下 8MB 上限 + 流式下载已覆盖大文件读侧。
|
||||
- **存储为 `meowpanel` 编译时刻写死**的 socket/路径会因 `--sock-perf/--sock-power`(qemu sim)可覆盖,但默认走 `/usr/data/meow_*.sock`。
|
||||
@@ -328,11 +347,11 @@ http://<host>.local:8080/
|
||||
|
||||
```
|
||||
patch_v2/meowpanel/
|
||||
├── meowpanel.c # 后端源码(约 3650 行,-Wall -Wextra 0 warning;含可选鉴权/内联 SHA-256/实时画面/触摸注入)
|
||||
├── meowpanel.c # 后端源码(约 4100 行,-Wall -Wextra 0 warning;含可选鉴权/内联 SHA-256/实时画面+增量帧/触摸注入/通知 IPC 实时化)
|
||||
├── 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 静态,约 201 KB,md5 f310a00e…)
|
||||
├── meowpanel # 交叉产物(mipsel 静态,约 206 KB,md5 24f53b40…)
|
||||
├── meowpanel_host # 宿主编译(本机 ld,调试用)
|
||||
├── services.d/
|
||||
│ └── meowpanel.conf # 部署到 TF 卡 MeowOS/services.d/meowpanel.conf
|
||||
|
||||
Reference in new issue
Block a user