import ClawdbotProtocol import Foundation extension ConnectionsStore { func start() { guard !self.isPreview else { return } guard self.pollTask == nil else { return } self.pollTask = Task.detached { [weak self] in guard let self else { return } await self.refresh(probe: true) await self.loadConfig() while !Task.isCancelled { try? await Task.sleep(nanoseconds: UInt64(self.interval * 1_000_000_000)) await self.refresh(probe: false) } } } func stop() { self.pollTask?.cancel() self.pollTask = nil } func refresh(probe: Bool) async { guard !self.isRefreshing else { return } self.isRefreshing = true defer { self.isRefreshing = false } do { let params: [String: AnyCodable] = [ "probe": AnyCodable(probe), "timeoutMs": AnyCodable(8000), ] let snap: ProvidersStatusSnapshot = try await GatewayConnection.shared.requestDecoded( method: .providersStatus, params: params, timeoutMs: 12000) self.snapshot = snap self.lastSuccess = Date() self.lastError = nil } catch { self.lastError = error.localizedDescription } } func startWhatsAppLogin(force: Bool, autoWait: Bool = true) async { guard !self.whatsappBusy else { return } self.whatsappBusy = true defer { self.whatsappBusy = false } var shouldAutoWait = false do { let params: [String: AnyCodable] = [ "force": AnyCodable(force), "timeoutMs": AnyCodable(30000), ] let result: WhatsAppLoginStartResult = try await GatewayConnection.shared.requestDecoded( method: .webLoginStart, params: params, timeoutMs: 35000) self.whatsappLoginMessage = result.message self.whatsappLoginQrDataUrl = result.qrDataUrl self.whatsappLoginConnected = nil shouldAutoWait = autoWait && result.qrDataUrl != nil } catch { self.whatsappLoginMessage = error.localizedDescription self.whatsappLoginQrDataUrl = nil self.whatsappLoginConnected = nil } await self.refresh(probe: true) if shouldAutoWait { Task { await self.waitWhatsAppLogin() } } } func waitWhatsAppLogin(timeoutMs: Int = 120_000) async { guard !self.whatsappBusy else { return } self.whatsappBusy = true defer { self.whatsappBusy = false } do { let params: [String: AnyCodable] = [ "timeoutMs": AnyCodable(timeoutMs), ] let result: WhatsAppLoginWaitResult = try await GatewayConnection.shared.requestDecoded( method: .webLoginWait, params: params, timeoutMs: Double(timeoutMs) + 5000) self.whatsappLoginMessage = result.message self.whatsappLoginConnected = result.connected if result.connected { self.whatsappLoginQrDataUrl = nil } } catch { self.whatsappLoginMessage = error.localizedDescription } await self.refresh(probe: true) } func logoutWhatsApp() async { guard !self.whatsappBusy else { return } self.whatsappBusy = true defer { self.whatsappBusy = false } do { let result: WhatsAppLogoutResult = try await GatewayConnection.shared.requestDecoded( method: .webLogout, params: nil, timeoutMs: 15000) self.whatsappLoginMessage = result.cleared ? "Logged out and cleared credentials." : "No WhatsApp session found." self.whatsappLoginQrDataUrl = nil } catch { self.whatsappLoginMessage = error.localizedDescription } await self.refresh(probe: true) } func logoutTelegram() async { guard !self.telegramBusy else { return } self.telegramBusy = true defer { self.telegramBusy = false } do { let result: TelegramLogoutResult = try await GatewayConnection.shared.requestDecoded( method: .telegramLogout, params: nil, timeoutMs: 15000) if result.envToken == true { self.configStatus = "Telegram token still set via env; config cleared." } else { self.configStatus = result.cleared ? "Telegram token cleared." : "No Telegram token configured." } await self.loadConfig() } catch { self.configStatus = error.localizedDescription } await self.refresh(probe: true) } } private struct WhatsAppLoginStartResult: Codable { let qrDataUrl: String? let message: String } private struct WhatsAppLoginWaitResult: Codable { let connected: Bool let message: String } private struct WhatsAppLogoutResult: Codable { let cleared: Bool } private struct TelegramLogoutResult: Codable { let cleared: Bool let envToken: Bool? }