Sesame-iOS/Sesame/Client.swift
2022-01-29 18:59:42 +01:00

106 lines
3.4 KiB
Swift

import Foundation
import CryptoKit
struct Client {
let server: URL
private let delegate = NeverCacheDelegate()
init(server: URL) {
self.server = server
}
private enum RequestReponse: Error {
case requestFailed
case unknownResponse
case success(UInt8)
}
func deviceStatus() async throws -> ClientState {
let url = server.appendingPathComponent("status")
let request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData)
let response = await integerReponse(to: request)
switch response {
case .requestFailed:
return .statusRequestFailed
case .unknownResponse:
return .unknownDeviceStatus
case .success(let int):
switch int {
case 0:
return .deviceDisconnected
case 1:
return .deviceConnected
default:
print("Unexpected device status '\(int)'")
return .unknownDeviceStatus
}
}
}
func keyResponse(key: SymmetricKey, id: Int) async throws -> ClientState {
let url = server.appendingPathComponent("key/\(id)")
var request = URLRequest(url: url)
request.httpBody = key.data
request.httpMethod = "POST"
let response = await integerReponse(to: request)
switch response {
case .requestFailed:
return .statusRequestFailed
case .unknownResponse:
return .unknownDeviceStatus
case .success(let int):
guard let status = KeyResult(rawValue: int) else {
print("Invalid key response: \(int)")
return .unknownDeviceStatus
}
return ClientState(keyResult: status)
}
}
private func fulfill(_ request: URLRequest) async -> Result<Data, RequestReponse> {
do {
let (data, response) = try await URLSession.shared.data(for: request)
guard let code = (response as? HTTPURLResponse)?.statusCode else {
print("No response from server")
return .failure(.requestFailed)
}
guard code == 200 else {
print("Invalid server response \(code)")
return .failure(.requestFailed)
}
return .success(data)
} catch {
print("Request failed: \(error)")
return .failure(.requestFailed)
}
}
private func integerReponse(to request: URLRequest) async -> RequestReponse {
let response = await fulfill(request)
switch response {
case .failure(let cause):
return cause
case .success(let data):
guard let string = String(data: data, encoding: .utf8) else {
print("Unexpected device status data: \([UInt8](data))")
return .unknownResponse
}
guard let int = UInt8(string) else {
print("Unexpected device status '\(string)'")
return .unknownResponse
}
return .success(int)
}
}
}
class NeverCacheDelegate: NSObject, NSURLConnectionDataDelegate {
func connection(_ connection: NSURLConnection, willCacheResponse cachedResponse: CachedURLResponse) -> CachedURLResponse? {
return nil
}
}