mirror of
https://github.com/shadowsocks/ShadowsocksX-NG.git
synced 2026-11-04 02:13:45 +00:00
refactor(app): address code review for #72
- 回环候选清单上收到 ListenerMode.compatibleLoopbackAddresses(Domain 单点),proxyLoopbackAddress 派生为首项;策略不再复刻 mode→回环映射 - refreshCommandAddresses 更名 refreshTerminalCommands(返回命令的语义) - 监视创建失败注明为尽力而为增强(进入首页/复制前刷新兜底) - HTTPExportCapability 注释与首页完整命令的地址选择划清边界
This commit is contained in:
@@ -217,7 +217,7 @@ struct TerminalProxyEnvironmentCard: View {
|
||||
}
|
||||
)
|
||||
.onAppear {
|
||||
control.refreshCommandAddresses()
|
||||
control.refreshTerminalCommands()
|
||||
}
|
||||
.onDisappear {
|
||||
feedbackTask?.cancel()
|
||||
@@ -261,7 +261,7 @@ struct TerminalProxyEnvironmentCard: View {
|
||||
private func copy(_ shell: TerminalCommandShell) {
|
||||
// 复制前刷新(issue #72):失效选择回退后的命令即剪贴板内容,与按钮
|
||||
// 提示保持同一选择。
|
||||
let commands = control.refreshCommandAddresses()
|
||||
let commands = control.refreshTerminalCommands()
|
||||
do {
|
||||
try clipboard.write(shell.command(from: commands))
|
||||
feedbackTask?.cancel()
|
||||
|
||||
@@ -81,8 +81,8 @@ final class ControllerProxyRuntimeAdapter: ProxyRuntimeAdapting {
|
||||
}
|
||||
}
|
||||
|
||||
/// HTTP 导出能力的唯一派生点:监听设置 → 本机终端使用的可复制导出行。
|
||||
/// 环境变量始终指向回环地址,避免将命令误用于其他设备。
|
||||
/// HTTP 导出能力的唯一派生点:监听设置 → 可复制的 http/https 双导出行。
|
||||
/// 此导出行始终指向回环地址(与首页完整命令的命令地址选择无关,issue #72)。
|
||||
extension HTTPExportCapability {
|
||||
init(listen: SslocalListenSettings) {
|
||||
let urlHost = listen.proxyLoopbackURLHost
|
||||
|
||||
@@ -226,7 +226,7 @@ final class ProxyControlWorkflow: ObservableObject {
|
||||
/// 事实变化通知自动刷新)。返回刷新后的两种 shell 命令供剪贴板副作用
|
||||
/// 使用——失效选择已在本次观察中回退,提示投影与返回值一致。
|
||||
@discardableResult
|
||||
func refreshCommandAddresses() -> TerminalProxyEnvironmentCommands {
|
||||
func refreshTerminalCommands() -> TerminalProxyEnvironmentCommands {
|
||||
republish().terminalProxyEnvironmentCommands
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@ final class SystemInterfaceFactsProvider: LocalInterfaceFactsReading {
|
||||
}
|
||||
|
||||
private func startObserving() {
|
||||
// 变化通知是尽力而为的增强:监视创建失败(罕见)只失去推送刷新,
|
||||
// 进入首页与复制前刷新仍保证候选新鲜。
|
||||
var context = SCDynamicStoreContext(
|
||||
version: 0,
|
||||
info: Unmanaged.passUnretained(observation).toOpaque(),
|
||||
|
||||
@@ -85,24 +85,19 @@ enum TerminalCommandAddressPolicy {
|
||||
return loopbacks + interfaceCandidates(mode: mode, interfaces: interfaces)
|
||||
}
|
||||
|
||||
/// 当前监听方式的默认回环地址(与 ListenerMode.proxyLoopbackAddress 一致)。
|
||||
/// 当前监听方式的默认回环地址(Domain 回环清单首项)。
|
||||
static func defaultLoopback(for mode: ListenerMode) -> TerminalCommandAddress {
|
||||
TerminalCommandAddress(bsdName: "lo0", address: mode.proxyLoopbackAddress, displayName: "lo0")
|
||||
TerminalCommandAddress(
|
||||
bsdName: "lo0", address: mode.proxyLoopbackAddress, displayName: "lo0")
|
||||
}
|
||||
|
||||
// MARK: - 派生细节
|
||||
|
||||
/// 回环候选(置顶)直接来自 Domain 的监听方式回环清单,展示名固定 lo0。
|
||||
private static func loopbackCandidates(for mode: ListenerMode) -> [TerminalCommandAddress] {
|
||||
let addresses: [String]
|
||||
switch mode {
|
||||
case .localhost, .allIPv4Interfaces:
|
||||
addresses = ["127.0.0.1"]
|
||||
case .allIPv4AndIPv6Interfaces:
|
||||
addresses = ["127.0.0.1", "::1"]
|
||||
case .allIPv6Interfaces:
|
||||
addresses = ["::1"]
|
||||
mode.compatibleLoopbackAddresses.map {
|
||||
TerminalCommandAddress(bsdName: "lo0", address: $0, displayName: "lo0")
|
||||
}
|
||||
return addresses.map { TerminalCommandAddress(bsdName: "lo0", address: $0, displayName: "lo0") }
|
||||
}
|
||||
|
||||
/// 待排序的接口分组:显示名 + BSD 名 + 该接口的地址候选。
|
||||
|
||||
@@ -25,8 +25,19 @@ enum ListenerMode: String, Codable, CaseIterable, Equatable, Sendable {
|
||||
}
|
||||
}
|
||||
|
||||
/// 此监听方式可接受的回环地址(默认地址在前):IPv4/仅本机只接受
|
||||
/// 127.0.0.1,双栈通配绑定同时接受两个回环族,仅 IPv6 只接受 ::1。
|
||||
var compatibleLoopbackAddresses: [String] {
|
||||
switch self {
|
||||
case .localhost, .allIPv4Interfaces: ["127.0.0.1"]
|
||||
case .allIPv4AndIPv6Interfaces: ["127.0.0.1", "::1"]
|
||||
case .allIPv6Interfaces: ["::1"]
|
||||
}
|
||||
}
|
||||
|
||||
/// 健康探测、系统代理与 HTTP 导出行使用的默认兼容回环地址。
|
||||
var proxyLoopbackAddress: String {
|
||||
self == .allIPv6Interfaces ? "::1" : "127.0.0.1"
|
||||
compatibleLoopbackAddresses[0]
|
||||
}
|
||||
|
||||
var bindingHint: String {
|
||||
|
||||
@@ -233,7 +233,7 @@ final class ProxyCommandAddressLifecycleTests: XCTestCase {
|
||||
let wifi = workflow.snapshot.commandAddressPicker.candidates[1]
|
||||
_ = workflow.selectCommandAddress(wifi)
|
||||
|
||||
_ = workflow.refreshCommandAddresses() // 离开再进入首页
|
||||
_ = workflow.refreshTerminalCommands() // 离开再进入首页
|
||||
|
||||
XCTAssertEqual(
|
||||
workflow.snapshot.commandAddressPicker.selected.identity, wifi.identity,
|
||||
@@ -330,7 +330,7 @@ final class ProxyCommandAddressLifecycleTests: XCTestCase {
|
||||
|
||||
// 复制前地址消失且变化通知丢失:复制前刷新发现失效。
|
||||
interfaceFacts.interfaces = []
|
||||
let prepared = workflow.refreshCommandAddresses()
|
||||
let prepared = workflow.refreshTerminalCommands()
|
||||
|
||||
XCTAssertFalse(
|
||||
prepared.zshBash.contains("192.168.1.10"), "复制内容不包含已消失的地址")
|
||||
@@ -348,7 +348,7 @@ final class ProxyCommandAddressLifecycleTests: XCTestCase {
|
||||
runtime.runtimeFacts = ProxyRuntimeFacts(status: .off, isOn: false)
|
||||
runtime.emitChange()
|
||||
|
||||
let prepared = workflow.refreshCommandAddresses()
|
||||
let prepared = workflow.refreshTerminalCommands()
|
||||
|
||||
XCTAssertTrue(prepared.zshBash.contains("127.0.0.1"), "代理未运行时命令仍可准备")
|
||||
XCTAssertEqual(runtime.resyncCount, 0, "刷新不触碰运行时生命周期")
|
||||
|
||||
Reference in New Issue
Block a user