import Foundation import Network protocol SocketDelegate: AnyObject { func didChangeState(socket: String, state: SocketState) func didReceiveMessage(socket: String, message: String) } public class Socket: NSObject { var id: String var connection: NWConnection? weak var delegate: SocketDelegate? var dataBuffer = Data() public init(id: String) { self.id = id } public func connect(host: String, port: Int, useTLS: Bool, acceptInvalidCertificates: Bool) { let parameters = NWParameters.tcp if useTLS { let tls = NWProtocolTLS.Options() if (acceptInvalidCertificates) { sec_protocol_options_set_verify_block(tls.securityProtocolOptions, { (sec_protocol_metadata, sec_trust, sec_protocol_verify_complete) in sec_protocol_verify_complete(true) }, DispatchQueue.global()) } parameters.defaultProtocolStack.applicationProtocols.insert(tls, at: 0) } let connection = NWConnection(host: NWEndpoint.Host(host), port: NWEndpoint.Port(String(port))!, using: parameters) connection.stateUpdateHandler = self.stateDidChange(to:) self.receive(on: connection) connection.start(queue: DispatchQueue(label: "Igloo")) self.connection = connection } public func write(_ message: String) { if let data = message.data(using: .utf8) { connection?.send(content: data, completion: .idempotent) } } public func disconnect() { connection?.cancel() } func stateDidChange(to state: NWConnection.State) { switch state { case .setup: print("connection setup") case .waiting(let error): print("connection waiting: \(error)") case .preparing: self.delegate?.didChangeState(socket: self.id, state: .connecting) case .ready: self.delegate?.didChangeState(socket: self.id, state: .connected) case .failed(let error): print("connection failed: \(error)") self.delegate?.didChangeState(socket: self.id, state: .disconnected) self.disconnect() case .cancelled: self.delegate?.didChangeState(socket: self.id, state: .disconnected) default: print("other") } } func receive(on connection: NWConnection) { connection.receive(minimumIncompleteLength: 1, maximumLength: 65536) { (data, contentContext, isComplete, error) in if let error = error { print("Receive error: \(error)") self.delegate?.didChangeState(socket: self.id, state: .disconnected) return } if let data = data, !data.isEmpty { self.dataBuffer.append(data) // Append the data to the buffer // Process buffer if enough data is available (protocol-specific logic) if let message = String(data: self.dataBuffer, encoding: .utf8) { self.delegate?.didReceiveMessage(socket: self.id, message: message) self.dataBuffer.removeAll() // Clear buffer after processing } } if connection.state == .ready { self.receive(on: connection) } if isComplete { print("Connection completed.") self.delegate?.didChangeState(socket: self.id, state: .disconnected) } } } }