// // UDPMessageCenterServer.swift // sdlan // // Created by 安礼成 on 2024/5/20. // import Foundation import NIOCore import NIOPosix import Combine final class UDPNoticeCenterServer: ChannelInboundHandler { public typealias InboundIn = AddressedEnvelope public typealias OutboundOut = AddressedEnvelope private var group: MultiThreadedEventLoopGroup? private var thread: Thread? var messageFlow = PassthroughSubject() static let shared = UDPNoticeCenterServer() private init() { } func start() { self.thread = Thread { self.group = MultiThreadedEventLoopGroup(numberOfThreads: 1) let bootstrap = DatagramBootstrap(group: self.group!) .channelOption(ChannelOptions.socketOption(.so_reuseaddr), value: 1) .channelInitializer { channel in channel.pipeline.addHandler(self) } let channel = try! bootstrap.bind(host: "127.0.0.1", port: 50195).wait() try! channel.closeFuture.wait() } self.thread?.start() } func stop() { self.thread?.cancel() try? self.group?.syncShutdownGracefully() } // --MARK: ChannelInboundHandler public func channelRead(context: ChannelHandlerContext, data: NIOAny) { let envelope = self.unwrapInboundIn(data) var buffer = envelope.data guard let type = buffer.readInteger(as: UInt8.self), let noticeType = NoticeMessage.NoticeType(rawValue: type), let bytes = buffer.readBytes(length: buffer.readableBytes) else { return } switch noticeType { case .upgrade: if let upgradeMessage = try? JSONDecoder().decode(NoticeMessage.UpgradeMessage.self, from: Data(bytes)) { DispatchQueue.main.async { self.messageFlow.send(.upgradeMessage(upgradeMessage)) } } case .alert: if let alertMessage = try? JSONDecoder().decode(NoticeMessage.AlertMessage.self, from: Data(bytes)) { DispatchQueue.main.async { self.messageFlow.send(.alertMessage(alertMessage)) } } } } public func channelReadComplete(context: ChannelHandlerContext) { // As we are not really interested getting notified on success or failure we just pass nil as promise to // reduce allocations. context.flush() } public func errorCaught(context: ChannelHandlerContext, error: Error) { // As we are not really interested getting notified on success or failure we just pass nil as promise to // reduce allocations. context.close(promise: nil) } }