1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
|
//
// NetADSBDecoder.swift
// Net1090
//
// Created by Jacky Jack on 19/07/2024.
//
import Foundation
import Network
import NIO
protocol ADSBQueueDelegate: AnyObject {
//var message_array:Array<String> {get set}
func push(_ message: String)
func pop() -> String?
}
class NetADSBHandlder: ChannelInboundHandler {
typealias InboundIn = ByteBuffer
typealias OutboundOut = ByteBuffer
var messageDelegate: ADSBQueueDelegate?
func channelActive(context: ChannelHandlerContext) {
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
if let received = buffer.readString(length: readableBytes) {
//print(received,terminator: "")
/*
if let message_queue = message_queue {
message_queue.append(String(received))
print("Add new messsge")
}*/
//if self.message_array != nil {
// message_array?.append(String(received))
// print("\(message_array?.count)")
//}
if self.messageDelegate != nil {
if received.count == 17 {
let trimmed = received.trimmingCharacters(in: .newlines).lowercased()
//messageDelegate?.message_array.append(String(trimmed))
messageDelegate?.push(String(trimmed))
} else if received.count == 31 {
let trimmed = received.trimmingCharacters(in: .newlines).lowercased()
messageDelegate?.push(String(trimmed))
} else {
for line in received.components(separatedBy: .newlines) {
let trimmed = line.trimmingCharacters(in: .newlines).lowercased()
messageDelegate?.push(String(trimmed))
}
}
}
}
}
func errorCaught(context: ChannelHandlerContext, error: any Error) {
print("error: \(error.localizedDescription)")
context.close(promise: nil)
}
}
final class ADSBQueue: ADSBQueueDelegate {
private var message_array:Array<String> = []
private let lock = NSLock()
func push(_ message: String) {
lock.lock()
message_array.append(message)
lock.unlock()
}
func pop() -> String? {
lock.lock()
defer { lock.unlock() }
guard !message_array.isEmpty else { return nil }
return message_array.removeFirst()
}
var count: Int {
lock.lock()
defer { lock.unlock() }
return message_array.count
}
}
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
var port: Int
var msgarray = ADSBQueue()
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
//regiter delegate
handler.messageDelegate = msgarray
}
func start() throws {
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() {
stateLock.lock()
stopped = true
stateLock.unlock()
_ = retrySemaphore.signal()
do {
try group.syncShutdownGracefully()
} catch {
print("Error shutting down \(error.localizedDescription)")
}
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)
}
}
|