Skip to content

Architecture

Juwan-Hwang edited this page Apr 10, 2026 · 27 revisions

系统架构

整体架构

┌──────────────────────────────────────────────────────────┐
│                    前端 (JavaScript)                       │
│  ┌─────────┐ ┌──────────┐ ┌───────────┐ ┌─────────────┐  │
│  │  ui.js   │ │  api.js  │ │websocket │ │ traffic-    │  │
│  │ UI 逻辑  │ │ API 调用  │ │   .js    │ │ chart.js   │  │
│  └────┬─────┘ └────┬─────┘ └─────┬─────┘ └──────┬──────┘  │
│       │            │             │               │         │
│       └────────────┴──────┬──────┴───────────────┘         │
│                          │ invoke / listen                 │
├──────────────────────────┼─────────────────────────────────┤
│                    Tauri IPC 层                              │
├──────────────────────────┼─────────────────────────────────┤
│                    Rust 后端                                 │
│  ┌──────────┐ ┌──────────────┐ ┌──────────┐ ┌──────────┐  │
│  │  lib.rs  │ │core_manager  │ │  config_ │ │  sys_    │  │
│  │ 入口/状态│ │  .rs 核心    │ │ manager  │ │ proxy.rs │  │
│  │  管理    │ │  进程管理    │ │  .rs     │ │ 系统代理 │  │
│  └──────────┘ └──────┬───────┘ └──────────┘ └──────────┘  │
│  ┌──────────┐ ┌──────┴───────┐ ┌──────────┐               │
│  │  tray.rs │ │  updater.rs  │ │  uwp_    │               │
│  │ 系统托盘 │ │ 内核/Geo更新 │ │ loopback │               │
│  └──────────┘ └──────────────┘ └──────────┘               │
├──────────────────────────────────────────────────────────┤
│                    Mihomo 内核                               │
│  RESTful API (:9090) · /traffic (Stream) · /proxies · ... │
└──────────────────────────────────────────────────────────┘

Rust 后端模块

lib.rs — 应用入口与状态管理

职责:应用生命周期管理、状态初始化、命令注册。

核心组件

  • RateLimiter — 命令级限流器(HashMap<String, Instant>,60s 自动清理)
  • rate_limit! 宏 — 声明式限流装饰器
  • Settings 结构体 — 应用配置(close_to_tray, auto_update, autostart, theme, last_config, custom_args, dns_nameservers, dns_fallbacks)
  • SettingsState(Arc<Mutex<Settings>>) — 线程安全的状态容器

生命周期

  1. Panic Hook 注册(确保异常时清理)
  2. 插件注册(autostart, dialog, opener)
  3. 状态初始化(MihomoState, TrayState, RateLimiter)
  4. 应用存储目录创建
  5. 设置加载
  6. 托盘初始化
  7. 窗口事件绑定(关闭到托盘、拖拽导入 YAML)
  8. 命令注册(~30 个 Tauri Command)
  9. 退出清理(停止核心、清除系统代理)

core_manager.rs — 核心进程管理(~3000 行)

职责:Mihomo 内核的完整生命周期管理。

全局状态

  • TUN_MODE_ACTIVE: AtomicBool — TUN 模式状态
  • CORE_STARTING: AtomicBool — 启动锁(防并发启动)
  • DERIVED_KEY: OnceLock<Vec<u8>> — 派生加密密钥(延迟初始化)

核心数据结构

struct CoreData {
    process: Option<Child>,      // Mihomo 子进程
    last_secret: String,         // API 密钥
    last_config_path: String,    // 当前配置文件路径
    last_custom_args: String,    // 自定义启动参数
    last_port: u16,              // API 端口
}

struct AppPaths {
    app_data_dir: PathBuf,       // 应用数据目录
    core_dir: PathBuf,           // 内核目录
    profiles_dir: PathBuf,       // 配置文件目录
}

核心启动流程 (start_core):

