punchnet-macos/punchnet/Core/UDPNoticeCenterServer.swift
2025-08-05 15:15:15 +08:00

82 lines
2.7 KiB
Swift

//
// 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<ByteBuffer>
public typealias OutboundOut = AddressedEnvelope<ByteBuffer>
private var group: MultiThreadedEventLoopGroup?
private var channel: Channel?
var messageFlow = PassthroughSubject<NoticeMessage.InboundMessage, Never>()
static let shared = UDPNoticeCenterServer()
private init() {
}
func start() {
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)
}
self.channel = try! bootstrap.bind(host: "127.0.0.1", port: 50195).wait()
}
func stop() {
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)
}
}