系统架构
NetShuttle 采用“共享业务层 + 平台适配层”。共享核心保留在 Core、Models、Engine、Storage 和 Managers,不为了目录整齐进行大规模搬迁。
NetShuttleApp(条件编译入口)├── macOS: MenuBarExtra / Settings / Help / TTY CLI└── iOS / iPadOS: WindowGroup / AdaptiveMainView
Shared├── ServiceContainer / ServiceProtocols├── SSHEngine / PortForwardingManager / ProxyJumpHandler├── SSHConnectionManager / AutoReconnectManager / NetworkMonitor├── StorageProvider / Local / iCloud / DataMigrator└── ShellSession / ShellSessionManager / SSHShellSessionManager
Models├── SSHServerConfiguration├── TunnelConfiguration├── PortForwardRule├── AuthMethod└── ForwardingMode
UI and Platform├── ViewModels├── Shared Views├── macOS AppKit / MenuBarExtra└── iOS UIKit / SwiftTerm / Adaptive NavigationServiceContainer 是单例 DI 容器,集中持有连接、网络、速率与自动重连服务。测试可以通过 override* 注入 Mock,resetToDefaults() 恢复默认实现。
这层边界的目的是让网络状态、重连计时器和存储迁移不直接嵌入 SwiftUI View,也不会把 NIO Channel 或 EventLoop 带入 UI 状态。
共享 EventLoop
Section titled “共享 EventLoop”所有 SSH 连接复用 SSHConnectionManager 持有的单线程 MultiThreadedEventLoopGroup。连接数量增加时,不额外创建独立线程池。
- Local、iCloud Provider 和
DataMigrator使用actor隔离可变状态。 - 跨执行器接口使用
async throws和Sendable。 - 项目启用 Complete Strict Concurrency Checking,不使用
@unchecked Sendable绕过检查。 - SSH Channel 仅在对应 EventLoop 上操作;跨线程共享的可变状态必须加锁或串行化。
- SwiftUI 状态层使用
@MainActor,不持有 NIO Channel 或 EventLoop。
TerminalLaunching 隔离业务层与平台终端:
- macOS:
LocalTerminalManager+ Unix Socket TTY Bridge + 外部终端 CLI。 - iOS / iPadOS:
MobileTerminalLauncher+ SwiftTerm 直接附加 ShellSession。
两条路径共享 Shell 生命周期,但不共享传输和展示适配层。
- 使用 SwiftNIO SSH,避免管理外部 SSH 进程。
- 每条转发规则独立管理,保证独立启停。
- 用户断开与意外断开分开记录。
- 配置、Secret 和日志有明确同步边界。
- 终端品牌不进入 Swift 分支,由 JSON Profile 和通用启动策略描述。