# Volcengine Server Manager - 设计文档 **日期**: 2026-04-04 **状态**: 待审核 ## 概述 Windows 桌面应用,用于管理火山引擎云服务器 ECS。首期功能:查看服务器状态、重启服务器。 ## 技术栈 | 层 | 选型 | 说明 | |---|------|------| | GUI | egui + eframe (glow backend) | 纯 Rust,无外部依赖,单 exe 友好 | | 火山引擎 API | volcengine-rust-sdk (1.0.2) | crates.io 官方 SDK | | HTTP | reqwest (SDK 自带) | SDK 内部使用 | | 异步运行时 | tokio | API 异步调用 | | 序列化 | serde + serde_json | 配置读写、API 响应解析 | | 编译目标 | x86_64-pc-windows-gnu | MSYS2 MinGW 工具链 | ## 配置 ### 配置项 | 配置项 | 类型 | 默认值 | 必填 | 说明 | |--------|------|--------|------|------| | access_key_id | String | 空 | 是 | 火山引擎 Access Key ID | | secret_access_key | String | 空 | 是 | 火山引擎 Secret Access Key | | endpoint | String | `ecs.volcengineapi.com` | 否 | ECS API 端点 | ### 存储方式 - 文件路径: `%APPDATA%\volcengine-server-manager\config.json` - 格式: JSON - 首次启动时检测配置是否存在,不存在则弹出配置弹窗 ## 火山引擎 API 调用 ### DescribeInstances(查询实例列表) - **目的**: 获取用户账号下所有 ECS 实例 - **请求参数**: `MaxResults=100`,支持分页 - **响应关键字段**: - `InstanceId` - 实例 ID - `InstanceName` - 实例名称 - `Status` - 实例状态(Running, Stopped, etc.) - `PrivateIpAddresses` - 私网 IP - `PublicIpAddresses` - 公网 IP - `ZoneId` - 可用区 - `RegionId` - 地域 - `InstanceType` - 实例规格 - `CreationTime` - 创建时间 ### RebootInstance(重启单台实例) - **目的**: 重启指定 ECS 实例 - **请求参数**: `InstanceId` (字符串) - **响应**: 操作结果 - **注意**: 重启前需要用户确认弹窗 ### 区域处理 - 不要求用户手动配置 Region - 先调用 `DescribeRegions` 获取所有可用区域列表 - 对每个区域并发调用 `DescribeInstances` 获取该区域实例 - 如果 `DescribeRegions` 不可用,则使用常见区域列表硬编码:`cn-beijing`, `cn-shanghai`, `cn-guangzhou`, `cn-chengdu`, `ap-singapore-1` ## 架构设计 ### 模块划分 ``` src/ ├── main.rs # 入口:初始化 tokio 运行时,启动 eframe ├── app.rs # egui UI 主逻辑:渲染、事件处理、状态管理 ├── config.rs # 配置结构体、JSON 读写 ├── api.rs # 火山引擎 API 封装 └── types.rs # 数据类型定义 ``` ### 模块职责 #### `types.rs` - `InstanceStatus` 枚举: Running, Stopped, Starting, Stopping, Rebooting, Error, Unknown - `InstanceInfo` 结构体: 实例完整信息 - `AppState` 枚举: Loading, Ready, Error(String) #### `config.rs` - `AppConfig` 结构体: 配置项 - `load_config()` -> `Result` - `save_config(&AppConfig)` -> `Result<()>` - 配置目录: `%APPDATA%\volcengine-server-manager\` #### `api.rs` - `VolcClient` 结构体: 封装 SDK Session 或 HTTP 客户端 - `new(access_key_id, secret_access_key, endpoint)` -> Self - `list_instances()` -> `Result>` - `reboot_instance(instance_id)` -> `Result<()>` - **签名机制**: 火山引擎使用 HMAC-SHA256 签名,SDK 不支持时直接构造 HTTP 请求 #### `app.rs` - `VolcManagerApp` 结构体: egui App 实现 - 状态: instances (Vec), app_state, config, show_config_dialog, selected_instance, loading - `update()`: UI 渲染主循环 - 方法: `refresh_instances()`, `reboot_selected()`, `open_config_dialog()`, `save_config()` #### `main.rs` - 初始化配置 - 创建 tokio 运行时 - 启动 eframe native window - 设置 `windows_subsystem = "windows"` 去掉控制台 ### 数据流 ``` 用户操作 → egui 事件 → App 方法 → tokio spawn 后台任务 → API 调用 → 结果通过 channel 返回 → 更新 state → request_repaint() → UI 刷新 ``` ### UI 布局 #### 主窗口 ``` ┌──────────────────────────────────────────────────────┐ │ 火山引擎服务器管理 [刷新] [⚙ 配置] │ ├──────────────────────────────────────────────────────┤ │ │ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ │ │ 实例名称 │ │ 实例名称 │ │ 实例名称 │ │ │ │ 状态: 运行中 │ │ 状态: 已停止 │ │ 状态: 运行中 │ │ │ │ IP: x.x.x.x │ │ IP: x.x.x.x │ │ IP: x.x.x.x │ │ │ │ 区域: cn-beijing │ 区域: cn-shanghai │ 区域: cn-guangzhou│ │ │ 规格: ecs.g3i.large │ 规格: ... │ 规格: ... │ │ │ │ │ │ │ │ │ [🔄 重启] │ [▶ 启动] │ [🔄 重启] │ │ └────────────┘ └────────────┘ └────────────┘ │ │ │ │ ┌────────────┐ ┌────────────┐ │ │ │ ... │ │ ... │ │ │ └────────────┘ └────────────┘ │ │ │ ├──────────────────────────────────────────────────────┤ │ 实例数: 5 最后刷新: 2026-04-04 19:30 │ └──────────────────────────────────────────────────────┘ ``` #### 配置弹窗(Modal) ``` ┌────────────────────────────────────┐ │ 配置 │ ├────────────────────────────────────┤ │ Access Key ID: │ │ [________________________________]│ │ │ │ Secret Access Key: │ │ [________________________________]│ │ │ │ Endpoint: │ │ [ecs.volcengineapi.com___________]│ │ │ │ [保存] [取消] │ └────────────────────────────────────┘ ``` #### 重启确认弹窗 ``` ┌────────────────────────────────────┐ │ 确认重启 │ ├────────────────────────────────────┤ │ 确定要重启实例 "xxx" 吗? │ │ 实例 ID: i-xxxxxxxxxxxx │ │ │ │ [确定] [取消] │ └────────────────────────────────────┘ ``` ### 状态颜色映射 | 状态 | 颜色 | |------|------| | Running | 绿色 | | Stopped | 灰色 | | Starting | 蓝色 | | Stopping | 橙色 | | Rebooting | 橙色 | | Error | 红色 | | Unknown | 黄色 | ### 错误处理 - API 调用失败:底部状态栏显示错误信息,3 秒后自动消失 - 配置未设置:首次启动弹出配置弹窗,阻止主界面操作 - 网络异常:显示 "网络连接失败,请检查网络设置" - 认证失败:显示 "Access Key 或 Secret Key 无效" ### 中文支持 - 加载 Windows 系统字体 `C:\Windows\Fonts\msyh.ttc`(微软雅黑) - 通过 `egui::FontDefinitions` 注入为默认字体 - 如果字体加载失败,回退到 egui 内置字体(英文字符) ### 编译配置 #### Cargo.toml 关键设置 ```toml [package] name = "volcengine-server-manager" version = "0.1.0" edition = "2021" [[bin]] name = "volcengine-server-manager" path = "src/main.rs" [profile.release] opt-level = 2 strip = true lto = true # Windows 子系统设置(去掉控制台窗口) [package.metadata.windows] subsystem = "windows" ``` 实际去掉控制台的方法:在 `main.rs` 中设置 `#![windows_subsystem = "windows"]` 属性。 ### 依赖列表 ```toml [dependencies] eframe = { version = "0.29", default-features = false, features = ["glow"] } egui = "0.29" volcengine-rust-sdk = "1.0.2" tokio = { version = "1", features = ["rt-multi-thread", "macros"] } serde = { version = "1", features = ["derive"] } serde_json = "1" dirs = "5" ``` ### 编译命令 ```bash # 在 MSYS2 MinGW 环境下 rustup target add x86_64-pc-windows-gnu cargo build --release --target x86_64-pc-windows-gnu ``` 输出文件: `target/x86_64-pc-windows-gnu/release/volcengine-server-manager.exe`