Initial release v0.1.0
This commit is contained in:
commit
b997bd6078
62 changed files with 56224 additions and 0 deletions
976
docs/第一次开发日志.md
Normal file
976
docs/第一次开发日志.md
Normal file
|
|
@ -0,0 +1,976 @@
|
|||
# 环境搭建
|
||||
|
||||
省略
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# 初始文件树
|
||||
|
||||
`cargo init --bin --name tz .`
|
||||
|
||||
#文件树1
|
||||
|
||||
```
|
||||
TZ/
|
||||
├── Cargo.toml
|
||||
├── Cargo.lock
|
||||
└── src/
|
||||
├── main.rs # tz 可执行程序入口
|
||||
└── lib.rs # 项目的主要代码入口
|
||||
```
|
||||
|
||||
## 常用代码
|
||||
|
||||
```bash
|
||||
# 检查代码,不生成最终程序
|
||||
cargo check
|
||||
|
||||
# 编译
|
||||
cargo build
|
||||
|
||||
# 编译并运行
|
||||
cargo run
|
||||
|
||||
# 向 tz 传入参数
|
||||
cargo run -- status
|
||||
cargo run -- core list
|
||||
|
||||
# 运行测试
|
||||
cargo test
|
||||
|
||||
# 格式代码
|
||||
cargo fmt
|
||||
|
||||
# 静态检查
|
||||
cargo clippy
|
||||
|
||||
# 添加依赖
|
||||
cargo add clap --features derive
|
||||
|
||||
# 删除依赖
|
||||
cargo remove clap
|
||||
|
||||
# 查看依赖树
|
||||
cargo tree
|
||||
|
||||
# 查看项目元数据
|
||||
cargo metadata
|
||||
--format-version 1
|
||||
```
|
||||
|
||||
|
||||
|
||||
# CLI 解析层的第一个小闭环
|
||||
|
||||
1. 添加clap依赖
|
||||
|
||||
```bash
|
||||
cargo add clap --features derive
|
||||
```
|
||||
|
||||
`cargo add` 会修改当前 Package 的 `Cargo.toml`;`derive` feature 让我们可以使用 `#[derive(Parser)]` 和 `#[derive(Subcommand)]`。
|
||||
|
||||
|
||||
|
||||
2. 写文件功能 #文件树2
|
||||
|
||||
```bash
|
||||
mkdir -p src/cli
|
||||
touch src/cli/mod.rs # 管理并导出 cli 模块
|
||||
touch src/cli/args.rs # 定义用户可以输入什么
|
||||
```
|
||||
|
||||
```
|
||||
src/
|
||||
├── main.rs # 程序入口
|
||||
├── lib.rs # 整个项目的库模块入口
|
||||
└── cli/
|
||||
├── mod.rs # 管理并导出 cli 模块
|
||||
└── args.rs # 定义用户可以输入什么
|
||||
```
|
||||
|
||||
3. `lib.rs`中添加声明
|
||||
|
||||
```rust
|
||||
pub mod cli;
|
||||
```
|
||||
|
||||
声明项目中存在 `cli` 模块,Rust 会自动寻找`src/cli.rs`或者`src/cli/mod.rs`
|
||||
|
||||
4. `src/cli/mod.rs`中管理子模块
|
||||
|
||||
```rust
|
||||
mod args; // cli 模块内部还有一个 args 子模块。
|
||||
|
||||
pub use args::{Cli, CliCommand, CoreCommand}; // 表示把三个类型重新导出到 cli 模块表面
|
||||
```
|
||||
|
||||
没有写 `pub`,所以外部不能直接访问`args`/`tz::cli::args::Cli`;
|
||||
|
||||
然后补充[args.rs](../src/cli/args.rs)即可,注释也写在里面
|
||||
|
||||
即使`main.rs`和`lib.rs`在同一个 Cargo package 中, 仍然是两个独立 crate。Rust 官方文档明确说明:同时存在 `src/lib.rs` 和 `src/main.rs` 时,package 中包含一个库 crate 和一个二进制 crate。
|
||||
|
||||
```tcl
|
||||
package tz
|
||||
├── library crate tz
|
||||
│ └── cli
|
||||
└── binary crate tz
|
||||
└── main
|
||||
```
|
||||
|
||||
|
||||
|
||||
5. 补充main.rs
|
||||
|
||||
```rust
|
||||
use clap::Parser;
|
||||
use tz::cli::Cli; // cli 当前是由 lib.rs 管理的,它属于库 crate tz,不是 main.rs 所属二进制 crate 的直接模块。
|
||||
|
||||
fn main() {
|
||||
let cli = Cli::parse();
|
||||
|
||||
println!("{cli:#?}");
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
6. 测试,`--`表示隔开,后面的参数是输入给二进制文件的
|
||||
|
||||
```bash
|
||||
cargo run -- --help # 查看帮助
|
||||
cargo run -- status #
|
||||
cargo run -- core --help # 查看 core 的帮助
|
||||
cargo run -- unknown # 测试错误输入
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 常用代码
|
||||
|
||||
```bash
|
||||
cargo tree # 检查依赖
|
||||
cargo tree -i clap
|
||||
|
||||
cargo fmt # 统一代码格式
|
||||
cargo check # 类型检查和编译检查
|
||||
cargo clippy # 检查潜在问题和不规范写法
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# CLI 解析run态
|
||||
|
||||
1. 新增命令分发层 #文件树3
|
||||
|
||||
```bash
|
||||
src/
|
||||
├── main.rs
|
||||
├── lib.rs
|
||||
├── cli/
|
||||
│ ├── mod.rs
|
||||
│ ├── args.rs # 用户可以使用什么命令
|
||||
│ └── commands/ # 定义“收到命令之后调用什么”
|
||||
│ ├── mod.rs
|
||||
│ ├── status.rs
|
||||
│ ├── service.rs
|
||||
│ └── core.rs
|
||||
```
|
||||
|
||||
创建
|
||||
|
||||
```bash
|
||||
mkdir -p src/cli/commands
|
||||
|
||||
touch src/cli/commands/mod.rs
|
||||
touch src/cli/commands/status.rs
|
||||
touch src/cli/commands/service.rs
|
||||
touch src/cli/commands/core.rs
|
||||
```
|
||||
|
||||
2. 补充command代码
|
||||
|
||||
补充 [src/cli/mod.rs](../src/cli/mod.rs)
|
||||
|
||||
补充 [src/cli/commands/mod.rs](../src/cli/commands/mod.rs)
|
||||
|
||||
补充 [src/cli/commands/status.rs](../src/cli/commands/status.rs)
|
||||
|
||||
补充 [src/cli/commands/service.rs](../src/cli/commands/service.rs)
|
||||
|
||||
补充 [src/cli/commands/core.rs](../src/cli/commands/core.rs)
|
||||
|
||||
补充 [src/main.rs](../src/main.rs)
|
||||
|
||||
|
||||
|
||||
3. 测试
|
||||
|
||||
```bash
|
||||
cargo fmt
|
||||
cargo check
|
||||
cargo clippy
|
||||
```
|
||||
|
||||
然后
|
||||
|
||||
```bash
|
||||
cargo run -- status
|
||||
cargo run -- start
|
||||
cargo run -- stop
|
||||
cargo run -- restart
|
||||
cargo run -- core list
|
||||
```
|
||||
|
||||
```
|
||||
之前:
|
||||
用户输入 → Debug 打印
|
||||
|
||||
现在:
|
||||
用户输入
|
||||
↓
|
||||
Cli
|
||||
↓
|
||||
CliCommand
|
||||
↓
|
||||
match
|
||||
↓
|
||||
具体 command handler
|
||||
```
|
||||
|
||||
# application
|
||||
|
||||
|
||||
|
||||
```bash
|
||||
mkdir -p src/application
|
||||
|
||||
touch src/application/mod.rs
|
||||
touch src/application/service.rs
|
||||
```
|
||||
|
||||
文件树4
|
||||
|
||||
````bash
|
||||
src/
|
||||
├── main.rs # 程序入口
|
||||
├── lib.rs # 整个项目的库模块入口
|
||||
└── cli/
|
||||
│ ├── mod.rs # 管理并导出 cli 模块
|
||||
│ ├── args.rs # 定义用户可以输入什么
|
||||
│ └── commands/ # 定义“收到命令之后调用什么”
|
||||
│ ├── mod.rs # commands 本体
|
||||
│ ├── status.rs # commands 的 子模块
|
||||
│ ├── service.rs
|
||||
│ └── core.rs
|
||||
│
|
||||
└── application/
|
||||
├── mod.rs
|
||||
└── service.rs # 这个替换commands/service.rs的服务
|
||||
|
||||
````
|
||||
|
||||
随后需要补充的 `lib.rs`中定义新的模块
|
||||
|
||||
之后将commands中的相关模块替换成
|
||||
|
||||
|
||||
|
||||
# 前部小结
|
||||
|
||||
这里主要是创建两个模块
|
||||
|
||||
cli : 指令列表,以及管理\\调用
|
||||
|
||||
application : 真实实现
|
||||
目前只是搭建了基础框架没有实际执行,
|
||||
|
||||
1. 搭建cli
|
||||
2. 搭建application,改cli的调用路线为application
|
||||
|
||||
主要完成了指令的分发
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# 路径系统
|
||||
|
||||
|
||||
|
||||
设定软件的路径系统,
|
||||
|
||||
```bash
|
||||
mkdir -p src/platform
|
||||
|
||||
touch src/platform/mod.rs
|
||||
touch src/platform/paths.rs
|
||||
```
|
||||
|
||||
文件树5
|
||||
|
||||
```bash
|
||||
src/
|
||||
├── main.rs # 程序入口
|
||||
├── lib.rs # 整个项目的库模块入口
|
||||
└── cli/
|
||||
│ ├── mod.rs # 管理并导出 cli 模块
|
||||
│ ├── args.rs # 定义用户可以输入什么
|
||||
│ └── commands/ # 定义“收到命令之后调用什么”
|
||||
│ ├── mod.rs # commands 本体
|
||||
│ ├── status.rs # commands 的 子模块
|
||||
│ ├── service.rs
|
||||
│ └── core.rs
|
||||
│
|
||||
└── application/
|
||||
│ ├── mod.rs
|
||||
│ └── service.rs # 这个替换commands/service.rs的服务
|
||||
│
|
||||
└── platform/
|
||||
├── mod.rs
|
||||
└── paths.rs
|
||||
```
|
||||
|
||||
要求:
|
||||
|
||||
- 默认配置不依赖环境变量即可使用。
|
||||
- 路径配置统一保存在 `paths.toml`,由 `TZ_PATHS_TOML` 指向;未设置时使用 `$HOME/.config/tz/paths.toml`。
|
||||
- `tz init` 可以在用户确认后把 `TZ_PATHS_TOML` 的 export 追加到 `~/.bashrc`。
|
||||
|
||||
## 文件系统初始化规则
|
||||
|
||||
`paths.toml` 是文件系统路径的唯一配置源,文件只保存一次选定的四个目录,不保存布局类型或多个方案:
|
||||
|
||||
```toml
|
||||
[layout]
|
||||
config_dir = "~/.config/tz"
|
||||
data_dir = "~/.local/share/tz"
|
||||
state_dir = "~/.local/state/tz"
|
||||
cache_dir = "~/.cache/tz"
|
||||
```
|
||||
|
||||
路径文件定位规则:
|
||||
|
||||
1. 设置 `TZ_PATHS_TOML` 时,读取该绝对路径文件;文件不存在或格式错误直接报错,不回退。
|
||||
2. 未设置时,读取 `$HOME/.config/tz/paths.toml`。
|
||||
3. 默认路径文件不存在时,提示运行 `tz init`。
|
||||
|
||||
程序固定读取 `[layout]` 下的四个字段。路径可以写成绝对路径或 `~/...`;读取时展开 `~`,展开后必须是绝对路径。普通命令不再读取 `TZ_ROOT_DIR` 或四个 `XDG_*` 环境变量。
|
||||
|
||||
`tz init` 的首次选择提供三个模板:
|
||||
|
||||
1. 默认 XDG:`~/.config/tz`、`~/.local/share/tz`、`~/.local/state/tz`、`~/.cache/tz`。
|
||||
2. 默认 Unified:`~/.tz/config`、`~/.tz/data`、`~/.tz/state`、`~/.tz/cache`。
|
||||
3. 开发测试:项目目录下的 `target/tz-dev/{config,data,state,cache}`。
|
||||
|
||||
选择模板后,交互询问四个目录,回车保留模板值,也可以修改。最终只写入一个 `[layout]` 表。
|
||||
|
||||
重复运行 `tz init` 时,如果 paths 文件已存在,先询问是否继续;拒绝则退出且不修改文件,确认后才重新选择和写入。写入路径文件后,初始化根据四个目录补齐结构和初始文件,已有文件一律跳过,不覆盖内容。
|
||||
|
||||
## `tz init` 交互
|
||||
|
||||
- 第一次运行时选择三个内置模板:默认 XDG、默认 Unified、开发测试 `target/tz-dev`。
|
||||
- 选择后分别询问 `config_dir`、`data_dir`、`state_dir`、`cache_dir`,回车使用模板值。
|
||||
- 如果 paths 文件已经存在,先询问是否继续;默认退出,不修改现有路径。
|
||||
- 初始化结束后始终打印 `export TZ_PATHS_TOML='...'` 提示。默认 `$HOME/.config/tz/paths.toml` 不需要设置变量;自定义 paths 文件可以确认后追加到 `~/.bashrc`。
|
||||
|
||||
## 开发测试
|
||||
|
||||
开发测试模板使用项目目录下的 `target/tz-dev`,示例:
|
||||
|
||||
```bash
|
||||
cargo run -- init
|
||||
# 选择 3) 开发测试 target/tz-dev
|
||||
TZ_PATHS_TOML="$PWD/target/tz-paths.toml" cargo run -- status
|
||||
```
|
||||
|
||||
如果 paths 文件放在默认 `$HOME/.config/tz/paths.toml`,后续命令不需要设置环境变量;如果使用自定义路径文件,需要设置 `TZ_PATHS_TOML` 或按初始化结束时的提示加入 bashrc。
|
||||
|
||||
## 本次修改的代码文件
|
||||
|
||||
- `src/platform/paths.rs`
|
||||
- 使用 `paths.toml` 作为唯一路径配置源。
|
||||
- 支持 `TZ_PATHS_TOML` 和默认 `$HOME/.config/tz/paths.toml`。
|
||||
- 解析 `[layout]` 的四个固定目录,支持 `~/` 展开和绝对路径校验。
|
||||
- 保留初始化目录、五个初始文件和幂等补全。
|
||||
- `src/application/init.rs`
|
||||
- 提供默认 XDG、默认 Unified、开发 `target/tz-dev` 三个模板。
|
||||
- 已有 paths 文件先确认,再允许重新选择。
|
||||
- 初始化结束打印 `TZ_PATHS_TOML` export;自定义路径可确认后追加到 `~/.bashrc`。
|
||||
|
||||
验证命令:
|
||||
|
||||
```bash
|
||||
cargo fmt --check
|
||||
cargo check
|
||||
cargo test --all-targets
|
||||
cargo clippy --all-targets -- -D warnings
|
||||
```
|
||||
|
||||
# 文件作用
|
||||
|
||||
接下来固定文件作用
|
||||
|
||||
`paths.toml` TZ_PATHS_TOML
|
||||
|
||||
```toml
|
||||
[layout]
|
||||
config_dir = "/mnt/data_4t2/lht_self/TZ/target/tz-dev/config"
|
||||
data_dir = "/mnt/data_4t2/lht_self/TZ/target/tz-dev/data"
|
||||
state_dir = "/mnt/data_4t2/lht_self/TZ/target/tz-dev/state"
|
||||
cache_dir = "/mnt/data_4t2/lht_self/TZ/target/tz-dev/cache"
|
||||
|
||||
```
|
||||
|
||||
## 三级配置
|
||||
|
||||
### 一级配置
|
||||
|
||||
> 全局、长期、比较稳定的信息。
|
||||
|
||||
`settings.toml`:tz软件的统一配置信息,与core的运行不太相关。默认不会修改,只是展示一下
|
||||
|
||||
```toml
|
||||
schema_version = 1
|
||||
|
||||
[bypass]
|
||||
enabled = true
|
||||
# bypass.list 之外的内联补充项,生成规则时合并并去重。
|
||||
inline = [
|
||||
"localhost",
|
||||
"127.0.0.0/8",
|
||||
]
|
||||
|
||||
[log]
|
||||
level = "warn"
|
||||
# tz.log 超限后直接清除重建,不保留归档。
|
||||
max_size_mb = 10
|
||||
|
||||
[update.profiles]
|
||||
auto_update = false
|
||||
interval_minutes = 4320
|
||||
|
||||
[update.cores]
|
||||
auto_update = false
|
||||
interval_minutes = 14400
|
||||
```
|
||||
|
||||
`runtime.toml`:TZ 可以跨 core 表达的运行参数,包括端口、API、DNS 和 TUN 的复杂参数。是否开启 TUN 不在这里,开关保存在 `active.toml`。
|
||||
|
||||
```toml
|
||||
schema_version = 1
|
||||
|
||||
[proxy]
|
||||
mode = "rule"
|
||||
listen = "127.0.0.1"
|
||||
mixed_port = 7890
|
||||
http_port = 7892
|
||||
socks_port = 7891
|
||||
allow_lan = false
|
||||
ipv6 = false
|
||||
|
||||
[api]
|
||||
enabled = true
|
||||
listen = "127.0.0.1"
|
||||
port = 9189
|
||||
|
||||
[dns]
|
||||
enabled = true
|
||||
listen = "127.0.0.1"
|
||||
port = 1053
|
||||
ipv6 = false
|
||||
|
||||
[tun]
|
||||
stack = "system"
|
||||
auto_route = true
|
||||
auto_detect_interface = true
|
||||
dns_hijack = true
|
||||
```
|
||||
|
||||
### 二级配置
|
||||
|
||||
`active.toml`:保存主页需要展示和切换的状态,只放当前 core 与三个开关。当前 profile 和节点选择由 `profiles.toml` 保存,PID 与锁由 `state/runtime/` 保存。
|
||||
|
||||
```toml
|
||||
schema_version = 1
|
||||
|
||||
[current]
|
||||
core = "mihomo"
|
||||
|
||||
[tun]
|
||||
enabled = false
|
||||
|
||||
[shell_proxy]
|
||||
enabled = false
|
||||
bypass = true
|
||||
|
||||
[system_proxy]
|
||||
enabled = false
|
||||
bypass = true
|
||||
```
|
||||
|
||||
|
||||
### 三级配置
|
||||
|
||||
`state/generated/<core>/` 只保存根据配置生成的内核入口文件,可随时删除重建。`state/runtime/<core>/` 才是 `{workdir}` 指向的内核工作目录,用来隔离 cache.db 等副产物。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 介绍文档
|
||||
|
||||
> 除了上面的一些控制文档,还需要有一些总结性的文档,避免每次都重新扫描文件。
|
||||
|
||||
`profiles.toml`
|
||||
|
||||
```toml
|
||||
schema_version = 1
|
||||
|
||||
# 每个 family 各自保存当前 profile,切换 core 后可以恢复对应选择。
|
||||
[current]
|
||||
clash = "home"
|
||||
sing-box = "sid"
|
||||
|
||||
[[profiles]]
|
||||
name = "home"
|
||||
family = "clash"
|
||||
format = "yaml"
|
||||
source_file = "home/source.yaml"
|
||||
|
||||
[profiles.origin]
|
||||
kind = "remote"
|
||||
url = "https://example.com/subscription"
|
||||
|
||||
[profiles.update]
|
||||
updated_at = "2026-08-14T10:00:00Z"
|
||||
|
||||
# 一个 profile 可以保存多个策略组的节点选择。
|
||||
[profiles.state.selected]
|
||||
Proxy = "Hong Kong 01"
|
||||
Final = "Proxy"
|
||||
|
||||
[[profiles]]
|
||||
name = "company"
|
||||
family = "clash"
|
||||
format = "yaml"
|
||||
source_file = "company/source.yaml"
|
||||
|
||||
[profiles.origin]
|
||||
kind = "local"
|
||||
original_path = "/home/lht/config/company.yaml"
|
||||
```
|
||||
|
||||
# cores标准设计
|
||||
|
||||
> 下面的不需要tz程序初始化,也不需要其修改,基本上手动制作,tz读取使用即可
|
||||
|
||||
```bash
|
||||
cores/
|
||||
└── mihomo/
|
||||
├── core.toml # Core 描述文件
|
||||
└── mihomo # 二进制
|
||||
```
|
||||
|
||||
这一部分还作为后续cores制作的参考标准
|
||||
|
||||
`core.toml`
|
||||
|
||||
```toml
|
||||
schema_version = 1
|
||||
|
||||
|
||||
[core]
|
||||
name = "mihomo"
|
||||
family = "clash"
|
||||
version = "1.19.18"
|
||||
binary = "mihomo"
|
||||
os = "linux"
|
||||
arch = "x86_64"
|
||||
|
||||
|
||||
[runtime]
|
||||
entrypoint = "config.yaml"
|
||||
format = "yaml"
|
||||
|
||||
|
||||
[capabilities.config]
|
||||
mixed_proxy = true
|
||||
http_proxy = true
|
||||
socks_proxy = true
|
||||
api = true
|
||||
dns = true
|
||||
tun = true
|
||||
|
||||
# start 必填;check/version/reload 为可选表。
|
||||
# 某个命令表存在就表示支持对应 CLI 动作,不再维护重复的 actions 布尔值。
|
||||
[commands.start]
|
||||
args = ["-d", "{workdir}", "-f", "{config}"]
|
||||
|
||||
[commands.check]
|
||||
args = ["-t", "-d", "{workdir}", "-f", "{config}"]
|
||||
|
||||
[commands.version]
|
||||
args = ["-v"]
|
||||
```
|
||||
|
||||
`core.toml` 只允许 `{config}` 和 `{workdir}` 两个占位符。`binary` 与 `entrypoint` 必须是单个相对文件名;加载 core 时还会检查 schema、目录名、family/format 组合、二进制是否存在且可执行。
|
||||
|
||||
## 最终文件树
|
||||
|
||||
> 这里是结合文件作用+cores的
|
||||
|
||||
```toml
|
||||
TZ_PATHS_TOML
|
||||
└── paths.toml # 保存四个基础路径
|
||||
|
||||
|
||||
config/
|
||||
├── settings.toml # TZ 自身的长期策略:bypass、日志、更新配置
|
||||
├── runtime.toml # 跨 core 的端口、API、DNS、TUN 参数
|
||||
├── shell/ # 后续生成 shell 代理脚本;当前阶段尚未实装
|
||||
└── bypass.list
|
||||
|
||||
|
||||
data/
|
||||
├── profiles/
|
||||
│ ├── profiles.toml # profile 索引、当前选择和策略组节点选择
|
||||
│ ├── tnt/
|
||||
│ │ └── source.yaml
|
||||
│ └── sid/
|
||||
│ └── source.json
|
||||
│
|
||||
└── cores/ # 手工制作、TZ 只读;目录名必须等于 core.name
|
||||
├── mihomo/
|
||||
│ ├── core.toml
|
||||
│ └── mihomo
|
||||
└── sing-box/
|
||||
├── core.toml
|
||||
└── sing-box
|
||||
|
||||
|
||||
state/
|
||||
├── active.toml # 当前 core 与主页开关
|
||||
│
|
||||
├── generated/ # 只放可删除重建的生成配置
|
||||
│ ├── mihomo/
|
||||
│ │ └── config.yaml
|
||||
│ └── sing-box/
|
||||
│ └── config.json
|
||||
│
|
||||
├── runtime/
|
||||
│ ├── mihomo/ # Mihomo cache.db 等运行副产物,{workdir} 指向这里
|
||||
│ ├── sing-box/
|
||||
│ ├── tz.lock # 防止多个 TZ 同时修改运行状态
|
||||
│ └── core.pid # 停止时还必须通过 /proc/<pid>/exe 校验身份
|
||||
│
|
||||
└── logs/
|
||||
├── tz.log
|
||||
└── core.log
|
||||
|
||||
|
||||
cache/
|
||||
├── downloads/
|
||||
└── speedtest/
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
# 配置层 domain 与命令实装
|
||||
|
||||
## 本次目标
|
||||
|
||||
把“文件作用 + cores 标准”定稿落到 Rust:用 domain 结构体描述 `settings.toml`、`runtime.toml`、`active.toml`、`profiles.toml` 和 `core.toml`,由 `tz init` 生成默认文件,由 `tz status` 与 `tz core list` 严格读取。配置 builder 和真实进程启停留到下一阶段。
|
||||
|
||||
## 代码结构
|
||||
|
||||
`src/domain/` 只负责配置结构、序列化和业务校验;`application` 负责行为;`platform` 负责路径:
|
||||
|
||||
```
|
||||
src/
|
||||
├── domain/
|
||||
│ ├── mod.rs # domain 类型重导出
|
||||
│ ├── settings.rs # settings.toml:[bypass]/[log]/[update]
|
||||
│ ├── runtime.rs # runtime.toml:[proxy]/[api]/[dns]/[tun]
|
||||
│ ├── active.rs # active.toml:当前 core + 三个主页开关
|
||||
│ ├── profiles.rs # profiles.toml:当前 profile、索引、节点选择
|
||||
│ └── core_manifest.rs # core.toml 加载、校验和 list_cores
|
||||
├── platform/paths.rs # 四个根目录和固定子路径
|
||||
├── application/
|
||||
│ ├── init.rs # 生成默认配置
|
||||
│ └── service.rs # status 与未实现启停错误
|
||||
└── cli/commands/ # CLI 薄分发
|
||||
```
|
||||
|
||||
## 配置职责与校验
|
||||
|
||||
- `settings.toml` 保存 TZ 自身的长期策略。日志超限直接清除重建,因此没有 `keep` 字段。
|
||||
- `runtime.toml` 保存端口、API、DNS 与 TUN 复杂参数;默认端口为 mixed `7890`、HTTP `7892`、SOCKS `7891`。
|
||||
- `active.toml` 只保存 `[current].core`、`tun.enabled`、shell proxy 和 system proxy 开关。
|
||||
- `profiles.toml` 在顶层 `[current]` 按 family 保存当前 profile;`[profiles.state.selected]` 可以保存多个策略组各自选择的节点。
|
||||
- `state/generated/<core>/` 只保存可删除重建的入口配置;`state/runtime/<core>/` 是 `{workdir}`,用于隔离内核数据库和缓存。
|
||||
- 四份配置都只支持 `schema_version = 1` 并拒绝未知字段。`Default` 只供 `tz init` 生成模板;普通命令严格读取,文件缺失、损坏或版本不支持都会报错。
|
||||
- profile 会校验名称、family/format、来源字段、重复项、当前选择引用和 `source_file` 安全相对路径。
|
||||
|
||||
## cores 标准
|
||||
|
||||
- `core.name` 必须等于目录名,名称只能使用 ASCII 字母、数字、点、下划线和连字符。
|
||||
- `family/format` 当前支持 `clash/yaml` 与 `sing-box/json`。
|
||||
- `binary` 和 `runtime.entrypoint` 必须是单个相对文件名;binary 还必须实际存在且可执行。
|
||||
- `commands.start` 必填;`commands.check`、`commands.version`、`commands.reload` 可选。命令表存在即表示支持对应动作,不再使用重复的 `[capabilities.actions]` 布尔值。
|
||||
- 命令参数只支持 `{config}` 和 `{workdir}`,由 `CoreDescriptor::render_args` 展开。
|
||||
- `[capabilities.config].api` 只表示内核提供控制 API,不等同于支持 CLI reload。
|
||||
|
||||
## paths.rs 与初始化
|
||||
|
||||
- `paths.toml` 仍是四个根目录的唯一来源;设置 `TZ_PATHS_TOML` 时必须是绝对路径。
|
||||
- `AppPaths::from_env_or_none()` 让非 init 命令自己输出未初始化提示,不再提前重复解析路径。
|
||||
- `initialize_files` 只建目录并幂等写 `bypass.list`;domain 默认值负责生成四份 TOML,已有文件不覆盖。
|
||||
- 初始化先准备目录与默认配置,最后写 `paths.toml`,避免配置生成失败后留下已提交的路径文件。
|
||||
- `generated_dir` 与 `core_workdir` 分离;没有独立的 `active.example.toml`。
|
||||
|
||||
## 当前命令行为
|
||||
|
||||
- `tz init`:选择模板,确认四个路径,准备目录和默认配置,最后写 `paths.toml`,再提示 `TZ_PATHS_TOML` export。
|
||||
- `tz status`:显示当前 core、profile、受管进程和当前节点;PID 检查会排除僵尸进程。
|
||||
- `tz core list`:扫描 `data/cores/*/core.toml`,通过完整校验后按名称排序,并在 TTY 中允许直接选择。
|
||||
- `tz start`、`tz stop`、`tz restart`:生成并校验配置后真实控制受管进程;停止前核对进程用户和可执行文件。
|
||||
|
||||
`stop` 不会仅凭 PID 发送信号;`/proc/<pid>/exe` 与当前受管 core 不一致时直接拒绝。
|
||||
|
||||
## 验证
|
||||
|
||||
```bash
|
||||
cargo fmt --check
|
||||
cargo check
|
||||
cargo test --all-targets
|
||||
cargo clippy --all-targets -- -D warnings
|
||||
TZ_PATHS_TOML="$PWD/target/tz-paths.toml" cargo run -- status
|
||||
TZ_PATHS_TOML="$PWD/target/tz-paths.toml" cargo run -- core list
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# 控制逻辑界面
|
||||
|
||||
TZ 的公开控制入口围绕对象和业务动作组织,不提供任意 TOML 编辑器。配置文件是内部存储格式,所有写操作都经过类型校验、运行状态检查、锁保护和原子保存。
|
||||
|
||||
## 当前命令
|
||||
|
||||
```bash
|
||||
tz init
|
||||
tz status
|
||||
tz setting
|
||||
tz setting list
|
||||
tz setting get <key>
|
||||
tz setting set <key> [value]
|
||||
tz setting reset [key]
|
||||
|
||||
tz profile add <name> <url-or-file> --family clash|sing-box
|
||||
tz profile list [--family clash|sing-box] [--all]
|
||||
tz profile info <name>
|
||||
tz profile use [name]
|
||||
tz profile update
|
||||
tz profile remove <na
|
||||
|
||||
tz core add <directory>
|
||||
tz core list
|
||||
tz core info [name]
|
||||
tz core use [name]
|
||||
tz core remove <name>
|
||||
|
||||
tz completion generate bash|zsh|fish # 生成tab服务
|
||||
```
|
||||
|
||||
`tz setting` 无子命令时在 TTY 中进入选择界面;非交互调用使用 `list`。`set` 缺少 value 时只允许 TTY 交互。`start`、`stop`、`restart` 当前明确返回未实现错误,不打印成功状态。
|
||||
|
||||
## 简明指令
|
||||
|
||||
```bash
|
||||
tz start|on # 直接读取上一次的配置
|
||||
tz off|stop|end # 关闭服务,清理环境
|
||||
tz -l # 列出节点
|
||||
tz -l <name> # 不区分大小写的关键词搜索
|
||||
|
||||
tz completion generate bash|zsh|fish # 生成 shell 补全脚本
|
||||
# eval "$(tz completion generate bash)"
|
||||
|
||||
```
|
||||
|
||||
## 快捷键
|
||||
|
||||
```bash
|
||||
tz # tz status ,需要展示当前使用的core,profile,节点及其测速
|
||||
tz select # tz profile list
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 状态归属
|
||||
|
||||
- `settings.toml` 与 `runtime.toml` 由 `tz setting` 的固定 key registry 管理,禁止任意路径写入。
|
||||
- `active.toml` 只由 core 选择等业务命令维护,`tz status` 负责展示,不提供通用字段编辑。
|
||||
- `profiles.toml` 与受管 profile source 由 `tz profile` 管理;远程来源保存 URL 和实际下载路径,下载优先使用环境代理,失败后回退直连。
|
||||
- `profile list` 默认按当前 core 的 family 过滤;只有 `--all` 才显示全部 family。
|
||||
- `core.toml` 与二进制由 `tz core` 只读校验和管理;PID、锁、日志属于运行状态。
|
||||
- generated 配置由当前 family builder 生成并调用真实 core 校验;节点选择、测速、真实启停、TUN 独立开关及 shell/GNOME system proxy 已开放。
|
||||
|
||||
## 修改规则
|
||||
|
||||
1. 命令先重新读取并校验当前状态,再持有 `tz.lock` 执行修改。
|
||||
2. 文件使用同目录临时文件和原子替换;失败时保留旧状态。
|
||||
3. profile/core 在受管进程运行时拒绝 `use`、`update`、`remove` 等可能改变运行输入的操作。
|
||||
4. profile URL 只允许 HTTP(S),校验公网地址、DNS 全部结果和每次重定向;本地文件复制为受管副本。
|
||||
5. core 只接受本地目录,不接受 URL;导入成功后不自动选择、不自动启动。
|
||||
|
||||
# core 制作
|
||||
|
||||
## 目标与范围
|
||||
|
||||
TZ 当前支持统一的本地 core 包格式,用于识别和调用已经存在的 Mihomo 或 sing-box 二进制。core 包只描述运行契约,不包含 profile、用户配置、secret、PID、日志或缓存。
|
||||
|
||||
当前稳定槽位为 `mihomo` 和 `sing-box`,目录名必须与 `core.name` 相同:
|
||||
|
||||
```text
|
||||
data/cores/
|
||||
├── mihomo/
|
||||
│ ├── core.toml
|
||||
│ └── mihomo
|
||||
└── sing-box/
|
||||
├── core.toml
|
||||
└── sing-box
|
||||
```
|
||||
|
||||
## 当前 schema v1
|
||||
|
||||
`core.toml` 必须声明 schema、名称、family、版本、二进制、目标平台、配置格式、能力和命令参数。Mihomo 使用 `family = "clash"`、`format = "yaml"`,sing-box 使用 `family = "sing-box"`、`format = "json"`。命令参数只支持 `{config}` 和 `{workdir}` 占位符,由 TZ 展开。完整字段以 [`docs/core-package.md`](core-package.md) 为准。
|
||||
|
||||
```toml
|
||||
schema_version = 1
|
||||
|
||||
[core]
|
||||
name = "mihomo"
|
||||
family = "clash"
|
||||
version = "1.19.18"
|
||||
binary = "mihomo"
|
||||
os = "linux"
|
||||
arch = "x86_64"
|
||||
|
||||
[runtime]
|
||||
entrypoint = "config.yaml"
|
||||
format = "yaml"
|
||||
|
||||
[commands.start]
|
||||
args = ["-d", "{workdir}", "-f", "{config}"]
|
||||
```
|
||||
|
||||
## 当前制作和导入流程
|
||||
|
||||
1. 用户自行下载或制作二进制,在本地准备包含 `core.toml` 和可执行文件的目录。
|
||||
2. 使用 `tz core add <directory>` 导入;TZ 校验目录、manifest、平台、family、格式、二进制权限和命令占位符。
|
||||
3. 如 manifest 声明 `commands.version`,导入前执行该命令;参数按数组传递,不经过 shell。
|
||||
4. 目标名称已存在时拒绝覆盖;通过 staging 目录复制并原子重命名到 `data/cores/<name>`。
|
||||
5. 导入成功后不自动 `core use`,也不自动启动;后续用 `tz core list/info/use/remove` 管理。
|
||||
|
||||
`core remove` 在运行中拒绝,删除前检查当前选择和受管 PID,并清理该 core 的派生配置。手工复制到 `data/cores/` 也会被扫描,但不会绕过运行状态和安全校验。
|
||||
|
||||
## 当前不做
|
||||
|
||||
core 不通过 URL 安装、不负责下载更新、不覆盖正在运行的 core。远端 registry、归档校验和 core update 不在当前路线内。任意其他代理二进制也不能只凭一份 `core.toml` 接入,必须先提供对应 family 的配置 builder 和控制 adapter。
|
||||
|
||||
|
||||
## 本轮实现结果
|
||||
|
||||
- 新增 `platform/storage.rs`:`tz.lock` 非阻塞独占锁、同目录临时文件、flush/fsync、原子 rename;profile 索引和 source 使用当前用户私有权限。
|
||||
- 新增 `platform/process.rs`:统一正整数 PID、存活和僵尸状态判断,供 status、profile/core use/remove 共用。
|
||||
- 新增 `platform/network.rs`:profile URL 只允许 HTTP/HTTPS,拒绝凭据、本机、环回、私有和保留地址;DNS 全结果与重定向逐次复核,优先使用环境代理并在失败后回退直连,限制超时、重定向和响应大小,错误不泄露订阅 URL。
|
||||
- 新增 typed setting registry,完成 `setting/list/get/set/reset`;不允许任意 TOML 路径编辑,保存后明确提示需要重新 build/start。
|
||||
- 完成 profile add/list/info/use/update/remove:URL 与本地文件都变成受管副本,family 固定映射格式,运行中禁止 use/update/remove,删除不触碰用户原文件。
|
||||
- core schema v1 新增必填 os/arch,稳定槽位统一为 `mihomo`、`sing-box`。
|
||||
- 完成 core add/list/info/use/remove:手工复制仍可直接扫描,add 只做本地安全导入,version 命令不经过 shell,运行中禁止 use/remove。
|
||||
- 新增正式规范 `docs/control-interface.md`、`docs/core-package.md` 和 `examples/cores/mihomo/` 制作模板。
|
||||
|
||||
## 当前边界与下一阶段
|
||||
|
||||
当前路线已完成 config builder、节点选择与测速、受管进程启停、TUN 独立控制及 shell/GNOME system proxy。core 在线更新与其他桌面环境 adapter 留在后续阶段。
|
||||
|
||||
# v0.1 可运行闭环
|
||||
|
||||
本章覆盖当前可运行行为;前文中的阶段性设计以这里和 `docs/control-interface.md` 为准。
|
||||
|
||||
## 当前指令
|
||||
|
||||
```bash
|
||||
tz status|start|stop|restart
|
||||
tz list [keyword]
|
||||
tz node test [keyword] [--url <url>] [--timeout <ms>] [--select]
|
||||
tz tun status|on|off
|
||||
tz proxy status|on|off
|
||||
tz proxy terminal|system status|on|off
|
||||
tz proxy env|noenv [bash|zsh|fish]
|
||||
tz proxy shell-init bash|zsh|fish
|
||||
tz setting [list|get|set|reset]
|
||||
tz profile add|list|info|use|update|remove
|
||||
tz core add|list|info|use|remove
|
||||
tz config build|check|show
|
||||
tz completion generate bash|zsh|fish
|
||||
```
|
||||
|
||||
`profile update` 不接名称,一次更新全部远程 profile。`profile list` 默认只看当前 core family,只有 `--all` 跨 family。profile/core/node 的 list 在终端中均可编号选择并以 `*` 标记当前项;`use` 保留给脚本和显式操作。列表保持简洁,路径和来源等详情由 `info` 或对应文件提供。
|
||||
|
||||
```text
|
||||
nano_clash family=clash
|
||||
* mihomo version=1.19.18 family=clash
|
||||
```
|
||||
|
||||
Mihomo 读取 Clash 配置,所以其 family 必须为 `clash`;sing-box 才使用 `family=sing-box`。
|
||||
|
||||
## 简洁指令
|
||||
|
||||
```bash
|
||||
tz # status,并测速当前节点
|
||||
tz on # 使用上次的可用 profile 启动并显示 status
|
||||
tz off | tz end # stop
|
||||
tz -l [keyword] # 节点测速、延迟排序、搜索和选择
|
||||
tz select # 当前 family 的 profile 列表和选择
|
||||
```
|
||||
|
||||
## 快捷键
|
||||
|
||||
```bash
|
||||
tz st # status
|
||||
tz r # restart
|
||||
tz set # setting
|
||||
tz p # profile
|
||||
tz c # core
|
||||
tz cfg # config
|
||||
tz comp # completion
|
||||
tz p a|l|i|u|up|rm
|
||||
tz c a|l|i|u|rm
|
||||
```
|
||||
|
||||
Tab 提示由 completion generator 提供。节点选择会写入 profile state 并在下次启动后恢复。`tz -l` 和 `node test` 都走 controller delay API,最多 8 路并发、按延迟排序并缓存最新结果;`--select` 选择最快节点。`tz` 对当前节点实时测速,失败时才显示缓存结果。
|
||||
|
||||
Mihomo 标准 core 包携带 `Country.mmdb` 与 `GeoSite.dat`。Clash profile 实际引用 GEOIP/GEOSITE 时,builder 按需复制到该 core 的独立 runtime 工作目录,避免首次校验因 GitHub 下载受阻而误报超时;自制 core 包缺失资源时直接提示用户启用其他代理或补齐 core 包。`tz on/start` 始终使用当前 family 上次选择且 source 可用的 profile,启动后立即显示含节点测速的 status。
|
||||
|
||||
profile 下载的 User-Agent 按 family 选择:Clash 对齐 `mh` 的 Mihomo provider User-Agent,sing-box 对齐 `sb`。同一订阅 URL 若按客户端返回 Clash YAML 或 sing-box JSON,`add` 与批量 `update` 都能取得对应 family 的原生格式;`--family` 仍只负责选择契约,不做跨格式转换。
|
||||
|
||||
## Proxy、TUN 与权限
|
||||
|
||||
- `proxy env/noenv` 输出可由当前 shell `eval/source` 的环境命令;`shell-init` 为 Bash、Zsh、Fish 生成持久 hook。
|
||||
- `proxy system` 按 mh/sb 的当前参考路线使用 GNOME `gsettings`,读取 runtime/capability 端口并把 bypass 转成 ignore-hosts;开启前备份原桌面设置,关闭或失败时恢复。
|
||||
- `tun on/off` 检查 core capability、`/dev/net/tun` 和 `CAP_NET_ADMIN`;运行中切换会重启,失败回滚,不自动执行 sudo/setcap。
|
||||
|
||||
配置生成已通过 Mihomo 1.19.18 和 sing-box 1.13.14 的真实 check。隔离测试覆盖 sing-box 的 start/status/list/select/stop,并继续覆盖 proxy 环境输出、TUN 状态和节点测速错误/超时路径。
|
||||
Loading…
Add table
Add a link
Reference in a new issue