Files

97 lines
3.8 KiB
Swift

import Foundation
/// Pure projection of one SystemConfiguration Proxies dictionary. The key mapping is a
/// mechanical translation of the closed typed configuration : every field the
/// GUI supplies is written, disabled protocols lose their endpoint keys, PAC/auto-
/// discovery/simple-hostname exclusion follow their explicit flags, and the complete
/// exceptions list is always written. Keys outside the typed field set are preserved.
enum SystemProxyPropertyList {
static let httpEnabled = "HTTPEnable"
static let httpsEnabled = "HTTPSEnable"
static let socksEnabled = "SOCKSEnable"
static let httpPort = "HTTPPort"
static let httpProxy = "HTTPProxy"
static let httpsPort = "HTTPSPort"
static let httpsProxy = "HTTPSProxy"
static let socksPort = "SOCKSPort"
static let socksProxy = "SOCKSProxy"
static let pacEnabled = "ProxyAutoConfigEnable"
static let pacURL = "ProxyAutoConfigURLString"
static let pacJavaScript = "ProxyAutoConfigJavaScript"
static let autoDiscoveryEnabled = "ProxyAutoDiscoveryEnable"
static let exceptionsList = "ExceptionsList"
static let excludeSimpleHostnames = "ExcludeSimpleHostnames"
/// 一个协议族的 Proxies 键组。
private struct ProtocolKeys {
let enable: String
let proxy: String
let port: String
}
static func applying(
_ configuration: SystemProxyConfiguration, to original: [String: Any]
) -> [String: Any] {
var dictionary = original
applyProtocol(
enabled: configuration.socksEnabled, endpoint: configuration.socks,
keys: ProtocolKeys(enable: socksEnabled, proxy: socksProxy, port: socksPort),
into: &dictionary)
applyProtocol(
enabled: configuration.httpEnabled, endpoint: configuration.http,
keys: ProtocolKeys(enable: httpEnabled, proxy: httpProxy, port: httpPort),
into: &dictionary)
applyProtocol(
enabled: configuration.httpsEnabled, endpoint: configuration.https,
keys: ProtocolKeys(enable: httpsEnabled, proxy: httpsProxy, port: httpsPort),
into: &dictionary)
dictionary[pacEnabled] = configuration.pacEnabled ? 1 : 0
if !configuration.pacEnabled {
// 关闭的 PAC 不留残余:URL 与 JavaScript 值一并移除。
dictionary.removeValue(forKey: pacJavaScript)
dictionary.removeValue(forKey: pacURL)
}
dictionary[autoDiscoveryEnabled] = configuration.autoDiscoveryEnabled ? 1 : 0
dictionary[excludeSimpleHostnames] = configuration.excludeSimpleHostnames ? 1 : 0
dictionary[exceptionsList] = configuration.exceptions
return dictionary
}
/// Normalize only values whose SystemConfiguration meaning is equivalent.
/// Unknown fields stay verbatim; stale managed endpoint/PAC values still differ.
static func semanticallyNormalized(_ original: [String: Any]) -> [String: Any] {
var values = original
for key in [
httpEnabled, httpsEnabled, socksEnabled, pacEnabled,
autoDiscoveryEnabled, excludeSimpleHostnames,
] {
if let number = values[key] as? NSNumber {
values[key] = number.boolValue ? 1 : 0
} else if values[key] == nil {
values[key] = 0
}
}
if let exceptions = values[exceptionsList] as? [String] {
values[exceptionsList] = Set(exceptions).sorted()
}
return values
}
/// 启用的协议族写入显式端点;关闭的协议族移除端点键,保持字典与配置一致。
private static func applyProtocol(
enabled: Bool, endpoint: SystemProxyConfiguration.Endpoint,
keys: ProtocolKeys,
into dictionary: inout [String: Any]
) {
dictionary[keys.enable] = enabled ? 1 : 0
if enabled {
dictionary[keys.proxy] = endpoint.host
dictionary[keys.port] = endpoint.port
} else {
dictionary.removeValue(forKey: keys.proxy)
dictionary.removeValue(forKey: keys.port)
}
}
}