103 lines
3.7 KiB
Swift
103 lines
3.7 KiB
Swift
//
|
|
// GeminiConnection.swift
|
|
// Gemini
|
|
//
|
|
// Created by Shadowfacts on 7/12/20.
|
|
//
|
|
|
|
import Foundation
|
|
import Network
|
|
|
|
protocol GeminiConnectionDelegate: class {
|
|
func connectionReady(_ connection: GeminiConnection)
|
|
func connection(_ connection: GeminiConnection, receivedData data: Data?, header: GeminiResponseHeader)
|
|
func connectionCompleted(_ connection: GeminiConnection)
|
|
}
|
|
|
|
class GeminiConnection {
|
|
|
|
weak var delegate: GeminiConnectionDelegate?
|
|
|
|
private var connection: NWConnection?
|
|
|
|
init(endpoint: NWEndpoint, delegate: GeminiConnectionDelegate? = nil) {
|
|
self.connection = NWConnection(to: endpoint, using: .gemini)
|
|
self.delegate = delegate
|
|
|
|
startConnection()
|
|
}
|
|
|
|
private func startConnection() {
|
|
guard let connection = connection else { return }
|
|
|
|
connection.stateUpdateHandler = { (newState) in
|
|
switch newState {
|
|
case .ready:
|
|
print("\(connection) established")
|
|
self.delegate?.connectionReady(self)
|
|
case let .failed(error):
|
|
print("\(connection) failed: \(error)")
|
|
connection.cancel()
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
|
|
// todo: should this be on a background queue?
|
|
connection.start(queue: .main)
|
|
}
|
|
|
|
var report: NWConnection.PendingDataTransferReport!
|
|
|
|
func sendRequest(_ request: GeminiRequest) {
|
|
guard let connection = connection else { return }
|
|
|
|
let message = NWProtocolFramer.Message(geminiRequest: request)
|
|
let context = NWConnection.ContentContext(identifier: "GeminiRequest", metadata: [message])
|
|
// todo: should this really always be idempotent?
|
|
connection.send(content: nil, contentContext: context, isComplete: true, completion: .contentProcessed({ (_) in }))
|
|
receiveNextMessage()
|
|
report = connection.startDataTransferReport()
|
|
}
|
|
|
|
private func receiveNextMessage() {
|
|
guard let connection = connection else { return }
|
|
|
|
// todo: should this really be .max
|
|
connection.receive(minimumIncompleteLength: 1, maximumLength: 65536) { (data, context, isComplete, error) in
|
|
// todo: handle error
|
|
if let message = context?.protocolMetadata(definition: GeminiProtocol.definition) as? NWProtocolFramer.Message,
|
|
let header = message.geminiResponseHeader,
|
|
let delegate = self.delegate {
|
|
delegate.connection(self, receivedData: data, header: header)
|
|
self.receiveNextMessage()
|
|
}
|
|
if isComplete {
|
|
self.delegate?.connectionCompleted(self)
|
|
self.report.collect(queue: .main) { (report) in
|
|
print(report.debugDescription)
|
|
}
|
|
// connection.cancel()
|
|
}
|
|
}
|
|
// connection.receiveMessage { (data, context, isComplete, error) in
|
|
// if let message = context?.protocolMetadata(definition: GeminiProtocol.definition) as? NWProtocolFramer.Message,
|
|
// let header = message.geminiResponseHeader,
|
|
// let delegate = self.delegate {
|
|
//// let response = GeminiResponse(status: header.status, meta: header.meta, body: data)
|
|
// delegate.connection(self, receivedData: data, header: header)
|
|
// }
|
|
// // todo: error handling
|
|
// if let error = error {
|
|
// print(error)
|
|
// } else if isComplete {
|
|
// self.delegate?.connectionCompleted(self)
|
|
// connection.cancel()
|
|
// } else {
|
|
// self.receiveNextMessage()
|
|
// }
|
|
// }
|
|
}
|
|
|
|
}
|