summaryrefslogtreecommitdiff
path: root/Net1090
diff options
context:
space:
mode:
authorArturs Artamonovs <arturs.artamonovs@protonmail.com>2026-09-10 09:57:11 +0100
committerArturs Artamonovs <arturs.artamonovs@protonmail.com>2026-09-10 09:57:11 +0100
commited53ed83b71f2f3005d8b52ad005aeff1f59e39c (patch)
tree33244508eae2ed3651de5b5a840556438fd39495 /Net1090
parentdd31184b900636214897a1a08026279390049b92 (diff)
downloadADSBDecoder-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.swift136
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)
+ }
}