Files
multi-simadmin/apps/ios/Sources/MultiSimAdmin/Features/Fleet/FleetViewModel.swift
T

88 lines
2.8 KiB
Swift

import Foundation
@MainActor
final class FleetViewModel: ObservableObject {
struct Row: Equatable, Identifiable {
let id: UUID
var instance: Instance
var status: ConnectionStatus
var testing: Bool
}
@Published var rows: [Row] = []
@Published var searchText = ""
@Published var selectedIDs: Set<UUID> = []
@Published var selectionMode = false
@Published var isLoading = false
@Published var errorMessage: String?
@Published var showingForm = false
private let repository: any InstanceRepository
private let probe: ConnectionProbe
private let credentials: any CredentialStore
init(
repository: any InstanceRepository,
probe: ConnectionProbe,
credentials: any CredentialStore
) {
self.repository = repository
self.probe = probe
self.credentials = credentials
}
func refresh() async {
isLoading = true
errorMessage = nil
do {
let query = InstanceQuery(search: searchText.isEmpty ? nil : searchText)
let instances = try await repository.list(query)
rows = instances.map {
Row(id: $0.id, instance: $0, status: .unknown, testing: true)
}
await withTaskGroup(of: Void.self) { group in
for instance in instances {
group.addTask { [probe] in
let result = try? await probe.test(instance)
await self.applyProbe(instance.id, result)
}
}
}
} catch {
errorMessage = "无法刷新节点列表"
}
isLoading = false
}
func add(_ input: InstanceInput) async throws {
let created = try await repository.create(input)
if let password = input.password, !password.isEmpty {
try credentials.set(instanceID: created.id, password: password)
}
showingForm = false
await refresh()
}
func delete(_ ids: [UUID]) async {
for id in ids {
if let row = rows.first(where: { $0.id == id }) {
do {
try await repository.delete(id, expectedRevision: row.instance.configRevision)
try credentials.remove(instanceID: id)
} catch {
errorMessage = "删除 \(row.instance.name) 失败"
}
}
}
selectedIDs.removeAll()
selectionMode = false
await refresh()
}
private func applyProbe(_ id: UUID, _ result: ConnectionResult?) {
guard let index = rows.firstIndex(where: { $0.id == id }) else { return }
rows[index].status = result?.status ?? .unknown
rows[index].testing = false
}
}