Spaces:
Running
Running
| import OpenClawProtocol | |
| import Foundation | |
| extension ChannelsStore { | |
| 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.loadConfigSchema() | |
| 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: ChannelsStatusSnapshot = try await GatewayConnection.shared.requestDecoded( | |
| method: .channelsStatus, | |
| 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 params: [String: AnyCodable] = [ | |
| "channel": AnyCodable("whatsapp"), | |
| ] | |
| let result: ChannelLogoutResult = try await GatewayConnection.shared.requestDecoded( | |
| method: .channelsLogout, | |
| params: params, | |
| 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 params: [String: AnyCodable] = [ | |
| "channel": AnyCodable("telegram"), | |
| ] | |
| let result: ChannelLogoutResult = try await GatewayConnection.shared.requestDecoded( | |
| method: .channelsLogout, | |
| params: params, | |
| 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 ChannelLogoutResult: Codable { | |
| let channel: String? | |
| let accountId: String? | |
| let cleared: Bool | |
| let envToken: Bool? | |
| } | |