Add SocketManager for multiplexing namespaces
This commit is contained in:
		
							parent
							
								
									1ed87e571d
								
							
						
					
					
						commit
						5b52edd880
					
				
							
								
								
									
										18
									
								
								CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					# v13.0.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					What's new:
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-Adds a new `SocketManager` class that multiplexes multiple namespaces through a single engine. 
 | 
				
			||||||
 | 
					- Adds `.sentPing` and `.gotPong` client events for tracking ping/pongs.
 | 
				
			||||||
 | 
					- watchOS support.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Important API changes
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Many properties that were previously on `SocketIOClient` have been moved to the `SocketManager`.
 | 
				
			||||||
 | 
					- `SocketIOClientOption.nsp` has been removed. Use `SocketManager.socket(forNamespace:)` to create/get a socket attached to a specific namespace.
 | 
				
			||||||
 | 
					- Adds `.sentPing` and `.gotPong` client events for tracking ping/pongs.
 | 
				
			||||||
 | 
					- Makes the framework a single target.
 | 
				
			||||||
 | 
					- Updates Starscream to 3.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										20
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								README.md
									
									
									
									
									
								
							@ -7,20 +7,21 @@ Socket.IO-client for iOS/OS X.
 | 
				
			|||||||
```swift
 | 
					```swift
 | 
				
			||||||
import SocketIO
 | 
					import SocketIO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let socket = SocketIOClient(socketURL: URL(string: "http://localhost:8080")!, config: [.log(true), .compress])
 | 
					let manager = SocketManager(socketURL: URL(string: "http://localhost:8080")!, config: [.log(true), .compress])
 | 
				
			||||||
 | 
					let socket = manager.defaultSocket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
socket.on(clientEvent: .connect) {data, ack in
 | 
					socket.on(clientEvent: .connect) {data, ack in
 | 
				
			||||||
    print("socket connected")
 | 
					    print("socket connected")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
socket.on("currentAmount") {data, ack in
 | 
					socket.on("currentAmount") {data, ack in
 | 
				
			||||||
    if let cur = data[0] as? Double {
 | 
					    guard let cur = data[0] as? Double else { return }
 | 
				
			||||||
        socket.emitWithAck("canUpdate", cur).timingOut(after: 0) {data in
 | 
					    
 | 
				
			||||||
            socket.emit("update", ["amount": cur + 2.50])
 | 
					    socket.emitWithAck("canUpdate", cur).timingOut(after: 0) {data in
 | 
				
			||||||
        }
 | 
					        socket.emit("update", ["amount": cur + 2.50])
 | 
				
			||||||
 | 
					 | 
				
			||||||
        ack.with("Got your currentAmount", "dude")
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ack.with("Got your currentAmount", "dude")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
socket.connect()
 | 
					socket.connect()
 | 
				
			||||||
@ -29,8 +30,10 @@ socket.connect()
 | 
				
			|||||||
## Objective-C Example
 | 
					## Objective-C Example
 | 
				
			||||||
```objective-c
 | 
					```objective-c
 | 
				
			||||||
@import SocketIO;
 | 
					@import SocketIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
NSURL* url = [[NSURL alloc] initWithString:@"http://localhost:8080"];
 | 
					NSURL* url = [[NSURL alloc] initWithString:@"http://localhost:8080"];
 | 
				
			||||||
SocketIOClient* socket = [[SocketIOClient alloc] initWithSocketURL:url config:@{@"log": @YES, @"compress": @YES}];
 | 
					SocketManager* manager = [[SocketManager alloc] initWithSocketURL:url config:@{@"log": @YES, @"compress": @YES}];
 | 
				
			||||||
 | 
					SocketIOClient* socket = manager.defaultSocket;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[socket on:@"connect" callback:^(NSArray* data, SocketAckEmitter* ack) {
 | 
					[socket on:@"connect" callback:^(NSArray* data, SocketAckEmitter* ack) {
 | 
				
			||||||
    NSLog(@"socket connected");
 | 
					    NSLog(@"socket connected");
 | 
				
			||||||
@ -134,6 +137,7 @@ Objective-C:
 | 
				
			|||||||
# [Docs](https://nuclearace.github.io/Socket.IO-Client-Swift/index.html)
 | 
					# [Docs](https://nuclearace.github.io/Socket.IO-Client-Swift/index.html)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- [Client](https://nuclearace.github.io/Socket.IO-Client-Swift/Classes/SocketIOClient.html)
 | 
					- [Client](https://nuclearace.github.io/Socket.IO-Client-Swift/Classes/SocketIOClient.html)
 | 
				
			||||||
 | 
					- [Manager](https://nuclearace.github.io/Socket.IO-Client-Swift/Classes/SocketManager.html)
 | 
				
			||||||
- [Engine](https://nuclearace.github.io/Socket.IO-Client-Swift/Classes/SocketEngine.html)
 | 
					- [Engine](https://nuclearace.github.io/Socket.IO-Client-Swift/Classes/SocketEngine.html)
 | 
				
			||||||
- [Options](https://nuclearace.github.io/Socket.IO-Client-Swift/Enums/SocketIOClientOption.html)
 | 
					- [Options](https://nuclearace.github.io/Socket.IO-Client-Swift/Enums/SocketIOClientOption.html)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -7,6 +7,8 @@
 | 
				
			|||||||
	objects = {
 | 
						objects = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Begin PBXBuildFile section */
 | 
					/* Begin PBXBuildFile section */
 | 
				
			||||||
 | 
							1C6572803D7E252A77A86E5F /* SocketManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C65763817782DFAC67BE05C /* SocketManager.swift */; };
 | 
				
			||||||
 | 
							1C657FBB3F670261780FD72E /* SocketManagerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C6574AF9687A213814753E4 /* SocketManagerSpec.swift */; };
 | 
				
			||||||
		1C686BE21F869AFD007D8627 /* SocketIOClientConfigurationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C686BD21F869AF1007D8627 /* SocketIOClientConfigurationTest.swift */; };
 | 
							1C686BE21F869AFD007D8627 /* SocketIOClientConfigurationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C686BD21F869AF1007D8627 /* SocketIOClientConfigurationTest.swift */; };
 | 
				
			||||||
		1C686BE31F869AFD007D8627 /* SocketEngineTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C686BD31F869AF1007D8627 /* SocketEngineTest.swift */; };
 | 
							1C686BE31F869AFD007D8627 /* SocketEngineTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C686BD31F869AF1007D8627 /* SocketEngineTest.swift */; };
 | 
				
			||||||
		1C686BE41F869AFD007D8627 /* SocketSideEffectTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C686BD41F869AF1007D8627 /* SocketSideEffectTest.swift */; };
 | 
							1C686BE41F869AFD007D8627 /* SocketSideEffectTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C686BD41F869AF1007D8627 /* SocketSideEffectTest.swift */; };
 | 
				
			||||||
@ -30,17 +32,18 @@
 | 
				
			|||||||
		DD52B3A6C1E082841C35C85D /* SocketEngineClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52BE5FDCE1D684132E897C /* SocketEngineClient.swift */; };
 | 
							DD52B3A6C1E082841C35C85D /* SocketEngineClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52BE5FDCE1D684132E897C /* SocketEngineClient.swift */; };
 | 
				
			||||||
		DD52B44AE56F2E07F3F3F991 /* SocketAckManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52B09F7984E730513AB7E5 /* SocketAckManager.swift */; };
 | 
							DD52B44AE56F2E07F3F3F991 /* SocketAckManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52B09F7984E730513AB7E5 /* SocketAckManager.swift */; };
 | 
				
			||||||
		DD52B4DFA12F2599410205D9 /* SocketEngineWebsocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52BE9AD8B2BD7F841CD1D4 /* SocketEngineWebsocket.swift */; };
 | 
							DD52B4DFA12F2599410205D9 /* SocketEngineWebsocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52BE9AD8B2BD7F841CD1D4 /* SocketEngineWebsocket.swift */; };
 | 
				
			||||||
 | 
							DD52B53F2609D91A683DFCDD /* ManagerObjectiveCTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DD52BB5E907D283ACC31E17F /* ManagerObjectiveCTest.m */; };
 | 
				
			||||||
		DD52B56DE03CDB4F40BD1A23 /* SocketExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52B471D780013E18DF9335 /* SocketExtensions.swift */; };
 | 
							DD52B56DE03CDB4F40BD1A23 /* SocketExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52B471D780013E18DF9335 /* SocketExtensions.swift */; };
 | 
				
			||||||
		DD52B57E7ABC61B57EE2A4B8 /* SocketPacket.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52B59C11D3D2BC63612E50 /* SocketPacket.swift */; };
 | 
							DD52B57E7ABC61B57EE2A4B8 /* SocketPacket.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52B59C11D3D2BC63612E50 /* SocketPacket.swift */; };
 | 
				
			||||||
		DD52B660D63B6A25C3755AA7 /* SocketClientManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52B282975446C9A9C56D7B /* SocketClientManager.swift */; };
 | 
					 | 
				
			||||||
		DD52B883F942CD5A9D29892B /* SocketEnginePollable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52B2D110F55723F82B108E /* SocketEnginePollable.swift */; };
 | 
							DD52B883F942CD5A9D29892B /* SocketEnginePollable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52B2D110F55723F82B108E /* SocketEnginePollable.swift */; };
 | 
				
			||||||
		DD52B9412F660F828B683422 /* SocketParsable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52B31D0E6815F5F10CEFB6 /* SocketParsable.swift */; };
 | 
							DD52B9412F660F828B683422 /* SocketParsable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52B31D0E6815F5F10CEFB6 /* SocketParsable.swift */; };
 | 
				
			||||||
		DD52BB69B6D260035B652CA4 /* SocketAnyEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52B5A9DE10C7A8AD35617F /* SocketAnyEvent.swift */; };
 | 
							DD52BB69B6D260035B652CA4 /* SocketAnyEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52B5A9DE10C7A8AD35617F /* SocketAnyEvent.swift */; };
 | 
				
			||||||
		DD52BB82239886CF6ADD642C /* SocketEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52B7A9779A2E08075E5AAC /* SocketEngine.swift */; };
 | 
							DD52BB82239886CF6ADD642C /* SocketEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52B7A9779A2E08075E5AAC /* SocketEngine.swift */; };
 | 
				
			||||||
		DD52BB9A3E42FF2DD6BE7C2F /* SocketIOClientSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52BCAF915A546288664346 /* SocketIOClientSpec.swift */; };
 | 
							DD52BB9A3E42FF2DD6BE7C2F /* SocketIOClientSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52BCAF915A546288664346 /* SocketIOClientSpec.swift */; };
 | 
				
			||||||
		DD52BC3F1F880820E8FDFD0C /* SocketLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52BED81BF312B0E90E92AC /* SocketLogger.swift */; };
 | 
							DD52BC3F1F880820E8FDFD0C /* SocketLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52BED81BF312B0E90E92AC /* SocketLogger.swift */; };
 | 
				
			||||||
 | 
							DD52BCCD25EFA76E0F9B313C /* SocketMangerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52BBAC5FAA7730D32CD5BF /* SocketMangerTest.swift */; };
 | 
				
			||||||
		DD52BD065B74AC5B77BAEFAA /* SocketIOClientConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52B57FFEE8560CFFD793B3 /* SocketIOClientConfiguration.swift */; };
 | 
							DD52BD065B74AC5B77BAEFAA /* SocketIOClientConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52B57FFEE8560CFFD793B3 /* SocketIOClientConfiguration.swift */; };
 | 
				
			||||||
		DD52BE4D1E6BB752CD9614A6 /* SocketIOClientStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52B1D9BC4AE46D38D827DE /* SocketIOClientStatus.swift */; };
 | 
							DD52BE4D1E6BB752CD9614A6 /* SocketIOStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52B1D9BC4AE46D38D827DE /* SocketIOStatus.swift */; };
 | 
				
			||||||
		DD52BF924BEF05E1235CFD29 /* SocketIOClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52BA1F41F2E4B3DC20260E /* SocketIOClient.swift */; };
 | 
							DD52BF924BEF05E1235CFD29 /* SocketIOClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52BA1F41F2E4B3DC20260E /* SocketIOClient.swift */; };
 | 
				
			||||||
		DD52BFBC9E7CC32D3515AC80 /* SocketEngineSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52B645273A873667BC2D43 /* SocketEngineSpec.swift */; };
 | 
							DD52BFBC9E7CC32D3515AC80 /* SocketEngineSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52B645273A873667BC2D43 /* SocketEngineSpec.swift */; };
 | 
				
			||||||
		DD52BFEB4DBD3BF8D93DAEFF /* SocketEventHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52B6DCCBBAC6BE9C22568D /* SocketEventHandler.swift */; };
 | 
							DD52BFEB4DBD3BF8D93DAEFF /* SocketEventHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD52B6DCCBBAC6BE9C22568D /* SocketEventHandler.swift */; };
 | 
				
			||||||
@ -57,6 +60,8 @@
 | 
				
			|||||||
