Case: 怎样捕捉针对domain 对象的批量修改的请求

本文讨论了如何在系统中实现针对特定类域对象的批量属性修改,包括序列化为XML或使用动态表存储修改请求,以及通过反射解析域对象属性进行操作的策略。

      从题目上看到这是一个很奇怪的需要。 具体说来现在有一组domain 对象,  它们是用来表示各种规则的。 总共有大约10类这些对象,  每一种对象又分为不同层次的, 不同复杂度。  现在有一个需求, 客户想针对某一类domain 对象, 想批量的修改它们的属性, 这些属性的修改是比较复杂的,需要在UI 上面设定。  在用户提交save 请求后 系统记录下所有的修改请求。 可能涉及到多个domain 对象的属性的增加、修改或者删除。

 

     系统中一个MDB 类型的EJB 取得这个request, 然后分析出所有domain 的增加、修改或者删除, 执行具体的相应的操作。 如果针对某一个domain 对象的操作失败 并不会影响别的domain 对象的修改, 系统只是记录下该失败的domain 的操作供反馈给用户。  

 

      说了一大堆, 问题出来了,  怎么保持这个临时的request的内容。  按照本人已经其他开发人员的意思将这个请求的内容 序列化,  如果担心二进制的序列化难以debug, 可以将其marshal 成 XML string, 保存到CLOB类型的字段中。  这样就是一个典型的key/value 的形式。  

     但是现在客户坚决反对这种方式 提出了采用动态表的方式。 主要涉及到两张表 item 表记录需要改变的 domain 对象 ,类型: 增加 , 修改, 删除, 以及domain对象的 key; 另外一张item detail 表 记录domain 对象的每一个需要改变的属性。主要记录改变后属性的值。   当然如果domain 里的属性如果是另外一个domain,  就需要涉及到另外一个item ,  这个属性对应的item的 parent 是原来的那个domain 对应的item。 系统中一大堆的domain  对象 总共5,60个, 如果每个这么手工match 非要疯掉不可。  现在想到一个主意 前期已经有每一个domain 对象到 数据库表的 Hibernate ORM mapping 文件。  可以通过分析这些mapping 文件 得到每个domain 中的属性 对应表字段的对应关系,  然后根据前台传过来的 domain 对象来通过反射方式分析所有的属性。

        写了这么一大堆, 只是为了让自己更清楚点。 先暂时这样, 这段时间就要耗在上面了,囧。