1. 限流检查(3s 冷却)
2. 原子锁获取(10s 超时 + ResetGuard)
3. TUN 模式检查 → macOS 需要 root 权限
4. 终止现有 Mihomo 进程
5. 确保应用存储目录存在
6. macOS: 等待端口 9090 释放
7. 解析配置文件路径
8. 验证自定义启动参数
9. 测试模式验证(mihomo -t)
10. 准备运行时配置(注入 external-controller + secret + unified-delay)
11. 写入 run_config.yaml
12. 启动 Mihomo 子进程(日志输出到临时文件)
13. cache.db 锁重试
14. TCP 健康检查(20 次轮询)
15. 更新全局状态

订阅下载流程 (download_sub):

1. 限流检查(5s 冷却)
2. SSRF 验证(DNS 解析 + 私有 IP 检查)
3. 尝试直接下载
4. 失败 → 通过 Mihomo 代理下载
5. 再失败 → 通过系统代理下载
6. Base64 自动检测与解码
7. YAML + proxies 字段验证
8. 清除危险配置键
9. 加密存储元数据
10. 安全写入文件

config_manager.rs — 配置管理

职责:配置文件的读取、合并、写入和热重载。

核心流程 (update_config):

1. 读取当前 run_config.yaml
2. JSON patch → YAML 转换
3. 递归深度合并(深度限制 50 层)
4. 安全键保护:
   - 保存 external-controller(强制 127.0.0.1)
   - 保存 secret
   - 保存 TUN enable 状态
5. 合并后恢复安全键
6. 写入 run_config.yaml
7. 同步更新原始 profile 文件
8. PATCH 到 Mihomo API(/configs?force=true)
9. 返回详细结果

YAML 合并规则

  • null 值删除对应键
  • 嵌套对象递归合并
  • 数组整体替换(非元素级合并)
  • 深度限制 50 层(防止栈溢出)

sys_proxy.rs — 系统代理

