monorepo finale: relocate crates, monitor release pipeline, docs overhaul - #1234
Draft
lollipopkit wants to merge 173 commits into
Draft
monorepo finale: relocate crates, monitor release pipeline, docs overhaul#1234lollipopkit wants to merge 173 commits into
lollipopkit wants to merge 173 commits into
Conversation
sbm_parser 早已解析这六类数据,但 monitoring.rs 从不读取,面板也没有对应 UI。新增低频"扩展采集周期"(默认 60s,可配 extended_interval_secs)跑一次 完整脚本获取 battery/sensors/SMART/AMD 等慢命令,核心 5s 周期之间用 carry-forward 语义补齐(顺带修好了 AMD GPU 因 core:false 从未被采集到的 潜在 bug)。前端加对应卡片/详情页,15 个 locale 同步补齐翻译 key。
diskio 是磁盘的从属信息,合到 disk 详情页底部的表格里更合理; 首页少一张卡片,DetailKind 也去掉了独立的 diskio 枚举值。
aggregate_disks/flatten_disks 用 path.starts_with("/dev") 过滤磁盘,这是
Unix 惯例;Windows 上磁盘 path 是盘符("C:"),永远不匹配,导致 disk 恒为
0、disk_details 恒为空。改为按 SystemType 分支:Windows 只要求 size>0,
Unix/BSD 保留原有 /dev 前缀过滤。
之前 ServerStatus 每个字段在 Linux/BSD/Windows 上是否支持,全靠"没写 代码所以恰好是空"隐性表达,调用方无法区分"平台不支持"和"没这个硬件"。 capabilities() 从 commands 表机械派生 Supported/NotImplemented/ HardwareDependent 三态,随命令表变化自动同步,只有 swap(无专属命令) 需要显式特判并写明原因。
commands.rs 里 Windows 的 SENSORS/DISK_SMART 命令一直有定义、脚本也真的 采集了对应输出,但 lib.rs 的 Windows 分发从没接上解析函数,数据白采了。 新增 windows::parse_sensors/parse_disk_smart(两个命令均无 Dart 对应实现, 按 WMI 输出字段直接给出;disk_smart 没有 pass/fail 标志就不编健康状态)。
不动 adapt_cpu/diskio 的统一(影响已部署实例历史数据口径,需要单独 评估),先把"混乱"从隐性变成文档里写明的已知限制:类型定义处加详细 doc comment,monitor/CLAUDE.md 加一节汇总,并说明 capabilities() 能 力矩阵的存在及其边界(反映命令清单是否存在,不代表分发逻辑一定接好)。
按"monitor 本机 / App 远程"拆分:sbm_parser 继续服务 App 的 SSH+脚本 路径不变,sbm_native 只服务 monitor 的本机直接采集,内部按 #[cfg(target_os)] 分子模块支持多平台(不是每平台一个 crate)。这一步 只搭骨架(sample() 占位返回空 ServerStatus),Linux/sysinfo 后端留给 后续子步骤实现。
cpu/mem/swap/net/conn/diskio/temps/cpu_brand 直接读对应 /proc、/sys 文件, 一字不改地喂给现有 sbm_parser::linux::parse_*;disks/uptime 没有干净的单 文件 procfs 等价物,保留一次目标明确的 df -k / uptime 子进程调用(仍比 "生成整个脚本再按分隔符切"轻量得多)。batteries/sensors/nvidia/amd/ disk_smart 留空,继续走共享脚本路径。cargo check --target x86_64-unknown-linux-gnu 通过;真机数值对比留到影子模式那一步。
吸收 macos_cpu.rs 的"起 sysinfo::System + 每周期 refresh 求 delta"模式,
从"仅 macOS cpu 一个字段"扩到 mem/swap/disks/diskio/net/uptime/host/sys。
NativeState 里的 sysinfo 部分改成调用方持有,不再用 static Mutex 全局态。
顺带发现:sysinfo 的 disk usage() 是真正的累计读写字节数,不像现有
Windows 脚本路径的 diskio 那样把速率误标成累计值——原生路径这块反而是
对的。也顺带确认了一个新坑:sysinfo 在 macOS 上 Disk::name() 返回卷标
("Macintosh HD"),不是 /dev 路径,留了 doc comment 提醒 monitor 集成时
is_real_disk 的 Bsd 分支不能再要求 /dev 前缀(和今天早些时候修的 Windows
磁盘过滤是同一类坑)。
cargo check 验证了 Linux/macOS/Windows 三个 target 都能过编译,macOS 上
真机跑了单测。macos_cpu.rs 暂不删——留到 monitor 集成那一步再替换,避免
中间状态出现 mac CPU 数据来源的空档期。
collect_metrics 每周期额外跑一次 sbm_native::sample(),不改变最终返回值 (仍是脚本解析结果),只把两路结果的关键字段 debug! 出来供人工核对。 本机(macOS)实测跑了几轮,数值符合预期:cpu_cores 第二轮起完全对齐, host 完全一致;mem_total/disks/net_ifaces/sys 有差异但都能解释(script 的 mem.total 来自 vm_stat 页统计会随内存压力小幅漂移,native 用的是 真实物理内存大小,反而更稳;native.disks=3 是 sysinfo 已经去重过的真实 卷,script.disks=15 是 df 原始行数,aggregate_disks 自己的 APFS 池化逻辑 会把它收敛到同样的口径;net_ifaces 多出的是 script 路径过滤掉的虚拟 接口;sys 两边给的是不同粒度的系统描述,都对)。没有发现数值错误。
collect_metrics 改为 sbm_native::sample() 打底(cpu/mem/swap/disk/diskio/ net/uptime/host/sys),nvidia-smi 独立一次子进程调用(不再走生成脚本), 只有 amd/sensors/batteries/disk_smart(以及 Windows 的 conn,原生没做) 还走扩展周期脚本,靠已有的 carry_forward 语义在非扩展周期保留上次值。 is_real_disk 的 Bsd 分支不再要求 /dev 前缀(sysinfo 在 macOS 上 Disk::name() 给的是卷标不是设备路径,继续要求 /dev 会把所有原生磁盘过滤 成 0,和今天早些时候修的 Windows 磁盘 bug 是同一类问题,这次直接在切换 前改掉,不留同样的坑)。 macos_cpu.rs 删除,吸收进 sbm_native::sysinfo_backend。build_status_script/ script_path/execute_commands 去掉 core_only 参数,只保留一种(扩展)脚本 变体。monitor/CLAUDE.md 更新采集架构描述,补了 sbm_native 的说明。 验证:cargo test --workspace 全过;本机(macOS)、lkd-wsl(Linux)、 lkd(Windows)影子模式下三边数值分别核对过(cpu/mem/uptime/host 基本一致, disks/net_ifaces 计数差异均可解释,非错误);本机切换后实跑校验了 /api/v1/metrics 输出(cpu/mem/disk/disk_details/network/diskio 都正确)。
已经可以在 config.toml 里配置,只是默认值太保守。降到 10s 后需要注意: 默认 interval_seconds=7 时扩展周期会变成每个核心周期都跑一次(10/7 取整 为 1),等于 amd-smi/sensors/smartctl 这些命令每次采集都执行——如果磁盘 唤醒延迟不可接受,需要显式调大这个值。
… config.toml extended_interval_secs 改成 Option<u64>,未配置时(默认)通过 effective_extended_interval_secs() 取 interval_seconds 的值,而不是写死 的常量,这样跟着 interval_seconds 走,不用同时维护两个默认值。 config.json(旧 Go 兼容格式)加载后现在会一次性迁移写出 config.toml, 原文件改名保留为 config.json.migrated(不删除,留作回退),下次启动直接 走 config.toml 分支。新增集成测试锁定这个行为(独立测试文件,避免和其他 测试共享进程级 CWD 状态互相干扰)。
Cloudflare Pages 一直在构建失败(check-run: Cloudflare Pages: sbmd, failure),本地用完全相同的命令复现确认:svelte-check 报 8 个 "Cannot find module" 错误,全部指向 packages/webui/src 下的文件 (clsx/tailwind-merge/tailwind-variants/svelte 本身)。 根因和 Docker 构建之前踩过的坑一样(3bd4263 修的):@serverbox/webui 是 file:../../packages/webui 依赖,npm ci 在 monitor/frontend 里只会把它 软链进来,不会装它自己的 devDependencies。Dockerfile 已经补了 `npm install --prefix /app/packages/webui`,但 Cloudflare Pages 控制台 里配置的构建命令没有同步更新。 这次改动只更新了 CLAUDE.md 里记录的正确命令并本地验证通过(clone 到 临时目录,完全按文档命令跑,0 错误、构建成功)——Cloudflare Pages 控制台 的实际构建命令是外部平台设置,不在仓库里,需要手动去后台改。
APFS 同一容器下的多个卷("/" 和 "/System/Volumes/Data")在 sysinfo 里
name() 返回同一个值("Macintosh HD"),disks/diskio 因此各出现一条重复
记录。disk_details 侥幸被 monitor 侧的 seen-path 去重挡住了,但 diskio
没有任何下游去重,直接把重复 dev 喂给前端 `{#each m.diskio as d (d.dev)}`
——Svelte keyed each 遇到重复 key 会直接报错崩掉整个磁盘详情页渲染,
点击磁盘卡片跳转到子页面时就表现为"点了没反应"。
在 sysinfo_backend.rs 里按卷名去重一遍,disks 和 diskio 共用同一份去重
后的列表,不再依赖 monitor 侧偶然的去重逻辑。新增回归测试(在这台真机上
断言 disks/diskio 的 key 全部唯一,机器本身就有这个 APFS 重复条件)。
顺带修正 Cloudflare Pages 构建命令文档:根据用户贴的真实构建日志确认
该项目 Root directory 配置的是 monitor/frontend(不是仓库根目录),
之前记的命令假设错了根目录,已按日志重新验证并改成相对路径版本。
diskio 现在每个核心周期都被原生采集刷新(不再局限于扩展周期),具备了 算真实速率的条件:新增 diskio_rate,用当前周期和上一周期的累计扇区数 + 时间戳差值算出 bytes/sec,首个周期或设备刚出现时没有基线,留空。 磁盘详情页的 I/O 表格改为主显速率(读/写 每秒),累计总量降级为设备名 下面的小字辅助信息。加了单测锁定速率计算(固定用例:2 秒内 +2000/+1000 扇区,应得 512000/256000 B/s)。
新增 GET /api/v1/capabilities(平台相关、不随采样变化,前端只在切服务器 时拉一次,不跟 /metrics 一起轮询)。首页 gpu/battery/sensors/smart 四张 卡片的可见性判断从"数组非空"改成"能力矩阵不是 not_implemented 且数组非 空",能力矩阵没加载完时按放行处理避免闪烁。 验证过程中发现两个原生采集(sbm_native)的真实回归,顺手修了: - cpu_brand 在 sysinfo 后端(mac/Windows)从没被填过,cutover 后 CPU 卡片 型号信息在这两个平台上一直是空的——加 cpu.brand() 分组统计补上。 - temps(CPU 温度)同理从没接,Windows 温度显示因此跟着丢了;加 sysinfo Components 支持。本机(Apple Silicon)硬件本身不暴露温度传感器,验证后 确认是平台限制不是 bug,capabilities 矩阵相应标成 hardware_dependent。 capabilities() 本身留在 sbm_parser、只反映脚本清单(App 用得到的口径不 能改);swap/diskio/temps 在 Bsd 上因为原生采集新增覆盖而被脚本清单标记 过时的问题,在 monitor 侧新增 effective_capabilities() 覆盖,不碰共享 crate。 本机(macOS)实测验证:cpu_brand 恢复正确显示,capabilities 端点返回值 符合预期。cargo test --workspace / npm run check+build 全过。
battery/sensors/SMART 详情页顶部加"更新于 X"提示(extended_updated_at, 只在真正跑了扩展脚本那一轮更新,carry_forward 的周期不刷新),复用现有 lastUpdated 翻译,不需要新增语言包。 首页卡片网格加 md:grid-cols-3,原来 2 列直接跳到 4 列,平板宽度(约 640-1023px)满配 8 张卡片时和手机一样挤,现在有个过渡档位。 顺带发现并修了 adapt_status 里"Bsd 强制温度为 None"的过时逻辑(注释写的 是"top 命令没有温度",但原生采集 cutover 后 sysinfo Components 在部分 Bsd/macOS 机器上是能拿到真实温度的)。本机实测验证:extended_updated_at 正确入库,且温度字段从 None 变成了真实读数 44°C,证明这个平台确实有可用 的温度传感器,之前是代码强制清空,不是硬件限制。 cargo test --workspace / npm run check+build+test 全过。
新迁移(004)给 system_metrics 加 diskio_read_bytes/diskio_write_bytes (跨设备汇总累计字节数,和 network_rx/tx_bytes 同样存法)、battery_percent (只存第一块电池,和首页卡片现状一致)。sensors/disk_smart 不做曲线——没 有统一的单一数值语义,更适合当前值展示或以后做告警,不是趋势图。 store_metrics 写入这两列;get_metrics_history 的 SQL 和 rx/tx 一样对 diskio 做 bucket 差分算速率,battery 直接 avg。磁盘详情页加读写速率 曲线,电池详情页加电量曲线。 新增集成测试锁定 store_metrics 的聚合口径(多设备求和、取首块电池)。 sqlx 离线查询缓存已用 cargo sqlx prepare 重新生成并入库。 cargo test --workspace(含 DATABASE_URL 未设置的离线模式)/ npm run check+build+test 全过;本机实测确认 history 端点返回真实的 diskio_read_speed/write_speed 数值。
新增 GET/PUT /api/v1/settings(白名单读写 interval_seconds/extended_interval_secs/ idle_pause_enabled/idle_pause_threshold_secs/rules/data_retention/cors_allowed_origins, 绝不涉及 jwt_secret/database_url/push 密钥),保存前备份 config.toml。 空闲暂停:AppState 新增 live_settings + last_viewer_seen 心跳(由 /metrics、/status 轮询驱动),run_monitoring_loop 每轮实时读取,should_run_extended 只会把已到期的扩展 周期(smartctl/sensors/amd-smi)降级为跳过,核心指标采集和告警检查不受影响。 前端新增设置页(Sidebar 入口、无路由的视图切换),表单标注哪些字段保存即生效、 哪些需要重启;补全 15 个语言包对应文案。
新增 GET/PUT /api/v1/card-order,独立于 /settings 单独存 config.toml 的 [server].card_order,避免和规则/CORS 的读改写产生并发覆盖;首页卡片支持拖拽 重排,自动为新增卡片类型补位。 /api/v1/capabilities 响应增加 platform 字段(复用 system_type() 机械推导,和 capabilities 本身不会失配),前端新增 OsIcon 组件+capabilitiesStore 缓存, sidebar 每个已登录服务器和顶部标题栏据此显示对应的系统图标。 CPU 卡片已显示温度,系统信息卡片移除重复的温度行。
Collaborator
|
@coderabbitai review |
Contributor
✅ Action performedReview finished.
|
Collaborator
|
@winnowl review |
规则编辑区加字段说明(type/matcher/threshold 取值与格式)+ 示例 placeholder, 去掉规则/CORS 列表项的外框,改用 divider 分隔,item 左侧加序号,删除按钮挪到 每项顶部,避免和某个字段绑死。 新增 PageHeader 组件,统一 Dashboard/Settings/DetailPanel 的顶栏(page 变体 全宽 sticky,section 变体用于 DetailPanel 的返回栏,叠在 page 头下方),取代 三处重复的 header 标记;Settings 保存按钮移入顶栏。 在线状态从小圆点改为给图标本身着色(sidebar 每行图标、Dashboard 标题图标), 未知/离线态可读性更好;sidebar 已命名的服务器不再重复显示 URL。
Owner
Author
|
@coderabbitai ignore |
Contributor
✅ Action performedReviews paused. |
lollipopkit
marked this pull request as draft
July 20, 2026 11:14
面板可选走官方 relay 转发、不暴露公网端口的设计要点(鉴权、推拉节奏、数据 最小化、成本控制、混合兜底)记到根目录 TODOS.md,全部转中文。删除 monitor/doc/TODO.md,未完成项没有迁移(Web UI/Firebase 推送等),仍在 git 历史里。
- sbm_parser 的 BSD 命令表新增 diskSmart(此前 BSD 平台完全没有 smartctl 命令), 用 diskutil list 只筛选真实物理盘(排除 APFS 合成卷/磁盘映像),复用 Linux 同一套 JSON 解析,is_physical_disk 加 /dev/diskN 白名单。真机(Apple Silicon NVMe SSD)实测验证过完整链路:capabilities 从 not_implemented 变成 hardware_dependent,/api/v1/metrics 拿到真实健康状态/温度/开机时长/通电次数。 额外修了 parse_status_opts 里 Bsd 分支从未读取 DISK_SMART 段的遗漏(是这条链路 之前完全不通的真正原因,不只是缺命令)。 - Dart 侧 BSDStatusCmdType 补 diskSmart 保持和 Rust 命令表的清单一致性(locked by test/frb_parser_test.dart),server edit 页的磁盘健康开关同步补上 BSD 分支。 - Linux 的 smartctl 调用改成先 `[ -r /dev/$d ]` 探测可读性,不可读才补 `sudo -n`(非交互、没配置就在 1 秒内失败,不阻塞、不弹密码提示)——不是无脑加 sudo 前缀,避免在已经能跑通的机器上多此一举或因为没装 sudo 反而变差。 - 新增 smart_parse_macos_nvme dart_compat 测试,用真实(序列号已脱敏)Apple SSD smartctl JSON 锁定行为。 - extended_interval_secs 未配置时的默认值从"等于采集间隔"(等于每 7 秒跑一次 smartctl/sensors/amd-smi)改成 interval_seconds x10、下限 120 秒,降低这类 CLI 工具调用对 CPU/功耗的常态开销;SMART 读取本身对闪存寿命的影响可忽略 (诊断性日志读取,不是写入),这次调整解决的是主机资源占用,不是磁盘寿命。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR finishes the monorepo migration with three main blocks, plus follow-up hardening:
1. migrate: merge
rust/andrust_builder/intocrates/sbm_ffirust_root, pubspec paths, and per-platform glue updated in synccargo test --workspacegreen, 12/12 FFI parity tests pass,flutter build macos --debugbuilds through cargokit for real2. feat: monitor release pipeline
monitor-v*tags), decoupled from the app'sv1.0.xinstall.shrewritten for the new release layout; fresh installs generate a randomJWT_SECRET3. docs: full audit of the docs site (en/zh/ja/de/fr/es)
4. Follow-ups on this branch
Notes
server-box-monitorghcr image to public in package settings if desiredSummary
Changes