新增景区排队管理功能

This commit is contained in:
2026-07-07 15:32:25 +08:00
parent 854a66689f
commit 0aa8b14e1f
20 changed files with 4642 additions and 1 deletions

View File

@ -0,0 +1,73 @@
//
// 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)
}
}