socket.io-client-swift icon indicating copy to clipboard operation
socket.io-client-swift copied to clipboard

Add completion handler to SocketIOClient connect, disconnect, and emit methods

Open Rspoon3 opened this issue 4 years ago • 0 comments

Currently you have to use on(clientEvent: .connect), on(clientEvent: .disconnect), and socket.on(clientEvent: .error) completion handlers to know when you have connected, disconnected, or have an error. The problem with this is that you only have one access point to when these events happen, which makes doing individual actions difficult. A better approach would be to have completion handlers on the connect, disconnect and emit methods themselves.

A use case where this would be useful is if you're trying to emit a message while disconnected. Here is a current implantation involving dispatchGroups to notify you that the connection has been re-established and you should resend the data.

class SocketIOManager: ObservableObject {
    static let shared = SocketIOManager()
    private let manager: SocketManager
    private let socket: SocketIOClient
    
    let connectionGroup = DispatchGroup()
    
    private init() {
        let config: SocketIOClientConfiguration = [.log(false), .compress, .reconnects(true)]
        let url = URL(string: "http://localhost:3000")!
        
        manager = SocketManager(socketURL: url, config: config)
        socket = manager.defaultSocket
        
        establishConnection()
    }
    
    
    private func establishConnection() {
        socket.on(clientEvent: .connect) { [self]data, ack in
            print("socket connected")
            connectionGroup.leave()
        }
        
        
        socket.on(clientEvent: .disconnect){_,_ in
            print("disconnected")
        }
        
        
        socket.on(clientEvent: .error) {data, ack in
            let errorString = (data[0] as? String)
            print("socket error: \(errorString ?? "N/A")")
        }
        
        connectionGroup.enter()
        socket.connect()
    }
    
    func sendLocation(lat: Double, long: Double) {
        if socket.status == .connected{
            socket.emit("locationUpdate", lat, long){
                print("Sent via socketIO...", lat, long)
            }
        } else {
            print("Reconnecting")
            connectionGroup.enter()
            socket.connect()
            
            connectionGroup.notify(queue: .global(qos: .background)){
                self.socket.emit("locationUpdate", lat, long, "interpro_2951"){
                    print("Sent via socketIO...", lat, long)
                }
            }
        }
    }
}

With proper completion handlers this could be simplified.

class SocketIOManager: ObservableObject {
    static let shared = SocketIOManager()
    private let manager: SocketManager
    private let socket: SocketIOClient
    
    let connectionGroup = DispatchGroup()
    
    private init() {
        let config: SocketIOClientConfiguration = [.log(false), .compress, .reconnects(true)]
        let url = URL(string: "http://localhost:3000")!
        
        manager = SocketManager(socketURL: url, config: config)
        socket = manager.defaultSocket
        
        establishInitialConnection()
    }
    
    
    private func establishInitialConnection() {
        socket.connect() { result in
            switch result{
            case .success:
                print("Socket initial connection successful!")
            case .failure(let error):
                print("Socket connection error: \(error.localizedDescription)")
            }
        }
    }
    
    private func disconnected() {
        socket.disconnect() { result in
            switch result{
            case .success:
                print("Socket disconnected")
            case .failure(let error):
                print("Socket disconnection error: \(error.localizedDescription)")
            }
        }
    }
    
    func sendLocation(lat: Double, long: Double) {
        socket.emit("locationUpdate", lat, long){ result in
            switch result{
            case .success:
                print("Emitted via socketIO...", lat, long)
            case .failure(let error): //Tried emitting when not connected
                print("Emitting error: \(error.localizedDescription)")
                
                if socket.status = .disconnected{
                    print("Trying to reestablish connection and try again...")
                    
                    socket.connect() { result in
                        switch result{
                        case .success:
                            sendLocation(lat: lat, long: long)
                        case .failure(let error):
                            print("Could not re-establish connection: \(error.localizedDescription)")
                        }
                    }
                }
            }
        }
    }
}

Rspoon3 avatar Jul 21 '21 17:07 Rspoon3