punchnet-macos/Tun/Punchnet/Policy/IdentityStore.swift
2026-02-05 23:13:37 +08:00

111 lines
3.4 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// IdentityStore.swift
// punchnet
//
// Created by on 2026/2/5.
//
import Foundation
import NIO
final class IdentitySession {
var version: UInt32
var totalNum: UInt32
private var parts: [UInt32: SDLPolicyResponse] = [:]
init(part: SDLPolicyResponse) {
self.version = part.version
self.totalNum = part.totalNum
self.parts[part.index] = part
}
func merge(part: SDLPolicyResponse) {
if part.version < version {
//
} else if part.version == version {
self.parts[part.index] = part
} else {
self.parts.removeAll()
self.parts[part.index] = part
}
}
func process() -> Data? {
// parts0total_num
let indexs = parts.keys.sorted().map { UInt32($0) }
guard indexs.count == self.totalNum && isContinuousFromZero(indexs: indexs) else {
return nil
}
var rulesData: Data = Data()
for i in 0..<totalNum {
if let part = self.parts[i] {
rulesData.append(part.rules)
}
}
SDLLogger.shared.log("[IdentitySession] get a completed rules: \(rulesData.count)")
return rulesData
}
private func isContinuousFromZero(indexs: [UInt32]) -> Bool {
guard !indexs.isEmpty else {
return false
}
return indexs.enumerated().allSatisfy { idx, value in
idx == value
}
}
}
actor IdentityStore {
typealias IdentityID = UInt32
nonisolated private let alloctor = ByteBufferAllocator()
private let publisher: SnapshotPublisher<IdentitySnapshot>
private var identityMap: [IdentityID: IdentityRuleMap] = [:]
private var sessions: [IdentityID: IdentitySession] = [:]
init(publisher: SnapshotPublisher<IdentitySnapshot>) {
self.publisher = publisher
}
func apply(policyResponse: SDLPolicyResponse) {
let id = policyResponse.srcIdentityID
let session = self.sessions[id, default: IdentitySession(part: policyResponse)]
session.merge(part: policyResponse)
//
if let rulesData = session.process() {
var buffer = alloctor.buffer(bytes: rulesData)
var ruleMap: [UInt8: [UInt16: Bool]] = [:]
while true {
guard let proto = buffer.readInteger(endianness: .big, as: UInt8.self),
let port = buffer.readInteger(endianness: .big, as: UInt16.self) else {
break
}
ruleMap[proto, default: [:]][port] = true
}
self.identityMap[id] = IdentityRuleMap(ruleMap: ruleMap)
// session
self.sessions.removeValue(forKey: id)
SDLLogger.shared.log("[IdentitySession] get compile Snapshot rules nums: \(self.identityMap[id]?.ruleMap.count), success: \(self.identityMap[id]?.isAllow(proto: 1, port: 80))")
//
let snapshot = compileSnapshot()
publisher.publish(snapshot)
} else {
self.sessions[id] = session
}
}
private func compileSnapshot() -> IdentitySnapshot {
return IdentitySnapshot(identityMap: identityMap)
}
}