feat: 初始化项目 - 火山引擎服务器管理工具

This commit is contained in:
xiaji
2026-04-04 20:15:55 +08:00
commit 1bc119f083
3 changed files with 1312 additions and 0 deletions

View File

@@ -0,0 +1,251 @@
# 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`