新增景区排队管理功能
This commit is contained in:
@ -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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user