feat(rules): reorder presets and default to GFWList

This commit is contained in:
Qiu Yuzhou
2026-10-25 14:32:12 +08:00
committed by Qiu Yuzhou
parent 813ae99090
commit 168ff2e93e
9 changed files with 12 additions and 12 deletions
@@ -74,7 +74,7 @@ struct ProxyControlSnapshot: Equatable, Sendable {
/// 当前已应用的代理模式(持久化成功的模式)。
let proxyMode: ProxyMode
/// 规则模式子选项:未匹配默认动作;仅规则模式呈现。
var rulePreset: RulePreset = .chinaDirect
var rulePreset: RulePreset = .gfwlist
var ruleDefaultAction: RuleDefaultAction { rulePreset.defaultAction }
/// 可用模式由 Domain 单点策略投影;UI 不自行判断可用性。
let availableModes: [ProxyMode]
@@ -23,7 +23,7 @@ final class RulesWorkflow: ObservableObject {
private let analysisDelay: @Sendable () async throws -> Void
init(
preset: RulePreset = .chinaDirect,
preset: RulePreset = .gfwlist,
loadCustom: (@Sendable () throws -> [CustomRule])? = nil,
loadDocument: (@MainActor () throws -> CustomRuleDocument)? = nil,
commitDocument: (@MainActor (CustomRuleDocument) async -> RuleDocumentCommit)? = nil,
@@ -4,7 +4,7 @@ import Foundation
/// Each preset owns an unchanged workflow, including its in-flight operations.
@MainActor
final class RulesWorkspaces: ObservableObject {
@Published var selectedPreset: RulePreset = .chinaDirect
@Published var selectedPreset: RulePreset = .gfwlist
@Published private(set) var reportSource: RulesSourceSnapshot?
private let workflows: [RulePreset: RulesWorkflow]
private var reports: Set<AnyCancellable> = []
@@ -117,8 +117,8 @@ actor BuiltinRuleSnapshots {
/// The same policy supplies runtime candidates and the management collection.
enum RulePreset: String, Codable, CaseIterable, Hashable, Sendable {
case chinaDirect = "china-direct"
case gfwlist = "gfwlist"
case chinaDirect = "china-direct"
case chinaProxy = "china-proxy"
init(legacy action: RuleDefaultAction) {
@@ -23,7 +23,7 @@ struct ProxyControlPreferences {
}
let legacy =
defaults.string(forKey: "proxyControl.ruleDefaultAction")
.flatMap(RuleDefaultAction.init(rawValue:)) ?? .proxyWhenUnmatched
.flatMap(RuleDefaultAction.init(rawValue:)) ?? .directWhenUnmatched
return RulePreset(legacy: legacy)
}
nonmutating set { defaults.set(newValue.rawValue, forKey: "proxyControl.rulePreset") }
@@ -11,7 +11,7 @@ struct ProxyRuntimeSettings: Equatable, Sendable {
/// The persisted current mode: the mode selector's choice survives GUI
/// restarts. First run defaults to rule mode.
var preferredMode: ProxyModeKind
/// 规则模式预设,出厂为中国大陆目标直连。
/// 规则模式预设,首次启动默认为仅 GFW 列表内目标代理。
var rulePreset: RulePreset
var ruleDefaultAction: RuleDefaultAction {
get { rulePreset.defaultAction }
@@ -27,7 +27,7 @@ struct ProxyRuntimeSettings: Equatable, Sendable {
listen: ProxyListeningConfiguration = ProxyListeningConfiguration(),
proxyExceptions: String = ProxyRuntimeSettings.defaultProxyExceptions,
preferredMode: ProxyModeKind = .rule,
ruleDefaultAction: RuleDefaultAction = .proxyWhenUnmatched,
ruleDefaultAction: RuleDefaultAction = .directWhenUnmatched,
rulePreset: RulePreset? = nil,
agentEnabled: Bool = false,
systemProxyEnabled: Bool = false
@@ -93,7 +93,7 @@ extension RulePresetWorkflowTests {
let defaults = try #require(UserDefaults(suiteName: suite))
defer { defaults.removePersistentDomain(forName: suite) }
let preferences = ProxyControlPreferences(defaults: defaults)
#expect(preferences.rulePreset == .chinaDirect)
#expect(preferences.rulePreset == .gfwlist)
defaults.set("direct-when-unmatched", forKey: "proxyControl.ruleDefaultAction")
#expect(preferences.rulePreset == .gfwlist)
preferences.rulePreset = .chinaProxy
@@ -16,7 +16,7 @@ struct ProxyControlPreferencesTests {
preferences: ProxyControlPreferences(defaults: defaults))
#expect(settings.preferredMode == .rule)
#expect(settings.ruleDefaultAction == .proxyWhenUnmatched)
#expect(settings.ruleDefaultAction == .directWhenUnmatched)
#expect(!settings.agentEnabled)
#expect(!settings.systemProxyEnabled)
#expect(settings.proxyExceptions.isEmpty)
@@ -1,10 +1,10 @@
# 将隐式路由策略显式建模为规则预设
**状态**:已接受,已实现(2026-10-24)。
**状态**:已接受,已实现(2026-10-24;默认项与展示顺序于 2026-10-25 调整)。
## 决定
规则、全局、直连仍是代理模式。规则模式内使用三种规则预设:“中国大陆目标直连”“仅GFW列表内目标代理”“中国大陆目标代理”。预设一起确定内置来源、命中行动和默认动作,替代原来的默认动作选择入口,不另设独立默认动作开关。新预设复用中国域名、`.cn` 和中国 IPv4 数据,将其用于代理,其余目标默认直连;固定本地目标仍直连,不维护视频专用集合,也不承诺平台内容可播放。
规则、全局、直连仍是代理模式。规则模式内使用三种规则预设,展示顺序为“仅GFW列表内目标代理”“中国大陆目标直连”“中国大陆目标代理”。预设一起确定内置来源、命中行动和默认动作,替代原来的默认动作选择入口,不另设独立默认动作开关。新预设复用中国域名、`.cn` 和中国 IPv4 数据,将其用于代理,其余目标默认直连;固定本地目标仍直连,不维护视频专用集合,也不承诺平台内容可播放。
每项预设独立拥有自定义规则集合和规则停用选择。自定义规则保留自身行动,沿用现有冲突机制,用于补充规则而不保证覆盖内置规则。预设内继续使用“匹配条件+行动”的规则身份及跨来源停用语义,修改不影响其他预设。不增加共享自定义层或同一条目的多预设归属。
@@ -16,7 +16,7 @@
地址测试依据所选预设的完整规则和默认动作解释代理或直连结论,区分规则命中与未匹配时采用默认动作,并展示决定行动的规则。结果不受搜索、过滤、实际代理模式或运行状态影响,不要求该预设正在使用。测试输入和结果按预设独立保留;测试不解析 DNS、不测试连通性,域名测试明确说明未检查 DNS 解析后的 IP 规则。
保留原出厂默认及已有的路由选择映射。旧自定义规则和规则启用/禁用用户配置均不迁移,不按行动拆分,也不复制到新预设。新预设工作区不继承旧自定义条目或旧停用选择,按默认启用状态初始化;发版时明确说明这两项不兼容变化。
没有显式保存的预设或旧版默认动作偏好时,默认选第一项“仅GFW列表内目标代理”;显式保存的预设继续生效,旧版默认动作继续映射到等价预设。旧自定义规则和规则启用/禁用用户配置均不迁移,不按行动拆分,也不复制到新预设。新预设工作区不继承旧自定义条目或旧停用选择,按默认启用状态初始化;发版时明确说明这两项不兼容变化。
## 取舍与替代