2024-10-03 05:22:10 +00:00
|
|
|
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?
|
|
|
|
|
2024-10-05 17:05:11 +00:00
|
|
|
var dataBuffer = Data()
|
|
|
|
|
2024-10-03 18:42:36 +00:00
|
|
|
public init(id: String) {
|
2024-10-03 05:22:10 +00:00
|
|
|
self.id = id
|
|
|
|
}
|
|
|
|
|
2024-10-03 18:42:36 +00:00
|
|
|
public func connect(host: String, port: Int, useTLS: Bool, acceptInvalidCertificates: Bool) {
|
2024-10-03 17:55:00 +00:00
|
|
|
let parameters = NWParameters.tcp
|
2024-10-03 18:42:36 +00:00
|
|
|
if useTLS {
|
2024-10-03 17:55:00 +00:00
|
|
|
let tls = NWProtocolTLS.Options()
|
|
|
|
|
2024-10-03 18:42:36 +00:00
|
|
|
if (acceptInvalidCertificates) {
|
2024-10-03 17:55:00 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2024-10-03 18:42:36 +00:00
|
|
|
let connection = NWConnection(host: NWEndpoint.Host(host), port: NWEndpoint.Port(String(port))!, using: parameters)
|
2024-10-03 05:22:10 +00:00
|
|
|
connection.stateUpdateHandler = self.stateDidChange(to:)
|
|
|
|
self.receive(on: connection)
|
2024-10-05 17:05:11 +00:00
|
|
|
connection.start(queue: DispatchQueue(label: "Igloo"))
|
2024-10-03 05:22:10 +00:00
|
|
|
self.connection = connection
|
|
|
|
}
|
|
|
|
|
|
|
|
public func write(_ message: String) {
|
|
|
|
if let data = message.data(using: .utf8) {
|
|
|
|
connection?.send(content: data, completion: .idempotent)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public func disconnect() {
|
2024-10-05 17:05:11 +00:00
|
|
|
connection?.cancel()
|
2024-10-03 05:22:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)")
|
2024-10-05 17:05:11 +00:00
|
|
|
self.delegate?.didChangeState(socket: self.id, state: .disconnected)
|
|
|
|
self.disconnect()
|
2024-10-03 05:22:10 +00:00
|
|
|
|
|
|
|
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
|
2024-10-05 17:05:11 +00:00
|
|
|
if let error = error {
|
|
|
|
print("Receive error: \(error)")
|
|
|
|
self.delegate?.didChangeState(socket: self.id, state: .disconnected)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-10-03 05:22:10 +00:00
|
|
|
if let data = data, !data.isEmpty {
|
2024-10-05 17:05:11 +00:00
|
|
|
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) {
|
2024-10-03 05:22:10 +00:00
|
|
|
self.delegate?.didReceiveMessage(socket: self.id, message: message)
|
2024-10-05 17:05:11 +00:00
|
|
|
self.dataBuffer.removeAll() // Clear buffer after processing
|
2024-10-03 05:22:10 +00:00
|
|
|
}
|
|
|
|
}
|
2024-10-05 17:05:11 +00:00
|
|
|
|
|
|
|
if connection.state == .ready {
|
2024-10-03 17:55:00 +00:00
|
|
|
self.receive(on: connection)
|
|
|
|
}
|
2024-10-05 17:05:11 +00:00
|
|
|
|
|
|
|
if isComplete {
|
|
|
|
print("Connection completed.")
|
|
|
|
self.delegate?.didChangeState(socket: self.id, state: .disconnected)
|
|
|
|
}
|
2024-10-03 05:22:10 +00:00
|
|
|
}
|
|
|
|
}
|
2024-10-05 17:05:11 +00:00
|
|
|
|
2024-10-03 05:22:10 +00:00
|
|
|
|
|
|
|
}
|