mirror of
https://github.com/shadowsocks/ShadowsocksX-NG.git
synced 2026-11-08 13:44:51 +00:00
83 lines
3.2 KiB
Swift
83 lines
3.2 KiB
Swift
import Foundation
|
||
|
||
/// LaunchAgent 注册态(GUI 视角):SMAppService.Status 的纯域
|
||
/// 映射。SMAppService 不暴露运行中 agent 的 pid,wrapper 活性另由
|
||
/// `WrapperProcessState` 表达。
|
||
enum LaunchAgentStatus: Equatable, Sendable {
|
||
case notRegistered
|
||
/// 已注册(无论 wrapper 进程当前是否在运行)。
|
||
case registered
|
||
/// 需要用户在系统设置的登录项中批准。
|
||
case requiresApproval
|
||
/// 注册清单缺失(bundle 内 plist 不在)。
|
||
case notFound
|
||
}
|
||
|
||
/// wrapper 进程活性:GUI 读 `agent.pid` 并以 `kill(pid, 0)` 判定。
|
||
enum WrapperProcessState: Equatable, Sendable {
|
||
case notRunning
|
||
case running(pid: Int32)
|
||
}
|
||
|
||
/// GUI 对代理运行时的意图:运行给定义档,或停止并清理。
|
||
enum RuntimeIntent: Equatable {
|
||
case run(SslocalRuntimeDocument)
|
||
case stop
|
||
}
|
||
|
||
/// 控制器按序执行的动作。
|
||
enum RuntimeAction: Equatable, Sendable {
|
||
/// 原子写契约文件(权限与替换基线由 RuntimeFileStore 保证)。
|
||
case writeContract
|
||
/// 注册 LaunchAgent;launchd 随即拉起 wrapper,wrapper 启动时读契约。
|
||
case registerAgent
|
||
/// 注销 LaunchAgent:launchd 以 SIGTERM 结束 wrapper,触发显式停止协议
|
||
/// (wrapper 停 sslocal 并等待退出)。
|
||
case unregisterAgent
|
||
/// 通知运行中的 wrapper 重读契约;热重载或优雅重启由 wrapper 按监听
|
||
/// 指纹判定遵循变更协议。
|
||
case signalReload(pid: Int32)
|
||
/// 删除运行时文件(契约、pid 文件与残留临时文件)。
|
||
case deleteRuntimeFiles
|
||
}
|
||
|
||
/// 纯决策层:把「代理意图 + launchd 注册态 + wrapper 活性
|
||
/// + 磁盘契约」推到有序动作序列。GUI 启动重同步、目录提交重展开与代理开关
|
||
/// 共用同一决策;相同契约内容跳过写入,兑现激活状态机的幂等注记。
|
||
enum ProxyRuntimePlan {
|
||
static func actions(
|
||
intent: RuntimeIntent,
|
||
agentStatus: LaunchAgentStatus,
|
||
wrapper: WrapperProcessState,
|
||
configurationIsCurrent: Bool
|
||
) -> [RuntimeAction] {
|
||
switch intent {
|
||
case .run:
|
||
switch agentStatus {
|
||
case .notRegistered, .notFound, .requiresApproval:
|
||
// 首次启用或从未注册:写盘后注册,launchd 拉起的 wrapper 直接读新档。
|
||
return [.writeContract, .registerAgent]
|
||
case .registered:
|
||
switch wrapper {
|
||
case .running(let pid):
|
||
if configurationIsCurrent { return [] }
|
||
return [.writeContract, .signalReload(pid: pid)]
|
||
case .notRunning:
|
||
// 已注册但 wrapper 已干净退出(如契约曾被清理):强制重新拉起。
|
||
// SMAppService 对已注册服务重复 register 不保证重跑,先注销再注册。
|
||
return [.writeContract, .unregisterAgent, .registerAgent]
|
||
}
|
||
}
|
||
case .stop:
|
||
switch agentStatus {
|
||
case .registered:
|
||
// 显式停止协议次序:注销即 SIGTERM wrapper → wrapper 停 sslocal
|
||
// 并等待 → 控制器确认 wrapper 退出后才删文件(执行侧保证次序)。
|
||
return [.unregisterAgent, .deleteRuntimeFiles]
|
||
case .notRegistered, .requiresApproval, .notFound:
|
||
return [.deleteRuntimeFiles]
|
||
}
|
||
}
|
||
}
|
||
}
|