224 lines
8.5 KiB
Markdown
224 lines
8.5 KiB
Markdown
# shusub2
|
||
|
||
- 文档层级:客户端工具
|
||
- 应用性质:客户端 TUI
|
||
- 源码来源:repo 原生
|
||
- 运行关系:客户端工具
|
||
- 部署模型:无
|
||
- 对应服务:无
|
||
- 对应 stack:无
|
||
- Secret 边界:本地用户配置
|
||
- 目标 API:Pricing Monitor `GET /api/ui-data?view=workspace`
|
||
- 分发方式:`uvx` / `uv tool install`
|
||
- 包名:`shusub2`
|
||
- 命令名:`shusub2`
|
||
- 本地状态路径:`~/.config/shusub2/`
|
||
- 默认数据源:Pricing Monitor `GET /api/ui-data?view=workspace`
|
||
|
||
`shusub2` 是 Sub2API 聚合运维 TUI。默认模式只读取 server2 Pricing Monitor
|
||
后台生成的内存 snapshot,不直接访问 Accounts helper、`sub2api-status`、Sub2API
|
||
admin API、PostgreSQL、SSH 或 pricing upstream。每次数据刷新只请求一次 workspace
|
||
projection;Dashboard、Accounts、Sources、Requests 和 Errors 共用同一份进程内缓存。缓存保留
|
||
服务端 workspace weak ETag;TTL 到期或按 `r` 后只做条件 GET,未变时 bodyless `304` 会续期既有
|
||
已验证 snapshot,且不会附加 `refresh=1` 或触发服务端采集。workspace URL 必须直接指向最终
|
||
端点;客户端拒绝重定向,以免把内存 validator 带往其它 origin。后台 snapshot
|
||
读取之外,默认启动仍会进行一次短超时的 Gitea 版本检查;使用
|
||
`--no-version-check` 或 `SHUSUB2_NO_VERSION_CHECK=1` 可关闭它。
|
||
|
||
## Quick Start
|
||
|
||
已安装时直接运行:
|
||
|
||
```bash
|
||
shusub2
|
||
```
|
||
|
||
默认 workspace URL 是 Tailscale HTTPS 入口:
|
||
|
||
```text
|
||
https://price.tailbeb9ad.ts.net/api/ui-data?view=workspace
|
||
```
|
||
|
||
覆盖并保存 workspace URL:
|
||
|
||
```bash
|
||
shusub2 \
|
||
--workspace-url https://price.tailbeb9ad.ts.net/api/ui-data?view=workspace \
|
||
--save-config
|
||
```
|
||
|
||
从 Gitea 安装为用户命令:
|
||
|
||
```bash
|
||
uv tool install git+https://gitea.shujk.top/shujakuin/shusub2.git
|
||
shusub2
|
||
```
|
||
|
||
也可以一次性运行:
|
||
|
||
```bash
|
||
uvx --from git+https://gitea.shujk.top/shujakuin/shusub2.git shusub2
|
||
```
|
||
|
||
## Data Contract
|
||
|
||
Pricing Monitor 在后台按固定节奏采集并裁剪数据。普通 workspace HTTP 读取只复制
|
||
最近一次内存 snapshot,不触发 SSH、生产 SQL、旧 helper refresh 或 pricing source
|
||
refresh。组件失败时服务端保留对应 last-good 数据,并在 `components` / `state` 中标记
|
||
`stale`、`partial` 和更新时间。
|
||
|
||
Workspace 当前提供以下有界 projection:
|
||
|
||
- `accounts`:账号摘要、quota window、当日用量和 provider/group/status 字段。
|
||
- `status`:channel monitor 摘要。
|
||
- `sources`:Pricing Monitor 已有的脱敏 source 余额与健康状态。
|
||
- `traffic.requests`:仅 server6 的最新有界请求样本。
|
||
- `traffic.errors`:server6/server4 的有界逐条错误事件,保留节点、时间、key/account、结构化错误类别和状态链路,不做错误分组或 per-row count。
|
||
- `traffic.keys`:仅 server6 按 `Asia/Shanghai` 自然日完整聚合的 key 使用量;事件样本上限不会截断其 request/token/cost totals,payload 同时携带统计日期和时区。
|
||
|
||
投影允许展示 account/key 名称、稳定 ID、model、instance 和运维状态,但不包含 API
|
||
key 原文、access/refresh token、cookie、密码、数据库凭据或请求/响应正文。ID 始终按
|
||
字符串处理,避免 JavaScript 或 Python 客户端误损失大整数精度。
|
||
|
||
## Interface
|
||
|
||
默认首页是紧凑 Dashboard。页面信息架构为:
|
||
|
||
```text
|
||
Dashboard | Accounts | Sources | Requests | Errors
|
||
```
|
||
|
||
快捷键:
|
||
|
||
- `a`:聚焦 Accounts,或从独立页面打开 Accounts。
|
||
- `p`:打开 Sources。
|
||
- `k`:在 Dashboard 聚焦 Key usage。
|
||
- `l`:聚焦 Requests,或从独立页面打开 Requests。
|
||
- `e`:聚焦 Errors,或从独立页面打开 Errors。
|
||
- `d`:从独立页面返回 Dashboard。
|
||
- `/`:聚焦当前页面 filter;Dashboard filter 同时作用于全部表。
|
||
- `r`:重新读取 workspace snapshot。该操作不会要求服务端立即采集上游。
|
||
|
||
窄终端中的长 key、account 和 model 使用横向滚动,不截短原字段。独立页面可通过
|
||
以下参数启动:
|
||
|
||
```bash
|
||
shusub2 --accounts
|
||
shusub2 --sources # --pricing 保留为兼容别名
|
||
shusub2 --requests # --logs 保留为兼容别名
|
||
shusub2 --errors
|
||
```
|
||
|
||
加上 `--once` 可输出对应 snapshot 并退出:
|
||
|
||
```bash
|
||
shusub2 --once --requests
|
||
```
|
||
|
||
Accounts 只在 canonical 名称 `{family}-quota-{source}` 或
|
||
`{family}-quotaonly-{source}` 与唯一健康 source 精确匹配时显示 CNY 余额。不会根据
|
||
provider、URL、display name 或模糊文本推断;source 为 error/stale 时保留名称和状态,
|
||
但不伪造 CNY 数值。
|
||
|
||
Requests 展示 server6 的最新有界明细:key、account、model、token bucket、actual cost、first-token latency、
|
||
duration 和 decode throughput。Errors 展示 server6/server4 的逐条 instance、事件时间、status path、key、
|
||
account、model、phase/type/owner,不显示聚合次数。Key usage 和对应 Traffic Account usage 是 server6
|
||
完整当天 rollup;Errors 与 Requests 仍是事件样本。所有 workspace Traffic 都使用服务器声明的 `Asia/Shanghai` 自然日,不依赖客户端本地日期或滚动
|
||
24 小时窗口;每个 Traffic projection 显式携带日期、时区和 `[00:00, 次日 00:00)` 边界。
|
||
|
||
## Legacy Direct
|
||
|
||
`--legacy-direct` 仅用于迁移对账和故障诊断。它恢复旧拓扑:
|
||
|
||
- Accounts helper `/api/tui/accounts`
|
||
- `sub2api-status` `/api/status`
|
||
- Pricing Monitor `view=accounts`
|
||
- Sub2API admin usage/key/error API
|
||
|
||
```bash
|
||
shusub2 --legacy-direct --accounts
|
||
shusub2 --legacy-direct --requests
|
||
```
|
||
|
||
显式传入空 `--workspace-url ''` 也会进入 legacy direct 模式。legacy Requests、Errors
|
||
和 Key usage 需要 Sub2API admin API key;默认 workspace 模式不会读取该凭据文件。legacy
|
||
Key usage 也固定按 `Asia/Shanghai` 当日查询;legacy Errors 的 `--errors-time-range` 保留为与
|
||
上游诊断 API 对账的独立兼容参数,不能代表 workspace 的当天 Traffic 口径。
|
||
|
||
legacy token 仅允许放在 `SHUSUB2_LOGS_TOKEN` 或权限为 `0600` 的
|
||
`~/.config/shusub2/logs-token`:
|
||
|
||
```bash
|
||
mkdir -p ~/.config/shusub2
|
||
chmod 700 ~/.config/shusub2
|
||
printf '%s\n' '<sub2api-admin-api-key>' > ~/.config/shusub2/logs-token
|
||
chmod 600 ~/.config/shusub2/logs-token
|
||
```
|
||
|
||
## Configuration
|
||
|
||
Workspace-first 配置:
|
||
|
||
- `--workspace-url` / `SHUSUB2_WORKSPACE_URL` /
|
||
`SHUSUB2_WORKSPACE_URL_FILE`
|
||
- `--refresh-seconds` / `SUB2API_QUOTA_TUI_REFRESH_SECONDS`
|
||
- `--timeout` / `SUB2API_QUOTA_TUI_TIMEOUT`
|
||
- `--accounts` / `--sources` / `--requests` / `--errors`
|
||
- `--once`
|
||
- `--save-config`
|
||
- `--install`
|
||
- `--version-check-url` / `SHUSUB2_VERSION_CHECK_URL`
|
||
- `--no-version-check` / `SHUSUB2_NO_VERSION_CHECK`
|
||
|
||
Legacy-only 配置:
|
||
|
||
- `--legacy-direct`
|
||
- `--api-url` / `SUB2API_QUOTA_TUI_API_URL`
|
||
- `--status-url` / `SHUSUB2_STATUS_URL`
|
||
- `--pricing-url` / `SHUSUB2_PRICING_URL`
|
||
- `--logs-url` / `SHUSUB2_LOGS_URL`
|
||
- `--logs-token` / `SHUSUB2_LOGS_TOKEN`
|
||
- `--errors-cn-url` / `SHUSUB2_ERRORS_CN_URL`
|
||
- `--errors-us-url` / `SHUSUB2_ERRORS_US_URL`
|
||
- `--logs-limit`、`--errors-limit`、`--errors-time-range`
|
||
|
||
URL config 文件默认位于 `~/.config/shusub2/`。环境变量优先于 config 文件。
|
||
|
||
## Local Development
|
||
|
||
```bash
|
||
cd apps/sub2api-quota-tui
|
||
uv run shusub2
|
||
```
|
||
|
||
运行完整测试和静态检查:
|
||
|
||
```bash
|
||
uv run python -m unittest discover -s tests -p 'test_*.py' -v
|
||
uv run python -m py_compile sub2api_quota_tui.py
|
||
uv lock --check
|
||
```
|
||
|
||
## Maintenance Notes
|
||
|
||
Workspace adapter 只负责把 server projection 映射为现有渲染模型,不得在普通刷新中
|
||
重新引入 legacy HTTP 请求。新增 projection 字段时应同时验证:字段 allowlist、字符串 ID、
|
||
finite number、payload 上限、单请求 cache、错误聚合次数和 legacy fallback。
|
||
|
||
`cliproxy-codex-quota` 与 `sub2api-status` 当前仍可作为 Aggregation Hub 的过渡采集输入和
|
||
双读对照,但不再是默认 TUI 客户端直连依赖。移除这些过渡输入前,必须先完成 server2
|
||
聚合字段对账和 AstrBot `view=alerts` 连续性验证。
|
||
|
||
## Tests And Release
|
||
|
||
发布遵循本仓库 `client-tui-gitea-uv` 流程:完成 scoped diff 审阅和测试后,将
|
||
`apps/sub2api-quota-tui/` 同步到独立 Gitea 仓库,再通过 git source 执行
|
||
`uv tool install --force`。安装后检查 `uv-receipt.toml`,确保来源仍是 Gitea git URL,
|
||
而不是本地目录。
|
||
|
||
## Secret Boundary
|
||
|
||
默认 workspace 模式不需要任何客户端 secret,也不读取 legacy token 文件。服务端
|
||
workspace 不聚合原始凭据或请求/响应正文。legacy direct 模式的 admin API key 仅保存在
|
||
本机用户配置或进程环境中,不得写入仓库、文档、日志或测试 fixture。
|