mirror of
https://github.com/shadowsocks/ShadowsocksX-NG.git
synced 2026-11-08 21:04:50 +00:00
App/ 根目录原有 73 个散落源文件,已无法从目录读出任何分组信息。 按「目录即分层」重组为 Composition / Application / Presentation / UI / PlatformEffects / Resources 六个目录,UI 层再按子视图分目录(Workspace、 Home、Servers(含 Plugin)、Subscriptions、Rules、Settings、Diagnostics、 StatusMenu)。纯移动:类型名、模块名与 import 均未改动,App/ 根层不再有 散落文件。 配套改动: - project.yml:Core 测试镜像的 excludes 由裸文件名改为 `**/` 递归形式。 XcodeGen 的 exclude 不跨 `/`,裸名只匹配 App 根层;MainApp.swift 下移后 旧写法会静默失效,把 @main 组合根编进测试镜像。info.path 与 entitlements.path 指向 App/Resources/;并排除 `**/*.md`——App/ 下任何 非源码文件都会被 XcodeGen 收进 Resources 阶段并封进签名后的 bundle。 - SkeletonTests 的架构守卫由「默认扫描全部 App/ + 7 个豁免文件 + 1 个豁免 前缀 + 4 个豁免目录」改为正面圈定 App/UI/,豁免登记全部删除;新增运行时 适配器放进 Application/ 即自动落在扫描范围外,无需再登记。 - README 工程结构说明同步;根 .gitignore 的生成物路径随 Resources/ 归位。 验证:clean build 0 error;task test 1022 用例全通过(含两个架构守卫); task format 无改动(证明纯移动);task lint 与移动前同为 21 条内容型 warning;packaging-gate.sh ALL CHECKS PASSED,确认 plist/entitlements 归位 后签名与 entitlements 语义不变。 注意:迁移时须先删旧的生成物再 xcodegen generate,否则遗留的 App/Info.plist 会被当作普通资源扫进 Resources 阶段。
66 lines
2.9 KiB
Swift
66 lines
2.9 KiB
Swift
import Combine
|
||
import Foundation
|
||
|
||
// MARK: - 原始接口事实(issue #72)
|
||
|
||
/// IPv6 地址的内核标志(经 `SIOCGIFAFLAG_IN6` 逐地址查询,netinet6/in6_var.h
|
||
/// 的 `IN6_IFF_*` 子集)。仅 IPv6 单播地址携带;IPv4 或查询失败为 nil。
|
||
struct LocalInterfaceV6Flags: OptionSet, Sendable {
|
||
let rawValue: Int32
|
||
/// `IN6_IFF_AUTOCONF`:SLAAC 自动配置地址。
|
||
static let autoconf = Self(rawValue: IN6_IFF_AUTOCONF)
|
||
/// `IN6_IFF_TEMPORARY`:RFC 4941 隐私临时地址(会轮换)。
|
||
static let temporary = Self(rawValue: IN6_IFF_TEMPORARY)
|
||
/// `IN6_IFF_SECURED`:稳定接口标识生成的地址。
|
||
static let secured = Self(rawValue: IN6_IFF_SECURED)
|
||
/// `IN6_IFF_DYNAMIC`:DHCPv6 分配的地址。
|
||
static let dynamic = Self(rawValue: IN6_IFF_DYNAMIC)
|
||
}
|
||
|
||
/// 单个本机接口单播地址的原始事实:族与 IPv6 标记已判明,过滤、排序与
|
||
/// 取舍全部由工作流层策略完成。
|
||
struct LocalInterfaceAddress: Equatable, Sendable {
|
||
enum Family: Equatable, Sendable {
|
||
case ipv4
|
||
case ipv6
|
||
}
|
||
|
||
/// 规范化 IP 文本(inet_ntop 呈现形,无作用域后缀)。
|
||
let address: String
|
||
let family: Family
|
||
/// IPv6 链路本地(fe80::/10);IPv4 链路本地不置位(属于允许接口的单播
|
||
/// 地址时可以列出)。
|
||
let isIPv6LinkLocal: Bool
|
||
/// IPv6 地址内核标志(含临时地址、DHCPv6 等类型事实);IPv4 或查询失败
|
||
/// 为 nil——nil 不触发过滤,也不注记。
|
||
let v6Flags: LocalInterfaceV6Flags?
|
||
}
|
||
|
||
/// 单个本机接口的原始事实(issue #72):系统适配器逐接口提供,类型白名单、
|
||
/// 地址族过滤、名称回退与排序均不在适配器内发生。
|
||
struct LocalInterfaceFacts: Equatable, Sendable {
|
||
/// BSD 接口名(lo0/en0/…):地址关联与地址身份的锚点。
|
||
let bsdName: String
|
||
/// IFF_LOOPBACK。
|
||
let isLoopback: Bool
|
||
/// SCNetworkInterfaceGetInterfaceType 原文;无 SystemConfiguration 映射
|
||
/// (如回环)为 nil。
|
||
let interfaceType: String?
|
||
/// SCNetworkInterfaceGetLocalizedDisplayName;缺失为 nil。
|
||
let localizedName: String?
|
||
/// 该接口的全部单播地址(未过滤)。
|
||
let addresses: [LocalInterfaceAddress]
|
||
}
|
||
|
||
/// 本机接口事实来源缝(issue #72):唯一的工作流层可注入事实来源,统一
|
||
/// 提供接口地址、类型、名称及变化通知;系统 API 查询细节封装于生产适配器,
|
||
/// 不为每个底层 API 另设 mock 协议。测试注入可编程替身。
|
||
@MainActor
|
||
protocol LocalInterfaceFactsReading: AnyObject {
|
||
/// 当前全部本机接口的原始事实(未过滤、未排序);枚举失败为 nil,
|
||
/// 调用方按「仅兼容回环候选」退化。
|
||
var interfaces: [LocalInterfaceFacts]? { get }
|
||
/// 接口事实变化通知(网络变化后发值);生产实现去抖,fake 同步手动。
|
||
var changes: AnyPublisher<Void, Never> { get }
|
||
}
|