// // QSLSocketManager.swift // QuickSearchLocation // // Created by Destiny on 2024/12/6. // import SocketRocket import Foundation enum QSLSocketStatus: UInt { case connecting // 正在连接 case connected // 已连接 case failed // 失败 case closedByServer // 系统关闭 case closedByUser // 用户关闭 case received // 接收消息 } protocol QSLSocketManagerDelegate: AnyObject { func socketDidReceiveMessage(with string: String) } class QSLSocketManager: NSObject, SRWebSocketDelegate { static let shared = QSLSocketManager() private var webSocket: SRWebSocket? private var timer: Timer? private var pingTimer: Timer? // 每10秒钟发送一次ping消息 private var currentCount: UInt = 0 // 当前重连次数 var delegate: QSLSocketManagerDelegate? var urlString: String = "" var overtime: TimeInterval = 3.0 // 重连时间间隔,默认3秒钟 var reconnectCount: UInt = UInt.max // 重连次数,默认无限次 var status: QSLSocketStatus = .connecting private override init() { super.init() let url = "\(QSLApi.prodWSUrl)/websocket/\(QSLBaseManager.shared.userModel.authToken)" self.urlString = url } // MARK: - Public Methods @objc func connect() { // 先关闭连接 self.webSocket?.close() self.webSocket?.delegate = nil // 后开启连接 if let url = URL(string: self.urlString) { self.webSocket = SRWebSocket(urlRequest: URLRequest(url: url)) self.webSocket?.delegate = self } self.status = .connecting self.webSocket?.open() } func close() { self.webSocket?.close() self.webSocket = nil self.timer?.invalidate() self.timer = nil self.pingTimer?.invalidate() self.pingTimer = nil } func reconnect() { guard currentCount < reconnectCount else { print("重连次数已用完……") self.timer?.invalidate() self.timer = nil return } // 计数器 +1 currentCount += 1 print("\(overtime)秒后进行第\(currentCount)次重试连接……") // 开启定时器进行重连 self.timer = Timer.scheduledTimer(timeInterval: overtime, target: self, selector: #selector(connect), userInfo: nil, repeats: false) RunLoop.current.add(self.timer!, forMode: .common) } func sendMessage(_ message: String) { do { try self.webSocket?.send(string: message) ///判断要不要弹引导用户去评价 QSLGuideusersToCommentManager.commentShare.manageWhetherTriggerPopUpWindow(QSLGuideusersToCommentType.nonMember) print("消息已发送") } catch { print("发送消息失败!") } } @objc func sendPingMessage() { guard status == .connected else { return } do { try self.webSocket?.sendPing(nil) print("发送心跳包") } catch { print("发送心跳包失败!") } } // MARK: - SRWebSocketDelegate Methods func webSocket(_ webSocket: SRWebSocket, didReceiveMessageWith string: String) { delegate?.socketDidReceiveMessage(with: string) let locationMessage = QSLMapMessageModel.mapModel(from: string) switch locationMessage.cmd { case "d.refresh.friend.list": NotificationCenter.default.post(name: QSLNotification.QSLRefreshFriend, object: nil) break case "d.refresh.friend.message": NotificationCenter.default.post(name: QSLNotification.QSLRefreshMessage, object: nil) break case "d.refresh.friend.request": NotificationCenter.default.post(name: QSLNotification.QSLRefreshRequest, object: nil) break case "d.refresh.contact": NotificationCenter.default.post(name: QSLNotification.QSLRefreshContact, object: nil) break case "d.refresh.member": NotificationCenter.default.post(name: QSLNotification.QSLRefreshMember, object: nil) break default: break } print("收到信息:\(string)") } func webSocketDidOpen(_ webSocket: SRWebSocket) { print("已链接服务器:\(webSocket.url ?? URL(fileURLWithPath: ""))") // 重置计数器 self.currentCount = 0 self.status = .connected // 开启ping定时器 self.pingTimer = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(sendPingMessage), userInfo: nil, repeats: true) RunLoop.current.add(self.pingTimer!, forMode: .common) } func webSocket(_ webSocket: SRWebSocket, didFailWithError error: Error) { print("链接失败:\(error.localizedDescription)") self.status = .failed // 尝试重新连接 reconnect() } func webSocket(_ webSocket: SRWebSocket, didCloseWithCode code: Int, reason: String?, wasClean: Bool) { print("链接已关闭:code:\(code) reason:\(String(describing: reason))") if code == 1000 { self.status = .closedByUser } else { self.status = .closedByServer reconnect() } } func webSocket(_ webSocket: SRWebSocket, didReceivePingWith data: Data?) { print("收到 Ping") } func webSocket(_ webSocket: SRWebSocket, didReceivePong pongData: Data?) { print("收到 Pong") } }