Add completion handler to SocketIOClient connect, disconnect, and emit methods
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)")
}
}
}
}
}
}
}