mirror of
https://github.com/shadowsocks/ShadowsocksX-NG.git
synced 2026-11-08 18:24:51 +00:00
* feat: add GUI-scoped subscription automatic updates * fix: drain newly due subscription updates during a batch * style: use segmented subscription update pickers
80 lines
2.8 KiB
Swift
80 lines
2.8 KiB
Swift
import Foundation
|
|
|
|
/// 订阅源记录:持久不透明的订阅 UUID + 固定分组
|
|
/// 身份 + 订阅 URL + 最近刷新状态。URL 随服务器库整体加密;
|
|
/// 编辑 URL 保留订阅与固定分组身份。
|
|
struct SubscriptionRecord: Codable, Equatable, Sendable, Identifiable {
|
|
/// 订阅源身份;删除后新建即新身份(GLOSSARY.md「Subscription」)。
|
|
let id: NodeID
|
|
/// 固定订阅分组的稳定身份(客户端所有,跨刷新与 URL 编辑不变)。
|
|
let groupID: NodeID
|
|
var url: String
|
|
var status: SubscriptionRefreshStatus
|
|
/// 最近成功提交的白名单资料;成功响应省略时清除,失败或取消保留。
|
|
var information: SubscriptionInformation?
|
|
/// 独立于最近尝试状态,旧文件缺失时不猜测。
|
|
var lastSucceededAt: Date?
|
|
/// Optional envelope keeps existing encrypted documents compatible and disabled.
|
|
var autoUpdateState: SubscriptionAutoUpdate?
|
|
|
|
var autoUpdate: SubscriptionAutoUpdate {
|
|
get { autoUpdateState ?? SubscriptionAutoUpdate() }
|
|
set { autoUpdateState = newValue }
|
|
}
|
|
}
|
|
|
|
/// 最近一次刷新结果。失败只保存白名单事实,不保存订阅 URL、秘密、凭据引用
|
|
/// 或任意错误 description(均需脱敏)。
|
|
enum SubscriptionRefreshStatus: Codable, Equatable, Sendable {
|
|
case never
|
|
// swiftlint:disable:next identifier_name
|
|
case succeeded(at: Date)
|
|
// swiftlint:disable:next identifier_name
|
|
case failed(at: Date, failure: SubscriptionRefreshFailure)
|
|
|
|
}
|
|
|
|
/// 配置目录持久化文档:结构树、订阅源记录与有序收藏一次原子落盘,
|
|
/// 保证「订阅记录 ↔ 固定分组子树」跨文档一致。
|
|
struct CatalogDocument: Equatable, Sendable {
|
|
var catalog: ConfigurationCatalog
|
|
var subscriptions: [SubscriptionRecord]
|
|
var favoriteIDs: [NodeID]
|
|
|
|
init(
|
|
catalog: ConfigurationCatalog = ConfigurationCatalog(),
|
|
subscriptions: [SubscriptionRecord] = [],
|
|
favoriteIDs: [NodeID] = []
|
|
) {
|
|
self.catalog = catalog
|
|
self.subscriptions = subscriptions
|
|
self.favoriteIDs = favoriteIDs
|
|
}
|
|
}
|
|
|
|
/// 已解析为目录形态的订阅快照:身份已按订阅作用域限定,记录携带凭据值。
|
|
/// `root` 是固定分组的内容来源;固定分组自身身份由应用入口的 `groupID`
|
|
/// 决定(客户端所有),`root.id` 不参与挂载。
|
|
struct CatalogSubscriptionSnapshot: Equatable, Sendable {
|
|
struct ServerLeaf: Equatable, Sendable {
|
|
let id: NodeID
|
|
var fields: ServerFields
|
|
}
|
|
|
|
/// 有序子引用:顺序即快照(远端权威)的用户可见顺序。
|
|
enum Child: Equatable, Sendable {
|
|
case group(Group)
|
|
case server(ServerLeaf)
|
|
}
|
|
|
|
struct Group: Equatable, Sendable {
|
|
let id: NodeID
|
|
let name: String
|
|
var children: [Child]
|
|
}
|
|
|
|
/// 固定分组显示名:远端根分组名,扩展缺失时为 URL host。
|
|
let name: String
|
|
let root: Group
|
|
}
|