安全验证 (validate_proxy_server):

  • 仅允许 127.0.0.1::1localhost
  • 拒绝欺骗性主机名(如 127.0.0.1.evil.com
  • 最大 512 字符

Windows 实现

  • 注册表路径:HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings
  • 原子写入:先备份当前值 → 写入新值 → 刷新 InternetSetOptionW → 失败则回滚
  • Bypass 默认包含:localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.2*;172.3*;192.168.*

macOS 实现

  • 动态获取网络服务列表(-listallnetworkservices
  • 跳过禁用的服务(以 * 开头)
  • 逐服务设置 HTTP/HTTPS/SOCKS 代理
  • 任一服务成功即视为成功

Linux 实现

  • GNOME:gsettings 原子写入(先设所有值再切 mode=manual,失败回滚)
  • KDE:kwriteconfig5/6 + DBus 通知 KIODaemon/KWin
  • XFCE:xfconf-query 设置 HTTP/HTTPS/SOCKS

tray.rs — 系统托盘

状态结构

struct TrayMenuState {
    sys_proxy_enabled: bool,
    tun_enabled: bool,
    current_mode: String,        // "rule" / "global" / "direct"
    active_config: String,
    active_proxy: String,
}

菜单构建 (update_tray_full_menu):

  • 动态获取代理组和节点(每组最多 15 个)
  • 订阅列表从 profiles 目录读取
  • 模式状态用 ●/○ 标记

事件系统

  • 托盘操作通过 Tauri Event 通知前端
  • 前端监听事件后同步 UI 状态
  • 实现前后端双向状态同步

updater.rs — 内核更新

更新流程 (update_core):

1. 解析 GitHub Release URL
2. 验证 URL 结构(MetaCubeX/mihomo/releases/download/)
3. 验证版本格式
4. 下载到 UUID 临时文件(进度 24-80%)
5. SHA256 校验
6. 解压到 UUID 临时文件
7. 停止 Mihomo 核心
8. 替换二进制文件(Windows 重试 5 次)
9. 安装内核二进制
10. 使用上次配置重启核心

平台标签映射

OS arch Tag
Windows x86_64 windows-amd64
Windows aarch64 windows-arm64
macOS x86_64 darwin-amd64
macOS aarch64 darwin-arm64
Linux x86_64 linux-amd64

Windows 优先选择 compatible 架构的资产。

uwp_loopback.rs — UWP 环回免除

  • 5 分钟限流 — 防止频繁调用
  • 合法性检查 — 确认核心正在运行且主窗口存在
  • 用户确认 — 通过 Tauri Dialog 插件弹出确认对话框
  • 执行方式 — Base64 编码的 PowerShell 脚本 + CheckNetIsolation.exe LoopbackExempt -a

前端架构

数据流

用户操作 → ui.js (事件处理)
    ↓
api.js (invoke 调用)
    ↓
Tauri IPC → Rust Command → 执行 → 返回结果
    ↓
ui.js (更新 DOM)
    ↓
Tauri Event (后端推送) → ui.js (监听处理)

缓存系统

  • API 缓存apiCache 对象,TTL 2 秒,覆盖 config/proxies/settings/configs
  • 托盘菜单缓存trayMenuCache,TTL 2 秒
  • 缓存失效 — 操作后主动调用 invalidate*Cache()

初始化顺序

1. 禁用右键菜单
2. 应用翻译 (i18n)
3. 初始化窗口控制
4. 显示主窗口 (50ms 延迟)
5. 启动核心 → 获取 secret + port
6. 设置 API 基地址和密钥
7. 初始化各模块(导航 → 图表 → 托盘 → 代理 → DNS → 模式 → TUN → 设置 → UWP → 节点滚轮)
8. 检查加密密钥持久化
9. 同步核心配置 + 更新托盘
10. 启动统一周期同步 (10s 间隔)
11. 监听配置解析错误事件
12. 连接流量监控

统一周期同步

每 10 秒并行检查:

  • 系统代理状态是否与 UI 一致
  • 托盘图标模式是否与预期一致

Tauri Commands 完整列表

命令 模块 说明
get_settings lib 获取应用设置
save_settings lib 保存应用设置
show_main_window lib 显示主窗口
get_tray_status lib 获取托盘状态
start_core core 启动 Mihomo 核心
stop_core core 停止核心
restart_core core 重启核心
get_core_version core 获取内核版本
download_sub core 下载订阅
list_configs core 列出配置文件
delete_config core 删除配置文件
read_config core 读取运行时配置
read_config_file core 读取配置文件内容
write_config_file core 写入配置文件内容
update_config config 更新配置并热重载
open_config_folder core 打开配置文件夹
get_sys_proxy proxy 获取系统代理状态
enable_sysproxy proxy 启用系统代理
disable_sysproxy proxy 禁用系统代理
change_tray_icon tray 更改托盘图标
update_tray_full_menu tray 更新托盘完整菜单
update_tray_toggle_states tray 更新托盘开关状态
get_latest_version updater 获取最新内核版本
update_core updater 更新内核
update_geo_data updater 更新 Geo 数据
get_latest_client_versions updater 获取客户端版本号
exempt_uwp_apps uwp UWP 环回免除
restart_core_as_root_cmd core root 权限重启(macOS TUN)
set_tun_enabled core 设置 TUN 状态
disable_tun_cmd core 禁用 TUN
is_machine_key_persisted core 检查密钥持久化
fetch_text core 后端代理获取文本

事件系统

后端 → 前端

事件 触发场景
config-parse-error 配置文件 YAML 解析失败
profiles-imported 拖拽导入配置文件完成
tray-sysproxy-changed 托盘切换系统代理
tray-tun-changed 托盘切换 TUN 模式
tray-mode-changed 托盘切换运行模式
tray-subscription-changed 托盘切换订阅
tray-proxy-changed 托盘切换代理节点
core-download-progress 内核下载进度
core-download-status 内核下载状态文本
geo-download-progress Geo 数据下载进度

Clone this wiki locally