# u-fs-agent 远程文件服务 - 设计文档
## 目录
- [1. 项目概述](#1-项目概述)
- [2. 架构设计](#2-架构设计)
- [2.1 整体架构](#21-整体架构)
- [2.2 单仓库双入口模式](#22-单仓库双入口模式)
- [2.3 共享包零拷贝](#23-共享包零拷贝)
- [2.4 数据流](#24-数据流)
- [3. 技术决策](#3-技术决策)
- [4. API 端点设计(MVP v0.1)](#4-api-端点设计mvp-v01)
- [4.1 概览](#41-概览)
- [4.2 系统端点](#42-系统端点)
- [4.3 文件操作端点](#43-文件操作端点)
- [4.4 系统信息端点](#44-系统信息端点)
- [4.5 代理端点](#45-代理端点)
- [4.6 统一响应格式](#46-统一响应格式)
- [4.7 错误码规范](#47-错误码规范)
- [5. 后端实现细节](#5-后端实现细节)
- [5.1 Agent 入口 (cmd/agent/main.go)](#51-agent-入口-cmdagentmaingo)
- [5.2 配置管理 (internal/agent/config)](#52-配置管理-internalagentconfig)
- [5.3 Handler 层 (internal/agent/handler)](#53-handler-层-internalagenthandler)
- [5.4 中间件 (internal/agent/middleware)](#54-中间件-internalagentmiddleware)
- [5.5 响应模型 (internal/agent/model)](#55-响应模型-internalagentmodel)
- [6. 前端改造方案](#6-前端改造方案)
- [6.1 Transport 适配器模式](#61-transport-适配器模式)
- [6.2 ConnectionProfile 数据模型](#62-connectionprofile-数据模型)
- [6.3 连接管理器](#63-连接管理器)
- [6.4 Pinia Store 设计](#64-pinia-store-设计)
- [6.5 Toolbar 连接指示器](#65-toolbar-连接指示器)
- [6.6 文件变更清单](#66-文件变更清单)
- [7. 目录结构](#7-目录结构)
- [8. 分阶段实施计划](#8-分阶段实施计划)
- [8.1 Wave 1: 核心连通(MVP)](#81-wave-1-核心连通mvp)
- [8.2 Wave 2: 编辑体验增强](#82-wave-2-编辑体验增强)
- [8.3 Wave 3: 增强功能](#83-wave-3-增强功能)
- [8.4 Wave 4: 用户间文件共享](#84-wave-4-用户间文件共享)
- [9. 安全设计](#9-安全设计)
- [10. 部署方案](#10-部署方案)
- [11. 配置说明](#11-配置说明)
- [12. 测试策略](#12-测试策略)
---
## 1. 项目概述
### 1.1 背景
u-desk 当前是一个基于 Wails 的桌面应用,所有文件操作通过 Wails Bindings 在本地执行。随着使用场景扩展,用户需要能够访问和管理远程服务器上的文件 -- 例如开发机、测试环境、生产服务器的文件系统。
### 1.2 目标
在 u-desk 同一 Git 仓库中新增 `cmd/agent` 入口,编译为独立的 HTTP 服务程序 `u-fs-agent`,部署到远端服务器后,本地 u-desk 通过 REST API 远程操作远端文件系统。
**核心价值**:
| 维度 | 本地模式 | 远程模式 |
|------|---------|---------|
| 访问范围 | 本地文件系统 | 远程服务器文件系统 |
| 通信方式 | Wails Bindings(进程内) | REST HTTP(网络) |
| 文件系统 | filesystem 包直接调用 | filesystem 包通过 HTTP 代理调用 |
| 用户体验 | 无感知切换 | Transport 抽象层自动路由 |
### 1.3 核心原则
- **单仓库双入口**:`cmd/desk`(桌面端)和 `cmd/agent`(HTTP 服务)共存于同一仓库
- **filesystem 零拷贝**:`internal/filesystem` 包被两个入口共享引用,无代码复制
- **前端无感知**:通过 Transport 抽象层,前端不关心底层是本地还是远程
- **渐进式增强**:MVP 先跑通核心链路,后续 Wave 迭代增强能力
---
## 2. 架构设计
### 2.1 整体架构
```
┌─────────────────────────────────────────────────────────────────────┐
│ u-desk 前端 (Vue 3) │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌───────────────────────────┐ │
│ │ FileExplorer │ │ Editor │ │ ConnectionManager │ │
│ └──────┬───────┘ └──────┬───────┘ └───────────┬───────────────┘ │
│ │ │ │ │
│ └────────┬────────┘ │ │
│ ▼ │ │
│ ┌───────────────┐ │ │
│ │ Transport │◄──────────────────────┘ │
│ │ (抽象接口) │ 根据 ConnectionProfile 选择实现 │
│ └───────┬───────┘ │
└──────────────────┼──────────────────────────────────────────────────┘
│ ┌──────────────────────────────┐
┌───────┴───────┐ │ │
▼ ▼ ▼ │
┌──────────────────┐ ┌────────────────────┐ │
│ WailsTransport │ │ HttpTransport │ REST over HTTP │
│ (本地 Wails 调用) │ │ (远程 HTTP 调用) │ Bearer Token │
└────────┬─────────┘ └────────┬───────────┘ │
│ │ │
▼ ▼ │
┌──────────────────┐ ┌──────────────────────────────────────────┐ │
│ cmd/desk │ │ cmd/agent (u-fs-agent) │ │
│ Wails 桌面端 │ │ Echo v4 HTTP 服务 │ │
│ main.go │ │ main.go │ │
└────────┬─────────┘ └─────────────────┬────────────────────────┘ │
│ │ │
└──────────────┬───────────────┘ │
▼ │
┌───────────────────────┐ │
│ internal/filesystem │ ◄── 共享包,零拷贝 │
│ (17 个 Go 源文件) │ │
│ │ │
│ ┌──────────────────┐ │ │
│ │FileSystemService │ │ │
│ ├──────────────────┤ │ │
│ │PathValidator │ │ │
│ │FileTypeManager │ │ │
│ │AssetHandler │ │ │
│ │AuditLogger │ │ │
│ │RecycleBin │ │ │
│ │FileLockChecker │ │ │
│ └──────────────────┘ │ │
└───────────────────────┘ │
│ │
▼ │
┌─────────────────┐ │
│ 操作系统文件系统 │ ◄── 本地磁盘 / 远程服务器磁盘 │
└─────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
```
### 2.2 单仓库双入口模式
```
u-desk/
├── cmd/
│ ├── desk/
│ │ └── main.go # Wails 桌面端入口(已有)
│ └── agent/
│ └── main.go # u-fs-agent HTTP 服务入口(新增)
│
├── internal/
│ ├── filesystem/ # ★ 共享包:两个入口都引用
│ │ ├── service.go # FileSystemService 核心
│ │ ├── config.go # 安全/性能/功能配置
│ │ ├── path_validator.go # 路径安全验证
│ │ ├── filetype_manager.go # 文件类型管理
│ │ ├── asset_handler.go # 静态资源处理
│ │ ├── audit_log.go # 审计日志
│ │ ├── recycle_bin.go # 回收站
│ │ ├── file_lock.go # 文件锁检查
│ │ ├── content_detector.go # 内容类型检测
│ │ ├── zip.go / zip_helper.go # ZIP 操作
│ │ ├── directory_stats.go # 目录统计
│ │ ├── fs.go # 文件系统工具函数
│ │ ├── errors.go # 错误定义
│ │ ├── constants.go # 常量定义
│ │ └── logger.go # 日志工具
│ │
│ ├── agent/ # ★ Agent 专用模块(仅 agent 入口使用)
│ │ ├── config/ # Agent 配置加载
│ │ ├── handler/ # Echo Handler(HTTP → FileSystemService)
│ │ ├── middleware/ # 认证/CORS/恢复中间件
│ │ └── model/ # API 请求/响应模型
│ │
│ ├── app/ # 桌面端 App 结构体(仅 desk 使用)
│ ├── common/ # 公共工具
│ ├── service/ # 业务服务
│ ├── storage/ # 存储层
│ └── system/ # 系统信息
│
├── frontend/src/ # 前端 Vue 3 项目
│ └── api/
│ ├── transport.ts # ★ Transport 接口定义
│ ├── wails-transport.ts # ★ WailsTransport 实现
│ ├── http-transport.ts # ★ HttpTransport 实现
│ ├── connection-manager.ts # ★ 连接管理器
│ ├── types.ts # 类型定义
│ └── index.ts # 统一导出
│
└── configs/
└── agent.yaml # ★ Agent 运行时配置
```
**关键约束**:
- `internal/filesystem` **不导入**任何 Wails 或 Echo 依赖,保持纯净
- `internal/agent` **只导入** `internal/filesystem`,不导入 `internal/app`
- `cmd/desk` 和 `cmd/agent` 编译产物完全独立,可分别部署
### 2.3 共享包零拷贝
filesystem 包的 17 个源文件在编译时被两个二进制文件共同链接,不存在运行时代码复制:
```
编译流程:
go build ./cmd/desk → u-desk.exe (包含 filesystem 全部代码)
go build ./cmd/agent → u-fs-agent (包含 filesystem 全部代码)
两者独立编译,各自包含一份 filesystem 的机器码
源码层面零拷贝 -- 同一套 .go 文件,import 路径一致
```
**filesystem 包对外暴露的核心能力**(Agent Handler 直接调用的方法):
| 方法 | 说明 | Agent 端点映射 |
|------|------|---------------|
| `ListDir(path)` | 列出目录内容 | `GET /api/v1/files/*` |
| `GetFileInfo(path)` | 获取文件/目录信息 | `GET /api/v1/files/*?action=stat` |
| `ReadFile(path)` | 读取文件内容 | `GET /api/v1/files/*/content` |
| `WriteFile(path, content)` | 写入文件内容 | `PUT /api/v1/files/*/content` |
| `CreateFile(path)` | 创建空文件 | `POST /api/v1/files/*` (type=file) |
| `CreateDir(path)` | 创建目录 | `POST /api/v1/files/*` (type=dir) |
| `DeletePath(path)` | 删除文件/目录 | `DELETE /api/v1/files/*` |
| `RenamePath(old, new)` | 重命名 | `PATCH /api/v1/files/*` |
| `SaveBase64File(path, b64)` | Base64 写入 | `POST /api/v1/files/*/upload` |
| `DetectContentType(data)` | 内容类型检测 | `GET /api/v1/files/*/detect-type` |
| `StartLocalFileServer()` | 启动内置文件服务器 | 代理端点内部调用 |
### 2.4 数据流
**本地模式数据流**:
```
用户点击文件 → Vue Component → WailsTransport.ReadFile(path)
→ window.go.main.App.ReadFile(path) // Wails Binding
→ app.go → filesystem.FileSystemService.ReadFile(path)
→ os.ReadFile(path) → 返回内容给前端
```
**远程模式数据流**:
```
用户点击文件 → Vue Component → HttpTransport.readFile(path)
→ fetch(`http://remote:9876/api/v1/files/${path}/content`, { headers: { Authorization: 'Bearer xxx' } })
→ [网络] → u-fs-agent Echo Router → handler.ReadFile
→ filesystem.FileSystemService.ReadFile(path)
→ os.ReadFile(path) → JSON Response → [网络] → 前端解析展示
```
---
## 3. 技术决策
| 决策项 | 选择 | 备选方案 | 选择理由 |
|--------|------|---------|---------|
| 工程组织 | 单仓库双入口 | 独立仓库 / monorepo | filesystem 包零拷贝,避免同步噩梦;同一仓库便于 CI 统一管理 |
| HTTP 框架 | Echo v4 | Gin / Chi / net/http | 已在项目依赖树中;API 定义简洁优雅;中间件生态成熟 |
| 通信协议 | REST + JSON | gRPC / WebSocket | CRUD 天然映射 HTTP 动词;前端 fetch 原生支持;调试友好(curl 即可) |
| 认证方式 | Bearer Token (MVP) | JWT / OAuth2 / mTLS | MVP 最简实现;Token 可配置为空(内网信任场景);后续 Wave 4 升级 JWT |
| 前端架构 | Transport 接口 | 条件分支 / 策略模式 | Composable 设计,业务代码零感知;新增协议只需实现接口 |
| 配置格式 | YAML | JSON / TOML / 环境变量 | 可读性好;支持注释;Go 生态 yaml.v3 成熟 |
| 文件上传 | Base64 JSON | multipart/form-data | MVP 简化实现;与现有 Wails Base64 接口对齐;Wave 2 升级 multipart |
| 内嵌文件服务器 | 复用 AssetHandler | 独立代理服务 | 复用现有 8073 端口逻辑;HTML 预览代理无缝衔接 |
---
## 4. API 端点设计(MVP v0.1)
### 4.1 概览
| Method | Path | 说明 | Handler |
|--------|------|------|---------|
| GET | `/api/v1/ping` | 健康检查 | Ping |
| GET | `/api/v1/info` | Agent 信息 | Info |
| GET | `/api/v1/files/*` | 列目录 / 文件信息 | ListOrStat |
| GET | `/api/v1/files/*/content` | 读文件内容 | ReadFile |
| PUT | `/api/v1/files/*/content` | 写文件内容 | WriteFile |
| POST | `/api/v1/files/*` | 新建文件/目录 | Create |
| DELETE | `/api/v1/files/*` | 删除 | Delete |
| PATCH | `/api/v1/files/*` | 重命名 | Rename |
| POST | `/api/v1/files/*/upload` | Base64 上传 | Upload |
| GET | `/api/v1/files/*/detect-type` | 内容类型检测 | DetectType |
| GET | `/api/v1/system/common-paths` | 常用路径列表 | CommonPaths |
| GET | `/api/v1/system/drives` | 磁盘分区列表 | Drives |
| GET | `/api/v1/proxy/localfs/*` | 文件服务器代理 | FileServerProxy |
| GET | `/api/v1/proxy/html-preview` | HTML 预览代理 | HTMLPreviewProxy |
**Base URL**: `http://{host}:{port}/api/v1`
**默认端口**: `9876`
### 4.2 系统端点
#### GET /api/v1/ping
健康检查端点,用于负载均衡探活和客户端连通性检测。
**请求**:无参数
**响应 (200)**:
```json
{
"code": 0,
"message": "ok",
"data": {
"status": "up",
"timestamp": "2026-04-26T10:30:00Z",
"version": "0.1.0"
}
}
```
#### GET /api/v1/info
返回 Agent 实例信息,用于前端展示连接状态和版本校验。
**请求**:无参数
**响应 (200)**:
```json
{
"code": 0,
"message": "ok",
"data": {
"hostname": "dev-server-01",
"os": "linux",
"arch": "amd64",
"version": "0.1.0",
"uptime_seconds": 3600,
"root_path": "/home/user",
"features": {
"recycle_bin": true,
"audit_log": true,
"zip_extraction": true
}
}
}
```
### 4.3 文件操作端点
#### GET /api/v1/files/*
根据查询参数决定行为:默认列目录,`?action=stat` 返回单个文件信息。
**路径参数**:`*` -- 文件或目录路径(URL 编码)
**查询参数**:
| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| action | string | `list` | `list`=列目录, `stat`=文件信息 |
**列目录响应 (200)**:
```json
{
"code": 0,
"message": "ok",
"data": [
{
"name": "src",
"path": "/home/user/project/src",
"is_dir": true,
"size": 4096,
"mod_time": "2026-04-26 10:00:00"
},
{
"name": "main.go",
"path": "/home/user/project/main.go",
"is_dir": false,
"size": 2048,
"mod_time": "2026-04-26 09:30:00"
}
]
}
```
**文件信息响应 (200, ?action=stat)**:
```json
{
"code": 0,
"message": "ok",
"data": {
"name": "main.go",
"path": "/home/user/project/main.go",
"size": 2048,
"size_str": "2 KB",
"is_dir": false,
"mod_time": "2026-04-26 09:30:00",
"mode": "0644"
}
}
```
#### GET /api/v1/files/*/content
读取文件文本内容(限制最大 10MB)。
**路径参数**:`*` -- 文件路径
**响应 (200)**:
```json
{
"code": 0,
"message": "ok",
"data": {
"content": "package main\n\nimport \"fmt\"\n...",
"size": 2048,
"encoding": "utf-8"
}
}
```
**错误 (413)**:文件超过 10MB 限制
```json
{
"code": 41301,
"message": "文件过大 (15.2 MB),超过读取上限 (10 MB)"
}
```
#### PUT /api/v1/files/*/content
写入文件文本内容。
**路径参数**:`*` -- 目标文件路径
**请求体**:
```json
{
"content": "package main\n\n..."
}
```
**响应 (200)**:
```json
{
"code": 0,
"message": "ok",
"data": {
"path": "/home/user/project/main.go",
"name": "main.go",
"size": 2048,
"is_dir": false
}
}
```
#### POST /api/v1/files/*
新建文件或目录。
**路径参数**:`*` -- 目标路径
**请求体**:
```json
{
"type": "file" // "file" | "dir"
}
```
**响应 (201)**:
```json
{
"code": 0,
"message": "created",
"data": {
"path": "/home/user/project/newfile.txt",
"name": "newfile.txt",
"size": 0,
"is_dir": false
}
}
```
#### DELETE /api/v1/files/*
删除文件或目录。
**路径参数**:`*` -- 要删除的路径
**响应 (200)**:
```json
{
"code": 0,
"message": "ok",
"data": {
"path": "/home/user/project/oldfile.txt",
"name": "oldfile.txt",
"size": 1024,
"is_dir": false,
"deleted": true
}
}
```
#### PATCH /api/v1/files/*
重命名文件或目录。
**路径参数**:`*` -- 原路径
**请求体**:
```json
{
"new_name": "renamed.txt" // 仅新名称(非完整路径)
}
```
**响应 (200)**:
```json
{
"code": 0,
"message": "ok",
"data": {
"path": "/home/user/project/renamed.txt",
"name": "renamed.txt",
"old_path": "/home/user/project/oldfile.txt"
}
}
```
#### POST /api/v1/files/*/upload
以 Base64 编码上传二进制文件内容(图片等非文本文件)。
**路径参数**:`*` -- 目标文件路径
**请求体**:
```json
{
"base64_content": "iVBORw0KGgoAAAANSUhEUgAA...",
"filename": "screenshot.png"
}
```
**响应 (201)**:
```json
{
"code": 0,
"message": "created",
"data": {
"path": "/home/user/images/screenshot.png",
"name": "screenshot.png",
"size": 15360,
"is_dir": false
}
}
```
#### GET /api/v1/files/*/detect-type
检测文件内容的实际类型(基于 magic bytes,而非扩展名)。
**路径参数**:`*` -- 文件路径
**响应 (200)**:
```json
{
"code": 0,
"message": "ok",
"data": {
"detected_type": "image/png",
"extension": ".png",
"confidence": "high"
}
}
```
### 4.4 系统信息端点
#### GET /api/v1/system/common-paths
返回当前系统的常用路径列表(用户主目录、桌面、文档等)。
**响应 (200)**:
```json
{
"code": 0,
"message": "ok",
"data": {
"home": "/home/user",
"desktop": "/home/user/Desktop",
"documents": "/home/user/Documents",
"downloads": "/home/user/Downloads",
"temp": "/tmp"
}
}
```
#### GET /api/v1/system/drives
返回磁盘分区列表(Windows 显示 C:/ D:/ 等,Linux 显示挂载点)。
**响应 (200)**:
```json
{
"code": 0,
"message": "ok",
"data": [
{ "letter": "C:", "path": "C:\\", "total_gb": 256, "free_gb": 80, "fs_type": "NTFS" },
{ "letter": "D:", "path": "D:\\", "total_gb": 512, "free_gb": 200, "fs_type": "NTFS" }
]
}
```
### 4.5 代理端点
#### GET /api/v1/proxy/localfs/*
代理访问 Agent 内嵌的本地文件服务器(端口 8073),用于媒体文件预览。
**路径参数**:`*` -- 相对于文件服务器根目录的路径
**行为**:反向代理到 `http://127.0.0.1:8073/{path}`,透传响应。
**用途**:前端 `
` / `