diff --git a/Socket.IO-Client-Swift.xcodeproj/xcshareddata/xcschemes/SocketIO-iOS.xcscheme b/Socket.IO-Client-Swift.xcodeproj/xcshareddata/xcschemes/SocketIO-iOS.xcscheme index c583c9a..74ad40a 100644 --- a/Socket.IO-Client-Swift.xcodeproj/xcshareddata/xcschemes/SocketIO-iOS.xcscheme +++ b/Socket.IO-Client-Swift.xcodeproj/xcshareddata/xcschemes/SocketIO-iOS.xcscheme @@ -40,8 +40,8 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - shouldUseLaunchSchemeArgsEnv = "YES" - codeCoverageEnabled = "YES"> + language = "" + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -70,6 +70,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/Source/SocketIO/Client/SocketIOClient.swift b/Source/SocketIO/Client/SocketIOClient.swift index c70685b..7ff919a 100644 --- a/Source/SocketIO/Client/SocketIOClient.swift +++ b/Source/SocketIO/Client/SocketIOClient.swift @@ -33,6 +33,8 @@ import Foundation open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, SocketParsable { // MARK: Properties + private static let logType = "SocketIOClient" + /// The engine for this client. public private(set) var engine: SocketEngineSpec? @@ -87,8 +89,6 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So private(set) var currentAck = -1 private(set) var reconnectAttempts = -1 - private let logType = "SocketIOClient" - private var anyHandler: ((SocketAnyEvent) -> ())? private var currentReconnectAttempt = 0 private var handlers = [SocketEventHandler]() @@ -146,16 +146,19 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So } deinit { - DefaultSocketLogger.Logger.log("Client is being released", type: logType) + DefaultSocketLogger.Logger.log("Client is being released", type: SocketIOClient.logType) engine?.disconnect(reason: "Client Deinit") } // MARK: Methods private func addEngine() { - DefaultSocketLogger.Logger.log("Adding engine", type: logType, args: "") + DefaultSocketLogger.Logger.log("Adding engine", type: SocketIOClient.logType, args: "") + + engine?.engineQueue.sync { + self.engine?.client = nil + } - engine?.client = nil engine = SocketEngine(client: self, url: socketURL, config: config) } @@ -173,7 +176,8 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So assert(timeoutAfter >= 0, "Invalid timeout: \(timeoutAfter)") guard status != .connected else { - DefaultSocketLogger.Logger.log("Tried connecting on an already connected socket", type: logType) + DefaultSocketLogger.Logger.log("Tried connecting on an already connected socket", + type: SocketIOClient.logType) return } @@ -204,7 +208,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So } func didConnect(toNamespace namespace: String) { - DefaultSocketLogger.Logger.log("Socket connected", type: logType) + DefaultSocketLogger.Logger.log("Socket connected", type: SocketIOClient.logType) status = .connected @@ -214,7 +218,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So func didDisconnect(reason: String) { guard status != .disconnected else { return } - DefaultSocketLogger.Logger.log("Disconnected: %@", type: logType, args: reason) + DefaultSocketLogger.Logger.log("Disconnected: %@", type: SocketIOClient.logType, args: reason) reconnecting = false status = .disconnected @@ -226,7 +230,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So /// Disconnects the socket. open func disconnect() { - DefaultSocketLogger.Logger.log("Closing socket", type: logType) + DefaultSocketLogger.Logger.log("Closing socket", type: SocketIOClient.logType) didDisconnect(reason: "Disconnect") } @@ -243,7 +247,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So try emit(event, with: items.map({ try $0.socketRepresentation() })) } catch let err { DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)", - type: logType) + type: SocketIOClient.logType) handleClientEvent(.error, data: [event, items, err]) } @@ -286,7 +290,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So return emitWithAck(event, with: try items.map({ try $0.socketRepresentation() })) } catch let err { DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)", - type: logType) + type: SocketIOClient.logType) handleClientEvent(.error, data: [event, items, err]) @@ -323,7 +327,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So let packet = SocketPacket.packetFromEmit(data, id: ack ?? -1, nsp: nsp, ack: false) let str = packet.packetString - DefaultSocketLogger.Logger.log("Emitting: %@", type: logType, args: str) + DefaultSocketLogger.Logger.log("Emitting: %@", type: SocketIOClient.logType, args: str) engine?.send(str, withData: packet.binary) } @@ -335,7 +339,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So let packet = SocketPacket.packetFromEmit(items, id: ack, nsp: nsp, ack: true) let str = packet.packetString - DefaultSocketLogger.Logger.log("Emitting Ack: %@", type: logType, args: str) + DefaultSocketLogger.Logger.log("Emitting Ack: %@", type: SocketIOClient.logType, args: str) engine?.send(str, withData: packet.binary) } @@ -374,7 +378,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So } private func _engineDidError(reason: String) { - DefaultSocketLogger.Logger.error("%@", type: logType, args: reason) + DefaultSocketLogger.Logger.error("%@", type: SocketIOClient.logType, args: reason) handleClientEvent(.error, data: [reason]) } @@ -383,14 +387,14 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So /// /// - parameter reason: The reason the engine opened. open func engineDidOpen(reason: String) { - DefaultSocketLogger.Logger.log(reason, type: "SocketEngineClient") + DefaultSocketLogger.Logger.log(reason, type: SocketIOClient.logType) } // Called when the socket gets an ack for something it sent func handleAck(_ ack: Int, data: [Any]) { guard status == .connected else { return } - DefaultSocketLogger.Logger.log("Handling ack: %@ with data: %@", type: logType, args: ack, data) + DefaultSocketLogger.Logger.log("Handling ack: %@ with data: %@", type: SocketIOClient.logType, args: ack, data) ackHandlers.executeAck(ack, with: data, onQueue: handleQueue) } @@ -404,7 +408,8 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So open func handleEvent(_ event: String, data: [Any], isInternalMessage: Bool, withAck ack: Int = -1) { guard status == .connected || isInternalMessage else { return } - DefaultSocketLogger.Logger.log("Handling event: %@ with data: %@", type: logType, args: event, data) + DefaultSocketLogger.Logger.log("Handling event: %@ with data: %@", type: SocketIOClient.logType, + args: event, data) anyHandler?(SocketAnyEvent(event: event, items: data)) @@ -434,7 +439,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So nsp = namespace if nsp != "/" { - DefaultSocketLogger.Logger.log("Joining namespace", type: logType) + DefaultSocketLogger.Logger.log("Joining namespace", type: SocketIOClient.logType) engine?.send("0\(nsp)", withData: []) } } @@ -454,7 +459,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So /// /// - parameter event: The event to remove handlers for. open func off(_ event: String) { - DefaultSocketLogger.Logger.log("Removing handler for event: %@", type: logType, args: event) + DefaultSocketLogger.Logger.log("Removing handler for event: %@", type: SocketIOClient.logType, args: event) handlers = handlers.filter({ $0.event != event }) } @@ -465,7 +470,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So /// /// - parameter id: The UUID of the handler you wish to remove. open func off(id: UUID) { - DefaultSocketLogger.Logger.log("Removing handler with id: %@", type: logType, args: id) + DefaultSocketLogger.Logger.log("Removing handler with id: %@", type: SocketIOClient.logType, args: id) handlers = handlers.filter({ $0.id != id }) } @@ -477,7 +482,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So /// - returns: A unique id for the handler that can be used to remove it. @discardableResult open func on(_ event: String, callback: @escaping NormalCallback) -> UUID { - DefaultSocketLogger.Logger.log("Adding handler for event: %@", type: logType, args: event) + DefaultSocketLogger.Logger.log("Adding handler for event: %@", type: SocketIOClient.logType, args: event) let handler = SocketEventHandler(event: event, id: UUID(), callback: callback) handlers.append(handler) @@ -500,7 +505,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So /// - returns: A unique id for the handler that can be used to remove it. @discardableResult open func on(clientEvent event: SocketClientEvent, callback: @escaping NormalCallback) -> UUID { - DefaultSocketLogger.Logger.log("Adding handler for event: %@", type: logType, args: event) + DefaultSocketLogger.Logger.log("Adding handler for event: %@", type: SocketIOClient.logType, args: event) let handler = SocketEventHandler(event: event.rawValue, id: UUID(), callback: callback) handlers.append(handler) @@ -525,7 +530,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So /// - returns: A unique id for the handler that can be used to remove it. @discardableResult open func once(_ event: String, callback: @escaping NormalCallback) -> UUID { - DefaultSocketLogger.Logger.log("Adding once handler for event: %@", type: logType, args: event) + DefaultSocketLogger.Logger.log("Adding once handler for event: %@", type: SocketIOClient.logType, args: event) let id = UUID() @@ -551,7 +556,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So /// /// - parameter msg: The message that needs parsing. public func parseEngineMessage(_ msg: String) { - DefaultSocketLogger.Logger.log("Should parse message: %@", type: "SocketIOClient", args: msg) + DefaultSocketLogger.Logger.log("Should parse message: %@", type: SocketIOClient.logType, args: msg) handleQueue.async { self.parseSocketMessage(msg) } } @@ -581,7 +586,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So private func tryReconnect(reason: String) { guard reconnecting else { return } - DefaultSocketLogger.Logger.log("Starting reconnect", type: logType) + DefaultSocketLogger.Logger.log("Starting reconnect", type: SocketIOClient.logType) handleClientEvent(.reconnect, data: [reason]) _tryReconnect() @@ -594,7 +599,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So return didDisconnect(reason: "Reconnect Failed") } - DefaultSocketLogger.Logger.log("Trying to reconnect", type: logType) + DefaultSocketLogger.Logger.log("Trying to reconnect", type: SocketIOClient.logType) handleClientEvent(.reconnectAttempt, data: [(reconnectAttempts - currentReconnectAttempt)]) currentReconnectAttempt += 1 diff --git a/Source/SocketIO/Engine/SocketEngine.swift b/Source/SocketIO/Engine/SocketEngine.swift index 3d93979..9995cb9 100644 --- a/Source/SocketIO/Engine/SocketEngine.swift +++ b/Source/SocketIO/Engine/SocketEngine.swift @@ -31,6 +31,8 @@ import StarscreamSocketIO public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, SocketEngineWebsocket { // MARK: Properties + private static let logType = "SocketEngine" + /// The queue that all engine actions take place on. public let engineQueue = DispatchQueue(label: "com.socketio.engineHandleQueue") @@ -119,13 +121,12 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll private weak var sessionDelegate: URLSessionDelegate? - private let logType = "SocketEngine" private let url: URL - private var pingInterval: Double? - private var pingTimeout = 0.0 { + private var pingInterval: Int? + private var pingTimeout = 0 { didSet { - pongsMissedMax = Int(pingTimeout / (pingInterval ?? 25)) + pongsMissedMax = Int(pingTimeout / (pingInterval ?? 25000)) } } @@ -196,7 +197,7 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll } deinit { - DefaultSocketLogger.Logger.log("Engine is being released", type: logType) + DefaultSocketLogger.Logger.log("Engine is being released", type: SocketEngine.logType) closed = true stopPolling() } @@ -249,35 +250,26 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll private func _connect() { if connected { - DefaultSocketLogger.Logger.error("Engine tried opening while connected. Assuming this was a reconnect", type: logType) + DefaultSocketLogger.Logger.error("Engine tried opening while connected. Assuming this was a reconnect", + type: SocketEngine.logType) disconnect(reason: "reconnect") } - DefaultSocketLogger.Logger.log("Starting engine. Server: %@", type: logType, args: url) - DefaultSocketLogger.Logger.log("Handshaking", type: logType) + DefaultSocketLogger.Logger.log("Starting engine. Server: %@", type: SocketEngine.logType, args: url) + DefaultSocketLogger.Logger.log("Handshaking", type: SocketEngine.logType) resetEngine() if forceWebsockets { polling = false websocket = true - createWebsocketAndConnect() + createWebSocketAndConnect() return } var reqPolling = URLRequest(url: urlPolling, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 60.0) - if cookies != nil { - let headers = HTTPCookie.requestHeaderFields(with: cookies!) - reqPolling.allHTTPHeaderFields = headers - } - - if let extraHeaders = extraHeaders { - for (headerName, value) in extraHeaders { - reqPolling.setValue(value, forHTTPHeaderField: headerName) - } - } - + addHeaders(to: &reqPolling) doLongPoll(for: reqPolling) } @@ -301,9 +293,9 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll urlWebSocket.scheme = "ws" } - if connectParams != nil { - for (key, value) in connectParams! { - let keyEsc = key.urlEncode()! + if let connectParams = self.connectParams { + for (key, value) in connectParams { + let keyEsc = key.urlEncode()! let valueEsc = "\(value)".urlEncode()! queryString += "&\(keyEsc)=\(valueEsc)" @@ -316,9 +308,9 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll return (urlPolling.url!, urlWebSocket.url!) } - private func createWebsocketAndConnect() { - ws?.delegate = nil - ws = WebSocket(url: urlWebSocketWithSid as URL) + private func createWebSocketAndConnect() { + ws?.delegate = nil // TODO this seems a bit defensive, is this really needed? + ws = WebSocket(url: urlWebSocketWithSid) if cookies != nil { let headers = HTTPCookie.requestHeaderFields(with: cookies!) @@ -344,7 +336,7 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll /// Called when an error happens during execution. Causes a disconnection. public func didError(reason: String) { - DefaultSocketLogger.Logger.error("%@", type: logType, args: reason) + DefaultSocketLogger.Logger.error("%@", type: SocketEngine.logType, args: reason) client?.engineDidError(reason: reason) disconnect(reason: reason) } @@ -361,7 +353,7 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll private func _disconnect(reason: String) { guard connected else { return closeOutEngine(reason: reason) } - DefaultSocketLogger.Logger.log("Engine is being closed.", type: logType) + DefaultSocketLogger.Logger.log("Engine is being closed.", type: SocketEngine.logType) if closed { return closeOutEngine(reason: reason) @@ -391,7 +383,7 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll public func doFastUpgrade() { if waitingForPoll { DefaultSocketLogger.Logger.error("Outstanding poll when switched to WebSockets," + - "we'll probably disconnect soon. You should report this.", type: logType) + "we'll probably disconnect soon. You should report this.", type: SocketEngine.logType) } sendWebSocketMessage("", withType: .upgrade, withData: []) @@ -403,7 +395,7 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll } private func flushProbeWait() { - DefaultSocketLogger.Logger.log("Flushing probe wait", type: logType) + DefaultSocketLogger.Logger.log("Flushing probe wait", type: SocketEngine.logType) for waiter in probeWait { write(waiter.msg, withType: waiter.type, withData: waiter.data) @@ -467,13 +459,13 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll upgradeWs = false } - if let pingInterval = json["pingInterval"] as? Double, let pingTimeout = json["pingTimeout"] as? Double { - self.pingInterval = pingInterval / 1000.0 - self.pingTimeout = pingTimeout / 1000.0 + if let pingInterval = json["pingInterval"] as? Int, let pingTimeout = json["pingTimeout"] as? Int { + self.pingInterval = pingInterval + self.pingTimeout = pingTimeout } if !forcePolling && !forceWebsockets && upgradeWs { - createWebsocketAndConnect() + createWebSocketAndConnect() } sendPing() @@ -498,7 +490,7 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll /// /// - parameter data: The data to parse. public func parseEngineData(_ data: Data) { - DefaultSocketLogger.Logger.log("Got binary data: %@", type: "SocketEngine", args: data) + DefaultSocketLogger.Logger.log("Got binary data: %@", type: SocketEngine.logType, args: data) client?.parseEngineBinaryData(data.subdata(in: 1.. pongsMissedMax { @@ -567,18 +559,18 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll return } - guard let pingInterval = pingInterval else { return } - pongsMissed += 1 write("", withType: .ping, withData: []) - engineQueue.asyncAfter(deadline: DispatchTime.now() + Double(pingInterval)) {[weak self] in self?.sendPing() } + engineQueue.asyncAfter(deadline: DispatchTime.now() + .milliseconds(pingInterval)) {[weak self] in + self?.sendPing() + } } // Moves from long-polling to websockets private func upgradeTransport() { if ws?.isConnected ?? false { - DefaultSocketLogger.Logger.log("Upgrading transport to WebSockets", type: logType) + DefaultSocketLogger.Logger.log("Upgrading transport to WebSockets", type: SocketEngine.logType) fastUpgrade = true sendPollMessage("", withType: .noop, withData: []) @@ -597,11 +589,11 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll if self.websocket { DefaultSocketLogger.Logger.log("Writing ws: %@ has data: %@", - type: self.logType, args: msg, data.count != 0) + type: SocketEngine.logType, args: msg, data.count != 0) self.sendWebSocketMessage(msg, withType: type, withData: data) } else if !self.probing { DefaultSocketLogger.Logger.log("Writing poll: %@ has data: %@", - type: self.logType, args: msg, data.count != 0) + type: SocketEngine.logType, args: msg, data.count != 0) self.sendPollMessage(msg, withType: type, withData: data) } else { self.probeWait.append((msg, type, data)) diff --git a/Source/SocketIO/Engine/SocketEnginePollable.swift b/Source/SocketIO/Engine/SocketEnginePollable.swift index e3e9248..89c7dff 100644 --- a/Source/SocketIO/Engine/SocketEnginePollable.swift +++ b/Source/SocketIO/Engine/SocketEnginePollable.swift @@ -71,19 +71,6 @@ public protocol SocketEnginePollable : SocketEngineSpec { // Default polling methods extension SocketEnginePollable { - private func addHeaders(to req: inout URLRequest) { - if cookies != nil { - let headers = HTTPCookie.requestHeaderFields(with: cookies!) - req.allHTTPHeaderFields = headers - } - - if extraHeaders != nil { - for (headerName, value) in extraHeaders! { - req.setValue(value, forHTTPHeaderField: headerName) - } - } - } - func createRequestForPostWithPostWait() -> URLRequest { defer { postWait.removeAll(keepingCapacity: true) } diff --git a/Source/SocketIO/Engine/SocketEngineSpec.swift b/Source/SocketIO/Engine/SocketEngineSpec.swift index ab8f10d..89f068f 100644 --- a/Source/SocketIO/Engine/SocketEngineSpec.swift +++ b/Source/SocketIO/Engine/SocketEngineSpec.swift @@ -29,7 +29,7 @@ import StarscreamSocketIO /// Specifies a SocketEngine. @objc public protocol SocketEngineSpec { /// The client for this engine. - weak var client: SocketEngineClient? { get set } + var client: SocketEngineClient? { get set } /// `true` if this engine is closed. var closed: Bool { get } @@ -147,6 +147,18 @@ extension SocketEngineSpec { return com.url! } + func addHeaders(to req: inout URLRequest) { + if let cookies = cookies { + req.allHTTPHeaderFields = HTTPCookie.requestHeaderFields(with: cookies) + } + + if let extraHeaders = extraHeaders { + for (headerName, value) in extraHeaders { + req.setValue(value, forHTTPHeaderField: headerName) + } + } + } + func createBinaryDataForSend(using data: Data) -> Either { if websocket { var byteArray = [UInt8](repeating: 0x4, count: 1) diff --git a/Usage Docs/FAQ.md b/Usage Docs/FAQ.md index 860d890..1090073 100644 --- a/Usage Docs/FAQ.md +++ b/Usage Docs/FAQ.md @@ -42,3 +42,13 @@ class SocketManager { } ``` + +------ + +Another case where this might happen is if you use namespaces in your socket.io application. + +In the JavaScript client a url that looks like `http://somesocketioserver.com/client` would be done with the `nsp` config. + +```swift +let socket = SocketIOClient(socketURL: URL(string: "http://somesocketioserver.com")!, config: [.nsp("/client")]) +```