diff --git a/ShadowsocksX-NG2/Domain/ProxySettingsFileStore.swift b/ShadowsocksX-NG2/Domain/ProxySettingsFileStore.swift index f2c495a4..52697238 100644 --- a/ShadowsocksX-NG2/Domain/ProxySettingsFileStore.swift +++ b/ShadowsocksX-NG2/Domain/ProxySettingsFileStore.swift @@ -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) diff --git a/ShadowsocksX-NG2/Tests/ProxySettingsFileStoreTests.swift b/ShadowsocksX-NG2/Tests/ProxySettingsFileStoreTests.swift index 35855c85..59c83090 100644 --- a/ShadowsocksX-NG2/Tests/ProxySettingsFileStoreTests.swift +++ b/ShadowsocksX-NG2/Tests/ProxySettingsFileStoreTests.swift @@ -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()