iOS/Sources/App/Thread/CredentialsManagement/ThreadCredentialsManagement...

103 lines
3.2 KiB
Swift

import Foundation
import HAKit
import Shared
struct HAThreadNetworkConfig {
enum Source {
case Apple
case HomeAssistant
}
let id: String
let name: String
let source: Source
let credentials: [ThreadCredential]
}
final class ThreadCredentialsManagementViewModel: ObservableObject {
@Published var configs: [HAThreadNetworkConfig] = []
@Published var isLoading = false
private let threadClientService = Current.matter.threadClientService
@MainActor
func loadCredentials() async {
configs = []
do {
let appleKeychainCredentials = try await threadClientService.retrieveAllCredentials()
configs.append(.init(
id: UUID().uuidString,
name: "Apple Keychain",
source: .Apple,
credentials: appleKeychainCredentials
))
} catch {
Current.Log.error("Failed to 'retrieveAllCredentials' from thread Apple Keychain with error: \(error)")
}
}
@MainActor
func transfer(
_ credential: ThreadCredential,
to destination: HAThreadNetworkConfig.Source,
completion: @escaping (Bool) -> Void
) {
switch destination {
case .Apple:
// To be implemented when HA has a proper dataset listing similar to Apple
break
case .HomeAssistant:
shareCredentialWithHomeAssistant(credential: credential.activeOperationalDataSet) { success in
completion(success)
}
}
}
func deleteCredential(_ credential: ThreadCredential?) {
guard let credential else {
Current.Log.error("No credential provided to be deleted")
return
}
threadClientService.deleteCredential(macExtendedAddress: credential.macExtendedAddress) { [weak self] error in
if let error {
Current.Log.error("Failed to delete credential with error: \(error)")
}
Task.detached {
await self?.loadCredentials()
}
}
}
@MainActor
private func shareCredentialWithHomeAssistant(credential: String, completion: @escaping (Bool) -> Void) {
var remainingServers = Current.servers.all.count
var successCount = 0
let request = HARequest(type: .webSocket("thread/add_dataset_tlv"), data: [
"tlv": credential,
"source": "iOS-app",
])
for server in Current.servers.all {
Current.api(for: server)?.connection?.send(request).promise.pipe { result in
switch result {
case .fulfilled:
successCount += 1
case let .rejected(error):
Current.Log
.error(
"Failed to transfer thread credentials from apple to home assistant (server name: \(server.info.name): \(error.localizedDescription)"
)
}
remainingServers -= 1
if remainingServers == 0 {
completion(successCount == Current.servers.all.count)
}
}
}
}
}