/* End PBXContainerItemProxy section */
 | 
					/* End PBXContainerItemProxy section */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Begin PBXFileReference section */
 | 
					/* Begin PBXFileReference section */
 | 
				
			||||||
 | 
							1C6574AF9687A213814753E4 /* SocketManagerSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketManagerSpec.swift; sourceTree = "<group>"; };
 | 
				
			||||||
 | 
							1C65763817782DFAC67BE05C /* SocketManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketManager.swift; sourceTree = "<group>"; };
 | 
				
			||||||
		1C686BD21F869AF1007D8627 /* SocketIOClientConfigurationTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketIOClientConfigurationTest.swift; sourceTree = "<group>"; };
 | 
							1C686BD21F869AF1007D8627 /* SocketIOClientConfigurationTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketIOClientConfigurationTest.swift; sourceTree = "<group>"; };
 | 
				
			||||||
		1C686BD31F869AF1007D8627 /* SocketEngineTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketEngineTest.swift; sourceTree = "<group>"; };
 | 
							1C686BD31F869AF1007D8627 /* SocketEngineTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketEngineTest.swift; sourceTree = "<group>"; };
 | 
				
			||||||
		1C686BD41F869AF1007D8627 /* SocketSideEffectTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketSideEffectTest.swift; sourceTree = "<group>"; };
 | 
							1C686BD41F869AF1007D8627 /* SocketSideEffectTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketSideEffectTest.swift; sourceTree = "<group>"; };
 | 
				
			||||||
@ -83,8 +88,8 @@
 | 
				
			|||||||
		9432E00D1F77F889006AF628 /* Starscream.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Starscream.framework; path = Carthage/Build/tvOS/Starscream.framework; sourceTree = "<group>"; };
 | 
							9432E00D1F77F889006AF628 /* Starscream.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Starscream.framework; path = Carthage/Build/tvOS/Starscream.framework; sourceTree = "<group>"; };
 | 
				
			||||||
		DD52B078DB0A3C3D1BB507CD /* SocketIOClientOption.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketIOClientOption.swift; sourceTree = "<group>"; };
 | 
							DD52B078DB0A3C3D1BB507CD /* SocketIOClientOption.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketIOClientOption.swift; sourceTree = "<group>"; };
 | 
				
			||||||
		DD52B09F7984E730513AB7E5 /* SocketAckManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketAckManager.swift; sourceTree = "<group>"; };
 | 
							DD52B09F7984E730513AB7E5 /* SocketAckManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketAckManager.swift; sourceTree = "<group>"; };
 | 
				
			||||||
		DD52B1D9BC4AE46D38D827DE /* SocketIOClientStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketIOClientStatus.swift; sourceTree = "<group>"; };
 | 
							DD52B1D9BC4AE46D38D827DE /* SocketIOStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketIOStatus.swift; sourceTree = "<group>"; };
 | 
				
			||||||
		DD52B282975446C9A9C56D7B /* SocketClientManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketClientManager.swift; sourceTree = "<group>"; };
 | 
							DD52B2C54A6ADF3371C13DCB /* SocketObjectiveCTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SocketObjectiveCTest.h; sourceTree = "<group>"; };
 | 
				
			||||||
		DD52B2D110F55723F82B108E /* SocketEnginePollable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketEnginePollable.swift; sourceTree = "<group>"; };
 | 
							DD52B2D110F55723F82B108E /* SocketEnginePollable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketEnginePollable.swift; sourceTree = "<group>"; };
 | 
				
			||||||
		DD52B31D0E6815F5F10CEFB6 /* SocketParsable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketParsable.swift; sourceTree = "<group>"; };
 | 
							DD52B31D0E6815F5F10CEFB6 /* SocketParsable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketParsable.swift; sourceTree = "<group>"; };
 | 
				
			||||||
		DD52B471D780013E18DF9335 /* SocketExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketExtensions.swift; sourceTree = "<group>"; };
 | 
							DD52B471D780013E18DF9335 /* SocketExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketExtensions.swift; sourceTree = "<group>"; };
 | 
				
			||||||
@ -95,8 +100,11 @@
 | 
				
			|||||||
		DD52B645273A873667BC2D43 /* SocketEngineSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketEngineSpec.swift; sourceTree = "<group>"; };
 | 
							DD52B645273A873667BC2D43 /* SocketEngineSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketEngineSpec.swift; sourceTree = "<group>"; };
 | 
				
			||||||
		DD52B6DCCBBAC6BE9C22568D /* SocketEventHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketEventHandler.swift; sourceTree = "<group>"; };
 | 
							DD52B6DCCBBAC6BE9C22568D /* SocketEventHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketEventHandler.swift; sourceTree = "<group>"; };
 | 
				
			||||||
		DD52B7A9779A2E08075E5AAC /* SocketEngine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketEngine.swift; sourceTree = "<group>"; };
 | 
							DD52B7A9779A2E08075E5AAC /* SocketEngine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketEngine.swift; sourceTree = "<group>"; };
 | 
				
			||||||
 | 
							DD52B8396C7DEE7BFD6A985A /* ManagerObjectiveCTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ManagerObjectiveCTest.h; sourceTree = "<group>"; };
 | 
				
			||||||
		DD52BA1F41F2E4B3DC20260E /* SocketIOClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketIOClient.swift; sourceTree = "<group>"; };
 | 
							DD52BA1F41F2E4B3DC20260E /* SocketIOClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketIOClient.swift; sourceTree = "<group>"; };
 | 
				
			||||||
		DD52BA240D139F72633D4159 /* SocketStringReader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketStringReader.swift; sourceTree = "<group>"; };
 | 
							DD52BA240D139F72633D4159 /* SocketStringReader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketStringReader.swift; sourceTree = "<group>"; };
 | 
				
			||||||
 | 
							DD52BB5E907D283ACC31E17F /* ManagerObjectiveCTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ManagerObjectiveCTest.m; sourceTree = "<group>"; };
 | 
				
			||||||
 | 
							DD52BBAC5FAA7730D32CD5BF /* SocketMangerTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketMangerTest.swift; sourceTree = "<group>"; };
 | 
				
			||||||
		DD52BCAF915A546288664346 /* SocketIOClientSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketIOClientSpec.swift; sourceTree = "<group>"; };
 | 
							DD52BCAF915A546288664346 /* SocketIOClientSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketIOClientSpec.swift; sourceTree = "<group>"; };
 | 
				
			||||||
		DD52BDC9E66AADA2CC5E8246 /* SocketTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketTypes.swift; sourceTree = "<group>"; };
 | 
							DD52BDC9E66AADA2CC5E8246 /* SocketTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketTypes.swift; sourceTree = "<group>"; };
 | 
				
			||||||
		DD52BE5FDCE1D684132E897C /* SocketEngineClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketEngineClient.swift; sourceTree = "<group>"; };
 | 
							DD52BE5FDCE1D684132E897C /* SocketEngineClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketEngineClient.swift; sourceTree = "<group>"; };
 | 
				
			||||||
@ -128,6 +136,16 @@
 | 
				
			|||||||
/* End PBXFrameworksBuildPhase section */
 | 
					/* End PBXFrameworksBuildPhase section */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Begin PBXGroup section */
 | 
					/* Begin PBXGroup section */
 | 
				
			||||||
 | 
							1C657951DEA2E0293D0FD1B6 /* Manager */ = {
 | 
				
			||||||
 | 
								isa = PBXGroup;
 | 
				
			||||||
 | 
								children = (
 | 
				
			||||||
 | 
									1C65763817782DFAC67BE05C /* SocketManager.swift */,
 | 
				
			||||||
 | 
									1C6574AF9687A213814753E4 /* SocketManagerSpec.swift */,
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
								name = Manager;
 | 
				
			||||||
 | 
								path = Source/SocketIO/Manager;
 | 
				
			||||||
 | 
								sourceTree = "<group>";
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
		1C686BD11F869AF1007D8627 /* TestSocketIO */ = {
 | 
							1C686BD11F869AF1007D8627 /* TestSocketIO */ = {
 | 
				
			||||||
			isa = PBXGroup;
 | 
								isa = PBXGroup;
 | 
				
			||||||
			children = (
 | 
								children = (
 | 
				
			||||||
@ -138,6 +156,7 @@
 | 
				
			|||||||
				1C686BD61F869AF1007D8627 /* SocketAckManagerTest.swift */,
 | 
									1C686BD61F869AF1007D8627 /* SocketAckManagerTest.swift */,
 | 
				
			||||||
				1C686BD71F869AF1007D8627 /* SocketParserTest.swift */,
 | 
									1C686BD71F869AF1007D8627 /* SocketParserTest.swift */,
 | 
				
			||||||
				1C686BD81F869AF1007D8627 /* SocketNamespacePacketTest.swift */,
 | 
									1C686BD81F869AF1007D8627 /* SocketNamespacePacketTest.swift */,
 | 
				
			||||||
 | 
									DD52BBAC5FAA7730D32CD5BF /* SocketMangerTest.swift */,
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
			name = TestSocketIO;
 | 
								name = TestSocketIO;
 | 
				
			||||||
			path = Tests/TestSocketIO;
 | 
								path = Tests/TestSocketIO;
 | 
				
			||||||
@ -147,6 +166,9 @@
 | 
				
			|||||||
			isa = PBXGroup;
 | 
								isa = PBXGroup;
 | 
				
			||||||
			children = (
 | 
								children = (
 | 
				
			||||||
				1C686BFE1F869E9D007D8627 /* SocketObjectiveCTest.m */,
 | 
									1C686BFE1F869E9D007D8627 /* SocketObjectiveCTest.m */,
 | 
				
			||||||
 | 
									DD52BB5E907D283ACC31E17F /* ManagerObjectiveCTest.m */,
 | 
				
			||||||
 | 
									DD52B8396C7DEE7BFD6A985A /* ManagerObjectiveCTest.h */,
 | 
				
			||||||
 | 
									DD52B2C54A6ADF3371C13DCB /* SocketObjectiveCTest.h */,
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
			name = TestSocketIOObjc;
 | 
								name = TestSocketIOObjc;
 | 
				
			||||||
			path = Tests/TestSocketIOObjc;
 | 
								path = Tests/TestSocketIOObjc;
 | 
				
			||||||
@ -198,6 +220,7 @@
 | 
				
			|||||||
				DD52B6A0966AF71393777311 /* Client */,
 | 
									DD52B6A0966AF71393777311 /* Client */,
 | 
				
			||||||
				DD52B1D10D761CEF3944A6BC /* Util */,
 | 
									DD52B1D10D761CEF3944A6BC /* Util */,
 | 
				
			||||||
				DD52B647ED881F3FF6EEC617 /* Parse */,
 | 
									DD52B647ED881F3FF6EEC617 /* Parse */,
 | 
				
			||||||
 | 
									1C657951DEA2E0293D0FD1B6 /* Manager */,
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
			name = Source;
 | 
								name = Source;
 | 
				
			||||||
			sourceTree = "<group>";
 | 
								sourceTree = "<group>";
 | 
				
			||||||
@ -251,7 +274,6 @@
 | 
				
			|||||||
				DD52BED81BF312B0E90E92AC /* SocketLogger.swift */,
 | 
									DD52BED81BF312B0E90E92AC /* SocketLogger.swift */,
 | 
				
			||||||
				DD52B471D780013E18DF9335 /* SocketExtensions.swift */,
 | 
									DD52B471D780013E18DF9335 /* SocketExtensions.swift */,
 | 
				
			||||||
				DD52BA240D139F72633D4159 /* SocketStringReader.swift */,
 | 
									DD52BA240D139F72633D4159 /* SocketStringReader.swift */,
 | 
				
			||||||
				DD52B282975446C9A9C56D7B /* SocketClientManager.swift */,
 | 
					 | 
				
			||||||
				9432E0061F77F7CA006AF628 /* SSLSecurity.swift */,
 | 
									9432E0061F77F7CA006AF628 /* SSLSecurity.swift */,
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
			name = Util;
 | 
								name = Util;
 | 
				
			||||||
@ -276,7 +298,7 @@
 | 
				
			|||||||
				DD52B6DCCBBAC6BE9C22568D /* SocketEventHandler.swift */,
 | 
									DD52B6DCCBBAC6BE9C22568D /* SocketEventHandler.swift */,
 | 
				
			||||||
				DD52BCAF915A546288664346 /* SocketIOClientSpec.swift */,
 | 
									DD52BCAF915A546288664346 /* SocketIOClientSpec.swift */,
 | 
				
			||||||
				DD52B078DB0A3C3D1BB507CD /* SocketIOClientOption.swift */,
 | 
									DD52B078DB0A3C3D1BB507CD /* SocketIOClientOption.swift */,
 | 
				
			||||||
				DD52B1D9BC4AE46D38D827DE /* SocketIOClientStatus.swift */,
 | 
									DD52B1D9BC4AE46D38D827DE /* SocketIOStatus.swift */,
 | 
				
			||||||
				DD52B57FFEE8560CFFD793B3 /* SocketIOClientConfiguration.swift */,
 | 
									DD52B57FFEE8560CFFD793B3 /* SocketIOClientConfiguration.swift */,
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
			name = Client;
 | 
								name = Client;
 | 
				
			||||||
@ -448,15 +470,16 @@
 | 
				
			|||||||
				9432E00F1F77F8C4006AF628 /* SSLSecurity.swift in Sources */,
 | 
									9432E00F1F77F8C4006AF628 /* SSLSecurity.swift in Sources */,
 | 
				
			||||||
				DD52BB9A3E42FF2DD6BE7C2F /* SocketIOClientSpec.swift in Sources */,
 | 
									DD52BB9A3E42FF2DD6BE7C2F /* SocketIOClientSpec.swift in Sources */,
 | 
				
			||||||
				DD52B2AFE7D46039C7AE4D19 /* SocketIOClientOption.swift in Sources */,
 | 
									DD52B2AFE7D46039C7AE4D19 /* SocketIOClientOption.swift in Sources */,
 | 
				
			||||||
				DD52BE4D1E6BB752CD9614A6 /* SocketIOClientStatus.swift in Sources */,
 | 
									DD52BE4D1E6BB752CD9614A6 /* SocketIOStatus.swift in Sources */,
 | 
				
			||||||
				DD52BD065B74AC5B77BAEFAA /* SocketIOClientConfiguration.swift in Sources */,
 | 
									DD52BD065B74AC5B77BAEFAA /* SocketIOClientConfiguration.swift in Sources */,
 | 
				
			||||||
				DD52B048C71D724ABBD18C71 /* SocketTypes.swift in Sources */,
 | 
									DD52B048C71D724ABBD18C71 /* SocketTypes.swift in Sources */,
 | 
				
			||||||
				DD52BC3F1F880820E8FDFD0C /* SocketLogger.swift in Sources */,
 | 
									DD52BC3F1F880820E8FDFD0C /* SocketLogger.swift in Sources */,
 | 
				
			||||||
				DD52B56DE03CDB4F40BD1A23 /* SocketExtensions.swift in Sources */,
 | 
									DD52B56DE03CDB4F40BD1A23 /* SocketExtensions.swift in Sources */,
 | 
				
			||||||
				DD52B11AF936352BAE30B2C8 /* SocketStringReader.swift in Sources */,
 | 
									DD52B11AF936352BAE30B2C8 /* SocketStringReader.swift in Sources */,
 | 
				
			||||||
				DD52B660D63B6A25C3755AA7 /* SocketClientManager.swift in Sources */,
 | 
					 | 
				
			||||||
				DD52B57E7ABC61B57EE2A4B8 /* SocketPacket.swift in Sources */,
 | 
									DD52B57E7ABC61B57EE2A4B8 /* SocketPacket.swift in Sources */,
 | 
				
			||||||
				DD52B9412F660F828B683422 /* SocketParsable.swift in Sources */,
 | 
									DD52B9412F660F828B683422 /* SocketParsable.swift in Sources */,
 | 
				
			||||||
 | 
									1C6572803D7E252A77A86E5F /* SocketManager.swift in Sources */,
 | 
				
			||||||
 | 
									1C657FBB3F670261780FD72E /* SocketManagerSpec.swift in Sources */,
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
			runOnlyForDeploymentPostprocessing = 0;
 | 
								runOnlyForDeploymentPostprocessing = 0;
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
@ -472,6 +495,8 @@
 | 
				
			|||||||
				1C686BE61F869AFD007D8627 /* SocketAckManagerTest.swift in Sources */,
 | 
									1C686BE61F869AFD007D8627 /* SocketAckManagerTest.swift in Sources */,
 | 
				
			||||||
				1C686BE71F869AFD007D8627 /* SocketParserTest.swift in Sources */,
 | 
									1C686BE71F869AFD007D8627 /* SocketParserTest.swift in Sources */,
 | 
				
			||||||
				1C686BE81F869AFD007D8627 /* SocketNamespacePacketTest.swift in Sources */,
 | 
									1C686BE81F869AFD007D8627 /* SocketNamespacePacketTest.swift in Sources */,
 | 
				
			||||||
 | 
									DD52BCCD25EFA76E0F9B313C /* SocketMangerTest.swift in Sources */,
 | 
				
			||||||
 | 
									DD52B53F2609D91A683DFCDD /* ManagerObjectiveCTest.m in Sources */,
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
			runOnlyForDeploymentPostprocessing = 0;
 | 
								runOnlyForDeploymentPostprocessing = 0;
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
 | 
				
			|||||||
@ -120,8 +120,10 @@ public final class OnAckCallback : NSObject {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        guard seconds != 0 else { return }
 | 
					        guard seconds != 0 else { return }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        socket.handleQueue.asyncAfter(deadline: DispatchTime.now() + seconds) {
 | 
					        socket.manager?.handleQueue.asyncAfter(deadline: DispatchTime.now() + seconds) {[weak socket] in
 | 
				
			||||||
            socket.ackHandlers.timeoutAck(self.ackNumber, onQueue: socket.handleQueue)
 | 
					            guard let socket = socket, let manager = socket.manager else { return }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            socket.ackHandlers.timeoutAck(self.ackNumber, onQueue: manager.handleQueue)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -25,110 +25,52 @@
 | 
				
			|||||||
import Dispatch
 | 
					import Dispatch
 | 
				
			||||||
import Foundation
 | 
					import Foundation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// The main class for SocketIOClientSwift.
 | 
					/// Represents a socket.io-client.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// **NOTE**: The client is not thread/queue safe, all interaction with the socket should be done on the `handleQueue`
 | 
					/// Clients are created through a `SocketManager`, which owns the `SocketEngineSpec` that controls the connection to the server.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// Represents a socket.io-client. Most interaction with socket.io will be through this class.
 | 
					/// For example:
 | 
				
			||||||
open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, SocketParsable {
 | 
					///
 | 
				
			||||||
 | 
					/// ```swift
 | 
				
			||||||
 | 
					/// // Create a socket for the /swift namespace
 | 
				
			||||||
 | 
					/// let socket = manager.socket(forNamespace: "/swift")
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// // Add some handlers and connect
 | 
				
			||||||
 | 
					/// ```
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// **NOTE**: The client is not thread/queue safe, all interaction with the socket should be done on the `manager.handleQueue`
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					open class SocketIOClient : NSObject, SocketIOClientSpec {
 | 
				
			||||||
    // MARK: Properties
 | 
					    // MARK: Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static let logType = "SocketIOClient"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// If `true` then every time `connect` is called, a new engine will be created.
 | 
					 | 
				
			||||||
    @objc
 | 
					 | 
				
			||||||
    public var forceNew = false
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// The queue that all interaction with the client should occur on. This is the queue that event handlers are
 | 
					 | 
				
			||||||
    /// called on.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// **This should be a serial queue! Concurrent queues are not supported and might cause crashes and races**.
 | 
					 | 
				
			||||||
    @objc
 | 
					 | 
				
			||||||
    public var handleQueue = DispatchQueue.main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// The namespace that this socket is currently connected to.
 | 
					    /// The namespace that this socket is currently connected to.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// **Must** start with a `/`.
 | 
					    /// **Must** start with a `/`.
 | 
				
			||||||
    @objc
 | 
					    @objc
 | 
				
			||||||
    public var nsp = "/"
 | 
					    public var nsp = "/"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// The configuration for this client.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// **This cannot be set after calling one of the connect methods**.
 | 
					 | 
				
			||||||
    public var config: SocketIOClientConfiguration {
 | 
					 | 
				
			||||||
        get {
 | 
					 | 
				
			||||||
            return _config
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        set {
 | 
					 | 
				
			||||||
            guard status == .notConnected else {
 | 
					 | 
				
			||||||
                DefaultSocketLogger.Logger.error("Tried setting config after calling connect",
 | 
					 | 
				
			||||||
                                                 type: SocketIOClient.logType)
 | 
					 | 
				
			||||||
                return
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            _config = newValue
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if socketURL.absoluteString.hasPrefix("https://") {
 | 
					 | 
				
			||||||
                _config.insert(.secure(true))
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            _config.insert(.path("/socket.io/"), replacing: false)
 | 
					 | 
				
			||||||
            setConfigs()
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// If `true`, this client will try and reconnect on any disconnects.
 | 
					 | 
				
			||||||
    @objc
 | 
					 | 
				
			||||||
    public var reconnects = true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// The number of seconds to wait before attempting to reconnect.
 | 
					 | 
				
			||||||
    @objc
 | 
					 | 
				
			||||||
    public var reconnectWait = 10
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// The session id of this client.
 | 
					    /// The session id of this client.
 | 
				
			||||||
    @objc
 | 
					    @objc
 | 
				
			||||||
    public var sid: String? {
 | 
					    public var sid: String {
 | 
				
			||||||
        return engine?.sid
 | 
					        guard let engine = manager?.engine else { return "" }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return nsp == "/" ? engine.sid : "\(nsp)#\(engine.sid)"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// The URL of the socket.io server.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// If changed after calling `init`, `forceNew` must be set to `true`, or it will only connect to the url set in the
 | 
					 | 
				
			||||||
    /// init.
 | 
					 | 
				
			||||||
    @objc
 | 
					 | 
				
			||||||
    public var socketURL: URL
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// A list of packets that are waiting for binary data.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// The way that socket.io works all data should be sent directly after each packet.
 | 
					 | 
				
			||||||
    /// So this should ideally be an array of one packet waiting for data.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// **This should not be modified directly.**
 | 
					 | 
				
			||||||
    public var waitingPackets = [SocketPacket]()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// A handler that will be called on any event.
 | 
					    /// A handler that will be called on any event.
 | 
				
			||||||
    public private(set) var anyHandler: ((SocketAnyEvent) -> ())?
 | 
					    public private(set) var anyHandler: ((SocketAnyEvent) -> ())?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// The engine for this client.
 | 
					 | 
				
			||||||
    @objc
 | 
					 | 
				
			||||||
    public internal(set) var engine: SocketEngineSpec?
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// The array of handlers for this socket.
 | 
					    /// The array of handlers for this socket.
 | 
				
			||||||
    public private(set) var handlers = [SocketEventHandler]()
 | 
					    public private(set) var handlers = [SocketEventHandler]()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// The manager for this socket.
 | 
				
			||||||
 | 
					    @objc
 | 
				
			||||||
 | 
					    public private(set) weak var manager: SocketManagerSpec?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// The status of this client.
 | 
					    /// The status of this client.
 | 
				
			||||||
    @objc
 | 
					    @objc
 | 
				
			||||||
    public private(set) var status = SocketIOClientStatus.notConnected {
 | 
					    public private(set) var status = SocketIOStatus.notConnected {
 | 
				
			||||||
        didSet {
 | 
					        didSet {
 | 
				
			||||||
            switch status {
 | 
					 | 
				
			||||||
            case .connected:
 | 
					 | 
				
			||||||
                reconnecting = false
 | 
					 | 
				
			||||||
                currentReconnectAttempt = 0
 | 
					 | 
				
			||||||
            default:
 | 
					 | 
				
			||||||
                break
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            handleClientEvent(.statusChange, data: [status])
 | 
					            handleClientEvent(.statusChange, data: [status])
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -136,60 +78,29 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So
 | 
				
			|||||||
    var ackHandlers = SocketAckManager()
 | 
					    var ackHandlers = SocketAckManager()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private(set) var currentAck = -1
 | 
					    private(set) var currentAck = -1
 | 
				
			||||||
    private(set) var reconnectAttempts = -1
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private var _config: SocketIOClientConfiguration
 | 
					    private lazy var logType = "SocketIOClient{\(nsp)}"
 | 
				
			||||||
    private var currentReconnectAttempt = 0
 | 
					 | 
				
			||||||
    private var reconnecting = false
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // MARK: Initializers
 | 
					    // MARK: Initializers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Type safe way to create a new SocketIOClient. `opts` can be omitted.
 | 
					    /// Type safe way to create a new SocketIOClient. `opts` can be omitted.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
 | 
					    /// - parameter manager: The manager for this socket.
 | 
				
			||||||
    /// - parameter socketURL: The url of the socket.io server.
 | 
					    /// - parameter socketURL: The url of the socket.io server.
 | 
				
			||||||
    /// - parameter config: The config for this socket.
 | 
					    @objc
 | 
				
			||||||
    public init(socketURL: URL, config: SocketIOClientConfiguration = []) {
 | 
					    public init(manager: SocketManagerSpec, nsp: String) {
 | 
				
			||||||
        self._config = config
 | 
					        self.manager = manager
 | 
				
			||||||
        self.socketURL = socketURL
 | 
					        self.nsp = nsp
 | 
				
			||||||
 | 
					 | 
				
			||||||
        if socketURL.absoluteString.hasPrefix("https://") {
 | 
					 | 
				
			||||||
            self._config.insert(.secure(true))
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self._config.insert(.path("/socket.io/"), replacing: false)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        super.init()
 | 
					        super.init()
 | 
				
			||||||
 | 
					 | 
				
			||||||
        setConfigs()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Not so type safe way to create a SocketIOClient, meant for Objective-C compatiblity.
 | 
					 | 
				
			||||||
    /// If using Swift it's recommended to use `init(socketURL: NSURL, options: Set<SocketIOClientOption>)`
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// - parameter socketURL: The url of the socket.io server.
 | 
					 | 
				
			||||||
    /// - parameter config: The config for this socket.
 | 
					 | 
				
			||||||
    @objc
 | 
					 | 
				
			||||||
    public convenience init(socketURL: NSURL, config: NSDictionary?) {
 | 
					 | 
				
			||||||
        self.init(socketURL: socketURL as URL, config: config?.toSocketConfiguration() ?? [])
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    deinit {
 | 
					    deinit {
 | 
				
			||||||
        DefaultSocketLogger.Logger.log("Client is being released", type: SocketIOClient.logType)
 | 
					        DefaultSocketLogger.Logger.log("Client is being released", type: logType)
 | 
				
			||||||
        engine?.disconnect(reason: "Client Deinit")
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // MARK: Methods
 | 
					    // MARK: Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private func addEngine() {
 | 
					 | 
				
			||||||
        DefaultSocketLogger.Logger.log("Adding engine", type: SocketIOClient.logType)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        engine?.engineQueue.sync {
 | 
					 | 
				
			||||||
            self.engine?.client = nil
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        engine = SocketEngine(client: self, url: socketURL, config: config)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Connect to the server. The same as calling `connect(timeoutAfter:withHandler:)` with a timeout of 0.
 | 
					    /// Connect to the server. The same as calling `connect(timeoutAfter:withHandler:)` with a timeout of 0.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// Only call after adding your event listeners, unless you know what you're doing.
 | 
					    /// Only call after adding your event listeners, unless you know what you're doing.
 | 
				
			||||||
@ -209,27 +120,22 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So
 | 
				
			|||||||
    open func connect(timeoutAfter: Double, withHandler handler: (() -> ())?) {
 | 
					    open func connect(timeoutAfter: Double, withHandler handler: (() -> ())?) {
 | 
				
			||||||
        assert(timeoutAfter >= 0, "Invalid timeout: \(timeoutAfter)")
 | 
					        assert(timeoutAfter >= 0, "Invalid timeout: \(timeoutAfter)")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        guard status != .connected else {
 | 
					        guard let manager = self.manager, status != .connected else {
 | 
				
			||||||
            DefaultSocketLogger.Logger.log("Tried connecting on an already connected socket",
 | 
					            DefaultSocketLogger.Logger.log("Tried connecting on an already connected socket", type: logType)
 | 
				
			||||||
                                           type: SocketIOClient.logType)
 | 
					 | 
				
			||||||
            return
 | 
					            return
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        status = .connecting
 | 
					        status = .connecting
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if engine == nil || forceNew {
 | 
					        manager.connectSocket(self)
 | 
				
			||||||
            addEngine()
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        engine?.connect()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        guard timeoutAfter != 0 else { return }
 | 
					        guard timeoutAfter != 0 else { return }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        handleQueue.asyncAfter(deadline: DispatchTime.now() + timeoutAfter) {[weak self] in
 | 
					        manager.handleQueue.asyncAfter(deadline: DispatchTime.now() + timeoutAfter) {[weak self] in
 | 
				
			||||||
            guard let this = self, this.status == .connecting || this.status == .notConnected else { return }
 | 
					            guard let this = self, this.status == .connecting || this.status == .notConnected else { return }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.status = .disconnected
 | 
					            this.status = .disconnected
 | 
				
			||||||
            this.engine?.disconnect(reason: "Connect timeout")
 | 
					            this.leaveNamespace()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            handler?()
 | 
					            handler?()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -248,7 +154,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So
 | 
				
			|||||||
    open func didConnect(toNamespace namespace: String) {
 | 
					    open func didConnect(toNamespace namespace: String) {
 | 
				
			||||||
        guard status != .connected else { return }
 | 
					        guard status != .connected else { return }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        DefaultSocketLogger.Logger.log("Socket connected", type: SocketIOClient.logType)
 | 
					        DefaultSocketLogger.Logger.log("Socket connected", type: logType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        status = .connected
 | 
					        status = .connected
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -261,21 +167,22 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So
 | 
				
			|||||||
    open func didDisconnect(reason: String) {
 | 
					    open func didDisconnect(reason: String) {
 | 
				
			||||||
        guard status != .disconnected else { return }
 | 
					        guard status != .disconnected else { return }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        DefaultSocketLogger.Logger.log("Disconnected: \(reason)", type: SocketIOClient.logType)
 | 
					        DefaultSocketLogger.Logger.log("Disconnected: \(reason)", type: logType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        reconnecting = false
 | 
					 | 
				
			||||||
        status = .disconnected
 | 
					        status = .disconnected
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Make sure the engine is actually dead.
 | 
					 | 
				
			||||||
        engine?.disconnect(reason: reason)
 | 
					 | 
				
			||||||
        handleClientEvent(.disconnect, data: [reason])
 | 
					        handleClientEvent(.disconnect, data: [reason])
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Disconnects the socket.
 | 
					    /// Disconnects the socket.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// This will cause the socket to leave the namespace it is associated to, as well as remove itself from the
 | 
				
			||||||
 | 
					    /// `manager`.
 | 
				
			||||||
    @objc
 | 
					    @objc
 | 
				
			||||||
    open func disconnect() {
 | 
					    open func disconnect() {
 | 
				
			||||||
        DefaultSocketLogger.Logger.log("Closing socket", type: SocketIOClient.logType)
 | 
					        DefaultSocketLogger.Logger.log("Closing socket", type: logType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        leaveNamespace()
 | 
				
			||||||
        didDisconnect(reason: "Disconnect")
 | 
					        didDisconnect(reason: "Disconnect")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -291,7 +198,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So
 | 
				
			|||||||
            try emit(event, with: items.map({ try $0.socketRepresentation() }))
 | 
					            try emit(event, with: items.map({ try $0.socketRepresentation() }))
 | 
				
			||||||
        } catch let err {
 | 
					        } catch let err {
 | 
				
			||||||
            DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)",
 | 
					            DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)",
 | 
				
			||||||
                                             type: SocketIOClient.logType)
 | 
					                                             type: logType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            handleClientEvent(.error, data: [event, items, err])
 | 
					            handleClientEvent(.error, data: [event, items, err])
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -335,7 +242,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So
 | 
				
			|||||||
            return emitWithAck(event, with: try items.map({ try $0.socketRepresentation() }))
 | 
					            return emitWithAck(event, with: try items.map({ try $0.socketRepresentation() }))
 | 
				
			||||||
        } catch let err {
 | 
					        } catch let err {
 | 
				
			||||||
            DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)",
 | 
					            DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)",
 | 
				
			||||||
                                             type: SocketIOClient.logType)
 | 
					                                             type: logType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            handleClientEvent(.error, data: [event, items, err])
 | 
					            handleClientEvent(.error, data: [event, items, err])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -373,9 +280,9 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So
 | 
				
			|||||||
        let packet = SocketPacket.packetFromEmit(data, id: ack ?? -1, nsp: nsp, ack: false)
 | 
					        let packet = SocketPacket.packetFromEmit(data, id: ack ?? -1, nsp: nsp, ack: false)
 | 
				
			||||||
        let str = packet.packetString
 | 
					        let str = packet.packetString
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        DefaultSocketLogger.Logger.log("Emitting: \(str)", type: SocketIOClient.logType)
 | 
					        DefaultSocketLogger.Logger.log("Emitting: \(str)", type: logType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        engine?.send(str, withData: packet.binary)
 | 
					        manager?.engine?.send(str, withData: packet.binary)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Call when you wish to tell the server that you've received the event for `ack`.
 | 
					    /// Call when you wish to tell the server that you've received the event for `ack`.
 | 
				
			||||||
@ -390,91 +297,9 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So
 | 
				
			|||||||
        let packet = SocketPacket.packetFromEmit(items, id: ack, nsp: nsp, ack: true)
 | 
					        let packet = SocketPacket.packetFromEmit(items, id: ack, nsp: nsp, ack: true)
 | 
				
			||||||
        let str = packet.packetString
 | 
					        let str = packet.packetString
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        DefaultSocketLogger.Logger.log("Emitting Ack: \(str)", type: SocketIOClient.logType)
 | 
					        DefaultSocketLogger.Logger.log("Emitting Ack: \(str)", type: logType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        engine?.send(str, withData: packet.binary)
 | 
					        manager?.engine?.send(str, withData: packet.binary)
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Called when the engine closes.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// - parameter reason: The reason that the engine closed.
 | 
					 | 
				
			||||||
    open func engineDidClose(reason: String) {
 | 
					 | 
				
			||||||
        handleQueue.async {
 | 
					 | 
				
			||||||
            self._engineDidClose(reason: reason)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private func _engineDidClose(reason: String) {
 | 
					 | 
				
			||||||
        waitingPackets.removeAll()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if status != .disconnected {
 | 
					 | 
				
			||||||
            status = .notConnected
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if status == .disconnected || !reconnects {
 | 
					 | 
				
			||||||
            didDisconnect(reason: reason)
 | 
					 | 
				
			||||||
        } else if !reconnecting {
 | 
					 | 
				
			||||||
            reconnecting = true
 | 
					 | 
				
			||||||
            tryReconnect(reason: reason)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Called when the engine errors.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// - parameter reason: The reason the engine errored.
 | 
					 | 
				
			||||||
    open func engineDidError(reason: String) {
 | 
					 | 
				
			||||||
        handleQueue.async {
 | 
					 | 
				
			||||||
            self._engineDidError(reason: reason)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private func _engineDidError(reason: String) {
 | 
					 | 
				
			||||||
        DefaultSocketLogger.Logger.error("\(reason)", type: SocketIOClient.logType)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        handleClientEvent(.error, data: [reason])
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Called when the engine opens.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// - parameter reason: The reason the engine opened.
 | 
					 | 
				
			||||||
    open func engineDidOpen(reason: String) {
 | 
					 | 
				
			||||||
        handleQueue.async {
 | 
					 | 
				
			||||||
            self._engineDidOpen(reason: reason)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private func _engineDidOpen(reason: String) {
 | 
					 | 
				
			||||||
        DefaultSocketLogger.Logger.log("Engine opened \(reason)", type: SocketIOClient.logType)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        guard nsp != "/" else {
 | 
					 | 
				
			||||||
            didConnect(toNamespace: "/")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        joinNamespace(nsp)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Called when the engine receives a pong message.
 | 
					 | 
				
			||||||
    open func engineDidReceivePong() {
 | 
					 | 
				
			||||||
        handleQueue.async {
 | 
					 | 
				
			||||||
            self._engineDidReceivePong()
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private func _engineDidReceivePong() {
 | 
					 | 
				
			||||||
        handleClientEvent(.pong, data: [])
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Called when the sends a ping to the server.
 | 
					 | 
				
			||||||
    open func engineDidSendPing() {
 | 
					 | 
				
			||||||
        handleQueue.async {
 | 
					 | 
				
			||||||
            self._engineDidSendPing()
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private func _engineDidSendPing() {
 | 
					 | 
				
			||||||
        handleClientEvent(.ping, data: [])
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Called when socket.io has acked one of our emits. Causes the corresponding ack callback to be called.
 | 
					    /// Called when socket.io has acked one of our emits. Causes the corresponding ack callback to be called.
 | 
				
			||||||
@ -483,11 +308,19 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So
 | 
				
			|||||||
    /// - parameter data: The data sent back with this ack.
 | 
					    /// - parameter data: The data sent back with this ack.
 | 
				
			||||||
    @objc
 | 
					    @objc
 | 
				
			||||||
    open func handleAck(_ ack: Int, data: [Any]) {
 | 
					    open func handleAck(_ ack: Int, data: [Any]) {
 | 
				
			||||||
        guard status == .connected else { return }
 | 
					        guard status == .connected, let manager = self.manager else { return }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        DefaultSocketLogger.Logger.log("Handling ack: \(ack) with data: \(data)", type: SocketIOClient.logType)
 | 
					        DefaultSocketLogger.Logger.log("Handling ack: \(ack) with data: \(data)", type: logType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ackHandlers.executeAck(ack, with: data, onQueue: handleQueue)
 | 
					        ackHandlers.executeAck(ack, with: data, onQueue: manager.handleQueue)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Called on socket.io specific events.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// - parameter event: The `SocketClientEvent`.
 | 
				
			||||||
 | 
					    /// - parameter data: The data for this event.
 | 
				
			||||||
 | 
					    open func handleClientEvent(_ event: SocketClientEvent, data: [Any]) {
 | 
				
			||||||
 | 
					        handleEvent(event.rawValue, data: data, isInternalMessage: true)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Called when we get an event from socket.io.
 | 
					    /// Called when we get an event from socket.io.
 | 
				
			||||||
@ -500,7 +333,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So
 | 
				
			|||||||
    open func handleEvent(_ event: String, data: [Any], isInternalMessage: Bool, withAck ack: Int = -1) {
 | 
					    open func handleEvent(_ event: String, data: [Any], isInternalMessage: Bool, withAck ack: Int = -1) {
 | 
				
			||||||
        guard status == .connected || isInternalMessage else { return }
 | 
					        guard status == .connected || isInternalMessage else { return }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        DefaultSocketLogger.Logger.log("Handling event: \(event) with data: \(data)", type: SocketIOClient.logType)
 | 
					        DefaultSocketLogger.Logger.log("Handling event: \(event) with data: \(data)", type: logType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        anyHandler?(SocketAnyEvent(event: event, items: data))
 | 
					        anyHandler?(SocketAnyEvent(event: event, items: data))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -509,36 +342,49 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Called on socket.io specific events.
 | 
					    /// Causes a client to handle a socket.io packet. The namespace for the packet must match the namespace of the
 | 
				
			||||||
 | 
					    /// socket.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// - parameter event: The `SocketClientEvent`.
 | 
					    /// - parameter pack: The packet to handle.
 | 
				
			||||||
    /// - parameter data: The data for this event.
 | 
					    open func handlePacket(_ pack: SocketPacket) {
 | 
				
			||||||
    open func handleClientEvent(_ event: SocketClientEvent, data: [Any]) {
 | 
					        func handleConnect(_ packetNamespace: String) {
 | 
				
			||||||
        handleEvent(event.rawValue, data: data, isInternalMessage: true)
 | 
					            guard packetNamespace == nsp else { return }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            didConnect(toNamespace: packetNamespace)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        switch pack.type {
 | 
				
			||||||
 | 
					        case .event, .binaryEvent:
 | 
				
			||||||
 | 
					            handleEvent(pack.event, data: pack.args, isInternalMessage: false, withAck: pack.id)
 | 
				
			||||||
 | 
					        case .ack, .binaryAck:
 | 
				
			||||||
 | 
					            handleAck(pack.id, data: pack.data)
 | 
				
			||||||
 | 
					        case .connect:
 | 
				
			||||||
 | 
					            handleConnect(pack.nsp)
 | 
				
			||||||
 | 
					        case .disconnect:
 | 
				
			||||||
 | 
					            didDisconnect(reason: "Got Disconnect")
 | 
				
			||||||
 | 
					        case .error:
 | 
				
			||||||
 | 
					            handleEvent("error", data: pack.data, isInternalMessage: true, withAck: pack.id)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Call when you wish to leave a namespace and return to the default namespace.
 | 
					    /// Call when you wish to leave a namespace and disconnect this socket.
 | 
				
			||||||
    @objc
 | 
					    @objc
 | 
				
			||||||
    open func leaveNamespace() {
 | 
					    open func leaveNamespace() {
 | 
				
			||||||
        guard nsp != "/" else { return }
 | 
					        guard nsp != "/" else { return }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        engine?.send("1\(nsp)", withData: [])
 | 
					        status = .disconnected
 | 
				
			||||||
        nsp = "/"
 | 
					
 | 
				
			||||||
 | 
					        manager?.disconnectSocket(self)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Joins `namespace`.
 | 
					    /// Joins `nsp`.
 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// **Do not use this to join the default namespace.** Instead call `leaveNamespace`.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// - parameter namespace: The namespace to join.
 | 
					 | 
				
			||||||
    @objc
 | 
					    @objc
 | 
				
			||||||
    open func joinNamespace(_ namespace: String) {
 | 
					    open func joinNamespace() {
 | 
				
			||||||
        guard namespace != "/" else { return }
 | 
					        guard nsp != "/" else { return }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        DefaultSocketLogger.Logger.log("Joining namespace \(namespace)", type: SocketIOClient.logType)
 | 
					        DefaultSocketLogger.Logger.log("Joining namespace \(nsp)", type: logType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        nsp = namespace
 | 
					        manager?.engine?.send("0\(nsp)", withData: [])
 | 
				
			||||||
        engine?.send("0\(nsp)", withData: [])
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Removes handler(s) for a client event.
 | 
					    /// Removes handler(s) for a client event.
 | 
				
			||||||
@ -557,7 +403,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So
 | 
				
			|||||||
    /// - parameter event: The event to remove handlers for.
 | 
					    /// - parameter event: The event to remove handlers for.
 | 
				
			||||||
    @objc
 | 
					    @objc
 | 
				
			||||||
    open func off(_ event: String) {
 | 
					    open func off(_ event: String) {
 | 
				
			||||||
        DefaultSocketLogger.Logger.log("Removing handler for event: \(event)", type: SocketIOClient.logType)
 | 
					        DefaultSocketLogger.Logger.log("Removing handler for event: \(event)", type: logType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        handlers = handlers.filter({ $0.event != event })
 | 
					        handlers = handlers.filter({ $0.event != event })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -569,7 +415,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So
 | 
				
			|||||||
    /// - parameter id: The UUID of the handler you wish to remove.
 | 
					    /// - parameter id: The UUID of the handler you wish to remove.
 | 
				
			||||||
    @objc
 | 
					    @objc
 | 
				
			||||||
    open func off(id: UUID) {
 | 
					    open func off(id: UUID) {
 | 
				
			||||||
        DefaultSocketLogger.Logger.log("Removing handler with id: \(id)", type: SocketIOClient.logType)
 | 
					        DefaultSocketLogger.Logger.log("Removing handler with id: \(id)", type: logType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        handlers = handlers.filter({ $0.id != id })
 | 
					        handlers = handlers.filter({ $0.id != id })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -582,7 +428,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So
 | 
				
			|||||||
    @objc
 | 
					    @objc
 | 
				
			||||||
    @discardableResult
 | 
					    @discardableResult
 | 
				
			||||||
    open func on(_ event: String, callback: @escaping NormalCallback) -> UUID {
 | 
					    open func on(_ event: String, callback: @escaping NormalCallback) -> UUID {
 | 
				
			||||||
        DefaultSocketLogger.Logger.log("Adding handler for event: \(event)", type: SocketIOClient.logType)
 | 
					        DefaultSocketLogger.Logger.log("Adding handler for event: \(event)", type: logType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let handler = SocketEventHandler(event: event, id: UUID(), callback: callback)
 | 
					        let handler = SocketEventHandler(event: event, id: UUID(), callback: callback)
 | 
				
			||||||
        handlers.append(handler)
 | 
					        handlers.append(handler)
 | 
				
			||||||
@ -626,7 +472,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So
 | 
				
			|||||||
    @objc
 | 
					    @objc
 | 
				
			||||||
    @discardableResult
 | 
					    @discardableResult
 | 
				
			||||||
    open func once(_ event: String, callback: @escaping NormalCallback) -> UUID {
 | 
					    open func once(_ event: String, callback: @escaping NormalCallback) -> UUID {
 | 
				
			||||||
        DefaultSocketLogger.Logger.log("Adding once handler for event: \(event)", type: SocketIOClient.logType)
 | 
					        DefaultSocketLogger.Logger.log("Adding once handler for event: \(event)", type: logType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let id = UUID()
 | 
					        let id = UUID()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -649,31 +495,10 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So
 | 
				
			|||||||
        anyHandler = handler
 | 
					        anyHandler = handler
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Called when the engine has a message that must be parsed.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// - parameter msg: The message that needs parsing.
 | 
					 | 
				
			||||||
    public func parseEngineMessage(_ msg: String) {
 | 
					 | 
				
			||||||
        DefaultSocketLogger.Logger.log("Should parse message: \(msg)", type: SocketIOClient.logType)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        handleQueue.async { self.parseSocketMessage(msg) }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Called when the engine receives binary data.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// - parameter data: The data the engine received.
 | 
					 | 
				
			||||||
    public func parseEngineBinaryData(_ data: Data) {
 | 
					 | 
				
			||||||
        handleQueue.async { self.parseBinaryData(data) }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Tries to reconnect to the server.
 | 
					    /// Tries to reconnect to the server.
 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// This will cause a `disconnect` event to be emitted, as well as an `reconnectAttempt` event.
 | 
					 | 
				
			||||||
    @objc
 | 
					    @objc
 | 
				
			||||||
    open func reconnect() {
 | 
					    @available(*, unavailable, message: "Call the manager's reconnect method")
 | 
				
			||||||
        guard !reconnecting else { return }
 | 
					    open func reconnect() { }
 | 
				
			||||||
 | 
					 | 
				
			||||||
        engine?.disconnect(reason: "manual reconnect")
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Removes all handlers.
 | 
					    /// Removes all handlers.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
@ -683,54 +508,15 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So
 | 
				
			|||||||
        handlers.removeAll(keepingCapacity: false)
 | 
					        handlers.removeAll(keepingCapacity: false)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private func tryReconnect(reason: String) {
 | 
					    /// Puts the socket back into the connecting state.
 | 
				
			||||||
        guard reconnecting else { return }
 | 
					    /// Called when the manager detects a broken connection, or when a manual reconnect is triggered.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// - parameter reason: The reason this socket is reconnecting.
 | 
				
			||||||
 | 
					    @objc
 | 
				
			||||||
 | 
					    open func setReconnecting(reason: String) {
 | 
				
			||||||
 | 
					        status = .connecting
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        DefaultSocketLogger.Logger.log("Starting reconnect", type: SocketIOClient.logType)
 | 
					 | 
				
			||||||
        handleClientEvent(.reconnect, data: [reason])
 | 
					        handleClientEvent(.reconnect, data: [reason])
 | 
				
			||||||
 | 
					 | 
				
			||||||
        _tryReconnect()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private func _tryReconnect() {
 | 
					 | 
				
			||||||
        guard reconnects && reconnecting && status != .disconnected else { return }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if reconnectAttempts != -1 && currentReconnectAttempt + 1 > reconnectAttempts {
 | 
					 | 
				
			||||||
            return didDisconnect(reason: "Reconnect Failed")
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        DefaultSocketLogger.Logger.log("Trying to reconnect", type: SocketIOClient.logType)
 | 
					 | 
				
			||||||
        handleClientEvent(.reconnectAttempt, data: [(reconnectAttempts - currentReconnectAttempt)])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        currentReconnectAttempt += 1
 | 
					 | 
				
			||||||
        connect()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        handleQueue.asyncAfter(deadline: DispatchTime.now() + Double(reconnectWait), execute: _tryReconnect)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private func setConfigs() {
 | 
					 | 
				
			||||||
        for option in config {
 | 
					 | 
				
			||||||
            switch option {
 | 
					 | 
				
			||||||
            case let .reconnects(reconnects):
 | 
					 | 
				
			||||||
                self.reconnects = reconnects
 | 
					 | 
				
			||||||
            case let .reconnectAttempts(attempts):
 | 
					 | 
				
			||||||
                reconnectAttempts = attempts
 | 
					 | 
				
			||||||
            case let .reconnectWait(wait):
 | 
					 | 
				
			||||||
                reconnectWait = abs(wait)
 | 
					 | 
				
			||||||
            case let .nsp(nsp):
 | 
					 | 
				
			||||||
                self.nsp = nsp
 | 
					 | 
				
			||||||
            case let .log(log):
 | 
					 | 
				
			||||||
                DefaultSocketLogger.Logger.log = log
 | 
					 | 
				
			||||||
            case let .logger(logger):
 | 
					 | 
				
			||||||
                DefaultSocketLogger.Logger = logger
 | 
					 | 
				
			||||||
            case let .handleQueue(queue):
 | 
					 | 
				
			||||||
                handleQueue = queue
 | 
					 | 
				
			||||||
            case let .forceNew(force):
 | 
					 | 
				
			||||||
                forceNew = force
 | 
					 | 
				
			||||||
            default:
 | 
					 | 
				
			||||||
                continue
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Test properties
 | 
					    // Test properties
 | 
				
			||||||
@ -743,14 +529,10 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So
 | 
				
			|||||||
        status = .connected
 | 
					        status = .connected
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    func setTestStatus(_ status: SocketIOClientStatus) {
 | 
					    func setTestStatus(_ status: SocketIOStatus) {
 | 
				
			||||||
        self.status = status
 | 
					        self.status = status
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    func setTestEngine(_ engine: SocketEngineSpec?) {
 | 
					 | 
				
			||||||
        self.engine = engine
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    func emitTest(event: String, _ data: Any...) {
 | 
					    func emitTest(event: String, _ data: Any...) {
 | 
				
			||||||
        emit([event] + data)
 | 
					        emit([event] + data)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -125,5 +125,12 @@ public struct SocketIOClientConfiguration : ExpressibleByArrayLiteral, Collectio
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        backingArray.append(element)
 | 
					        backingArray.append(element)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Declares that a type can set configs from a `SocketIOClientConfiguration`.
 | 
				
			||||||
 | 
					public protocol ConfigSettable {
 | 
				
			||||||
 | 
					    /// Called when an `ConfigSettable` should set/update its configs from a given configuration.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// - parameter config: The `SocketIOClientConfiguration` that should be used to set/update configs.
 | 
				
			||||||
 | 
					    mutating func setConfigs(_ config: SocketIOClientConfiguration)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -40,10 +40,6 @@ public enum SocketIOClientOption : ClientOption {
 | 
				
			|||||||
    /// An array of cookies that will be sent during the initial connection.
 | 
					    /// An array of cookies that will be sent during the initial connection.
 | 
				
			||||||
    case cookies([HTTPCookie])
 | 
					    case cookies([HTTPCookie])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Deprecated
 | 
					 | 
				
			||||||
    @available(*, deprecated, message: "No longer needed in socket.io 2.0+")
 | 
					 | 
				
			||||||
    case doubleEncodeUTF8(Bool)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Any extra HTTP headers that should be sent during the initial connection.
 | 
					    /// Any extra HTTP headers that should be sent during the initial connection.
 | 
				
			||||||
    case extraHeaders([String: String])
 | 
					    case extraHeaders([String: String])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -67,10 +63,6 @@ public enum SocketIOClientOption : ClientOption {
 | 
				
			|||||||
    /// Used to pass in a custom logger.
 | 
					    /// Used to pass in a custom logger.
 | 
				
			||||||
    case logger(SocketLogger)
 | 
					    case logger(SocketLogger)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// The namespace that this client should connect to. Can be changed during use using the `joinNamespace`
 | 
					 | 
				
			||||||
    /// and `leaveNamespace` methods on `SocketIOClient`.
 | 
					 | 
				
			||||||
    case nsp(String)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// A custom path to socket.io. Only use this if the socket.io server is configured to look for this path.
 | 
					    /// A custom path to socket.io. Only use this if the socket.io server is configured to look for this path.
 | 
				
			||||||
    case path(String)
 | 
					    case path(String)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -96,11 +88,6 @@ public enum SocketIOClientOption : ClientOption {
 | 
				
			|||||||
    /// Sets an NSURLSessionDelegate for the underlying engine. Useful if you need to handle self-signed certs.
 | 
					    /// Sets an NSURLSessionDelegate for the underlying engine. Useful if you need to handle self-signed certs.
 | 
				
			||||||
    case sessionDelegate(URLSessionDelegate)
 | 
					    case sessionDelegate(URLSessionDelegate)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// If passed `true`, the WebSocket transport will try and use voip logic to keep network connections open in
 | 
					 | 
				
			||||||
    /// the background. **This option is experimental as socket.io shouldn't be used for background communication.**
 | 
					 | 
				
			||||||
    @available(*, deprecated, message: "No longer has any effect, and will be removed in v11.0")
 | 
					 | 
				
			||||||
    case voipEnabled(Bool)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // MARK: Properties
 | 
					    // MARK: Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// The description of this option.
 | 
					    /// The description of this option.
 | 
				
			||||||
@ -114,8 +101,6 @@ public enum SocketIOClientOption : ClientOption {
 | 
				
			|||||||
            description = "connectParams"
 | 
					            description = "connectParams"
 | 
				
			||||||
        case .cookies:
 | 
					        case .cookies:
 | 
				
			||||||
            description = "cookies"
 | 
					            description = "cookies"
 | 
				
			||||||
        case .doubleEncodeUTF8:
 | 
					 | 
				
			||||||
            description = "doubleEncodeUTF8"
 | 
					 | 
				
			||||||
        case .extraHeaders:
 | 
					        case .extraHeaders:
 | 
				
			||||||
            description = "extraHeaders"
 | 
					            description = "extraHeaders"
 | 
				
			||||||
        case .forceNew:
 | 
					        case .forceNew:
 | 
				
			||||||
@ -130,8 +115,6 @@ public enum SocketIOClientOption : ClientOption {
 | 
				
			|||||||
            description = "log"
 | 
					            description = "log"
 | 
				
			||||||
        case .logger:
 | 
					        case .logger:
 | 
				
			||||||
            description = "logger"
 | 
					            description = "logger"
 | 
				
			||||||
        case .nsp:
 | 
					 | 
				
			||||||
            description = "nsp"
 | 
					 | 
				
			||||||
        case .path:
 | 
					        case .path:
 | 
				
			||||||
            description = "path"
 | 
					            description = "path"
 | 
				
			||||||
        case .reconnects:
 | 
					        case .reconnects:
 | 
				
			||||||
@ -148,8 +131,6 @@ public enum SocketIOClientOption : ClientOption {
 | 
				
			|||||||
            description = "security"
 | 
					            description = "security"
 | 
				
			||||||
        case .sessionDelegate:
 | 
					        case .sessionDelegate:
 | 
				
			||||||
            description = "sessionDelegate"
 | 
					            description = "sessionDelegate"
 | 
				
			||||||
        case .voipEnabled:
 | 
					 | 
				
			||||||
            description = "voipEnabled"
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return description
 | 
					        return description
 | 
				
			||||||
@ -165,8 +146,6 @@ public enum SocketIOClientOption : ClientOption {
 | 
				
			|||||||
            value = params
 | 
					            value = params
 | 
				
			||||||
        case let .cookies(cookies):
 | 
					        case let .cookies(cookies):
 | 
				
			||||||
            value = cookies
 | 
					            value = cookies
 | 
				
			||||||
        case let .doubleEncodeUTF8(encode):
 | 
					 | 
				
			||||||
            value = encode
 | 
					 | 
				
			||||||
        case let .extraHeaders(headers):
 | 
					        case let .extraHeaders(headers):
 | 
				
			||||||
            value = headers
 | 
					            value = headers
 | 
				
			||||||
        case let .forceNew(force):
 | 
					        case let .forceNew(force):
 | 
				
			||||||
@ -181,8 +160,6 @@ public enum SocketIOClientOption : ClientOption {
 | 
				
			|||||||
            value = log
 | 
					            value = log
 | 
				
			||||||
        case let .logger(logger):
 | 
					        case let .logger(logger):
 | 
				
			||||||
            value = logger
 | 
					            value = logger
 | 
				
			||||||
        case let .nsp(nsp):
 | 
					 | 
				
			||||||
            value = nsp
 | 
					 | 
				
			||||||
        case let .path(path):
 | 
					        case let .path(path):
 | 
				
			||||||
            value = path
 | 
					            value = path
 | 
				
			||||||
        case let .reconnects(reconnects):
 | 
					        case let .reconnects(reconnects):
 | 
				
			||||||
@ -199,8 +176,6 @@ public enum SocketIOClientOption : ClientOption {
 | 
				
			|||||||
            value = signed
 | 
					            value = signed
 | 
				
			||||||
        case let .sessionDelegate(delegate):
 | 
					        case let .sessionDelegate(delegate):
 | 
				
			||||||
            value = delegate
 | 
					            value = delegate
 | 
				
			||||||
        case let .voipEnabled(enabled):
 | 
					 | 
				
			||||||
            value = enabled
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return value
 | 
					        return value
 | 
				
			||||||
 | 
				
			|||||||
@ -32,22 +32,19 @@ public protocol SocketIOClientSpec : class {
 | 
				
			|||||||
    /// A handler that will be called on any event.
 | 
					    /// A handler that will be called on any event.
 | 
				
			||||||
    var anyHandler: ((SocketAnyEvent) -> ())? { get }
 | 
					    var anyHandler: ((SocketAnyEvent) -> ())? { get }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// The configuration for this client.
 | 
					 | 
				
			||||||
    var config: SocketIOClientConfiguration { get set }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// The queue that all interaction with the client must be on.
 | 
					 | 
				
			||||||
    var handleQueue: DispatchQueue { get set }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// The array of handlers for this socket.
 | 
					    /// The array of handlers for this socket.
 | 
				
			||||||
    var handlers: [SocketEventHandler] { get }
 | 
					    var handlers: [SocketEventHandler] { get }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// The manager for this socket.
 | 
				
			||||||
 | 
					    var manager: SocketManagerSpec? { get }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// The namespace that this socket is currently connected to.
 | 
					    /// The namespace that this socket is currently connected to.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// **Must** start with a `/`.
 | 
					    /// **Must** start with a `/`.
 | 
				
			||||||
    var nsp: String { get set }
 | 
					    var nsp: String { get set }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// The status of this client.
 | 
					    /// The status of this client.
 | 
				
			||||||
    var status: SocketIOClientStatus { get }
 | 
					    var status: SocketIOStatus { get }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // MARK: Methods
 | 
					    // MARK: Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -126,6 +123,12 @@ public protocol SocketIOClientSpec : class {
 | 
				
			|||||||
    /// - parameter data: The data sent back with this ack.
 | 
					    /// - parameter data: The data sent back with this ack.
 | 
				
			||||||
    func handleAck(_ ack: Int, data: [Any])
 | 
					    func handleAck(_ ack: Int, data: [Any])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Called on socket.io specific events.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// - parameter event: The `SocketClientEvent`.
 | 
				
			||||||
 | 
					    /// - parameter data: The data for this event.
 | 
				
			||||||
 | 
					    func handleClientEvent(_ event: SocketClientEvent, data: [Any])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Called when we get an event from socket.io.
 | 
					    /// Called when we get an event from socket.io.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// - parameter event: The name of the event.
 | 
					    /// - parameter event: The name of the event.
 | 
				
			||||||
@ -134,21 +137,17 @@ public protocol SocketIOClientSpec : class {
 | 
				
			|||||||
    /// - parameter withAck: If > 0 then this event expects to get an ack back from the client.
 | 
					    /// - parameter withAck: If > 0 then this event expects to get an ack back from the client.
 | 
				
			||||||
    func handleEvent(_ event: String, data: [Any], isInternalMessage: Bool, withAck ack: Int)
 | 
					    func handleEvent(_ event: String, data: [Any], isInternalMessage: Bool, withAck ack: Int)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Called on socket.io specific events.
 | 
					    /// Causes a client to handle a socket.io packet. The namespace for the packet must match the namespace of the
 | 
				
			||||||
 | 
					    /// socket.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// - parameter event: The `SocketClientEvent`.
 | 
					    /// - parameter pack: The packet to handle.
 | 
				
			||||||
    /// - parameter data: The data for this event.
 | 
					    func handlePacket(_ pack: SocketPacket)
 | 
				
			||||||
    func handleClientEvent(_ event: SocketClientEvent, data: [Any])
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Call when you wish to leave a namespace and return to the default namespace.
 | 
					    /// Call when you wish to leave a namespace and disconnect this socket.
 | 
				
			||||||
    func leaveNamespace()
 | 
					    func leaveNamespace()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Joins `namespace`.
 | 
					    /// Joins `nsp`.
 | 
				
			||||||
    ///
 | 
					    func joinNamespace()
 | 
				
			||||||
    /// **Do not use this to join the default namespace.** Instead call `leaveNamespace`.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// - parameter namespace: The namespace to join.
 | 
					 | 
				
			||||||
    func joinNamespace(_ namespace: String)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Removes handler(s) for a client event.
 | 
					    /// Removes handler(s) for a client event.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
@ -212,13 +211,16 @@ public protocol SocketIOClientSpec : class {
 | 
				
			|||||||
    /// - parameter handler: The callback that will execute whenever an event is received.
 | 
					    /// - parameter handler: The callback that will execute whenever an event is received.
 | 
				
			||||||
    func onAny(_ handler: @escaping (SocketAnyEvent) -> ())
 | 
					    func onAny(_ handler: @escaping (SocketAnyEvent) -> ())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Tries to reconnect to the server.
 | 
					 | 
				
			||||||
    func reconnect()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Removes all handlers.
 | 
					    /// Removes all handlers.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// Can be used after disconnecting to break any potential remaining retain cycles.
 | 
					    /// Can be used after disconnecting to break any potential remaining retain cycles.
 | 
				
			||||||
    func removeAllHandlers()
 | 
					    func removeAllHandlers()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Puts the socket back into the connecting state.
 | 
				
			||||||
 | 
					    /// Called when the manager detects a broken connection, or when a manual reconnect is triggered.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// parameter reason: The reason this socket is going reconnecting.
 | 
				
			||||||
 | 
					    func setReconnecting(reason: String)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public extension SocketIOClientSpec {
 | 
					public extension SocketIOClientSpec {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
//
 | 
					//
 | 
				
			||||||
//  SocketIOClientStatus.swift
 | 
					//  SocketIOStatus.swift
 | 
				
			||||||
//  Socket.IO-Client-Swift
 | 
					//  Socket.IO-Client-Swift
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
//  Created by Erik Little on 8/14/15.
 | 
					//  Created by Erik Little on 8/14/15.
 | 
				
			||||||
@ -24,17 +24,36 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import Foundation
 | 
					import Foundation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Represents the state of the client.
 | 
					/// Represents state of a manager or client.
 | 
				
			||||||
@objc public enum SocketIOClientStatus : Int {
 | 
					@objc
 | 
				
			||||||
    /// The client has never been connected. Or the client has been reset.
 | 
					public enum SocketIOStatus : Int, CustomStringConvertible {
 | 
				
			||||||
 | 
					    // MARK: Cases
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// The client/manager has never been connected. Or the client has been reset.
 | 
				
			||||||
    case notConnected
 | 
					    case notConnected
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// The client was once connected, but not anymore.
 | 
					    /// The client/manager was once connected, but not anymore.
 | 
				
			||||||
    case disconnected
 | 
					    case disconnected
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// The client is in the process of connecting.
 | 
					    /// The client/manager is in the process of connecting.
 | 
				
			||||||
    case connecting
 | 
					    case connecting
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// The client is currently connected.
 | 
					    /// The client/manager is currently connected.
 | 
				
			||||||
    case connected
 | 
					    case connected
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // MARK: Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// - returns: True if this client/manager is connected/connecting to a server.
 | 
				
			||||||
 | 
					    public var active: Bool {
 | 
				
			||||||
 | 
					        return self == .connected || self == .connecting
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public var description: String {
 | 
				
			||||||
 | 
					        switch self {
 | 
				
			||||||
 | 
					        case .connected:    return "connected"
 | 
				
			||||||
 | 
					        case .connecting:   return "connecting"
 | 
				
			||||||
 | 
					        case .disconnected: return "disconnected"
 | 
				
			||||||
 | 
					        case .notConnected: return "notConnected"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -28,7 +28,8 @@ import Starscream
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/// The class that handles the engine.io protocol and transports.
 | 
					/// The class that handles the engine.io protocol and transports.
 | 
				
			||||||
/// See `SocketEnginePollable` and `SocketEngineWebsocket` for transport specific methods.
 | 
					/// See `SocketEnginePollable` and `SocketEngineWebsocket` for transport specific methods.
 | 
				
			||||||
public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, SocketEngineWebsocket {
 | 
					public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePollable, SocketEngineWebsocket,
 | 
				
			||||||
 | 
					                                  ConfigSettable {
 | 
				
			||||||
    // MARK: Properties
 | 
					    // MARK: Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static let logType = "SocketEngine"
 | 
					    private static let logType = "SocketEngine"
 | 
				
			||||||
@ -147,41 +148,11 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll
 | 
				
			|||||||
    public init(client: SocketEngineClient, url: URL, config: SocketIOClientConfiguration) {
 | 
					    public init(client: SocketEngineClient, url: URL, config: SocketIOClientConfiguration) {
 | 
				
			||||||
        self.client = client
 | 
					        self.client = client
 | 
				
			||||||
        self.url = url
 | 
					        self.url = url
 | 
				
			||||||
        for option in config {
 | 
					 | 
				
			||||||
            switch option {
 | 
					 | 
				
			||||||
            case let .connectParams(params):
 | 
					 | 
				
			||||||
                connectParams = params
 | 
					 | 
				
			||||||
            case let .cookies(cookies):
 | 
					 | 
				
			||||||
                self.cookies = cookies
 | 
					 | 
				
			||||||
            case let .extraHeaders(headers):
 | 
					 | 
				
			||||||
                extraHeaders = headers
 | 
					 | 
				
			||||||
            case let .sessionDelegate(delegate):
 | 
					 | 
				
			||||||
                sessionDelegate = delegate
 | 
					 | 
				
			||||||
            case let .forcePolling(force):
 | 
					 | 
				
			||||||
                forcePolling = force
 | 
					 | 
				
			||||||
            case let .forceWebsockets(force):
 | 
					 | 
				
			||||||
                forceWebsockets = force
 | 
					 | 
				
			||||||
            case let .path(path):
 | 
					 | 
				
			||||||
                socketPath = path
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if !socketPath.hasSuffix("/") {
 | 
					 | 
				
			||||||
                    socketPath += "/"
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            case let .secure(secure):
 | 
					 | 
				
			||||||
                self.secure = secure
 | 
					 | 
				
			||||||
            case let .selfSigned(selfSigned):
 | 
					 | 
				
			||||||
                self.selfSigned = selfSigned
 | 
					 | 
				
			||||||
            case let .security(security):
 | 
					 | 
				
			||||||
                self.security = security
 | 
					 | 
				
			||||||
            case .compress:
 | 
					 | 
				
			||||||
                self.compress = true
 | 
					 | 
				
			||||||
            default:
 | 
					 | 
				
			||||||
                continue
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        super.init()
 | 
					        super.init()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        setConfigs(config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        sessionDelegate = sessionDelegate ?? self
 | 
					        sessionDelegate = sessionDelegate ?? self
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        (urlPolling, urlWebSocket) = createURLs()
 | 
					        (urlPolling, urlWebSocket) = createURLs()
 | 
				
			||||||
@ -572,6 +543,44 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll
 | 
				
			|||||||
        client?.engineDidSendPing()
 | 
					        client?.engineDidSendPing()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Called when the engine should set/update its configs from a given configuration.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// parameter config: The `SocketIOClientConfiguration` that should be used to set/update configs.
 | 
				
			||||||
 | 
					    open func setConfigs(_ config: SocketIOClientConfiguration) {
 | 
				
			||||||
 | 
					        for option in config {
 | 
				
			||||||
 | 
					            switch option {
 | 
				
			||||||
 | 
					            case let .connectParams(params):
 | 
				
			||||||
 | 
					                connectParams = params
 | 
				
			||||||
 | 
					            case let .cookies(cookies):
 | 
				
			||||||
 | 
					                self.cookies = cookies
 | 
				
			||||||
 | 
					            case let .extraHeaders(headers):
 | 
				
			||||||
 | 
					                extraHeaders = headers
 | 
				
			||||||
 | 
					            case let .sessionDelegate(delegate):
 | 
				
			||||||
 | 
					                sessionDelegate = delegate
 | 
				
			||||||
 | 
					            case let .forcePolling(force):
 | 
				
			||||||
 | 
					                forcePolling = force
 | 
				
			||||||
 | 
					            case let .forceWebsockets(force):
 | 
				
			||||||
 | 
					                forceWebsockets = force
 | 
				
			||||||
 | 
					            case let .path(path):
 | 
				
			||||||
 | 
					                socketPath = path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if !socketPath.hasSuffix("/") {
 | 
				
			||||||
 | 
					                    socketPath += "/"
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            case let .secure(secure):
 | 
				
			||||||
 | 
					                self.secure = secure
 | 
				
			||||||
 | 
					            case let .selfSigned(selfSigned):
 | 
				
			||||||
 | 
					                self.selfSigned = selfSigned
 | 
				
			||||||
 | 
					            case let .security(security):
 | 
				
			||||||
 | 
					                self.security = security
 | 
				
			||||||
 | 
					            case .compress:
 | 
				
			||||||
 | 
					                self.compress = true
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Moves from long-polling to websockets
 | 
					    // Moves from long-polling to websockets
 | 
				
			||||||
    private func upgradeTransport() {
 | 
					    private func upgradeTransport() {
 | 
				
			||||||
        if ws?.isConnected ?? false {
 | 
					        if ws?.isConnected ?? false {
 | 
				
			||||||
@ -645,6 +654,12 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll
 | 
				
			|||||||
            client?.engineDidClose(reason: "Socket Disconnected")
 | 
					            client?.engineDidClose(reason: "Socket Disconnected")
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Test Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    func setConnected(_ value: Bool) {
 | 
				
			||||||
 | 
					        connected = value
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extension SocketEngine {
 | 
					extension SocketEngine {
 | 
				
			||||||
 | 
				
			|||||||
@ -34,6 +34,9 @@ import Starscream
 | 
				
			|||||||
    /// `true` if this engine is closed.
 | 
					    /// `true` if this engine is closed.
 | 
				
			||||||
    var closed: Bool { get }
 | 
					    var closed: Bool { get }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// If `true` the engine will attempt to use WebSocket compression.
 | 
				
			||||||
 | 
					    var compress: Bool { get }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// `true` if this engine is connected. Connected means that the initial poll connect has succeeded.
 | 
					    /// `true` if this engine is connected. Connected means that the initial poll connect has succeeded.
 | 
				
			||||||
    var connected: Bool { get }
 | 
					    var connected: Bool { get }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										519
									
								
								Source/SocketIO/Manager/SocketManager.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										519
									
								
								Source/SocketIO/Manager/SocketManager.swift
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,519 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// Created by Erik Little on 10/14/17.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//  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 Dispatch
 | 
				
			||||||
 | 
					import Foundation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// A manager for a socket.io connection.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// A `SocketManager` is responsible for multiplexing multiple namespaces through a single `SocketEngineSpec`.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Example:
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// ```swift
 | 
				
			||||||
 | 
					/// let manager = SocketManager(socketURL: URL(string:"http://localhost:8080/")!)
 | 
				
			||||||
 | 
					/// let defaultNamespaceSocket = manager.defaultSocket
 | 
				
			||||||
 | 
					/// let swiftSocket = manager.socket(forNamespace: "/swift")
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// // defaultNamespaceSocket and swiftSocket both share a single connection to the server
 | 
				
			||||||
 | 
					/// ```
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Sockets created through the manager are retained by the manager. So at the very least, a single strong reference
 | 
				
			||||||
 | 
					/// to the manager must be maintained to keep sockets alive.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// To disconnect a socket and remove it from the manager, either call `SocketIOClient.disconnect()` on the socket,
 | 
				
			||||||
 | 
					/// or call one of the `disconnectSocket` methods on this class.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					open class SocketManager : NSObject, SocketManagerSpec, SocketParsable, SocketDataBufferable, ConfigSettable {
 | 
				
			||||||
 | 
					    private static let logType = "SocketManager"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // MARK Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// The socket associated with the default namespace ("/").
 | 
				
			||||||
 | 
					    public var defaultSocket: SocketIOClient? {
 | 
				
			||||||
 | 
					        return socket(forNamespace: "/")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// The URL of the socket.io server.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// If changed after calling `init`, `forceNew` must be set to `true`, or it will only connect to the url set in the
 | 
				
			||||||
 | 
					    /// init.
 | 
				
			||||||
 | 
					    public let socketURL: URL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// The configuration for this client.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// **Some configs will not take affect until after a reconnect if set after calling a connect method**.
 | 
				
			||||||
 | 
					    public var config: SocketIOClientConfiguration {
 | 
				
			||||||
 | 
					        get {
 | 
				
			||||||
 | 
					            return _config
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        set {
 | 
				
			||||||
 | 
					            if status.active {
 | 
				
			||||||
 | 
					                DefaultSocketLogger.Logger.log("Setting configs on active manager. Some configs may not be applied until reconnect",
 | 
				
			||||||
 | 
					                                               type: SocketManager.logType)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            setConfigs(newValue)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// The engine for this manager.
 | 
				
			||||||
 | 
					    public var engine: SocketEngineSpec?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// If `true` then every time `connect` is called, a new engine will be created.
 | 
				
			||||||
 | 
					    public var forceNew = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// The queue that all interaction with the client should occur on. This is the queue that event handlers are
 | 
				
			||||||
 | 
					    /// called on.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// **This should be a serial queue! Concurrent queues are not supported and might cause crashes and races**.
 | 
				
			||||||
 | 
					    public var handleQueue = DispatchQueue.main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// The sockets in this manager indexed by namespace.
 | 
				
			||||||
 | 
					    public var nsps = [String: SocketIOClient]()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// If `true`, this client will try and reconnect on any disconnects.
 | 
				
			||||||
 | 
					    public var reconnects = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// The number of seconds to wait before attempting to reconnect.
 | 
				
			||||||
 | 
					    public var reconnectWait = 10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// The status of this manager.
 | 
				
			||||||
 | 
					    public private(set) var status: SocketIOStatus = .notConnected {
 | 
				
			||||||
 | 
					        didSet {
 | 
				
			||||||
 | 
					            switch status {
 | 
				
			||||||
 | 
					            case .connected:
 | 
				
			||||||
 | 
					                reconnecting = false
 | 
				
			||||||
 | 
					                currentReconnectAttempt = 0
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// A list of packets that are waiting for binary data.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// The way that socket.io works all data should be sent directly after each packet.
 | 
				
			||||||
 | 
					    /// So this should ideally be an array of one packet waiting for data.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// **This should not be modified directly.**
 | 
				
			||||||
 | 
					    public var waitingPackets = [SocketPacket]()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private(set) var reconnectAttempts = -1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private var _config: SocketIOClientConfiguration
 | 
				
			||||||
 | 
					    private var currentReconnectAttempt = 0
 | 
				
			||||||
 | 
					    private var reconnecting = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Type safe way to create a new SocketIOClient. `opts` can be omitted.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// - parameter socketURL: The url of the socket.io server.
 | 
				
			||||||
 | 
					    /// - parameter config: The config for this socket.
 | 
				
			||||||
 | 
					    public init(socketURL: URL, config: SocketIOClientConfiguration = []) {
 | 
				
			||||||
 | 
					        self._config = config
 | 
				
			||||||
 | 
					        self.socketURL = socketURL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if socketURL.absoluteString.hasPrefix("https://") {
 | 
				
			||||||
 | 
					            self._config.insert(.secure(true))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._config.insert(.path("/socket.io/"), replacing: false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        super.init()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        setConfigs(_config)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Not so type safe way to create a SocketIOClient, meant for Objective-C compatiblity.
 | 
				
			||||||
 | 
					    /// If using Swift it's recommended to use `init(socketURL: NSURL, options: Set<SocketIOClientOption>)`
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// - parameter socketURL: The url of the socket.io server.
 | 
				
			||||||
 | 
					    /// - parameter config: The config for this socket.
 | 
				
			||||||
 | 
					    @objc
 | 
				
			||||||
 | 
					    public convenience init(socketURL: NSURL, config: NSDictionary?) {
 | 
				
			||||||
 | 
					        self.init(socketURL: socketURL as URL, config: config?.toSocketConfiguration() ?? [])
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    deinit {
 | 
				
			||||||
 | 
					        DefaultSocketLogger.Logger.log("Manager is being released", type: SocketManager.logType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        engine?.disconnect(reason: "Manager Deinit")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // MARK: Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private func addEngine() {
 | 
				
			||||||
 | 
					        DefaultSocketLogger.Logger.log("Adding engine", type: SocketManager.logType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        engine?.engineQueue.sync {
 | 
				
			||||||
 | 
					            self.engine?.client = nil
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        engine = SocketEngine(client: self, url: socketURL, config: config)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Connects the underlying transport and the default namespace socket.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// Override if you wish to attach a custom `SocketEngineSpec`.
 | 
				
			||||||
 | 
					    open func connect() {
 | 
				
			||||||
 | 
					        guard !status.active else {
 | 
				
			||||||
 | 
					            DefaultSocketLogger.Logger.log("Tried connecting an already active socket", type: SocketManager.logType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if engine == nil || forceNew {
 | 
				
			||||||
 | 
					            addEngine()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        status = .connecting
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        engine?.connect()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Connects a socket through this manager's engine.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// - parameter socket: The socket who we should connect through this manager.
 | 
				
			||||||
 | 
					    open func connectSocket(_ socket: SocketIOClient) {
 | 
				
			||||||
 | 
					        guard status == .connected else {
 | 
				
			||||||
 | 
					            DefaultSocketLogger.Logger.log("Tried connecting socket when engine isn't open. Connecting",
 | 
				
			||||||
 | 
					                                           type: SocketManager.logType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            connect()
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        engine?.send("0\(socket.nsp)", withData: [])
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Called when the manager has disconnected from socket.io.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// - parameter reason: The reason for the disconnection.
 | 
				
			||||||
 | 
					    open func didDisconnect(reason: String) {
 | 
				
			||||||
 | 
					        forAll {socket in
 | 
				
			||||||
 | 
					            socket.didDisconnect(reason: reason)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Disconnects the manager and all associated sockets.
 | 
				
			||||||
 | 
					    open func disconnect() {
 | 
				
			||||||
 | 
					        DefaultSocketLogger.Logger.log("Manager closing", type: SocketManager.logType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        status = .disconnected
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        engine?.disconnect(reason: "Disconnect")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Disconnects the given socket.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// This will remove the socket for the manager's control, and make the socket instance useless and ready for
 | 
				
			||||||
 | 
					    /// releasing.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// - parameter socket: The socket to disconnect.
 | 
				
			||||||
 | 
					    open func disconnectSocket(_ socket: SocketIOClient) {
 | 
				
			||||||
 | 
					        // Make sure we remove socket from nsps
 | 
				
			||||||
 | 
					        nsps.removeValue(forKey: socket.nsp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        engine?.send("1\(socket.nsp)", withData: [])
 | 
				
			||||||
 | 
					        socket.didDisconnect(reason: "Namespace leave")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Disconnects the socket associated with `forNamespace`.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// This will remove the socket for the manager's control, and make the socket instance useless and ready for
 | 
				
			||||||
 | 
					    /// releasing.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// - parameter forNamespace: The namespace to disconnect from.
 | 
				
			||||||
 | 
					    open func disconnectSocket(forNamespace nsp: String) {
 | 
				
			||||||
 | 
					        guard let socket = nsps.removeValue(forKey: nsp) else {
 | 
				
			||||||
 | 
					            DefaultSocketLogger.Logger.log("Could not find socket for \(nsp) to disconnect",
 | 
				
			||||||
 | 
					                                           type: SocketManager.logType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        disconnectSocket(socket)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Sends a client event to all sockets in `nsps`
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// - parameter clientEvent: The event to emit.
 | 
				
			||||||
 | 
					    open func emitAll(clientEvent event: SocketClientEvent, data: [Any]) {
 | 
				
			||||||
 | 
					        forAll {socket in
 | 
				
			||||||
 | 
					            socket.handleClientEvent(event, data: data)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Sends an event to the server on all namespaces in this manager.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// - parameter event: The event to send.
 | 
				
			||||||
 | 
					    /// - parameter items: The data to send with this event.
 | 
				
			||||||
 | 
					    open func emitAll(_ event: String, _ items: SocketData...) {
 | 
				
			||||||
 | 
					        guard let emitData = try? items.map({ try $0.socketRepresentation() }) else {
 | 
				
			||||||
 | 
					            DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)",
 | 
				
			||||||
 | 
					                                             type: SocketManager.logType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        emitAll(event, withItems: emitData)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Sends an event to the server on all namespaces in this manager.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// Same as `emitAll(_:_:)`, but meant for Objective-C.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// - parameter event: The event to send.
 | 
				
			||||||
 | 
					    /// - parameter withItems: The data to send with this event.
 | 
				
			||||||
 | 
					    open func emitAll(_ event: String, withItems items: [Any]) {
 | 
				
			||||||
 | 
					        forAll {socket in
 | 
				
			||||||
 | 
					            socket.emit(event, with: items)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Called when the engine closes.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// - parameter reason: The reason that the engine closed.
 | 
				
			||||||
 | 
					    open func engineDidClose(reason: String) {
 | 
				
			||||||
 | 
					        handleQueue.async {
 | 
				
			||||||
 | 
					            self._engineDidClose(reason: reason)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private func _engineDidClose(reason: String) {
 | 
				
			||||||
 | 
					        waitingPackets.removeAll()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if status != .disconnected {
 | 
				
			||||||
 | 
					            status = .notConnected
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if status == .disconnected || !reconnects {
 | 
				
			||||||
 | 
					            didDisconnect(reason: reason)
 | 
				
			||||||
 | 
					        } else if !reconnecting {
 | 
				
			||||||
 | 
					            reconnecting = true
 | 
				
			||||||
 | 
					            tryReconnect(reason: reason)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Called when the engine errors.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// - parameter reason: The reason the engine errored.
 | 
				
			||||||
 | 
					    open func engineDidError(reason: String) {
 | 
				
			||||||
 | 
					        handleQueue.async {
 | 
				
			||||||
 | 
					            self._engineDidError(reason: reason)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private func _engineDidError(reason: String) {
 | 
				
			||||||
 | 
					        DefaultSocketLogger.Logger.error("\(reason)", type: SocketManager.logType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        emitAll(clientEvent: .error, data: [reason])
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Called when the engine opens.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// - parameter reason: The reason the engine opened.
 | 
				
			||||||
 | 
					    open func engineDidOpen(reason: String) {
 | 
				
			||||||
 | 
					        handleQueue.async {
 | 
				
			||||||
 | 
					            self._engineDidOpen(reason: reason)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private func _engineDidOpen(reason: String) {
 | 
				
			||||||
 | 
					        DefaultSocketLogger.Logger.log("Engine opened \(reason)", type: SocketManager.logType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        status = .connected
 | 
				
			||||||
 | 
					        nsps["/"]?.didConnect(toNamespace: "/")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (nsp, socket) in nsps where nsp != "/" && socket.status == .connecting {
 | 
				
			||||||
 | 
					            connectSocket(socket)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Called when the engine receives a pong message.
 | 
				
			||||||
 | 
					    open func engineDidReceivePong() {
 | 
				
			||||||
 | 
					        handleQueue.async {
 | 
				
			||||||
 | 
					            self._engineDidReceivePong()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private func _engineDidReceivePong() {
 | 
				
			||||||
 | 
					        emitAll(clientEvent: .pong, data: [])
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Called when the sends a ping to the server.
 | 
				
			||||||
 | 
					    open func engineDidSendPing() {
 | 
				
			||||||
 | 
					        handleQueue.async {
 | 
				
			||||||
 | 
					            self._engineDidSendPing()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private func _engineDidSendPing() {
 | 
				
			||||||
 | 
					        emitAll(clientEvent: .ping, data: [])
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private func forAll(do: (SocketIOClient) throws -> ()) rethrows {
 | 
				
			||||||
 | 
					        for (_, socket) in nsps {
 | 
				
			||||||
 | 
					            try `do`(socket)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Called when the engine has a message that must be parsed.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// - parameter msg: The message that needs parsing.
 | 
				
			||||||
 | 
					    open func parseEngineMessage(_ msg: String) {
 | 
				
			||||||
 | 
					        handleQueue.async {
 | 
				
			||||||
 | 
					            self._parseEngineMessage(msg)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private func _parseEngineMessage(_ msg: String) {
 | 
				
			||||||
 | 
					        guard let packet = parseSocketMessage(msg) else { return }
 | 
				
			||||||
 | 
					        guard packet.type != .binaryAck && packet.type != .binaryEvent else {
 | 
				
			||||||
 | 
					            waitingPackets.append(packet)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        nsps[packet.nsp]?.handlePacket(packet)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Called when the engine receives binary data.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// - parameter data: The data the engine received.
 | 
				
			||||||
 | 
					    open func parseEngineBinaryData(_ data: Data) {
 | 
				
			||||||
 | 
					        handleQueue.async {
 | 
				
			||||||
 | 
					            self._parseEngineBinaryData(data)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private func _parseEngineBinaryData(_ data: Data) {
 | 
				
			||||||
 | 
					        guard let packet = parseBinaryData(data) else { return }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        nsps[packet.nsp]?.handlePacket(packet)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Tries to reconnect to the server.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// This will cause a `disconnect` event to be emitted, as well as an `reconnectAttempt` event.
 | 
				
			||||||
 | 
					    open func reconnect() {
 | 
				
			||||||
 | 
					        guard !reconnecting else { return }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        engine?.disconnect(reason: "manual reconnect")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private func tryReconnect(reason: String) {
 | 
				
			||||||
 | 
					        guard reconnecting else { return }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        DefaultSocketLogger.Logger.log("Starting reconnect", type: SocketManager.logType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Set status to connecting and emit reconnect for all sockets
 | 
				
			||||||
 | 
					        forAll {socket in
 | 
				
			||||||
 | 
					            guard socket.status == .connected else { return }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            socket.setReconnecting(reason: reason)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _tryReconnect()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private func _tryReconnect() {
 | 
				
			||||||
 | 
					        guard reconnects && reconnecting && status != .disconnected else { return }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if reconnectAttempts != -1 && currentReconnectAttempt + 1 > reconnectAttempts {
 | 
				
			||||||
 | 
					            return didDisconnect(reason: "Reconnect Failed")
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        DefaultSocketLogger.Logger.log("Trying to reconnect", type: SocketManager.logType)
 | 
				
			||||||
 | 
					        emitAll(clientEvent: .reconnectAttempt, data: [(reconnectAttempts - currentReconnectAttempt)])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        currentReconnectAttempt += 1
 | 
				
			||||||
 | 
					        connect()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        handleQueue.asyncAfter(deadline: DispatchTime.now() + Double(reconnectWait), execute: _tryReconnect)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Sets manager specific configs.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// parameter config: The configs that should be set.
 | 
				
			||||||
 | 
					    open func setConfigs(_ config: SocketIOClientConfiguration) {
 | 
				
			||||||
 | 
					        for option in config {
 | 
				
			||||||
 | 
					            switch option {
 | 
				
			||||||
 | 
					            case let .forceNew(new):
 | 
				
			||||||
 | 
					                self.forceNew = new
 | 
				
			||||||
 | 
					            case let .reconnects(reconnects):
 | 
				
			||||||
 | 
					                self.reconnects = reconnects
 | 
				
			||||||
 | 
					            case let .reconnectWait(wait):
 | 
				
			||||||
 | 
					                reconnectWait = abs(wait)
 | 
				
			||||||
 | 
					            case let .log(log):
 | 
				
			||||||
 | 
					                DefaultSocketLogger.Logger.log = log
 | 
				
			||||||
 | 
					            case let .logger(logger):
 | 
				
			||||||
 | 
					                DefaultSocketLogger.Logger = logger
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _config = config
 | 
				
			||||||
 | 
					        _config.insert(.path("/socket.io/"), replacing: false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // If `ConfigSettable` & `SocketEngineSpec`, update its configs.
 | 
				
			||||||
 | 
					        if var settableEngine = engine as? ConfigSettable & SocketEngineSpec {
 | 
				
			||||||
 | 
					            settableEngine.engineQueue.sync {
 | 
				
			||||||
 | 
					                settableEngine.setConfigs(self._config)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            engine = settableEngine
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Returns a `SocketIOClient` for the given namespace. This socket shares a transport with the manager.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// Calling multiple times returns the same socket.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// Sockets created from this method are retained by the manager.
 | 
				
			||||||
 | 
					    /// Call one of the `disconnectSocket` methods on this class to remove the socket from manager control.
 | 
				
			||||||
 | 
					    /// Or call `SocketIOClient.disconnect()` on the client.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// - parameter forNamespace: The namespace for the socket.
 | 
				
			||||||
 | 
					    /// - returns: A `SocketIOClient` for the given namespace.
 | 
				
			||||||
 | 
					    open func socket(forNamespace nsp: String) -> SocketIOClient {
 | 
				
			||||||
 | 
					        assert(nsp.hasPrefix("/"), "forNamespace must have a leading /")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if let socket = nsps[nsp] {
 | 
				
			||||||
 | 
					            return socket
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let client = SocketIOClient(manager: self, nsp: nsp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        nsps[nsp] = client
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return client
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Test properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    func setTestStatus(_ status: SocketIOStatus) {
 | 
				
			||||||
 | 
					        self.status = status
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										128
									
								
								Source/SocketIO/Manager/SocketManagerSpec.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								Source/SocketIO/Manager/SocketManagerSpec.swift
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,128 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// Created by Erik Little on 10/18/17.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//  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 Dispatch
 | 
				
			||||||
 | 
					import Foundation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO Fix the types so that we aren't using concrete types
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// A manager for a socket.io connection.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// A `SocketManagerSpec` is responsible for multiplexing multiple namespaces through a single `SocketEngineSpec`.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Example with `SocketManager`:
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// ```swift
 | 
				
			||||||
 | 
					/// let manager = SocketManager(socketURL: URL(string:"http://localhost:8080/")!)
 | 
				
			||||||
 | 
					/// let defaultNamespaceSocket = manager.defaultSocket
 | 
				
			||||||
 | 
					/// let swiftSocket = manager.socket(forNamespace: "/swift")
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// // defaultNamespaceSocket and swiftSocket both share a single connection to the server
 | 
				
			||||||
 | 
					/// ```
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Sockets created through the manager are retained by the manager. So at the very least, a single strong reference
 | 
				
			||||||
 | 
					/// to the manager must be maintained to keep sockets alive.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// To disconnect a socket and remove it from the manager, either call `SocketIOClient.disconnect()` on the socket,
 | 
				
			||||||
 | 
					/// or call one of the `disconnectSocket` methods on this class.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					@objc
 | 
				
			||||||
 | 
					public protocol SocketManagerSpec : class, SocketEngineClient {
 | 
				
			||||||
 | 
					    // MARK: Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Returns the socket associated with the default namespace ("/").
 | 
				
			||||||
 | 
					    var defaultSocket: SocketIOClient? { get }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// The engine for this manager.
 | 
				
			||||||
 | 
					    var engine: SocketEngineSpec? { get set }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// If `true` then every time `connect` is called, a new engine will be created.
 | 
				
			||||||
 | 
					    var forceNew: Bool { get set }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO Per socket queues?
 | 
				
			||||||
 | 
					    /// The queue that all interaction with the client should occur on. This is the queue that event handlers are
 | 
				
			||||||
 | 
					    /// called on.
 | 
				
			||||||
 | 
					    var handleQueue: DispatchQueue { get set }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// If `true`, this manager will try and reconnect on any disconnects.
 | 
				
			||||||
 | 
					    var reconnects: Bool { get set }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// The number of seconds to wait before attempting to reconnect.
 | 
				
			||||||
 | 
					    var reconnectWait: Int { get set }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// The URL of the socket.io server.
 | 
				
			||||||
 | 
					    var socketURL: URL { get }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// The status of this manager.
 | 
				
			||||||
 | 
					    var status: SocketIOStatus { get }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // MARK: Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Connects the underlying transport.
 | 
				
			||||||
 | 
					    func connect()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Connects a socket through this manager's engine.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// - parameter socket: The socket who we should connect through this manager.
 | 
				
			||||||
 | 
					    func connectSocket(_ socket: SocketIOClient)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Called when the manager has disconnected from socket.io.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// - parameter reason: The reason for the disconnection.
 | 
				
			||||||
 | 
					    func didDisconnect(reason: String)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Disconnects the manager and all associated sockets.
 | 
				
			||||||
 | 
					    func disconnect()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Disconnects the given socket.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// - parameter socket: The socket to disconnect.
 | 
				
			||||||
 | 
					    func disconnectSocket(_ socket: SocketIOClient)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Disconnects the socket associated with `forNamespace`.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// - parameter forNamespace: The namespace to disconnect from.
 | 
				
			||||||
 | 
					    func disconnectSocket(forNamespace nsp: String)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Sends an event to the server on all namespaces in this manager.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// - parameter event: The event to send.
 | 
				
			||||||
 | 
					    /// - parameter withItems: The data to send with this event.
 | 
				
			||||||
 | 
					    func emitAll(_ event: String, withItems items: [Any])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Tries to reconnect to the server.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// This will cause a `disconnect` event to be emitted, as well as an `reconnectAttempt` event.
 | 
				
			||||||
 | 
					    func reconnect()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Returns a `SocketIOClient` for the given namespace. This socket shares a transport with the manager.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// Calling multiple times returns the same socket.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// Sockets created from this method are retained by the manager.
 | 
				
			||||||
 | 
					    /// Call one of the `disconnectSocket` methods on the implementing class to remove the socket from manager control.
 | 
				
			||||||
 | 
					    /// Or call `SocketIOClient.disconnect()` on the client.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// - parameter forNamespace: The namespace for the socket.
 | 
				
			||||||
 | 
					    /// - returns: A `SocketIOClient` for the given namespace.
 | 
				
			||||||
 | 
					    func socket(forNamespace nsp: String) -> SocketIOClient
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -142,12 +142,8 @@ public struct SocketPacket : CustomStringConvertible {
 | 
				
			|||||||
            if dict["_placeholder"] as? Bool ?? false {
 | 
					            if dict["_placeholder"] as? Bool ?? false {
 | 
				
			||||||
                return binary[dict["num"] as! Int]
 | 
					                return binary[dict["num"] as! Int]
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                return dict.reduce(JSON(), {cur, keyValue in
 | 
					                return dict.reduce(into: JSON(), {cur, keyValue in
 | 
				
			||||||
                    var cur = cur
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    cur[keyValue.0] = _fillInPlaceholders(keyValue.1)
 | 
					                    cur[keyValue.0] = _fillInPlaceholders(keyValue.1)
 | 
				
			||||||
 | 
					 | 
				
			||||||
                    return cur
 | 
					 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        case let arr as [Any]:
 | 
					        case let arr as [Any]:
 | 
				
			||||||
@ -225,12 +221,8 @@ private extension SocketPacket {
 | 
				
			|||||||
        case let arr as [Any]:
 | 
					        case let arr as [Any]:
 | 
				
			||||||
            return arr.map({shred($0, binary: &binary)})
 | 
					            return arr.map({shred($0, binary: &binary)})
 | 
				
			||||||
        case let dict as JSON:
 | 
					        case let dict as JSON:
 | 
				
			||||||
            return dict.reduce(JSON(), {cur, keyValue in
 | 
					            return dict.reduce(into: JSON(), {cur, keyValue in
 | 
				
			||||||
                var mutCur = cur
 | 
					                cur[keyValue.0] = shred(keyValue.1, binary: &binary)
 | 
				
			||||||
 | 
					 | 
				
			||||||
                mutCur[keyValue.0] = shred(keyValue.1, binary: &binary)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                return mutCur
 | 
					 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
        default:
 | 
					        default:
 | 
				
			||||||
            return data
 | 
					            return data
 | 
				
			||||||
 | 
				
			|||||||
@ -26,14 +26,6 @@ import Foundation
 | 
				
			|||||||
public protocol SocketParsable : class {
 | 
					public protocol SocketParsable : class {
 | 
				
			||||||
    // MARK: Properties
 | 
					    // MARK: Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// A list of packets that are waiting for binary data.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// The way that socket.io works all data should be sent directly after each packet.
 | 
					 | 
				
			||||||
    /// So this should ideally be an array of one packet waiting for data.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// **This should not be modified directly.**
 | 
					 | 
				
			||||||
    var waitingPackets: [SocketPacket] { get set }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // MARK: Methods
 | 
					    // MARK: Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Called when the engine has received some binary data that should be attached to a packet.
 | 
					    /// Called when the engine has received some binary data that should be attached to a packet.
 | 
				
			||||||
@ -43,12 +35,13 @@ public protocol SocketParsable : class {
 | 
				
			|||||||
    /// into the correct placeholder.
 | 
					    /// into the correct placeholder.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// - parameter data: The data that should be attached to a packet.
 | 
					    /// - parameter data: The data that should be attached to a packet.
 | 
				
			||||||
    func parseBinaryData(_ data: Data)
 | 
					    func parseBinaryData(_ data: Data) -> SocketPacket?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Called when the engine has received a string that should be parsed into a socket.io packet.
 | 
					    /// Called when the engine has received a string that should be parsed into a socket.io packet.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// - parameter message: The string that needs parsing.
 | 
					    /// - parameter message: The string that needs parsing.
 | 
				
			||||||
    func parseSocketMessage(_ message: String)
 | 
					    /// - returns: A completed socket packet if there is no more data left to collect.
 | 
				
			||||||
 | 
					    func parseSocketMessage(_ message: String) -> SocketPacket?
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Errors that can be thrown during parsing.
 | 
					/// Errors that can be thrown during parsing.
 | 
				
			||||||
@ -65,38 +58,18 @@ public enum SocketParsableError : Error {
 | 
				
			|||||||
    case invalidPacketType
 | 
					    case invalidPacketType
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public extension SocketParsable where Self: SocketIOClientSpec {
 | 
					/// Says that a type will be able to buffer binary data before all data for an event has come in.
 | 
				
			||||||
    private func isCorrectNamespace(_ nsp: String) -> Bool {
 | 
					public protocol SocketDataBufferable : class {
 | 
				
			||||||
        return nsp == self.nsp
 | 
					    /// A list of packets that are waiting for binary data.
 | 
				
			||||||
    }
 | 
					    ///
 | 
				
			||||||
 | 
					    /// The way that socket.io works all data should be sent directly after each packet.
 | 
				
			||||||
    private func handleConnect(_ packetNamespace: String) {
 | 
					    /// So this should ideally be an array of one packet waiting for data.
 | 
				
			||||||
        guard packetNamespace == nsp else { return }
 | 
					    ///
 | 
				
			||||||
 | 
					    /// **This should not be modified directly.**
 | 
				
			||||||
        didConnect(toNamespace: packetNamespace)
 | 
					    var waitingPackets: [SocketPacket] { get set }
 | 
				
			||||||
    }
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
    private func handlePacket(_ pack: SocketPacket) {
 | 
					 | 
				
			||||||
        switch pack.type {
 | 
					 | 
				
			||||||
        case .event where isCorrectNamespace(pack.nsp):
 | 
					 | 
				
			||||||
            handleEvent(pack.event, data: pack.args, isInternalMessage: false, withAck: pack.id)
 | 
					 | 
				
			||||||
        case .ack where isCorrectNamespace(pack.nsp):
 | 
					 | 
				
			||||||
            handleAck(pack.id, data: pack.data)
 | 
					 | 
				
			||||||
        case .binaryEvent where isCorrectNamespace(pack.nsp):
 | 
					 | 
				
			||||||
            waitingPackets.append(pack)
 | 
					 | 
				
			||||||
        case .binaryAck where isCorrectNamespace(pack.nsp):
 | 
					 | 
				
			||||||
            waitingPackets.append(pack)
 | 
					 | 
				
			||||||
        case .connect:
 | 
					 | 
				
			||||||
            handleConnect(pack.nsp)
 | 
					 | 
				
			||||||
        case .disconnect:
 | 
					 | 
				
			||||||
            didDisconnect(reason: "Got Disconnect")
 | 
					 | 
				
			||||||
        case .error:
 | 
					 | 
				
			||||||
            handleEvent("error", data: pack.data, isInternalMessage: true, withAck: pack.id)
 | 
					 | 
				
			||||||
        default:
 | 
					 | 
				
			||||||
            DefaultSocketLogger.Logger.log("Got invalid packet: \(pack.description)", type: "SocketParser")
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public extension SocketParsable where Self: SocketManagerSpec & SocketDataBufferable {
 | 
				
			||||||
    /// Parses a message from the engine, returning a complete SocketPacket or throwing.
 | 
					    /// Parses a message from the engine, returning a complete SocketPacket or throwing.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// - parameter message: The message to parse.
 | 
					    /// - parameter message: The message to parse.
 | 
				
			||||||
@ -169,8 +142,9 @@ public extension SocketParsable where Self: SocketIOClientSpec {
 | 
				
			|||||||
    /// Called when the engine has received a string that should be parsed into a socket.io packet.
 | 
					    /// Called when the engine has received a string that should be parsed into a socket.io packet.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// - parameter message: The string that needs parsing.
 | 
					    /// - parameter message: The string that needs parsing.
 | 
				
			||||||
    public func parseSocketMessage(_ message: String) {
 | 
					    /// - returns: A completed socket packet or nil if the packet is invalid.
 | 
				
			||||||
        guard !message.isEmpty else { return }
 | 
					    public func parseSocketMessage(_ message: String) -> SocketPacket? {
 | 
				
			||||||
 | 
					        guard !message.isEmpty else { return nil }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        DefaultSocketLogger.Logger.log("Parsing \(message)", type: "SocketParser")
 | 
					        DefaultSocketLogger.Logger.log("Parsing \(message)", type: "SocketParser")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -179,9 +153,11 @@ public extension SocketParsable where Self: SocketIOClientSpec {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            DefaultSocketLogger.Logger.log("Decoded packet as: \(packet.description)", type: "SocketParser")
 | 
					            DefaultSocketLogger.Logger.log("Decoded packet as: \(packet.description)", type: "SocketParser")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            handlePacket(packet)
 | 
					            return packet
 | 
				
			||||||
        } catch {
 | 
					        } catch {
 | 
				
			||||||
            DefaultSocketLogger.Logger.error("\(error): \(message)", type: "SocketParser")
 | 
					            DefaultSocketLogger.Logger.error("\(error): \(message)", type: "SocketParser")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return nil
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -192,21 +168,17 @@ public extension SocketParsable where Self: SocketIOClientSpec {
 | 
				
			|||||||
    /// into the correct placeholder.
 | 
					    /// into the correct placeholder.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// - parameter data: The data that should be attached to a packet.
 | 
					    /// - parameter data: The data that should be attached to a packet.
 | 
				
			||||||
    public func parseBinaryData(_ data: Data) {
 | 
					    /// - returns: A completed socket packet if there is no more data left to collect.
 | 
				
			||||||
 | 
					    public func parseBinaryData(_ data: Data) -> SocketPacket? {
 | 
				
			||||||
        guard !waitingPackets.isEmpty else {
 | 
					        guard !waitingPackets.isEmpty else {
 | 
				
			||||||
            DefaultSocketLogger.Logger.error("Got data when not remaking packet", type: "SocketParser")
 | 
					            DefaultSocketLogger.Logger.error("Got data when not remaking packet", type: "SocketParser")
 | 
				
			||||||
            return
 | 
					
 | 
				
			||||||
 | 
					            return nil
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Should execute event?
 | 
					        // Should execute event?
 | 
				
			||||||
        guard waitingPackets[waitingPackets.count - 1].addData(data) else { return }
 | 
					        guard waitingPackets[waitingPackets.count - 1].addData(data) else { return nil }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let packet = waitingPackets.removeLast()
 | 
					        return waitingPackets.removeLast()
 | 
				
			||||||
 | 
					 | 
				
			||||||
        if packet.type != .binaryAck {
 | 
					 | 
				
			||||||
            handleEvent(packet.event, data: packet.args, isInternalMessage: false, withAck: packet.id)
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            handleAck(packet.id, data: packet.args)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,110 +0,0 @@
 | 
				
			|||||||
//
 | 
					 | 
				
			||||||
//  SocketClientManager.swift
 | 
					 | 
				
			||||||
//  Socket.IO-Client-Swift
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
//  Created by Erik Little on 6/11/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
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 Experimental socket manager.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 API subject to change.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 Can be used to persist sockets across ViewControllers.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 Sockets are strongly stored, so be sure to remove them once they are no
 | 
					 | 
				
			||||||
 longer needed.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 Example usage:
 | 
					 | 
				
			||||||
 ```
 | 
					 | 
				
			||||||
 let manager = SocketClientManager.sharedManager
 | 
					 | 
				
			||||||
 manager["room1"] = socket1
 | 
					 | 
				
			||||||
 manager["room2"] = socket2
 | 
					 | 
				
			||||||
 manager.removeSocket(socket: socket2)
 | 
					 | 
				
			||||||
 manager["room1"]?.emit("hello")
 | 
					 | 
				
			||||||
 ```
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
open class SocketClientManager : NSObject {
 | 
					 | 
				
			||||||
    // MARK: Properties.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// The shared manager.
 | 
					 | 
				
			||||||
    @objc
 | 
					 | 
				
			||||||
    open static let sharedManager = SocketClientManager()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private var sockets = [String: SocketIOClient]()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Gets a socket by its name.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// - returns: The socket, if one had the given name.
 | 
					 | 
				
			||||||
    open subscript(string: String) -> SocketIOClient? {
 | 
					 | 
				
			||||||
        get {
 | 
					 | 
				
			||||||
            return sockets[string]
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        set(socket) {
 | 
					 | 
				
			||||||
            sockets[string] = socket
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // MARK: Methods.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Adds a socket.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// - parameter socket: The socket to add.
 | 
					 | 
				
			||||||
    /// - parameter labeledAs: The label for this socket.
 | 
					 | 
				
			||||||
    @objc
 | 
					 | 
				
			||||||
    open func addSocket(_ socket: SocketIOClient, labeledAs label: String) {
 | 
					 | 
				
			||||||
        sockets[label] = socket
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Removes a socket by a given name.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// - parameter withLabel: The label of the socket to remove.
 | 
					 | 
				
			||||||
    /// - returns: The socket for the given label, if one was present.
 | 
					 | 
				
			||||||
    @objc
 | 
					 | 
				
			||||||
    @discardableResult
 | 
					 | 
				
			||||||
    open func removeSocket(withLabel label: String) -> SocketIOClient? {
 | 
					 | 
				
			||||||
        return sockets.removeValue(forKey: label)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Removes a socket.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// - parameter socket: The socket to remove.
 | 
					 | 
				
			||||||
    /// - returns: The socket if it was in the manager.
 | 
					 | 
				
			||||||
    @objc
 | 
					 | 
				
			||||||
    @discardableResult
 | 
					 | 
				
			||||||
    open func removeSocket(_ socket: SocketIOClient) -> SocketIOClient? {
 | 
					 | 
				
			||||||
        var returnSocket: SocketIOClient?
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for (label, dictSocket) in sockets where dictSocket === socket {
 | 
					 | 
				
			||||||
            returnSocket = sockets.removeValue(forKey: label)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return returnSocket
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Removes all the sockets in the manager.
 | 
					 | 
				
			||||||
    @objc
 | 
					 | 
				
			||||||
    open func removeSockets() {
 | 
					 | 
				
			||||||
        sockets.removeAll()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -63,8 +63,6 @@ extension NSDictionary {
 | 
				
			|||||||
            return .log(log)
 | 
					            return .log(log)
 | 
				
			||||||
        case let ("logger", logger as SocketLogger):
 | 
					        case let ("logger", logger as SocketLogger):
 | 
				
			||||||
            return .logger(logger)
 | 
					            return .logger(logger)
 | 
				
			||||||
        case let ("nsp", nsp as String):
 | 
					 | 
				
			||||||
            return .nsp(nsp)
 | 
					 | 
				
			||||||
        case let ("path", path as String):
 | 
					        case let ("path", path as String):
 | 
				
			||||||
            return .path(path)
 | 
					            return .path(path)
 | 
				
			||||||
        case let ("reconnects", reconnects as Bool):
 | 
					        case let ("reconnects", reconnects as Bool):
 | 
				
			||||||
 | 
				
			|||||||
@ -150,10 +150,9 @@ class SocketBasicPacketTest: XCTestCase {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    func testBinaryStringPlaceholderInMessage() {
 | 
					    func testBinaryStringPlaceholderInMessage() {
 | 
				
			||||||
        let engineString = "52-[\"test\",\"~~0\",{\"num\":0,\"_placeholder\":true},{\"_placeholder\":true,\"num\":1}]"
 | 
					        let engineString = "52-[\"test\",\"~~0\",{\"num\":0,\"_placeholder\":true},{\"_placeholder\":true,\"num\":1}]"
 | 
				
			||||||
        let socket = SocketIOClient(socketURL: URL(string: "http://localhost/")!)
 | 
					        let manager = SocketManager(socketURL: URL(string: "http://localhost/")!)
 | 
				
			||||||
        socket.setTestable()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        var packet = try! socket.parseString(engineString)
 | 
					        var packet = try! manager.parseString(engineString)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        XCTAssertEqual(packet.event, "test")
 | 
					        XCTAssertEqual(packet.event, "test")
 | 
				
			||||||
        _ = packet.addData(data)
 | 
					        _ = packet.addData(data)
 | 
				
			||||||
 | 
				
			|||||||
@ -10,20 +10,9 @@ import XCTest
 | 
				
			|||||||
@testable import SocketIO
 | 
					@testable import SocketIO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SocketEngineTest: XCTestCase {
 | 
					class SocketEngineTest: XCTestCase {
 | 
				
			||||||
    var client: SocketIOClient!
 | 
					 | 
				
			||||||
    var engine: SocketEngine!
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override func setUp() {
 | 
					 | 
				
			||||||
        super.setUp()
 | 
					 | 
				
			||||||
        client = SocketIOClient(socketURL: URL(string: "http://localhost")!)
 | 
					 | 
				
			||||||
        engine = SocketEngine(client: client, url: URL(string: "http://localhost")!, options: nil)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        client.setTestable()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    func testBasicPollingMessage() {
 | 
					    func testBasicPollingMessage() {
 | 
				
			||||||
        let expect = expectation(description: "Basic polling test")
 | 
					        let expect = expectation(description: "Basic polling test")
 | 
				
			||||||
        client.on("blankTest") {data, ack in
 | 
					        socket.on("blankTest") {data, ack in
 | 
				
			||||||
            expect.fulfill()
 | 
					            expect.fulfill()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -35,11 +24,11 @@ class SocketEngineTest: XCTestCase {
 | 
				
			|||||||
        let finalExpectation = expectation(description: "Final packet in poll test")
 | 
					        let finalExpectation = expectation(description: "Final packet in poll test")
 | 
				
			||||||
        var gotBlank = false
 | 
					        var gotBlank = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        client.on("blankTest") {data, ack in
 | 
					        socket.on("blankTest") {data, ack in
 | 
				
			||||||
            gotBlank = true
 | 
					            gotBlank = true
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        client.on("stringTest") {data, ack in
 | 
					        socket.on("stringTest") {data, ack in
 | 
				
			||||||
            if let str = data[0] as? String, gotBlank {
 | 
					            if let str = data[0] as? String, gotBlank {
 | 
				
			||||||
                if str == "hello" {
 | 
					                if str == "hello" {
 | 
				
			||||||
                    finalExpectation.fulfill()
 | 
					                    finalExpectation.fulfill()
 | 
				
			||||||
@ -54,7 +43,7 @@ class SocketEngineTest: XCTestCase {
 | 
				
			|||||||
    func testEngineDoesErrorOnUnknownTransport() {
 | 
					    func testEngineDoesErrorOnUnknownTransport() {
 | 
				
			||||||
        let finalExpectation = expectation(description: "Unknown Transport")
 | 
					        let finalExpectation = expectation(description: "Unknown Transport")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        client.on("error") {data, ack in
 | 
					        socket.on("error") {data, ack in
 | 
				
			||||||
            if let error = data[0] as? String, error == "Unknown transport" {
 | 
					            if let error = data[0] as? String, error == "Unknown transport" {
 | 
				
			||||||
                finalExpectation.fulfill()
 | 
					                finalExpectation.fulfill()
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -67,7 +56,7 @@ class SocketEngineTest: XCTestCase {
 | 
				
			|||||||
    func testEngineDoesErrorOnUnknownMessage() {
 | 
					    func testEngineDoesErrorOnUnknownMessage() {
 | 
				
			||||||
        let finalExpectation = expectation(description: "Engine Errors")
 | 
					        let finalExpectation = expectation(description: "Engine Errors")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        client.on("error") {data, ack in
 | 
					        socket.on("error") {data, ack in
 | 
				
			||||||
            finalExpectation.fulfill()
 | 
					            finalExpectation.fulfill()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -78,7 +67,7 @@ class SocketEngineTest: XCTestCase {
 | 
				
			|||||||
    func testEngineDecodesUTF8Properly() {
 | 
					    func testEngineDecodesUTF8Properly() {
 | 
				
			||||||
        let expect = expectation(description: "Engine Decodes utf8")
 | 
					        let expect = expectation(description: "Engine Decodes utf8")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        client.on("stringTest") {data, ack in
 | 
					        socket.on("stringTest") {data, ack in
 | 
				
			||||||
            XCTAssertEqual(data[0] as? String, "lïne one\nlīne \rtwo𦅙𦅛", "Failed string test")
 | 
					            XCTAssertEqual(data[0] as? String, "lïne one\nlīne \rtwo𦅙𦅛", "Failed string test")
 | 
				
			||||||
            expect.fulfill()
 | 
					            expect.fulfill()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -110,7 +99,7 @@ class SocketEngineTest: XCTestCase {
 | 
				
			|||||||
        let b64String = "b4aGVsbG8NCg=="
 | 
					        let b64String = "b4aGVsbG8NCg=="
 | 
				
			||||||
        let packetString = "451-[\"test\",{\"test\":{\"_placeholder\":true,\"num\":0}}]"
 | 
					        let packetString = "451-[\"test\",{\"test\":{\"_placeholder\":true,\"num\":0}}]"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        client.on("test") {data, ack in
 | 
					        socket.on("test") {data, ack in
 | 
				
			||||||
            if let data = data[0] as? Data, let string = String(data: data, encoding: .utf8) {
 | 
					            if let data = data[0] as? Data, let string = String(data: data, encoding: .utf8) {
 | 
				
			||||||
                XCTAssertEqual(string, "hello")
 | 
					                XCTAssertEqual(string, "hello")
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -123,4 +112,97 @@ class SocketEngineTest: XCTestCase {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        waitForExpectations(timeout: 3, handler: nil)
 | 
					        waitForExpectations(timeout: 3, handler: nil)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    func testSettingExtraHeadersBeforeConnectSetsEngineExtraHeaders() {
 | 
				
			||||||
 | 
					        let newValue = ["hello": "world"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        manager.engine = engine
 | 
				
			||||||
 | 
					        manager.setTestStatus(.notConnected)
 | 
				
			||||||
 | 
					        manager.config = [.extraHeaders(["new": "value"])]
 | 
				
			||||||
 | 
					        manager.config.insert(.extraHeaders(newValue), replacing: true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        XCTAssertEqual(2, manager.config.count)
 | 
				
			||||||
 | 
					        XCTAssertEqual(manager.engine!.extraHeaders!, newValue)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for config in manager.config {
 | 
				
			||||||
 | 
					            switch config {
 | 
				
			||||||
 | 
					            case let .extraHeaders(headers):
 | 
				
			||||||
 | 
					                XCTAssertTrue(headers.keys.contains("hello"), "It should contain hello header key")
 | 
				
			||||||
 | 
					                XCTAssertFalse(headers.keys.contains("new"), "It should not contain old data")
 | 
				
			||||||
 | 
					            case .path:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                XCTFail("It should only have two configs")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    func testSettingExtraHeadersAfterConnectDoesNotIgnoreChanges() {
 | 
				
			||||||
 | 
					        let newValue = ["hello": "world"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        manager.engine = engine
 | 
				
			||||||
 | 
					        manager.setTestStatus(.connected)
 | 
				
			||||||
 | 
					        engine.setConnected(true)
 | 
				
			||||||
 | 
					        manager.config = [.extraHeaders(["new": "value"])]
 | 
				
			||||||
 | 
					        manager.config.insert(.extraHeaders(["hello": "world"]), replacing: true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        XCTAssertEqual(2, manager.config.count)
 | 
				
			||||||
 | 
					        XCTAssertEqual(manager.engine!.extraHeaders!, newValue)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    func testSettingPathAfterConnectDoesNotIgnoreChanges() {
 | 
				
			||||||
 | 
					        let newValue = "/newpath/"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        manager.engine = engine
 | 
				
			||||||
 | 
					        manager.setTestStatus(.connected)
 | 
				
			||||||
 | 
					        engine.setConnected(true)
 | 
				
			||||||
 | 
					        manager.config.insert(.path(newValue))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        XCTAssertEqual(1, manager.config.count)
 | 
				
			||||||
 | 
					        XCTAssertEqual(manager.engine!.socketPath, newValue)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    func testSettingCompressAfterConnectDoesNotIgnoreChanges() {
 | 
				
			||||||
 | 
					        manager.engine = engine
 | 
				
			||||||
 | 
					        manager.setTestStatus(.connected)
 | 
				
			||||||
 | 
					        engine.setConnected(true)
 | 
				
			||||||
 | 
					        manager.config.insert(.compress)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        XCTAssertEqual(2, manager.config.count)
 | 
				
			||||||
 | 
					        XCTAssertTrue(manager.engine!.compress)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    func testSettingForcePollingAfterConnectDoesNotIgnoreChanges() {
 | 
				
			||||||
 | 
					        manager.engine = engine
 | 
				
			||||||
 | 
					        manager.setTestStatus(.connected)
 | 
				
			||||||
 | 
					        engine.setConnected(true)
 | 
				
			||||||
 | 
					        manager.config.insert(.forcePolling(true))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        XCTAssertEqual(2, manager.config.count)
 | 
				
			||||||
 | 
					        XCTAssertTrue(manager.engine!.forcePolling)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    func testSettingForceWebSocketsAfterConnectDoesNotIgnoreChanges() {
 | 
				
			||||||
 | 
					        manager.engine = engine
 | 
				
			||||||
 | 
					        manager.setTestStatus(.connected)
 | 
				
			||||||
 | 
					        engine.setConnected(true)
 | 
				
			||||||
 | 
					        manager.config.insert(.forceWebsockets(true))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        XCTAssertEqual(2, manager.config.count)
 | 
				
			||||||
 | 
					        XCTAssertTrue(manager.engine!.forceWebsockets)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var manager: SocketManager!
 | 
				
			||||||
 | 
					    var socket: SocketIOClient!
 | 
				
			||||||
 | 
					    var engine: SocketEngine!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override func setUp() {
 | 
				
			||||||
 | 
					        super.setUp()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        manager = SocketManager(socketURL: URL(string: "http://localhost")!)
 | 
				
			||||||
 | 
					        socket = manager.defaultSocket
 | 
				
			||||||
 | 
					        engine = SocketEngine(client: manager, url: URL(string: "http://localhost")!, options: nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        socket.setTestable()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -9,20 +9,12 @@
 | 
				
			|||||||
import XCTest
 | 
					import XCTest
 | 
				
			||||||
import SocketIO
 | 
					import SocketIO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestSocketIOClientConfiguration: XCTestCase {
 | 
					class TestSocketIOClientConfiguration : XCTestCase {
 | 
				
			||||||
    var config = [] as SocketIOClientConfiguration
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override func setUp() {
 | 
					 | 
				
			||||||
        super.setUp()
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        config = [.log(false), .forceNew(true)]
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    func testReplaceSameOption() {
 | 
					    func testReplaceSameOption() {
 | 
				
			||||||
        config.insert(.log(true))
 | 
					        config.insert(.log(true))
 | 
				
			||||||
        
 | 
					
 | 
				
			||||||
        XCTAssertEqual(config.count, 2)
 | 
					        XCTAssertEqual(config.count, 2)
 | 
				
			||||||
        
 | 
					
 | 
				
			||||||
        switch config[0] {
 | 
					        switch config[0] {
 | 
				
			||||||
        case let .log(log):
 | 
					        case let .log(log):
 | 
				
			||||||
            XCTAssertTrue(log)
 | 
					            XCTAssertTrue(log)
 | 
				
			||||||
@ -30,12 +22,12 @@ class TestSocketIOClientConfiguration: XCTestCase {
 | 
				
			|||||||
            XCTFail()
 | 
					            XCTFail()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    func testIgnoreIfExisting() {
 | 
					    func testIgnoreIfExisting() {
 | 
				
			||||||
        config.insert(.forceNew(false), replacing: false)
 | 
					        config.insert(.forceNew(false), replacing: false)
 | 
				
			||||||
        
 | 
					
 | 
				
			||||||
        XCTAssertEqual(config.count, 2)
 | 
					        XCTAssertEqual(config.count, 2)
 | 
				
			||||||
        
 | 
					
 | 
				
			||||||
        switch config[1] {
 | 
					        switch config[1] {
 | 
				
			||||||
        case let .forceNew(new):
 | 
					        case let .forceNew(new):
 | 
				
			||||||
            XCTAssertTrue(new)
 | 
					            XCTAssertTrue(new)
 | 
				
			||||||
@ -43,4 +35,12 @@ class TestSocketIOClientConfiguration: XCTestCase {
 | 
				
			|||||||
            XCTFail()
 | 
					            XCTFail()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var config = [] as SocketIOClientConfiguration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override func setUp() {
 | 
				
			||||||
 | 
					        config = [.log(false), .forceNew(true)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        super.setUp()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										174
									
								
								Tests/TestSocketIO/SocketMangerTest.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								Tests/TestSocketIO/SocketMangerTest.swift
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,174 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// Created by Erik Little on 10/21/17.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Dispatch
 | 
				
			||||||
 | 
					import Foundation
 | 
				
			||||||
 | 
					@testable import SocketIO
 | 
				
			||||||
 | 
					import XCTest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SocketMangerTest : XCTestCase {
 | 
				
			||||||
 | 
					    func testManagerProperties() {
 | 
				
			||||||
 | 
					        XCTAssertNotNil(manager.defaultSocket)
 | 
				
			||||||
 | 
					        XCTAssertNil(manager.engine)
 | 
				
			||||||
 | 
					        XCTAssertFalse(manager.forceNew)
 | 
				
			||||||
 | 
					        XCTAssertEqual(manager.handleQueue, DispatchQueue.main)
 | 
				
			||||||
 | 
					        XCTAssertTrue(manager.reconnects)
 | 
				
			||||||
 | 
					        XCTAssertEqual(manager.reconnectWait, 10)
 | 
				
			||||||
 | 
					        XCTAssertEqual(manager.status, .notConnected)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    func testManagerCallsConnect() {
 | 
				
			||||||
 | 
					        setUpSockets()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        socket.expectations[ManagerExpectation.didConnectCalled] = expectation(description: "The manager should call connect on the default socket")
 | 
				
			||||||
 | 
					        socket2.expectations[ManagerExpectation.didConnectCalled] = expectation(description: "The manager should call connect on the socket")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        socket.connect()
 | 
				
			||||||
 | 
					        socket2.connect()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        manager.fakeConnecting()
 | 
				
			||||||
 | 
					        manager.fakeConnecting(toNamespace: "/swift")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        waitForExpectations(timeout: 0.3)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    func testManagerCallsDisconnect() {
 | 
				
			||||||
 | 
					        setUpSockets()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        socket.expectations[ManagerExpectation.didDisconnectCalled] = expectation(description: "The manager should call disconnect on the default socket")
 | 
				
			||||||
 | 
					        socket2.expectations[ManagerExpectation.didDisconnectCalled] = expectation(description: "The manager should call disconnect on the socket")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        socket2.on(clientEvent: .connect) {data, ack in
 | 
				
			||||||
 | 
					            self.manager.disconnect()
 | 
				
			||||||
 | 
					            self.manager.fakeDisconnecting()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        socket.connect()
 | 
				
			||||||
 | 
					        socket2.connect()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        manager.fakeConnecting()
 | 
				
			||||||
 | 
					        manager.fakeConnecting(toNamespace: "/swift")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        waitForExpectations(timeout: 0.3)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    func testManagerEmitAll() {
 | 
				
			||||||
 | 
					        setUpSockets()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        socket.expectations[ManagerExpectation.emitAllEventCalled] = expectation(description: "The manager should emit an event to the default socket")
 | 
				
			||||||
 | 
					        socket2.expectations[ManagerExpectation.emitAllEventCalled] = expectation(description: "The manager should emit an event to the socket")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        socket2.on(clientEvent: .connect) {data, ack in
 | 
				
			||||||
 | 
					            self.manager.emitAll("event", "testing")
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        socket.connect()
 | 
				
			||||||
 | 
					        socket2.connect()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        manager.fakeConnecting()
 | 
				
			||||||
 | 
					        manager.fakeConnecting(toNamespace: "/swift")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        waitForExpectations(timeout: 0.3)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private func setUpSockets() {
 | 
				
			||||||
 | 
					        socket = manager.testSocket(forNamespace: "/")
 | 
				
			||||||
 | 
					        socket2 = manager.testSocket(forNamespace: "/swift")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private var manager: TestManager!
 | 
				
			||||||
 | 
					    private var socket: TestSocket!
 | 
				
			||||||
 | 
					    private var socket2: TestSocket!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override func setUp() {
 | 
				
			||||||
 | 
					        super.setUp()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        manager = TestManager(socketURL: URL(string: "http://localhost/")!)
 | 
				
			||||||
 | 
					        socket = nil
 | 
				
			||||||
 | 
					        socket2 = nil
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public enum ManagerExpectation : String {
 | 
				
			||||||
 | 
					    case didConnectCalled
 | 
				
			||||||
 | 
					    case didDisconnectCalled
 | 
				
			||||||
 | 
					    case emitAllEventCalled
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class TestManager : SocketManager {
 | 
				
			||||||
 | 
					    public override func disconnect() {
 | 
				
			||||||
 | 
					        setTestStatus(.disconnected)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @objc
 | 
				
			||||||
 | 
					    public func testSocket(forNamespace nsp: String) -> TestSocket {
 | 
				
			||||||
 | 
					        return socket(forNamespace: nsp) as! TestSocket
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @objc
 | 
				
			||||||
 | 
					    public func fakeConnecting(toNamespace nsp: String) {
 | 
				
			||||||
 | 
					        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) {
 | 
				
			||||||
 | 
					            // Fake connecting
 | 
				
			||||||
 | 
					            self.parseEngineMessage("0\(nsp)")
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @objc
 | 
				
			||||||
 | 
					    public func fakeDisconnecting() {
 | 
				
			||||||
 | 
					        engineDidClose(reason: "")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @objc
 | 
				
			||||||
 | 
					    public func fakeConnecting() {
 | 
				
			||||||
 | 
					        engineDidOpen(reason: "")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override func socket(forNamespace nsp: String) -> SocketIOClient {
 | 
				
			||||||
 | 
					        // set socket to our test socket, the superclass method will get this from nsps
 | 
				
			||||||
 | 
					        nsps[nsp] = TestSocket(manager: self, nsp: nsp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return super.socket(forNamespace: nsp)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class TestSocket : SocketIOClient {
 | 
				
			||||||
 | 
					    public var expectations = [ManagerExpectation: XCTestExpectation]()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @objc
 | 
				
			||||||
 | 
					    public var expects =  NSMutableDictionary()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override func didConnect(toNamespace nsp: String) {
 | 
				
			||||||
 | 
					        expectations[ManagerExpectation.didConnectCalled]?.fulfill()
 | 
				
			||||||
 | 
					        expectations[ManagerExpectation.didConnectCalled] = nil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if let expect = expects[ManagerExpectation.didConnectCalled.rawValue] as? XCTestExpectation {
 | 
				
			||||||
 | 
					            expect.fulfill()
 | 
				
			||||||
 | 
					            expects[ManagerExpectation.didConnectCalled.rawValue] = nil
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        super.didConnect(toNamespace: nsp)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override func didDisconnect(reason: String) {
 | 
				
			||||||
 | 
					        expectations[ManagerExpectation.didDisconnectCalled]?.fulfill()
 | 
				
			||||||
 | 
					        expectations[ManagerExpectation.didDisconnectCalled] = nil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if let expect = expects[ManagerExpectation.didDisconnectCalled.rawValue] as? XCTestExpectation {
 | 
				
			||||||
 | 
					            expect.fulfill()
 | 
				
			||||||
 | 
					            expects[ManagerExpectation.didDisconnectCalled.rawValue] = nil
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        super.didDisconnect(reason: reason)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override func emit(_ event: String, with items: [Any]) {
 | 
				
			||||||
 | 
					        expectations[ManagerExpectation.emitAllEventCalled]?.fulfill()
 | 
				
			||||||
 | 
					        expectations[ManagerExpectation.emitAllEventCalled] = nil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if let expect = expects[ManagerExpectation.emitAllEventCalled.rawValue] as? XCTestExpectation {
 | 
				
			||||||
 | 
					            expect.fulfill()
 | 
				
			||||||
 | 
					            expects[ManagerExpectation.emitAllEventCalled.rawValue] = nil
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -10,26 +10,6 @@ import XCTest
 | 
				
			|||||||
@testable import SocketIO
 | 
					@testable import SocketIO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SocketParserTest: XCTestCase {
 | 
					class SocketParserTest: XCTestCase {
 | 
				
			||||||
    let testSocket = SocketIOClient(socketURL: URL(string: "http://localhost/")!)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    //Format key: message; namespace-data-binary-id
 | 
					 | 
				
			||||||
    static let packetTypes: [String: (String, [Any], [Data], Int)] = [
 | 
					 | 
				
			||||||
        "0": ("/", [], [], -1), "1": ("/", [], [], -1),
 | 
					 | 
				
			||||||
        "25[\"test\"]": ("/", ["test"], [], 5),
 | 
					 | 
				
			||||||
        "2[\"test\",\"~~0\"]": ("/", ["test", "~~0"], [], -1),
 | 
					 | 
				
			||||||
        "2/swift,[\"testArrayEmitReturn\",[\"test3\",\"test4\"]]": ("/swift", ["testArrayEmitReturn", ["test3", "test4"] as NSArray], [], -1),
 | 
					 | 
				
			||||||
        "51-/swift,[\"testMultipleItemsWithBufferEmitReturn\",[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]": ("/swift", ["testMultipleItemsWithBufferEmitReturn", [1, 2] as NSArray, ["test": "bob"] as NSDictionary, 25, "polo", ["_placeholder": true, "num": 0] as NSDictionary], [], -1),
 | 
					 | 
				
			||||||
        "3/swift,0[[\"test3\",\"test4\"]]": ("/swift", [["test3", "test4"] as NSArray], [], 0),
 | 
					 | 
				
			||||||
        "61-/swift,19[[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]":
 | 
					 | 
				
			||||||
            ("/swift", [ [1, 2] as NSArray, ["test": "bob"] as NSDictionary, 25, "polo", ["_placeholder": true, "num": 0] as NSDictionary], [], 19),
 | 
					 | 
				
			||||||
        "4/swift,": ("/swift", [], [], -1),
 | 
					 | 
				
			||||||
        "0/swift": ("/swift", [], [], -1),
 | 
					 | 
				
			||||||
        "1/swift": ("/swift", [], [], -1),
 | 
					 | 
				
			||||||
        "4\"ERROR\"": ("/", ["ERROR"], [], -1),
 | 
					 | 
				
			||||||
        "4{\"test\":2}": ("/", [["test": 2]], [], -1),
 | 
					 | 
				
			||||||
        "41": ("/", [1], [], -1),
 | 
					 | 
				
			||||||
        "4[1, \"hello\"]": ("/", [1, "hello"], [], -1)]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    func testDisconnect() {
 | 
					    func testDisconnect() {
 | 
				
			||||||
        let message = "1"
 | 
					        let message = "1"
 | 
				
			||||||
        validateParseResult(message)
 | 
					        validateParseResult(message)
 | 
				
			||||||
@ -108,7 +88,7 @@ class SocketParserTest: XCTestCase {
 | 
				
			|||||||
    func testInvalidInput() {
 | 
					    func testInvalidInput() {
 | 
				
			||||||
        let message = "8"
 | 
					        let message = "8"
 | 
				
			||||||
        do {
 | 
					        do {
 | 
				
			||||||
            let _ = try testSocket.parseString(message)
 | 
					            let _ = try testManager.parseString(message)
 | 
				
			||||||
            XCTFail()
 | 
					            XCTFail()
 | 
				
			||||||
        } catch {
 | 
					        } catch {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -125,7 +105,7 @@ class SocketParserTest: XCTestCase {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    func validateParseResult(_ message: String) {
 | 
					    func validateParseResult(_ message: String) {
 | 
				
			||||||
        let validValues = SocketParserTest.packetTypes[message]!
 | 
					        let validValues = SocketParserTest.packetTypes[message]!
 | 
				
			||||||
        let packet = try! testSocket.parseString(message)
 | 
					        let packet = try! testManager.parseString(message)
 | 
				
			||||||
        let type = String(message.characters.prefix(1))
 | 
					        let type = String(message.characters.prefix(1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        XCTAssertEqual(packet.type, SocketPacket.PacketType(rawValue: Int(type) ?? -1)!)
 | 
					        XCTAssertEqual(packet.type, SocketPacket.PacketType(rawValue: Int(type) ?? -1)!)
 | 
				
			||||||
@ -139,8 +119,29 @@ class SocketParserTest: XCTestCase {
 | 
				
			|||||||
        let keys = Array(SocketParserTest.packetTypes.keys)
 | 
					        let keys = Array(SocketParserTest.packetTypes.keys)
 | 
				
			||||||
        measure {
 | 
					        measure {
 | 
				
			||||||
            for item in keys.enumerated() {
 | 
					            for item in keys.enumerated() {
 | 
				
			||||||
                _ = try! self.testSocket.parseString(item.element)
 | 
					                _ = try! self.testManager.parseString(item.element)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let testManager = SocketManager(socketURL: URL(string: "http://localhost/")!)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //Format key: message; namespace-data-binary-id
 | 
				
			||||||
 | 
					    static let packetTypes: [String: (String, [Any], [Data], Int)] = [
 | 
				
			||||||
 | 
					        "0": ("/", [], [], -1), "1": ("/", [], [], -1),
 | 
				
			||||||
 | 
					        "25[\"test\"]": ("/", ["test"], [], 5),
 | 
				
			||||||
 | 
					        "2[\"test\",\"~~0\"]": ("/", ["test", "~~0"], [], -1),
 | 
				
			||||||
 | 
					        "2/swift,[\"testArrayEmitReturn\",[\"test3\",\"test4\"]]": ("/swift", ["testArrayEmitReturn", ["test3", "test4"] as NSArray], [], -1),
 | 
				
			||||||
 | 
					        "51-/swift,[\"testMultipleItemsWithBufferEmitReturn\",[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]": ("/swift", ["testMultipleItemsWithBufferEmitReturn", [1, 2] as NSArray, ["test": "bob"] as NSDictionary, 25, "polo", ["_placeholder": true, "num": 0] as NSDictionary], [], -1),
 | 
				
			||||||
 | 
					        "3/swift,0[[\"test3\",\"test4\"]]": ("/swift", [["test3", "test4"] as NSArray], [], 0),
 | 
				
			||||||
 | 
					        "61-/swift,19[[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]":
 | 
				
			||||||
 | 
					        ("/swift", [ [1, 2] as NSArray, ["test": "bob"] as NSDictionary, 25, "polo", ["_placeholder": true, "num": 0] as NSDictionary], [], 19),
 | 
				
			||||||
 | 
					        "4/swift,": ("/swift", [], [], -1),
 | 
				
			||||||
 | 
					        "0/swift": ("/swift", [], [], -1),
 | 
				
			||||||
 | 
					        "1/swift": ("/swift", [], [], -1),
 | 
				
			||||||
 | 
					        "4\"ERROR\"": ("/", ["ERROR"], [], -1),
 | 
				
			||||||
 | 
					        "4{\"test\":2}": ("/", [["test": 2]], [], -1),
 | 
				
			||||||
 | 
					        "41": ("/", [1], [], -1),
 | 
				
			||||||
 | 
					        "4[1, \"hello\"]": ("/", [1, "hello"], [], -1)
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -34,7 +34,7 @@ class SocketSideEffectTest: XCTestCase {
 | 
				
			|||||||
            expect.fulfill()
 | 
					            expect.fulfill()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        socket.parseSocketMessage("30[\"hello world\"]")
 | 
					        manager.parseEngineMessage("30[\"hello world\"]")
 | 
				
			||||||
        waitForExpectations(timeout: 3, handler: nil)
 | 
					        waitForExpectations(timeout: 3, handler: nil)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -45,8 +45,8 @@ class SocketSideEffectTest: XCTestCase {
 | 
				
			|||||||
            expect.fulfill()
 | 
					            expect.fulfill()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        socket.parseSocketMessage("61-0[{\"_placeholder\":true,\"num\":0},{\"test\":true}]")
 | 
					        manager.parseEngineMessage("61-0[{\"_placeholder\":true,\"num\":0},{\"test\":true}]")
 | 
				
			||||||
        socket.parseBinaryData(Data())
 | 
					        manager.parseEngineBinaryData(Data())
 | 
				
			||||||
        waitForExpectations(timeout: 3, handler: nil)
 | 
					        waitForExpectations(timeout: 3, handler: nil)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -57,7 +57,7 @@ class SocketSideEffectTest: XCTestCase {
 | 
				
			|||||||
            expect.fulfill()
 | 
					            expect.fulfill()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        socket.parseSocketMessage("2[\"test\",\"hello world\"]")
 | 
					        manager.parseEngineMessage("2[\"test\",\"hello world\"]")
 | 
				
			||||||
        waitForExpectations(timeout: 3, handler: nil)
 | 
					        waitForExpectations(timeout: 3, handler: nil)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -68,7 +68,7 @@ class SocketSideEffectTest: XCTestCase {
 | 
				
			|||||||
            expect.fulfill()
 | 
					            expect.fulfill()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        socket.parseSocketMessage("2[\"test\",\"\\\"hello world\\\"\"]")
 | 
					        manager.parseEngineMessage("2[\"test\",\"\\\"hello world\\\"\"]")
 | 
				
			||||||
        waitForExpectations(timeout: 3, handler: nil)
 | 
					        waitForExpectations(timeout: 3, handler: nil)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -80,7 +80,7 @@ class SocketSideEffectTest: XCTestCase {
 | 
				
			|||||||
            expect.fulfill()
 | 
					            expect.fulfill()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        socket.parseSocketMessage("2[\"test\",\"hello world\"]")
 | 
					        manager.parseEngineMessage("2[\"test\",\"hello world\"]")
 | 
				
			||||||
        waitForExpectations(timeout: 3, handler: nil)
 | 
					        waitForExpectations(timeout: 3, handler: nil)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -96,7 +96,7 @@ class SocketSideEffectTest: XCTestCase {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) {
 | 
					        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) {
 | 
				
			||||||
            // Fake connecting
 | 
					            // Fake connecting
 | 
				
			||||||
            self.socket.parseEngineMessage("0/")
 | 
					            self.manager.parseEngineMessage("0/")
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        waitForExpectations(timeout: 3, handler: nil)
 | 
					        waitForExpectations(timeout: 3, handler: nil)
 | 
				
			||||||
@ -136,59 +136,47 @@ class SocketSideEffectTest: XCTestCase {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        socket.parseSocketMessage("4\"test error\"")
 | 
					        manager.parseEngineMessage("4\"test error\"")
 | 
				
			||||||
        waitForExpectations(timeout: 3, handler: nil)
 | 
					        waitForExpectations(timeout: 3, handler: nil)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    func testHandleBinaryEvent() {
 | 
					    func testHandleBinaryEvent() {
 | 
				
			||||||
        let expect = expectation(description: "handled binary event")
 | 
					        let expect = expectation(description: "handled binary event")
 | 
				
			||||||
        socket.on("test") {data, ack in
 | 
					        socket.on("test") {data, ack in
 | 
				
			||||||
            if let dict = data[0] as? NSDictionary, let data = dict["test"] as? NSData {
 | 
					            if let dict = data[0] as? [String: Any], let data = dict["test"] as? Data {
 | 
				
			||||||
                XCTAssertEqual(data as Data, self.data)
 | 
					                XCTAssertEqual(data as Data, self.data)
 | 
				
			||||||
                expect.fulfill()
 | 
					                expect.fulfill()
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        socket.parseSocketMessage("51-[\"test\",{\"test\":{\"_placeholder\":true,\"num\":0}}]")
 | 
					        manager.parseEngineMessage("51-[\"test\",{\"test\":{\"_placeholder\":true,\"num\":0}}]")
 | 
				
			||||||
        socket.parseBinaryData(data)
 | 
					        manager.parseEngineBinaryData(data)
 | 
				
			||||||
        waitForExpectations(timeout: 3, handler: nil)
 | 
					        waitForExpectations(timeout: 3, handler: nil)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    func testHandleMultipleBinaryEvent() {
 | 
					    func testHandleMultipleBinaryEvent() {
 | 
				
			||||||
        let expect = expectation(description: "handled multiple binary event")
 | 
					        let expect = expectation(description: "handled multiple binary event")
 | 
				
			||||||
        socket.on("test") {data, ack in
 | 
					        socket.on("test") {data, ack in
 | 
				
			||||||
            if let dict = data[0] as? NSDictionary, let data = dict["test"] as? NSData,
 | 
					            if let dict = data[0] as? [String: Any], let data = dict["test"] as? Data,
 | 
				
			||||||
                let data2 = dict["test2"] as? NSData {
 | 
					               let data2 = dict["test2"] as? Data {
 | 
				
			||||||
                    XCTAssertEqual(data as Data, self.data)
 | 
					                XCTAssertEqual(data as Data, self.data)
 | 
				
			||||||
                    XCTAssertEqual(data2 as Data, self.data2)
 | 
					                XCTAssertEqual(data2 as Data, self.data2)
 | 
				
			||||||
                    expect.fulfill()
 | 
					                expect.fulfill()
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        socket.parseSocketMessage("52-[\"test\",{\"test\":{\"_placeholder\":true,\"num\":0},\"test2\":{\"_placeholder\":true,\"num\":1}}]")
 | 
					        manager.parseEngineMessage("52-[\"test\",{\"test\":{\"_placeholder\":true,\"num\":0},\"test2\":{\"_placeholder\":true,\"num\":1}}]")
 | 
				
			||||||
        socket.parseBinaryData(data)
 | 
					        manager.parseEngineBinaryData(data)
 | 
				
			||||||
        socket.parseBinaryData(data2)
 | 
					        manager.parseEngineBinaryData(data2)
 | 
				
			||||||
        waitForExpectations(timeout: 3, handler: nil)
 | 
					        waitForExpectations(timeout: 3, handler: nil)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    func testSocketManager() {
 | 
					 | 
				
			||||||
        let manager = SocketClientManager.sharedManager
 | 
					 | 
				
			||||||
        manager["test"] = socket
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        XCTAssert(manager["test"] === socket, "failed to get socket")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        manager["test"] = nil
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        XCTAssert(manager["test"] == nil, "socket not removed")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    func testChangingStatusCallsStatusChangeHandler() {
 | 
					    func testChangingStatusCallsStatusChangeHandler() {
 | 
				
			||||||
        let expect = expectation(description: "The client should announce when the status changes")
 | 
					        let expect = expectation(description: "The client should announce when the status changes")
 | 
				
			||||||
        let statusChange = SocketIOClientStatus.connecting
 | 
					        let statusChange = SocketIOStatus.connecting
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        socket.on("statusChange") {data, ack in
 | 
					        socket.on("statusChange") {data, ack in
 | 
				
			||||||
            guard let status = data[0] as? SocketIOClientStatus else {
 | 
					            guard let status = data[0] as? SocketIOStatus else {
 | 
				
			||||||
                XCTFail("Status should be one of the defined statuses")
 | 
					                XCTFail("Status should be one of the defined statuses")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                return
 | 
					                return
 | 
				
			||||||
@ -251,9 +239,9 @@ class SocketSideEffectTest: XCTestCase {
 | 
				
			|||||||
    func testConnectTimesOutIfNotConnected() {
 | 
					    func testConnectTimesOutIfNotConnected() {
 | 
				
			||||||
        let expect = expectation(description: "The client should call the timeout function")
 | 
					        let expect = expectation(description: "The client should call the timeout function")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        socket = manager.socket(forNamespace: "/someNamespace")
 | 
				
			||||||
        socket.setTestStatus(.notConnected)
 | 
					        socket.setTestStatus(.notConnected)
 | 
				
			||||||
        socket.nsp = "/someNamespace"
 | 
					        manager.engine = TestEngine(client: manager, url: manager.socketURL, options: nil)
 | 
				
			||||||
        socket.engine = TestEngine(client: socket, url: socket.socketURL, options: nil)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        socket.connect(timeoutAfter: 0.5, withHandler: {
 | 
					        socket.connect(timeoutAfter: 0.5, withHandler: {
 | 
				
			||||||
            expect.fulfill()
 | 
					            expect.fulfill()
 | 
				
			||||||
@ -266,7 +254,7 @@ class SocketSideEffectTest: XCTestCase {
 | 
				
			|||||||
        let expect = expectation(description: "The client should not call the timeout function")
 | 
					        let expect = expectation(description: "The client should not call the timeout function")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        socket.setTestStatus(.notConnected)
 | 
					        socket.setTestStatus(.notConnected)
 | 
				
			||||||
        socket.engine = TestEngine(client: socket, url: socket.socketURL, options: nil)
 | 
					        manager.engine = TestEngine(client: manager, url: manager.socketURL, options: nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        socket.on(clientEvent: .connect) {data, ack in
 | 
					        socket.on(clientEvent: .connect) {data, ack in
 | 
				
			||||||
            expect.fulfill()
 | 
					            expect.fulfill()
 | 
				
			||||||
@ -278,7 +266,7 @@ class SocketSideEffectTest: XCTestCase {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) {
 | 
					        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) {
 | 
				
			||||||
            // Fake connecting
 | 
					            // Fake connecting
 | 
				
			||||||
            self.socket.parseEngineMessage("0/")
 | 
					            self.manager.parseEngineMessage("0/")
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        waitForExpectations(timeout: 2)
 | 
					        waitForExpectations(timeout: 2)
 | 
				
			||||||
@ -288,7 +276,7 @@ class SocketSideEffectTest: XCTestCase {
 | 
				
			|||||||
        let expect = expectation(description: "The client call the connect handler")
 | 
					        let expect = expectation(description: "The client call the connect handler")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        socket.setTestStatus(.notConnected)
 | 
					        socket.setTestStatus(.notConnected)
 | 
				
			||||||
        socket.engine = TestEngine(client: socket, url: socket.socketURL, options: nil)
 | 
					        manager.engine = TestEngine(client: manager, url: manager.socketURL, options: nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        socket.on(clientEvent: .connect) {data, ack in
 | 
					        socket.on(clientEvent: .connect) {data, ack in
 | 
				
			||||||
            expect.fulfill()
 | 
					            expect.fulfill()
 | 
				
			||||||
@ -305,9 +293,9 @@ class SocketSideEffectTest: XCTestCase {
 | 
				
			|||||||
        let expect = expectation(description: "The client should not call the timeout function")
 | 
					        let expect = expectation(description: "The client should not call the timeout function")
 | 
				
			||||||
        let nspString = "/swift"
 | 
					        let nspString = "/swift"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        socket = manager.socket(forNamespace: "/swift")
 | 
				
			||||||
        socket.setTestStatus(.notConnected)
 | 
					        socket.setTestStatus(.notConnected)
 | 
				
			||||||
        socket.nsp = nspString
 | 
					        manager.engine = TestEngine(client: manager, url: manager.socketURL, options: nil)
 | 
				
			||||||
        socket.engine = TestEngine(client: socket, url: socket.socketURL, options: nil)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        socket.on(clientEvent: .connect) {data, ack in
 | 
					        socket.on(clientEvent: .connect) {data, ack in
 | 
				
			||||||
            guard let nsp = data[0] as? String else {
 | 
					            guard let nsp = data[0] as? String else {
 | 
				
			||||||
@ -327,7 +315,7 @@ class SocketSideEffectTest: XCTestCase {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) {
 | 
					        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) {
 | 
				
			||||||
            // Fake connecting
 | 
					            // Fake connecting
 | 
				
			||||||
            self.socket.parseEngineMessage("0/swift")
 | 
					            self.manager.parseEngineMessage("0/swift")
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        waitForExpectations(timeout: 2)
 | 
					        waitForExpectations(timeout: 2)
 | 
				
			||||||
@ -377,39 +365,31 @@ class SocketSideEffectTest: XCTestCase {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    func testSettingConfigAfterInit() {
 | 
					    func testSettingConfigAfterInit() {
 | 
				
			||||||
        socket.setTestStatus(.notConnected)
 | 
					        socket.setTestStatus(.notConnected)
 | 
				
			||||||
        socket.config.insert(.log(true))
 | 
					        manager.config.insert(.log(true))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        XCTAssertTrue(DefaultSocketLogger.Logger.log, "It should set logging to true after creation")
 | 
					        XCTAssertTrue(DefaultSocketLogger.Logger.log, "It should set logging to true after creation")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        socket.config = [.log(false), .nsp("/test")]
 | 
					        manager.config = [.log(false)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        XCTAssertFalse(DefaultSocketLogger.Logger.log, "It should set logging to false after creation")
 | 
					        XCTAssertFalse(DefaultSocketLogger.Logger.log, "It should set logging to false after creation")
 | 
				
			||||||
        XCTAssertEqual(socket.nsp, "/test", "It should set the namespace after creation")
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    func testSettingExtraHeadersAfterInit() {
 | 
					    func testSettingConfigAfterDisconnect() {
 | 
				
			||||||
        socket.setTestStatus(.notConnected)
 | 
					        socket.setTestStatus(.disconnected)
 | 
				
			||||||
        socket.config = [.extraHeaders(["new": "value"])]
 | 
					        manager.config.insert(.log(true))
 | 
				
			||||||
        socket.config.insert(.extraHeaders(["hello": "world"]), replacing: true)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for config in socket.config {
 | 
					        XCTAssertTrue(DefaultSocketLogger.Logger.log, "It should set logging to true after creation")
 | 
				
			||||||
            switch config {
 | 
					 | 
				
			||||||
            case let .extraHeaders(headers):
 | 
					 | 
				
			||||||
                XCTAssertTrue(headers.keys.contains("hello"), "It should contain hello header key")
 | 
					 | 
				
			||||||
                XCTAssertFalse(headers.keys.contains("new"), "It should not contain old data")
 | 
					 | 
				
			||||||
            case .path:
 | 
					 | 
				
			||||||
                continue
 | 
					 | 
				
			||||||
            default:
 | 
					 | 
				
			||||||
                XCTFail("It should only have two configs")
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    func testSettingConfigAfterInitWhenConnectedIgnoresChanges() {
 | 
					        manager.config = [.log(false)]
 | 
				
			||||||
        socket.config = [.log(true), .nsp("/test")]
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        XCTAssertFalse(DefaultSocketLogger.Logger.log, "It should set logging to false after creation")
 | 
					        XCTAssertFalse(DefaultSocketLogger.Logger.log, "It should set logging to false after creation")
 | 
				
			||||||
        XCTAssertEqual(socket.nsp, "/", "It should set the namespace after creation")
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    func testSettingConfigAfterInitWhenConnectedDoesNotIgnoreChanges() {
 | 
				
			||||||
 | 
					        manager.connect()
 | 
				
			||||||
 | 
					        manager.config = [.log(true)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        XCTAssertTrue(DefaultSocketLogger.Logger.log, "It should set logging to false after creation")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    func testClientCallsSentPingHandler() {
 | 
					    func testClientCallsSentPingHandler() {
 | 
				
			||||||
@ -419,7 +399,7 @@ class SocketSideEffectTest: XCTestCase {
 | 
				
			|||||||
            expect.fulfill()
 | 
					            expect.fulfill()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        socket.engineDidSendPing()
 | 
					        manager.engineDidSendPing()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        waitForExpectations(timeout: 0.2)
 | 
					        waitForExpectations(timeout: 0.2)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -431,18 +411,22 @@ class SocketSideEffectTest: XCTestCase {
 | 
				
			|||||||
            expect.fulfill()
 | 
					            expect.fulfill()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        socket.engineDidReceivePong()
 | 
					        manager.engineDidReceivePong()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        waitForExpectations(timeout: 0.2)
 | 
					        waitForExpectations(timeout: 0.2)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let data = "test".data(using: String.Encoding.utf8)!
 | 
					    let data = "test".data(using: String.Encoding.utf8)!
 | 
				
			||||||
    let data2 = "test2".data(using: String.Encoding.utf8)!
 | 
					    let data2 = "test2".data(using: String.Encoding.utf8)!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private var manager: SocketManager!
 | 
				
			||||||
    private var socket: SocketIOClient!
 | 
					    private var socket: SocketIOClient!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override func setUp() {
 | 
					    override func setUp() {
 | 
				
			||||||
        super.setUp()
 | 
					        super.setUp()
 | 
				
			||||||
        socket = SocketIOClient(socketURL: URL(string: "http://localhost/")!)
 | 
					
 | 
				
			||||||
 | 
					        manager = SocketManager(socketURL: URL(string: "http://localhost/")!)
 | 
				
			||||||
 | 
					        socket = manager.defaultSocket
 | 
				
			||||||
        socket.setTestable()
 | 
					        socket.setTestable()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -461,6 +445,7 @@ struct ThrowingData : SocketData {
 | 
				
			|||||||
class TestEngine : SocketEngineSpec {
 | 
					class TestEngine : SocketEngineSpec {
 | 
				
			||||||
    weak var client: SocketEngineClient?
 | 
					    weak var client: SocketEngineClient?
 | 
				
			||||||
    private(set) var closed = false
 | 
					    private(set) var closed = false
 | 
				
			||||||
 | 
					    private(set) var compress = false
 | 
				
			||||||
    private(set) var connected = false
 | 
					    private(set) var connected = false
 | 
				
			||||||
    var connectParams: [String: Any]? = nil
 | 
					    var connectParams: [String: Any]? = nil
 | 
				
			||||||
    private(set) var cookies: [HTTPCookie]? = nil
 | 
					    private(set) var cookies: [HTTPCookie]? = nil
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										16
									
								
								Tests/TestSocketIOObjc/ManagerObjectiveCTest.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								Tests/TestSocketIOObjc/ManagerObjectiveCTest.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// Created by Erik Little on 10/21/17.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#import "SocketIO_Tests-Swift.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@import XCTest;
 | 
				
			||||||
 | 
					@import SocketIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@interface ManagerObjectiveCTest : XCTestCase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@property TestSocket* socket;
 | 
				
			||||||
 | 
					@property TestSocket* socket2;
 | 
				
			||||||
 | 
					@property TestManager* manager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@end
 | 
				
			||||||
							
								
								
									
										115
									
								
								Tests/TestSocketIOObjc/ManagerObjectiveCTest.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								Tests/TestSocketIOObjc/ManagerObjectiveCTest.m
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,115 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// Created by Erik Little on 10/21/17.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#import "ManagerObjectiveCTest.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@import Dispatch;
 | 
				
			||||||
 | 
					@import Foundation;
 | 
				
			||||||
 | 
					@import XCTest;
 | 
				
			||||||
 | 
					@import SocketIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@implementation ManagerObjectiveCTest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- (void)testManagerProperties {
 | 
				
			||||||
 | 
					    XCTAssertNotNil(self.manager.defaultSocket);
 | 
				
			||||||
 | 
					    XCTAssertNil(self.manager.engine);
 | 
				
			||||||
 | 
					    XCTAssertFalse(self.manager.forceNew);
 | 
				
			||||||
 | 
					    XCTAssertEqual(self.manager.handleQueue, dispatch_get_main_queue());
 | 
				
			||||||
 | 
					    XCTAssertTrue(self.manager.reconnects);
 | 
				
			||||||
 | 
					    XCTAssertEqual(self.manager.reconnectWait, 10);
 | 
				
			||||||
 | 
					    XCTAssertEqual(self.manager.status, SocketIOStatusNotConnected);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- (void)testConnectSocketSyntax {
 | 
				
			||||||
 | 
					    [self setUpSockets];
 | 
				
			||||||
 | 
					    [self.manager connectSocket:self.socket];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- (void)testDisconnectSocketSyntax {
 | 
				
			||||||
 | 
					    [self setUpSockets];
 | 
				
			||||||
 | 
					    [self.manager disconnectSocket:self.socket];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- (void)testSocketForNamespaceSyntax {
 | 
				
			||||||
 | 
					    SocketIOClient* client = [self.manager socketForNamespace:@"/swift"];
 | 
				
			||||||
 | 
					    client = nil;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- (void)testManagerCallsConnect {
 | 
				
			||||||
 | 
					    [self setUpSockets];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    XCTestExpectation* expect = [self expectationWithDescription:@"The manager should call connect on the default socket"];
 | 
				
			||||||
 | 
					    XCTestExpectation* expect2 = [self expectationWithDescription:@"The manager should call connect on the socket"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    self.socket.expects[@"didConnectCalled"] = expect;
 | 
				
			||||||
 | 
					    self.socket2.expects[@"didConnectCalled"] = expect2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [self.socket connect];
 | 
				
			||||||
 | 
					    [self.socket2 connect];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [self.manager fakeConnecting];
 | 
				
			||||||
 | 
					    [self.manager fakeConnectingToNamespace:@"/swift"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [self waitForExpectationsWithTimeout:0.3 handler:nil];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- (void)testManagerCallsDisconnect {
 | 
				
			||||||
 | 
					    [self setUpSockets];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    XCTestExpectation* expect = [self expectationWithDescription:@"The manager should call disconnect on the default socket"];
 | 
				
			||||||
 | 
					    XCTestExpectation* expect2 = [self expectationWithDescription:@"The manager should call disconnect on the socket"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    self.socket.expects[@"didDisconnectCalled"] = expect;
 | 
				
			||||||
 | 
					    self.socket2.expects[@"didDisconnectCalled"] = expect2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [self.socket2 on:@"connect" callback:^(NSArray* data, SocketAckEmitter* ack) {
 | 
				
			||||||
 | 
					        [self.manager disconnect];
 | 
				
			||||||
 | 
					        [self.manager fakeDisconnecting];
 | 
				
			||||||
 | 
					    }];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [self.socket connect];
 | 
				
			||||||
 | 
					    [self.socket2 connect];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [self.manager fakeConnecting];
 | 
				
			||||||
 | 
					    [self.manager fakeConnectingToNamespace:@"/swift"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [self waitForExpectationsWithTimeout:0.3 handler:nil];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- (void)testManagerEmitAll {
 | 
				
			||||||
 | 
					    [self setUpSockets];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    XCTestExpectation* expect = [self expectationWithDescription:@"The manager should emit an event to the default socket"];
 | 
				
			||||||
 | 
					    XCTestExpectation* expect2 = [self expectationWithDescription:@"The manager should emit an event to the socket"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    self.socket.expects[@"emitAllEventCalled"] = expect;
 | 
				
			||||||
 | 
					    self.socket2.expects[@"emitAllEventCalled"] = expect2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [self.socket2 on:@"connect" callback:^(NSArray* data, SocketAckEmitter* ack) {
 | 
				
			||||||
 | 
					        [self.manager emitAll:@"event" withItems:@[@"testing"]];
 | 
				
			||||||
 | 
					    }];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [self.socket connect];
 | 
				
			||||||
 | 
					    [self.socket2 connect];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [self.manager fakeConnecting];
 | 
				
			||||||
 | 
					    [self.manager fakeConnectingToNamespace:@"/swift"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [self waitForExpectationsWithTimeout:0.3 handler:nil];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- (void)setUpSockets {
 | 
				
			||||||
 | 
					    self.socket = [self.manager testSocketForNamespace:@"/"];
 | 
				
			||||||
 | 
					    self.socket2 = [self.manager testSocketForNamespace:@"/swift"];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- (void)setUp {
 | 
				
			||||||
 | 
					    [super setUp];
 | 
				
			||||||
 | 
					    NSURL* url = [[NSURL alloc] initWithString:@"http://localhost"];
 | 
				
			||||||
 | 
					    self.manager = [[TestManager alloc] initWithSocketURL:url config:nil];
 | 
				
			||||||
 | 
					    self.socket = nil;
 | 
				
			||||||
 | 
					    self.socket2 = nil;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@end
 | 
				
			||||||
							
								
								
									
										16
									
								
								Tests/TestSocketIOObjc/SocketObjectiveCTest.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								Tests/TestSocketIOObjc/SocketObjectiveCTest.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// Created by Erik Little on 10/21/17.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@import Dispatch;
 | 
				
			||||||
 | 
					@import Foundation;
 | 
				
			||||||
 | 
					@import XCTest;
 | 
				
			||||||
 | 
					@import SocketIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@interface SocketObjectiveCTest : XCTestCase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@property SocketIOClient* socket;
 | 
				
			||||||
 | 
					@property SocketManager* manager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@end
 | 
				
			||||||
@ -7,36 +7,20 @@
 | 
				
			|||||||
//  Merely tests whether the Objective-C api breaks
 | 
					//  Merely tests whether the Objective-C api breaks
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#import "SocketObjectiveCTest.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@import Dispatch;
 | 
					@import Dispatch;
 | 
				
			||||||
@import Foundation;
 | 
					@import Foundation;
 | 
				
			||||||
@import XCTest;
 | 
					@import XCTest;
 | 
				
			||||||
@import SocketIO;
 | 
					@import SocketIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@interface SocketObjectiveCTest : XCTestCase
 | 
					// TODO Manager interface tests
 | 
				
			||||||
 | 
					 | 
				
			||||||
@property SocketIOClient* socket;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@end
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
@implementation SocketObjectiveCTest
 | 
					@implementation SocketObjectiveCTest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- (void)setUp {
 | 
					 | 
				
			||||||
    [super setUp];
 | 
					 | 
				
			||||||
    NSURL* url = [[NSURL alloc] initWithString:@"http://localhost"];
 | 
					 | 
				
			||||||
    self.socket = [[SocketIOClient alloc] initWithSocketURL:url config:@{@"log": @NO, @"forcePolling": @YES}];
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- (void)testProperties {
 | 
					- (void)testProperties {
 | 
				
			||||||
    NSURL* url = nil;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    url = self.socket.socketURL;
 | 
					 | 
				
			||||||
    self.socket.forceNew = false;
 | 
					 | 
				
			||||||
    self.socket.handleQueue = dispatch_get_main_queue();
 | 
					 | 
				
			||||||
    self.socket.nsp = @"/objective-c";
 | 
					    self.socket.nsp = @"/objective-c";
 | 
				
			||||||
    self.socket.reconnects = false;
 | 
					    if (self.socket.status == SocketIOStatusConnected) { }
 | 
				
			||||||
    self.socket.reconnectWait = 1;
 | 
					 | 
				
			||||||
    if (self.socket.status == SocketIOClientStatusConnected) { }
 | 
					 | 
				
			||||||
    if (self.socket.engine == NULL) { }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- (void)testOnSyntax {
 | 
					- (void)testOnSyntax {
 | 
				
			||||||
@ -62,7 +46,7 @@
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- (void)testJoinNamespaceSyntax {
 | 
					- (void)testJoinNamespaceSyntax {
 | 
				
			||||||
    [self.socket joinNamespace:@"/objective-c"];
 | 
					    [self.socket joinNamespace];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- (void)testOnAnySyntax {
 | 
					- (void)testOnAnySyntax {
 | 
				
			||||||
@ -74,10 +58,6 @@
 | 
				
			|||||||
    }];
 | 
					    }];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- (void)testReconnectSyntax {
 | 
					 | 
				
			||||||
    [self.socket reconnect];
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- (void)testRemoveAllHandlersSyntax {
 | 
					- (void)testRemoveAllHandlersSyntax {
 | 
				
			||||||
    [self.socket removeAllHandlers];
 | 
					    [self.socket removeAllHandlers];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -94,15 +74,16 @@
 | 
				
			|||||||
    [self.socket off:@"test"];
 | 
					    [self.socket off:@"test"];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- (void)testSocketManager {
 | 
					 | 
				
			||||||
    SocketClientManager* manager = [SocketClientManager sharedManager];
 | 
					 | 
				
			||||||
    [manager addSocket:self.socket labeledAs:@"test"];
 | 
					 | 
				
			||||||
    [manager removeSocketWithLabel:@"test"];
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- (void)testSSLSecurity {
 | 
					- (void)testSSLSecurity {
 | 
				
			||||||
    SSLSecurity* sec = [[SSLSecurity alloc] initWithUsePublicKeys:0];
 | 
					    SSLSecurity* sec = [[SSLSecurity alloc] initWithUsePublicKeys:0];
 | 
				
			||||||
    sec = nil;
 | 
					    sec = nil;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- (void)setUp {
 | 
				
			||||||
 | 
					    [super setUp];
 | 
				
			||||||
 | 
					    NSURL* url = [[NSURL alloc] initWithString:@"http://localhost"];
 | 
				
			||||||
 | 
					    self.manager = [[SocketManager alloc] initWithSocketURL:url config:nil];
 | 
				
			||||||
 | 
					    self.socket = [self.manager defaultSocket];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@end
 | 
					@end
 | 
				
			||||||
 | 
				
			|||||||
@ -13,11 +13,11 @@ One of the most common reasons your event might not be called is if the client i
 | 
				
			|||||||
Take this code for example:
 | 
					Take this code for example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```swift
 | 
					```swift
 | 
				
			||||||
class SocketManager {
 | 
					class Manager {
 | 
				
			||||||
    func addHandlers() {
 | 
					    func addHandlers() {
 | 
				
			||||||
        let socket = SocketIOClient(socketURL: URL(string: "http://somesocketioserver.com")!)
 | 
					        let manager = SocketManager(socketURL: URL(string: "http://somesocketioserver.com")!)
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        socket.on("myEvent") {data, ack in
 | 
					        manager.defaultSocket.on("myEvent") {data, ack in
 | 
				
			||||||
            print(data)
 | 
					            print(data)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -25,30 +25,20 @@ class SocketManager {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This code is **incorrect**, and the event handler will never be called. Because as soon as this method is called `socket`
 | 
					This code is **incorrect**, and the event handler will never be called. Because as soon as this method is called `manager`
 | 
				
			||||||
will be released and its memory reclaimed.
 | 
					will be released, along with the socket, and its memory reclaimed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
A correct way would be:
 | 
					A correct way would be:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```swift
 | 
					```swift
 | 
				
			||||||
class SocketManager {
 | 
					class Manager {
 | 
				
			||||||
    let socket = SocketIOClient(socketURL: URL(string: "http://somesocketioserver.com")!)
 | 
					    let manager = SocketManager(socketURL: URL(string: "http://somesocketioserver.com")!)
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    func addHandlers() {
 | 
					    func addHandlers() {
 | 
				
			||||||
        socket.on("myEvent") {data, ack in
 | 
					        manager.defaultSocket.on("myEvent") {data, ack in
 | 
				
			||||||
            print(data)
 | 
					            print(data)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					 | 
				
			||||||
------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Another case where this might happen is if you use namespaces in your socket.io application.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
In the JavaScript client a url that looks like `http://somesocketioserver.com/client` would be done with the `nsp` config.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```swift
 | 
					 | 
				
			||||||
let socket = SocketIOClient(socketURL: URL(string: "http://somesocketioserver.com")!, config: [.nsp("/client")])
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user