From 19c68416bba2fbf97d25d88153c431c00fe057c8 Mon Sep 17 00:00:00 2001 From: leo0307vb Date: Thu, 14 Jan 2016 14:44:32 -0500 Subject: [PATCH 01/19] add new method engineDidOpen in socketEngineClient protocol --- Source/SocketEngine.swift | 1 + Source/SocketEngineClient.swift | 1 + 2 files changed, 2 insertions(+) diff --git a/Source/SocketEngine.swift b/Source/SocketEngine.swift index 5eb023e..37fa951 100644 --- a/Source/SocketEngine.swift +++ b/Source/SocketEngine.swift @@ -762,6 +762,7 @@ extension SocketEngine { connected = true probing = false polling = false + client?.engineDidOpen!("Connect") } } diff --git a/Source/SocketEngineClient.swift b/Source/SocketEngineClient.swift index 776dc5a..7609862 100644 --- a/Source/SocketEngineClient.swift +++ b/Source/SocketEngineClient.swift @@ -30,4 +30,5 @@ import Foundation func engineDidClose(reason: String) func parseEngineMessage(msg: String) func parseEngineBinaryData(data: NSData) + optional func engineDidOpen(reason: String) } From 3c9070b3e77b77011b5b9e67f0c625fe9099f142 Mon Sep 17 00:00:00 2001 From: leo0307vb Date: Thu, 14 Jan 2016 17:57:58 -0500 Subject: [PATCH 02/19] fix engineDidOpen implementation --- Source/SocketEngine.swift | 3 ++- Source/SocketEngineClient.swift | 2 +- Source/SocketIOClient.swift | 4 ++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Source/SocketEngine.swift b/Source/SocketEngine.swift index 37fa951..5d4c470 100644 --- a/Source/SocketEngine.swift +++ b/Source/SocketEngine.swift @@ -331,6 +331,8 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate { if !forcePolling && !forceWebsockets && upgradeWs { createWebsocketAndConnect(true) } + + client?.engineDidOpen("Connect") } } catch { DefaultSocketLogger.Logger.error("Error parsing open packet", type: logType) @@ -762,7 +764,6 @@ extension SocketEngine { connected = true probing = false polling = false - client?.engineDidOpen!("Connect") } } diff --git a/Source/SocketEngineClient.swift b/Source/SocketEngineClient.swift index 7609862..762aca7 100644 --- a/Source/SocketEngineClient.swift +++ b/Source/SocketEngineClient.swift @@ -30,5 +30,5 @@ import Foundation func engineDidClose(reason: String) func parseEngineMessage(msg: String) func parseEngineBinaryData(data: NSData) - optional func engineDidOpen(reason: String) + func engineDidOpen(reason: String) } diff --git a/Source/SocketIOClient.swift b/Source/SocketIOClient.swift index 16ab0a4..3d8adcd 100644 --- a/Source/SocketIOClient.swift +++ b/Source/SocketIOClient.swift @@ -318,6 +318,10 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable } } + public func engineDidOpen(reason: String) { + didConnect() + } + // Called when the socket gets an ack for something it sent func handleAck(ack: Int, data: [AnyObject]) { guard status == .Connected else {return} From 660aed8359d35ee452f376a363a12052a61945fb Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 15 Jan 2016 09:56:53 -0500 Subject: [PATCH 03/19] small tweaks --- Source/SocketEngine.swift | 2 +- Source/SocketEngineClient.swift | 2 +- Source/SocketIOClient.swift | 4 ---- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Source/SocketEngine.swift b/Source/SocketEngine.swift index 5d4c470..d19f068 100644 --- a/Source/SocketEngine.swift +++ b/Source/SocketEngine.swift @@ -332,7 +332,7 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate { createWebsocketAndConnect(true) } - client?.engineDidOpen("Connect") + client?.engineDidOpen?("Connect") } } catch { DefaultSocketLogger.Logger.error("Error parsing open packet", type: logType) diff --git a/Source/SocketEngineClient.swift b/Source/SocketEngineClient.swift index 762aca7..276bcfc 100644 --- a/Source/SocketEngineClient.swift +++ b/Source/SocketEngineClient.swift @@ -28,7 +28,7 @@ import Foundation @objc public protocol SocketEngineClient { func didError(reason: AnyObject) func engineDidClose(reason: String) + optional func engineDidOpen(reason: String) func parseEngineMessage(msg: String) func parseEngineBinaryData(data: NSData) - func engineDidOpen(reason: String) } diff --git a/Source/SocketIOClient.swift b/Source/SocketIOClient.swift index 3d8adcd..16ab0a4 100644 --- a/Source/SocketIOClient.swift +++ b/Source/SocketIOClient.swift @@ -318,10 +318,6 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable } } - public func engineDidOpen(reason: String) { - didConnect() - } - // Called when the socket gets an ack for something it sent func handleAck(ack: Int, data: [AnyObject]) { guard status == .Connected else {return} From a299901fa8d662535fe604d56a85c3a285a421a7 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 15 Jan 2016 10:05:44 -0500 Subject: [PATCH 04/19] why I didn't use contains first idk --- Source/SocketEngine.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/SocketEngine.swift b/Source/SocketEngine.swift index d19f068..09170aa 100644 --- a/Source/SocketEngine.swift +++ b/Source/SocketEngine.swift @@ -318,7 +318,7 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate { connected = true if let upgrades = json?["upgrades"] as? [String] { - upgradeWs = upgrades.filter {$0 == "websocket"}.count != 0 + upgradeWs = upgrades.contains("websocket") } else { upgradeWs = false } From 731c8a851b2e852349653b4134309b1ff298ffd9 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 15 Jan 2016 13:17:13 -0500 Subject: [PATCH 05/19] first pass at refactoring engine --- .../project.pbxproj | 16 + Source/SocketEngine.swift | 311 +++--------------- Source/SocketEngineClient.swift | 2 +- Source/SocketEnginePollable.swift | 217 ++++++++++++ Source/SocketEngineSpec.swift | 48 ++- Source/SocketEngineWebsocket.swift | 64 ++++ 6 files changed, 382 insertions(+), 276 deletions(-) create mode 100644 Source/SocketEnginePollable.swift create mode 100644 Source/SocketEngineWebsocket.swift diff --git a/Socket.IO-Client-Swift.xcodeproj/project.pbxproj b/Socket.IO-Client-Swift.xcodeproj/project.pbxproj index 4675dee..f19e020 100644 --- a/Socket.IO-Client-Swift.xcodeproj/project.pbxproj +++ b/Socket.IO-Client-Swift.xcodeproj/project.pbxproj @@ -17,6 +17,9 @@ 57634A2F1BD9B46D00E19CD7 /* SocketBasicPacketTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74F124EF1BC574CF002966F4 /* SocketBasicPacketTest.swift */; }; 57634A321BD9B46D00E19CD7 /* SocketNamespacePacketTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7472C65B1BCAB53E003CA70D /* SocketNamespacePacketTest.swift */; }; 57634A3F1BD9B4BF00E19CD7 /* SocketIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 57634A161BD9B46A00E19CD7 /* SocketIO.framework */; }; + 740CA1201C496EEB00CB98F4 /* SocketEngineWebsocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 740CA11F1C496EEB00CB98F4 /* SocketEngineWebsocket.swift */; }; + 740CA1211C496EF200CB98F4 /* SocketEngineWebsocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 740CA11F1C496EEB00CB98F4 /* SocketEngineWebsocket.swift */; }; + 740CA1221C496EF700CB98F4 /* SocketEngineWebsocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 740CA11F1C496EEB00CB98F4 /* SocketEngineWebsocket.swift */; }; 74171E631C10CD240062D398 /* SocketAckEmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74171E501C10CD240062D398 /* SocketAckEmitter.swift */; }; 74171E641C10CD240062D398 /* SocketAckEmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74171E501C10CD240062D398 /* SocketAckEmitter.swift */; }; 74171E651C10CD240062D398 /* SocketAckEmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74171E501C10CD240062D398 /* SocketAckEmitter.swift */; }; @@ -115,6 +118,9 @@ 74171ED41C10CD240062D398 /* WebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74171E621C10CD240062D398 /* WebSocket.swift */; }; 741F39EE1BD025D80026C9CC /* SocketEngineTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 741F39ED1BD025D80026C9CC /* SocketEngineTest.swift */; }; 741F39EF1BD025D80026C9CC /* SocketEngineTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 741F39ED1BD025D80026C9CC /* SocketEngineTest.swift */; }; + 7420CB791C49629E00956AA4 /* SocketEnginePollable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7420CB781C49629E00956AA4 /* SocketEnginePollable.swift */; }; + 7420CB7A1C49629E00956AA4 /* SocketEnginePollable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7420CB781C49629E00956AA4 /* SocketEnginePollable.swift */; }; + 7420CB7B1C49629E00956AA4 /* SocketEnginePollable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7420CB781C49629E00956AA4 /* SocketEnginePollable.swift */; }; 74321DCB1C2D939A00CF6F43 /* SocketAckManagerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74321DC91C2D939A00CF6F43 /* SocketAckManagerTest.swift */; }; 74321DCC1C2D939A00CF6F43 /* SocketParserTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74321DCA1C2D939A00CF6F43 /* SocketParserTest.swift */; }; 7471CCEA1C39926300364B59 /* SocketClientSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74ABF7761C3991C10078C657 /* SocketClientSpec.swift */; }; @@ -165,6 +171,7 @@ 572EF2481B51F18A00EEBB58 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 57634A161BD9B46A00E19CD7 /* SocketIO.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SocketIO.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 57634A3B1BD9B46D00E19CD7 /* SocketIO-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SocketIO-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 740CA11F1C496EEB00CB98F4 /* SocketEngineWebsocket.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SocketEngineWebsocket.swift; path = Source/SocketEngineWebsocket.swift; sourceTree = ""; }; 74171E501C10CD240062D398 /* SocketAckEmitter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketAckEmitter.swift; path = Source/SocketAckEmitter.swift; sourceTree = ""; }; 74171E511C10CD240062D398 /* SocketAckManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketAckManager.swift; path = Source/SocketAckManager.swift; sourceTree = ""; }; 74171E521C10CD240062D398 /* SocketAnyEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketAnyEvent.swift; path = Source/SocketAnyEvent.swift; sourceTree = ""; }; @@ -185,6 +192,7 @@ 74171E611C10CD240062D398 /* SwiftRegex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SwiftRegex.swift; path = Source/SwiftRegex.swift; sourceTree = ""; }; 74171E621C10CD240062D398 /* WebSocket.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WebSocket.swift; path = Source/WebSocket.swift; sourceTree = ""; }; 741F39ED1BD025D80026C9CC /* SocketEngineTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketEngineTest.swift; sourceTree = ""; }; + 7420CB781C49629E00956AA4 /* SocketEnginePollable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketEnginePollable.swift; path = Source/SocketEnginePollable.swift; sourceTree = ""; }; 74321DC91C2D939A00CF6F43 /* SocketAckManagerTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketAckManagerTest.swift; sourceTree = ""; }; 74321DCA1C2D939A00CF6F43 /* SocketParserTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketParserTest.swift; sourceTree = ""; }; 7472C65B1BCAB53E003CA70D /* SocketNamespacePacketTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketNamespacePacketTest.swift; sourceTree = ""; }; @@ -349,7 +357,9 @@ 74171E531C10CD240062D398 /* SocketEngine.swift */, 74171E541C10CD240062D398 /* SocketEngineClient.swift */, 74171E551C10CD240062D398 /* SocketEnginePacketType.swift */, + 7420CB781C49629E00956AA4 /* SocketEnginePollable.swift */, 74171E561C10CD240062D398 /* SocketEngineSpec.swift */, + 740CA11F1C496EEB00CB98F4 /* SocketEngineWebsocket.swift */, 74171E571C10CD240062D398 /* SocketEventHandler.swift */, 74171E581C10CD240062D398 /* SocketFixUTF8.swift */, 74171E591C10CD240062D398 /* SocketIOClient.swift */, @@ -599,10 +609,12 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 740CA1221C496EF700CB98F4 /* SocketEngineWebsocket.swift in Sources */, 74171E931C10CD240062D398 /* SocketFixUTF8.swift in Sources */, 74171EA51C10CD240062D398 /* SocketIOClientStatus.swift in Sources */, 74171E751C10CD240062D398 /* SocketEngine.swift in Sources */, 74171E691C10CD240062D398 /* SocketAckManager.swift in Sources */, + 7420CB791C49629E00956AA4 /* SocketEnginePollable.swift in Sources */, 74ABF7771C3991C10078C657 /* SocketClientSpec.swift in Sources */, 74171E871C10CD240062D398 /* SocketEngineSpec.swift in Sources */, 74171E631C10CD240062D398 /* SocketAckEmitter.swift in Sources */, @@ -656,10 +668,12 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 740CA1211C496EF200CB98F4 /* SocketEngineWebsocket.swift in Sources */, 7471CCEA1C39926300364B59 /* SocketClientSpec.swift in Sources */, 74171E951C10CD240062D398 /* SocketFixUTF8.swift in Sources */, 74171EA71C10CD240062D398 /* SocketIOClientStatus.swift in Sources */, 74171E771C10CD240062D398 /* SocketEngine.swift in Sources */, + 7420CB7A1C49629E00956AA4 /* SocketEnginePollable.swift in Sources */, 74171E6B1C10CD240062D398 /* SocketAckManager.swift in Sources */, 74171E891C10CD240062D398 /* SocketEngineSpec.swift in Sources */, 74171E651C10CD240062D398 /* SocketAckEmitter.swift in Sources */, @@ -697,10 +711,12 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 740CA1201C496EEB00CB98F4 /* SocketEngineWebsocket.swift in Sources */, 7471CCEB1C39926C00364B59 /* SocketClientSpec.swift in Sources */, 74171E971C10CD240062D398 /* SocketFixUTF8.swift in Sources */, 74171EA91C10CD240062D398 /* SocketIOClientStatus.swift in Sources */, 74171E791C10CD240062D398 /* SocketEngine.swift in Sources */, + 7420CB7B1C49629E00956AA4 /* SocketEnginePollable.swift in Sources */, 74171E6D1C10CD240062D398 /* SocketAckManager.swift in Sources */, 74171E8B1C10CD240062D398 /* SocketEngineSpec.swift in Sources */, 74171E671C10CD240062D398 /* SocketAckEmitter.swift in Sources */, diff --git a/Source/SocketEngine.swift b/Source/SocketEngine.swift index 09170aa..bae0613 100644 --- a/Source/SocketEngine.swift +++ b/Source/SocketEngine.swift @@ -24,12 +24,33 @@ import Foundation -public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate { - public private(set) var sid = "" +public final class SocketEngine: NSObject, SocketEngineSpec, SocketEnginePollable, SocketEngineWebsocket { + public let emitQueue = dispatch_queue_create("com.socketio.engineEmitQueue", DISPATCH_QUEUE_SERIAL) + public let handleQueue = dispatch_queue_create("com.socketio.engineHandleQueue", DISPATCH_QUEUE_SERIAL) + public let parseQueue = dispatch_queue_create("com.socketio.engineParseQueue", DISPATCH_QUEUE_SERIAL) + + public var invalidated = false + public var postWait = [String]() + public var probing = false + public var waitingForPoll = false + public var waitingForPost = false + public var websocketConnected = false + + public private(set) var closed = false + public private(set) var connected = false public private(set) var cookies: [NSHTTPCookie]? + public private(set) var extraHeaders: [String: String]? + public private(set) var fastUpgrade = false + public private(set) var forcePolling = false + public private(set) var forceWebsockets = false + public private(set) var pingTimer: NSTimer? + public private(set) var polling = true + public private(set) var session: NSURLSession? + public private(set) var sid = "" public private(set) var socketPath = "/engine.io" public private(set) var urlPolling = "" public private(set) var urlWebSocket = "" + public private(set) var websocket = false public private(set) var ws: WebSocket? public weak var client: SocketEngineClient? @@ -40,22 +61,13 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate { private typealias ProbeWaitQueue = [Probe] private let allowedCharacterSet = NSCharacterSet(charactersInString: "!*'();:@&=+$,/?%#[]\" {}").invertedSet - private let emitQueue = dispatch_queue_create("com.socketio.engineEmitQueue", DISPATCH_QUEUE_SERIAL) - private let handleQueue = dispatch_queue_create("com.socketio.engineHandleQueue", DISPATCH_QUEUE_SERIAL) + private let logType = "SocketEngine" - private let parseQueue = dispatch_queue_create("com.socketio.engineParseQueue", DISPATCH_QUEUE_SERIAL) private let url: String private let workQueue = NSOperationQueue() - + private var connectParams: [String: AnyObject]? - private var closed = false - private var extraHeaders: [String: String]? - private var fastUpgrade = false - private var forcePolling = false - private var forceWebsockets = false - private var invalidated = false private var pingInterval: Double? - private var pingTimer: NSTimer? private var pingTimeout = 0.0 { didSet { pongsMissedMax = Int(pingTimeout / (pingInterval ?? 25)) @@ -63,19 +75,10 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate { } private var pongsMissed = 0 private var pongsMissedMax = 0 - private var postWait = [String]() - private var probing = false private var probeWait = ProbeWaitQueue() private var secure = false private var selfSigned = false - private var session: NSURLSession? private var voipEnabled = false - private var waitingForPoll = false - private var waitingForPost = false - private var websocketConnected = false - private(set) var connected = false - private(set) var polling = true - private(set) var websocket = false public init(client: SocketEngineClient, url: String, options: Set) { self.client = client @@ -181,22 +184,6 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate { client?.engineDidClose("Disconnect") } - private func createBinaryDataForSend(data: NSData) -> Either { - if websocket { - var byteArray = [UInt8](count: 1, repeatedValue: 0x0) - byteArray[0] = 4 - let mutData = NSMutableData(bytes: &byteArray, length: 1) - - mutData.appendData(data) - - return .Left(mutData) - } else { - let str = "b4" + data.base64EncodedStringWithOptions(.Encoding64CharacterLineLength) - - return .Right(str) - } - } - private func createURLs(params: [String: AnyObject]?) -> (String, String) { if client == nil { return ("", "") @@ -264,7 +251,7 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate { } } - private func doFastUpgrade() { + 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) @@ -293,6 +280,18 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate { } } } + + // We had packets waiting for send when we upgraded + // Send them raw + public func flushWaitingForPostToWebSocket() { + guard let ws = self.ws else { return } + + for msg in postWait { + ws.writeString(fixDoubleUTF8(msg)) + } + + postWait.removeAll(keepCapacity: true) + } private func handleClose(reason: String) { client?.engineDidClose(reason) @@ -356,7 +355,7 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate { } // A poll failed, tell the client about it - private func handlePollingFailed(reason: String) { + public func handlePollingFailed(reason: String) { connected = false ws?.disconnect() pingTimer?.invalidate() @@ -414,12 +413,12 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate { doLongPoll(reqPolling) } - private func parseEngineData(data: NSData) { + public func parseEngineData(data: NSData) { DefaultSocketLogger.Logger.log("Got binary data: %@", type: "SocketEngine", args: data) client?.parseEngineBinaryData(data.subdataWithRange(NSMakeRange(1, data.length - 1))) } - private func parseEngineMessage(message: String, fromPolling: Bool) { + public func parseEngineMessage(message: String, fromPolling: Bool) { DefaultSocketLogger.Logger.log("Got message: %@", type: logType, args: message) let reader = SocketStringReader(message: message) @@ -454,13 +453,6 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate { DefaultSocketLogger.Logger.log("Got unknown packet type", type: logType) } } - - private func probeWebSocket() { - if websocketConnected { - sendWebSocketMessage("probe", withType: .Ping, withData: []) - } - } - private func resetEngine() { closed = false @@ -541,220 +533,9 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate { } } } -} - -// Polling methods -extension SocketEngine { - private func addHeaders(req: NSMutableURLRequest) { - if cookies != nil { - let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies!) - req.allHTTPHeaderFields = headers - } - - if extraHeaders != nil { - for (headerName, value) in extraHeaders! { - req.setValue(value, forHTTPHeaderField: headerName) - } - } - } - - private func doPoll() { - if websocket || waitingForPoll || !connected || closed { - return - } - - waitingForPoll = true - let req = NSMutableURLRequest(URL: NSURL(string: urlPolling + "&sid=\(sid)&b64=1")!) - - addHeaders(req) - doLongPoll(req) - } - - private func doRequest(req: NSURLRequest, - withCallback callback: (NSData?, NSURLResponse?, NSError?) -> Void) { - if !polling || closed || invalidated { - DefaultSocketLogger.Logger.error("Tried to do polling request when not supposed to", type: logType) - return - } - - DefaultSocketLogger.Logger.log("Doing polling request", type: logType) - - session?.dataTaskWithRequest(req, completionHandler: callback).resume() - } - - private func doLongPoll(req: NSURLRequest) { - doRequest(req) {[weak self] data, res, err in - guard let this = self else {return} - - if err != nil || data == nil { - DefaultSocketLogger.Logger.error(err?.localizedDescription ?? "Error", type: this.logType) - - if this.polling { - this.handlePollingFailed(err?.localizedDescription ?? "Error") - } - - return - } - - DefaultSocketLogger.Logger.log("Got polling response", type: this.logType) - - if let str = String(data: data!, encoding: NSUTF8StringEncoding) { - dispatch_async(this.parseQueue) { - this.parsePollingMessage(str) - } - } - - this.waitingForPoll = false - - if this.fastUpgrade { - this.doFastUpgrade() - } else if !this.closed && this.polling { - this.doPoll() - } - } - } - - private func flushWaitingForPost() { - if postWait.count == 0 || !connected { - return - } else if websocket { - flushWaitingForPostToWebSocket() - return - } - - var postStr = "" - - for packet in postWait { - let len = packet.characters.count - - postStr += "\(len):\(packet)" - } - - postWait.removeAll(keepCapacity: false) - - let req = NSMutableURLRequest(URL: NSURL(string: urlPolling + "&sid=\(sid)")!) - - addHeaders(req) - - req.HTTPMethod = "POST" - req.setValue("text/plain; charset=UTF-8", forHTTPHeaderField: "Content-Type") - - let postData = postStr.dataUsingEncoding(NSUTF8StringEncoding, - allowLossyConversion: false)! - - req.HTTPBody = postData - req.setValue(String(postData.length), forHTTPHeaderField: "Content-Length") - - waitingForPost = true - - DefaultSocketLogger.Logger.log("POSTing: %@", type: logType, args: postStr) - - doRequest(req) {[weak self] data, res, err in - guard let this = self else {return} - - if err != nil { - DefaultSocketLogger.Logger.error(err?.localizedDescription ?? "Error", type: this.logType) - - if this.polling { - this.handlePollingFailed(err?.localizedDescription ?? "Error") - } - - return - } - - this.waitingForPost = false - - dispatch_async(this.emitQueue) { - if !this.fastUpgrade { - this.flushWaitingForPost() - this.doPoll() - } - } - } - } - - // We had packets waiting for send when we upgraded - // Send them raw - private func flushWaitingForPostToWebSocket() { - guard let ws = self.ws else { return } - - for msg in postWait { - ws.writeString(fixDoubleUTF8(msg)) - } - - postWait.removeAll(keepCapacity: true) - } - - func parsePollingMessage(str: String) { - guard str.characters.count != 1 else { - return - } - - var reader = SocketStringReader(message: str) - - while reader.hasNext { - if let n = Int(reader.readUntilStringOccurence(":")) { - let str = reader.read(n) - - dispatch_async(handleQueue) { - self.parseEngineMessage(str, fromPolling: true) - } - } else { - dispatch_async(handleQueue) { - self.parseEngineMessage(str, fromPolling: true) - } - break - } - } - } - - /// Send polling message. - /// Only call on emitQueue - private func sendPollMessage(message: String, withType type: SocketEnginePacketType, - withData datas: [NSData]) { - DefaultSocketLogger.Logger.log("Sending poll: %@ as type: %@", type: logType, args: message, type.rawValue) - let fixedMessage = doubleEncodeUTF8(message) - let strMsg = "\(type.rawValue)\(fixedMessage)" - - postWait.append(strMsg) - - for data in datas { - if case let .Right(bin) = createBinaryDataForSend(data) { - postWait.append(bin) - } - } - - if !waitingForPost { - flushWaitingForPost() - } - } - - private func stopPolling() { - invalidated = true - session?.finishTasksAndInvalidate() - } -} - -// WebSocket methods -extension SocketEngine { - /// Send message on WebSockets - /// Only call on emitQueue - private func sendWebSocketMessage(str: String, withType type: SocketEnginePacketType, - withData datas: [NSData]) { - DefaultSocketLogger.Logger.log("Sending ws: %@ as type: %@", type: logType, args: str, type.rawValue) - - ws?.writeString("\(type.rawValue)\(str)") - - for data in datas { - if case let .Left(bin) = createBinaryDataForSend(data) { - ws?.writeData(bin) - } - } - } // Delagate methods - - public func websocketDidConnect(socket:WebSocket) { + public func websocketDidConnect(socket: WebSocket) { websocketConnected = true if !forceWebsockets { @@ -792,12 +573,4 @@ extension SocketEngine { flushProbeWait() } } - - public func websocketDidReceiveMessage(socket: WebSocket, text: String) { - parseEngineMessage(text, fromPolling: false) - } - - public func websocketDidReceiveData(socket: WebSocket, data: NSData) { - parseEngineData(data) - } } diff --git a/Source/SocketEngineClient.swift b/Source/SocketEngineClient.swift index 276bcfc..74956aa 100644 --- a/Source/SocketEngineClient.swift +++ b/Source/SocketEngineClient.swift @@ -25,7 +25,7 @@ import Foundation -@objc public protocol SocketEngineClient { +@objc public protocol SocketEngineClient { func didError(reason: AnyObject) func engineDidClose(reason: String) optional func engineDidOpen(reason: String) diff --git a/Source/SocketEnginePollable.swift b/Source/SocketEnginePollable.swift new file mode 100644 index 0000000..8a325b9 --- /dev/null +++ b/Source/SocketEnginePollable.swift @@ -0,0 +1,217 @@ +// +// SocketEnginePollable.swift +// Socket.IO-Client-Swift +// +// Created by Erik Little on 1/15/16. +// +// 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 + +public protocol SocketEnginePollable: SocketEngineSpec { + var invalidated: Bool { get set } + var session: NSURLSession? { get } + var waitingForPoll: Bool { get set } + var waitingForPost: Bool { get set } + + func doPoll() + func handlePollingFailed(reason: String) + func sendPollMessage(message: String, withType type: SocketEnginePacketType, withData datas: [NSData]) + func stopPolling() +} + +// Default polling methods +extension SocketEnginePollable { + private func addHeaders(req: NSMutableURLRequest) { + if cookies != nil { + let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies!) + req.allHTTPHeaderFields = headers + } + + if extraHeaders != nil { + for (headerName, value) in extraHeaders! { + req.setValue(value, forHTTPHeaderField: headerName) + } + } + } + + public func doPoll() { + if websocket || waitingForPoll || !connected || closed { + return + } + + waitingForPoll = true + let req = NSMutableURLRequest(URL: NSURL(string: urlPolling + "&sid=\(sid)&b64=1")!) + + addHeaders(req) + doLongPoll(req) + } + + private func doRequest(req: NSURLRequest, + withCallback callback: (NSData?, NSURLResponse?, NSError?) -> Void) { + if !polling || closed || invalidated { + DefaultSocketLogger.Logger.error("Tried to do polling request when not supposed to", type: "SocketEngine") + return + } + + DefaultSocketLogger.Logger.log("Doing polling request", type: "SocketEngine") + + session?.dataTaskWithRequest(req, completionHandler: callback).resume() + } + + func doLongPoll(req: NSURLRequest) { + doRequest(req) {[weak self] data, res, err in + guard let this = self else {return} + + if err != nil || data == nil { + DefaultSocketLogger.Logger.error(err?.localizedDescription ?? "Error", type: "SocketEngine") + + if this.polling { + this.handlePollingFailed(err?.localizedDescription ?? "Error") + } + + return + } + + DefaultSocketLogger.Logger.log("Got polling response", type: "SocketEngine") + + if let str = String(data: data!, encoding: NSUTF8StringEncoding) { + dispatch_async(this.parseQueue) { + this.parsePollingMessage(str) + } + } + + this.waitingForPoll = false + + if this.fastUpgrade { + this.doFastUpgrade() + } else if !this.closed && this.polling { + this.doPoll() + } + } + } + + private func flushWaitingForPost() { + if postWait.count == 0 || !connected { + return + } else if websocket { + flushWaitingForPostToWebSocket() + return + } + + var postStr = "" + + for packet in postWait { + let len = packet.characters.count + + postStr += "\(len):\(packet)" + } + + postWait.removeAll(keepCapacity: false) + + let req = NSMutableURLRequest(URL: NSURL(string: urlPolling + "&sid=\(sid)")!) + + addHeaders(req) + + req.HTTPMethod = "POST" + req.setValue("text/plain; charset=UTF-8", forHTTPHeaderField: "Content-Type") + + let postData = postStr.dataUsingEncoding(NSUTF8StringEncoding, + allowLossyConversion: false)! + + req.HTTPBody = postData + req.setValue(String(postData.length), forHTTPHeaderField: "Content-Length") + + waitingForPost = true + + DefaultSocketLogger.Logger.log("POSTing: %@", type: "SocketEngine", args: postStr) + + doRequest(req) {[weak self] data, res, err in + guard let this = self else {return} + + if err != nil { + DefaultSocketLogger.Logger.error(err?.localizedDescription ?? "Error", type: "SocketEngine") + + if this.polling { + this.handlePollingFailed(err?.localizedDescription ?? "Error") + } + + return + } + + this.waitingForPost = false + + dispatch_async(this.emitQueue) { + if !this.fastUpgrade { + this.flushWaitingForPost() + this.doPoll() + } + } + } + } + + func parsePollingMessage(str: String) { + guard str.characters.count != 1 else { + return + } + + var reader = SocketStringReader(message: str) + + while reader.hasNext { + if let n = Int(reader.readUntilStringOccurence(":")) { + let str = reader.read(n) + + dispatch_async(handleQueue) { + self.parseEngineMessage(str, fromPolling: true) + } + } else { + dispatch_async(handleQueue) { + self.parseEngineMessage(str, fromPolling: true) + } + break + } + } + } + + /// Send polling message. + /// Only call on emitQueue + public func sendPollMessage(message: String, withType type: SocketEnginePacketType, + withData datas: [NSData]) { + DefaultSocketLogger.Logger.log("Sending poll: %@ as type: %@", type: "SocketEngine", args: message, type.rawValue) + let fixedMessage = doubleEncodeUTF8(message) + let strMsg = "\(type.rawValue)\(fixedMessage)" + + postWait.append(strMsg) + + for data in datas { + if case let .Right(bin) = createBinaryDataForSend(data) { + postWait.append(bin) + } + } + + if !waitingForPost { + flushWaitingForPost() + } + } + + public func stopPolling() { + invalidated = true + session?.finishTasksAndInvalidate() + } +} diff --git a/Source/SocketEngineSpec.swift b/Source/SocketEngineSpec.swift index 52ec6e5..11ed9a0 100644 --- a/Source/SocketEngineSpec.swift +++ b/Source/SocketEngineSpec.swift @@ -26,17 +26,53 @@ import Foundation @objc public protocol SocketEngineSpec { - weak var client: SocketEngineClient? {get set} - var cookies: [NSHTTPCookie]? {get} - var sid: String {get} - var socketPath: String {get} - var urlPolling: String {get} - var urlWebSocket: String {get} + weak var client: SocketEngineClient? { get set } + var closed: Bool { get } + var connected: Bool { get } + var cookies: [NSHTTPCookie]? { get } + var extraHeaders: [String: String]? { get } + var fastUpgrade: Bool { get } + var forcePolling: Bool { get } + var forceWebsockets: Bool { get } + var parseQueue: dispatch_queue_t! { get } + var pingTimer: NSTimer? { get } + var polling: Bool { get } + var postWait: [String] { get set } + var probing: Bool { get set } + var emitQueue: dispatch_queue_t! { get } + var handleQueue: dispatch_queue_t! { get } + var sid: String { get } + var socketPath: String { get } + var urlPolling: String { get } + var urlWebSocket: String { get } + var websocket: Bool { get } init(client: SocketEngineClient, url: String, options: NSDictionary?) func close() + func doFastUpgrade() + func flushWaitingForPostToWebSocket() func open(opts: [String: AnyObject]?) + func parseEngineData(data: NSData) + func parseEngineMessage(message: String, fromPolling: Bool) func send(msg: String, withData datas: [NSData]) func write(msg: String, withType type: SocketEnginePacketType, withData data: [NSData]) } + +extension SocketEngineSpec { + func createBinaryDataForSend(data: NSData) -> Either { + if websocket { + var byteArray = [UInt8](count: 1, repeatedValue: 0x0) + byteArray[0] = 4 + let mutData = NSMutableData(bytes: &byteArray, length: 1) + + mutData.appendData(data) + + return .Left(mutData) + } else { + let str = "b4" + data.base64EncodedStringWithOptions(.Encoding64CharacterLineLength) + + return .Right(str) + } + } +} diff --git a/Source/SocketEngineWebsocket.swift b/Source/SocketEngineWebsocket.swift new file mode 100644 index 0000000..358d433 --- /dev/null +++ b/Source/SocketEngineWebsocket.swift @@ -0,0 +1,64 @@ +// +// SocketEngineWebsocket.swift +// Socket.IO-Client-Swift +// +// Created by Erik Little on 1/15/16. +// +// 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 + +public protocol SocketEngineWebsocket: SocketEngineSpec, WebSocketDelegate { + var websocketConnected: Bool { get set } + var ws: WebSocket? { get } + + func sendWebSocketMessage(str: String, withType type: SocketEnginePacketType, withData datas: [NSData]) +} + +// WebSocket methods +extension SocketEngineWebsocket { + func probeWebSocket() { + if websocketConnected { + sendWebSocketMessage("probe", withType: .Ping, withData: []) + } + } + + /// Send message on WebSockets + /// Only call on emitQueue + public func sendWebSocketMessage(str: String, withType type: SocketEnginePacketType, withData datas: [NSData]) { + DefaultSocketLogger.Logger.log("Sending ws: %@ as type: %@", type: "SocketEngine", args: str, type.rawValue) + + ws?.writeString("\(type.rawValue)\(str)") + + for data in datas { + if case let .Left(bin) = createBinaryDataForSend(data) { + ws?.writeData(bin) + } + } + } + + public func websocketDidReceiveMessage(socket: WebSocket, text: String) { + parseEngineMessage(text, fromPolling: false) + } + + public func websocketDidReceiveData(socket: WebSocket, data: NSData) { + parseEngineData(data) + } +} \ No newline at end of file From ac460d8023dc4d0a5831fb6a6c6c8ed93e08309f Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 15 Jan 2016 13:31:01 -0500 Subject: [PATCH 06/19] newline --- Source/SocketEngineWebsocket.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/SocketEngineWebsocket.swift b/Source/SocketEngineWebsocket.swift index 358d433..8961592 100644 --- a/Source/SocketEngineWebsocket.swift +++ b/Source/SocketEngineWebsocket.swift @@ -61,4 +61,4 @@ extension SocketEngineWebsocket { public func websocketDidReceiveData(socket: WebSocket, data: NSData) { parseEngineData(data) } -} \ No newline at end of file +} From 3979b36f63ef32a16a02d02b7c3a1abf1577a470 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 15 Jan 2016 14:15:50 -0500 Subject: [PATCH 07/19] more refactoring --- Source/SocketEngine.swift | 14 +++++--------- Source/SocketEnginePollable.swift | 3 +-- Source/SocketEngineSpec.swift | 4 ++-- Source/SocketEngineWebsocket.swift | 3 +-- 4 files changed, 9 insertions(+), 15 deletions(-) diff --git a/Source/SocketEngine.swift b/Source/SocketEngine.swift index bae0613..1f914fc 100644 --- a/Source/SocketEngine.swift +++ b/Source/SocketEngine.swift @@ -24,17 +24,14 @@ import Foundation -public final class SocketEngine: NSObject, SocketEngineSpec, SocketEnginePollable, SocketEngineWebsocket { +public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWebsocket { public let emitQueue = dispatch_queue_create("com.socketio.engineEmitQueue", DISPATCH_QUEUE_SERIAL) public let handleQueue = dispatch_queue_create("com.socketio.engineHandleQueue", DISPATCH_QUEUE_SERIAL) public let parseQueue = dispatch_queue_create("com.socketio.engineParseQueue", DISPATCH_QUEUE_SERIAL) - public var invalidated = false public var postWait = [String]() - public var probing = false public var waitingForPoll = false public var waitingForPost = false - public var websocketConnected = false public private(set) var closed = false public private(set) var connected = false @@ -43,8 +40,10 @@ public final class SocketEngine: NSObject, SocketEngineSpec, SocketEnginePollabl public private(set) var fastUpgrade = false public private(set) var forcePolling = false public private(set) var forceWebsockets = false + public private(set) var invalidated = false public private(set) var pingTimer: NSTimer? public private(set) var polling = true + public private(set) var probing = false public private(set) var session: NSURLSession? public private(set) var sid = "" public private(set) var socketPath = "/engine.io" @@ -171,6 +170,7 @@ public final class SocketEngine: NSObject, SocketEngineSpec, SocketEnginePollabl pingTimer?.invalidate() closed = true + invalidated = true connected = false if websocket { @@ -468,7 +468,6 @@ public final class SocketEngine: NSObject, SocketEngineSpec, SocketEnginePollabl waitingForPoll = false waitingForPost = false websocket = false - websocketConnected = false } /// Send an engine message (4) @@ -506,7 +505,7 @@ public final class SocketEngine: NSObject, SocketEngineSpec, SocketEnginePollabl } private func upgradeTransport() { - if websocketConnected { + if ws?.isConnected ?? false { DefaultSocketLogger.Logger.log("Upgrading transport to WebSockets", type: logType) fastUpgrade = true @@ -536,8 +535,6 @@ public final class SocketEngine: NSObject, SocketEngineSpec, SocketEnginePollabl // Delagate methods public func websocketDidConnect(socket: WebSocket) { - websocketConnected = true - if !forceWebsockets { probing = true probeWebSocket() @@ -549,7 +546,6 @@ public final class SocketEngine: NSObject, SocketEngineSpec, SocketEnginePollabl } public func websocketDidDisconnect(socket: WebSocket, error: NSError?) { - websocketConnected = false probing = false if closed { diff --git a/Source/SocketEnginePollable.swift b/Source/SocketEnginePollable.swift index 8a325b9..52d09d6 100644 --- a/Source/SocketEnginePollable.swift +++ b/Source/SocketEnginePollable.swift @@ -25,7 +25,7 @@ import Foundation public protocol SocketEnginePollable: SocketEngineSpec { - var invalidated: Bool { get set } + var invalidated: Bool { get } var session: NSURLSession? { get } var waitingForPoll: Bool { get set } var waitingForPost: Bool { get set } @@ -211,7 +211,6 @@ extension SocketEnginePollable { } public func stopPolling() { - invalidated = true session?.finishTasksAndInvalidate() } } diff --git a/Source/SocketEngineSpec.swift b/Source/SocketEngineSpec.swift index 11ed9a0..f00f967 100644 --- a/Source/SocketEngineSpec.swift +++ b/Source/SocketEngineSpec.swift @@ -37,8 +37,8 @@ import Foundation var parseQueue: dispatch_queue_t! { get } var pingTimer: NSTimer? { get } var polling: Bool { get } - var postWait: [String] { get set } - var probing: Bool { get set } + var postWait: [String] { get set } // Would like to change to get only + var probing: Bool { get } // Would like to change to get only var emitQueue: dispatch_queue_t! { get } var handleQueue: dispatch_queue_t! { get } var sid: String { get } diff --git a/Source/SocketEngineWebsocket.swift b/Source/SocketEngineWebsocket.swift index 8961592..53215c7 100644 --- a/Source/SocketEngineWebsocket.swift +++ b/Source/SocketEngineWebsocket.swift @@ -26,7 +26,6 @@ import Foundation public protocol SocketEngineWebsocket: SocketEngineSpec, WebSocketDelegate { - var websocketConnected: Bool { get set } var ws: WebSocket? { get } func sendWebSocketMessage(str: String, withType type: SocketEnginePacketType, withData datas: [NSData]) @@ -35,7 +34,7 @@ public protocol SocketEngineWebsocket: SocketEngineSpec, WebSocketDelegate { // WebSocket methods extension SocketEngineWebsocket { func probeWebSocket() { - if websocketConnected { + if ws?.isConnected ?? false { sendWebSocketMessage("probe", withType: .Ping, withData: []) } } From 443f5c5b22af098455f6a4db291539204ee97552 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 15 Jan 2016 14:21:59 -0500 Subject: [PATCH 08/19] move declaration of postWait --- Source/SocketEnginePollable.swift | 4 ++-- Source/SocketEngineSpec.swift | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Source/SocketEnginePollable.swift b/Source/SocketEnginePollable.swift index 52d09d6..e4dd023 100644 --- a/Source/SocketEnginePollable.swift +++ b/Source/SocketEnginePollable.swift @@ -26,6 +26,7 @@ import Foundation public protocol SocketEnginePollable: SocketEngineSpec { var invalidated: Bool { get } + var postWait: [String] { get set } // Would like to change to get only var session: NSURLSession? { get } var waitingForPoll: Bool { get set } var waitingForPost: Bool { get set } @@ -191,8 +192,7 @@ extension SocketEnginePollable { /// Send polling message. /// Only call on emitQueue - public func sendPollMessage(message: String, withType type: SocketEnginePacketType, - withData datas: [NSData]) { + public func sendPollMessage(message: String, withType type: SocketEnginePacketType, withData datas: [NSData]) { DefaultSocketLogger.Logger.log("Sending poll: %@ as type: %@", type: "SocketEngine", args: message, type.rawValue) let fixedMessage = doubleEncodeUTF8(message) let strMsg = "\(type.rawValue)\(fixedMessage)" diff --git a/Source/SocketEngineSpec.swift b/Source/SocketEngineSpec.swift index f00f967..365fdfc 100644 --- a/Source/SocketEngineSpec.swift +++ b/Source/SocketEngineSpec.swift @@ -37,8 +37,7 @@ import Foundation var parseQueue: dispatch_queue_t! { get } var pingTimer: NSTimer? { get } var polling: Bool { get } - var postWait: [String] { get set } // Would like to change to get only - var probing: Bool { get } // Would like to change to get only + var probing: Bool { get } var emitQueue: dispatch_queue_t! { get } var handleQueue: dispatch_queue_t! { get } var sid: String { get } From b202b21d4300671e35d761adc3828f1819ba2621 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 15 Jan 2016 17:35:20 -0500 Subject: [PATCH 09/19] remove comment --- Source/SocketEnginePollable.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/SocketEnginePollable.swift b/Source/SocketEnginePollable.swift index e4dd023..41e771e 100644 --- a/Source/SocketEnginePollable.swift +++ b/Source/SocketEnginePollable.swift @@ -26,7 +26,7 @@ import Foundation public protocol SocketEnginePollable: SocketEngineSpec { var invalidated: Bool { get } - var postWait: [String] { get set } // Would like to change to get only + var postWait: [String] { get set } var session: NSURLSession? { get } var waitingForPoll: Bool { get set } var waitingForPost: Bool { get set } From e06a7925032ef2cb316d819905120854977dc25d Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 15 Jan 2016 19:12:07 -0500 Subject: [PATCH 10/19] add some comments --- Source/SocketEnginePollable.swift | 7 +++++++ Source/SocketEngineWebsocket.swift | 1 + 2 files changed, 8 insertions(+) diff --git a/Source/SocketEnginePollable.swift b/Source/SocketEnginePollable.swift index 41e771e..ca90c5d 100644 --- a/Source/SocketEnginePollable.swift +++ b/Source/SocketEnginePollable.swift @@ -24,11 +24,18 @@ import Foundation +/// Protocol that is used to implement socket.io polling support public protocol SocketEnginePollable: SocketEngineSpec { var invalidated: Bool { get } + /// Holds strings waiting to be sent over polling. + /// You shouldn't need to mess with this. var postWait: [String] { get set } var session: NSURLSession? { get } + /// Because socket.io doesn't let you send two polling request at the same time + /// we have to keep track if there's an outstanding poll var waitingForPoll: Bool { get set } + /// Because socket.io doesn't let you send two post request at the same time + /// we have to keep track if there's an outstanding post var waitingForPost: Bool { get set } func doPoll() diff --git a/Source/SocketEngineWebsocket.swift b/Source/SocketEngineWebsocket.swift index 53215c7..4b1be7f 100644 --- a/Source/SocketEngineWebsocket.swift +++ b/Source/SocketEngineWebsocket.swift @@ -25,6 +25,7 @@ import Foundation +/// Protocol that is used to implement socket.io WebSocket support public protocol SocketEngineWebsocket: SocketEngineSpec, WebSocketDelegate { var ws: WebSocket? { get } From dbc8b6fadce82a22acfa8db7cf90a0c93635feec Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 16 Jan 2016 15:04:03 -0500 Subject: [PATCH 11/19] refactor engine erroring --- SocketIO-MacTests/SocketEngineTest.swift | 24 +++++++++ Source/SocketClientSpec.swift | 11 +++- Source/SocketEngine.swift | 65 ++++++++++-------------- Source/SocketEngineClient.swift | 2 +- Source/SocketEnginePollable.swift | 7 +-- Source/SocketEngineSpec.swift | 1 + Source/SocketIOClient.swift | 44 ++++++++-------- 7 files changed, 89 insertions(+), 65 deletions(-) diff --git a/SocketIO-MacTests/SocketEngineTest.swift b/SocketIO-MacTests/SocketEngineTest.swift index 636b562..90a4c22 100644 --- a/SocketIO-MacTests/SocketEngineTest.swift +++ b/SocketIO-MacTests/SocketEngineTest.swift @@ -50,4 +50,28 @@ class SocketEngineTest: XCTestCase { engine.parsePollingMessage("15:42[\"blankTest\"]24:42[\"stringTest\",\"hello\"]") waitForExpectationsWithTimeout(3, handler: nil) } + + func testEngineDoesErrorOnUnknownTransport() { + let finalExpectation = expectationWithDescription("Unknown Transport") + + client.on("error") {data, ack in + if let error = data[0] as? String where error == "Unknown transport" { + finalExpectation.fulfill() + } + } + + engine.parseEngineMessage("{\"code\": 0, \"message\": \"Unknown transport\"}", fromPolling: false) + waitForExpectationsWithTimeout(3, handler: nil) + } + + func testEngineDoesErrorOnUnknownMessage() { + let finalExpectation = expectationWithDescription("Engine Errors") + + client.on("error") {data, ack in + finalExpectation.fulfill() + } + + engine.parseEngineMessage("afafafda", fromPolling: false) + waitForExpectationsWithTimeout(3, handler: nil) + } } diff --git a/Source/SocketClientSpec.swift b/Source/SocketClientSpec.swift index a0314b4..7a72cad 100644 --- a/Source/SocketClientSpec.swift +++ b/Source/SocketClientSpec.swift @@ -32,4 +32,13 @@ protocol SocketClientSpec: class { func handleAck(ack: Int, data: [AnyObject]) func handleEvent(event: String, data: [AnyObject], isInternalMessage: Bool, withAck ack: Int) func joinNamespace(namespace: String) -} \ No newline at end of file +} + +extension SocketClientSpec { + func didError(reason: AnyObject) { + DefaultSocketLogger.Logger.error("%@", type: "SocketIOClient", args: reason) + + handleEvent("error", data: reason as? [AnyObject] ?? [reason], + isInternalMessage: true, withAck: -1) + } +} diff --git a/Source/SocketEngine.swift b/Source/SocketEngine.swift index 1f914fc..8bfd8a1 100644 --- a/Source/SocketEngine.swift +++ b/Source/SocketEngine.swift @@ -60,10 +60,8 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb private typealias ProbeWaitQueue = [Probe] private let allowedCharacterSet = NSCharacterSet(charactersInString: "!*'();:@&=+$,/?%#[]\" {}").invertedSet - private let logType = "SocketEngine" private let url: String - private let workQueue = NSOperationQueue() private var connectParams: [String: AnyObject]? private var pingInterval: Double? @@ -132,20 +130,20 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb switch code { case 0: // Unknown transport - logAndError(error) + didError(error) case 1: // Unknown sid. clear and retry connect sid = "" open(connectParams) case 2: // Bad handshake request - logAndError(error) + didError(error) case 3: // Bad request - logAndError(error) + didError(error) default: - logAndError(error) + didError(error) } } } catch { - logAndError("Got unknown error from server") + didError("Got unknown error from server \(msg)") } } @@ -250,6 +248,17 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb ws?.connect() } } + + public func didError(error: String) { + connected = false + ws?.disconnect() + stopPolling() + pingTimer?.invalidate() + + DefaultSocketLogger.Logger.error(error, type: logType) + client?.engineDidError(error) + client?.engineDidClose(error) + } public func doFastUpgrade() { if waitingForPoll { @@ -331,18 +340,19 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb createWebsocketAndConnect(true) } + + startPingTimer() + + if !forceWebsockets { + doPoll() + } + client?.engineDidOpen?("Connect") } } catch { - DefaultSocketLogger.Logger.error("Error parsing open packet", type: logType) + didError("Error parsing open packet") return } - - startPingTimer() - - if !forceWebsockets { - doPoll() - } } private func handlePong(pongMessage: String) { @@ -354,31 +364,12 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb } } - // A poll failed, tell the client about it - public func handlePollingFailed(reason: String) { - connected = false - ws?.disconnect() - pingTimer?.invalidate() - waitingForPoll = false - waitingForPost = false - - if !closed { - client?.didError(reason) - client?.engineDidClose(reason) - } - } - - private func logAndError(error: String) { - DefaultSocketLogger.Logger.error(error, type: logType) - client?.didError(error) - } - public func open(opts: [String: AnyObject]? = nil) { connectParams = opts if connected { DefaultSocketLogger.Logger.error("Tried to open while connected", type: logType) - client?.didError("Tried to open engine while connected") + didError("Tried to open engine while connected") return } @@ -463,7 +454,7 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb invalidated = false session = NSURLSession(configuration: .defaultSessionConfiguration(), delegate: sessionDelegate, - delegateQueue: workQueue) + delegateQueue: NSOperationQueue()) sid = "" waitingForPoll = false waitingForPost = false @@ -533,7 +524,7 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb } } - // Delagate methods + // Delegate methods public func websocketDidConnect(socket: WebSocket) { if !forceWebsockets { probing = true @@ -561,7 +552,7 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb let reason = error?.localizedDescription ?? "Socket Disconnected" if error != nil { - client?.didError(reason) + didError(reason) } client?.engineDidClose(reason) diff --git a/Source/SocketEngineClient.swift b/Source/SocketEngineClient.swift index 74956aa..f2b997c 100644 --- a/Source/SocketEngineClient.swift +++ b/Source/SocketEngineClient.swift @@ -26,7 +26,7 @@ import Foundation @objc public protocol SocketEngineClient { - func didError(reason: AnyObject) + func engineDidError(reason: AnyObject) func engineDidClose(reason: String) optional func engineDidOpen(reason: String) func parseEngineMessage(msg: String) diff --git a/Source/SocketEnginePollable.swift b/Source/SocketEnginePollable.swift index ca90c5d..0da2ed9 100644 --- a/Source/SocketEnginePollable.swift +++ b/Source/SocketEnginePollable.swift @@ -39,7 +39,6 @@ public protocol SocketEnginePollable: SocketEngineSpec { var waitingForPost: Bool { get set } func doPoll() - func handlePollingFailed(reason: String) func sendPollMessage(message: String, withType type: SocketEnginePacketType, withData datas: [NSData]) func stopPolling() } @@ -91,7 +90,7 @@ extension SocketEnginePollable { DefaultSocketLogger.Logger.error(err?.localizedDescription ?? "Error", type: "SocketEngine") if this.polling { - this.handlePollingFailed(err?.localizedDescription ?? "Error") + this.didError(err?.localizedDescription ?? "Error") } return @@ -157,7 +156,7 @@ extension SocketEnginePollable { DefaultSocketLogger.Logger.error(err?.localizedDescription ?? "Error", type: "SocketEngine") if this.polling { - this.handlePollingFailed(err?.localizedDescription ?? "Error") + this.didError(err?.localizedDescription ?? "Error") } return @@ -218,6 +217,8 @@ extension SocketEnginePollable { } public func stopPolling() { + waitingForPoll = false + waitingForPost = false session?.finishTasksAndInvalidate() } } diff --git a/Source/SocketEngineSpec.swift b/Source/SocketEngineSpec.swift index 365fdfc..f60fc52 100644 --- a/Source/SocketEngineSpec.swift +++ b/Source/SocketEngineSpec.swift @@ -49,6 +49,7 @@ import Foundation init(client: SocketEngineClient, url: String, options: NSDictionary?) func close() + func didError(error: String) func doFastUpgrade() func flushWaitingForPostToWebSocket() func open(opts: [String: AnyObject]?) diff --git a/Source/SocketIOClient.swift b/Source/SocketIOClient.swift index 16ab0a4..1b0228a 100644 --- a/Source/SocketIOClient.swift +++ b/Source/SocketIOClient.swift @@ -227,14 +227,6 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable handleEvent("disconnect", data: [reason], isInternalMessage: true) } - /// error - public func didError(reason: AnyObject) { - DefaultSocketLogger.Logger.error("%@", type: logType, args: reason) - - handleEvent("error", data: reason as? [AnyObject] ?? [reason], - isInternalMessage: true) - } - /** Same as close */ @@ -318,6 +310,14 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable } } + /// error + public func engineDidError(reason: AnyObject) { + DefaultSocketLogger.Logger.error("%@", type: logType, args: reason) + + handleEvent("error", data: reason as? [AnyObject] ?? [reason], + isInternalMessage: true) + } + // Called when the socket gets an ack for something it sent func handleAck(ack: Int, data: [AnyObject]) { guard status == .Connected else {return} @@ -330,22 +330,20 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable /** Causes an event to be handled. Only use if you know what you're doing. */ - public func handleEvent(event: String, data: [AnyObject], isInternalMessage: Bool, - withAck ack: Int = -1) { - guard status == .Connected || isInternalMessage else { - return + public func handleEvent(event: String, data: [AnyObject], isInternalMessage: Bool, withAck ack: Int = -1) { + guard status == .Connected || isInternalMessage else { + return + } + + DefaultSocketLogger.Logger.log("Handling event: %@ with data: %@", type: logType, args: event, data ?? "") + + dispatch_async(handleQueue) { + self.anyHandler?(SocketAnyEvent(event: event, items: data)) + + for handler in self.handlers where handler.event == event { + handler.executeCallback(data, withAck: ack, withSocket: self) } - - DefaultSocketLogger.Logger.log("Handling event: %@ with data: %@", type: logType, args: event, data ?? "") - - dispatch_async(handleQueue) { - self.anyHandler?(SocketAnyEvent(event: event, items: data)) - - for handler in self.handlers where handler.event == event { - handler.executeCallback(data, withAck: ack, withSocket: self) - } - } - + } } /** From 15cfba46bc117bfda40c4f2ac018829c822dfd32 Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 16 Jan 2016 15:16:18 -0500 Subject: [PATCH 12/19] refactor didError --- SocketIO-MacTests/SocketSideEffectTest.swift | 12 ++++++++++++ Source/SocketClientSpec.swift | 7 +++---- Source/SocketParsable.swift | 2 +- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/SocketIO-MacTests/SocketSideEffectTest.swift b/SocketIO-MacTests/SocketSideEffectTest.swift index 6bae725..ba2d795 100644 --- a/SocketIO-MacTests/SocketSideEffectTest.swift +++ b/SocketIO-MacTests/SocketSideEffectTest.swift @@ -100,6 +100,18 @@ class SocketSideEffectTest: XCTestCase { XCTAssertEqual(socket.testHandlers.count, 1) } + func testHandlesErrorPacket() { + let expectation = expectationWithDescription("Handled error") + socket.on("error") {data, ack in + if let error = data[0] as? String where error == "test error" { + expectation.fulfill() + } + } + + socket.parseSocketMessage("4\"test error\"") + waitForExpectationsWithTimeout(3, handler: nil) + } + func testHandleBinaryEvent() { let expectation = expectationWithDescription("handled binary event") socket.on("test") {data, ack in diff --git a/Source/SocketClientSpec.swift b/Source/SocketClientSpec.swift index 7a72cad..6408f39 100644 --- a/Source/SocketClientSpec.swift +++ b/Source/SocketClientSpec.swift @@ -28,17 +28,16 @@ protocol SocketClientSpec: class { func didConnect() func didDisconnect(reason: String) - func didError(reason: AnyObject) + func didError(reason: String) func handleAck(ack: Int, data: [AnyObject]) func handleEvent(event: String, data: [AnyObject], isInternalMessage: Bool, withAck ack: Int) func joinNamespace(namespace: String) } extension SocketClientSpec { - func didError(reason: AnyObject) { + func didError(reason: String) { DefaultSocketLogger.Logger.error("%@", type: "SocketIOClient", args: reason) - handleEvent("error", data: reason as? [AnyObject] ?? [reason], - isInternalMessage: true, withAck: -1) + handleEvent("error", data: [reason], isInternalMessage: true, withAck: -1) } } diff --git a/Source/SocketParsable.swift b/Source/SocketParsable.swift index 35117ef..f7304c4 100644 --- a/Source/SocketParsable.swift +++ b/Source/SocketParsable.swift @@ -58,7 +58,7 @@ extension SocketParsable { case .Disconnect: didDisconnect("Got Disconnect") case .Error: - didError(pack.data) + handleEvent("error", data: pack.data, isInternalMessage: false, withAck: pack.id) default: DefaultSocketLogger.Logger.log("Got invalid packet: %@", type: "SocketParser", args: pack.description) } From ec67056d2a4652c3d98a811ef12173388691861f Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 16 Jan 2016 16:38:10 -0500 Subject: [PATCH 13/19] change method signature --- Source/SocketEngineClient.swift | 2 +- Source/SocketIOClient.swift | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Source/SocketEngineClient.swift b/Source/SocketEngineClient.swift index f2b997c..a1db7f6 100644 --- a/Source/SocketEngineClient.swift +++ b/Source/SocketEngineClient.swift @@ -26,7 +26,7 @@ import Foundation @objc public protocol SocketEngineClient { - func engineDidError(reason: AnyObject) + func engineDidError(reason: String) func engineDidClose(reason: String) optional func engineDidOpen(reason: String) func parseEngineMessage(msg: String) diff --git a/Source/SocketIOClient.swift b/Source/SocketIOClient.swift index 1b0228a..c4369df 100644 --- a/Source/SocketIOClient.swift +++ b/Source/SocketIOClient.swift @@ -311,11 +311,10 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable } /// error - public func engineDidError(reason: AnyObject) { + public func engineDidError(reason: String) { DefaultSocketLogger.Logger.error("%@", type: logType, args: reason) - handleEvent("error", data: reason as? [AnyObject] ?? [reason], - isInternalMessage: true) + handleEvent("error", data: [reason], isInternalMessage: true) } // Called when the socket gets an ack for something it sent From 024384dc822ec1f802b02ef316af9acb4901db6d Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 16 Jan 2016 16:40:50 -0500 Subject: [PATCH 14/19] change close method of engine --- Source/SocketEngine.swift | 4 ++-- Source/SocketEngineSpec.swift | 2 +- Source/SocketIOClient.swift | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Source/SocketEngine.swift b/Source/SocketEngine.swift index 8bfd8a1..fec7df4 100644 --- a/Source/SocketEngine.swift +++ b/Source/SocketEngine.swift @@ -163,7 +163,7 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb } } - public func close() { + public func close(reason: String) { DefaultSocketLogger.Logger.log("Engine is being closed.", type: logType) pingTimer?.invalidate() @@ -179,7 +179,7 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb ws?.disconnect() stopPolling() - client?.engineDidClose("Disconnect") + client?.engineDidClose(reason) } private func createURLs(params: [String: AnyObject]?) -> (String, String) { diff --git a/Source/SocketEngineSpec.swift b/Source/SocketEngineSpec.swift index f60fc52..a12c323 100644 --- a/Source/SocketEngineSpec.swift +++ b/Source/SocketEngineSpec.swift @@ -48,7 +48,7 @@ import Foundation init(client: SocketEngineClient, url: String, options: NSDictionary?) - func close() + func close(reason: String) func didError(error: String) func doFastUpgrade() func flushWaitingForPostToWebSocket() diff --git a/Source/SocketIOClient.swift b/Source/SocketIOClient.swift index c4369df..57a1bcd 100644 --- a/Source/SocketIOClient.swift +++ b/Source/SocketIOClient.swift @@ -109,7 +109,7 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable deinit { DefaultSocketLogger.Logger.log("Client is being deinit", type: logType) - engine?.close() + engine?.close("Client Deinit") } private func addEngine() -> SocketEngineSpec { @@ -172,7 +172,7 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable dispatch_after(time, handleQueue) {[weak self] in if let this = self where this.status != .Connected { this.status = .Closed - this.engine?.close() + this.engine?.close("Connect timeout") handler?() } @@ -223,7 +223,7 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable reconnects = false // Make sure the engine is actually dead. - engine?.close() + engine?.close("Client closed") handleEvent("disconnect", data: [reason], isInternalMessage: true) } From d6c521123b8064b25e51b6d1bbb557258dca85b7 Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 16 Jan 2016 17:23:07 -0500 Subject: [PATCH 15/19] refactor closing engine --- Source/SocketEngine.swift | 56 +++++++++++++------------- Source/SocketEnginePollable.swift | 67 +++++++++++++++++-------------- 2 files changed, 64 insertions(+), 59 deletions(-) diff --git a/Source/SocketEngine.swift b/Source/SocketEngine.swift index fec7df4..6e16ed5 100644 --- a/Source/SocketEngine.swift +++ b/Source/SocketEngine.swift @@ -132,8 +132,7 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb case 0: // Unknown transport didError(error) case 1: // Unknown sid. clear and retry connect - sid = "" - open(connectParams) + didError(error) case 2: // Bad handshake request didError(error) case 3: // Bad request @@ -164,22 +163,29 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb } public func close(reason: String) { - DefaultSocketLogger.Logger.log("Engine is being closed.", type: logType) - - pingTimer?.invalidate() - closed = true - invalidated = true - connected = false - - if websocket { - sendWebSocketMessage("", withType: .Close, withData: []) - } else { - sendPollMessage("", withType: .Close, withData: []) + func postSendClose(data: NSData?, _ res: NSURLResponse?, _ err: NSError?) { + sid = "" + closed = true + invalidated = true + connected = false + + pingTimer?.invalidate() + ws?.disconnect() + stopPolling() + client?.engineDidClose(reason) } - ws?.disconnect() - stopPolling() - client?.engineDidClose(reason) + DefaultSocketLogger.Logger.log("Engine is being closed.", type: logType) + + if websocket { + sendWebSocketMessage("", withType: .Close, withData: []) + postSendClose(nil, nil, nil) + } else { + // We need to take special care when we're polling that we send it ASAP + postWait.append("1") + let req = createRequestForPostWithPostWait() + doRequest(req, withCallback: postSendClose) + } } private func createURLs(params: [String: AnyObject]?) -> (String, String) { @@ -250,14 +256,9 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb } public func didError(error: String) { - connected = false - ws?.disconnect() - stopPolling() - pingTimer?.invalidate() - DefaultSocketLogger.Logger.error(error, type: logType) client?.engineDidError(error) - client?.engineDidClose(error) + close(error) } public func doFastUpgrade() { @@ -364,15 +365,14 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb } } - public func open(opts: [String: AnyObject]? = nil) { - connectParams = opts - + public func open(opts: [String: AnyObject]?) { if connected { - DefaultSocketLogger.Logger.error("Tried to open while connected", type: logType) - didError("Tried to open engine while connected") - + DefaultSocketLogger.Logger.error("Engine tried opening while connected. This is probably a programming error. " + + "Abandoning open attempt", type: logType) return } + + connectParams = opts DefaultSocketLogger.Logger.log("Starting engine", type: logType) DefaultSocketLogger.Logger.log("Handshaking", type: logType) diff --git a/Source/SocketEnginePollable.swift b/Source/SocketEnginePollable.swift index 0da2ed9..46c8ea0 100644 --- a/Source/SocketEnginePollable.swift +++ b/Source/SocketEnginePollable.swift @@ -58,6 +58,33 @@ extension SocketEnginePollable { } } + func createRequestForPostWithPostWait() -> NSURLRequest { + var postStr = "" + + for packet in postWait { + let len = packet.characters.count + + postStr += "\(len):\(packet)" + } + + postWait.removeAll(keepCapacity: false) + + let req = NSMutableURLRequest(URL: NSURL(string: urlPolling + "&sid=\(sid)")!) + + addHeaders(req) + + req.HTTPMethod = "POST" + req.setValue("text/plain; charset=UTF-8", forHTTPHeaderField: "Content-Type") + + let postData = postStr.dataUsingEncoding(NSUTF8StringEncoding, + allowLossyConversion: false)! + + req.HTTPBody = postData + req.setValue(String(postData.length), forHTTPHeaderField: "Content-Length") + + return req + } + public func doPoll() { if websocket || waitingForPoll || !connected || closed { return @@ -70,10 +97,9 @@ extension SocketEnginePollable { doLongPoll(req) } - private func doRequest(req: NSURLRequest, - withCallback callback: (NSData?, NSURLResponse?, NSError?) -> Void) { + func doRequest(req: NSURLRequest, withCallback callback: (NSData?, NSURLResponse?, NSError?) -> Void) { if !polling || closed || invalidated { - DefaultSocketLogger.Logger.error("Tried to do polling request when not supposed to", type: "SocketEngine") + DefaultSocketLogger.Logger.error("Tried to do polling request when not supposed to", type: "SocketEnginePolling") return } @@ -87,7 +113,7 @@ extension SocketEnginePollable { guard let this = self else {return} if err != nil || data == nil { - DefaultSocketLogger.Logger.error(err?.localizedDescription ?? "Error", type: "SocketEngine") + DefaultSocketLogger.Logger.error(err?.localizedDescription ?? "Error", type: "SocketEnginePolling") if this.polling { this.didError(err?.localizedDescription ?? "Error") @@ -96,7 +122,7 @@ extension SocketEnginePollable { return } - DefaultSocketLogger.Logger.log("Got polling response", type: "SocketEngine") + DefaultSocketLogger.Logger.log("Got polling response", type: "SocketEnginePolling") if let str = String(data: data!, encoding: NSUTF8StringEncoding) { dispatch_async(this.parseQueue) { @@ -122,38 +148,17 @@ extension SocketEnginePollable { return } - var postStr = "" - - for packet in postWait { - let len = packet.characters.count - - postStr += "\(len):\(packet)" - } - - postWait.removeAll(keepCapacity: false) - - let req = NSMutableURLRequest(URL: NSURL(string: urlPolling + "&sid=\(sid)")!) - - addHeaders(req) - - req.HTTPMethod = "POST" - req.setValue("text/plain; charset=UTF-8", forHTTPHeaderField: "Content-Type") - - let postData = postStr.dataUsingEncoding(NSUTF8StringEncoding, - allowLossyConversion: false)! - - req.HTTPBody = postData - req.setValue(String(postData.length), forHTTPHeaderField: "Content-Length") + let req = createRequestForPostWithPostWait() waitingForPost = true - DefaultSocketLogger.Logger.log("POSTing: %@", type: "SocketEngine", args: postStr) + DefaultSocketLogger.Logger.log("POSTing: %@", type: "SocketEngine", args: postWait) doRequest(req) {[weak self] data, res, err in - guard let this = self else {return} + guard let this = self else { return } if err != nil { - DefaultSocketLogger.Logger.error(err?.localizedDescription ?? "Error", type: "SocketEngine") + DefaultSocketLogger.Logger.error(err?.localizedDescription ?? "Error", type: "SocketEnginePolling") if this.polling { this.didError(err?.localizedDescription ?? "Error") @@ -199,7 +204,7 @@ extension SocketEnginePollable { /// Send polling message. /// Only call on emitQueue public func sendPollMessage(message: String, withType type: SocketEnginePacketType, withData datas: [NSData]) { - DefaultSocketLogger.Logger.log("Sending poll: %@ as type: %@", type: "SocketEngine", args: message, type.rawValue) + DefaultSocketLogger.Logger.log("Sending poll: %@ as type: %@", type: "SocketEnginePolling", args: message, type.rawValue) let fixedMessage = doubleEncodeUTF8(message) let strMsg = "\(type.rawValue)\(fixedMessage)" From 67f47ad6fe33f06c64c309592dac83a137e80509 Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 16 Jan 2016 17:37:17 -0500 Subject: [PATCH 16/19] tweak logging --- Source/SocketEngine.swift | 2 +- Source/SocketEnginePollable.swift | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Source/SocketEngine.swift b/Source/SocketEngine.swift index 6e16ed5..666f8d4 100644 --- a/Source/SocketEngine.swift +++ b/Source/SocketEngine.swift @@ -182,7 +182,7 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb postSendClose(nil, nil, nil) } else { // We need to take special care when we're polling that we send it ASAP - postWait.append("1") + postWait.append(String(SocketEnginePacketType.Close.rawValue)) let req = createRequestForPostWithPostWait() doRequest(req, withCallback: postSendClose) } diff --git a/Source/SocketEnginePollable.swift b/Source/SocketEnginePollable.swift index 46c8ea0..cd8e512 100644 --- a/Source/SocketEnginePollable.swift +++ b/Source/SocketEnginePollable.swift @@ -67,6 +67,8 @@ extension SocketEnginePollable { postStr += "\(len):\(packet)" } + DefaultSocketLogger.Logger.log("Created POST string: %@", type: "SocketEnginePolling", args: postStr) + postWait.removeAll(keepCapacity: false) let req = NSMutableURLRequest(URL: NSURL(string: urlPolling + "&sid=\(sid)")!) @@ -103,7 +105,7 @@ extension SocketEnginePollable { return } - DefaultSocketLogger.Logger.log("Doing polling request", type: "SocketEngine") + DefaultSocketLogger.Logger.log("Doing polling request", type: "SocketEnginePolling") session?.dataTaskWithRequest(req, completionHandler: callback).resume() } @@ -152,7 +154,7 @@ extension SocketEnginePollable { waitingForPost = true - DefaultSocketLogger.Logger.log("POSTing: %@", type: "SocketEngine", args: postWait) + DefaultSocketLogger.Logger.log("POSTing", type: "SocketEnginePolling") doRequest(req) {[weak self] data, res, err in guard let this = self else { return } From 88b1eb1948cc328ce920de7e585cb3e2931e40c9 Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 16 Jan 2016 19:51:21 -0500 Subject: [PATCH 17/19] going to remove close() --- Source/SocketIOClient.swift | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/Source/SocketIOClient.swift b/Source/SocketIOClient.swift index 57a1bcd..d275d37 100644 --- a/Source/SocketIOClient.swift +++ b/Source/SocketIOClient.swift @@ -125,16 +125,9 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable reconnectTimer = nil } - /** - Closes the socket. Only reopen the same socket if you know what you're doing. - Will turn off automatic reconnects. - Pass true to fast if you're closing from a background task - */ + @available(*, deprecated=6.0) public func close() { - DefaultSocketLogger.Logger.log("Closing socket", type: logType) - - reconnects = false - didDisconnect("Closed") + disconnect() } /** @@ -228,10 +221,14 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable } /** - Same as close + Closes the socket. Only reopen the same socket if you know what you're doing. + Will turn off automatic reconnects. */ public func disconnect() { - close() + DefaultSocketLogger.Logger.log("Closing socket", type: logType) + + reconnects = false + didDisconnect("Closed") } /** From 95d2dce641d290efad25d346dd9723e372cede59 Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 16 Jan 2016 19:53:00 -0500 Subject: [PATCH 18/19] bump version --- README.md | 6 +++--- Socket.IO-Client-Swift.podspec | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 41383c7..bb7bac2 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ Carthage ----------------- Add this line to your `Cartfile`: ``` -github "socketio/socket.io-client-swift" ~> 5.0.0 # Or latest version +github "socketio/socket.io-client-swift" ~> 5.1.0 # Or latest version ``` Run `carthage update --platform ios,macosx`. @@ -99,7 +99,7 @@ source 'https://github.com/CocoaPods/Specs.git' platform :ios, '8.0' use_frameworks! -pod 'Socket.IO-Client-Swift', '~> 5.0.0' # Or latest version +pod 'Socket.IO-Client-Swift', '~> 5.1.0' # Or latest version ``` Install pods: @@ -127,7 +127,7 @@ CocoaSeeds Add this line to your `Seedfile`: ``` -github "socketio/socket.io-client-swift", "v5.0.0", :files => "SocketIOClientSwift/*.swift" # Or latest version +github "socketio/socket.io-client-swift", "v5.1.0", :files => "SocketIOClientSwift/*.swift" # Or latest version ``` Run `seed install`. diff --git a/Socket.IO-Client-Swift.podspec b/Socket.IO-Client-Swift.podspec index dc14c44..8e59980 100644 --- a/Socket.IO-Client-Swift.podspec +++ b/Socket.IO-Client-Swift.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "Socket.IO-Client-Swift" - s.version = "5.0.0" + s.version = "5.1.0" s.summary = "Socket.IO-client for iOS and OS X" s.description = <<-DESC Socket.IO-client for iOS and OS X. @@ -13,7 +13,7 @@ Pod::Spec.new do |s| s.ios.deployment_target = '8.0' s.osx.deployment_target = '10.10' s.tvos.deployment_target = '9.0' - s.source = { :git => "https://github.com/socketio/socket.io-client-swift.git", :tag => 'v5.0.0' } + s.source = { :git => "https://github.com/socketio/socket.io-client-swift.git", :tag => 'v5.1.0' } s.source_files = "Source/**/*.swift" s.requires_arc = true # s.dependency 'Starscream', '~> 0.9' # currently this repo includes Starscream swift files From a9633510ff987c1b7f4dc17c26d1512d8d8bf33c Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 16 Jan 2016 19:56:03 -0500 Subject: [PATCH 19/19] update readme to reflect close being deprecated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bb7bac2..03364ff 100644 --- a/README.md +++ b/README.md @@ -176,7 +176,7 @@ Methods 7. `emitWithAck(event: String, withItems items: [AnyObject]) -> (UInt64, (NSArray?) -> Void) -> Void` - `emitWithAck` for Objective-C. Note: The message is not sent until you call the returned function. 8. `connect()` - Establishes a connection to the server. A "connect" event is fired upon successful connection. 9. `connect(timeoutAfter timeoutAfter: Int, withTimeoutHandler handler: (() -> Void)?)` - Connect to the server. If it isn't connected after timeoutAfter seconds, the handler is called. -10. `close()` - Closes the socket. Once a socket is closed it should not be reopened. +10. `disconnect()` - Closes the socket. Reopening a disconnected socket is not fully tested. 11. `reconnect()` - Causes the client to reconnect to the server. 12. `joinNamespace(namespace: String)` - Causes the client to join namespace. Shouldn't need to be called unless you change namespaces manually. 13. `leaveNamespace()` - Causes the client to leave the nsp and go back to /