punchnet-macos/Tun/Punchnet/SDLNoticeClient.swift
2025-08-25 15:43:17 +08:00

89 lines
2.8 KiB
Swift

//
// SDLNoticeClient.swift
// Tun
//
// Created by on 2024/5/20.
//
import Foundation
//
// SDLanServer.swift
// Tun
//
// Created by on 2024/1/31.
//
import Foundation
import NIOCore
import NIOPosix
// sn-server
actor SDLNoticeClient {
private let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
private let asyncChannel: NIOAsyncChannel<AddressedEnvelope<ByteBuffer>, AddressedEnvelope<ByteBuffer>>
private let remoteAddress: SocketAddress
private let (writeStream, writeContinuation) = AsyncStream.makeStream(of: Data.self, bufferingPolicy: .unbounded)
private let logger: SDLLogger
//
init(noticePort: Int, logger: SDLLogger) async throws {
self.logger = logger
self.remoteAddress = try! SocketAddress(ipAddress: "127.0.0.1", port: noticePort)
let bootstrap = DatagramBootstrap(group: self.group)
.channelOption(ChannelOptions.socketOption(.so_reuseaddr), value: 1)
self.asyncChannel = try await bootstrap.bind(host: "0.0.0.0", port: 0)
.flatMapThrowing {channel in
return try NIOAsyncChannel(wrappingChannelSynchronously: channel, configuration: .init(
inboundType: AddressedEnvelope<ByteBuffer>.self,
outboundType: AddressedEnvelope<ByteBuffer>.self
))
}
.get()
self.logger.log("[SDLNoticeClient] started and listening on: \(self.asyncChannel.channel.localAddress!)", level: .debug)
}
func start() async throws {
try await self.asyncChannel.executeThenClose { inbound, outbound in
try await withThrowingTaskGroup(of: Void.self) { group in
group.addTask {
try await self.asyncChannel.channel.closeFuture.get()
throw SDLError.socketClosed
}
group.addTask {
defer {
self.writeContinuation.finish()
}
for try await message in self.writeStream {
let buf = self.asyncChannel.channel.allocator.buffer(bytes: message)
let envelope = AddressedEnvelope<ByteBuffer>(remoteAddress: self.remoteAddress, data: buf)
try await outbound.write(envelope)
}
}
for try await _ in group {
}
}
}
}
//
func send(data: Data) {
self.writeContinuation.yield(data)
}
deinit {
try? self.group.syncShutdownGracefully()
self.writeContinuation.finish()
}
}