fix(proxy): tolerate legacy PAC preferredMode when decoding settings

An old settings.json with preferredMode "pac" made decodeIfPresent throw
on ProxyModeKind, which marked the whole snapshot unreadable and refused
to deploy. Decode the raw string and fall back to rule mode for unknown
values so retained fields (ports, timeout, exceptions) survive.

Closes the startup failure reported after #67.
This commit is contained in:
Qiu Yuzhou
2026-09-26 22:44:24 +08:00
parent a8cd6262c2
commit 973e8dd3b0
2 changed files with 23 additions and 2 deletions
@@ -224,8 +224,15 @@ private struct ProxySettingsRecord: Codable, Equatable, Sendable {
proxyExceptions =
try container.decodeIfPresent(String.self, forKey: .proxyExceptions)
?? ProxySettings.defaultProxyExceptions
preferredMode =
try container.decodeIfPresent(ProxyModeKind.self, forKey: .preferredMode) ?? .rule
// 旧 NG2 偏好里的 "pac" 等已删除值容错回落到规则模式(issue #67:
// 未发布的 PAC 偏好不做迁移,但解码失败会把全部保留字段连坐丢掉)。
if let rawMode = try container.decodeIfPresent(String.self, forKey: .preferredMode),
let mode = ProxyModeKind(rawValue: rawMode)
{
preferredMode = mode
} else {
preferredMode = .rule
}
// 规则模式子选项(issue #63):出厂「未匹配时代理」。
ruleDefaultAction =
try container.decodeIfPresent(RuleDefaultAction.self, forKey: .ruleDefaultAction)
@@ -82,6 +82,20 @@ final class ProxySettingsFileStoreTests: XCTestCase {
XCTAssertFalse(raw.contains("enabledModes"))
}
func testLegacyPACPreferredModeFallsBackToRuleWithoutLosingOtherFields() throws {
try writeRaw(
"""
{"preferredMode":"pac","socksPort":2086,"httpPort":2087,"timeoutSeconds":120,
"pacUserRules":"@@example.com","gfwListURLConfigured":true,"pacPort":2089}
""")
let loaded = try store.load()
XCTAssertEqual(loaded.preferredMode, .rule)
XCTAssertEqual(loaded.listen.socksPort, 2086)
XCTAssertEqual(loaded.listen.httpPort, 2087)
XCTAssertEqual(loaded.timeoutSeconds, 120)
}
func testInvalidSaveDoesNotTouchExistingSettings() throws {
try store.save(ProxySettings())
var invalid = ProxySettings()