From bfe54f8df7d24d8b9e1ee2e9695f2f1da9a06601 Mon Sep 17 00:00:00 2001 From: Erik Date: Wed, 7 Oct 2015 11:16:35 -0400 Subject: [PATCH] start work on seperating socket client and engine so they can be tested --- .../project.pbxproj | 20 ++++++ SocketIOClientSwift/SocketEngine.swift | 68 ++++++++----------- .../SocketEnginePacketType.swift | 38 +++++++++++ SocketIOClientSwift/SocketEngineSpec.swift | 45 ++++++++++++ SocketIOClientSwift/SocketIOClient.swift | 10 ++- 5 files changed, 135 insertions(+), 46 deletions(-) create mode 100644 SocketIOClientSwift/SocketEnginePacketType.swift create mode 100644 SocketIOClientSwift/SocketEngineSpec.swift diff --git a/Socket.IO-Client-Swift.xcodeproj/project.pbxproj b/Socket.IO-Client-Swift.xcodeproj/project.pbxproj index 1445694..6268aef 100644 --- a/Socket.IO-Client-Swift.xcodeproj/project.pbxproj +++ b/Socket.IO-Client-Swift.xcodeproj/project.pbxproj @@ -75,6 +75,14 @@ 74D765621B9F0D870028551C /* SocketStringReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74D765611B9F0D870028551C /* SocketStringReader.swift */; }; 74D765631B9F0D9F0028551C /* SocketStringReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74D765611B9F0D870028551C /* SocketStringReader.swift */; }; 74D765641B9F0DA40028551C /* SocketStringReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74D765611B9F0D870028551C /* SocketStringReader.swift */; }; + 74F124E31BC5697B002966F4 /* SocketEngineSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74F124E21BC5697B002966F4 /* SocketEngineSpec.swift */; settings = {ASSET_TAGS = (); }; }; + 74F124E41BC5697B002966F4 /* SocketEngineSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74F124E21BC5697B002966F4 /* SocketEngineSpec.swift */; settings = {ASSET_TAGS = (); }; }; + 74F124E51BC5697B002966F4 /* SocketEngineSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74F124E21BC5697B002966F4 /* SocketEngineSpec.swift */; settings = {ASSET_TAGS = (); }; }; + 74F124E61BC5697B002966F4 /* SocketEngineSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74F124E21BC5697B002966F4 /* SocketEngineSpec.swift */; settings = {ASSET_TAGS = (); }; }; + 74F124E81BC56BFC002966F4 /* SocketEnginePacketType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74F124E71BC56BFC002966F4 /* SocketEnginePacketType.swift */; settings = {ASSET_TAGS = (); }; }; + 74F124E91BC56BFC002966F4 /* SocketEnginePacketType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74F124E71BC56BFC002966F4 /* SocketEnginePacketType.swift */; settings = {ASSET_TAGS = (); }; }; + 74F124EA1BC56BFC002966F4 /* SocketEnginePacketType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74F124E71BC56BFC002966F4 /* SocketEnginePacketType.swift */; settings = {ASSET_TAGS = (); }; }; + 74F124EB1BC56BFC002966F4 /* SocketEnginePacketType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74F124E71BC56BFC002966F4 /* SocketEnginePacketType.swift */; settings = {ASSET_TAGS = (); }; }; 941A4ABA1B67A56C00C42318 /* TestKind.swift in Sources */ = {isa = PBXBuildFile; fileRef = 941A4AB91B67A56C00C42318 /* TestKind.swift */; }; 94242BB81B67B0E500AAAC9D /* SocketNamespaceAcknowledgementTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94242BB71B67B0E500AAAC9D /* SocketNamespaceAcknowledgementTest.swift */; }; 945B65351B5FCEEA0081E995 /* SocketAckManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF7C1B51F254004FF46E /* SocketAckManager.swift */; }; @@ -147,6 +155,8 @@ 74781D591B7E83930042CACA /* SocketIOClientStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketIOClientStatus.swift; path = SocketIOClientSwift/SocketIOClientStatus.swift; sourceTree = ""; }; 749A7F8A1BA9D42D00782993 /* SocketAckEmitter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketAckEmitter.swift; path = SocketIOClientSwift/SocketAckEmitter.swift; sourceTree = ""; }; 74D765611B9F0D870028551C /* SocketStringReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SocketStringReader.swift; path = SocketIOClientSwift/SocketStringReader.swift; sourceTree = ""; }; + 74F124E21BC5697B002966F4 /* SocketEngineSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketEngineSpec.swift; path = SocketIOClientSwift/SocketEngineSpec.swift; sourceTree = ""; }; + 74F124E71BC56BFC002966F4 /* SocketEnginePacketType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketEnginePacketType.swift; path = SocketIOClientSwift/SocketEnginePacketType.swift; sourceTree = ""; }; 941A4AB91B67A56C00C42318 /* TestKind.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestKind.swift; path = "../SocketIO-iOSTests/TestKind.swift"; sourceTree = ""; }; 94242BB71B67B0E500AAAC9D /* SocketNamespaceAcknowledgementTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketNamespaceAcknowledgementTest.swift; path = "../SocketIO-iOSTests/SocketNamespaceAcknowledgementTest.swift"; sourceTree = ""; }; 945B65421B63D9DB0081E995 /* SocketEmitTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketEmitTest.swift; path = "../SocketIO-iOSTests/SocketEmitTest.swift"; sourceTree = ""; }; @@ -302,6 +312,8 @@ 5764DF7D1B51F254004FF46E /* SocketAnyEvent.swift */, 5764DF7E1B51F254004FF46E /* SocketEngine.swift */, 5764DF7F1B51F254004FF46E /* SocketEngineClient.swift */, + 74F124E71BC56BFC002966F4 /* SocketEnginePacketType.swift */, + 74F124E21BC5697B002966F4 /* SocketEngineSpec.swift */, 5764DF801B51F254004FF46E /* SocketEventHandler.swift */, 5764DF811B51F254004FF46E /* SocketFixUTF8.swift */, 5764DF821B51F254004FF46E /* SocketIOClient.swift */, @@ -504,7 +516,9 @@ 74781D5A1B7E83930042CACA /* SocketIOClientStatus.swift in Sources */, 5764DFA11B51F254004FF46E /* WebSocket.swift in Sources */, 5764DF991B51F254004FF46E /* SocketPacket.swift in Sources */, + 74F124E31BC5697B002966F4 /* SocketEngineSpec.swift in Sources */, 5764DF891B51F254004FF46E /* SocketAckManager.swift in Sources */, + 74F124E81BC56BFC002966F4 /* SocketEnginePacketType.swift in Sources */, 5764DF9F1B51F254004FF46E /* SwiftRegex.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -528,6 +542,7 @@ 945B65401B5FCEEA0081E995 /* SwiftRegex.swift in Sources */, 945B653C1B5FCEEA0081E995 /* SocketLogger.swift in Sources */, 94A20D611B99E22F00BF9E44 /* SocketAckManagerTest.swift in Sources */, + 74F124E41BC5697B002966F4 /* SocketEngineSpec.swift in Sources */, 945B65381B5FCEEA0081E995 /* SocketEngineClient.swift in Sources */, 945B65361B5FCEEA0081E995 /* SocketAnyEvent.swift in Sources */, 94ADAC4B1B6632DD00FD79AE /* SocketAcknowledgementTest.swift in Sources */, @@ -537,6 +552,7 @@ 949FAE8D1B9B94E600073BE9 /* SocketParserTest.swift in Sources */, 94ADAC491B652D3300FD79AE /* SocketNamespaceEmitTest.swift in Sources */, 945B65411B5FCEEA0081E995 /* WebSocket.swift in Sources */, + 74F124E91BC56BFC002966F4 /* SocketEnginePacketType.swift in Sources */, 94242BB81B67B0E500AAAC9D /* SocketNamespaceAcknowledgementTest.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -559,7 +575,9 @@ 74781D5C1B7E83930042CACA /* SocketIOClientStatus.swift in Sources */, 5764DFA21B51F254004FF46E /* WebSocket.swift in Sources */, 5764DF9A1B51F254004FF46E /* SocketPacket.swift in Sources */, + 74F124E51BC5697B002966F4 /* SocketEngineSpec.swift in Sources */, 5764DF8A1B51F254004FF46E /* SocketAckManager.swift in Sources */, + 74F124EA1BC56BFC002966F4 /* SocketEnginePacketType.swift in Sources */, 5764DFA01B51F254004FF46E /* SwiftRegex.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -571,6 +589,7 @@ 743AC4231BB9C032009F615E /* SocketPollingNamespaceAcknowledgementTest.swift in Sources */, 7472A5E11BB6ECE800CD4F59 /* SocketAckManager.swift in Sources */, 7472A5E21BB6ECE800CD4F59 /* SocketAnyEvent.swift in Sources */, + 74F124E61BC5697B002966F4 /* SocketEngineSpec.swift in Sources */, 7472A5E31BB6ECE800CD4F59 /* SocketEngine.swift in Sources */, 7472A5E41BB6ECE800CD4F59 /* SocketEngineClient.swift in Sources */, 7472A5E51BB6ECE800CD4F59 /* SocketEventHandler.swift in Sources */, @@ -594,6 +613,7 @@ 743AC41F1BB9B07C009F615E /* SocketPollingAcknowledgementTest.swift in Sources */, 743AC41D1BB9A7A7009F615E /* SocketPollingEmitTest.swift in Sources */, 7458953F1BB59A0A0050ACC8 /* AbstractSocketTest.swift in Sources */, + 74F124EB1BC56BFC002966F4 /* SocketEnginePacketType.swift in Sources */, 745895401BB59A0A0050ACC8 /* TestKind.swift in Sources */, 749A7F901BA9D42D00782993 /* SocketAckEmitter.swift in Sources */, 74781D5D1B7E83930042CACA /* SocketIOClientStatus.swift in Sources */, diff --git a/SocketIOClientSwift/SocketEngine.swift b/SocketIOClientSwift/SocketEngine.swift index 57f58b0..cb28042 100644 --- a/SocketIOClientSwift/SocketEngine.swift +++ b/SocketIOClientSwift/SocketEngine.swift @@ -24,8 +24,17 @@ import Foundation -public final class SocketEngine: NSObject, WebSocketDelegate { - private typealias Probe = (msg: String, type: PacketType, data: [NSData]?) +public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate { + public private(set) var sid = "" + public private(set) var cookies: [NSHTTPCookie]? + public private(set) var socketPath = "" + public private(set) var urlPolling = "" + public private(set) var urlWebSocket = "" + public private(set) var ws: WebSocket? + + public weak var client: SocketEngineClient? + + private typealias Probe = (msg: String, type: SocketEnginePacketType, data: [NSData]?) private typealias ProbeWaitQueue = [Probe] private let allowedCharacterSet = NSCharacterSet(charactersInString: "!*'();:@&=+$,/?%#[]\" {}").invertedSet @@ -62,27 +71,6 @@ public final class SocketEngine: NSObject, WebSocketDelegate { private(set) var polling = true private(set) var websocket = false - weak var client: SocketEngineClient? - var cookies: [NSHTTPCookie]? - var sid = "" - var socketPath = "" - var urlPolling = "" - var urlWebSocket = "" - - var ws: WebSocket? - - @objc public enum PacketType: Int { - case Open, Close, Ping, Pong, Message, Upgrade, Noop - - init?(str: String) { - if let value = Int(str), raw = PacketType(rawValue: value) { - self = raw - } else { - return nil - } - } - } - public init(client: SocketEngineClient, sessionDelegate: NSURLSessionDelegate?) { self.client = client self.session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration(), @@ -126,7 +114,7 @@ public final class SocketEngine: NSObject, WebSocketDelegate { ws?.disconnect() if fast || polling { - write("", withType: PacketType.Close, withData: nil) + write("", withType: .Close, withData: nil) client?.engineDidClose("Disconnect") } @@ -223,7 +211,7 @@ public final class SocketEngine: NSObject, WebSocketDelegate { "we'll probably disconnect soon. You should report this.", type: logType) } - sendWebSocketMessage("", withType: PacketType.Upgrade, datas: nil) + sendWebSocketMessage("", withType: .Upgrade, datas: nil) websocket = true polling = false fastUpgrade = false @@ -534,23 +522,23 @@ public final class SocketEngine: NSObject, WebSocketDelegate { fixDoubleUTF8(&message) } - let type = PacketType(str: (message["^(\\d)"].groups()?[1]) ?? "") ?? { + let type = SocketEnginePacketType(str: (message["^(\\d)"].groups()?[1]) ?? "") ?? { self.checkIfMessageIsBase64Binary(message) return .Noop }() switch type { - case PacketType.Message: + case .Message: message.removeAtIndex(message.startIndex) handleMessage(message) - case PacketType.Noop: + case .Noop: handleNOOP() - case PacketType.Pong: + case .Pong: handlePong(message) - case PacketType.Open: + case .Open: message.removeAtIndex(message.startIndex) handleOpen(message) - case PacketType.Close: + case .Close: handleClose() default: Logger.log("Got unknown packet type", type: logType) @@ -559,16 +547,16 @@ public final class SocketEngine: NSObject, WebSocketDelegate { private func probeWebSocket() { if websocketConnected { - sendWebSocketMessage("probe", withType: PacketType.Ping) + sendWebSocketMessage("probe", withType: .Ping) } } /// Send an engine message (4) public func send(msg: String, withData datas: [NSData]?) { if probing { - probeWait.append((msg, PacketType.Message, datas)) + probeWait.append((msg, .Message, datas)) } else { - write(msg, withType: PacketType.Message, withData: datas) + write(msg, withType: .Message, withData: datas) } } @@ -581,12 +569,12 @@ public final class SocketEngine: NSObject, WebSocketDelegate { } ++pongsMissed - write("", withType: PacketType.Ping, withData: nil) + write("", withType: .Ping, withData: nil) } /// Send polling message. /// Only call on emitQueue - private func sendPollMessage(var msg: String, withType type: PacketType, + private func sendPollMessage(var msg: String, withType type: SocketEnginePacketType, datas:[NSData]? = nil) { Logger.log("Sending poll: %@ as type: %@", type: logType, args: msg, type.rawValue) @@ -608,7 +596,7 @@ public final class SocketEngine: NSObject, WebSocketDelegate { /// Send message on WebSockets /// Only call on emitQueue - private func sendWebSocketMessage(str: String, withType type: PacketType, + private func sendWebSocketMessage(str: String, withType type: SocketEnginePacketType, datas:[NSData]? = nil) { Logger.log("Sending ws: %@ as type: %@", type: logType, args: str, type.rawValue) @@ -634,7 +622,7 @@ public final class SocketEngine: NSObject, WebSocketDelegate { } } - func stopPolling() { + public func stopPolling() { invalidated = true session.finishTasksAndInvalidate() } @@ -644,7 +632,7 @@ public final class SocketEngine: NSObject, WebSocketDelegate { Logger.log("Upgrading transport to WebSockets", type: logType) fastUpgrade = true - sendPollMessage("", withType: PacketType.Noop) + sendPollMessage("", withType: .Noop) // After this point, we should not send anymore polling messages } } @@ -652,7 +640,7 @@ public final class SocketEngine: NSObject, WebSocketDelegate { /** Write a message, independent of transport. */ - public func write(msg: String, withType type: PacketType, withData data: [NSData]?) { + public func write(msg: String, withType type: SocketEnginePacketType, withData data: [NSData]?) { dispatch_async(emitQueue) { if self.connected { if self.websocket { diff --git a/SocketIOClientSwift/SocketEnginePacketType.swift b/SocketIOClientSwift/SocketEnginePacketType.swift new file mode 100644 index 0000000..5bbd690 --- /dev/null +++ b/SocketIOClientSwift/SocketEnginePacketType.swift @@ -0,0 +1,38 @@ +// +// SocketEnginePacketType.swift +// Socket.IO-Client-Swift +// +// Created by Erik Little on 10/7/15. +// +// 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 + +@objc public enum SocketEnginePacketType: Int { + case Open, Close, Ping, Pong, Message, Upgrade, Noop + + init?(str: String) { + if let value = Int(str), raw = SocketEnginePacketType(rawValue: value) { + self = raw + } else { + return nil + } + } +} \ No newline at end of file diff --git a/SocketIOClientSwift/SocketEngineSpec.swift b/SocketIOClientSwift/SocketEngineSpec.swift new file mode 100644 index 0000000..2423174 --- /dev/null +++ b/SocketIOClientSwift/SocketEngineSpec.swift @@ -0,0 +1,45 @@ +// +// SocketEngineSpec.swift +// Socket.IO-Client-Swift +// +// Created by Erik Little on 10/7/15. +// +// 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 + +@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} + var ws: WebSocket? {get} + + init(client: SocketEngineClient, sessionDelegate: NSURLSessionDelegate?) + init(client: SocketEngineClient, opts: NSDictionary?) + + func close(fast fast: Bool) + func open(opts: [String: AnyObject]?) + func send(msg: String, withData datas: [NSData]?) + func stopPolling() + func write(msg: String, withType type: SocketEnginePacketType, withData data: [NSData]?) +} diff --git a/SocketIOClientSwift/SocketIOClient.swift b/SocketIOClientSwift/SocketIOClient.swift index 86831eb..29c6a7d 100644 --- a/SocketIOClientSwift/SocketIOClient.swift +++ b/SocketIOClientSwift/SocketIOClient.swift @@ -25,12 +25,9 @@ import Foundation public final class SocketIOClient: NSObject, SocketEngineClient { - private let emitQueue = dispatch_queue_create("com.socketio.emitQueue", DISPATCH_QUEUE_SERIAL) - private let handleQueue: dispatch_queue_t! - public let socketURL: String - public private(set) var engine: SocketEngine? + public private(set) var engine: SocketEngineSpec? public private(set) var secure = false public private(set) var status = SocketIOClientStatus.NotConnected @@ -42,15 +39,16 @@ public final class SocketIOClient: NSObject, SocketEngineClient { return engine?.sid } + private let emitQueue = dispatch_queue_create("com.socketio.emitQueue", DISPATCH_QUEUE_SERIAL) + private let handleQueue: dispatch_queue_t! private let logType = "SocketIOClient" + private let reconnectAttempts: Int! private var anyHandler: ((SocketAnyEvent) -> Void)? private var currentReconnectAttempt = 0 private var handlers = ContiguousArray() private var connectParams: [String: AnyObject]? private var reconnectTimer: NSTimer? - - private let reconnectAttempts: Int! private var ackHandlers = SocketAckManager() private var currentAck = -1