GO-DESK-10: SFTP 直连支持
版本: v0.5.0 | 状态: 开发中 | 分支: fs-only-v3 → u-desk-sftp
概述
为 U-Desk 新增 SFTP(SSH File Transfer Protocol)直连模式,作为第三种文件系统传输方式,与现有的本地模式(Wails IPC)和远程 HTTP Agent 模式并列。
用户无需在目标机器部署任何 Agent 服务,仅需 SSH 账号即可直接浏览和操作远程 Linux 服务器的文件系统。
架构设计
FsTransport (interface)
├── WailsTransport → Wails IPC → FileSystemService (本地 os)
├── HttpTransport → HTTP REST → u-fs-agent (远程部署)
└── SftpTransport [NEW]→ Wails IPC → SftpService → pkg/sftp (SSH/SFTP)
核心原则:复用现有 FsTransport 接口抽象,前端组件无感知。
技术方案
后端(Go)
新增依赖:
github.com/pkg/sftp— SFTP 客户端库golang.org/x/crypto/ssh— SSH 协议(已在 indirect 中,提升为 direct)
新增包 internal/sftp/(4 个文件):
| 文件 | 职责 |
|---|---|
config.go |
Config 结构体:Host/Port/Username/Password/KeyPath/Timeout |
client.go |
Manager(sync.Map 连接池,以 host:port 为 key)+ Client(单连接封装:SSH 握手、健康检查、自动重连、双认证) |
service.go |
Service(对齐 FileSystemService 返回格式的文件操作方法) |
errors.go |
ConnectionError + ToUserMessage() 中文友好错误映射 |
连接管理:
- 以
host:port为 key 的sync.Map连接池 - 支持密码认证 / 私钥文件认证(二选一)
WithRetry(fn)— 操作前检查健康度,断线自动重连(3 次,指数退避)IsHealthy()— 通过Stat("/")探测- 切换 profile 时复用已有连接(避免重复 SSH 握手)
App 层新增绑定方法(12 个):
SftpConnect(req) → connID 建立连接
SftpDisconnect(connID) 断开连接
SftpListDir(connID, path) 列目录
SftpReadFile(connID, path) 读文件
SftpWriteFile(req) 写文件
SftpGetFileInfo(connID, path) 文件信息
SftpCreateDir(connID, path) 创建目录
SftpCreateFile(connID, path) 创建文件
SftpDeletePath(connID, path) 删除
SftpRenamePath(req) 重命名
SftpDownloadToTemp(connID, path) 下载到临时目录(预览用)
SftpGetCommonPaths(connID) 远程主机常用路径
前端(TypeScript/Vue)
新建 frontend/src/api/sftp-transport.ts:
- 实现
FsTransport接口的完整 23 个方法 connect()/disconnect()/requireConn()管理 SFTP 会话生命周期downloadForPreview(remotePath)下载远程文件到本地临时目录(带缓存)- ZIP/回收站/openPath 等不适用方法抛出 "暂未实现"
修改 connection-manager.ts:
ConnectionType扩展:'local' | 'remote' | 'sftp'ConnectionProfile新增字段:username?,password?,keyPath?applyActive()增加 sftp 分支(创建 SftpTransport → connect() → 连通性检查)- 新增
isSftp()方法 isRemote()扩展为包含'sftp'getFileServerBaseURL()sftp 模式返回'http://localhost:8073'- 切换/删除 profile 时显式断开 SFTP 连接
修改 ConnectionDialog.vue:
- 新增连接类型选择器(RadioGroup: HTTP Agent / SFTP)
- SFTP 类型显示额外字段:用户名(默认 root)、密码、私钥路径
- HTTP Agent 类型保持原有 Token 字段
- 默认端口根据类型切换(SFTP=22,HTTP=9876)
addProfile时 type 使用表单选择的值
修改 ConnectionIndicator.vue:
.dot.sftp样式(紫色#7c3aed)dotClass(p)函数返回 local/remote/sftp- "更多操作"按钮条件从
type === 'remote'改为type !== 'local'
修改 Sidebar.vue:
- 模式标签区分显示:本地(绿)/远程(蓝)/SFTP(紫)
- 新增
isSftp响应式变量
修改 useFilePreview.ts:
- SFTP 模式下
updatePreviewUrl()先调用downloadForPreview()下载到本地临时目录 - 下载完成后使用
http://localhost:8073/localfs/{temp_path}预览(复用现有 LocalFileServer) - 已下载文件缓存避免重复下载
文件预览方案
策略:下载到本地临时目录 + 复用 LocalFileServer
用户点击 SFTP 远程文件
→ useFilePreview 检测 isSftp()
→ SftpTransport.downloadForPreview(remotePath)
→ Go 后端 SFTP 下载到 %TEMP%/udesk-sftp-preview-{filename}
→ 返回本地绝对路径
→ 预览 URL = http://localhost:8073/localfs/{temp_path}
→ 现有 LocalFileServer 直接提供服务
临时文件管理:
- 启动时清理上次遗留的
udesk-sftp-preview-*文件(ServiceStartup中调用CleanupTempFiles()) - 关闭时清理本次创建的临时文件(
ServiceShutdown中调用) - SftpTransport 内部维护 remotePath → localTempPath 缓存
文件变更清单
新增(5 个)
| 文件 | 说明 |
|---|---|
internal/sftp/config.go |
SFTP 配置结构体 |
internal/sftp/client.go |
SSH/SFTP 连接管理器 |
internal/sftp/service.go |
SFTP 文件操作服务 |
internal/sftp/errors.go |
错误处理 + 用户友好消息 |
frontend/src/api/sftp-transport.ts |
前端 FsTransport 实现 |
修改(8 个)
| 文件 | 变更 |
|---|---|
go.mod |
添加 github.com/pkg/sftp 依赖 |
internal/filesystem/fs.go |
formatBytes 导出为 FormatBytes |
app.go |
+sftpService 字段 + 12 个绑定方法 + Shutdown 扩展 + 清理临时文件 |
frontend/src/api/connection-manager.ts |
类型扩展 + sftp 分支 + isSftp() |
frontend/src/.../ConnectionDialog.vue |
类型选择器 + SFTP 表单 |
frontend/src/.../ConnectionIndicator.vue |
sftp 样式 + dotClass |
frontend/src/.../Sidebar.vue |
SFTP 模式标签 |
frontend/src/.../useFilePreview.ts |
SFTP 下载预览 |
自动生成
| 文件 | 触发方式 |
|---|---|
frontend/src/wailsjs/v3-bindings/u-desk/app.ts |
wails dev 启动时重新生成 |
与现有模式的对比
| 特性 | 本地 (WailsTransport) | 远程 (HttpTransport) | SFTP (SftpTransport) |
|---|---|---|---|
| 协议 | Wails IPC | HTTP REST | SSH/SFTP |
| 目标要求 | 本地桌面 | 部署 u-fs-agent | SSH 服务 |
| 认证 | 无 | Bearer Token | 密码 / 私钥 |
| 文件预览 | LocalFileServer | Agent 反向代理 | 下载到临时目录 |
| ZIP 支持 | ✅ | ❌ | ❌ |
| 回收站 | ✅ | ❌ | ❌ |
| 延迟 | < 10ms | 取决于网络 | 取决于网络(首次握手 ~2s) |
| 连接复用 | N/A | 每次请求 HTTP | sync.Map 连接池 |
后续迭代方向
Phase 2(体验完善)
- 密钥文件选择器(Wails OpenFileDialog)
- 断线重连 UI 提示 + 手动重连按钮
- 大文件传输进度显示
- saveBase64File 二进制上传支持
Phase 3(高级功能)
- SSH known_hosts 安全验证(替换 InsecureIgnoreHostKey)
- TCP KeepAlive + 应用层心跳防空闲断开
- 端口转发(SOCKS5/本地转发)
- 符号链接处理选项
- 并发传输队列 + 带宽限制