/* meow_notif.h — MeowOS 通知存储 + 分发(阶段 D · M2a) * * 定位:MeowOS 通知中心后端(存储 + 分发),是阶段 B 通知中心 UI(M5)+ 阶段 D * (M2b D-Bus 桥 / M2c 转储 TF 卡)的前提。设计规范:NOTIFICATION_SYSTEM.md §1-§8 * + FRAMEWORK_DESIGN §4/附C(freedesktop.org Desktop Notifications)。 * * 本批(M2a)只做核心存储骨架: * - 通知数据结构(对齐 freedesktop 字段 + MeowOS 扩展 target_activity/progress); * - 内存配额(每 App ≤ notify.categories 个类型;每类型活跃 ≤ notify.category_quota; * 媒体通知每 App ≤ notify.media_quota,允许多媒体 App 同时); * - TTL 10s 转储钩子(设计 §8,实际 TF 落盘 M2c 后置,本批预留 notif_dump_cb); * - 原生 IPC 通道接入点(MSG_NOTIFY→ACK / MSG_NOTIFY_DISMISS→ACK;MSG_NOTIFY_LIST * 为守护→App 下发,本批提供序列化 helper,UI(M5) 接入)。 * * 空洞实现风格:本文件自包含(不依赖 meow_launcherd.c 的 logmsg/now_ms), * 配额从 meow_settings 读(B2a;键缺省时用本文件默认值)。注释风格中文 +「M2.a 说明」。 */ #ifndef MEOW_NOTIF_H #define MEOW_NOTIF_H #include /* uint32_t/uint64_t/int32_t */ #include /* size_t */ #ifdef __cplusplus extern "C" { #endif /* == 返回码(对齐 meow_ipc.h / MEOWOS_API.md §1,通知专用枚举)== */ enum { NOTIF_OK = 0, NOTIF_ERR_INVAL = -1, /* 参数非法 */ NOTIF_ERR_NOMEM = -6, /* 槽满/内存不足 */ NOTIF_ERR_NOTINIT = -7, /* 未 init */ NOTIF_ERR_QUOTA = -12, /* 配额超限(App 类型数 / 类型条数 / 媒体数) */ NOTIF_ERR_NOENT = -2, /* 通知 id 不存在 */ NOTIF_ERR_IO = -5 /* 文件/存储 IO 失败(TF 转储,无卡/不可写) */ }; /* == 容量/长度(单设备上限;定长,控制静态内存)== */ #define MEOW_NOTIF_APP_ID_MAX 32 #define MEOW_NOTIF_CAT_MAX 24 #define MEOW_NOTIF_SUMMARY_MAX 64 #define MEOW_NOTIF_BODY_MAX 96 #define MEOW_NOTIF_ICON_MAX 48 #define MEOW_NOTIF_ACTIVITY_MAX 48 #define MEOW_NOTIF_ACTIONS_MAX 96 /* NUL 分隔动作键列表 */ #define MEOW_NOTIF_HINTS_MAX 96 /* 原始 "k=v;..." 提示串 */ /* == 配额默认(运行时从 meow_settings notify.* 覆盖;键缺省用此)== */ #define MEOW_NOTIF_CATS_DEF 4 /* 每 App 最多申请的通知类型数(notify.categories) */ #define MEOW_NOTIF_CAT_QUOTA_DEF 4 /* 每类型活跃(未过期)通知上限(notify.category_quota) */ #define MEOW_NOTIF_MEDIA_QUOTA_DEF 1 /* 每 App 媒体通知上限(notify.media_quota) */ #define MEOW_NOTIF_TTL_MS 10000 /* 设计 §8:通知创建 10s 后自动转储到 TF */ /* 媒体通知(category)约定名:命中即按 notify.media_quota 约束(单 App 1 条) */ #define MEOW_NOTIF_MEDIA_CAT "media" /* 系统事件作为 App 的 app_id(NOTIFICATION_SYSTEM.md §7:系统也抽象为 App,同样走配额) */ #define MEOW_NOTIF_SYSTEM_APP "system" /* 通知结构(对齐 freedesktop + MeowOS 扩展)。 * fields 注释:NOTIFICATION_SYSTEM.md §4。 */ typedef struct meow_notif { uint32_t id; /* 全局递增通知 id(0=无效/未分配) */ char app_id[MEOW_NOTIF_APP_ID_MAX]; /* 来源应用;系统事件="system" */ char category[MEOW_NOTIF_CAT_MAX]; /* 通知类型(媒体通知="media") */ char summary[MEOW_NOTIF_SUMMARY_MAX]; /* 标题(单行) */ char body[MEOW_NOTIF_BODY_MAX]; /* 正文(可多行) */ char app_icon[MEOW_NOTIF_ICON_MAX]; /* 图标 icon name 或 path */ char actions[MEOW_NOTIF_ACTIONS_MAX]; /* actions[](NUL 分隔;v1 空,M2b 填) */ char hints[MEOW_NOTIF_HINTS_MAX]; /* hints{} 原始 "k=v;..." 串(v1 空,M2b 填) */ uint32_t expire_timeout; /* 超时 ms;0xFFFFFFFF=ONGOING 常驻 */ uint64_t created_ms; /* 创建时刻(墙钟 epoch ms,供归档/显示) */ uint64_t dump_at_ms; /* 转储时刻(monotonic ms,TTL=创建+10s;ONGOING 亦到此转储) */ int32_t progress; /* MeowOS:0-100 进度;<0=无 */ char target_activity[MEOW_NOTIF_ACTIVITY_MAX]; /* MeowOS:点击跳转目标 activity */ uint8_t ongoing; /* 1=常驻通知(服务死随清) */ uint8_t media; /* 1=媒体通知(走 notify.media_quota) */ uint8_t dismissed; /* 1=已撤下 */ uint8_t dumped; /* 1=已转储(归档) */ uint8_t active; /* 1=槽位占用 */ } meow_notif_t; /* 转储回调(M2c 落盘 / 本批默认仅日志):通知归档时调用。 */ typedef void (*meow_notif_dump_cb)(const meow_notif_t *n); /* == 生命周期 == */ int meow_notif_init(void); /* 幂等;从 meow_settings 读 notify.* 配额(B2a) */ int meow_notif_shutdown(void); /* 保存/清理(进程退出前调;本批=归档未转储项) */ /* == 核心 API == */ /* 推送/更新通知。n->id 为 0(新建);若 n->id>0 或 replace 语义, * 按 n 中同 id 更新已存在通知(未找到则新建)。返回 NOTIF_OK/NOTIF_ERR_*; * *out_id 返回分配/更新的通知 id(可为 NULL)。 */ int meow_notif_post(const meow_notif_t *n, uint32_t *out_id); /* 撤下通知(dismiss)。随之为该通知归档(未转储则立即调 dump_cb + 标记),并释放槽。 */ int meow_notif_dismiss(uint32_t id); /* 活跃(未转储)通知数。app_id 为 NULL/空=全部。 */ int meow_notif_count(const char *app_id); /* 遍历(回调)当前通知。app_id 为 NULL/空=全部。返回遍历到的条数; * 回调返回非 0 则中止遍历。 */ int meow_notif_list(const char *app_id, int (*cb)(const meow_notif_t *n, void *ctx), void *ctx); /* 立即转储所有未上卡(未 dumped)通知:逐条调 dump_cb + 标 dumped(不释放; * 停机前转储用)。返回转储条数。 */ int meow_notif_dump_now(void); /* 主循环周期调(每 10ms 排空 TODO):TTL 到期 → 归档 + (非 ONGOING)释放槽; * dismissed 且未转储 → 归档 + 释放;ONGOING 转储后仍保留内存(服务死随清)。 */ void meow_notif_tick(void); /* 正常电源事件(关机/重启)前调用:先转储所有未上卡通知,再清板载。 */ void meow_notif_before_poweroff(void); /* 覆盖转储回调(NULL=恢复默认日志;M2c 接 TF 落盘)。 */ void meow_notif_set_dump_cb(meow_notif_dump_cb cb); /* == TF 卡转储(通知#6 / M2c,NOTIFICATION_SYSTEM.md §5/§8 + MEOWOS_SPEC_REF §5.3)== * 把 dump_cb 接到 meow_notif_dump_tf 即把每条通知追加为一行 CSV 到 * <卡根>/MeowOS/notifications/notifications.log,并按日志总大小滚动截断 * (保留最新 10MB,不被电源事件清;启动时 meow_notif_init 先清板载+内存表)。 * 字段按 meow_notif 结构(title<-summary;urgency 结构无字段故列留空;均做 CSV * 转义/去换行)。无卡/不可写仅打点降级,绝不崩。 */ int meow_notif_dump_tf(const meow_notif_t *n); /* 0=成功;负=失败(无卡/IO/参数) */ void meow_notif_clear_tf(void); /* 开机清板载通知(清空文件,保留目录) */ void meow_notif_set_tf_path(const char *path); /* 覆盖转储日志路径;NULL=恢复默认卡路径(宿主单测用) */ void meow_notif_set_tf_max(size_t max_bytes); /* 覆盖滚动截断上限;0=恢复默认 10MB(宿主单测用) */ /* 调试:打印当前 Active 表/App 表(前缀)。 */ void meow_notif_dump(const char *log_prefix); /* MSG_NOTIFY_LIST(守护→App 下发清单,M5 通知中心/重同步用): * 把 app_id 的当前通知序列化为 MSG_NOTIFY_LIST 负载写入 buf(≤MEOW_IPC_CARGO), * 返回负载字节数;<0=无(app 无通知)。 */ int meow_notif_serialize_list(const char *app_id, uint8_t *buf, int buf_len); #ifdef __cplusplus } #endif #endif /* MEOW_NOTIF_H */