// // WebSocketManager.swift // SurveillanceHome // // Created by duxuying on 2023/10/26. // Copyright © 2023 tplink. All rights reserved. // import Foundation import Starscream import SwiftyJSON public enum AppnetworkStatus: Int { case unknow = 0 case wan case wlan case none } public enum CloudWSEventType: Int { case roleChange = 0 case siteChange } // MARK: - WebSocket代理 //这里即设置代理,稍后还会发通知.使用情况不一样. protocol WebSocketManagerDelegate: AnyObject { /// 建立连接成功通知 func webSocketManagerDidConnect(manager: WebSocketManager) /// 断开链接通知,参数 `isReconnecting` 表示是否处于等待重新连接状态。 func webSocketManagerDidDisconnect(manager: WebSocketManager, error: Error?) /// 接收到消息后的回调(String) func webSocketManagerDidReceiveMessage(manager: WebSocketManager, text: String) /// 接收到消息后的回调(Data) func webSocketManagerDidReceiveData(manager: WebSocketManager, data: Data) } enum WebSocketConnectType { case closed //初始状态,未连接 case connect //已连接 case disconnect //连接后断开 case reconnecting //重连中... } class WebSocketManager: NSObject { /// 单例,可以使用单例,也可以使用[alloc]init 根据情况自己选择 static let shard = WebSocketManager() /// WebSocket对象 private var webSocket : Starscream.WebSocket? /// 是否连接 var isConnected : Bool = false { didSet { if isConnected != oldValue { if (!isConnected && !isActivelyClose && isHaveNet) { self.reConnectSocket() } } } } /// 代理 weak var delegate: WebSocketManagerDelegate? private var heartbeatInterval: TimeInterval = 15 /// 重连次数 private var reConnectCount: Int = 0 private var reConnectVmsCount: Int = 0 //存储要发送给服务端的数据,本案例不实现此功能,如有需求自行实现 // private var sendDataArray = [String]() private let appContext = TPAppContextFactory.shared() public var connectDic: [String : Any] public var subscribeDic: [String : String] public var deviceStatusSubscribeDic: [String: String] = [:] public var deviceShareSubscribeDic: [String: String] = [:] // private let onceToken = "创建单例" public var receiveMessageList:[TPSSMessage] = [] ///心跳包定时器 var heartBeatTimer: Timer? ///网络监听定时器 var netWorkTimer:Timer? var connectType : WebSocketConnectType = .closed /// 用于判断是否主动关闭长连接,如果是主动断开连接,连接失败的代理中,就不用执行 重新连接方法 private var isActivelyClose:Bool = false /// 当前是否有网络, private var isHaveNet:Bool = true //短时收到多次通知,只执行一次 private var isNotificationPost = false public var urlStrng: String? private var retryCount = 0 override private init() { self.connectDic = ["method":"connect","data":["csrfToken":"\(appContext.loginHistories[0].vmsToken)"]] as [String : Any] self.subscribeDic = ["method":"subscribe","topic":"/v2user/queue/vms/\(appContext.loginHistories[0].vmsId)/device-message-inform"] // webSocket.advancedDelegate = self } // MARK: - 公开方法,外部调用 public func updatenetWorkStatus(networkStatus: AppnetworkStatus){ switch(networkStatus){ case .wan: if !self.isConnected { self.isHaveNet = true } case .wlan: if !self.isConnected { self.isHaveNet = true } case .none: if self.isConnected { self.isHaveNet = false } case .unknow: break } } public func update(cloudEventType: CloudWSEventType = .roleChange){ if appContext.loginType == .personal { guard let url = URL(string: "https://aps1-vms-api-beta.tplinkcloud.com"), let ip = url.host else { return } self.urlStrng = String(format: "wss://%@/api/app/personal/accounts/%@/ws/status",ip ,appContext.accountInfo.pcAccountId) // self.connectDic = ["method":"connect","data":["csrfToken":"3530618e30e74c68847e817f77114141"]] as [String : Any] self.connectDic = ["method":"connect","data":["csrfToken":"\(appContext.accountInfo.vmsToken)"]] as [String : Any] // self.connectDic = ["method":"connect","data":["csrfToken":"TPEC_SID=a1-iam-d3b65df38e864e55905372bcc623cdcd"]] as [String : Any] self.subscribeDic = ["method":"subscribe","topic":"/topic/omada/\(appContext.accountInfo.accountID)/device-info"] self.deviceStatusSubscribeDic = ["method":"subscribe","topic":"/topic/omada/\(appContext.accountInfo.pcAccountId)/device-info"] self.deviceShareSubscribeDic = ["method":"subscribe","topic":"/topic/personal/accounts/\(appContext.accountInfo.pcAccountId)/share-message-notify"] } else if appContext.loginType == .cloudLocalAccess { guard let url = URL(string: appContext.loginHistories[0].vmsURL), let ip = url.host else { return } self.urlStrng = String(format: "wss://%@/api/v1/vms/cloud-access/%@/websocket/api/app/vms/%@/ws/status",ip ,appContext.loginHistories[0].vmsId, appContext.loginHistories[0].localVmsId) self.connectDic = ["method":"connect","data":["csrfToken":"\(appContext.loginHistories[0].vmsToken)"]] as [String : Any] self.subscribeDic = ["method":"subscribe","topic":"/v2user/queue/vms/\(appContext.loginHistories[0].localVmsId)/users/\(appContext.loginHistories[0].vmsOwnerAccountId)/device-message-inform"] } else if appContext.loginType == .local{ self.urlStrng = String(format: "wss://%@:%d/api/app/vms/%@/ws/status",appContext.loginHistories[0].vmsIp, appContext.loginHistories[0].vmsPort, appContext.loginHistories[0].vmsId) self.connectDic = ["method":"connect","data":["csrfToken":"\(appContext.loginHistories[0].vmsToken)"]] as [String : Any] self.subscribeDic = ["method":"subscribe","topic":"/v2user/queue/vms/\(appContext.loginHistories[0].vmsId)/device-message-inform"] } else if appContext.loginType == .cloud { guard let url = URL(string: appContext.loginHistories[0].vmsURL), let ip = url.host else { return } self.urlStrng = String(format: "wss://%@/api/app/vms/%@/ws/status",ip, appContext.loginHistories[0].vmsId) self.connectDic = ["method":"connect","data":["csrfToken":"\(appContext.loginHistories[0].vmsToken)"]] as [String : Any] if cloudEventType == .siteChange { self.subscribeDic = ["method":"subscribe","topic":"/topic/vms/\(appContext.loginHistories[0].vmsId)/users/\(appContext.accountInfo.pcUserId)/site-permission" ] } else { self.subscribeDic = ["method":"subscribe","topic":"/topic/vms/\(appContext.loginHistories[0].vmsId)/users/\(appContext.accountInfo.pcUserId)/role"] } } } private func checkIfInfoOk() -> Bool { if appContext.loginType == .cloudLocalAccess { if (appContext.loginHistories[0].vmsURL == "" || appContext.loginHistories[0].vmsId == "" || appContext.loginHistories[0].vmsToken == "" || appContext.loginHistories[0].vmsOwnerAccountId == "") { return false } } else if appContext.loginType == .local{ if (appContext.loginHistories[0].vmsIp == "" || appContext.loginHistories[0].vmsId == "" || appContext.loginHistories[0].vmsToken == "") { return false } } return true } public func getMessageList()->Array<TPSSMessage> { return receiveMessageList } public func clearMessageList(){ self.receiveMessageList.removeAll() } func connectSocket(_ paremeters: Any?) { if let url = urlStrng { guard let url = URL(string: url) else { return } if !checkIfInfoOk() { return } self.isActivelyClose = false var request = URLRequest(url: url) request.timeoutInterval = 5 //添加头信息 request.setValue(appContext.accountInfo.vmsCookie, forHTTPHeaderField: "Cookie") let pinner = FoundationSecurity(allowSelfSigned: true) if appContext.loginType == .cloudLocalAccess { //cloudAccess 使用CustomEngine会报错403 webSocket = WebSocket(request: request, certPinner: pinner, useCustomEngine: false) } else if appContext.loginType == .local{ webSocket = WebSocket(request: request, certPinner: pinner) } else if appContext.loginType == .cloud { webSocket = WebSocket(request: request, certPinner: pinner, useCustomEngine: false) } else { webSocket = WebSocket(request: request, certPinner: pinner, useCustomEngine: false) } webSocket?.delegate = self webSocket?.connect() print("WebSocket Request:\nURL:\(String(describing: request.url))\nHeader:\(String(describing: request.allHTTPHeaderFields))\nBody:\(String(describing: request.httpBody))") // 自定义队列,一般不需要设置,默认主队列 //webSocket?.callbackQueue = DispatchQueue(label: "com.vluxe.starscream.myapp") } } /// 发送消息 func sendMessage(_ text: String) { if self.isHaveNet { // 有网络直接发消息 if self.connectType == .connect { //已经连接 self.webSocket?.write(string: text) }else if self.connectType == .reconnecting { // self.sendDataArray.append(text) }else if self.connectType == .disconnect { reConnectSocket() }else{ // self.sendDataArray.append(text) } } else { // 无网络的时候的操作 //1.提示无网络 //2.存储消息 // self.sendDataArray.append(text) //等待来网 guard isActivelyClose else { initNetWorkTestingTimer() return } } } /// 断开链接 func disconnect() { self.isActivelyClose = true self.connectType = .disconnect webSocket?.disconnect() destoryHeartBeat() destoryNetWorkStartTesting() } /// 重新连接 func reConnectSocket() { if !checkIfInfoOk() { return } if self.reConnectCount > 10 { //重连10次 self.reConnectCount = 0; return } //重连10次,每两次间隔5s DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 5) { if self.connectType == .reconnecting { return } /// 连接 self.update() self.connectSocket(nil) self.reConnectCount = self.reConnectCount + 1 } } func reConnectVms() { self.disconnect() if self.reConnectVmsCount > 10 { //重连10次 self.reConnectVmsCount = 0; return } //重连10次,每两次间隔5s DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 5) { if self.connectType == .reconnecting { return } /// 连接 self.update() self.connectSocket(nil) self.reConnectVmsCount = self.reConnectVmsCount + 1 } } // MARK: - 网络监听 func networkNotifation() { //外部最好也传进来一个网络变化的通知 //当断开网络时候,不在进行重新连接 //当网络恢复的时候,重新连接,根据自己业务进行更新. //更新网络状态 isHaveNet = false } // MARK: - 私有方法 /// 初始化心跳 private func initHeartBeat() { if self.heartBeatTimer != nil { return } self.heartBeatTimer = Timer(timeInterval: 1, target: self, selector: #selector(sendHeartBeat), userInfo: nil, repeats: true) RunLoop.current.add(self.heartBeatTimer!, forMode: RunLoop.Mode.common) } private func initNetWorkTestingTimer() { if self.netWorkTimer != nil { return } self.netWorkTimer = Timer(timeInterval: 5, target: self, selector: #selector(noNetWorkStartTesting), userInfo: nil, repeats: true) RunLoop.current.add(self.netWorkTimer!, forMode: RunLoop.Mode.common) } /// 心跳 @objc private func sendHeartBeat() { if self.isConnected { // let text = "ping的内容,服务器商定" let text = "h" if let data = text.data(using: String.Encoding.utf8) { webSocket?.write(ping: data) } // 我在网上查阅资料显示,也可以使用webSocket?.write(string: "") // 即: webSocket?.write(string: text) // write方法中pingtext是一样的,只是传入的枚举不一样,可以参考源代码 }else{ // 发现没有连接,根据需求做判断 } } /// 没有网络的时候开始定时 -- 用于网络检测 @objc private func noNetWorkStartTesting() { //有网络 if isHaveNet {//这里可以根据业务需要修改 //1.关闭网络监测定时器 destoryNetWorkStartTesting() //2.重新连接 reConnectSocket() } } //关闭心跳定时器 private func destoryHeartBeat() { self.heartBeatTimer?.invalidate() self.heartBeatTimer = nil } //关闭网络监测定时器 private func destoryNetWorkStartTesting() { self.netWorkTimer?.invalidate() self.netWorkTimer = nil } private func sendConnectRequest() { guard let connectJson = try? JSONSerialization.data(withJSONObject: self.connectDic, options: .prettyPrinted) else { //转换失败 // print("starcream: connect JSON tranlate failed") return } let connectStr = String(data: connectJson, encoding: .utf8) ?? "" self.webSocket?.write(string:connectStr) } private func sendSubscribeRequest() { guard let subscribeJson = try? JSONSerialization.data(withJSONObject: self.subscribeDic, options: .prettyPrinted) else { //转换失败 // print("starcream: subscribe JSON tranlate failed") return } let subscribeStr = String(data: subscribeJson, encoding: .utf8) ?? "" self.webSocket?.write(string: subscribeStr) if appContext.loginType == .cloud { update(cloudEventType: .siteChange) guard let subscribeJson2 = try? JSONSerialization.data(withJSONObject: self.subscribeDic, options: .prettyPrinted) else { //转换失败 return } //cloudVMS 需要订阅角色,站点改变两个subscribe,第一次订阅的是角色,这里订阅站点 let subscribeStr2 = String(data: subscribeJson2, encoding: .utf8) ?? "" self.webSocket?.write(string: subscribeStr2) } } private func sendDeviceStatusSubscribeRequest() { guard let subscribeJson = try? JSONSerialization.data(withJSONObject: self.deviceStatusSubscribeDic, options: .prettyPrinted) else { //转换失败 print("starcream: subscribe JSON tranlate failed") return } let subscribeStr = String(data: subscribeJson, encoding: .utf8) ?? "" // print("dxy::Device Status \(subscribeStr)") self.webSocket?.write(string: subscribeStr) if appContext.loginType == .cloud { update(cloudEventType: .siteChange) guard let subscribeJson2 = try? JSONSerialization.data(withJSONObject: self.deviceStatusSubscribeDic, options: .prettyPrinted) else { //转换失败 return } //cloudVMS 需要订阅角色,站点改变两个subscribe,第一次订阅的是角色,这里订阅站点 let subscribeStr2 = String(data: subscribeJson2, encoding: .utf8) ?? "" self.webSocket?.write(string: subscribeStr2) } } private func sendDeviceShareSubscribeRequest() { guard let subscribeJson = try? JSONSerialization.data(withJSONObject: self.deviceShareSubscribeDic, options: .prettyPrinted) else { //转换失败 print("starcream: subscribe JSON tranlate failed") return } let subscribeStr = String(data: subscribeJson, encoding: .utf8) ?? "" // print("dxy::Device Share \(subscribeStr)") self.webSocket?.write(string: subscribeStr) if appContext.loginType == .cloud { update(cloudEventType: .siteChange) guard let subscribeJson2 = try? JSONSerialization.data(withJSONObject: self.deviceShareSubscribeDic, options: .prettyPrinted) else { //转换失败 return } //cloudVMS 需要订阅角色,站点改变两个subscribe,第一次订阅的是角色,这里订阅站点 let subscribeStr2 = String(data: subscribeJson2, encoding: .utf8) ?? "" self.webSocket?.write(string: subscribeStr2) } } private func addMessageToList(message: TPSSMessage) { if !self.receiveMessageList.contains(message) { self.receiveMessageList.append(message) } } } extension WebSocketManager: Starscream.WebSocketDelegate{ func didReceive(event: WebSocketEvent, client: Starscream.WebSocketClient) { switch event { // case .connected(let headers): case .connected(_): isConnected = true delegate?.webSocketManagerDidConnect(manager: self) // _ = "连接成功,在这里处理成功后的逻辑,比如将发送失败的消息重新发送等等..." // print("dxy::websocket is connected: \(headers)") DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.5, execute: { self.initHeartBeat() self.sendConnectRequest() }) break case .disconnected(let reason, let code): isConnected = false let error = NSError(domain: reason, code: Int(code), userInfo: nil) as Error delegate?.webSocketManagerDidDisconnect(manager: self, error: error) self.connectType = .disconnect if self.isActivelyClose { self.connectType = .closed } else { self.connectType = .disconnect destoryHeartBeat() //断开心跳定时器 if self.isHaveNet { reConnectSocket() //重新连接 } else { initNetWorkTestingTimer() } } // print("dxy::websocket is disconnected: \(reason) with code: \(code)") break case .text(let string): delegate?.webSocketManagerDidReceiveMessage(manager: self, text: string) let dic = ["text" : string] // print("dxy::\(dic)") let jsonData = string.data(using: String.Encoding.utf8, allowLossyConversion: false) ?? Data() guard let dict = try? JSONSerialization.jsonObject(with: jsonData, options: [JSONSerialization.ReadingOptions.init(rawValue: 0)]) as? [String:AnyObject] else { //消息获取失败 return } if (string.contains("errorCode")) { //请求部分 if let errorcode = dict["errorCode"] as? Int, let method = dict["method"] as? String { //请求 if errorcode == 0 { //请求成功 if "connect" == method{ //链接请求成功 // print("dxy::链接请求成功") #if APP_VIGI if appContext.loginType == .cloudLocalAccess || appContext.loginType == .local{ //VIGI cloudVMS无需订阅subscribe self.sendSubscribeRequest() } #else // self.sendSubscribeRequest() self.sendDeviceStatusSubscribeRequest() self.sendDeviceShareSubscribeRequest() #endif } else if "subscribe" == method { //订阅返回成功 // print("dxy::订阅返回成功") } } else { //接口请求失败,重新连接 self.reConnectVms() } } else { //请求失败 self.reConnectVms() } } else if let dictTopic = dict["topic"] as? String { //消息内容 let components = dictTopic.components(separatedBy: "/") let lastComponent = components.last switch lastComponent { case "role": if let data = dict["data"] as? [String:AnyObject], let orgRole = data["orgRole"] as? String { NotificationCenter.default.post(name: NSNotification.Name(rawValue: "webSocketManagerDidReceiveRoleChange"), object: orgRole) } case "site-permission": if !isNotificationPost { isNotificationPost = true DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) { [weak self] in // 确保self仍然存在(避免循环引用) guard let self = self else { return } // 发送通知 NotificationCenter.default.post(name: NSNotification.Name(rawValue: "webSocketManagerDidReceiveSitePrivilegeChange"), object: dictTopic) // 重置标志,表示通知已经发送 self.isNotificationPost = false } } case "device-message-inform": if let messageArray = dict["data"] as? Array<[AnyHashable: Any]> { var pushEventList:[TPSSPushEvent] = [] for messageDic in messageArray { let message = TPSSMessage(siteMessageWith: messageDic, isCloud: false) self.addMessageToList(message: message) let pushEvent = TPSSPushEvent(vmsPushUserInfo: messageDic, isCloudVms: false) pushEventList.append(pushEvent) } NotificationCenter.default.post(name: TPGuardNewEventMessageNotification, object: pushEventList) } case "share-message-notify": if let messageDictList = dict["data"] as? [[String: Any]] { for messageDict in messageDictList { let shareMessage = TPGuardDeviceShareMessage() shareMessage.messageID = messageDict["msgId"] as? String ?? "" let msgSubTypes = messageDict["msgSubType"] as? [Int64] ?? [] shareMessage.messageType = TPGuardMessageType(rawValue: (messageDict["msgType"] as? Int ?? 5)) ?? .deviceShareIPC shareMessage.msgSubType = msgSubTypes.first ?? 0 shareMessage.time = TimeInterval((messageDict["time"] as? Int64 ?? 0) / 1000) shareMessage.createTime = TimeInterval((messageDict["createTime"] as? Int64 ?? 0) / 1000) shareMessage.duration = TimeInterval((messageDict["duration"] as? Int64 ?? 0) / 1000) shareMessage.state = messageDict["state"] as? Bool ?? false shareMessage.deviceModel = messageDict["deviceModel"] as? String ?? "" shareMessage.deviceName = messageDict["deviceName"] as? String ?? "" shareMessage.deviceType = messageDict["deviceType"] as? String ?? "" shareMessage.deviceId = messageDict["deviceId"] as? String ?? "" shareMessage.shareId = messageDict["shareId"] as? String ?? "" shareMessage.sharerUserName = messageDict["sharerUserName"] as? String ?? "" shareMessage.sharerNickName = messageDict["sharerNickName"] as? String ?? "" shareMessage.content = messageDict["content"] as? String ?? "" shareMessage.expiry = TimeInterval((messageDict["expiry"] as? Int64 ?? 0) / 1000) if msgSubTypes.contains(2) { let device = appContext.deviceForDeviceList(withPcDeviceID: shareMessage.deviceId, of: .remote) var userInfo: [String: Any] = ["deviceID": device?.identifier ?? 0] if shareMessage.messageType == .deviceShareNVR { userInfo["channels"] = [-1] } else if shareMessage.messageType == .deviceShareNVR { userInfo["channels"] = messageDict["channels"] as? [Int] } else { userInfo["channels"] = [-1] } NotificationCenter.default.post(name: TPGuardPlayerStopPlayNotification, object: nil, userInfo: userInfo) } else { TPGuardMessageManager.shard.addDeviceShareMessage(newMessage: shareMessage) } } } case "device-info": if let deviceDict = dict["data"] as? [String: Any] { if let deviceID = deviceDict["deviceId"] as? String, let accountID = deviceDict["accountId"] as? String { if accountID == appContext.accountInfo.pcAccountId { guard let deviceIDNumber = TPSSDeviceIdentifier(deviceID) else { return } var needDelete = false var needReloadFromClound = false if let isDeleted = deviceDict["isDeleted"] as? Bool { if isDeleted == true { needDelete = true } } if let isBind = deviceDict["isBind"] as? Bool { if isBind == false { needDelete = true } } if needDelete { appContext.setDeviceInvalidByManuallyforDevice(deviceIDNumber, listType: .remote) } else { if let deviceStatus = deviceDict["status"] as? Int { if deviceStatus == 0 { appContext.setDeviceStateByManually(false, forDevice: deviceIDNumber, listType: .remote) } else if deviceStatus == 1 { appContext.setDeviceStateByManually(true, forDevice: deviceIDNumber, listType: .remote) } else if deviceStatus == 3 { appContext.setFactoryDefaultByManually(true, forDevice: deviceIDNumber, listType: .remote) } else { // appContext.newRequestLoadDeviceList() needReloadFromClound = true } } if let toDeleteChannelList = deviceDict["shareChannelList"] as? [Int] { for channel in toDeleteChannelList { if channel == -1 { appContext.setDeviceInvalidByManuallyforDevice(deviceIDNumber, listType: .remote) } else { appContext.deleteShareChannel(byManuallyforDevice: deviceIDNumber, channelID: channel, listType: .remote) } } } } if needReloadFromClound { NotificationCenter.default.post(name: TPGuardDeviceListNeedUpdateNotification, object: nil) } else { NotificationCenter.default.post(name: TPGuardDeviceListDidUpdateNotification, object: nil) } } } } default: break } } // print("dxy::Received text3: \(string)") break // case .binary(let data): case .binary(_): // print("dxy::Received data4: \(data.count)") break case .ping(_): // print("dxy::ping") break case .pong(_): // print("dxy::pong") break case .viabilityChanged(_): break case .reconnectSuggested(_): break case .cancelled: isConnected = false case .error(let error): isConnected = false if retryCount < 5 { retryCount += 1 update() connectSocket(nil) } handleError(error) case .peerClosed: isConnected = false break } } // custom func handleError(_ error: Error?) { // if let e = error as? WSError { // print("dxy::websocket encountered an error: \(e.message) \n") // } else if let e = error { // print("dxy::websocket encountered an error: \(e.localizedDescription)\n") // } else { // print("dxy::websocket encountered an error\n") // } } } 在这个类中,如何订阅这些类型的topic
09-21
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值