侧边栏壁纸
博主头像
火阳的小站

软件、硬件与结构的工作笔记

  • 累计撰写 20 篇文章
  • 累计创建 47 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

火阳 架构拆解:PyQt5、SQLite/WAL、SSE 与可恢复数据

火阳
2026-09-03 / 0 评论 / 0 点赞 / 0 阅读 / 0 字
桌面工具最容易在“功能能跑”之后失去控制:窗口越来越多,数据结构不断变,后台任务和网络回调开始互相影响。火阳 的架构调整,核心目标一直是把状态边界说清楚。

火阳 需求与信息架构设计稿

这是需求与信息架构设计稿。图中的范围代表当时的设计目标,本文以当前代码和本次测试结果为准。

一条清晰的主运行线

程序从 main.py 进入 momo_app.app.main。启动层处理运行环境、单实例锁、日志轮转、未捕获异常和 faulthandler,随后加载主题并创建主窗口。把这些事情放在入口,是为了避免页面模块各自处理生命周期,最后出现“窗口关了,线程还在”或“异常只在控制台闪一下”的情况。

主窗口只负责壳层和跨页面协调。真正的业务能力落在几个明确模块里:

main.py
└─ momo_app.app
   ├─ main_window.py            导航、托盘、提醒、全局拖放
   ├─ datastore.py              SQLite/WAL、迁移、CRUD、备份恢复
   ├─ pages/records_page.py     项目、记录、资料库、待办、时间线
   ├─ pages/notes_page.py       独立便签与筛选
   ├─ pages/stats_page.py       项目和时间统计
   ├─ pages/reimbursements_page.py
   ├─ floating.py               快捷记录与大输入窗口
   ├─ expense_export.py         Excel/WPS 导出
   └─ live_updates.py           SSE 刷新

momo_api.server                 局域网 HTTP API、鉴权与 Webhook

这份结构还不是终点。records_page.py 已经增长到 8,391 行,是目前最明确的重构信号。它把项目空间、记录、附件、待办、资料库和大量交互都放在一起,短期便于快速迭代,长期则需要继续拆出视图模型和领域服务。

SQLite/WAL 为什么适合这个阶段

早期版本使用 JSON,优点是直观,缺点也很快出现:局部更新需要改写整份文件,崩溃恢复和并发访问很难建立稳定预期。当前数据层使用 SQLite,包含 metaprojectsrecordssettings 四张表和五个显式索引。

连接初始化会设置:

PRAGMA journal_mode=WAL;
PRAGMA synchronous=FULL;
PRAGMA foreign_keys=ON;
PRAGMA busy_timeout=10000;
PRAGMA wal_autocheckpoint=1000;
PRAGMA quick_check;

这些参数并不神秘。WAL 让读取和短写入更容易共存,FULL 用性能换更稳妥的落盘行为,外键检查防止关系静默损坏,busy timeout 给短暂锁竞争一个明确等待窗口,启动检查则尽早暴露数据问题。旧 JSON 会先校验再迁移;备份恢复继续兼容旧格式,避免一次存储升级切断历史数据。

火阳 系统设置与备份恢复设计稿

API 是受控的扩展面

momo_api.server 使用 ThreadingHTTPServer。当前实现的重点不是把桌面功能全部搬到 Web,而是开放少量高价值入口:健康检查、项目/待办读取、幂等待办创建、签名 Webhook、SSE 事件流,以及手机端报销录入。

网络层要求读写授权;局域网模式必须显式启用,并设置足够强的令牌;请求会检查私有或回环网段、CORS 白名单和请求体大小;Webhook 同时验证签名和事件 ID,避免重放。创建待办支持 Idempotency-Key,因为网络重试不该制造两条相同任务。

仓库中的 OpenAPI 文档有 48 个路径模板、68 个操作。它更接近接口蓝图,覆盖面明显大于当前服务器实现。把“设计过”写成“已经做完”会让后续维护失去基准,所以我在统计页和文章里始终把两者分开。

实时更新不该变成全局刷新

SSE 到达桌面端后,最粗暴的方式是让所有页面全部刷新。小数据时看不出问题,数据量上来以后,界面抖动、焦点丢失和重复查询会一起出现。当前实现把事件类型和页面更新关联起来,只在需要时刷新对应数据,并在后台任务结束时清理对象。

这也是后续重构的方向:让“谁拥有状态、谁能修改、谁负责通知”逐步固定下来。桌面应用的复杂度通常不在算法,而在大量看似独立的交互同时发生时,系统仍能解释自己为什么处于当前状态。

本次可重复验证

本次只读审计运行了以下检查:

python -m compileall -q momo_api momo_app tests tools
结果:COMPILEALL_OK

python -m unittest tests.test_reimbursements tests.test_momo_api -v
结果:Ran 16 tests in 11.440s; OK

python -m momo_app.self_check
结果:火阳 自检通过

通过测试只说明这些已覆盖路径在本次环境中表现符合预期。仓库目前没有覆盖率报告,因此我不会给出一个看起来精确、实际不存在的覆盖率百分比。

0

评论区