Commit Graph
3 Commits
Author SHA1 Message Date
KennethCheng 319eeb44ae feat(gotify): Phase 4 C1 — WebSocket reconnect + 帧解析
- src/gotify/reconnect.rs: ReconnectPolicy 按 §15 退避序列
  1s/2s/4s/8s/16s/30s...record_success() 重置;inline #[cfg(test)]
  3 个 backoff 测试
- src/gotify/websocket.rs: blocking tungstenite 0.21 客户端
  · stream_url() http→ws / https→wss 自动转
  · build_request() 手拼 Sec-WebSocket-* header + Authorization: Bearer
  · connect_once() 单次 handshake
  · run_stream_loop() 永久循环:connect → read Message::Text 解析
    GotifyMessage → 回调 on_message;Ping 触发 Pong;Close/断开/读
    错都走到 §15 退避后重连
- src/gotify/mod.rs: re-export 加 reconnect + websocket 子模块
- Cargo.toml: tungstenite 0.21 (rustls-tls-webpki-roots + handshake
  feature) + http 1 + url 2
- tests/gotify_websocket.rs: 3 个 JSON envelope 解析测试

避坑:
- tungstenite 0.21 的 connect 在 handshake feature 后(默认不带),要
  显式开
- WebSocketConfig 0.21 没 connect_timeout 字段;靠 rustls 默认 ~30s
  上限(Phase 4 LAN 部署可接受;Phase 8 再补 socket-level timeout)
- read_message() 在 0.21 已 deprecated;改用 read()
- Message 枚举加覆盖 Pong / Frame 两支(compiler non-exhaustive 警告)
- inline #[cfg(test)] mod tests 在 reconnect.rs 跑 unit tests(与
  tests/ 集成测试并列)

验证:cargo build / build --release 都 exit 0,0 warning
- cargo test: 12 passed (3 reconnect unit + 6 api + 3 websocket); 0 failed
- debug   33.36 MB, subsystem = WINDOWS_CUI
- release  9.43 MB, subsystem = WINDOWS_GUI(tungstenite + http 在 LTO
  后几乎不增体积——和 Phase 3 C2 持平)
2026-09-19 06:00:40 +08:00
KennethCheng c6ad3883f8 feat(gotify): Phase 3 C1 — Gotify REST API client
- src/gotify/api.rs: blocking reqwest 封装(§14);health / applications
  / messages 三个方法;Bearer token 用 HeaderValue::set_sensitive
  标记,日志绝不泄露(§20);10s per-request timeout
- src/gotify/model.rs: GotifyHealth / GotifyApplication / GotifyMessage
  DTO 镜像官方 wire schema;defaultPriority 加 rename(camelCase)
- src/gotify/mod.rs: re-export
- src/error.rs: 加 AppError::Gotify(String)
- Cargo.toml: reqwest 0.12 (blocking + json + rustls-tls) 从注释升级为真
  依赖(AGENTS.md §44 模板里早就列了,Phase 1 当时推迟)
- tests/gotify_api.rs: 6 个 JSON 解析测试

避坑:
- reqwest 0.12 默认 log Bearer token;要 set_sensitive(true) 才行
- reqwest::Error 转 AppError 不能用返回 impl Fn 的 helper(path 是
  &str 不是 'static)—— 改成每个调用点 inline closure
- Gotify 的 defaultPriority 是 camelCase,其他字段都是单字;
  用 #[serde(rename = "defaultPriority")] 单点 rename 而不是全局
  rename_all = "camelCase"(因为 Rust 端字段名是 snake_case)

验证:cargo build / build --release 都 exit 0,0 warning
- cargo test --test gotify_api: 6 passed; 0 failed
- debug   27.88 MB, subsystem = WINDOWS_CUI
- release  8.10 MB, subsystem = WINDOWS_GUI(reqwest 加进 release
  LTO 后体积几乎没变——rustls 是大头但被 strip + LTO 吃掉了)
2026-09-19 04:57:44 +08:00
KennethCheng a3a6a7c91d chore: 初始化 Windows-Gotify-Client-Rust 项目骨架
使用 Rust + Slint 重建一个轻量、现代、Windows 原生体验良好的 Gotify
桌面客户端。本次只搭目录骨架与占位文件,未进入 Phase 1(Bootstrap)。

本次提交内容
------------
- 保留 AGENTS.md(1363 行定制 Agent 实施计划,含 8 阶段路线图)
- 新建 Cargo.toml([package] 元数据 + AGENTS.md §44 依赖模板 + §42
  release profile;无 [[bin]],等 Phase 1 才加 src/main.rs)
- 新建 README.md(项目导览,引用 AGENTS.md)
- 新建 .gitignore(Rust / Slint / Windows / IDE / 密钥)
- 新建 LICENSE(MIT 占位)
- 按 AGENTS.md §4 建好全部 10 个目录,每个空目录放 .gitkeep:
    assets/        assets/fonts/
    ui/            scripts/
    src/           src/gotify/
    src/storage/   src/windows/
    src/services/  tests/

未提交(Phase 1 起才落地)
------------------------
- src/main.rs 及所有 .rs 业务代码
- ui/*.slint 视图
- scripts/build-release.ps1 等构建脚本
- Cargo.lock(当前 Cargo.toml 是占位、无可编译代码)

技术栈约束(来自 AGENTS.md §1 / §2)
------------------------------------
- Rust stable + Slint 1.17.x + Windows 10/11
- 显式禁用:Tauri / Wails / Electron / WebView2 / WPF / WinUI 3 / Node 运行时
- 单一主程序,无浏览器运行时依赖;UI 由 Slint 原生渲染

仓库
----
远程:https://gitea.kennethcheng.cc/KennethCheng/Windows-Gotify-Client-Rust
2026-09-19 04:02:51 +08:00