mirror of
https://github.com/shadowsocks/ShadowsocksX-NG.git
synced 2026-11-08 12:44:51 +00:00
72 lines
2.2 KiB
Swift
72 lines
2.2 KiB
Swift
import Foundation
|
|
|
|
// MARK: - 自定义规则
|
|
|
|
/// 自定义条目的持久身份与规范化规则值;编辑身份独立于跨来源规则身份。
|
|
struct CustomRule: Equatable, Hashable, Sendable, Identifiable {
|
|
let id: UUID
|
|
let rule: ProxyRule
|
|
|
|
init(id: UUID = UUID(), action: RuleAction, match: RuleMatch) {
|
|
self.id = id
|
|
rule = ProxyRule(action: action, match: match)
|
|
}
|
|
|
|
var action: RuleAction { rule.action }
|
|
var match: RuleMatch { rule.match }
|
|
var proxyRule: ProxyRule { rule }
|
|
var identity: ProxyRule { rule }
|
|
|
|
/// 稳定的内容身份(不含 UUID),用于去重与诊断摘要。
|
|
var contentToken: String {
|
|
identity.contentToken
|
|
}
|
|
}
|
|
|
|
// MARK: - 持久化集合
|
|
|
|
/// 已保存的自定义条目与跨全部来源的规则停用意图。
|
|
struct CustomRuleDocument: Equatable, Sendable {
|
|
let rules: [CustomRule]
|
|
let disabledIdentities: Set<ProxyRule>
|
|
|
|
init(rules: [CustomRule], disabledIdentities: Set<ProxyRule> = []) {
|
|
self.rules = rules
|
|
self.disabledIdentities = disabledIdentities
|
|
}
|
|
}
|
|
|
|
// MARK: - 诊断摘要
|
|
|
|
/// 自定义规则的安全诊断摘要:只含数量与内容版本,
|
|
/// 不导出原始自定义域名或来源内容。
|
|
struct CustomRuleSummary: Equatable, Sendable {
|
|
/// 规则条数。
|
|
let count: Int
|
|
/// 内容版本:规则内容(动作+匹配)的稳定短摘要。
|
|
let contentVersion: String
|
|
|
|
static func summarizing(_ document: CustomRuleDocument) -> CustomRuleSummary {
|
|
let tokens =
|
|
document.rules.map(\.contentToken).sorted()
|
|
+ document.disabledIdentities.map { "disabled:" + $0.contentToken }.sorted()
|
|
return CustomRuleSummary(
|
|
count: document.rules.count,
|
|
contentVersion: String(ProxyACLDocument.digest(tokens.joined(separator: "\n")).prefix(12)))
|
|
}
|
|
|
|
static func summarizing(_ rules: [CustomRule]) -> CustomRuleSummary {
|
|
CustomRuleSummary(count: rules.count, contentVersion: contentVersion(of: rules))
|
|
}
|
|
|
|
/// 内容版本按 (action, match) 排序后摘要;不含 UUID,重排不改版本。
|
|
static func contentVersion(of rules: [CustomRule]) -> String {
|
|
let payload =
|
|
rules
|
|
.map(\.contentToken)
|
|
.sorted()
|
|
.joined(separator: "\n")
|
|
return String(ProxyACLDocument.digest(payload).prefix(12))
|
|
}
|
|
}
|