punchnet-macos/Tun/Punchnet/Actors/SDLPuncherActor.swift
2026-02-25 00:25:58 +08:00

94 lines
2.8 KiB
Swift

//
// SDLPuncherActor.swift
// Tun
//
// Created by on 2026/1/7.
//
import Foundation
import NIOCore
actor SDLPuncherActor {
nonisolated private let cooldown: Duration = .seconds(5)
// dstMac
private var coolingDown: Set<Data> = []
private var pktId: UInt32 = 1
//
private var pendingRequests: [UInt32: RegisterRequest] = [:]
// holer
nonisolated private let querySocketAddress: SocketAddress
struct RegisterRequest {
let srcMac: Data
let dstMac: Data
let networkId: UInt32
}
init(querySocketAddress: SocketAddress) {
self.querySocketAddress = querySocketAddress
}
func submitRegisterRequest(quicClient: SDLQUICClient?, request: RegisterRequest) {
let dstMac = request.dstMac
guard let quicClient, !coolingDown.contains(dstMac) else {
return
}
//
coolingDown.insert(dstMac)
let pktId = self.pktId
self.pktId &+= 1
if self.pktId == 0 {
self.pktId = 1
}
self.tryHole(using: quicClient, pktId: pktId, request: request)
Task {
//
try? await Task.sleep(for: .seconds(5))
self.endCooldown(for: dstMac)
self.removePendingRequest(for: pktId)
}
}
func handlePeerInfo(using udpHole: SDLUDPHole, peerInfo: SDLPeerInfo) async {
guard let request = pendingRequests.removeValue(forKey: peerInfo.pktID),
let remoteAddress = try? await peerInfo.v4Info.socketAddress() else {
return
}
SDLLogger.shared.log("[SDLContext] hole sock address: \(remoteAddress)", level: .debug)
// register
var register = SDLRegister()
register.networkID = request.networkId
register.srcMac = request.srcMac
register.dstMac = request.dstMac
if let registerData = try? register.serializedData() {
udpHole.send(type: .register, data: registerData, remoteAddress: remoteAddress)
}
}
private func endCooldown(for key: Data) {
self.coolingDown.remove(key)
}
private func removePendingRequest(for pktId: UInt32) {
self.pendingRequests.removeValue(forKey: pktId)
}
private func tryHole(using quicClient: SDLQUICClient, pktId: UInt32, request: RegisterRequest) {
var queryInfo = SDLQueryInfo()
queryInfo.pktID = pktId
queryInfo.dstMac = request.dstMac
self.pendingRequests[pktId] = request
if let queryData = try? queryInfo.serializedData() {
quicClient.send(type: .queryInfo, data: queryData)
}
}
}