feat: v0.3.0 版本 - SSH终端、SFTP、端口转发功能实现

核心功能:
- SSH终端: 密码/密钥认证、XTerm.js终端、多主题配色、IP高亮
- SFTP管理: 双栏文件管理、上传下载、传输队列
- 端口转发: 本地/远程转发、SOCKS5动态代理、规则管理

架构改进:
- 拆分大型组件 (SFTPView/TabBar/Sidebar)
- 添加统一日志和错误处理
- 修复React严格模式下的终端黑屏问题

UI更新:
- 新增端口转发视图
- 更新UI预览文档
- 左侧栏右键菜单支持SFTP快捷打开
This commit is contained in:
Logan.Li committed 2026-04-06 01:20:47 +08:00
1 parent cf1c054381
commit 484d850abd
105 files changed
+25330 -64

No files matched your search

+85
View File
@@ -0,0 +1,85 @@
/**
* Connection Types - 统一的连接类型定义
* 在主进程和渲染进程间共享
*/
import type { SSHConnectionConfig } from './session.types'
// Re-export for convenience
export type { SSHConnectionConfig as ConnectionConfig } from './session.types'
// 连接状态
export type ConnectionState =
| 'disconnected' // 初始/已关闭
| 'connecting' // 正在连接
| 'connected' // 活跃连接
| 'background' // 后台保持
| 'suspended' // 挂起 (长时间未操作)
| 'error' // 连接错误
| 'reconnecting' // 正在重连
// 连接统计信息
export interface ConnectionStats {
connectedAt: number // 连接建立时间
lastActivityAt: number // 最后活动时间
lastBackgroundAt?: number // 进入后台时间
bytesTransferred: number // 传输字节数
commandsExecuted: number // 执行的命令数 (估算)
}
// 连接池配置
export interface PoolConfig {
maxConnections: number // 最大连接数 (默认 10)
maxBackgroundConnections: number // 最大后台连接数 (默认 5)
idleTimeoutMs: number // 空闲超时 (默认 5 分钟)
suspendTimeoutMs: number // 挂起超时 (默认 30 分钟)
keepaliveIntervalMs: number // 保活间隔 (默认 60 秒)
maxReconnectAttempts: number // 最大重连次数 (默认 3)
}
// 连接池中的连接项
export interface PooledConnection {
connectionId: string
config: SSHConnectionConfig
state: ConnectionState
error?: string
// 引用管理
refCount: number // 引用计数
tabIds: Set<string> // 哪些标签在使用这个连接
activeTabId: string | null // 当前活跃的标签
// 会话 ID
sessionId?: string
// Shell/SFTP 会话
shellIds: Set<string> // 该连接上创建的 shell 会话
sftpIds: Set<string> // 该连接上创建的 sftp 会话
// 统计
stats: ConnectionStats
// 定时器 ID (浏览器环境)
keepaliveInterval?: number // 保活定时器 ID
idleTimeout?: number // 空闲超时定时器 ID
// 重连
reconnectAttempts: number // 重连尝试次数
maxReconnectAttempts: number // 最大重连次数
}
// 连接结果
export interface ConnectionResult {
success: boolean
connectionId?: string
error?: string
isExisting?: boolean
}
// Shell 会话信息
export interface ShellInfo {
shellId: string
connectionId: string
cols: number
rows: number
}
+10
View File
@@ -0,0 +1,10 @@
/**
* Shared Types - 统一类型导出
* 在主进程和渲染进程间共享
*/
// Re-export all types
export * from './session.types'
export * from './connection.types'
export * from './sftp.types'
export * from './ipc.types'
+248
View File
@@ -0,0 +1,248 @@
/**
* IPC Types - 统一的 IPC 类型定义
* 定义所有 IPC 请求/响应的类型
*/
import type { Session } from './session.types'
// ============== SSH IPC ==============
export interface SSHConnectRequest {
host: string
port: number
username: string
password?: string
privateKey?: string
passphrase?: string
}
export interface SSHConnectResponse {
success: boolean
connectionId?: string
error?: string
}
export interface SSHExecRequest {
connectionId: string
command: string
}
export interface SSHExecResponse {
success: boolean
output?: string
error?: string
}
export interface SSHCreateShellRequest {
connectionId: string
cols?: number
rows?: number
}
export interface SSHCreateShellResponse {
success: boolean
shellId?: string
error?: string
}
export interface SSHShellWriteRequest {
shellId: string
data: string
}
export interface SSHShellResizeRequest {
shellId: string
cols: number
rows: number
}
// ============== Port Forward IPC ==============
export interface SSHForwardLocalRequest {
connectionId: string
localPort: number
remoteHost: string
remotePort: number
}
export interface SSHForwardRemoteRequest {
connectionId: string
remotePort: number
localHost: string
localPort: number
}
export interface SSHForwardDynamicRequest {
connectionId: string
localPort: number
}
export interface SSHForwardResponse {
success: boolean
boundPort?: number
error?: string
}
// ============== Session IPC ==============
export interface SessionCreateResponse {
success: boolean
session?: Session
error?: string
}
export interface SessionUpdateResponse {
success: boolean
session?: Session
error?: string
}
export interface SessionDeleteResponse {
success: boolean
error?: string
}
// ============== Settings IPC ==============
export interface SettingsGetRequest {
key: string
}
export interface SettingsSetRequest {
key: string
value: unknown
}
// ============== Dialog IPC ==============
export interface DialogOptions {
title?: string
defaultPath?: string
filters?: { name: string; extensions: string[] }[]
properties?: ('openFile' | 'openDirectory' | 'multiSelections')[]
}
export interface DialogResult {
canceled: boolean
filePath?: string
filePaths?: string[]
}
// ============== File IPC ==============
export interface FileReadRequest {
filePath: string
}
export interface FileWriteRequest {
filePath: string
data: string
}
export interface FileOperationResponse {
success: boolean
error?: string
}
export interface FileStats {
size: number
modified: number
isDirectory: boolean
isFile: boolean
}
export interface DirEntry {
name: string
path: string
isDirectory: boolean
}
// ============== Zmodem IPC ==============
export interface ZmodemProgress {
sessionId: string
fileName: string
progress: number
bytesTransferred: number
totalBytes: number
}
export interface ZmodemComplete {
sessionId: string
success: boolean
fileName?: string
error?: string
}
// ============== App IPC ==============
export interface AppVersionResponse {
version: string
}
// ============== IPC Channel Names ==============
export const IPC_CHANNELS = {
// SSH
SSH_CONNECT: 'ssh:connect',
SSH_DISCONNECT: 'ssh:disconnect',
SSH_EXEC: 'ssh:exec',
SSH_CREATE_SHELL: 'ssh:createShell',
SSH_SHELL_WRITE: 'ssh:shellWrite',
SSH_SHELL_RESIZE: 'ssh:shellResize',
SSH_FORWARD_LOCAL: 'ssh:forwardLocal',
SSH_FORWARD_REMOTE: 'ssh:forwardRemote',
SSH_FORWARD_DYNAMIC: 'ssh:forwardDynamic',
// SFTP
SFTP_CONNECT: 'sftp:connect',
SFTP_LIST_DIRECTORY: 'sftp:listDirectory',
SFTP_UPLOAD: 'sftp:upload',
SFTP_DOWNLOAD: 'sftp:download',
SFTP_RENAME: 'sftp:rename',
SFTP_DELETE: 'sftp:delete',
// Session
SESSION_CREATE: 'session:create',
SESSION_GET_ALL: 'session:getAll',
SESSION_GET_BY_ID: 'session:getById',
SESSION_UPDATE: 'session:update',
SESSION_DELETE: 'session:delete',
// Settings
SETTINGS_GET: 'settings:get',
SETTINGS_SET: 'settings:set',
// Dialog
DIALOG_SHOW_SAVE: 'dialog:showSaveDialog',
DIALOG_SHOW_OPEN: 'dialog:showOpenDialog',
// App
APP_GET_VERSION: 'app:getVersion',
APP_GET_DOWNLOADS_PATH: 'app:getDownloadsPath',
// File
FILE_READ: 'file:read',
FILE_WRITE: 'file:write',
LOCAL_GET_HOME: 'local:getHome',
LOCAL_READ_DIR: 'local:readDir',
LOCAL_GET_STATS: 'local:getStats',
LOCAL_DELETE: 'local:delete',
LOCAL_RENAME: 'local:rename',
LOCAL_MKDIR: 'local:mkdir',
// Zmodem
ZMODEM_SEND: 'zmodem:send',
ZMODEM_RECEIVE: 'zmodem:receive',
ZMODEM_CANCEL: 'zmodem:cancel',
// Events (renderer listens)
SHELL_DATA: 'ssh:shellData',
SFTP_PROGRESS: 'sftp:progress',
ZMODEM_PROGRESS: 'zmodem:progress',
ZMODEM_COMPLETE: 'zmodem:complete',
MENU_NEW_SESSION: 'menu-new-session',
MENU_QUICK_CONNECT: 'menu-quick-connect',
MENU_IMPORT_SESSIONS: 'menu-import-sessions',
MENU_EXPORT_SESSIONS: 'menu-export-sessions',
} as const
+51
View File
@@ -0,0 +1,51 @@
/**
* Session Types - 统一的会话类型定义
* 在主进程和渲染进程间共享
*/
// 认证方式
export type AuthType = 'password' | 'key' | 'agent'
// 会话配置 (用于快速连接)
export interface SSHConnectionConfig {
host: string
port: number
username: string
password?: string
privateKey?: string
passphrase?: string
}
// 持久化会话
export interface Session {
id: string
name: string
host: string
port: number
username: string
authType: AuthType
password?: string // 加密存储
privateKey?: string // 私钥路径或内容
passphrase?: string // 私钥密码
group?: string
tags?: string[]
createdAt?: number
updatedAt?: number
}
// 会话创建请求
export interface SessionCreateRequest {
name: string
host: string
port: number
username: string
authType: AuthType
password?: string
privateKey?: string
passphrase?: string
group?: string
tags?: string[]
}
// 会话更新请求
export type SessionUpdateRequest = Partial<Omit<Session, 'id' | 'createdAt' | 'updatedAt'>>
+47
View File
@@ -0,0 +1,47 @@
/**
* SFTP Types - 统一的 SFTP 类型定义
* 在主进程和渲染进程间共享
*/
// 文件项
export interface FileItem {
name: string
path: string
type: 'file' | 'directory' | 'symlink'
size: number
modified: number // Unix timestamp
permissions: string
}
// 传输任务
export interface TransferTask {
id: string
type: 'upload' | 'download'
fileName: string
filePath: string
status: 'pending' | 'transferring' | 'completed' | 'failed' | 'canceled'
progress: number
error?: string
total: number
transferred: number
speed?: number // bytes per second
startTime?: number
}
// 传输进度
export interface TransferProgress {
taskId: string
transferred: number
total: number
speed: number
}
// 文件列表排序
export type SortField = 'name' | 'size' | 'modified' | 'type'
export type SortOrder = 'asc' | 'desc'
// SFTP 操作结果
export interface SFTPOperationResult {
success: boolean
error?: string
}