diff options
| author | Arturs Artamonovs <arturs.artamonovs@protonmail.com> | 2026-09-10 09:57:11 +0100 |
|---|---|---|
| committer | Arturs Artamonovs <arturs.artamonovs@protonmail.com> | 2026-09-10 09:57:11 +0100 |
| commit | ed53ed83b71f2f3005d8b52ad005aeff1f59e39c (patch) | |
| tree | 33244508eae2ed3651de5b5a840556438fd39495 /Net1090 | |
| parent | dd31184b900636214897a1a08026279390049b92 (diff) | |
| download | ADSBDecoder-ed53ed83b71f2f3005d8b52ad005aeff1f59e39c.tar.gz ADSBDecoder-ed53ed83b71f2f3005d8b52ad005aeff1f59e39c.zip | |
reconnect works better, after wifi is on/offfix/net-reconnect
Diffstat (limited to 'Net1090')
| -rw-r--r-- | Net1090/NetADSBDecoder.swift | 136 |
1 files changed, 121 insertions, 15 deletions
diff --git a/Net1090/NetADSBDecoder.swift b/Net1090/NetADSBDecoder.swift index 36277ee..c7e8afc 100644 --- a/Net1090/NetADSBDecoder.swift +++ b/Net1090/NetADSBDecoder.swift @@ -25,6 +25,11 @@ class NetADSBHandlder: ChannelInboundHandler { print("Channel is active") } + func channelInactive(context: ChannelHandlerContext) { + print("Channel inactive") + context.fireChannelInactive() + } + func channelRead(context: ChannelHandlerContext, data: NIOAny) { var buffer = unwrapInboundIn(data) let readableBytes = buffer.readableBytes @@ -88,6 +93,20 @@ final class ADSBQueue: ADSBQueueDelegate { } } +enum ChannelState: CustomStringConvertible { + case connected + case disconnected + case retry(seconds: Int) + + var description: String { + switch self { + case .connected: return "connected" + case .disconnected: return "disconnected" + case .retry(let seconds): return "connection last retrying in \(seconds) sec" + } + } +} + class NetADSBDecoder { let group = MultiThreadedEventLoopGroup(numberOfThreads: 1) var host: String @@ -97,6 +116,24 @@ class NetADSBDecoder { var handler = NetADSBHandlder() //var msg_array:Array<String> = [] + var onStateChange: ((ChannelState) -> Void)? + private let stateLock = NSLock() + private var stopped = false + private var retries = 0 + private var retrySemaphore = DispatchSemaphore(value: 0) + private static let retryDelay = 30 + + private let pathMonitor = NWPathMonitor() + private let pathLock = NSLock() + private var currentChannel:Channel? = nil + + private var isStopped: Bool { + stateLock.lock() + defer {stateLock.unlock()} + return stopped + } + + init(host: String, port: Int) { self.host = host self.port = port @@ -105,28 +142,97 @@ class NetADSBDecoder { } func start() throws { - do { - let channel = try ClientBootstrap(group: group) - .channelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1) - .channelInitializer{channel in - //channel.pipeline.add(handler: ADSBHandlder()) - channel.pipeline.addHandlers([self.handler]) - }.connect(host: self.host, port: self.port) - .wait() - try channel.closeFuture.wait() - } catch let error { - print(error) - throw error + startPathMonitor() + defer { pathMonitor.cancel() } + + while (!isStopped) { + setState(.disconnected) + do { + let channel = try ClientBootstrap(group: group) + .connectTimeout(.seconds(10)) + .channelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET),SO_REUSEADDR), value: 1) + .channelOption(ChannelOptions.socketOption(.so_keepalive), value: 1) + .channelOption(ChannelOptions.socket(SocketOptionLevel(IPPROTO_TCP),TCP_KEEPALIVE), value: 15) + .channelInitializer{ channel in + channel.pipeline.addHandlers([self.handler]) + } + .connect(host: self.host, port: self.port) + .wait() + setCurrentChannel(channel) + retries = 0 + setState(.connected) + try channel.closeFuture.wait() + clearCurrentChannel() + print("Connection lost") + } catch let error { + clearCurrentChannel() + print("Connection error \(error)") + } + if isStopped { + break + } + retries += 1 + let delay = min(Self.retryDelay, 1 << min(retries, 5)) + setState(.retry(seconds: delay)) + if retrySemaphore.wait(timeout: .now() + .seconds(delay)) == .success, isStopped { break } } + print("Exit connection loop") } - func stop() { + + + func stop() { + stateLock.lock() + stopped = true + stateLock.unlock() + _ = retrySemaphore.signal() do { try group.syncShutdownGracefully() - } catch let error { + } catch { print("Error shutting down \(error.localizedDescription)") - exit(0) } print("Connection closed") } + + private func setState(_ state: ChannelState) { + print("socket: \(state)") + onStateChange?(state) + } + + private func startPathMonitor() { + /*pathMonitor.pathUpdateHandler = { [weak self] path in + guard let self else {return} + print("network connection changed \(path.status)") + self.closeCurrentChannel() + if path.status == .satisfied { + self.retrySemaphore.signal() + } + }*/ + pathMonitor.pathUpdateHandler = { path in + print("network connection changed \(path.status)") + self.closeCurrentChannel() + if path.status == .satisfied { + self.retrySemaphore.signal() + } + } + let queue = DispatchQueue(label: "net1090.connection-monitor") + pathMonitor.start(queue: queue) + } + + private func setCurrentChannel(_ channel: Channel?) { + pathLock.lock() + currentChannel = channel + pathLock.unlock() + } + + private func clearCurrentChannel() { + setCurrentChannel(nil) + } + + private func closeCurrentChannel() { + pathLock.lock() + let channel = currentChannel + pathLock.unlock() + channel?.close(promise: nil) + } } |
