Files
volcengine-server-manager/docs/superpowers/specs/2026-04-04-volcengine-server-manager-design.md

252 lines
9.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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<AppConfig>`
- `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<Vec<InstanceInfo>>`
- `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`