monitor

参考

主题契约

写一个第三方主题需要知道的全部接口。

主题是纯静态 SPA。hub 把它当文件伺服,不编译、不注入、不提供构建期变量。

主题包

一个可安装主题是一个目录,名字必须和 theme.json 里的 short 相同:

<themes-dir>/<short>/
├── theme.json
├── preview.png        # 可选,面板上的预览图。文件名是约定,不是字段
└── dist/
    └── index.html

theme.json 的字段都是字符串:

字段含义
name显示名称
short唯一短名,限字母、数字、-_default 为内置主题保留
description简介
version主题版本
author作者
url源码地址。指向 GitHub 仓库时,面板的一键更新从它的 release 取 theme.tar.gz

每个 tag 的 release 里的 theme.tar.gz 解开就是这个目录。

可以用的接口

只有这四个,全部同源:

接口用途
GET /api/me站点名、登录状态、公开页开关
GET /api/nodes节点列表、实时指标、累计流量
GET /api/nodes/{id}/metrics历史指标和延迟记录
GET /api/ws每 2 秒推送一次节点快照的 WebSocket

metrics 的三个查询参数都可以省:

  • hours=N 窗口宽度。匿名上限 168,登录后 2160,超出静默收窄
  • points=W 你画得下几个点。只会让 hub 抽得更稀,不会更密
  • series=metrics|ping 只取要画的那一半,省掉的那半原本占响应的三分之一到三分之二

探测曲线的名字在响应的 probes 里随样本一起下发,匿名可读——画延迟图不需要第二个请求, 也不需要管理员身份

匿名拿不到什么

匿名访问 GET /api/nodes 只返回公开的节点,而且响应里没有 iphostnameremark 这三个 key——不是空字符串,是根本不存在。

指标部分走白名单,所以 boot_idnet_rx_totalnet_tx_total 也只给登录后的面板。

字段定义以 hub 的源码为准。写主题时按「这个 key 可能不存在」处理。

三种要处理的状态

状态长什么样
离线节点metrics: null
刚连上还没上报online: true + metrics: null
坏数据字段缺失或类型不对

第二种最容易漏。默认主题在渲染入口再检查一次完整指标,缺失或畸形时显示「不可用」—— 不让一个节点的坏数据把整个页面白屏

路由

未知路径回落到主题自己的 dist/index.html,所以客户端路由可用。 /admin/* 由 hub 内置后台接管,主题覆盖不了它。

默认主题用 /node/{id} 做详情页。hub 的回落对它够用,但前面若有按路径做正向白名单的 反代或 WAF,得把这个前缀放行:从列表点进去只是 pushState,边缘看不见, 刷新详情页才会真的请求这个路径。症状是「点进去正常,一刷新就被拦」。

本地开发

起一个 hub 实例:

monitor-hub --listen 127.0.0.1:9911 --db /tmp/monitor.db --site http://127.0.0.1:9911
bash

主题的开发服务器把 /api 和 WebSocket 代理到它。默认主题的 vite.config.ts 里就是这么配的, 照抄即可。

参考实现

monitor-theme-default, React + Vite + shadcn/ui,黑白配色。它同时是内置默认主题和第三方主题的范本—— hub 嵌进去的那个包,和你解到 themes/ 的那个是同一个文件。