mihomo-py 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mihomo_py-0.1.0/.gitignore +7 -0
- mihomo_py-0.1.0/PKG-INFO +178 -0
- mihomo_py-0.1.0/README.md +161 -0
- mihomo_py-0.1.0/docs/README.md +15 -0
- mihomo_py-0.1.0/docs/geodata.md +19 -0
- mihomo_py-0.1.0/docs/packaging.md +79 -0
- mihomo_py-0.1.0/docs/tui.md +51 -0
- mihomo_py-0.1.0/hatch_build.py +42 -0
- mihomo_py-0.1.0/pyproject.toml +37 -0
- mihomo_py-0.1.0/scripts/check_install.py +127 -0
- mihomo_py-0.1.0/scripts/restore_vendor.py +36 -0
- mihomo_py-0.1.0/src/mihomo_py/__init__.py +3 -0
- mihomo_py-0.1.0/src/mihomo_py/__main__.py +3 -0
- mihomo_py-0.1.0/src/mihomo_py/_vendor/NOTICE.txt +20 -0
- mihomo_py-0.1.0/src/mihomo_py/_vendor/aarch64/mihomo +0 -0
- mihomo_py-0.1.0/src/mihomo_py/_vendor/geodata/ASN.mmdb +0 -0
- mihomo_py-0.1.0/src/mihomo_py/_vendor/geodata/country.mmdb +0 -0
- mihomo_py-0.1.0/src/mihomo_py/_vendor/geodata/geoip.dat +0 -0
- mihomo_py-0.1.0/src/mihomo_py/_vendor/geodata/geosite.dat +43243 -0
- mihomo_py-0.1.0/src/mihomo_py/_vendor/licenses/meta-rules-dat.txt +674 -0
- mihomo_py-0.1.0/src/mihomo_py/_vendor/licenses/mihomo.txt +674 -0
- mihomo_py-0.1.0/src/mihomo_py/_vendor/manifest.json +64 -0
- mihomo_py-0.1.0/src/mihomo_py/_vendor/x86_64/mihomo +4 -0
- mihomo_py-0.1.0/src/mihomo_py/bundle.py +20 -0
- mihomo_py-0.1.0/src/mihomo_py/cli.py +382 -0
- mihomo_py-0.1.0/src/mihomo_py/config.py +161 -0
- mihomo_py-0.1.0/src/mihomo_py/controller.py +155 -0
- mihomo_py-0.1.0/src/mihomo_py/download.py +48 -0
- mihomo_py-0.1.0/src/mihomo_py/engine.py +393 -0
- mihomo_py-0.1.0/src/mihomo_py/errors.py +15 -0
- mihomo_py-0.1.0/src/mihomo_py/geodata.py +130 -0
- mihomo_py-0.1.0/src/mihomo_py/manager.py +150 -0
- mihomo_py-0.1.0/src/mihomo_py/pidfd.py +54 -0
- mihomo_py-0.1.0/src/mihomo_py/store.py +91 -0
- mihomo_py-0.1.0/src/mihomo_py/tui.py +1006 -0
- mihomo_py-0.1.0/src/mihomo_py/tui.tcss +82 -0
- mihomo_py-0.1.0/tests/conftest.py +109 -0
- mihomo_py-0.1.0/tests/test_bundle.py +101 -0
- mihomo_py-0.1.0/tests/test_cli.py +317 -0
- mihomo_py-0.1.0/tests/test_controller.py +125 -0
- mihomo_py-0.1.0/tests/test_download.py +114 -0
- mihomo_py-0.1.0/tests/test_geodata.py +226 -0
- mihomo_py-0.1.0/tests/test_integration.py +253 -0
- mihomo_py-0.1.0/tests/test_pidfd.py +78 -0
- mihomo_py-0.1.0/tests/test_tui.py +569 -0
- mihomo_py-0.1.0/tests/test_tui_terminal.py +86 -0
mihomo_py-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: mihomo-py
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A subscription and process manager for mihomo on Linux servers
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Requires-Dist: click<9,>=8.1
|
|
7
|
+
Requires-Dist: maxminddb<4,>=3
|
|
8
|
+
Requires-Dist: pyyaml<7,>=6
|
|
9
|
+
Requires-Dist: textual<9,>=8.2.8
|
|
10
|
+
Provides-Extra: dev
|
|
11
|
+
Requires-Dist: build<2,>=1.2; extra == 'dev'
|
|
12
|
+
Requires-Dist: pytest-asyncio<2,>=1.4; extra == 'dev'
|
|
13
|
+
Requires-Dist: pytest<9,>=8; extra == 'dev'
|
|
14
|
+
Requires-Dist: ruff<1,>=0.9; extra == 'dev'
|
|
15
|
+
Requires-Dist: uv<1,>=0.7; extra == 'dev'
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# mihomo-py
|
|
19
|
+
|
|
20
|
+
面向 Linux 服务器的 mihomo CLI / TUI 客户端,支持订阅管理、节点切换和延迟测试、配置校验、独立本机设置及后台进程管理。
|
|
21
|
+
|
|
22
|
+
需要 Python 3.11+、Linux(支持 pidfd 的内核,5.3+),支持 x86_64 / aarch64。支持系统 Python 和 Conda:Python 缺少原生 pidfd 接口时,通过标准库 ctypes 调用相同的 Linux 系统接口,不需要编译器或切换 Python;容器须允许这些系统调用。已用系统 Python 3.12.3、Conda Python 3.12.4、Textual 8.2.8、mihomo v1.19.19 验证(x86_64)。发行包内置 mihomo 内核与默认地理数据库;systemd 和 TUN 是后续阶段。
|
|
23
|
+
|
|
24
|
+
## 安装与开始使用
|
|
25
|
+
|
|
26
|
+
发行包发布并同步到所用镜像后,在当前 Python 环境(包括 Conda)中安装:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
python -m pip install mihomo-py
|
|
30
|
+
mihomo-py
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
或使用独立虚拟环境:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
uv venv --python /usr/bin/python3
|
|
37
|
+
uv pip install -e .
|
|
38
|
+
source .venv/bin/activate
|
|
39
|
+
mihomo-py # 进入 TUI,也可使用 mihomo-py tui
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
也可以使用子命令:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
mihomo-py --help
|
|
46
|
+
|
|
47
|
+
# 导入本地完整的 Clash/Mihomo YAML 配置
|
|
48
|
+
mihomo-py sub add work ./config.yaml
|
|
49
|
+
mihomo-py sub use work
|
|
50
|
+
mihomo-py core start
|
|
51
|
+
mihomo-py core status
|
|
52
|
+
mihomo-py core logs --follow
|
|
53
|
+
mihomo-py core stop
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
安装只需要可用的 pip 镜像源:内核和默认 GEO 数据已包含在 wheel / 源码发行包中,安装、构建和首次准备这些资源不访问 GitHub 或其他下载站。镜像需要同步本项目的发行包及 Python 依赖。默认使用包内内核;如需覆盖,设置 `MIHOMO_PY_BINARY=/path/to/mihomo` 或使用全局选项 `--core-binary`(显式传入 `mihomo` 才会查找 PATH)。
|
|
57
|
+
|
|
58
|
+
远程订阅、自定义 `geox-url`、远程 rule/proxy providers 不属于内置资源,仍需可达或提前提供本地文件。默认 GEO 自动更新关闭,避免启动后触发外网更新。详见 [离线安装与发行](docs/packaging.md)。
|
|
59
|
+
|
|
60
|
+
远程订阅支持 HTTP(S)。可以从 stdin 输入地址,避免把令牌放进命令历史:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
read -rs 'SUB_URL?订阅 URL: '
|
|
64
|
+
printf '%s\n' "$SUB_URL" | mihomo-py sub add work -
|
|
65
|
+
unset SUB_URL
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
上例使用 zsh 的 `read` 语法;bash 可使用 `read -rs -p '订阅 URL: ' SUB_URL`。
|
|
69
|
+
也可以直接 `mihomo-py sub add work 'https://example.com/sub?token=…'`。
|
|
70
|
+
支持完整 YAML 配置,不转换 Base64 节点列表或 `ss://` 等单节点链接。
|
|
71
|
+
|
|
72
|
+
## 终端界面
|
|
73
|
+
|
|
74
|
+
在交互终端直接运行 `mihomo-py`,或显式执行 `mihomo-py tui`。界面采用克制的深色设计,自适应常见终端尺寸;建议至少 80×24,支持鼠标、键盘与 `NO_COLOR`。
|
|
75
|
+
|
|
76
|
+
- **订阅**:添加、使用、更新、更换来源及确认删除,提供表单校验和下载 / 校验进度。
|
|
77
|
+
- **节点**:选择代理组、搜索、切换手动组节点及单节点测速;刷新保留列表阅读位置。
|
|
78
|
+
- **日志**:最近 200 行,支持自动跟随、暂停阅读和恢复跟随。
|
|
79
|
+
|
|
80
|
+
`1/2/3` 切页,`/` 搜索节点,`i` 查看详情,`?` 查看快捷键,`Ctrl-R` 刷新,`Ctrl-A` 添加订阅。输入框保留原生编辑快捷键。打开界面不会自动启动内核,退出会保留运行中的内核。
|
|
81
|
+
|
|
82
|
+
完整操作与错误处理说明见 [终端界面文档](docs/tui.md),其他文档见 [文档导航](docs/README.md)。
|
|
83
|
+
|
|
84
|
+
## 命令
|
|
85
|
+
|
|
86
|
+
全局选项放在子命令前,例如 `mihomo-py --json sub list`。
|
|
87
|
+
|
|
88
|
+
| 命令 | 行为 |
|
|
89
|
+
|---|---|
|
|
90
|
+
| `tui` | 打开交互终端界面 |
|
|
91
|
+
| `sub add NAME SOURCE` | 读取来源、内核校验成功后保存;不会自动选择或启动 |
|
|
92
|
+
| `sub list` | 显示当前选择、来源和更新时间;隐藏 URL 路径及令牌 |
|
|
93
|
+
| `sub set NAME SOURCE` | 修改来源并刷新缓存;失败保留旧来源和配置 |
|
|
94
|
+
| `sub update [NAME]` | 重新读取来源;省略名称时更新当前订阅 |
|
|
95
|
+
| `sub use NAME` | 选择已缓存订阅;运行中则校验并重启,停止时只保存选择 |
|
|
96
|
+
| `sub remove NAME --yes` | 删除订阅记录和缓存原文;不能删除运行中的订阅 |
|
|
97
|
+
| `config show` | 查看本机设置 |
|
|
98
|
+
| `config set --proxy-port 17897 --controller-port 19090 --mode rule` | 修改设置;运行中自动重启生效 |
|
|
99
|
+
| `core start` | 从当前缓存后台启动;已健康运行则不重复启动 |
|
|
100
|
+
| `core restart` | 校验后重启;不刷新订阅 |
|
|
101
|
+
| `core stop` | 停止本实例;重复执行安全 |
|
|
102
|
+
| `core status` | 显示 PID、健康状态、已选订阅、实际运行订阅和设置 |
|
|
103
|
+
| `core logs [--lines 100] [--follow]` | 查看内核日志 |
|
|
104
|
+
| `node list [--group GROUP]` | 列出代理组,或指定组的节点、选择和最近延迟 |
|
|
105
|
+
| `node use NAME --group GROUP` | 按完整名称切换手动组节点,无需重启 |
|
|
106
|
+
| `node test NAME [--url URL] [--timeout-ms 5000]` | 测量一个节点的 HTTP 延迟,默认超时 5 秒 |
|
|
107
|
+
|
|
108
|
+
所有修改命令支持 `--dry-run`,输出 JSON 操作计划,退出码为 10。它不下载、不校验内核配置、不创建目录,因此只表示操作意图,不保证实际执行成功。终端删除会询问确认;管道中必须明确传入 `--yes`。
|
|
109
|
+
|
|
110
|
+
## 配置与数据
|
|
111
|
+
|
|
112
|
+
默认目录为 `${XDG_CONFIG_HOME:-~/.config}/mihomo-py`;空或相对路径的 `XDG_CONFIG_HOME` 使用 `~/.config`。可通过 `MIHOMO_PY_HOME` 或 `--data-dir` 覆盖。
|
|
113
|
+
|
|
114
|
+
```text
|
|
115
|
+
state.json # 订阅来源、缓存 YAML 原文、当前选择、本机设置(原子替换)
|
|
116
|
+
runtime.yaml # 由缓存原文与本机设置生成的实际配置
|
|
117
|
+
process.json # PID、Linux 启动标识、命令行、实际运行设置
|
|
118
|
+
core.log # 内核日志,追加写入
|
|
119
|
+
validation.log # 最近一次内核校验失败或超时的详细输出
|
|
120
|
+
geodata/ # 可选:手动放置离线地理数据库,供新订阅复制使用
|
|
121
|
+
core-data/ # 按订阅隔离的内核数据、provider 和节点选择缓存
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
目录默认权限 0700;客户端写入的状态、配置和日志文件为 0600。缓存包含订阅凭证,列举订阅时仅展示脱敏地址。
|
|
125
|
+
|
|
126
|
+
本机设置默认代理端口 `7897`、管理端口 `9090`、路由模式 `rule`。模式可选 `rule/global/direct`。HTTP/SOCKS 共用代理端口,管理接口使用随机密钥;两者只监听本机。当前固定禁用订阅携带的其他入站端口、自定义 listeners/tunnels、TUN、DNS/DoH 监听、iptables 接管、NTP 与外部 UI,保留节点、代理组、规则、DNS 解析配置,并启用节点选择缓存。代理端口不启用用户名密码验证。后续阶段再提供显式的入站和网络接管配置。
|
|
127
|
+
|
|
128
|
+
订阅原文不会被本机设置改写;更新后重新合成运行配置。下载默认直连,不使用 `HTTP_PROXY/HTTPS_PROXY`;上限 8 MiB、网络操作超时 20 秒。HTTPS 连接在 TCP 或 TLS 失败时尝试域名的其他地址,每个连接/握手阶段最多等待 5 秒,地址尝试共用 20 秒预算;始终校验证书与原始域名。订阅下载超时自动重试一次,并在 TUI 中提示。使用 `mihomo -t` 校验合成配置;默认 GEO 数据由包内资源提供;订阅自定义的数据和规则源仍可能触发下载。内核校验/启动超时可用全局 `--timeout 60` 调整。
|
|
129
|
+
|
|
130
|
+
校验前会将缺少的地理数据库从本客户端的 `geodata/`、已有 mihomo 的数据目录(通常为 `~/.config/mihomo`)、包内快照按此优先级复制到订阅目录。支持 MMDB(`country.mmdb` / `geoip.db` / `geoip.metadb`)、`geoip.dat`、`geosite.dat`、`ASN.mmdb`,文件名不区分大小写。可用 `MIHOMO_PY_GEODATA_DIR=/path/to/geodata` 显式指定唯一来源,也可用它提供自定义 `geox-url` 对应的离线数据。只复制这些数据库,不复制订阅、provider 或节点选择缓存;保留目标已有有效文件。订阅显式配置 `geox-url` 时,相应数据库不会被默认快照替代。空文件和无效 MMDB 会被剔除后重新准备,最终由真实内核校验。校验超时请查看 `validation.log`,并检查自定义资源是否可达。
|
|
131
|
+
|
|
132
|
+
已有残缺 MMDB 的恢复、校验失败回滚和自定义来源隔离见 [地理数据说明](docs/geodata.md)。
|
|
133
|
+
|
|
134
|
+
相对的 provider/规则/GEO 文件路径以对应的 `core-data/<订阅标识>/` 为基准,导入本地 YAML 不会复制其旁边的依赖文件。建议使用内嵌节点/规则或远程 providers。`sub remove` 删除缓存原文和来源,但保留内核派生数据及历史日志,便于排错。
|
|
135
|
+
|
|
136
|
+
运行中更新、切换订阅或修改本机设置会短暂中断连接:校验成功后重启;新实例启动失败时尝试恢复旧实例,失败则明确报告。状态文件在成功启动后提交;普通启动失败保留旧订阅记录。文件内容先 fsync,再通过 rename 原子替换;不承诺目录项在断电后的持久化。进程和文件无法形成跨资源原子事务,断电或强制终止仍可能使运行状态与选择不同;`core status` 分别展示两者,`core start` 重新应用已保存选择。
|
|
137
|
+
|
|
138
|
+
进程管理核对 PID、启动时间、启动标识及命令行,并通过 pidfd 发送信号;不使用 `pkill`。不同 `--data-dir` 可运行独立实例,但必须设置不同端口。默认不配置 systemd,也不修改 shell 代理环境。
|
|
139
|
+
|
|
140
|
+
## 脚本与错误处理
|
|
141
|
+
|
|
142
|
+
子命令在交互终端默认表格/文本,管道默认 JSON;可显式 `--format table` 或 `--json`。不带子命令时,交互终端进入 TUI,管道或显式指定输出格式时输出状态;`tui` 子命令要求交互终端。数据写 stdout,结构化错误写 stderr;普通子命令输出无 ANSI 色码。日志可能包含内核返回的地址,`core logs --follow` 在 JSON 模式下逐行输出 NDJSON。
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
mihomo-py --json sub list
|
|
146
|
+
mihomo-py --json core status
|
|
147
|
+
mihomo-py config set --mode direct --dry-run
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
| 退出码 | 含义 |
|
|
151
|
+
|---|---|
|
|
152
|
+
| 0 | 成功 |
|
|
153
|
+
| 1 | IO、下载、启动或其他运行错误 |
|
|
154
|
+
| 2 | 参数或配置错误 |
|
|
155
|
+
| 3 | 订阅、内核或日志不存在 |
|
|
156
|
+
| 4 | 权限不足 |
|
|
157
|
+
| 5 | 已存在、资源使用中、端口冲突或并发修改 |
|
|
158
|
+
| 10 | 已输出 dry-run 计划,未执行 |
|
|
159
|
+
| 130 | 用户取消 |
|
|
160
|
+
|
|
161
|
+
失败示例:`{"error":"not_found","message":"…","suggestion":"…","retryable":false}`。`--help` 与 `--version` 始终输出文本。
|
|
162
|
+
|
|
163
|
+
## 开发与验证
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
pip install -e '.[dev]'
|
|
167
|
+
pytest
|
|
168
|
+
ruff check .
|
|
169
|
+
python -m build --installer uv
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
真实内核测试默认使用包内 mihomo(也支持 `MIHOMO_TEST_BINARY`);使用临时目录、空闲端口、直连规则和本地 HTTP 测速目标,不读取现有订阅,不访问机场服务,不改变现有代理。覆盖真实节点 API、选择持久化、TUI 订阅/内核/节点交互,以及 PTY 中的默认入口和退出。发行包验证必须运行真实内核测试。
|
|
173
|
+
|
|
174
|
+
本地 TLS 下载回归测试需要 `openssl` 命令来生成临时测试证书;运行客户端本身无需此命令。
|
|
175
|
+
|
|
176
|
+
配置字段参考 [mihomo 全局配置](https://wiki.metacubex.one/config/general/)。
|
|
177
|
+
|
|
178
|
+
文档目录见 [docs/README.md](docs/README.md)。
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# mihomo-py
|
|
2
|
+
|
|
3
|
+
面向 Linux 服务器的 mihomo CLI / TUI 客户端,支持订阅管理、节点切换和延迟测试、配置校验、独立本机设置及后台进程管理。
|
|
4
|
+
|
|
5
|
+
需要 Python 3.11+、Linux(支持 pidfd 的内核,5.3+),支持 x86_64 / aarch64。支持系统 Python 和 Conda:Python 缺少原生 pidfd 接口时,通过标准库 ctypes 调用相同的 Linux 系统接口,不需要编译器或切换 Python;容器须允许这些系统调用。已用系统 Python 3.12.3、Conda Python 3.12.4、Textual 8.2.8、mihomo v1.19.19 验证(x86_64)。发行包内置 mihomo 内核与默认地理数据库;systemd 和 TUN 是后续阶段。
|
|
6
|
+
|
|
7
|
+
## 安装与开始使用
|
|
8
|
+
|
|
9
|
+
发行包发布并同步到所用镜像后,在当前 Python 环境(包括 Conda)中安装:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
python -m pip install mihomo-py
|
|
13
|
+
mihomo-py
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
或使用独立虚拟环境:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
uv venv --python /usr/bin/python3
|
|
20
|
+
uv pip install -e .
|
|
21
|
+
source .venv/bin/activate
|
|
22
|
+
mihomo-py # 进入 TUI,也可使用 mihomo-py tui
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
也可以使用子命令:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
mihomo-py --help
|
|
29
|
+
|
|
30
|
+
# 导入本地完整的 Clash/Mihomo YAML 配置
|
|
31
|
+
mihomo-py sub add work ./config.yaml
|
|
32
|
+
mihomo-py sub use work
|
|
33
|
+
mihomo-py core start
|
|
34
|
+
mihomo-py core status
|
|
35
|
+
mihomo-py core logs --follow
|
|
36
|
+
mihomo-py core stop
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
安装只需要可用的 pip 镜像源:内核和默认 GEO 数据已包含在 wheel / 源码发行包中,安装、构建和首次准备这些资源不访问 GitHub 或其他下载站。镜像需要同步本项目的发行包及 Python 依赖。默认使用包内内核;如需覆盖,设置 `MIHOMO_PY_BINARY=/path/to/mihomo` 或使用全局选项 `--core-binary`(显式传入 `mihomo` 才会查找 PATH)。
|
|
40
|
+
|
|
41
|
+
远程订阅、自定义 `geox-url`、远程 rule/proxy providers 不属于内置资源,仍需可达或提前提供本地文件。默认 GEO 自动更新关闭,避免启动后触发外网更新。详见 [离线安装与发行](docs/packaging.md)。
|
|
42
|
+
|
|
43
|
+
远程订阅支持 HTTP(S)。可以从 stdin 输入地址,避免把令牌放进命令历史:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
read -rs 'SUB_URL?订阅 URL: '
|
|
47
|
+
printf '%s\n' "$SUB_URL" | mihomo-py sub add work -
|
|
48
|
+
unset SUB_URL
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
上例使用 zsh 的 `read` 语法;bash 可使用 `read -rs -p '订阅 URL: ' SUB_URL`。
|
|
52
|
+
也可以直接 `mihomo-py sub add work 'https://example.com/sub?token=…'`。
|
|
53
|
+
支持完整 YAML 配置,不转换 Base64 节点列表或 `ss://` 等单节点链接。
|
|
54
|
+
|
|
55
|
+
## 终端界面
|
|
56
|
+
|
|
57
|
+
在交互终端直接运行 `mihomo-py`,或显式执行 `mihomo-py tui`。界面采用克制的深色设计,自适应常见终端尺寸;建议至少 80×24,支持鼠标、键盘与 `NO_COLOR`。
|
|
58
|
+
|
|
59
|
+
- **订阅**:添加、使用、更新、更换来源及确认删除,提供表单校验和下载 / 校验进度。
|
|
60
|
+
- **节点**:选择代理组、搜索、切换手动组节点及单节点测速;刷新保留列表阅读位置。
|
|
61
|
+
- **日志**:最近 200 行,支持自动跟随、暂停阅读和恢复跟随。
|
|
62
|
+
|
|
63
|
+
`1/2/3` 切页,`/` 搜索节点,`i` 查看详情,`?` 查看快捷键,`Ctrl-R` 刷新,`Ctrl-A` 添加订阅。输入框保留原生编辑快捷键。打开界面不会自动启动内核,退出会保留运行中的内核。
|
|
64
|
+
|
|
65
|
+
完整操作与错误处理说明见 [终端界面文档](docs/tui.md),其他文档见 [文档导航](docs/README.md)。
|
|
66
|
+
|
|
67
|
+
## 命令
|
|
68
|
+
|
|
69
|
+
全局选项放在子命令前,例如 `mihomo-py --json sub list`。
|
|
70
|
+
|
|
71
|
+
| 命令 | 行为 |
|
|
72
|
+
|---|---|
|
|
73
|
+
| `tui` | 打开交互终端界面 |
|
|
74
|
+
| `sub add NAME SOURCE` | 读取来源、内核校验成功后保存;不会自动选择或启动 |
|
|
75
|
+
| `sub list` | 显示当前选择、来源和更新时间;隐藏 URL 路径及令牌 |
|
|
76
|
+
| `sub set NAME SOURCE` | 修改来源并刷新缓存;失败保留旧来源和配置 |
|
|
77
|
+
| `sub update [NAME]` | 重新读取来源;省略名称时更新当前订阅 |
|
|
78
|
+
| `sub use NAME` | 选择已缓存订阅;运行中则校验并重启,停止时只保存选择 |
|
|
79
|
+
| `sub remove NAME --yes` | 删除订阅记录和缓存原文;不能删除运行中的订阅 |
|
|
80
|
+
| `config show` | 查看本机设置 |
|
|
81
|
+
| `config set --proxy-port 17897 --controller-port 19090 --mode rule` | 修改设置;运行中自动重启生效 |
|
|
82
|
+
| `core start` | 从当前缓存后台启动;已健康运行则不重复启动 |
|
|
83
|
+
| `core restart` | 校验后重启;不刷新订阅 |
|
|
84
|
+
| `core stop` | 停止本实例;重复执行安全 |
|
|
85
|
+
| `core status` | 显示 PID、健康状态、已选订阅、实际运行订阅和设置 |
|
|
86
|
+
| `core logs [--lines 100] [--follow]` | 查看内核日志 |
|
|
87
|
+
| `node list [--group GROUP]` | 列出代理组,或指定组的节点、选择和最近延迟 |
|
|
88
|
+
| `node use NAME --group GROUP` | 按完整名称切换手动组节点,无需重启 |
|
|
89
|
+
| `node test NAME [--url URL] [--timeout-ms 5000]` | 测量一个节点的 HTTP 延迟,默认超时 5 秒 |
|
|
90
|
+
|
|
91
|
+
所有修改命令支持 `--dry-run`,输出 JSON 操作计划,退出码为 10。它不下载、不校验内核配置、不创建目录,因此只表示操作意图,不保证实际执行成功。终端删除会询问确认;管道中必须明确传入 `--yes`。
|
|
92
|
+
|
|
93
|
+
## 配置与数据
|
|
94
|
+
|
|
95
|
+
默认目录为 `${XDG_CONFIG_HOME:-~/.config}/mihomo-py`;空或相对路径的 `XDG_CONFIG_HOME` 使用 `~/.config`。可通过 `MIHOMO_PY_HOME` 或 `--data-dir` 覆盖。
|
|
96
|
+
|
|
97
|
+
```text
|
|
98
|
+
state.json # 订阅来源、缓存 YAML 原文、当前选择、本机设置(原子替换)
|
|
99
|
+
runtime.yaml # 由缓存原文与本机设置生成的实际配置
|
|
100
|
+
process.json # PID、Linux 启动标识、命令行、实际运行设置
|
|
101
|
+
core.log # 内核日志,追加写入
|
|
102
|
+
validation.log # 最近一次内核校验失败或超时的详细输出
|
|
103
|
+
geodata/ # 可选:手动放置离线地理数据库,供新订阅复制使用
|
|
104
|
+
core-data/ # 按订阅隔离的内核数据、provider 和节点选择缓存
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
目录默认权限 0700;客户端写入的状态、配置和日志文件为 0600。缓存包含订阅凭证,列举订阅时仅展示脱敏地址。
|
|
108
|
+
|
|
109
|
+
本机设置默认代理端口 `7897`、管理端口 `9090`、路由模式 `rule`。模式可选 `rule/global/direct`。HTTP/SOCKS 共用代理端口,管理接口使用随机密钥;两者只监听本机。当前固定禁用订阅携带的其他入站端口、自定义 listeners/tunnels、TUN、DNS/DoH 监听、iptables 接管、NTP 与外部 UI,保留节点、代理组、规则、DNS 解析配置,并启用节点选择缓存。代理端口不启用用户名密码验证。后续阶段再提供显式的入站和网络接管配置。
|
|
110
|
+
|
|
111
|
+
订阅原文不会被本机设置改写;更新后重新合成运行配置。下载默认直连,不使用 `HTTP_PROXY/HTTPS_PROXY`;上限 8 MiB、网络操作超时 20 秒。HTTPS 连接在 TCP 或 TLS 失败时尝试域名的其他地址,每个连接/握手阶段最多等待 5 秒,地址尝试共用 20 秒预算;始终校验证书与原始域名。订阅下载超时自动重试一次,并在 TUI 中提示。使用 `mihomo -t` 校验合成配置;默认 GEO 数据由包内资源提供;订阅自定义的数据和规则源仍可能触发下载。内核校验/启动超时可用全局 `--timeout 60` 调整。
|
|
112
|
+
|
|
113
|
+
校验前会将缺少的地理数据库从本客户端的 `geodata/`、已有 mihomo 的数据目录(通常为 `~/.config/mihomo`)、包内快照按此优先级复制到订阅目录。支持 MMDB(`country.mmdb` / `geoip.db` / `geoip.metadb`)、`geoip.dat`、`geosite.dat`、`ASN.mmdb`,文件名不区分大小写。可用 `MIHOMO_PY_GEODATA_DIR=/path/to/geodata` 显式指定唯一来源,也可用它提供自定义 `geox-url` 对应的离线数据。只复制这些数据库,不复制订阅、provider 或节点选择缓存;保留目标已有有效文件。订阅显式配置 `geox-url` 时,相应数据库不会被默认快照替代。空文件和无效 MMDB 会被剔除后重新准备,最终由真实内核校验。校验超时请查看 `validation.log`,并检查自定义资源是否可达。
|
|
114
|
+
|
|
115
|
+
已有残缺 MMDB 的恢复、校验失败回滚和自定义来源隔离见 [地理数据说明](docs/geodata.md)。
|
|
116
|
+
|
|
117
|
+
相对的 provider/规则/GEO 文件路径以对应的 `core-data/<订阅标识>/` 为基准,导入本地 YAML 不会复制其旁边的依赖文件。建议使用内嵌节点/规则或远程 providers。`sub remove` 删除缓存原文和来源,但保留内核派生数据及历史日志,便于排错。
|
|
118
|
+
|
|
119
|
+
运行中更新、切换订阅或修改本机设置会短暂中断连接:校验成功后重启;新实例启动失败时尝试恢复旧实例,失败则明确报告。状态文件在成功启动后提交;普通启动失败保留旧订阅记录。文件内容先 fsync,再通过 rename 原子替换;不承诺目录项在断电后的持久化。进程和文件无法形成跨资源原子事务,断电或强制终止仍可能使运行状态与选择不同;`core status` 分别展示两者,`core start` 重新应用已保存选择。
|
|
120
|
+
|
|
121
|
+
进程管理核对 PID、启动时间、启动标识及命令行,并通过 pidfd 发送信号;不使用 `pkill`。不同 `--data-dir` 可运行独立实例,但必须设置不同端口。默认不配置 systemd,也不修改 shell 代理环境。
|
|
122
|
+
|
|
123
|
+
## 脚本与错误处理
|
|
124
|
+
|
|
125
|
+
子命令在交互终端默认表格/文本,管道默认 JSON;可显式 `--format table` 或 `--json`。不带子命令时,交互终端进入 TUI,管道或显式指定输出格式时输出状态;`tui` 子命令要求交互终端。数据写 stdout,结构化错误写 stderr;普通子命令输出无 ANSI 色码。日志可能包含内核返回的地址,`core logs --follow` 在 JSON 模式下逐行输出 NDJSON。
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
mihomo-py --json sub list
|
|
129
|
+
mihomo-py --json core status
|
|
130
|
+
mihomo-py config set --mode direct --dry-run
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
| 退出码 | 含义 |
|
|
134
|
+
|---|---|
|
|
135
|
+
| 0 | 成功 |
|
|
136
|
+
| 1 | IO、下载、启动或其他运行错误 |
|
|
137
|
+
| 2 | 参数或配置错误 |
|
|
138
|
+
| 3 | 订阅、内核或日志不存在 |
|
|
139
|
+
| 4 | 权限不足 |
|
|
140
|
+
| 5 | 已存在、资源使用中、端口冲突或并发修改 |
|
|
141
|
+
| 10 | 已输出 dry-run 计划,未执行 |
|
|
142
|
+
| 130 | 用户取消 |
|
|
143
|
+
|
|
144
|
+
失败示例:`{"error":"not_found","message":"…","suggestion":"…","retryable":false}`。`--help` 与 `--version` 始终输出文本。
|
|
145
|
+
|
|
146
|
+
## 开发与验证
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
pip install -e '.[dev]'
|
|
150
|
+
pytest
|
|
151
|
+
ruff check .
|
|
152
|
+
python -m build --installer uv
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
真实内核测试默认使用包内 mihomo(也支持 `MIHOMO_TEST_BINARY`);使用临时目录、空闲端口、直连规则和本地 HTTP 测速目标,不读取现有订阅,不访问机场服务,不改变现有代理。覆盖真实节点 API、选择持久化、TUI 订阅/内核/节点交互,以及 PTY 中的默认入口和退出。发行包验证必须运行真实内核测试。
|
|
156
|
+
|
|
157
|
+
本地 TLS 下载回归测试需要 `openssl` 命令来生成临时测试证书;运行客户端本身无需此命令。
|
|
158
|
+
|
|
159
|
+
配置字段参考 [mihomo 全局配置](https://wiki.metacubex.one/config/general/)。
|
|
160
|
+
|
|
161
|
+
文档目录见 [docs/README.md](docs/README.md)。
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# 项目文档
|
|
2
|
+
|
|
3
|
+
使用方法见 [项目 README](../README.md)。
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
docs/
|
|
7
|
+
├── README.md # 文档索引
|
|
8
|
+
├── geodata.md # 地理数据库、自定义来源与失败重试
|
|
9
|
+
├── packaging.md # 内置资源、离线安装与发行验证
|
|
10
|
+
└── tui.md # 终端界面
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
- [终端界面与键盘操作](tui.md)
|
|
14
|
+
- [地理数据库与失败重试](geodata.md)
|
|
15
|
+
- [离线安装与发行验证](packaging.md)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# 地理数据库与失败重试
|
|
2
|
+
|
|
3
|
+
添加、更新订阅时,客户端先准备 GEO 数据,再调用真实 mihomo 校验配置。订阅下载完成不代表 GEO 数据或远程规则已就绪;校验失败详情保存在实例目录的 `validation.log`,订阅不会保存。
|
|
4
|
+
|
|
5
|
+
## 已有残缺文件
|
|
6
|
+
|
|
7
|
+
复制前使用 MaxMind 读取器检查 MMDB 和 ASN 数据库能否打开,忽略损坏的来源文件,并替换目标中的残缺文件。这样,上次下载超时留下的同名 MMDB 不会阻止客户端复制可用的本地缓存。内核校验结束后会再次检查 MMDB/ASN,防止内核下载到无效内容却返回成功。DAT 文件在复制前检查非空,内容由 mihomo 校验。
|
|
8
|
+
|
|
9
|
+
校验开始前备份该目录中已知的 GEO 文件;失败或超时时恢复原文件,删除本次创建的 GEO 文件。规则 provider 和 `cache.db` 不在这个事务中。强制杀死客户端或断电不保证回滚;下次重试仍会检查 MMDB 是否可读。
|
|
10
|
+
|
|
11
|
+
## 自定义来源
|
|
12
|
+
|
|
13
|
+
`core-data/` 的目录标识由订阅名称与 `geox-url` 配置决定。修改自定义 URL 会使用另一个数据目录,避免有效的旧数据库阻止内核下载新来源。校验和启动使用同一个目录;更新失败保留原订阅与正在运行的旧实例,启动回滚使用原实例记录的目录。
|
|
14
|
+
|
|
15
|
+
默认来源的目录兼容已有订阅。移除 `geox-url` 后回到默认目录;重新使用相同的 `geox-url` 会复用其已有缓存。由于隔离的是整个内核目录,provider 和节点选择缓存也随来源配置隔离。旧目录保留,不自动删除。
|
|
16
|
+
|
|
17
|
+
默认缺失数据依次从实例的 `geodata/`、已有 mihomo 数据目录、安装包内快照复制,无需联网。包内快照与内核的发行方式见 [离线安装与发行](packaging.md)。
|
|
18
|
+
|
|
19
|
+
`MIHOMO_PY_GEODATA_DIR` 指定唯一的本地离线数据来源,也可以满足自定义 `geox-url`;请保证其中数据库与所需地理规则匹配。未显式指定离线目录时,自定义 URL 对应的数据不会被默认快照替代,仍由 mihomo 下载。GEO 自动更新固定关闭。
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# 离线安装与发行
|
|
2
|
+
|
|
3
|
+
## 安装契约
|
|
4
|
+
|
|
5
|
+
Linux x86_64 / aarch64、Python 3.11+、Linux 5.3+(允许 pidfd)。
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
python -m pip install mihomo-py --index-url https://your-mirror.example/simple
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
pip 镜像需要同步项目发行包及 `pyproject.toml` 声明的 Python 依赖。目标机器不需要 GitHub、Go、编译器或预装 mihomo。wheel 按 CPU 架构分开,内含静态内核及四份数据库;源码包包含两个架构,pip 从源码构建也不会下载资源。构建依赖 hatchling 从 pip 源获取。
|
|
12
|
+
|
|
13
|
+
安装后默认使用包内内核,不探测系统 PATH;`--core-binary` / `MIHOMO_PY_BINARY` 可显式覆盖。包内资源只读,首次校验从本地复制到每个订阅的数据目录;后续保留有效的已有文件,不共享可变缓存。GEO 自动更新固定关闭。
|
|
14
|
+
|
|
15
|
+
远程订阅、用户自定义 `geox-url`、rule/proxy providers 是订阅内容,不属于通用软件依赖。如果它们也无法直连,首次启动使用本地完整 YAML、内嵌节点和规则。自定义 GEO 数据可放进 `MIHOMO_PY_GEODATA_DIR`;该环境变量指定唯一数据来源,不再回退到包内数据。自定义 `geox-url` 不会被默认数据库替代,即使 URL 指向公共下载站。
|
|
16
|
+
|
|
17
|
+
## 资源与更新
|
|
18
|
+
|
|
19
|
+
`src/mihomo_py/_vendor/manifest.json` 锁定 mihomo v1.19.19、GEO 的不可变 Git revision、下载内容 SHA-256、解压后 SHA-256。`NOTICE.txt` 和 `licenses/` 随所有发行包分发,提供上游许可、源码链接和归属信息。
|
|
20
|
+
|
|
21
|
+
二进制和数据直接提交 Git(不使用需要额外下载的 LFS 指针),构建 hook 只读取本地资源,缺少文件或哈希不符立即失败。维护者需要恢复缺失资源时可联网运行:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
python scripts/restore_vendor.py
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
此脚本不参与 pip 安装、构建或运行。更新资源时先审查官方发行版本与数据来源,修改 manifest 并校验下载及解压哈希,更新 NOTICE,验证后一起提交。不要让安装流程使用 `latest` URL。
|
|
28
|
+
|
|
29
|
+
升级客户端会安装新版内核和快照;已有订阅的有效数据保持原样。如需改用新快照,应在停止内核后备份并删除对应 `core-data/<标识>/` 下的 GEO 文件,再启动使其重新复制。不要删除 provider 或节点选择缓存。
|
|
30
|
+
|
|
31
|
+
## 构建与验收
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
python -m pip install -e '.[dev]'
|
|
35
|
+
pytest
|
|
36
|
+
ruff check .
|
|
37
|
+
python -m build --installer uv
|
|
38
|
+
MIHOMO_BUILD_ARCH=aarch64 python -m build --wheel --installer uv
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
默认按构建主机架构生成 wheel;`MIHOMO_BUILD_ARCH` 仅用于维护者交叉打包预编译资源。wheel 使用 `py3-none-manylinux_2_17_<arch>.musllinux_1_2_<arch>`,内核是静态 ELF,不依赖 Python ABI 或 glibc。Python 依赖自身的 wheel/平台支持仍由 pip 解析。源码包必须包含全部资源、构建 hook、脚本和文档。
|
|
42
|
+
|
|
43
|
+
发行前必须验证:
|
|
44
|
+
|
|
45
|
+
- wheel 包含且仅包含目标架构内核,带可执行权限、四份数据库、许可和 manifest;源码包离线重建成功。
|
|
46
|
+
- 新虚拟环境只用 pip 镜像或本地 wheelhouse 安装完整依赖,不使用已有 mihomo 或用户数据。
|
|
47
|
+
- 真实内核在 `geodata-mode: false/true` 下校验 `GEOIP`、`GEOSITE`、`IP-ASN`,并完成启动、健康检查、代理访问本地 HTTP 服务、停止。
|
|
48
|
+
- 安装和首次启动期间阻断/审计外部联网,证明没有隐藏下载。Python mock 无法证明 Go 内核没有联网。
|
|
49
|
+
- aarch64 wheel 已通过 x86 主机上的 binfmt/QEMU ARM 容器和完整 AArch64 Linux 虚拟机验证:ARM Python、`pip check`、两种 GEO 模式下的真实内核校验、启动、代理访问和停止均成功。该结果验证了 ARM 镜像运行链路;仍建议发布前在真实 ARM 主机上做一次性能和内核兼容性检查。
|
|
50
|
+
|
|
51
|
+
可在全新环境中运行 `python scripts/check_install.py`,验证包内资源、两种 GEO 模式以及真实 CLI 的校验、启动、本地代理访问和停止。使用该环境的 Python,避免误用开发环境的 editable 安装;可通过 `strace -f -e trace=network -o network.log` 包裹命令审计 Python 和 Go 子进程。
|
|
52
|
+
|
|
53
|
+
本地构建不代表已发布;只有上传发行包并等待镜像同步后,用户才能直接从镜像执行 `pip install mihomo-py`。
|
|
54
|
+
|
|
55
|
+
GitHub 的 `.github/workflows/python-publish.yml` 在推送 `v*` tag 时构建两个架构的 wheel 和源码包,检查发行包元数据,再发布到 PyPI。发布凭据保存在仓库的 `PYPI_API_TOKEN` Actions secret 中。版本号在 `pyproject.toml` 和 `src/mihomo_py/__init__.py` 中保持一致,tag 使用对应的 `v<版本号>`。
|
|
56
|
+
|
|
57
|
+
## Docker 多架构验证
|
|
58
|
+
|
|
59
|
+
仓库根目录的 `Dockerfile` 使用 BuildKit 多阶段构建:第一阶段在目标架构生成 wheel 并从 `PIP_INDEX_URL` 下载 Python 依赖,最终阶段只用本地 wheelhouse 以 `--no-index` 安装,再运行真实 mihomo 校验、启动、代理访问和停止检查。安装阶段与运行阶段不依赖 GitHub。
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
docker buildx build \
|
|
63
|
+
--platform linux/amd64,linux/arm64 \
|
|
64
|
+
--build-arg PIP_INDEX_URL=https://your-pypi-mirror/simple \
|
|
65
|
+
--tag mihomo-py:offline \
|
|
66
|
+
--load .
|
|
67
|
+
|
|
68
|
+
docker run --rm --network=none mihomo-py:offline
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
多平台 `--load` 需要支持 manifest list 的 Docker image store;否则使用 `--push` 推送到镜像仓库,或分别构建单平台镜像。ARM 在 x86 主机运行需要 BuildKit 提供 QEMU,或使用带 ARM 原生节点的 builder:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
docker run --privileged --rm tonistiigi/binfmt --install arm64
|
|
75
|
+
docker buildx build --platform linux/amd64,linux/arm64 --push \
|
|
76
|
+
--tag registry.example/mihomo-py:offline .
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
若只验证当前机器,使用 `--platform linux/amd64 --load`;容器启动时的检查仍会调用真实包内 mihomo,而非 mock。
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# 终端界面
|
|
2
|
+
|
|
3
|
+
在交互终端运行 `mihomo-py` 或 `mihomo-py tui`。建议至少 80×24,支持鼠标及 Tab / Shift-Tab 导航。界面采用石墨色背景与低饱和强调色;小终端自动压缩间距,大终端扩展内容空间。支持 `NO_COLOR`,状态同时用文字和标识区分。
|
|
4
|
+
|
|
5
|
+
打开界面不会自动启动内核,退出界面会保留运行中的内核。后台每 2 秒刷新,网络请求和内核操作在线程中执行;保存或操作内核期间需等待完成后退出。
|
|
6
|
+
|
|
7
|
+
## 状态与订阅
|
|
8
|
+
|
|
9
|
+
顶部展示内核状态、已选 / 运行订阅、本机代理端口和路由模式。高亮行是当前浏览项,`●` 表示已选订阅或生效节点,两者不一定相同。
|
|
10
|
+
|
|
11
|
+
添加 URL 或本地 YAML 后,选择该行并按 Enter 使用,再点击「启动」。支持更新订阅、更换来源和确认删除。运行中的订阅不可删除,删除弹窗默认聚焦「取消」。
|
|
12
|
+
|
|
13
|
+
列表随终端宽度调整,长内容以省略号收尾;按 `i` 查看当前行完整信息。列表与详情里的远程来源均脱敏;更换来源时会在编辑弹窗预填完整原值,便于检查和修改。
|
|
14
|
+
|
|
15
|
+
表单中 Enter 跳到下一字段,最后一个文本字段按 Enter 提交。必填项与端口校验失败后保留输入并定位字段。设置中的路由模式从 `rule / global / direct` 选择,运行中应用设置会重启内核。
|
|
16
|
+
|
|
17
|
+
添加、更新和更换订阅来源时,显示读取订阅、准备地理数据、配置校验、应用保存的进度。下载超时与校验超时有不同提示;失败不会保存新订阅或覆盖旧配置。错误摘要显示在底部或弹窗内,「错误详情」或 F8 可查看完整内容。
|
|
18
|
+
|
|
19
|
+
## 节点
|
|
20
|
+
|
|
21
|
+
启动内核后选择代理组,按 `/` 聚焦名称搜索;搜索框内 Esc 清空搜索并返回列表。选中节点按 Enter 或点击「切换节点」;仅手动组(Selector)可切换,自动组可查看和测速。
|
|
22
|
+
|
|
23
|
+
自动刷新保留当前行和滚动位置;切页及关闭弹窗后恢复焦点。节点切换立即生效,无需重启,并按订阅缓存,在内核重启后恢复。若从旧版升级且内核仍在运行,请先重启一次,使 `profile.store-selected` 生效。
|
|
24
|
+
|
|
25
|
+
「测试延迟」只测试当前选中的一个节点,明确显示待测、测试中、成功结果或失败。默认目标为 `https://www.gstatic.com/generate_204`,可在节点页修改。请求经过所选节点,测量 HTTP 延迟而非下载带宽;失败可更换目标后重试,按 `i` 查看该节点的测速错误。
|
|
26
|
+
|
|
27
|
+
## 日志
|
|
28
|
+
|
|
29
|
+
显示最近 200 行,默认跟随末尾。向上滚动或点击「暂停」后,当前阅读窗口冻结;后台有新内容时显示「有更新」。点击「继续」或在日志区域按 End,加载最新内容并恢复跟随。
|
|
30
|
+
|
|
31
|
+
日志可能包含订阅内部地址,分享日志前请检查内容。
|
|
32
|
+
|
|
33
|
+
## 快捷键
|
|
34
|
+
|
|
35
|
+
| 按键 | 行为 |
|
|
36
|
+
|---|---|
|
|
37
|
+
| `1` / `2` / `3` | 切换订阅 / 节点 / 日志 |
|
|
38
|
+
| Tab / Shift-Tab | 下一个 / 上一个控件 |
|
|
39
|
+
| ↑ / ↓ | 选择列表行 |
|
|
40
|
+
| Enter | 使用订阅、切换手动组节点或操作当前控件 |
|
|
41
|
+
| `/` | 在节点页聚焦搜索 |
|
|
42
|
+
| Esc | 清空节点搜索,或关闭弹窗 |
|
|
43
|
+
| `i` | 查看当前订阅或节点的完整信息 |
|
|
44
|
+
| `?` | 快捷键帮助 |
|
|
45
|
+
| Ctrl-R | 刷新 |
|
|
46
|
+
| Ctrl-A | 添加订阅 |
|
|
47
|
+
| F8 | 展开完整错误 |
|
|
48
|
+
| End | 在日志区域恢复跟随 |
|
|
49
|
+
| `q` / Ctrl-Q | 退出界面,保留内核 |
|
|
50
|
+
|
|
51
|
+
输入框保留原生编辑快捷键,普通字符不会触发切页等全局动作;代理组下拉展开时可直接输入检索。弹窗内不会切换主页面。
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Build self-contained Linux distributions. Never download during a build."""
|
|
2
|
+
|
|
3
|
+
import hashlib
|
|
4
|
+
import json
|
|
5
|
+
import os
|
|
6
|
+
import platform
|
|
7
|
+
import sys
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from hatchling.builders.hooks.plugin.interface import BuildHookInterface
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BundleHook(BuildHookInterface):
|
|
14
|
+
def initialize(self, version, build_data):
|
|
15
|
+
root = Path(self.root) / "src/mihomo_py/_vendor"
|
|
16
|
+
manifest = json.loads((root / "manifest.json").read_text())
|
|
17
|
+
arch = os.environ.get("MIHOMO_BUILD_ARCH", platform.machine())
|
|
18
|
+
if self.target_name == "wheel" and (
|
|
19
|
+
sys.platform != "linux" or arch not in ("x86_64", "aarch64")
|
|
20
|
+
):
|
|
21
|
+
raise ValueError("mihomo-py supports Linux x86_64 and aarch64 only")
|
|
22
|
+
for asset in manifest["assets"]:
|
|
23
|
+
name = asset["path"]
|
|
24
|
+
if self.target_name == "wheel" and name.endswith("/mihomo"):
|
|
25
|
+
if name != f"{arch}/mihomo":
|
|
26
|
+
continue
|
|
27
|
+
path = root / name
|
|
28
|
+
if (
|
|
29
|
+
not path.is_file()
|
|
30
|
+
or hashlib.sha256(path.read_bytes()).hexdigest() != asset["sha256"]
|
|
31
|
+
):
|
|
32
|
+
raise ValueError(f"Missing or corrupt bundled asset: {name}; restore vendor files")
|
|
33
|
+
if name.endswith("/mihomo") and not os.access(path, os.X_OK):
|
|
34
|
+
raise ValueError(f"Bundled core must be executable: {name}")
|
|
35
|
+
if self.target_name == "wheel":
|
|
36
|
+
build_data["force_include"][str(path)] = f"mihomo_py/_vendor/{name}"
|
|
37
|
+
if self.target_name == "wheel":
|
|
38
|
+
for name in ("manifest.json", "NOTICE.txt"):
|
|
39
|
+
build_data["force_include"][str(root / name)] = f"mihomo_py/_vendor/{name}"
|
|
40
|
+
# Upstream CGO_ENABLED=0 cores are static ELF executables, independent of Python ABI.
|
|
41
|
+
build_data["pure_python"] = False
|
|
42
|
+
build_data["tag"] = f"py3-none-manylinux_2_17_{arch}.musllinux_1_2_{arch}"
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.26,<2"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "mihomo-py"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A subscription and process manager for mihomo on Linux servers"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
dependencies = ["click>=8.1,<9", "PyYAML>=6,<7", "textual>=8.2.8,<9", "maxminddb>=3,<4"]
|
|
12
|
+
|
|
13
|
+
[project.scripts]
|
|
14
|
+
mihomo-py = "mihomo_py.cli:main"
|
|
15
|
+
|
|
16
|
+
[project.optional-dependencies]
|
|
17
|
+
dev = ["pytest>=8,<9", "pytest-asyncio>=1.4,<2", "ruff>=0.9,<1", "build>=1.2,<2", "uv>=0.7,<1"]
|
|
18
|
+
|
|
19
|
+
[tool.pytest.ini_options]
|
|
20
|
+
testpaths = ["tests"]
|
|
21
|
+
markers = ["integration: runs a real local mihomo binary"]
|
|
22
|
+
|
|
23
|
+
[tool.ruff]
|
|
24
|
+
line-length = 100
|
|
25
|
+
|
|
26
|
+
[tool.ruff.lint]
|
|
27
|
+
select = ["E", "F", "I"]
|
|
28
|
+
|
|
29
|
+
[tool.hatch.build.hooks.custom]
|
|
30
|
+
path = "hatch_build.py"
|
|
31
|
+
|
|
32
|
+
[tool.hatch.build.targets.wheel]
|
|
33
|
+
packages = ["src/mihomo_py"]
|
|
34
|
+
exclude = ["src/mihomo_py/_vendor/**"]
|
|
35
|
+
|
|
36
|
+
[tool.hatch.build.targets.sdist]
|
|
37
|
+
include = ["src", "tests", "docs", "scripts", "hatch_build.py", "pyproject.toml", "README.md"]
|