// // SessionTable.swift // Tun // // Created by Codex on 2026/5/21. // import Foundation actor SessionManager { private var sessions: [Data: [Session.AddressType: Session]] = [:] // session的有效时间 private let ttl: Int32 nonisolated private let snapshotPublisher: SnapshotPublisher init() { let ttl: Int32 = 10 self.ttl = ttl self.snapshotPublisher = SnapshotPublisher(initial: SessionSnapshot.empty()) } func getSession(toAddress: Data) -> Session? { let timestamp = Int32(Date().timeIntervalSince1970) guard var peerSessions = self.sessions[toAddress] else { return nil } peerSessions = peerSessions.filter { $0.value.lastTimestamp + ttl >= timestamp } guard !peerSessions.isEmpty else { self.sessions.removeValue(forKey: toAddress) self.publishSnapshot() return nil } guard var session = self.selectSession(in: peerSessions) else { self.sessions[toAddress] = peerSessions self.publishSnapshot() return nil } session.updateLastTimestamp(timestamp) peerSessions[session.addressType] = session self.sessions[toAddress] = peerSessions self.publishSnapshot() return session } func addSession(session: Session) { let timestamp = Int32(Date().timeIntervalSince1970) var sessions = self.sessions[session.dstMac, default: [:]] sessions = sessions.filter { $0.value.lastTimestamp + ttl >= timestamp && $0.key != session.addressType } sessions[session.addressType] = session self.sessions[session.dstMac] = sessions self.publishSnapshot() } func removeSession(dstMac: Data) { self.sessions.removeValue(forKey: dstMac) self.publishSnapshot() } @discardableResult func clear() -> Int { let oldCount = self.sessionCount() self.sessions.removeAll() self.publishSnapshot() return oldCount } @discardableResult func pruneExpiredSessions() -> Int { let oldCount = self.sessionCount() self.sessions = self.validSessions() let newCount = self.sessionCount() self.publishSnapshot() return oldCount - newCount } nonisolated func snapshot() -> SessionSnapshot { return self.snapshotPublisher.current() } private func selectSession(in sessions: [Session.AddressType: Session]) -> Session? { return sessions.values.max(by: { $0.lastTimestamp < $1.lastTimestamp }) } private func publishSnapshot() { self.snapshotPublisher.publish(self.compileSnapshot()) } private func validSessions() -> [Data: [Session.AddressType: Session]] { let timestamp = Int32(Date().timeIntervalSince1970) return self.sessions.compactMapValues { peerSessions in let validSessions = peerSessions.filter { $0.value.lastTimestamp + self.ttl >= timestamp } return validSessions.isEmpty ? nil : validSessions } } private func sessionCount() -> Int { return self.sessions.values.reduce(0) { count, peerSessions in count + peerSessions.count } } private func compileSnapshot() -> SessionSnapshot { return SessionSnapshot(sessions: self.validSessions()) } }