diff options
| author | Dustin Mierau <dustin@mierau.me> | 2023-12-04 09:12:58 -0800 |
|---|---|---|
| committer | Dustin Mierau <dustin@mierau.me> | 2023-12-04 09:12:58 -0800 |
| commit | 471546236b8991f61d26c0e3aa8ee48b83b983af (patch) | |
| tree | b74331a8c8ea61ee7e1eaedfc7bbd1686bbc4702 /Hotline/Network/HotlineTracker.swift | |
| parent | 885119acdd27bd53ed3096285c3eca3e2d99ad70 (diff) | |
Starting to hash out a server view and tabs. Added research pdfs. etc.
Diffstat (limited to 'Hotline/Network/HotlineTracker.swift')
| -rw-r--r-- | Hotline/Network/HotlineTracker.swift | 260 |
1 files changed, 0 insertions, 260 deletions
diff --git a/Hotline/Network/HotlineTracker.swift b/Hotline/Network/HotlineTracker.swift deleted file mode 100644 index 2c44bc8..0000000 --- a/Hotline/Network/HotlineTracker.swift +++ /dev/null @@ -1,260 +0,0 @@ -import Foundation -import Network - -enum HotlineTrackerStatus: Int { - case disconnected - case connecting - case connected -} - -class HotlineTracker : ObservableObject { - let serverAddress: NWEndpoint.Host - let serverPort: NWEndpoint.Port = NWEndpoint.Port(rawValue: 5498)! - - static let magicPacket = Data([ - 0x48, 0x54, 0x52, 0x4B, // 'HTRK' - 0x00, 0x01 // Version - ]) - - var connection: NWConnection? - - var bytes = Data() - var maxDataLength: Int = 0 - var serverCount: Int = 0 - - @Published var connectionStatus: HotlineTrackerStatus = .disconnected - @Published var servers: [HotlineServer] = [] - - init(address: String) { - self.serverAddress = NWEndpoint.Host(address) - } - - func fetch() { - self.reset() - self.connect() - } - - private func reset() { - self.maxDataLength = 0 - self.serverCount = 0 - } - - private func connect() { - self.connection = NWConnection(host: self.serverAddress, port: self.serverPort, using: .tcp) - self.connection?.stateUpdateHandler = { [weak self] (newState: NWConnection.State) in - switch newState { - case .ready: - print("READY TO SEND AND RECEIVE DATA") - DispatchQueue.main.async { - self?.connectionStatus = .connected - } - self?.sendMagic() - case .cancelled: - print("CONNECTION CANCELLED") - DispatchQueue.main.async { - self?.connectionStatus = .disconnected - } - case .failed(let err): - print("CONNECTION ERROR \(err)") - DispatchQueue.main.async { - self?.connectionStatus = .disconnected - } - default: - print("CONNECTION OTHER THING") - } - } - - DispatchQueue.main.async { - self.connectionStatus = .connecting - } - self.connection?.start(queue: .global()) - } - - private func disconnect() { - guard let c = connection else { - print("HotlineTracker: already disconnected") - return - } - - c.cancel() - self.connection = nil - } - - private func sendMagic() { - guard let c = connection else { - print("HotlineTracker: invalid connection to send magic.") - return - } - - // let packet: [UInt8] = [0x48, 0x54, 0x52, 0x4B, 0x00, self.serverVersion] - - c.send(content: HotlineTracker.magicPacket, completion: .contentProcessed { [weak self] (error) in - if let err = error { - print("HotlineTracker: sending magic failed \(err)") - return - } - - print("HotlineTracker: sent magic!") - - self?.receiveMagic() - }) - } - - private func receiveMagic() { - guard let c = connection else { - print("HotlineTracker: invalid connection to receive magic.") - return - } - - print("HotlineTracker: receiving...") - c.receive(minimumIncompleteLength: 6, maximumLength: 6) { [weak self] (data, context, isComplete, error) in - guard let self = self, let data = data else { - return - } - - if data.isEmpty || !data.elementsEqual(HotlineTracker.magicPacket) { - print("HotlineTracker: invalid magic response") - self.disconnect() - return - } - // if let data = data, !data.isEmpty { - print("HotlineTracker: received magic response!") - // } - - if let error = error { - print("HotlineTracker: receive error \(error)") - } - else { - self.receiveHeader() - } - } - } - - private func receiveHeader() { - guard let c = connection else { - print("HotlineTracker: invalid connection to receive header.") - return - } - - print("HotlineTracker: receiving...") - c.receive(minimumIncompleteLength: 8, maximumLength: 8) { [weak self] (data, context, isComplete, error) in - guard let self = self else { - return - } - - if let error = error { - print("HotlineTracker: receive error \(error)") - self.disconnect() - return - } - - if let data = data, !data.isEmpty { - print("HotlineTracker: received \(data.count) header bytes") - - self.maxDataLength = Int(data[2]) * 0xFF + Int(data[3]) - self.maxDataLength -= 4 - print("HotlineTracker: message size = \(self.maxDataLength)") - - self.serverCount = Int(data[4]) * 256 + Int(data[5]) - print("HotlineTracker: server count = \(self.serverCount)") - } - - if let error = error { - print("HotlineTracker: receive error \(error)") - } - else { - self.receiveListing() - } - } - } - - private func receiveListing() { - guard let c = connection else { - print("HotlineTracker: invalid connection to receive data.") - return - } - - print("HotlineTracker: receiving...") - c.receive(minimumIncompleteLength: 1, maximumLength: 64 * 1024) { [weak self] (data, context, isComplete, error) in - guard let self = self else { - return - } - - if let data = data, !data.isEmpty { - print("HotlineTracker: received \(data.count) bytes") - self.bytes.append(contentsOf: data) - - if bytes.count >= maxDataLength { - print("HotlineTracker: done with data, should close. \(self.bytes.count) \(self.maxDataLength)") - self.disconnect() - self.parseListing() - return - } - } - - if let error = error { - print("HotlineTracker: receive error \(error)") - self.disconnect() - } - else { - print("HotlineTracker: not complete") - self.receiveListing() - } - } - } - - private func parseListing() { - // IP address (4 bytes) - // Port number (2 bytes) - // Number of users (2 bytes) - // Unused (2 bytes) - // Name size (1 byte) - // Name (name size) - // Description size (1 byte) - // Description (description size) - - var foundServers: [HotlineServer] = [] - - var cursor = 0 - for _ in 1...self.serverCount { - if self.bytes.count < cursor + 12 { - print("HotlineTracker: Data isn't long enough for next server") - break - } - - if - let ip_1 = self.bytes.readUInt8(at: cursor), - let ip_2 = self.bytes.readUInt8(at: cursor + 1), - let ip_3 = self.bytes.readUInt8(at: cursor + 2), - let ip_4 = self.bytes.readUInt8(at: cursor + 3), - let port = self.bytes.readUInt16(at: cursor + 4), - let userCount = self.bytes.readUInt16(at: cursor + 6), - let nameLengthByte = self.bytes.readUInt8(at: cursor + 10) { - - let nameLength = Int(nameLengthByte) - if let name = self.bytes.readString(at: cursor + 11, length: nameLength, encoding: .utf8) ?? self.bytes.readString(at: cursor + 11, length: nameLength, encoding: .ascii) { - if let descLengthByte = self.bytes.readUInt8(at: cursor + 11 + nameLength) { - let descLength = Int(descLengthByte) - if let desc = self.bytes.readString(at: cursor + 11 + nameLength + 1, length: descLength, encoding: .utf8) ?? self.bytes.readString(at: cursor + 11 + nameLength + 1, length: descLength, encoding: .ascii) { - let server = HotlineServer(address: "\(ip_1).\(ip_2).\(ip_3).\(ip_4)", port: port, users: userCount, name: name, description: desc) - - print("SERVER: \(server)") - - foundServers.append(server) - - cursor += 11 + nameLength + 1 + descLength - } - } - } - } - - print(cursor) - } - - DispatchQueue.main.async { -// print("CALLING CALLBACK") - self.servers = foundServers - } - - } -} |