2022-01-29 18:59:42 +01:00
|
|
|
import Foundation
|
|
|
|
import CryptoKit
|
|
|
|
|
2023-04-11 18:18:31 +02:00
|
|
|
final class Client {
|
2022-01-29 18:59:42 +01:00
|
|
|
|
2023-04-11 18:18:31 +02:00
|
|
|
// TODO: Use or delete
|
2022-01-29 18:59:42 +01:00
|
|
|
private let delegate = NeverCacheDelegate()
|
|
|
|
|
2023-04-11 18:18:31 +02:00
|
|
|
init() {}
|
2022-01-29 18:59:42 +01:00
|
|
|
|
2023-04-11 18:18:31 +02:00
|
|
|
func deviceStatus(authToken: Data, server: String) async -> ClientState {
|
|
|
|
await send(path: .getDeviceStatus, server: server, data: authToken).state
|
|
|
|
}
|
|
|
|
|
|
|
|
func sendMessageOverLocalNetwork(_ message: Message, server: String) async -> (state: ClientState, response: Message?) {
|
|
|
|
let data = message.encoded.hexEncoded
|
|
|
|
guard let url = URL(string: server + "message?m=\(data)") else {
|
|
|
|
return (.internalError("Invalid server url"), nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
var request = URLRequest(url: url)
|
|
|
|
request.httpMethod = "POST"
|
|
|
|
return await requestAndDecode(request)
|
2022-01-29 18:59:42 +01:00
|
|
|
}
|
|
|
|
|
2023-04-11 18:18:31 +02:00
|
|
|
func send(_ message: Message, server: String, authToken: Data) async -> (state: ClientState, response: Message?) {
|
2022-05-01 14:07:43 +02:00
|
|
|
let serverMessage = ServerMessage(authToken: authToken, message: message)
|
2023-04-11 18:18:31 +02:00
|
|
|
return await send(path: .postMessage, server: server, data: serverMessage.encoded)
|
|
|
|
}
|
|
|
|
|
|
|
|
private func send(path: RouteAPI, server: String, data: Data) async -> (state: ClientState, response: Message?) {
|
|
|
|
guard let url = URL(string: server) else {
|
|
|
|
return (.internalError("Invalid server url"), nil)
|
|
|
|
}
|
|
|
|
let fullUrl = url.appendingPathComponent(path.rawValue)
|
|
|
|
return await send(to: fullUrl, data: data)
|
2022-05-01 14:07:43 +02:00
|
|
|
}
|
|
|
|
|
2023-04-11 18:18:31 +02:00
|
|
|
private func send(to url: URL, data: Data) async -> (state: ClientState, response: Message?) {
|
2022-01-29 18:59:42 +01:00
|
|
|
var request = URLRequest(url: url)
|
2022-05-01 14:07:43 +02:00
|
|
|
request.httpBody = data
|
2022-01-29 18:59:42 +01:00
|
|
|
request.httpMethod = "POST"
|
2023-08-09 16:27:34 +02:00
|
|
|
request.timeoutInterval = 10
|
2023-04-11 18:18:31 +02:00
|
|
|
return await requestAndDecode(request)
|
|
|
|
}
|
|
|
|
|
|
|
|
private func requestAndDecode(_ request: URLRequest) async -> (state: ClientState, response: Message?) {
|
2022-04-09 17:43:33 +02:00
|
|
|
guard let data = await fulfill(request) else {
|
|
|
|
return (.deviceNotAvailable(.serverNotReached), nil)
|
|
|
|
}
|
|
|
|
guard let byte = data.first else {
|
|
|
|
return (.internalError("Empty response"), nil)
|
|
|
|
}
|
|
|
|
guard let status = MessageResult(rawValue: byte) else {
|
|
|
|
return (.internalError("Invalid message response: \(byte)"), nil)
|
2022-01-29 18:59:42 +01:00
|
|
|
}
|
2022-04-09 17:43:33 +02:00
|
|
|
let result = ClientState(keyResult: status)
|
|
|
|
guard data.count == Message.length + 1 else {
|
2023-04-11 18:18:31 +02:00
|
|
|
if data.count != 1 {
|
|
|
|
print("Device response with only \(data.count) bytes")
|
|
|
|
}
|
2022-04-09 17:43:33 +02:00
|
|
|
return (result, nil)
|
|
|
|
}
|
|
|
|
let messageData = Array(data.advanced(by: 1))
|
|
|
|
let message = Message(decodeFrom: messageData)
|
|
|
|
return (result, message)
|
2022-01-29 18:59:42 +01:00
|
|
|
}
|
|
|
|
|
2022-04-09 17:43:33 +02:00
|
|
|
private func fulfill(_ request: URLRequest) async -> Data? {
|
2022-01-29 18:59:42 +01:00
|
|
|
do {
|
|
|
|
let (data, response) = try await URLSession.shared.data(for: request)
|
|
|
|
guard let code = (response as? HTTPURLResponse)?.statusCode else {
|
|
|
|
print("No response from server")
|
2022-04-09 17:43:33 +02:00
|
|
|
return nil
|
2022-01-29 18:59:42 +01:00
|
|
|
}
|
|
|
|
guard code == 200 else {
|
|
|
|
print("Invalid server response \(code)")
|
2022-04-09 17:43:33 +02:00
|
|
|
return nil
|
2022-01-29 18:59:42 +01:00
|
|
|
}
|
2022-04-09 17:43:33 +02:00
|
|
|
return data
|
2022-01-29 18:59:42 +01:00
|
|
|
} catch {
|
|
|
|
print("Request failed: \(error)")
|
2022-04-09 17:43:33 +02:00
|
|
|
return nil
|
2022-01-29 18:59:42 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class NeverCacheDelegate: NSObject, NSURLConnectionDataDelegate {
|
|
|
|
|
|
|
|
func connection(_ connection: NSURLConnection, willCacheResponse cachedResponse: CachedURLResponse) -> CachedURLResponse? {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|