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 host: String
|
|
|
|
var port: Int
|
|
|
|
var useTLS: Bool
|
|
|
|
var acceptInvalidCertificates: Bool
|
|
|
|
|
|
|
|
var connection: NWConnection?
|
|
|
|
|
|
|
|
weak var delegate: SocketDelegate?
|
|
|
|
|
|
|
|
public init(id: String, host: String, port: Int, useTLS: Bool, acceptInvalidCertificates: Bool) {
|
|
|
|
self.id = id
|
|
|
|
self.host = host
|
|
|
|
self.port = port
|
|
|
|
|
|
|
|
self.useTLS = useTLS
|
|
|
|
self.acceptInvalidCertificates = acceptInvalidCertificates
|
|
|
|
}
|
|
|
|
|
|
|
|
public func connect() {
|
2024-10-03 17:55:00 +00:00
|
|
|
let parameters = NWParameters.tcp
|
|
|
|
if self.useTLS {
|
|
|
|
let tls = NWProtocolTLS.Options()
|
|
|
|
|
|
|
|
if (self.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(self.host), port: NWEndpoint.Port(String(self.port))!, using: parameters)
|
2024-10-03 05:22:10 +00:00
|
|
|
connection.stateUpdateHandler = self.stateDidChange(to:)
|
|
|
|
self.receive(on: connection)
|
|
|
|
connection.start(queue: .main)
|
|
|
|
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?.forceCancel()
|
|
|
|
}
|
|
|
|
|
|
|
|
func stateDidChange(to state: NWConnection.State) {
|
|
|
|
switch state {
|
|
|
|
case .setup:
|
|
|
|
print("connection setup")
|
|
|
|
break
|
|
|
|
|
|
|
|
case .waiting(let error):
|
|
|
|
print("connection waiting: \(error)")
|
|
|
|
break
|
|
|
|
|
|
|
|
case .preparing:
|
|
|
|
self.delegate?.didChangeState(socket: self.id, state: .connecting)
|
|
|
|
break
|
|
|
|
|
|
|
|
case .ready:
|
|
|
|
self.delegate?.didChangeState(socket: self.id, state: .connected)
|
|
|
|
break
|
|
|
|
|
|
|
|
case .failed(let error):
|
|
|
|
print("connection failed: \(error)")
|
|
|
|
break
|
|
|
|
|
|
|
|
case .cancelled:
|
|
|
|
self.delegate?.didChangeState(socket: self.id, state: .disconnected)
|
|
|
|
break
|
|
|
|
|
|
|
|
default:
|
|
|
|
print("other")
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func receive(on connection: NWConnection) {
|
|
|
|
connection.receive(minimumIncompleteLength: 1, maximumLength: 65536) { (data, contentContext, isComplete, error) in
|
|
|
|
if let data = data, !data.isEmpty {
|
2024-10-03 17:45:22 +00:00
|
|
|
if let message = String(data: data, encoding: .utf8) {
|
2024-10-03 05:22:10 +00:00
|
|
|
self.delegate?.didReceiveMessage(socket: self.id, message: message)
|
|
|
|
}
|
|
|
|
}
|
2024-10-03 17:55:00 +00:00
|
|
|
|
|
|
|
if (connection.state == .ready) {
|
|
|
|
self.receive(on: connection)
|
|
|
|
}
|
2024-10-03 05:22:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|