Files

106 lines
4.1 KiB
Swift
Raw Permalink 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
// MARK: - 只读事实投影与静态缝
extension ProxyRuntimeController {
var isActiveTargetPresent: Bool { machine.activeTargetID != nil }
/// Agent 开关意图(持久化事实;开关 UI 的绑定来源)。
var agentIntentEnabled: Bool { settings.agentEnabled }
/// 系统代理开关意图(持久化事实;开关 UI 的绑定来源)。
var systemProxyIntentEnabled: Bool { settings.systemProxyEnabled }
/// 系统代理观察机的呈现事实门面:存储与发布在 `SystemProxyObserver`,
/// 此处只读投影供既有测试与诊断面沿用原名。
var systemProxyState: SystemProxyApplicationFacts { systemProxyObserver.systemProxyState }
var systemProxyApprovalRequired: Bool { systemProxyObserver.systemProxyApprovalRequired }
var systemProxyInspection: SystemProxyInspectionFacts {
systemProxyObserver.systemProxyInspection
}
/// Desired system proxy configuration:当前保存设置要求的代理值(ADR-0022)。
/// 观察机经 init 闭包读取同一事实源。`nil` 只表示尚无运行时文档。
var desiredSystemProxyConfiguration: SystemProxyConfiguration? {
guard let document = runtimeObservation else { return nil }
return proxyMode.systemProxyConfiguration(
for: document.listen, exceptions: settings.proxyExceptionList)
}
/// Stable app-facing projection for status-menu presentation. The menu does
/// not depend on this controller's nested state representation.
var runtimeFacts: ProxyRuntimeFacts {
let facts = ProxyRuntimeFacts(state: state)
return ProxyRuntimeFacts(
status: facts.status, isOn: facts.isOn,
failure: facts.failure
?? (proxyMode == .rule && settings.agentEnabled ? ruleApplicationFailure : nil))
}
static var defaultFirewallExecutableURLs: [URL] {
let bundle = Bundle.main.bundleURL
return [
bundle.appendingPathComponent("Contents/MacOS/ShadowsocksX-NG2Agent"),
bundle.appendingPathComponent("Contents/Helpers/sslocal"),
]
}
/// 诊断只读面:当前监听设置;监听地址在导出中只以回环/非回环
/// 两态呈现。
var listenSettings: ProxyListeningConfiguration { settings.listen }
/// 当前已部署 runtime 的完整监听身份。已停止或启动失败时没有有效的
/// runtime 例外,不能拿最后一次设置快照冒充仍在监听。
var effectiveRuntimeListenFacts: RuntimeListenFacts? {
let isListening: Bool
switch state {
case .running, .firewallBlocked:
isListening = true
case .off, .starting, .launchFailed, .requiresApproval, .serviceFailed:
isListening = false
}
guard isListening, let runtimeObservation else { return nil }
return runtimeObservation.listen
}
/// PID of the sslocal child that owns the active runtime document. A process
/// name alone is not sufficient to treat an occupied listener as replaceable.
var effectiveRuntimeListenerProcessID: Int32? {
guard effectiveRuntimeListenFacts != nil,
let runtimeObservation,
let receipt = runtimeFileStore.readRuntimeReceipt(),
receipt.deploymentID
== runtimeFileStore.receiptIdentity(for: runtimeObservation.intentSHA256),
processIsAlive(receipt.processID)
else { return nil }
return receipt.processID
}
/// 运行时契约的脱敏摘要(数量与协议元数据);契约缺失或无效返回 nil。
/// 诊断导出不读契约内容,只携带此摘要。
func runtimeDocumentSummary() -> String? {
runtimeFileStore.publishedSummary()
}
}
extension ProxyRuntimeController.AgentRunState {
/// Agent 运行状态的「在跑」投影(状态摘要与诊断口径):启动失败等未运行
/// 态视为未跑。
var isOn: Bool {
switch self {
case .off, .launchFailed, .serviceFailed:
false
case .starting, .running, .firewallBlocked, .requiresApproval:
true
}
}
}
extension ProxyRuntimeController: Activating {}
extension ProxyRuntimeController {
static func makeProxyMode(from settings: ProxyRuntimeSettings) -> ProxyMode {
ProxyMode.availableModes.first { $0.kind == settings.preferredMode } ?? .rule
}
}