mirror of
https://github.com/shadowsocks/ShadowsocksX-NG.git
synced 2026-11-08 10:44:50 +00:00
Add Mainland China proxy routing with independent rule workspaces. Preserve existing routing choices through equivalent preset mappings. BREAKING CHANGE: existing custom rules and enablement settings are not migrated. Recreate them in the appropriate preset.
101 lines
3.1 KiB
Swift
101 lines
3.1 KiB
Swift
import Foundation
|
|
|
|
/// Persisted identity of a proxy mode. PAC is gone: the product
|
|
/// exposes rule / global / direct only.
|
|
enum ProxyModeKind: String, Codable, CaseIterable, Equatable, Hashable, Sendable {
|
|
case rule
|
|
case global
|
|
case direct
|
|
}
|
|
|
|
/// The mutually exclusive ways in which 2.0 exposes the local proxy to macOS.
|
|
/// Hashable 供菜单栏模式选择的勾选态 Picker 使用。
|
|
/// 规则模式另持久化 `RulePreset` 子选项。
|
|
enum ProxyMode: Codable, Equatable, Hashable, Sendable {
|
|
case rule
|
|
case global
|
|
case direct
|
|
|
|
private enum CodingKeys: String, CodingKey {
|
|
case kind
|
|
}
|
|
|
|
private enum Kind: String, Codable {
|
|
case rule
|
|
case global
|
|
case direct
|
|
}
|
|
|
|
init(from decoder: Decoder) throws {
|
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
switch try container.decode(Kind.self, forKey: .kind) {
|
|
case .rule:
|
|
self = .rule
|
|
case .global:
|
|
self = .global
|
|
case .direct:
|
|
self = .direct
|
|
}
|
|
}
|
|
|
|
func encode(to encoder: Encoder) throws {
|
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
switch self {
|
|
case .rule:
|
|
try container.encode(Kind.rule, forKey: .kind)
|
|
case .global:
|
|
try container.encode(Kind.global, forKey: .kind)
|
|
case .direct:
|
|
try container.encode(Kind.direct, forKey: .kind)
|
|
}
|
|
}
|
|
|
|
var label: String {
|
|
switch self {
|
|
case .rule:
|
|
String(localized: "规则")
|
|
case .global:
|
|
String(localized: "全局")
|
|
case .direct:
|
|
String(localized: "直连")
|
|
}
|
|
}
|
|
|
|
var kind: ProxyModeKind {
|
|
switch self {
|
|
case .rule: .rule
|
|
case .global: .global
|
|
case .direct: .direct
|
|
}
|
|
}
|
|
|
|
/// Returns every mode supported by the product in stable selector order.
|
|
static var availableModes: [ProxyMode] { [.rule, .global, .direct] }
|
|
|
|
/// Derives the only system-proxy state that this mode is allowed to own.
|
|
/// All three modes are projected as the local SOCKS and HTTP inbounds
|
|
/// SOCKS 之外,系统 HTTP/HTTPS 代理指向恒开启的 HTTP 入站。
|
|
/// 投影即 closed typed 配置:HTTPS 显式赋值、PAC/自动发现显式
|
|
/// 关闭、简单主机名排除显式开启、例外列表全量给出。
|
|
/// 端口合法性由 settings store 与运行时文档派生保证,投影对任意
|
|
/// 文档都是全函数,保证期望系统代理配置不被静默跳过(ADR-0022)。
|
|
func systemProxyConfiguration(
|
|
for document: SslocalRuntimeDocument,
|
|
exceptions: [String] = []
|
|
) -> SystemProxyConfiguration {
|
|
systemProxyConfiguration(for: RuntimeListenFacts(document: document), exceptions: exceptions)
|
|
}
|
|
|
|
func systemProxyConfiguration(
|
|
for listen: RuntimeListenFacts, exceptions: [String] = []
|
|
) -> SystemProxyConfiguration {
|
|
let loopback = "127.0.0.1"
|
|
return SystemProxyConfiguration(
|
|
socks: .init(host: loopback, port: listen.socksPort),
|
|
http: .init(host: loopback, port: listen.httpPort),
|
|
https: .init(host: loopback, port: listen.httpPort),
|
|
excludeSimpleHostnames: true,
|
|
exceptions: FixedLocalProxyRanges.systemProxyExceptions(including: exceptions))
|
|
}
|
|
}
|