// // NetworkServiceApiWebSockets.swift // Wallet // // Created by Saveliy Stavitsky on 1/15/21. // Copyright © 2021 AM. All rights reserved. // import Foundation import Starscream extension Notification.Name { static let socketDidConnect = Self("Network.Service.WebSockets.socketDidConnect") static let socketDidUpdateValue = Self("Network.Service.WebSockets.socketDidUpdateValue") static let socketDidDisconnect = Self("Network.Service.WebSockets.socketDidDisconnect") } extension Network.Service { class WebSockets: Common.Service.Provider { private var timer: Timer? private var reconectTimer: Timer? private var collection = [String:Subscription]() init() { timer = delayed(45, repeats: true) { self.update() } reconectTimer = delayed(1, repeats: true) { self.reconect() } } } } extension Network.Service.WebSockets { func open(subscription: String, id: String) { collection[id] = Subscription(id: id, subscription: subscription) } func contains(id: String) -> Bool { collection[id] != nil } func remove(id: String) { collection[id] = nil } func remove(idPrefix prefix: String) { let toRemoveIds = collection.filter({ $0.key.hasPrefix(prefix) }).map({ $0.key }) for id in toRemoveIds { collection[id] = nil } } func remove(idSuffix suffix: String) { let toRemoveIds = collection.filter({ $0.key.hasSuffix(suffix) }).map({ $0.key }) for id in toRemoveIds { collection[id] = nil } } func removeAll() { collection = [:] } } extension Network.Service.WebSockets { private func update() { for subscription in collection { if !subscription.value.socket.isConnected { subscription.value.socket.connect() } else { subscription.value.socket.write(ping: Data()) } } } private func reconect() { for subscription in collection { if !subscription.value.socket.isConnected { subscription.value.socket.connect() } } } } extension Network.Service.WebSockets { fileprivate class Subscription { let socket: WebSocket let id: String let subscription: String? deinit { socket.disconnect() } init(id: String, subscription: String?) { self.id = id self.subscription = subscription var request = URLRequest(url: URL(string: ApplicationEnvironment.shared().current.paycash.webSocket)!) request.timeoutInterval = 5 socket = WebSocket(request: request) socket.delegate = self socket.connect() } } } extension Network.Service.WebSockets.Subscription: WebSocketDelegate { func websocketDidConnect(socket: WebSocketClient) { if let subscription = subscription { socket.write(string: subscription) } Notification.post(name: .socketDidConnect, userInfo: ["id": id]) } func websocketDidDisconnect(socket: WebSocketClient, error: Error?) { socket.connect() Notification.post(name: .socketDidDisconnect, userInfo: ["id": id]) } func websocketDidReceiveMessage(socket: WebSocketClient, text: String) { Notification.post(name: .socketDidUpdateValue, userInfo: ["id": id, "data": text]) } func websocketDidReceiveData(socket: WebSocketClient, data: Data) { Notification.post(name: .socketDidUpdateValue, userInfo: ["id": id, "data": String(data: data, encoding: .utf8) ?? ""]) } }