78 lines
2.3 KiB
Swift
78 lines
2.3 KiB
Swift
import Combine
|
|
import Foundation
|
|
import GRDB
|
|
|
|
@MainActor
|
|
final class ClientsStore: ObservableObject {
|
|
static let shared = ClientsStore()
|
|
|
|
@Published private(set) var ready = false
|
|
@Published private(set) var clients: [Client] = []
|
|
|
|
private let credentialsObservation = ValueObservation.tracking(Credentials.fetchAll)
|
|
|
|
init() {
|
|
Task {
|
|
do {
|
|
for try await creds in credentialsObservation.values(in: Database.shared.dbQueue) {
|
|
processCredentials(creds)
|
|
if !ready {
|
|
ready = true
|
|
}
|
|
}
|
|
} catch {}
|
|
}
|
|
}
|
|
|
|
private func processCredentials(_ credentials: [Credentials]) {
|
|
let existsJids = Set(clients.map { $0.credentials.bareJid })
|
|
let credentialsJids = Set(credentials.map { $0.bareJid })
|
|
|
|
let forAdd = credentials.filter { !existsJids.contains($0.bareJid) }
|
|
let newClients = forAdd.map { Client(credentials: $0) }
|
|
|
|
let forRemove = clients.filter { !credentialsJids.contains($0.credentials.bareJid) }
|
|
forRemove.forEach { $0.disconnect() }
|
|
|
|
var updatedClients = clients.filter { credentialsJids.contains($0.credentials.bareJid) }
|
|
updatedClients.append(contentsOf: newClients)
|
|
clients = updatedClients
|
|
}
|
|
}
|
|
|
|
extension ClientsStore {
|
|
func tryLogin(_ jidStr: String, _ pass: String) async throws {
|
|
// login with fake timeout
|
|
async let sleep: Void? = try? await Task.sleep(nanoseconds: 1 * NSEC_PER_SEC)
|
|
async let request = try await Client.tryLogin(with: .init(bareJid: jidStr, pass: pass, isActive: true))
|
|
let client = try await(request, sleep).0
|
|
|
|
clients.append(client)
|
|
try? await client.credentials.save()
|
|
}
|
|
|
|
func reconnectAll() {
|
|
Task {
|
|
await withTaskGroup(of: Void.self) { taskGroup in
|
|
for client in clients {
|
|
taskGroup.addTask {
|
|
await client.connect()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
extension ClientsStore {
|
|
var actualRosters: [Roster] {
|
|
get async {
|
|
var allRosters: [Roster] = []
|
|
for client in clients {
|
|
allRosters.append(contentsOf: await client.rosters)
|
|
}
|
|
return allRosters
|
|
}
|
|
}
|
|
}
|