116 lines
3.4 KiB
Swift
116 lines
3.4 KiB
Swift
//
|
|
// 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<SessionSnapshot>
|
|
|
|
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())
|
|
}
|
|
}
|