Files
suixinkan_uikit/suixinkan/Features/ScenicQueue/Services/ScenicQueueSocketClient.swift
2026-07-07 15:32:25 +08:00

74 lines
2.4 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// ScenicQueueSocketClient.swift
// suixinkan
//
import Foundation
/// WebSocket
final class ScenicQueueSocketClient {
var onMessage: ((ScenicQueueSocketMessage) -> Void)?
private let environment: APIEnvironment
private let session: URLSession
private let decoder = JSONDecoder()
private var task: URLSessionWebSocketTask?
private var connectedSpotId: Int64?
init(environment: APIEnvironment = .current, session: URLSession = .shared) {
self.environment = environment
self.session = session
}
///
func connect(socketToken: String, scenicId: Int64, scenicSpotId: Int64) {
guard !socketToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else { return }
disconnect()
connectedSpotId = scenicSpotId
let webSocketTask = session.webSocketTask(with: environment.webSocketURL)
task = webSocketTask
webSocketTask.resume()
sendSubscribePayloads(scenicSpotId: scenicSpotId)
receiveLoop()
}
///
func disconnect() {
task?.cancel(with: .normalClosure, reason: nil)
task = nil
connectedSpotId = nil
}
private func sendSubscribePayloads(scenicSpotId: Int64) {
[
#"{"type":306,"params":{"scenic_spot_id":\#(scenicSpotId)}}"#,
#"{"type":307,"params":{"scenic_spot_id":\#(scenicSpotId)}}"#,
].forEach { payload in
task?.send(.string(payload)) { _ in }
}
}
private func receiveLoop() {
task?.receive { [weak self] result in
guard let self else { return }
switch result {
case .success(let message):
if case .string(let text) = message {
self.handle(text)
}
self.receiveLoop()
case .failure:
self.task = nil
}
}
}
private func handle(_ text: String) {
let trimmed = text.trimmingCharacters(in: .whitespacesAndNewlines)
guard trimmed.hasPrefix("{"), let data = trimmed.data(using: .utf8) else { return }
guard let message = try? decoder.decode(ScenicQueueSocketMessage.self, from: data) else { return }
guard message.isQueueEvent else { return }
onMessage?(message)
}
}