处理权限逻辑

This commit is contained in:
anlicheng 2026-05-21 17:41:56 +08:00
parent 3fa567762b
commit acab387898
2 changed files with 87 additions and 40 deletions

View File

@ -358,7 +358,7 @@ extension SDLContextActor {
let updatePolicyWorker = PeriodicWorker( let updatePolicyWorker = PeriodicWorker(
configuration: .init( configuration: .init(
interval: .seconds(120), interval: .seconds(10),
runImmediately: true, runImmediately: true,
mode: .fixedDelay, mode: .fixedDelay,
errorPolicy: .keepRunning(delay: .seconds(5)) errorPolicy: .keepRunning(delay: .seconds(5))

View File

@ -8,55 +8,56 @@ import Foundation
import NIO import NIO
actor PolicyRuleStore { actor PolicyRuleStore {
// private struct PolicyEntry {
nonisolated private let cooldown: Duration = .seconds(5) let ruleMap: PolicyRuleMap
// identityId let expiresAt: TimeInterval
private var coolingDown: Set<UInt32> = [] }
private struct PendingRequest {
let version: UInt32
let retryCount: Int
let nextRetryAt: TimeInterval
}
private let policyTTL: TimeInterval = 120
private let refreshLeadTime: TimeInterval = 15
private let baseRetryDelay: TimeInterval = 2
private let maxRetryDelay: TimeInterval = 60
// , map[identityId] = version // , map[identityId] = version
private var versions: [UInt32: UInt32] = [:] private var versions: [UInt32: UInt32] = [:]
private var pendingByIdentity: [UInt32: PendingRequest] = [:]
nonisolated private let alloctor = ByteBufferAllocator() nonisolated private let alloctor = ByteBufferAllocator()
private let publisher: SnapshotPublisher<PolicyRuleSnapshot> private let publisher: SnapshotPublisher<PolicyRuleSnapshot>
private var ruleMapByIdentity: [UInt32: PolicyRuleMap] = [:] private var policyByIdentity: [UInt32: PolicyEntry] = [:]
init(publisher: SnapshotPublisher<PolicyRuleSnapshot>) { init(publisher: SnapshotPublisher<PolicyRuleSnapshot>) {
self.publisher = publisher self.publisher = publisher
} }
func makeBatchPolicyRequests(dstIdentityID: UInt32) -> [Data] { func makeBatchPolicyRequests(dstIdentityID: UInt32) -> [Data] {
return self.ruleMapByIdentity.keys.compactMap { identityId in let now = Date().timeIntervalSince1970
var policyRequest = SDLPolicyRequest() let identities = Set(self.policyByIdentity.keys).union(self.pendingByIdentity.keys)
policyRequest.srcIdentityID = identityId
policyRequest.dstIdentityID = dstIdentityID return identities.compactMap { identityId in
policyRequest.version = self.nextVersion(identityId: identityId) self.makePolicyRequestIfDue(srcIdentityId: identityId, dstIdentityId: dstIdentityID, now: now, forceMissing: false)
return try? policyRequest.serializedData()
} }
} }
func makePolicyRequest(srcIdentityId: UInt32, dstIdentityId: UInt32) -> Data? { func makePolicyRequest(srcIdentityId: UInt32, dstIdentityId: UInt32) -> Data? {
guard self.ruleMapByIdentity[srcIdentityId] == nil else { guard self.policyByIdentity[srcIdentityId] == nil else {
return nil return nil
} }
guard !coolingDown.contains(srcIdentityId) else { return self.makePolicyRequestIfDue(
return nil srcIdentityId: srcIdentityId,
} dstIdentityId: dstIdentityId,
now: Date().timeIntervalSince1970,
var policyRequest = SDLPolicyRequest() forceMissing: true
policyRequest.srcIdentityID = srcIdentityId )
policyRequest.dstIdentityID = dstIdentityId
policyRequest.version = self.nextVersion(identityId: srcIdentityId)
coolingDown.insert(srcIdentityId)
Task { [weak self] in
try? await Task.sleep(for: .seconds(5))
await self?.endCooldown(for: srcIdentityId)
}
return try? policyRequest.serializedData()
} }
// //
@ -64,7 +65,11 @@ actor PolicyRuleStore {
let id = policyResponse.srcIdentityID let id = policyResponse.srcIdentityID
let version = policyResponse.version let version = policyResponse.version
guard self.ruleMapByIdentity[id] == nil || ((self.ruleMapByIdentity[id]?.version ?? 0) < version) else { if let pending = self.pendingByIdentity[id], pending.version <= version {
self.pendingByIdentity.removeValue(forKey: id)
}
guard self.policyByIdentity[id] == nil || ((self.policyByIdentity[id]?.ruleMap.version ?? 0) < version) else {
return return
} }
@ -78,7 +83,11 @@ actor PolicyRuleStore {
} }
ruleMap[proto, default: [:]][port] = true ruleMap[proto, default: [:]][port] = true
} }
self.ruleMapByIdentity[id] = PolicyRuleMap(version: version, ruleMap: ruleMap) let now = Date().timeIntervalSince1970
self.policyByIdentity[id] = PolicyEntry(
ruleMap: PolicyRuleMap(version: version, ruleMap: ruleMap),
expiresAt: now + self.policyTTL
)
SDLLogger.log("[PolicyRuleStore] apply policy response, srcIdentityID: \(id), version: \(version), rulesCount: \(ruleMap.reduce(0) { $0 + $1.value.count })", for: .debug) SDLLogger.log("[PolicyRuleStore] apply policy response, srcIdentityID: \(id), version: \(version), rulesCount: \(ruleMap.reduce(0) { $0 + $1.value.count })", for: .debug)
// //
@ -87,18 +96,14 @@ actor PolicyRuleStore {
} }
func clear() { func clear() {
self.coolingDown.removeAll()
self.versions.removeAll() self.versions.removeAll()
self.ruleMapByIdentity.removeAll() self.pendingByIdentity.removeAll()
self.policyByIdentity.removeAll()
self.publisher.publish(PolicyRuleSnapshot.empty()) self.publisher.publish(PolicyRuleSnapshot.empty())
} }
private func compileSnapshot() -> PolicyRuleSnapshot { private func compileSnapshot() -> PolicyRuleSnapshot {
return PolicyRuleSnapshot(ruleMapByIdentity: ruleMapByIdentity) return PolicyRuleSnapshot(ruleMapByIdentity: self.policyByIdentity.mapValues(\.ruleMap))
}
private func endCooldown(for key: UInt32) {
self.coolingDown.remove(key)
} }
private func nextVersion(identityId: UInt32) -> UInt32 { private func nextVersion(identityId: UInt32) -> UInt32 {
@ -108,4 +113,46 @@ actor PolicyRuleStore {
return version return version
} }
private func makePolicyRequestIfDue(srcIdentityId: UInt32, dstIdentityId: UInt32, now: TimeInterval, forceMissing: Bool) -> Data? {
if let pending = self.pendingByIdentity[srcIdentityId], pending.nextRetryAt > now {
return nil
}
if !forceMissing,
let entry = self.policyByIdentity[srcIdentityId],
entry.expiresAt - self.refreshLeadTime > now {
return nil
}
let version = self.nextVersion(identityId: srcIdentityId)
guard let data = self.makePolicyRequestData(srcIdentityId: srcIdentityId, dstIdentityId: dstIdentityId, version: version) else {
return nil
}
let retryCount = self.pendingByIdentity[srcIdentityId].map { $0.retryCount + 1 } ?? 0
let retryDelay = self.retryDelay(for: retryCount, identityId: srcIdentityId)
self.pendingByIdentity[srcIdentityId] = PendingRequest(
version: version,
retryCount: retryCount,
nextRetryAt: now + retryDelay
)
return data
}
private func makePolicyRequestData(srcIdentityId: UInt32, dstIdentityId: UInt32, version: UInt32) -> Data? {
var policyRequest = SDLPolicyRequest()
policyRequest.srcIdentityID = srcIdentityId
policyRequest.dstIdentityID = dstIdentityId
policyRequest.version = version
return try? policyRequest.serializedData()
}
private func retryDelay(for retryCount: Int, identityId: UInt32) -> TimeInterval {
let cappedRetryCount = min(retryCount, 5)
let multiplier = Double(1 << cappedRetryCount)
let jitter = Double(identityId % 1_000) / 1_000
return min(self.baseRetryDelay * multiplier + jitter, self.maxRetryDelay)
}
} }