From d24e8f83c645fce76650278d369085b19c367b6d Mon Sep 17 00:00:00 2001 From: Erik Little Date: Fri, 30 Mar 2018 09:39:56 -0400 Subject: [PATCH 01/12] Set reconnectAttempts in manager. Fixes #989 --- .travis.yml | 2 +- Package.resolved | 18 +++++++++--------- Source/SocketIO/Manager/SocketManager.swift | 2 ++ Tests/TestSocketIO/SocketMangerTest.swift | 4 +++- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index d9ed958..91243b7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: objective-c xcode_project: Socket.IO-Client-Swift.xcodeproj # path to your xcodeproj folder xcode_scheme: SocketIO-Mac -osx_image: xcode9 +osx_image: xcode9.2 branches: only: - master diff --git a/Package.resolved b/Package.resolved index 3f29cea..88064dd 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,15 +1,6 @@ { "object": { "pins": [ - { - "package": "SSCZLib", - "repositoryURL": "https://github.com/daltoniam/zlib-spm.git", - "state": { - "branch": null, - "revision": "83ac8d719a2f3aa775dbdf116a57f56fb2c49abb", - "version": "1.1.0" - } - }, { "package": "SSCommonCrypto", "repositoryURL": "https://github.com/daltoniam/common-crypto-spm", @@ -27,6 +18,15 @@ "revision": "6cb1c474e09b0a3aa60bcdc7553b570336d6a61a", "version": "3.0.3" } + }, + { + "package": "SSCZLib", + "repositoryURL": "https://github.com/daltoniam/zlib-spm.git", + "state": { + "branch": null, + "revision": "83ac8d719a2f3aa775dbdf116a57f56fb2c49abb", + "version": "1.1.0" + } } ] }, diff --git a/Source/SocketIO/Manager/SocketManager.swift b/Source/SocketIO/Manager/SocketManager.swift index e4fbf7d..c499b1a 100644 --- a/Source/SocketIO/Manager/SocketManager.swift +++ b/Source/SocketIO/Manager/SocketManager.swift @@ -476,6 +476,8 @@ open class SocketManager : NSObject, SocketManagerSpec, SocketParsable, SocketDa self.handleQueue = queue case let .reconnects(reconnects): self.reconnects = reconnects + case let .reconnectAttempts(attempts): + self.reconnectAttempts = attempts case let .reconnectWait(wait): reconnectWait = abs(wait) case let .log(log): diff --git a/Tests/TestSocketIO/SocketMangerTest.swift b/Tests/TestSocketIO/SocketMangerTest.swift index 8b83cf8..22da481 100644 --- a/Tests/TestSocketIO/SocketMangerTest.swift +++ b/Tests/TestSocketIO/SocketMangerTest.swift @@ -79,13 +79,15 @@ class SocketMangerTest : XCTestCase { .handleQueue(queue), .forceNew(true), .reconnects(false), - .reconnectWait(5) + .reconnectWait(5), + .reconnectAttempts(5) ]) XCTAssertEqual(manager.handleQueue, queue) XCTAssertTrue(manager.forceNew) XCTAssertFalse(manager.reconnects) XCTAssertEqual(manager.reconnectWait, 5) + XCTAssertEqual(manager.reconnectAttempts, 5) } func testManagerRemovesSocket() { From 47bcfb1299f488ea95d6b5b9fa34c659935bc5c9 Mon Sep 17 00:00:00 2001 From: Erik Little Date: Fri, 30 Mar 2018 09:51:41 -0400 Subject: [PATCH 02/12] bump version --- CHANGELOG.md | 7 ++++++- Socket.IO-Client-Swift.podspec | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c9bcee..bfaf269 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# v13.1.3 + +- Fix setting reconnectAttempts [#989]((https://github.com/socketio/socket.io-client-swift/issues/989)) + + # v13.1.2 - Fix [#950](https://github.com/socketio/socket.io-client-swift/issues/950) @@ -29,7 +34,7 @@ Checkout out the migration guide in Usage Docs for a more detailed guide on how What's new: --- -- Adds a new `SocketManager` class that multiplexes multiple namespaces through a single engine. +- Adds a new `SocketManager` class that multiplexes multiple namespaces through a single engine. - Adds `.sentPing` and `.gotPong` client events for tracking ping/pongs. - watchOS support. diff --git a/Socket.IO-Client-Swift.podspec b/Socket.IO-Client-Swift.podspec index 4354192..7e07ef7 100644 --- a/Socket.IO-Client-Swift.podspec +++ b/Socket.IO-Client-Swift.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "Socket.IO-Client-Swift" s.module_name = "SocketIO" - s.version = "13.1.2" + s.version = "13.1.3" s.summary = "Socket.IO-client for iOS and OS X" s.description = <<-DESC Socket.IO-client for iOS and OS X. @@ -18,7 +18,7 @@ Pod::Spec.new do |s| s.requires_arc = true s.source = { :git => "https://github.com/socketio/socket.io-client-swift.git", - :tag => 'v13.1.2', + :tag => 'v13.1.3', :submodules => true } s.pod_target_xcconfig = { From 4564aebec19404a03fd761968821444f989ef713 Mon Sep 17 00:00:00 2001 From: Erik Little Date: Fri, 30 Mar 2018 14:16:54 -0400 Subject: [PATCH 03/12] Add way to skip binary inspection. Still a WIP. ACKs still don't have a way to bypass --- .../project.pbxproj | 4 + Source/SocketIO/Ack/SocketAckEmitter.swift | 7 +- Source/SocketIO/Client/SocketBinaryView.swift | 106 ++++++++++++++++++ Source/SocketIO/Client/SocketIOClient.swift | 8 +- Source/SocketIO/Parse/SocketPacket.swift | 12 +- 5 files changed, 127 insertions(+), 10 deletions(-) create mode 100644 Source/SocketIO/Client/SocketBinaryView.swift diff --git a/Socket.IO-Client-Swift.xcodeproj/project.pbxproj b/Socket.IO-Client-Swift.xcodeproj/project.pbxproj index 0157206..c7f9eb4 100644 --- a/Socket.IO-Client-Swift.xcodeproj/project.pbxproj +++ b/Socket.IO-Client-Swift.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 1C6572803D7E252A77A86E5F /* SocketManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C65763817782DFAC67BE05C /* SocketManager.swift */; }; + 1C6573B22DC9423CDFC32F05 /* SocketBinaryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C657533E849FC3E4342C602 /* SocketBinaryView.swift */; }; 1C657FBB3F670261780FD72E /* SocketManagerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C6574AF9687A213814753E4 /* SocketManagerSpec.swift */; }; 1C686BE21F869AFD007D8627 /* SocketIOClientConfigurationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C686BD21F869AF1007D8627 /* SocketIOClientConfigurationTest.swift */; }; 1C686BE31F869AFD007D8627 /* SocketEngineTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C686BD31F869AF1007D8627 /* SocketEngineTest.swift */; }; @@ -61,6 +62,7 @@ /* Begin PBXFileReference section */ 1C6574AF9687A213814753E4 /* SocketManagerSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketManagerSpec.swift; sourceTree = ""; }; + 1C657533E849FC3E4342C602 /* SocketBinaryView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketBinaryView.swift; sourceTree = ""; }; 1C65763817782DFAC67BE05C /* SocketManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketManager.swift; sourceTree = ""; }; 1C686BD21F869AF1007D8627 /* SocketIOClientConfigurationTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketIOClientConfigurationTest.swift; sourceTree = ""; }; 1C686BD31F869AF1007D8627 /* SocketEngineTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketEngineTest.swift; sourceTree = ""; }; @@ -300,6 +302,7 @@ DD52B078DB0A3C3D1BB507CD /* SocketIOClientOption.swift */, DD52B1D9BC4AE46D38D827DE /* SocketIOStatus.swift */, DD52B57FFEE8560CFFD793B3 /* SocketIOClientConfiguration.swift */, + 1C657533E849FC3E4342C602 /* SocketBinaryView.swift */, ); name = Client; path = Source/SocketIO/Client; @@ -480,6 +483,7 @@ DD52B9412F660F828B683422 /* SocketParsable.swift in Sources */, 1C6572803D7E252A77A86E5F /* SocketManager.swift in Sources */, 1C657FBB3F670261780FD72E /* SocketManagerSpec.swift in Sources */, + 1C6573B22DC9423CDFC32F05 /* SocketBinaryView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Source/SocketIO/Ack/SocketAckEmitter.swift b/Source/SocketIO/Ack/SocketAckEmitter.swift index a7c80be..274db9f 100644 --- a/Source/SocketIO/Ack/SocketAckEmitter.swift +++ b/Source/SocketIO/Ack/SocketAckEmitter.swift @@ -91,13 +91,16 @@ public final class SocketAckEmitter : NSObject { /// ``` public final class OnAckCallback : NSObject { private let ackNumber: Int + private let binary: Bool private let items: [Any] + private weak var socket: SocketIOClient? - init(ackNumber: Int, items: [Any], socket: SocketIOClient) { + init(ackNumber: Int, items: [Any], socket: SocketIOClient, binary: Bool = true) { self.ackNumber = ackNumber self.items = items self.socket = socket + self.binary = binary } deinit { @@ -116,7 +119,7 @@ public final class OnAckCallback : NSObject { guard let socket = self.socket, ackNumber != -1 else { return } socket.ackHandlers.addAck(ackNumber, callback: callback) - socket.emit(items, ack: ackNumber) + socket.emit(items, ack: ackNumber, binary: binary) guard seconds != 0 else { return } diff --git a/Source/SocketIO/Client/SocketBinaryView.swift b/Source/SocketIO/Client/SocketBinaryView.swift new file mode 100644 index 0000000..abc8755 --- /dev/null +++ b/Source/SocketIO/Client/SocketBinaryView.swift @@ -0,0 +1,106 @@ +// +// Created by Erik Little on 3/30/18. +// + +import Foundation + +/// Class that gives a backwards compatible way to cause an emit not to recursively check for Data objects. +/// +/// Usage: +/// ```swift +/// socket.binary(false).emit("myEvent", myObject) +/// ``` +public final class SocketBinaryView : NSObject { + private unowned let socket: SocketIOClient + private let binary: Bool + + init(socket: SocketIOClient, binary: Bool) { + self.socket = socket + self.binary = binary + } + + /// Send an event to the server, with optional data items. + /// + /// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error` + /// will be emitted. The structure of the error data is `[eventName, items, theError]` + /// + /// - parameter event: The event to send. + /// - parameter items: The items to send with this event. May be left out. + open func emit(_ event: String, _ items: SocketData...) { + do { + try emit(event, with: items.map({ try $0.socketRepresentation() })) + } catch let err { + DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)", + type: "SocketIOClient") + + socket.handleClientEvent(.error, data: [event, items, err]) + } + } + + /// Same as emit, but meant for Objective-C + /// + /// - parameter event: The event to send. + /// - parameter items: The items to send with this event. Send an empty array to send no data. + @objc + open func emit(_ event: String, with items: [Any]) { + guard socket.status == .connected else { + socket.handleClientEvent(.error, data: ["Tried emitting \(event) when not connected"]) + return + } + + socket.emit([event] + items, binary: binary) + } + + /// Sends a message to the server, requesting an ack. + /// + /// **NOTE**: It is up to the server send an ack back, just calling this method does not mean the server will ack. + /// Check that your server's api will ack the event being sent. + /// + /// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error` + /// will be emitted. The structure of the error data is `[eventName, items, theError]` + /// + /// Example: + /// + /// ```swift + /// socket.emitWithAck("myEvent", 1).timingOut(after: 1) {data in + /// ... + /// } + /// ``` + /// + /// - parameter event: The event to send. + /// - parameter items: The items to send with this event. May be left out. + /// - returns: An `OnAckCallback`. You must call the `timingOut(after:)` method before the event will be sent. + open func emitWithAck(_ event: String, _ items: SocketData...) -> OnAckCallback { + do { + return emitWithAck(event, with: try items.map({ try $0.socketRepresentation() })) + } catch let err { + DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)", + type: "SocketIOClient") + + socket.handleClientEvent(.error, data: [event, items, err]) + + return OnAckCallback(ackNumber: -1, items: [], socket: socket) + } + } + + /// Same as emitWithAck, but for Objective-C + /// + /// **NOTE**: It is up to the server send an ack back, just calling this method does not mean the server will ack. + /// Check that your server's api will ack the event being sent. + /// + /// Example: + /// + /// ```swift + /// socket.emitWithAck("myEvent", with: [1]).timingOut(after: 1) {data in + /// ... + /// } + /// ``` + /// + /// - parameter event: The event to send. + /// - parameter items: The items to send with this event. Use `[]` to send nothing. + /// - returns: An `OnAckCallback`. You must call the `timingOut(after:)` method before the event will be sent. + @objc + open func emitWithAck(_ event: String, with items: [Any]) -> OnAckCallback { + return socket.createOnAck([event] + items, binary: binary) + } +} diff --git a/Source/SocketIO/Client/SocketIOClient.swift b/Source/SocketIO/Client/SocketIOClient.swift index a8f12f4..c1b3629 100644 --- a/Source/SocketIO/Client/SocketIOClient.swift +++ b/Source/SocketIO/Client/SocketIOClient.swift @@ -148,7 +148,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec { } } - private func createOnAck(_ items: [Any]) -> OnAckCallback { + func createOnAck(_ items: [Any], binary: Bool = true) -> OnAckCallback { currentAck += 1 return OnAckCallback(ackNumber: currentAck, items: items, socket: self) @@ -277,13 +277,13 @@ open class SocketIOClient : NSObject, SocketIOClientSpec { return createOnAck([event] + items) } - func emit(_ data: [Any], ack: Int? = nil) { + func emit(_ data: [Any], ack: Int? = nil, binary: Bool = true) { guard status == .connected else { handleClientEvent(.error, data: ["Tried emitting when not connected"]) return } - let packet = SocketPacket.packetFromEmit(data, id: ack ?? -1, nsp: nsp, ack: false) + let packet = SocketPacket.packetFromEmit(data, id: ack ?? -1, nsp: nsp, ack: false, checkForBinary: binary) let str = packet.packetString DefaultSocketLogger.Logger.log("Emitting: \(str)", type: logType) @@ -300,7 +300,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec { open func emitAck(_ ack: Int, with items: [Any]) { guard status == .connected else { return } - let packet = SocketPacket.packetFromEmit(items, id: ack, nsp: nsp, ack: true) + let packet = SocketPacket.packetFromEmit(items, id: ack, nsp: nsp, ack: true, checkForBinary: true) let str = packet.packetString DefaultSocketLogger.Logger.log("Emitting Ack: \(str)", type: logType) diff --git a/Source/SocketIO/Parse/SocketPacket.swift b/Source/SocketIO/Parse/SocketPacket.swift index 28fbf35..4b316fc 100644 --- a/Source/SocketIO/Parse/SocketPacket.swift +++ b/Source/SocketIO/Parse/SocketPacket.swift @@ -200,11 +200,15 @@ extension SocketPacket { } } - static func packetFromEmit(_ items: [Any], id: Int, nsp: String, ack: Bool) -> SocketPacket { - let (parsedData, binary) = deconstructData(items) + static func packetFromEmit(_ items: [Any], id: Int, nsp: String, ack: Bool, checkForBinary: Bool = true) -> SocketPacket { + if checkForBinary { + let (parsedData, binary) = deconstructData(items) - return SocketPacket(type: findType(binary.count, ack: ack), data: parsedData, id: id, nsp: nsp, - binary: binary) + return SocketPacket(type: findType(binary.count, ack: ack), data: parsedData, id: id, nsp: nsp, + binary: binary) + } else { + return SocketPacket(type: findType(0, ack: ack), data: items, id: id, nsp: nsp) + } } } From d21a65e1174ab6e5ad979f3aa367eec0ae5fb99b Mon Sep 17 00:00:00 2001 From: Erik Little Date: Fri, 30 Mar 2018 14:33:18 -0400 Subject: [PATCH 04/12] Add rawEmitView. Implements #992 --- Source/SocketIO/Client/SocketBinaryView.swift | 11 +++++------ Source/SocketIO/Client/SocketIOClient.swift | 12 ++++++++++++ Source/SocketIO/Client/SocketIOClientSpec.swift | 11 +++++++++++ Tests/TestSocketIOObjc/SocketObjectiveCTest.m | 4 ++++ 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/Source/SocketIO/Client/SocketBinaryView.swift b/Source/SocketIO/Client/SocketBinaryView.swift index abc8755..1f2ab73 100644 --- a/Source/SocketIO/Client/SocketBinaryView.swift +++ b/Source/SocketIO/Client/SocketBinaryView.swift @@ -7,16 +7,15 @@ import Foundation /// Class that gives a backwards compatible way to cause an emit not to recursively check for Data objects. /// /// Usage: +/// /// ```swift -/// socket.binary(false).emit("myEvent", myObject) +/// socket.rawEmitView.emit("myEvent", myObject) /// ``` public final class SocketBinaryView : NSObject { private unowned let socket: SocketIOClient - private let binary: Bool - init(socket: SocketIOClient, binary: Bool) { + init(socket: SocketIOClient) { self.socket = socket - self.binary = binary } /// Send an event to the server, with optional data items. @@ -48,7 +47,7 @@ public final class SocketBinaryView : NSObject { return } - socket.emit([event] + items, binary: binary) + socket.emit([event] + items, binary: false) } /// Sends a message to the server, requesting an ack. @@ -101,6 +100,6 @@ public final class SocketBinaryView : NSObject { /// - returns: An `OnAckCallback`. You must call the `timingOut(after:)` method before the event will be sent. @objc open func emitWithAck(_ event: String, with items: [Any]) -> OnAckCallback { - return socket.createOnAck([event] + items, binary: binary) + return socket.createOnAck([event] + items, binary: false) } } diff --git a/Source/SocketIO/Client/SocketIOClient.swift b/Source/SocketIO/Client/SocketIOClient.swift index c1b3629..6dc131a 100644 --- a/Source/SocketIO/Client/SocketIOClient.swift +++ b/Source/SocketIO/Client/SocketIOClient.swift @@ -67,6 +67,18 @@ open class SocketIOClient : NSObject, SocketIOClientSpec { @objc public private(set) weak var manager: SocketManagerSpec? + /// A view into this socket where emits do not check for binary data. + /// + /// Usage: + /// + /// ```swift + /// socket.rawEmitView.emit("myEvent", myObject) + /// ``` + /// + /// **NOTE**: It is not safe to hold on to this view beyond the life of the socket. + @objc + public private(set) lazy var rawEmitView = SocketBinaryView(socket: self) + /// The status of this client. @objc public private(set) var status = SocketIOStatus.notConnected { diff --git a/Source/SocketIO/Client/SocketIOClientSpec.swift b/Source/SocketIO/Client/SocketIOClientSpec.swift index 739c7e9..72fb988 100644 --- a/Source/SocketIO/Client/SocketIOClientSpec.swift +++ b/Source/SocketIO/Client/SocketIOClientSpec.swift @@ -43,6 +43,17 @@ public protocol SocketIOClientSpec : class { /// **Must** start with a `/`. var nsp: String { get } + /// A view into this socket where emits do not check for binary data. + /// + /// Usage: + /// + /// ```swift + /// socket.rawEmitView.emit("myEvent", myObject) + /// ``` + /// + /// **NOTE**: It is not safe to hold on to this view beyond the life of the socket. + var rawEmitView: SocketBinaryView { get } + /// The status of this client. var status: SocketIOStatus { get } diff --git a/Tests/TestSocketIOObjc/SocketObjectiveCTest.m b/Tests/TestSocketIOObjc/SocketObjectiveCTest.m index 7e18359..55b6710 100644 --- a/Tests/TestSocketIOObjc/SocketObjectiveCTest.m +++ b/Tests/TestSocketIOObjc/SocketObjectiveCTest.m @@ -66,6 +66,10 @@ [self.socket emit:@"testEmit" with:@[@YES]]; } +- (void)testRawEmitSyntax { + [[self.socket rawEmitView] emit:@"myEvent" with:@[@1]]; +} + - (void)testEmitWithAckSyntax { [[self.socket emitWithAck:@"testAckEmit" with:@[@YES]] timingOutAfter:0 callback:^(NSArray* data) { }]; } From 948ea5fa00b3152d6f0b74ee4a64a35d7bc9136d Mon Sep 17 00:00:00 2001 From: Erik Little Date: Fri, 30 Mar 2018 14:37:15 -0400 Subject: [PATCH 05/12] rename SocketBinaryView --- Socket.IO-Client-Swift.xcodeproj/project.pbxproj | 8 ++++---- Source/SocketIO/Client/SocketIOClient.swift | 2 +- Source/SocketIO/Client/SocketIOClientSpec.swift | 2 +- .../{SocketBinaryView.swift => SocketRawView.swift} | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) rename Source/SocketIO/Client/{SocketBinaryView.swift => SocketRawView.swift} (98%) diff --git a/Socket.IO-Client-Swift.xcodeproj/project.pbxproj b/Socket.IO-Client-Swift.xcodeproj/project.pbxproj index c7f9eb4..3d611e0 100644 --- a/Socket.IO-Client-Swift.xcodeproj/project.pbxproj +++ b/Socket.IO-Client-Swift.xcodeproj/project.pbxproj @@ -8,7 +8,7 @@ /* Begin PBXBuildFile section */ 1C6572803D7E252A77A86E5F /* SocketManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C65763817782DFAC67BE05C /* SocketManager.swift */; }; - 1C6573B22DC9423CDFC32F05 /* SocketBinaryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C657533E849FC3E4342C602 /* SocketBinaryView.swift */; }; + 1C6573B22DC9423CDFC32F05 /* SocketRawView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C657533E849FC3E4342C602 /* SocketRawView.swift */; }; 1C657FBB3F670261780FD72E /* SocketManagerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C6574AF9687A213814753E4 /* SocketManagerSpec.swift */; }; 1C686BE21F869AFD007D8627 /* SocketIOClientConfigurationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C686BD21F869AF1007D8627 /* SocketIOClientConfigurationTest.swift */; }; 1C686BE31F869AFD007D8627 /* SocketEngineTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C686BD31F869AF1007D8627 /* SocketEngineTest.swift */; }; @@ -62,7 +62,7 @@ /* Begin PBXFileReference section */ 1C6574AF9687A213814753E4 /* SocketManagerSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketManagerSpec.swift; sourceTree = ""; }; - 1C657533E849FC3E4342C602 /* SocketBinaryView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketBinaryView.swift; sourceTree = ""; }; + 1C657533E849FC3E4342C602 /* SocketRawView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketRawView.swift; sourceTree = ""; }; 1C65763817782DFAC67BE05C /* SocketManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketManager.swift; sourceTree = ""; }; 1C686BD21F869AF1007D8627 /* SocketIOClientConfigurationTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketIOClientConfigurationTest.swift; sourceTree = ""; }; 1C686BD31F869AF1007D8627 /* SocketEngineTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketEngineTest.swift; sourceTree = ""; }; @@ -302,7 +302,7 @@ DD52B078DB0A3C3D1BB507CD /* SocketIOClientOption.swift */, DD52B1D9BC4AE46D38D827DE /* SocketIOStatus.swift */, DD52B57FFEE8560CFFD793B3 /* SocketIOClientConfiguration.swift */, - 1C657533E849FC3E4342C602 /* SocketBinaryView.swift */, + 1C657533E849FC3E4342C602 /* SocketRawView.swift */, ); name = Client; path = Source/SocketIO/Client; @@ -483,7 +483,7 @@ DD52B9412F660F828B683422 /* SocketParsable.swift in Sources */, 1C6572803D7E252A77A86E5F /* SocketManager.swift in Sources */, 1C657FBB3F670261780FD72E /* SocketManagerSpec.swift in Sources */, - 1C6573B22DC9423CDFC32F05 /* SocketBinaryView.swift in Sources */, + 1C6573B22DC9423CDFC32F05 /* SocketRawView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Source/SocketIO/Client/SocketIOClient.swift b/Source/SocketIO/Client/SocketIOClient.swift index 6dc131a..03364a8 100644 --- a/Source/SocketIO/Client/SocketIOClient.swift +++ b/Source/SocketIO/Client/SocketIOClient.swift @@ -77,7 +77,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec { /// /// **NOTE**: It is not safe to hold on to this view beyond the life of the socket. @objc - public private(set) lazy var rawEmitView = SocketBinaryView(socket: self) + public private(set) lazy var rawEmitView = SocketRawView(socket: self) /// The status of this client. @objc diff --git a/Source/SocketIO/Client/SocketIOClientSpec.swift b/Source/SocketIO/Client/SocketIOClientSpec.swift index 72fb988..5015e44 100644 --- a/Source/SocketIO/Client/SocketIOClientSpec.swift +++ b/Source/SocketIO/Client/SocketIOClientSpec.swift @@ -52,7 +52,7 @@ public protocol SocketIOClientSpec : class { /// ``` /// /// **NOTE**: It is not safe to hold on to this view beyond the life of the socket. - var rawEmitView: SocketBinaryView { get } + var rawEmitView: SocketRawView { get } /// The status of this client. var status: SocketIOStatus { get } diff --git a/Source/SocketIO/Client/SocketBinaryView.swift b/Source/SocketIO/Client/SocketRawView.swift similarity index 98% rename from Source/SocketIO/Client/SocketBinaryView.swift rename to Source/SocketIO/Client/SocketRawView.swift index 1f2ab73..1811a4f 100644 --- a/Source/SocketIO/Client/SocketBinaryView.swift +++ b/Source/SocketIO/Client/SocketRawView.swift @@ -11,7 +11,7 @@ import Foundation /// ```swift /// socket.rawEmitView.emit("myEvent", myObject) /// ``` -public final class SocketBinaryView : NSObject { +public final class SocketRawView: NSObject { private unowned let socket: SocketIOClient init(socket: SocketIOClient) { From 1b6144a78c597af097bd4967dcd3278a3f39859e Mon Sep 17 00:00:00 2001 From: Erik Little Date: Fri, 30 Mar 2018 14:39:31 -0400 Subject: [PATCH 06/12] change access level to public for raw view --- Source/SocketIO/Client/SocketRawView.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/SocketIO/Client/SocketRawView.swift b/Source/SocketIO/Client/SocketRawView.swift index 1811a4f..b7c1f8c 100644 --- a/Source/SocketIO/Client/SocketRawView.swift +++ b/Source/SocketIO/Client/SocketRawView.swift @@ -25,7 +25,7 @@ public final class SocketRawView: NSObject { /// /// - parameter event: The event to send. /// - parameter items: The items to send with this event. May be left out. - open func emit(_ event: String, _ items: SocketData...) { + public func emit(_ event: String, _ items: SocketData...) { do { try emit(event, with: items.map({ try $0.socketRepresentation() })) } catch let err { @@ -41,7 +41,7 @@ public final class SocketRawView: NSObject { /// - parameter event: The event to send. /// - parameter items: The items to send with this event. Send an empty array to send no data. @objc - open func emit(_ event: String, with items: [Any]) { + public func emit(_ event: String, with items: [Any]) { guard socket.status == .connected else { socket.handleClientEvent(.error, data: ["Tried emitting \(event) when not connected"]) return @@ -69,7 +69,7 @@ public final class SocketRawView: NSObject { /// - parameter event: The event to send. /// - parameter items: The items to send with this event. May be left out. /// - returns: An `OnAckCallback`. You must call the `timingOut(after:)` method before the event will be sent. - open func emitWithAck(_ event: String, _ items: SocketData...) -> OnAckCallback { + public func emitWithAck(_ event: String, _ items: SocketData...) -> OnAckCallback { do { return emitWithAck(event, with: try items.map({ try $0.socketRepresentation() })) } catch let err { @@ -99,7 +99,7 @@ public final class SocketRawView: NSObject { /// - parameter items: The items to send with this event. Use `[]` to send nothing. /// - returns: An `OnAckCallback`. You must call the `timingOut(after:)` method before the event will be sent. @objc - open func emitWithAck(_ event: String, with items: [Any]) -> OnAckCallback { + public func emitWithAck(_ event: String, with items: [Any]) -> OnAckCallback { return socket.createOnAck([event] + items, binary: false) } } From 24f3106fe7b3cae676a1c76f1288b7da65a89d87 Mon Sep 17 00:00:00 2001 From: Erik Little Date: Fri, 30 Mar 2018 14:56:19 -0400 Subject: [PATCH 07/12] Add raw view to ack emitter --- Source/SocketIO/Ack/SocketAckEmitter.swift | 16 ++++- Source/SocketIO/Client/SocketIOClient.swift | 6 +- Source/SocketIO/Client/SocketRawView.swift | 67 ++++++++++++++++++- Tests/TestSocketIOObjc/SocketObjectiveCTest.m | 1 + 4 files changed, 85 insertions(+), 5 deletions(-) diff --git a/Source/SocketIO/Ack/SocketAckEmitter.swift b/Source/SocketIO/Ack/SocketAckEmitter.swift index 274db9f..417fe94 100644 --- a/Source/SocketIO/Ack/SocketAckEmitter.swift +++ b/Source/SocketIO/Ack/SocketAckEmitter.swift @@ -29,8 +29,20 @@ import Foundation /// /// **NOTE**: You should not store this beyond the life of the event handler. public final class SocketAckEmitter : NSObject { - let socket: SocketIOClient - let ackNum: Int + private unowned let socket: SocketIOClient + private let ackNum: Int + + /// A view into this emitter where emits do not check for binary data. + /// + /// Usage: + /// + /// ```swift + /// ack.rawEmitView.with(myObject) + /// ``` + /// + /// **NOTE**: It is not safe to hold on to this view beyond the life of the socket. + @objc + public private(set) lazy var rawEmitView = SocketRawAckView(socket: socket, ackNum: ackNum) // MARK: Properties diff --git a/Source/SocketIO/Client/SocketIOClient.swift b/Source/SocketIO/Client/SocketIOClient.swift index 03364a8..0318054 100644 --- a/Source/SocketIO/Client/SocketIOClient.swift +++ b/Source/SocketIO/Client/SocketIOClient.swift @@ -310,9 +310,13 @@ open class SocketIOClient : NSObject, SocketIOClientSpec { /// - parameter ack: The ack number. /// - parameter with: The data for this ack. open func emitAck(_ ack: Int, with items: [Any]) { + emitAck(ack, with: items, binary: true) + } + + func emitAck(_ ack: Int, with items: [Any], binary: Bool) { guard status == .connected else { return } - let packet = SocketPacket.packetFromEmit(items, id: ack, nsp: nsp, ack: true, checkForBinary: true) + let packet = SocketPacket.packetFromEmit(items, id: ack, nsp: nsp, ack: true, checkForBinary: binary) let str = packet.packetString DefaultSocketLogger.Logger.log("Emitting Ack: \(str)", type: logType) diff --git a/Source/SocketIO/Client/SocketRawView.swift b/Source/SocketIO/Client/SocketRawView.swift index b7c1f8c..ed4389b 100644 --- a/Source/SocketIO/Client/SocketRawView.swift +++ b/Source/SocketIO/Client/SocketRawView.swift @@ -1,6 +1,26 @@ // -// Created by Erik Little on 3/30/18. +// SocketRawView.swift +// Socket.IO-Client-Swift // +// Created by Erik Little on 3/30/18. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. import Foundation @@ -11,7 +31,7 @@ import Foundation /// ```swift /// socket.rawEmitView.emit("myEvent", myObject) /// ``` -public final class SocketRawView: NSObject { +public final class SocketRawView : NSObject { private unowned let socket: SocketIOClient init(socket: SocketIOClient) { @@ -103,3 +123,46 @@ public final class SocketRawView: NSObject { return socket.createOnAck([event] + items, binary: false) } } + +/// Class that gives a backwards compatible way to cause an emit not to recursively check for Data objects. +/// +/// Usage: +/// +/// ```swift +/// ack.rawEmitView.with(myObject) +/// ``` +public final class SocketRawAckView : NSObject { + private unowned let socket: SocketIOClient + private let ackNum: Int + + init(socket: SocketIOClient, ackNum: Int) { + self.socket = socket + self.ackNum = ackNum + } + + /// Call to ack receiving this event. + /// + /// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error` + /// will be emitted. The structure of the error data is `[ackNum, items, theError]` + /// + /// - parameter items: A variable number of items to send when acking. + public func with(_ items: SocketData...) { + guard ackNum != -1 else { return } + + do { + socket.emitAck(ackNum, with: try items.map({ try $0.socketRepresentation() }), binary: false) + } catch let err { + socket.handleClientEvent(.error, data: [ackNum, items, err]) + } + } + + /// Call to ack receiving this event. + /// + /// - parameter items: An array of items to send when acking. Use `[]` to send nothing. + @objc + public func with(_ items: [Any]) { + guard ackNum != -1 else { return } + + socket.emitAck(ackNum, with: items, binary: false) + } +} diff --git a/Tests/TestSocketIOObjc/SocketObjectiveCTest.m b/Tests/TestSocketIOObjc/SocketObjectiveCTest.m index 55b6710..1ad3475 100644 --- a/Tests/TestSocketIOObjc/SocketObjectiveCTest.m +++ b/Tests/TestSocketIOObjc/SocketObjectiveCTest.m @@ -26,6 +26,7 @@ - (void)testOnSyntax { [self.socket on:@"someCallback" callback:^(NSArray* data, SocketAckEmitter* ack) { [ack with:@[@1]]; + [[ack rawEmitView] with:@[@"hello"]]; }]; } From be43b0ab3c5b0ee51ac731b4e74af27f833a520f Mon Sep 17 00:00:00 2001 From: Erik Little Date: Sat, 31 Mar 2018 11:16:58 -0400 Subject: [PATCH 08/12] open engine --- CHANGELOG.md | 5 +++++ Source/SocketIO/Engine/SocketEngine.swift | 21 ++++++++++----------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bfaf269..d7a3dc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# v13.2.0 + +- Add ability to bypass Data inspection in emits. [#992]((https://github.com/socketio/socket.io-client-swift/issues/992)) +- Allow `SocketEngine` to be subclassed + # v13.1.3 - Fix setting reconnectAttempts [#989]((https://github.com/socketio/socket.io-client-swift/issues/989)) diff --git a/Source/SocketIO/Engine/SocketEngine.swift b/Source/SocketIO/Engine/SocketEngine.swift index fc1c1ad..4904ee5 100644 --- a/Source/SocketIO/Engine/SocketEngine.swift +++ b/Source/SocketIO/Engine/SocketEngine.swift @@ -28,8 +28,7 @@ import Starscream /// The class that handles the engine.io protocol and transports. /// See `SocketEnginePollable` and `SocketEngineWebsocket` for transport specific methods. -public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, SocketEngineWebsocket, - ConfigSettable { +open class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, SocketEngineWebsocket, ConfigSettable { // MARK: Properties private static let logType = "SocketEngine" @@ -164,7 +163,7 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll /// - parameter client: The client for this engine. /// - parameter url: The url for this engine. /// - parameter options: The options for this engine. - public convenience init(client: SocketEngineClient, url: URL, options: [String: Any]?) { + public required convenience init(client: SocketEngineClient, url: URL, options: [String: Any]?) { self.init(client: client, url: url, config: options?.toSocketConfiguration() ?? []) } @@ -214,7 +213,7 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll } /// Starts the connection to the server. - public func connect() { + open func connect() { engineQueue.async { self._connect() } @@ -318,7 +317,7 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll } /// Called when an error happens during execution. Causes a disconnection. - public func didError(reason: String) { + open func didError(reason: String) { DefaultSocketLogger.Logger.error("\(reason)", type: SocketEngine.logType) client?.engineDidError(reason: reason) disconnect(reason: reason) @@ -327,7 +326,7 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll /// Disconnects from the server. /// /// - parameter reason: The reason for the disconnection. This is communicated up to the client. - public func disconnect(reason: String) { + open func disconnect(reason: String) { engineQueue.async { self._disconnect(reason: reason) } @@ -359,7 +358,7 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll /// WebSocket mode. /// /// **You shouldn't call this directly** - public func doFastUpgrade() { + open func doFastUpgrade() { if waitingForPoll { DefaultSocketLogger.Logger.error("Outstanding poll when switched to WebSockets," + "we'll probably disconnect soon. You should report this.", type: SocketEngine.logType) @@ -392,7 +391,7 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll /// the engine is attempting to upgrade to WebSocket it does not do any POSTing. /// /// **You shouldn't call this directly** - public func flushWaitingForPostToWebSocket() { + open func flushWaitingForPostToWebSocket() { guard let ws = self.ws else { return } for msg in postWait { @@ -474,7 +473,7 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll /// Parses raw binary received from engine.io. /// /// - parameter data: The data to parse. - public func parseEngineData(_ data: Data) { + open func parseEngineData(_ data: Data) { DefaultSocketLogger.Logger.log("Got binary data: \(data)", type: SocketEngine.logType) client?.parseEngineBinaryData(data.subdata(in: 1.. Date: Sun, 1 Apr 2018 18:48:15 -0400 Subject: [PATCH 09/12] get rid of internal emitAck method --- Source/SocketIO/Client/SocketIOClient.swift | 19 ++++--------------- Source/SocketIO/Client/SocketRawView.swift | 4 ++-- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/Source/SocketIO/Client/SocketIOClient.swift b/Source/SocketIO/Client/SocketIOClient.swift index 0318054..f5701da 100644 --- a/Source/SocketIO/Client/SocketIOClient.swift +++ b/Source/SocketIO/Client/SocketIOClient.swift @@ -289,16 +289,16 @@ open class SocketIOClient : NSObject, SocketIOClientSpec { return createOnAck([event] + items) } - func emit(_ data: [Any], ack: Int? = nil, binary: Bool = true) { + func emit(_ data: [Any], ack: Int? = nil, binary: Bool = true, isAck: Bool = false) { guard status == .connected else { handleClientEvent(.error, data: ["Tried emitting when not connected"]) return } - let packet = SocketPacket.packetFromEmit(data, id: ack ?? -1, nsp: nsp, ack: false, checkForBinary: binary) + let packet = SocketPacket.packetFromEmit(data, id: ack ?? -1, nsp: nsp, ack: isAck, checkForBinary: binary) let str = packet.packetString - DefaultSocketLogger.Logger.log("Emitting: \(str)", type: logType) + DefaultSocketLogger.Logger.log("Emitting: \(str), Ack: \(isAck)", type: logType) manager?.engine?.send(str, withData: packet.binary) } @@ -310,18 +310,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec { /// - parameter ack: The ack number. /// - parameter with: The data for this ack. open func emitAck(_ ack: Int, with items: [Any]) { - emitAck(ack, with: items, binary: true) - } - - func emitAck(_ ack: Int, with items: [Any], binary: Bool) { - guard status == .connected else { return } - - let packet = SocketPacket.packetFromEmit(items, id: ack, nsp: nsp, ack: true, checkForBinary: binary) - let str = packet.packetString - - DefaultSocketLogger.Logger.log("Emitting Ack: \(str)", type: logType) - - manager?.engine?.send(str, withData: packet.binary) + emit(items, ack: ack, binary: true, isAck: true) } /// Called when socket.io has acked one of our emits. Causes the corresponding ack callback to be called. diff --git a/Source/SocketIO/Client/SocketRawView.swift b/Source/SocketIO/Client/SocketRawView.swift index ed4389b..809447c 100644 --- a/Source/SocketIO/Client/SocketRawView.swift +++ b/Source/SocketIO/Client/SocketRawView.swift @@ -150,7 +150,7 @@ public final class SocketRawAckView : NSObject { guard ackNum != -1 else { return } do { - socket.emitAck(ackNum, with: try items.map({ try $0.socketRepresentation() }), binary: false) + socket.emit(try items.map({ try $0.socketRepresentation() }), ack: ackNum, binary: false, isAck: true) } catch let err { socket.handleClientEvent(.error, data: [ackNum, items, err]) } @@ -163,6 +163,6 @@ public final class SocketRawAckView : NSObject { public func with(_ items: [Any]) { guard ackNum != -1 else { return } - socket.emitAck(ackNum, with: items, binary: false) + socket.emit(items, ack: ackNum, binary: false, isAck: true) } } From 6ff403fad1f28833e1806ceace138c96fc0f7806 Mon Sep 17 00:00:00 2001 From: Erik Little Date: Mon, 2 Apr 2018 11:36:20 -0400 Subject: [PATCH 10/12] remove some redundant connected checking --- Source/SocketIO/Client/SocketIOClient.swift | 5 ----- Source/SocketIO/Client/SocketRawView.swift | 5 ----- 2 files changed, 10 deletions(-) diff --git a/Source/SocketIO/Client/SocketIOClient.swift b/Source/SocketIO/Client/SocketIOClient.swift index f5701da..04f35a5 100644 --- a/Source/SocketIO/Client/SocketIOClient.swift +++ b/Source/SocketIO/Client/SocketIOClient.swift @@ -228,11 +228,6 @@ open class SocketIOClient : NSObject, SocketIOClientSpec { /// - parameter items: The items to send with this event. Send an empty array to send no data. @objc open func emit(_ event: String, with items: [Any]) { - guard status == .connected else { - handleClientEvent(.error, data: ["Tried emitting \(event) when not connected"]) - return - } - emit([event] + items) } diff --git a/Source/SocketIO/Client/SocketRawView.swift b/Source/SocketIO/Client/SocketRawView.swift index 809447c..73fe080 100644 --- a/Source/SocketIO/Client/SocketRawView.swift +++ b/Source/SocketIO/Client/SocketRawView.swift @@ -62,11 +62,6 @@ public final class SocketRawView : NSObject { /// - parameter items: The items to send with this event. Send an empty array to send no data. @objc public func emit(_ event: String, with items: [Any]) { - guard socket.status == .connected else { - socket.handleClientEvent(.error, data: ["Tried emitting \(event) when not connected"]) - return - } - socket.emit([event] + items, binary: false) } From c3cabe43bf9cd3deac97c20d46bb46ecf24a9af7 Mon Sep 17 00:00:00 2001 From: Erik Little Date: Thu, 10 May 2018 07:29:28 -0400 Subject: [PATCH 11/12] Make it clear that `handleQueue` should be serial --- Source/SocketIO/Client/SocketIOClientOption.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/SocketIO/Client/SocketIOClientOption.swift b/Source/SocketIO/Client/SocketIOClientOption.swift index 3e9114f..02d8898 100644 --- a/Source/SocketIO/Client/SocketIOClientOption.swift +++ b/Source/SocketIO/Client/SocketIOClientOption.swift @@ -55,6 +55,8 @@ public enum SocketIOClientOption : ClientOption { /// The queue that all interaction with the client should occur on. This is the queue that event handlers are /// called on. + /// + /// **This should be a serial queue! Concurrent queues are not supported and might cause crashes and races**. case handleQueue(DispatchQueue) /// If passed `true`, the client will log debug information. This should be turned off in production code. From 4ea1bb9c43627edb9a31a99367a6d9ef2e832e2d Mon Sep 17 00:00:00 2001 From: Erik Little Date: Thu, 10 May 2018 07:46:38 -0400 Subject: [PATCH 12/12] Add note about manager not being thread safe --- Source/SocketIO/Manager/SocketManager.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/SocketIO/Manager/SocketManager.swift b/Source/SocketIO/Manager/SocketManager.swift index c499b1a..7434ec7 100644 --- a/Source/SocketIO/Manager/SocketManager.swift +++ b/Source/SocketIO/Manager/SocketManager.swift @@ -43,6 +43,8 @@ import Foundation /// To disconnect a socket and remove it from the manager, either call `SocketIOClient.disconnect()` on the socket, /// or call one of the `disconnectSocket` methods on this class. /// +/// **NOTE**: The manager is not thread/queue safe, all interaction with the manager should be done on the `handleQueue` +/// open class SocketManager : NSObject, SocketManagerSpec, SocketParsable, SocketDataBufferable, ConfigSettable { private static let logType = "SocketManager"