Files
ShadowsocksX-NG/ShadowsocksX-NG2/Domain/SystemProxyHelperContract.swift
T
Qiu Yuzhou 7d0ebc79b4 refactor(tests): drop TEST_HOST by linking tests against app-source static lib
单测不再以 app 可执行为宿主:新增 ShadowsocksX-NG2Core 静态库 target 同源
编译 App/(除 @main)与 Domain/,模块名沿用 ShadowsocksX_NG2 使全部测试的
@testable import 零改动;app target 模块改名 ShadowsocksX_NG2App 避免共享
Products 目录 swiftmodule 撞名。两个测试 target 改链 Core 后 xcodegen 不再
生成 TEST_HOST,xcodebuild test 只构建不启动 app——与安装版运行实例零接触
(pgrep 全程验证无 app 进程)。同源双编译沿用 Agent/Helper 共享 Domain 文件
的既定模式,Core 只被测试 target 依赖,发布链不编译它。

随之删除 MainApp.swift 的整套测试宿主脚手架(isUnitTesting/makeTesting/
Noop 服务/Ephemeral 存储,-142 行),app 在测试下不再启动,守卫失去存在
理由。宿主移除暴露三处 Bundle.main 依赖,改为显式缝:控制器新增 appBundle
注入(内置规则快照 BuiltinRuleCatalog 与 LaunchDaemon 清单指纹
launchDaemonPlistData(in:) 均按 bundle 读取,生产默认 .main 不变);XPC
listener delegate 期望客户端身份改为可注入(测试按本进程 SecCode 自查)。
测试经 AppArtifact.bundle(沿测试包落盘位置向上查找 app 产物,兼容
TEST_HOST 内嵌与平级两种布局)统一取产物。

665 单测 + 11 冒烟全绿,task build 生产构建不受影响。
2026-09-30 20:44:13 +08:00

76 lines
3.2 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import Foundation
/// GUI 与特权系统代理 helper 的共享 XPC 契约(issue #71)。类型同时编入 GUI、
/// helper 与测试 target;payload 以 JSON 编码保持 closed typed 语义。
@objc protocol SystemProxyHelperControlling {
/// 应用 closed typed 配置到活动网络位置的每个服务。
func apply(_ payload: Data, withReply reply: @escaping (Data) -> Void)
/// 无条件清除全部网络位置全部服务的完整 Proxies 字典。
func clear(withReply reply: @escaping (Data) -> Void)
}
/// helper 的固定身份:MachService 名、LaunchDaemon plist 名与客户端校验基准。
/// 客户端只按 2.0 的 bundle identifier(代码签名 identifier)接受,不限
/// Team ID 或账号(issue #71)。
enum SystemProxyHelperIdentity {
static let machServiceName = "com.qiuyuzhou.ShadowsocksX-NG2.systemproxy"
static let plistName = "com.qiuyuzhou.ShadowsocksX-NG2.systemproxy.plist"
static let launchdLabel = "com.qiuyuzhou.ShadowsocksX-NG2.systemproxy"
static let clientCodeSigningIdentifier = "com.qiuyuzhou.ShadowsocksX-NG2"
/// App bundle 内 LaunchDaemon 清单内容(注册漂移指纹的基准)。helper 进程
/// 内没有 bundle,返回 nil,调用方按「无基准不动作」处理。Contents/Library
/// 不是资源目录,Bundle 资源 API 搜不到,按固定路径直读。bundle 参数生产
/// 默认 Bundle.main;去宿主化(ADR 0021)后单测经控制器的 appBundle 缝注入
/// 构建产物 bundle。
static func launchDaemonPlistData(in bundle: Bundle = .main) -> Data? {
let url = bundle.bundleURL
.appendingPathComponent("Contents/Library/LaunchDaemons")
.appendingPathComponent(plistName)
return try? Data(contentsOf: url)
}
}
/// helper XPC 应答:成功携带 typed 结果,失败携带 typed 错误族。
enum SystemProxyHelperResponse: Equatable, Sendable, Codable {
case applied(SystemProxyWriteOutcome)
case cleared
case failure(SystemProxyError)
}
enum SystemProxyHelperWireError: Error, Equatable, Sendable {
case undecodableResponse(String)
}
enum SystemProxyHelperWire {
/// SystemProxyHelperResponse 全部由简单可编码类型组成,JSON 编码不可失败;
/// 若未来加入不可编码载荷,显式失败好过发出无法解码的应答。
static func encode(_ response: SystemProxyHelperResponse) -> Data {
do {
return try JSONEncoder().encode(response)
} catch {
preconditionFailure("system proxy helper response encode failed: \(error)")
}
}
static func decode(_ payload: Data) throws -> SystemProxyHelperResponse {
do {
return try JSONDecoder().decode(SystemProxyHelperResponse.self, from: payload)
} catch {
throw SystemProxyHelperWireError.undecodableResponse(String(describing: error))
}
}
static func encodeConfiguration(_ configuration: SystemProxyConfiguration) throws -> Data {
try JSONEncoder().encode(configuration)
}
static func decodeConfiguration(_ payload: Data) throws -> SystemProxyConfiguration {
do {
return try JSONDecoder().decode(SystemProxyConfiguration.self, from: payload)
} catch {
throw SystemProxyError.invalidRequest(String(describing: error))
}
}
}