merge master
This commit is contained in:
commit
03d5f56114
@ -85,7 +85,7 @@ Carthage
|
|||||||
-----------------
|
-----------------
|
||||||
Add this line to your `Cartfile`:
|
Add this line to your `Cartfile`:
|
||||||
```
|
```
|
||||||
github "socketio/socket.io-client-swift" ~> 5.0.0 # Or latest version
|
github "socketio/socket.io-client-swift" ~> 5.1.0 # Or latest version
|
||||||
```
|
```
|
||||||
|
|
||||||
Run `carthage update --platform ios,macosx`.
|
Run `carthage update --platform ios,macosx`.
|
||||||
@ -99,7 +99,7 @@ source 'https://github.com/CocoaPods/Specs.git'
|
|||||||
platform :ios, '8.0'
|
platform :ios, '8.0'
|
||||||
use_frameworks!
|
use_frameworks!
|
||||||
|
|
||||||
pod 'Socket.IO-Client-Swift', '~> 5.0.0' # Or latest version
|
pod 'Socket.IO-Client-Swift', '~> 5.1.0' # Or latest version
|
||||||
```
|
```
|
||||||
|
|
||||||
Install pods:
|
Install pods:
|
||||||
@ -127,7 +127,7 @@ CocoaSeeds
|
|||||||
Add this line to your `Seedfile`:
|
Add this line to your `Seedfile`:
|
||||||
|
|
||||||
```
|
```
|
||||||
github "socketio/socket.io-client-swift", "v5.0.0", :files => "SocketIOClientSwift/*.swift" # Or latest version
|
github "socketio/socket.io-client-swift", "v5.1.0", :files => "SocketIOClientSwift/*.swift" # Or latest version
|
||||||
```
|
```
|
||||||
|
|
||||||
Run `seed install`.
|
Run `seed install`.
|
||||||
@ -176,7 +176,7 @@ Methods
|
|||||||
7. `emitWithAck(event: String, withItems items: [AnyObject]) -> (UInt64, (NSArray?) -> Void) -> Void` - `emitWithAck` for Objective-C. Note: The message is not sent until you call the returned function.
|
7. `emitWithAck(event: String, withItems items: [AnyObject]) -> (UInt64, (NSArray?) -> Void) -> Void` - `emitWithAck` for Objective-C. Note: The message is not sent until you call the returned function.
|
||||||
8. `connect()` - Establishes a connection to the server. A "connect" event is fired upon successful connection.
|
8. `connect()` - Establishes a connection to the server. A "connect" event is fired upon successful connection.
|
||||||
9. `connect(timeoutAfter timeoutAfter: Int, withTimeoutHandler handler: (() -> Void)?)` - Connect to the server. If it isn't connected after timeoutAfter seconds, the handler is called.
|
9. `connect(timeoutAfter timeoutAfter: Int, withTimeoutHandler handler: (() -> Void)?)` - Connect to the server. If it isn't connected after timeoutAfter seconds, the handler is called.
|
||||||
10. `close()` - Closes the socket. Once a socket is closed it should not be reopened.
|
10. `disconnect()` - Closes the socket. Reopening a disconnected socket is not fully tested.
|
||||||
11. `reconnect()` - Causes the client to reconnect to the server.
|
11. `reconnect()` - Causes the client to reconnect to the server.
|
||||||
12. `joinNamespace(namespace: String)` - Causes the client to join namespace. Shouldn't need to be called unless you change namespaces manually.
|
12. `joinNamespace(namespace: String)` - Causes the client to join namespace. Shouldn't need to be called unless you change namespaces manually.
|
||||||
13. `leaveNamespace()` - Causes the client to leave the nsp and go back to /
|
13. `leaveNamespace()` - Causes the client to leave the nsp and go back to /
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
Pod::Spec.new do |s|
|
Pod::Spec.new do |s|
|
||||||
s.name = "Socket.IO-Client-Swift"
|
s.name = "Socket.IO-Client-Swift"
|
||||||
s.module_name = "SocketIOClientSwift"
|
s.module_name = "SocketIOClientSwift"
|
||||||
s.version = "5.0.0"
|
s.version = "5.1.0"
|
||||||
s.summary = "Socket.IO-client for iOS and OS X"
|
s.summary = "Socket.IO-client for iOS and OS X"
|
||||||
s.description = <<-DESC
|
s.description = <<-DESC
|
||||||
Socket.IO-client for iOS and OS X.
|
Socket.IO-client for iOS and OS X.
|
||||||
@ -14,7 +14,7 @@ Pod::Spec.new do |s|
|
|||||||
s.ios.deployment_target = '8.0'
|
s.ios.deployment_target = '8.0'
|
||||||
s.osx.deployment_target = '10.10'
|
s.osx.deployment_target = '10.10'
|
||||||
s.tvos.deployment_target = '9.0'
|
s.tvos.deployment_target = '9.0'
|
||||||
s.source = { :git => "https://github.com/socketio/socket.io-client-swift.git", :tag => 'v5.0.0' }
|
s.source = { :git => "https://github.com/socketio/socket.io-client-swift.git", :tag => 'v5.1.0' }
|
||||||
s.source_files = "Source/**/*.swift"
|
s.source_files = "Source/**/*.swift"
|
||||||
s.requires_arc = true
|
s.requires_arc = true
|
||||||
# s.dependency 'Starscream', '~> 0.9' # currently this repo includes Starscream swift files
|
# s.dependency 'Starscream', '~> 0.9' # currently this repo includes Starscream swift files
|
||||||
|
|||||||
@ -17,6 +17,9 @@
|
|||||||
57634A2F1BD9B46D00E19CD7 /* SocketBasicPacketTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74F124EF1BC574CF002966F4 /* SocketBasicPacketTest.swift */; };
|
57634A2F1BD9B46D00E19CD7 /* SocketBasicPacketTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74F124EF1BC574CF002966F4 /* SocketBasicPacketTest.swift */; };
|
||||||
57634A321BD9B46D00E19CD7 /* SocketNamespacePacketTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7472C65B1BCAB53E003CA70D /* SocketNamespacePacketTest.swift */; };
|
57634A321BD9B46D00E19CD7 /* SocketNamespacePacketTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7472C65B1BCAB53E003CA70D /* SocketNamespacePacketTest.swift */; };
|
||||||
57634A3F1BD9B4BF00E19CD7 /* SocketIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 57634A161BD9B46A00E19CD7 /* SocketIO.framework */; };
|
57634A3F1BD9B4BF00E19CD7 /* SocketIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 57634A161BD9B46A00E19CD7 /* SocketIO.framework */; };
|
||||||
|
740CA1201C496EEB00CB98F4 /* SocketEngineWebsocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 740CA11F1C496EEB00CB98F4 /* SocketEngineWebsocket.swift */; };
|
||||||
|
740CA1211C496EF200CB98F4 /* SocketEngineWebsocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 740CA11F1C496EEB00CB98F4 /* SocketEngineWebsocket.swift */; };
|
||||||
|
740CA1221C496EF700CB98F4 /* SocketEngineWebsocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 740CA11F1C496EEB00CB98F4 /* SocketEngineWebsocket.swift */; };
|
||||||
74171E631C10CD240062D398 /* SocketAckEmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74171E501C10CD240062D398 /* SocketAckEmitter.swift */; };
|
74171E631C10CD240062D398 /* SocketAckEmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74171E501C10CD240062D398 /* SocketAckEmitter.swift */; };
|
||||||
74171E641C10CD240062D398 /* SocketAckEmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74171E501C10CD240062D398 /* SocketAckEmitter.swift */; };
|
74171E641C10CD240062D398 /* SocketAckEmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74171E501C10CD240062D398 /* SocketAckEmitter.swift */; };
|
||||||
74171E651C10CD240062D398 /* SocketAckEmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74171E501C10CD240062D398 /* SocketAckEmitter.swift */; };
|
74171E651C10CD240062D398 /* SocketAckEmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74171E501C10CD240062D398 /* SocketAckEmitter.swift */; };
|
||||||
@ -115,6 +118,9 @@
|
|||||||
74171ED41C10CD240062D398 /* WebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74171E621C10CD240062D398 /* WebSocket.swift */; };
|
74171ED41C10CD240062D398 /* WebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74171E621C10CD240062D398 /* WebSocket.swift */; };
|
||||||
741F39EE1BD025D80026C9CC /* SocketEngineTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 741F39ED1BD025D80026C9CC /* SocketEngineTest.swift */; };
|
741F39EE1BD025D80026C9CC /* SocketEngineTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 741F39ED1BD025D80026C9CC /* SocketEngineTest.swift */; };
|
||||||
741F39EF1BD025D80026C9CC /* SocketEngineTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 741F39ED1BD025D80026C9CC /* SocketEngineTest.swift */; };
|
741F39EF1BD025D80026C9CC /* SocketEngineTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 741F39ED1BD025D80026C9CC /* SocketEngineTest.swift */; };
|
||||||
|
7420CB791C49629E00956AA4 /* SocketEnginePollable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7420CB781C49629E00956AA4 /* SocketEnginePollable.swift */; };
|
||||||
|
7420CB7A1C49629E00956AA4 /* SocketEnginePollable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7420CB781C49629E00956AA4 /* SocketEnginePollable.swift */; };
|
||||||
|
7420CB7B1C49629E00956AA4 /* SocketEnginePollable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7420CB781C49629E00956AA4 /* SocketEnginePollable.swift */; };
|
||||||
74321DCB1C2D939A00CF6F43 /* SocketAckManagerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74321DC91C2D939A00CF6F43 /* SocketAckManagerTest.swift */; };
|
74321DCB1C2D939A00CF6F43 /* SocketAckManagerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74321DC91C2D939A00CF6F43 /* SocketAckManagerTest.swift */; };
|
||||||
74321DCC1C2D939A00CF6F43 /* SocketParserTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74321DCA1C2D939A00CF6F43 /* SocketParserTest.swift */; };
|
74321DCC1C2D939A00CF6F43 /* SocketParserTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74321DCA1C2D939A00CF6F43 /* SocketParserTest.swift */; };
|
||||||
7471CCEA1C39926300364B59 /* SocketClientSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74ABF7761C3991C10078C657 /* SocketClientSpec.swift */; };
|
7471CCEA1C39926300364B59 /* SocketClientSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74ABF7761C3991C10078C657 /* SocketClientSpec.swift */; };
|
||||||
@ -165,6 +171,7 @@
|
|||||||
572EF2481B51F18A00EEBB58 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
572EF2481B51F18A00EEBB58 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
57634A161BD9B46A00E19CD7 /* SocketIO.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SocketIO.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
57634A161BD9B46A00E19CD7 /* SocketIO.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SocketIO.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
57634A3B1BD9B46D00E19CD7 /* SocketIO-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SocketIO-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
57634A3B1BD9B46D00E19CD7 /* SocketIO-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SocketIO-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
740CA11F1C496EEB00CB98F4 /* SocketEngineWebsocket.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SocketEngineWebsocket.swift; path = Source/SocketEngineWebsocket.swift; sourceTree = "<group>"; };
|
||||||
74171E501C10CD240062D398 /* SocketAckEmitter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketAckEmitter.swift; path = Source/SocketAckEmitter.swift; sourceTree = "<group>"; };
|
74171E501C10CD240062D398 /* SocketAckEmitter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketAckEmitter.swift; path = Source/SocketAckEmitter.swift; sourceTree = "<group>"; };
|
||||||
74171E511C10CD240062D398 /* SocketAckManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketAckManager.swift; path = Source/SocketAckManager.swift; sourceTree = "<group>"; };
|
74171E511C10CD240062D398 /* SocketAckManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketAckManager.swift; path = Source/SocketAckManager.swift; sourceTree = "<group>"; };
|
||||||
74171E521C10CD240062D398 /* SocketAnyEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketAnyEvent.swift; path = Source/SocketAnyEvent.swift; sourceTree = "<group>"; };
|
74171E521C10CD240062D398 /* SocketAnyEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketAnyEvent.swift; path = Source/SocketAnyEvent.swift; sourceTree = "<group>"; };
|
||||||
@ -185,6 +192,7 @@
|
|||||||
74171E611C10CD240062D398 /* SwiftRegex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SwiftRegex.swift; path = Source/SwiftRegex.swift; sourceTree = "<group>"; };
|
74171E611C10CD240062D398 /* SwiftRegex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SwiftRegex.swift; path = Source/SwiftRegex.swift; sourceTree = "<group>"; };
|
||||||
74171E621C10CD240062D398 /* WebSocket.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WebSocket.swift; path = Source/WebSocket.swift; sourceTree = "<group>"; };
|
74171E621C10CD240062D398 /* WebSocket.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WebSocket.swift; path = Source/WebSocket.swift; sourceTree = "<group>"; };
|
||||||
741F39ED1BD025D80026C9CC /* SocketEngineTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketEngineTest.swift; sourceTree = "<group>"; };
|
741F39ED1BD025D80026C9CC /* SocketEngineTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketEngineTest.swift; sourceTree = "<group>"; };
|
||||||
|
7420CB781C49629E00956AA4 /* SocketEnginePollable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketEnginePollable.swift; path = Source/SocketEnginePollable.swift; sourceTree = "<group>"; };
|
||||||
74321DC91C2D939A00CF6F43 /* SocketAckManagerTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketAckManagerTest.swift; sourceTree = "<group>"; };
|
74321DC91C2D939A00CF6F43 /* SocketAckManagerTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketAckManagerTest.swift; sourceTree = "<group>"; };
|
||||||
74321DCA1C2D939A00CF6F43 /* SocketParserTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketParserTest.swift; sourceTree = "<group>"; };
|
74321DCA1C2D939A00CF6F43 /* SocketParserTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketParserTest.swift; sourceTree = "<group>"; };
|
||||||
7472C65B1BCAB53E003CA70D /* SocketNamespacePacketTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketNamespacePacketTest.swift; sourceTree = "<group>"; };
|
7472C65B1BCAB53E003CA70D /* SocketNamespacePacketTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketNamespacePacketTest.swift; sourceTree = "<group>"; };
|
||||||
@ -349,7 +357,9 @@
|
|||||||
74171E531C10CD240062D398 /* SocketEngine.swift */,
|
74171E531C10CD240062D398 /* SocketEngine.swift */,
|
||||||
74171E541C10CD240062D398 /* SocketEngineClient.swift */,
|
74171E541C10CD240062D398 /* SocketEngineClient.swift */,
|
||||||
74171E551C10CD240062D398 /* SocketEnginePacketType.swift */,
|
74171E551C10CD240062D398 /* SocketEnginePacketType.swift */,
|
||||||
|
7420CB781C49629E00956AA4 /* SocketEnginePollable.swift */,
|
||||||
74171E561C10CD240062D398 /* SocketEngineSpec.swift */,
|
74171E561C10CD240062D398 /* SocketEngineSpec.swift */,
|
||||||
|
740CA11F1C496EEB00CB98F4 /* SocketEngineWebsocket.swift */,
|
||||||
74171E571C10CD240062D398 /* SocketEventHandler.swift */,
|
74171E571C10CD240062D398 /* SocketEventHandler.swift */,
|
||||||
74171E581C10CD240062D398 /* SocketFixUTF8.swift */,
|
74171E581C10CD240062D398 /* SocketFixUTF8.swift */,
|
||||||
74171E591C10CD240062D398 /* SocketIOClient.swift */,
|
74171E591C10CD240062D398 /* SocketIOClient.swift */,
|
||||||
@ -599,10 +609,12 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
740CA1221C496EF700CB98F4 /* SocketEngineWebsocket.swift in Sources */,
|
||||||
74171E931C10CD240062D398 /* SocketFixUTF8.swift in Sources */,
|
74171E931C10CD240062D398 /* SocketFixUTF8.swift in Sources */,
|
||||||
74171EA51C10CD240062D398 /* SocketIOClientStatus.swift in Sources */,
|
74171EA51C10CD240062D398 /* SocketIOClientStatus.swift in Sources */,
|
||||||
74171E751C10CD240062D398 /* SocketEngine.swift in Sources */,
|
74171E751C10CD240062D398 /* SocketEngine.swift in Sources */,
|
||||||
74171E691C10CD240062D398 /* SocketAckManager.swift in Sources */,
|
74171E691C10CD240062D398 /* SocketAckManager.swift in Sources */,
|
||||||
|
7420CB791C49629E00956AA4 /* SocketEnginePollable.swift in Sources */,
|
||||||
74ABF7771C3991C10078C657 /* SocketClientSpec.swift in Sources */,
|
74ABF7771C3991C10078C657 /* SocketClientSpec.swift in Sources */,
|
||||||
74171E871C10CD240062D398 /* SocketEngineSpec.swift in Sources */,
|
74171E871C10CD240062D398 /* SocketEngineSpec.swift in Sources */,
|
||||||
74171E631C10CD240062D398 /* SocketAckEmitter.swift in Sources */,
|
74171E631C10CD240062D398 /* SocketAckEmitter.swift in Sources */,
|
||||||
@ -656,10 +668,12 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
740CA1211C496EF200CB98F4 /* SocketEngineWebsocket.swift in Sources */,
|
||||||
7471CCEA1C39926300364B59 /* SocketClientSpec.swift in Sources */,
|
7471CCEA1C39926300364B59 /* SocketClientSpec.swift in Sources */,
|
||||||
74171E951C10CD240062D398 /* SocketFixUTF8.swift in Sources */,
|
74171E951C10CD240062D398 /* SocketFixUTF8.swift in Sources */,
|
||||||
74171EA71C10CD240062D398 /* SocketIOClientStatus.swift in Sources */,
|
74171EA71C10CD240062D398 /* SocketIOClientStatus.swift in Sources */,
|
||||||
74171E771C10CD240062D398 /* SocketEngine.swift in Sources */,
|
74171E771C10CD240062D398 /* SocketEngine.swift in Sources */,
|
||||||
|
7420CB7A1C49629E00956AA4 /* SocketEnginePollable.swift in Sources */,
|
||||||
74171E6B1C10CD240062D398 /* SocketAckManager.swift in Sources */,
|
74171E6B1C10CD240062D398 /* SocketAckManager.swift in Sources */,
|
||||||
74171E891C10CD240062D398 /* SocketEngineSpec.swift in Sources */,
|
74171E891C10CD240062D398 /* SocketEngineSpec.swift in Sources */,
|
||||||
74171E651C10CD240062D398 /* SocketAckEmitter.swift in Sources */,
|
74171E651C10CD240062D398 /* SocketAckEmitter.swift in Sources */,
|
||||||
@ -697,10 +711,12 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
740CA1201C496EEB00CB98F4 /* SocketEngineWebsocket.swift in Sources */,
|
||||||
7471CCEB1C39926C00364B59 /* SocketClientSpec.swift in Sources */,
|
7471CCEB1C39926C00364B59 /* SocketClientSpec.swift in Sources */,
|
||||||
74171E971C10CD240062D398 /* SocketFixUTF8.swift in Sources */,
|
74171E971C10CD240062D398 /* SocketFixUTF8.swift in Sources */,
|
||||||
74171EA91C10CD240062D398 /* SocketIOClientStatus.swift in Sources */,
|
74171EA91C10CD240062D398 /* SocketIOClientStatus.swift in Sources */,
|
||||||
74171E791C10CD240062D398 /* SocketEngine.swift in Sources */,
|
74171E791C10CD240062D398 /* SocketEngine.swift in Sources */,
|
||||||
|
7420CB7B1C49629E00956AA4 /* SocketEnginePollable.swift in Sources */,
|
||||||
74171E6D1C10CD240062D398 /* SocketAckManager.swift in Sources */,
|
74171E6D1C10CD240062D398 /* SocketAckManager.swift in Sources */,
|
||||||
74171E8B1C10CD240062D398 /* SocketEngineSpec.swift in Sources */,
|
74171E8B1C10CD240062D398 /* SocketEngineSpec.swift in Sources */,
|
||||||
74171E671C10CD240062D398 /* SocketAckEmitter.swift in Sources */,
|
74171E671C10CD240062D398 /* SocketAckEmitter.swift in Sources */,
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "572EF2371B51F18A00EEBB58"
|
BlueprintIdentifier = "572EF2371B51F18A00EEBB58"
|
||||||
BuildableName = "SocketIO.framework"
|
BuildableName = "SocketIOClientSwift.framework"
|
||||||
BlueprintName = "SocketIO-Mac"
|
BlueprintName = "SocketIO-Mac"
|
||||||
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
@ -57,7 +57,7 @@
|
|||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "572EF2371B51F18A00EEBB58"
|
BlueprintIdentifier = "572EF2371B51F18A00EEBB58"
|
||||||
BuildableName = "SocketIO.framework"
|
BuildableName = "SocketIOClientSwift.framework"
|
||||||
BlueprintName = "SocketIO-Mac"
|
BlueprintName = "SocketIO-Mac"
|
||||||
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
@ -79,7 +79,7 @@
|
|||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "572EF2371B51F18A00EEBB58"
|
BlueprintIdentifier = "572EF2371B51F18A00EEBB58"
|
||||||
BuildableName = "SocketIO.framework"
|
BuildableName = "SocketIOClientSwift.framework"
|
||||||
BlueprintName = "SocketIO-Mac"
|
BlueprintName = "SocketIO-Mac"
|
||||||
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
@ -97,7 +97,7 @@
|
|||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "572EF2371B51F18A00EEBB58"
|
BlueprintIdentifier = "572EF2371B51F18A00EEBB58"
|
||||||
BuildableName = "SocketIO.framework"
|
BuildableName = "SocketIOClientSwift.framework"
|
||||||
BlueprintName = "SocketIO-Mac"
|
BlueprintName = "SocketIO-Mac"
|
||||||
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "572EF2181B51F16C00EEBB58"
|
BlueprintIdentifier = "572EF2181B51F16C00EEBB58"
|
||||||
BuildableName = "SocketIO.framework"
|
BuildableName = "SocketIOClientSwift.framework"
|
||||||
BlueprintName = "SocketIO-iOS"
|
BlueprintName = "SocketIO-iOS"
|
||||||
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
@ -58,7 +58,7 @@
|
|||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "572EF2181B51F16C00EEBB58"
|
BlueprintIdentifier = "572EF2181B51F16C00EEBB58"
|
||||||
BuildableName = "SocketIO.framework"
|
BuildableName = "SocketIOClientSwift.framework"
|
||||||
BlueprintName = "SocketIO-iOS"
|
BlueprintName = "SocketIO-iOS"
|
||||||
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
@ -80,7 +80,7 @@
|
|||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "572EF2181B51F16C00EEBB58"
|
BlueprintIdentifier = "572EF2181B51F16C00EEBB58"
|
||||||
BuildableName = "SocketIO.framework"
|
BuildableName = "SocketIOClientSwift.framework"
|
||||||
BlueprintName = "SocketIO-iOS"
|
BlueprintName = "SocketIO-iOS"
|
||||||
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
@ -98,7 +98,7 @@
|
|||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "572EF2181B51F16C00EEBB58"
|
BlueprintIdentifier = "572EF2181B51F16C00EEBB58"
|
||||||
BuildableName = "SocketIO.framework"
|
BuildableName = "SocketIOClientSwift.framework"
|
||||||
BlueprintName = "SocketIO-iOS"
|
BlueprintName = "SocketIO-iOS"
|
||||||
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
|
|||||||
@ -50,4 +50,28 @@ class SocketEngineTest: XCTestCase {
|
|||||||
engine.parsePollingMessage("15:42[\"blankTest\"]24:42[\"stringTest\",\"hello\"]")
|
engine.parsePollingMessage("15:42[\"blankTest\"]24:42[\"stringTest\",\"hello\"]")
|
||||||
waitForExpectationsWithTimeout(3, handler: nil)
|
waitForExpectationsWithTimeout(3, handler: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testEngineDoesErrorOnUnknownTransport() {
|
||||||
|
let finalExpectation = expectationWithDescription("Unknown Transport")
|
||||||
|
|
||||||
|
client.on("error") {data, ack in
|
||||||
|
if let error = data[0] as? String where error == "Unknown transport" {
|
||||||
|
finalExpectation.fulfill()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
engine.parseEngineMessage("{\"code\": 0, \"message\": \"Unknown transport\"}", fromPolling: false)
|
||||||
|
waitForExpectationsWithTimeout(3, handler: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testEngineDoesErrorOnUnknownMessage() {
|
||||||
|
let finalExpectation = expectationWithDescription("Engine Errors")
|
||||||
|
|
||||||
|
client.on("error") {data, ack in
|
||||||
|
finalExpectation.fulfill()
|
||||||
|
}
|
||||||
|
|
||||||
|
engine.parseEngineMessage("afafafda", fromPolling: false)
|
||||||
|
waitForExpectationsWithTimeout(3, handler: nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -100,6 +100,18 @@ class SocketSideEffectTest: XCTestCase {
|
|||||||
XCTAssertEqual(socket.testHandlers.count, 1)
|
XCTAssertEqual(socket.testHandlers.count, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testHandlesErrorPacket() {
|
||||||
|
let expectation = expectationWithDescription("Handled error")
|
||||||
|
socket.on("error") {data, ack in
|
||||||
|
if let error = data[0] as? String where error == "test error" {
|
||||||
|
expectation.fulfill()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.parseSocketMessage("4\"test error\"")
|
||||||
|
waitForExpectationsWithTimeout(3, handler: nil)
|
||||||
|
}
|
||||||
|
|
||||||
func testHandleBinaryEvent() {
|
func testHandleBinaryEvent() {
|
||||||
let expectation = expectationWithDescription("handled binary event")
|
let expectation = expectationWithDescription("handled binary event")
|
||||||
socket.on("test") {data, ack in
|
socket.on("test") {data, ack in
|
||||||
|
|||||||
@ -28,8 +28,16 @@ protocol SocketClientSpec: class {
|
|||||||
|
|
||||||
func didConnect()
|
func didConnect()
|
||||||
func didDisconnect(reason: String)
|
func didDisconnect(reason: String)
|
||||||
func didError(reason: AnyObject)
|
func didError(reason: String)
|
||||||
func handleAck(ack: Int, data: [AnyObject])
|
func handleAck(ack: Int, data: [AnyObject])
|
||||||
func handleEvent(event: String, data: [AnyObject], isInternalMessage: Bool, withAck ack: Int)
|
func handleEvent(event: String, data: [AnyObject], isInternalMessage: Bool, withAck ack: Int)
|
||||||
func joinNamespace(namespace: String)
|
func joinNamespace(namespace: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension SocketClientSpec {
|
||||||
|
func didError(reason: String) {
|
||||||
|
DefaultSocketLogger.Logger.error("%@", type: "SocketIOClient", args: reason)
|
||||||
|
|
||||||
|
handleEvent("error", data: [reason], isInternalMessage: true, withAck: -1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -24,12 +24,32 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate {
|
public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWebsocket {
|
||||||
public private(set) var sid = ""
|
public let emitQueue = dispatch_queue_create("com.socketio.engineEmitQueue", DISPATCH_QUEUE_SERIAL)
|
||||||
|
public let handleQueue = dispatch_queue_create("com.socketio.engineHandleQueue", DISPATCH_QUEUE_SERIAL)
|
||||||
|
public let parseQueue = dispatch_queue_create("com.socketio.engineParseQueue", DISPATCH_QUEUE_SERIAL)
|
||||||
|
|
||||||
|
public var postWait = [String]()
|
||||||
|
public var waitingForPoll = false
|
||||||
|
public var waitingForPost = false
|
||||||
|
|
||||||
|
public private(set) var closed = false
|
||||||
|
public private(set) var connected = false
|
||||||
public private(set) var cookies: [NSHTTPCookie]?
|
public private(set) var cookies: [NSHTTPCookie]?
|
||||||
|
public private(set) var extraHeaders: [String: String]?
|
||||||
|
public private(set) var fastUpgrade = false
|
||||||
|
public private(set) var forcePolling = false
|
||||||
|
public private(set) var forceWebsockets = false
|
||||||
|
public private(set) var invalidated = false
|
||||||
|
public private(set) var pingTimer: NSTimer?
|
||||||
|
public private(set) var polling = true
|
||||||
|
public private(set) var probing = false
|
||||||
|
public private(set) var session: NSURLSession?
|
||||||
|
public private(set) var sid = ""
|
||||||
public private(set) var socketPath = "/engine.io"
|
public private(set) var socketPath = "/engine.io"
|
||||||
public private(set) var urlPolling = ""
|
public private(set) var urlPolling = ""
|
||||||
public private(set) var urlWebSocket = ""
|
public private(set) var urlWebSocket = ""
|
||||||
|
public private(set) var websocket = false
|
||||||
public private(set) var ws: WebSocket?
|
public private(set) var ws: WebSocket?
|
||||||
|
|
||||||
public weak var client: SocketEngineClient?
|
public weak var client: SocketEngineClient?
|
||||||
@ -40,22 +60,11 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate {
|
|||||||
private typealias ProbeWaitQueue = [Probe]
|
private typealias ProbeWaitQueue = [Probe]
|
||||||
|
|
||||||
private let allowedCharacterSet = NSCharacterSet(charactersInString: "!*'();:@&=+$,/?%#[]\" {}").invertedSet
|
private let allowedCharacterSet = NSCharacterSet(charactersInString: "!*'();:@&=+$,/?%#[]\" {}").invertedSet
|
||||||
private let emitQueue = dispatch_queue_create("com.socketio.engineEmitQueue", DISPATCH_QUEUE_SERIAL)
|
|
||||||
private let handleQueue = dispatch_queue_create("com.socketio.engineHandleQueue", DISPATCH_QUEUE_SERIAL)
|
|
||||||
private let logType = "SocketEngine"
|
private let logType = "SocketEngine"
|
||||||
private let parseQueue = dispatch_queue_create("com.socketio.engineParseQueue", DISPATCH_QUEUE_SERIAL)
|
|
||||||
private let url: String
|
private let url: String
|
||||||
private let workQueue = NSOperationQueue()
|
|
||||||
|
|
||||||
private var connectParams: [String: AnyObject]?
|
private var connectParams: [String: AnyObject]?
|
||||||
private var closed = false
|
|
||||||
private var extraHeaders: [String: String]?
|
|
||||||
private var fastUpgrade = false
|
|
||||||
private var forcePolling = false
|
|
||||||
private var forceWebsockets = false
|
|
||||||
private var invalidated = false
|
|
||||||
private var pingInterval: Double?
|
private var pingInterval: Double?
|
||||||
private var pingTimer: NSTimer?
|
|
||||||
private var pingTimeout = 0.0 {
|
private var pingTimeout = 0.0 {
|
||||||
didSet {
|
didSet {
|
||||||
pongsMissedMax = Int(pingTimeout / (pingInterval ?? 25))
|
pongsMissedMax = Int(pingTimeout / (pingInterval ?? 25))
|
||||||
@ -63,19 +72,10 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate {
|
|||||||
}
|
}
|
||||||
private var pongsMissed = 0
|
private var pongsMissed = 0
|
||||||
private var pongsMissedMax = 0
|
private var pongsMissedMax = 0
|
||||||
private var postWait = [String]()
|
|
||||||
private var probing = false
|
|
||||||
private var probeWait = ProbeWaitQueue()
|
private var probeWait = ProbeWaitQueue()
|
||||||
private var secure = false
|
private var secure = false
|
||||||
private var selfSigned = false
|
private var selfSigned = false
|
||||||
private var session: NSURLSession?
|
|
||||||
private var voipEnabled = false
|
private var voipEnabled = false
|
||||||
private var waitingForPoll = false
|
|
||||||
private var waitingForPost = false
|
|
||||||
private var websocketConnected = false
|
|
||||||
private(set) var connected = false
|
|
||||||
private(set) var polling = true
|
|
||||||
private(set) var websocket = false
|
|
||||||
|
|
||||||
public init(client: SocketEngineClient, url: String, options: Set<SocketIOClientOption>) {
|
public init(client: SocketEngineClient, url: String, options: Set<SocketIOClientOption>) {
|
||||||
self.client = client
|
self.client = client
|
||||||
@ -130,20 +130,19 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate {
|
|||||||
|
|
||||||
switch code {
|
switch code {
|
||||||
case 0: // Unknown transport
|
case 0: // Unknown transport
|
||||||
logAndError(error)
|
didError(error)
|
||||||
case 1: // Unknown sid. clear and retry connect
|
case 1: // Unknown sid. clear and retry connect
|
||||||
sid = ""
|
didError(error)
|
||||||
open(connectParams)
|
|
||||||
case 2: // Bad handshake request
|
case 2: // Bad handshake request
|
||||||
logAndError(error)
|
didError(error)
|
||||||
case 3: // Bad request
|
case 3: // Bad request
|
||||||
logAndError(error)
|
didError(error)
|
||||||
default:
|
default:
|
||||||
logAndError(error)
|
didError(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
logAndError("Got unknown error from server")
|
didError("Got unknown error from server \(msg)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,37 +162,29 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func close() {
|
public func close(reason: String) {
|
||||||
DefaultSocketLogger.Logger.log("Engine is being closed.", type: logType)
|
func postSendClose(data: NSData?, _ res: NSURLResponse?, _ err: NSError?) {
|
||||||
|
sid = ""
|
||||||
pingTimer?.invalidate()
|
closed = true
|
||||||
closed = true
|
invalidated = true
|
||||||
connected = false
|
connected = false
|
||||||
|
|
||||||
if websocket {
|
pingTimer?.invalidate()
|
||||||
sendWebSocketMessage("", withType: .Close, withData: [])
|
ws?.disconnect()
|
||||||
} else {
|
stopPolling()
|
||||||
sendPollMessage("", withType: .Close, withData: [])
|
client?.engineDidClose(reason)
|
||||||
}
|
}
|
||||||
|
|
||||||
ws?.disconnect()
|
DefaultSocketLogger.Logger.log("Engine is being closed.", type: logType)
|
||||||
stopPolling()
|
|
||||||
client?.engineDidClose("Disconnect")
|
|
||||||
}
|
|
||||||
|
|
||||||
private func createBinaryDataForSend(data: NSData) -> Either<NSData, String> {
|
|
||||||
if websocket {
|
if websocket {
|
||||||
var byteArray = [UInt8](count: 1, repeatedValue: 0x0)
|
sendWebSocketMessage("", withType: .Close, withData: [])
|
||||||
byteArray[0] = 4
|
postSendClose(nil, nil, nil)
|
||||||
let mutData = NSMutableData(bytes: &byteArray, length: 1)
|
|
||||||
|
|
||||||
mutData.appendData(data)
|
|
||||||
|
|
||||||
return .Left(mutData)
|
|
||||||
} else {
|
} else {
|
||||||
let str = "b4" + data.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
|
// We need to take special care when we're polling that we send it ASAP
|
||||||
|
postWait.append(String(SocketEnginePacketType.Close.rawValue))
|
||||||
return .Right(str)
|
let req = createRequestForPostWithPostWait()
|
||||||
|
doRequest(req, withCallback: postSendClose)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,8 +254,14 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate {
|
|||||||
ws?.connect()
|
ws?.connect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func didError(error: String) {
|
||||||
|
DefaultSocketLogger.Logger.error(error, type: logType)
|
||||||
|
client?.engineDidError(error)
|
||||||
|
close(error)
|
||||||
|
}
|
||||||
|
|
||||||
private func doFastUpgrade() {
|
public func doFastUpgrade() {
|
||||||
if waitingForPoll {
|
if waitingForPoll {
|
||||||
DefaultSocketLogger.Logger.error("Outstanding poll when switched to WebSockets," +
|
DefaultSocketLogger.Logger.error("Outstanding poll when switched to WebSockets," +
|
||||||
"we'll probably disconnect soon. You should report this.", type: logType)
|
"we'll probably disconnect soon. You should report this.", type: logType)
|
||||||
@ -293,6 +290,18 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We had packets waiting for send when we upgraded
|
||||||
|
// Send them raw
|
||||||
|
public func flushWaitingForPostToWebSocket() {
|
||||||
|
guard let ws = self.ws else { return }
|
||||||
|
|
||||||
|
for msg in postWait {
|
||||||
|
ws.writeString(fixDoubleUTF8(msg))
|
||||||
|
}
|
||||||
|
|
||||||
|
postWait.removeAll(keepCapacity: true)
|
||||||
|
}
|
||||||
|
|
||||||
private func handleClose(reason: String) {
|
private func handleClose(reason: String) {
|
||||||
client?.engineDidClose(reason)
|
client?.engineDidClose(reason)
|
||||||
@ -318,7 +327,7 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate {
|
|||||||
connected = true
|
connected = true
|
||||||
|
|
||||||
if let upgrades = json?["upgrades"] as? [String] {
|
if let upgrades = json?["upgrades"] as? [String] {
|
||||||
upgradeWs = upgrades.filter {$0 == "websocket"}.count != 0
|
upgradeWs = upgrades.contains("websocket")
|
||||||
} else {
|
} else {
|
||||||
upgradeWs = false
|
upgradeWs = false
|
||||||
}
|
}
|
||||||
@ -331,17 +340,20 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate {
|
|||||||
if !forcePolling && !forceWebsockets && upgradeWs {
|
if !forcePolling && !forceWebsockets && upgradeWs {
|
||||||
createWebsocketAndConnect(true)
|
createWebsocketAndConnect(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
startPingTimer()
|
||||||
|
|
||||||
|
if !forceWebsockets {
|
||||||
|
doPoll()
|
||||||
|
}
|
||||||
|
|
||||||
|
client?.engineDidOpen?("Connect")
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
DefaultSocketLogger.Logger.error("Error parsing open packet", type: logType)
|
didError("Error parsing open packet")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
startPingTimer()
|
|
||||||
|
|
||||||
if !forceWebsockets {
|
|
||||||
doPoll()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handlePong(pongMessage: String) {
|
private func handlePong(pongMessage: String) {
|
||||||
@ -353,34 +365,14 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A poll failed, tell the client about it
|
public func open(opts: [String: AnyObject]?) {
|
||||||
private func handlePollingFailed(reason: String) {
|
|
||||||
connected = false
|
|
||||||
ws?.disconnect()
|
|
||||||
pingTimer?.invalidate()
|
|
||||||
waitingForPoll = false
|
|
||||||
waitingForPost = false
|
|
||||||
|
|
||||||
if !closed {
|
|
||||||
client?.didError(reason)
|
|
||||||
client?.engineDidClose(reason)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func logAndError(error: String) {
|
|
||||||
DefaultSocketLogger.Logger.error(error, type: logType)
|
|
||||||
client?.didError(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
public func open(opts: [String: AnyObject]? = nil) {
|
|
||||||
connectParams = opts
|
|
||||||
|
|
||||||
if connected {
|
if connected {
|
||||||
DefaultSocketLogger.Logger.error("Tried to open while connected", type: logType)
|
DefaultSocketLogger.Logger.error("Engine tried opening while connected. This is probably a programming error. "
|
||||||
client?.didError("Tried to open engine while connected")
|
+ "Abandoning open attempt", type: logType)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
connectParams = opts
|
||||||
|
|
||||||
DefaultSocketLogger.Logger.log("Starting engine", type: logType)
|
DefaultSocketLogger.Logger.log("Starting engine", type: logType)
|
||||||
DefaultSocketLogger.Logger.log("Handshaking", type: logType)
|
DefaultSocketLogger.Logger.log("Handshaking", type: logType)
|
||||||
@ -412,12 +404,12 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate {
|
|||||||
doLongPoll(reqPolling)
|
doLongPoll(reqPolling)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func parseEngineData(data: NSData) {
|
public func parseEngineData(data: NSData) {
|
||||||
DefaultSocketLogger.Logger.log("Got binary data: %@", type: "SocketEngine", args: data)
|
DefaultSocketLogger.Logger.log("Got binary data: %@", type: "SocketEngine", args: data)
|
||||||
client?.parseEngineBinaryData(data.subdataWithRange(NSMakeRange(1, data.length - 1)))
|
client?.parseEngineBinaryData(data.subdataWithRange(NSMakeRange(1, data.length - 1)))
|
||||||
}
|
}
|
||||||
|
|
||||||
private func parseEngineMessage(message: String, fromPolling: Bool) {
|
public func parseEngineMessage(message: String, fromPolling: Bool) {
|
||||||
DefaultSocketLogger.Logger.log("Got message: %@", type: logType, args: message)
|
DefaultSocketLogger.Logger.log("Got message: %@", type: logType, args: message)
|
||||||
|
|
||||||
let reader = SocketStringReader(message: message)
|
let reader = SocketStringReader(message: message)
|
||||||
@ -452,13 +444,6 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate {
|
|||||||
DefaultSocketLogger.Logger.log("Got unknown packet type", type: logType)
|
DefaultSocketLogger.Logger.log("Got unknown packet type", type: logType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func probeWebSocket() {
|
|
||||||
if websocketConnected {
|
|
||||||
sendWebSocketMessage("probe", withType: .Ping, withData: [])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private func resetEngine() {
|
private func resetEngine() {
|
||||||
closed = false
|
closed = false
|
||||||
@ -469,12 +454,11 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate {
|
|||||||
invalidated = false
|
invalidated = false
|
||||||
session = NSURLSession(configuration: .defaultSessionConfiguration(),
|
session = NSURLSession(configuration: .defaultSessionConfiguration(),
|
||||||
delegate: sessionDelegate,
|
delegate: sessionDelegate,
|
||||||
delegateQueue: workQueue)
|
delegateQueue: NSOperationQueue())
|
||||||
sid = ""
|
sid = ""
|
||||||
waitingForPoll = false
|
waitingForPoll = false
|
||||||
waitingForPost = false
|
waitingForPost = false
|
||||||
websocket = false
|
websocket = false
|
||||||
websocketConnected = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send an engine message (4)
|
/// Send an engine message (4)
|
||||||
@ -512,7 +496,7 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func upgradeTransport() {
|
private func upgradeTransport() {
|
||||||
if websocketConnected {
|
if ws?.isConnected ?? false {
|
||||||
DefaultSocketLogger.Logger.log("Upgrading transport to WebSockets", type: logType)
|
DefaultSocketLogger.Logger.log("Upgrading transport to WebSockets", type: logType)
|
||||||
|
|
||||||
fastUpgrade = true
|
fastUpgrade = true
|
||||||
@ -539,222 +523,9 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Polling methods
|
|
||||||
extension SocketEngine {
|
|
||||||
private func addHeaders(req: NSMutableURLRequest) {
|
|
||||||
if cookies != nil {
|
|
||||||
let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies!)
|
|
||||||
req.allHTTPHeaderFields = headers
|
|
||||||
}
|
|
||||||
|
|
||||||
if extraHeaders != nil {
|
|
||||||
for (headerName, value) in extraHeaders! {
|
|
||||||
req.setValue(value, forHTTPHeaderField: headerName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func doPoll() {
|
// Delegate methods
|
||||||
if websocket || waitingForPoll || !connected || closed {
|
public func websocketDidConnect(socket: WebSocket) {
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
waitingForPoll = true
|
|
||||||
let req = NSMutableURLRequest(URL: NSURL(string: urlPolling + "&sid=\(sid)&b64=1")!)
|
|
||||||
|
|
||||||
addHeaders(req)
|
|
||||||
doLongPoll(req)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func doRequest(req: NSURLRequest,
|
|
||||||
withCallback callback: (NSData?, NSURLResponse?, NSError?) -> Void) {
|
|
||||||
if !polling || closed || invalidated {
|
|
||||||
DefaultSocketLogger.Logger.error("Tried to do polling request when not supposed to", type: logType)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
DefaultSocketLogger.Logger.log("Doing polling request", type: logType)
|
|
||||||
|
|
||||||
session?.dataTaskWithRequest(req, completionHandler: callback).resume()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func doLongPoll(req: NSURLRequest) {
|
|
||||||
doRequest(req) {[weak self] data, res, err in
|
|
||||||
guard let this = self else {return}
|
|
||||||
|
|
||||||
if err != nil || data == nil {
|
|
||||||
DefaultSocketLogger.Logger.error(err?.localizedDescription ?? "Error", type: this.logType)
|
|
||||||
|
|
||||||
if this.polling {
|
|
||||||
this.handlePollingFailed(err?.localizedDescription ?? "Error")
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
DefaultSocketLogger.Logger.log("Got polling response", type: this.logType)
|
|
||||||
|
|
||||||
if let str = String(data: data!, encoding: NSUTF8StringEncoding) {
|
|
||||||
dispatch_async(this.parseQueue) {
|
|
||||||
this.parsePollingMessage(str)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.waitingForPoll = false
|
|
||||||
|
|
||||||
if this.fastUpgrade {
|
|
||||||
this.doFastUpgrade()
|
|
||||||
} else if !this.closed && this.polling {
|
|
||||||
this.doPoll()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func flushWaitingForPost() {
|
|
||||||
if postWait.count == 0 || !connected {
|
|
||||||
return
|
|
||||||
} else if websocket {
|
|
||||||
flushWaitingForPostToWebSocket()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var postStr = ""
|
|
||||||
|
|
||||||
for packet in postWait {
|
|
||||||
let len = packet.characters.count
|
|
||||||
|
|
||||||
postStr += "\(len):\(packet)"
|
|
||||||
}
|
|
||||||
|
|
||||||
postWait.removeAll(keepCapacity: false)
|
|
||||||
|
|
||||||
let req = NSMutableURLRequest(URL: NSURL(string: urlPolling + "&sid=\(sid)")!)
|
|
||||||
|
|
||||||
addHeaders(req)
|
|
||||||
|
|
||||||
req.HTTPMethod = "POST"
|
|
||||||
req.setValue("text/plain; charset=UTF-8", forHTTPHeaderField: "Content-Type")
|
|
||||||
|
|
||||||
let postData = postStr.dataUsingEncoding(NSUTF8StringEncoding,
|
|
||||||
allowLossyConversion: false)!
|
|
||||||
|
|
||||||
req.HTTPBody = postData
|
|
||||||
req.setValue(String(postData.length), forHTTPHeaderField: "Content-Length")
|
|
||||||
|
|
||||||
waitingForPost = true
|
|
||||||
|
|
||||||
DefaultSocketLogger.Logger.log("POSTing: %@", type: logType, args: postStr)
|
|
||||||
|
|
||||||
doRequest(req) {[weak self] data, res, err in
|
|
||||||
guard let this = self else {return}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
DefaultSocketLogger.Logger.error(err?.localizedDescription ?? "Error", type: this.logType)
|
|
||||||
|
|
||||||
if this.polling {
|
|
||||||
this.handlePollingFailed(err?.localizedDescription ?? "Error")
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.waitingForPost = false
|
|
||||||
|
|
||||||
dispatch_async(this.emitQueue) {
|
|
||||||
if !this.fastUpgrade {
|
|
||||||
this.flushWaitingForPost()
|
|
||||||
this.doPoll()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We had packets waiting for send when we upgraded
|
|
||||||
// Send them raw
|
|
||||||
private func flushWaitingForPostToWebSocket() {
|
|
||||||
guard let ws = self.ws else { return }
|
|
||||||
|
|
||||||
for msg in postWait {
|
|
||||||
ws.writeString(fixDoubleUTF8(msg))
|
|
||||||
}
|
|
||||||
|
|
||||||
postWait.removeAll(keepCapacity: true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func parsePollingMessage(str: String) {
|
|
||||||
guard str.characters.count != 1 else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var reader = SocketStringReader(message: str)
|
|
||||||
|
|
||||||
while reader.hasNext {
|
|
||||||
if let n = Int(reader.readUntilStringOccurence(":")) {
|
|
||||||
let str = reader.read(n)
|
|
||||||
|
|
||||||
dispatch_async(handleQueue) {
|
|
||||||
self.parseEngineMessage(str, fromPolling: true)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
dispatch_async(handleQueue) {
|
|
||||||
self.parseEngineMessage(str, fromPolling: true)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Send polling message.
|
|
||||||
/// Only call on emitQueue
|
|
||||||
private func sendPollMessage(message: String, withType type: SocketEnginePacketType,
|
|
||||||
withData datas: [NSData]) {
|
|
||||||
DefaultSocketLogger.Logger.log("Sending poll: %@ as type: %@", type: logType, args: message, type.rawValue)
|
|
||||||
let fixedMessage = doubleEncodeUTF8(message)
|
|
||||||
let strMsg = "\(type.rawValue)\(fixedMessage)"
|
|
||||||
|
|
||||||
postWait.append(strMsg)
|
|
||||||
|
|
||||||
for data in datas {
|
|
||||||
if case let .Right(bin) = createBinaryDataForSend(data) {
|
|
||||||
postWait.append(bin)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !waitingForPost {
|
|
||||||
flushWaitingForPost()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func stopPolling() {
|
|
||||||
invalidated = true
|
|
||||||
session?.finishTasksAndInvalidate()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WebSocket methods
|
|
||||||
extension SocketEngine {
|
|
||||||
/// Send message on WebSockets
|
|
||||||
/// Only call on emitQueue
|
|
||||||
private func sendWebSocketMessage(str: String, withType type: SocketEnginePacketType,
|
|
||||||
withData datas: [NSData]) {
|
|
||||||
DefaultSocketLogger.Logger.log("Sending ws: %@ as type: %@", type: logType, args: str, type.rawValue)
|
|
||||||
|
|
||||||
ws?.writeString("\(type.rawValue)\(str)")
|
|
||||||
|
|
||||||
for data in datas {
|
|
||||||
if case let .Left(bin) = createBinaryDataForSend(data) {
|
|
||||||
ws?.writeData(bin)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delagate methods
|
|
||||||
|
|
||||||
public func websocketDidConnect(socket:WebSocket) {
|
|
||||||
websocketConnected = true
|
|
||||||
|
|
||||||
if !forceWebsockets {
|
if !forceWebsockets {
|
||||||
probing = true
|
probing = true
|
||||||
probeWebSocket()
|
probeWebSocket()
|
||||||
@ -766,7 +537,6 @@ extension SocketEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func websocketDidDisconnect(socket: WebSocket, error: NSError?) {
|
public func websocketDidDisconnect(socket: WebSocket, error: NSError?) {
|
||||||
websocketConnected = false
|
|
||||||
probing = false
|
probing = false
|
||||||
|
|
||||||
if closed {
|
if closed {
|
||||||
@ -782,7 +552,7 @@ extension SocketEngine {
|
|||||||
let reason = error?.localizedDescription ?? "Socket Disconnected"
|
let reason = error?.localizedDescription ?? "Socket Disconnected"
|
||||||
|
|
||||||
if error != nil {
|
if error != nil {
|
||||||
client?.didError(reason)
|
didError(reason)
|
||||||
}
|
}
|
||||||
|
|
||||||
client?.engineDidClose(reason)
|
client?.engineDidClose(reason)
|
||||||
@ -790,12 +560,4 @@ extension SocketEngine {
|
|||||||
flushProbeWait()
|
flushProbeWait()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func websocketDidReceiveMessage(socket: WebSocket, text: String) {
|
|
||||||
parseEngineMessage(text, fromPolling: false)
|
|
||||||
}
|
|
||||||
|
|
||||||
public func websocketDidReceiveData(socket: WebSocket, data: NSData) {
|
|
||||||
parseEngineData(data)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,9 +25,10 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
@objc public protocol SocketEngineClient {
|
@objc public protocol SocketEngineClient {
|
||||||
func didError(reason: AnyObject)
|
func engineDidError(reason: String)
|
||||||
func engineDidClose(reason: String)
|
func engineDidClose(reason: String)
|
||||||
|
optional func engineDidOpen(reason: String)
|
||||||
func parseEngineMessage(msg: String)
|
func parseEngineMessage(msg: String)
|
||||||
func parseEngineBinaryData(data: NSData)
|
func parseEngineBinaryData(data: NSData)
|
||||||
}
|
}
|
||||||
|
|||||||
231
Source/SocketEnginePollable.swift
Normal file
231
Source/SocketEnginePollable.swift
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
//
|
||||||
|
// SocketEnginePollable.swift
|
||||||
|
// Socket.IO-Client-Swift
|
||||||
|
//
|
||||||
|
// Created by Erik Little on 1/15/16.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
/// Protocol that is used to implement socket.io polling support
|
||||||
|
public protocol SocketEnginePollable: SocketEngineSpec {
|
||||||
|
var invalidated: Bool { get }
|
||||||
|
/// Holds strings waiting to be sent over polling.
|
||||||
|
/// You shouldn't need to mess with this.
|
||||||
|
var postWait: [String] { get set }
|
||||||
|
var session: NSURLSession? { get }
|
||||||
|
/// Because socket.io doesn't let you send two polling request at the same time
|
||||||
|
/// we have to keep track if there's an outstanding poll
|
||||||
|
var waitingForPoll: Bool { get set }
|
||||||
|
/// Because socket.io doesn't let you send two post request at the same time
|
||||||
|
/// we have to keep track if there's an outstanding post
|
||||||
|
var waitingForPost: Bool { get set }
|
||||||
|
|
||||||
|
func doPoll()
|
||||||
|
func sendPollMessage(message: String, withType type: SocketEnginePacketType, withData datas: [NSData])
|
||||||
|
func stopPolling()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default polling methods
|
||||||
|
extension SocketEnginePollable {
|
||||||
|
private func addHeaders(req: NSMutableURLRequest) {
|
||||||
|
if cookies != nil {
|
||||||
|
let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies!)
|
||||||
|
req.allHTTPHeaderFields = headers
|
||||||
|
}
|
||||||
|
|
||||||
|
if extraHeaders != nil {
|
||||||
|
for (headerName, value) in extraHeaders! {
|
||||||
|
req.setValue(value, forHTTPHeaderField: headerName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createRequestForPostWithPostWait() -> NSURLRequest {
|
||||||
|
var postStr = ""
|
||||||
|
|
||||||
|
for packet in postWait {
|
||||||
|
let len = packet.characters.count
|
||||||
|
|
||||||
|
postStr += "\(len):\(packet)"
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultSocketLogger.Logger.log("Created POST string: %@", type: "SocketEnginePolling", args: postStr)
|
||||||
|
|
||||||
|
postWait.removeAll(keepCapacity: false)
|
||||||
|
|
||||||
|
let req = NSMutableURLRequest(URL: NSURL(string: urlPolling + "&sid=\(sid)")!)
|
||||||
|
|
||||||
|
addHeaders(req)
|
||||||
|
|
||||||
|
req.HTTPMethod = "POST"
|
||||||
|
req.setValue("text/plain; charset=UTF-8", forHTTPHeaderField: "Content-Type")
|
||||||
|
|
||||||
|
let postData = postStr.dataUsingEncoding(NSUTF8StringEncoding,
|
||||||
|
allowLossyConversion: false)!
|
||||||
|
|
||||||
|
req.HTTPBody = postData
|
||||||
|
req.setValue(String(postData.length), forHTTPHeaderField: "Content-Length")
|
||||||
|
|
||||||
|
return req
|
||||||
|
}
|
||||||
|
|
||||||
|
public func doPoll() {
|
||||||
|
if websocket || waitingForPoll || !connected || closed {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
waitingForPoll = true
|
||||||
|
let req = NSMutableURLRequest(URL: NSURL(string: urlPolling + "&sid=\(sid)&b64=1")!)
|
||||||
|
|
||||||
|
addHeaders(req)
|
||||||
|
doLongPoll(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func doRequest(req: NSURLRequest, withCallback callback: (NSData?, NSURLResponse?, NSError?) -> Void) {
|
||||||
|
if !polling || closed || invalidated {
|
||||||
|
DefaultSocketLogger.Logger.error("Tried to do polling request when not supposed to", type: "SocketEnginePolling")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultSocketLogger.Logger.log("Doing polling request", type: "SocketEnginePolling")
|
||||||
|
|
||||||
|
session?.dataTaskWithRequest(req, completionHandler: callback).resume()
|
||||||
|
}
|
||||||
|
|
||||||
|
func doLongPoll(req: NSURLRequest) {
|
||||||
|
doRequest(req) {[weak self] data, res, err in
|
||||||
|
guard let this = self else {return}
|
||||||
|
|
||||||
|
if err != nil || data == nil {
|
||||||
|
DefaultSocketLogger.Logger.error(err?.localizedDescription ?? "Error", type: "SocketEnginePolling")
|
||||||
|
|
||||||
|
if this.polling {
|
||||||
|
this.didError(err?.localizedDescription ?? "Error")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultSocketLogger.Logger.log("Got polling response", type: "SocketEnginePolling")
|
||||||
|
|
||||||
|
if let str = String(data: data!, encoding: NSUTF8StringEncoding) {
|
||||||
|
dispatch_async(this.parseQueue) {
|
||||||
|
this.parsePollingMessage(str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.waitingForPoll = false
|
||||||
|
|
||||||
|
if this.fastUpgrade {
|
||||||
|
this.doFastUpgrade()
|
||||||
|
} else if !this.closed && this.polling {
|
||||||
|
this.doPoll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func flushWaitingForPost() {
|
||||||
|
if postWait.count == 0 || !connected {
|
||||||
|
return
|
||||||
|
} else if websocket {
|
||||||
|
flushWaitingForPostToWebSocket()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let req = createRequestForPostWithPostWait()
|
||||||
|
|
||||||
|
waitingForPost = true
|
||||||
|
|
||||||
|
DefaultSocketLogger.Logger.log("POSTing", type: "SocketEnginePolling")
|
||||||
|
|
||||||
|
doRequest(req) {[weak self] data, res, err in
|
||||||
|
guard let this = self else { return }
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
DefaultSocketLogger.Logger.error(err?.localizedDescription ?? "Error", type: "SocketEnginePolling")
|
||||||
|
|
||||||
|
if this.polling {
|
||||||
|
this.didError(err?.localizedDescription ?? "Error")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.waitingForPost = false
|
||||||
|
|
||||||
|
dispatch_async(this.emitQueue) {
|
||||||
|
if !this.fastUpgrade {
|
||||||
|
this.flushWaitingForPost()
|
||||||
|
this.doPoll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parsePollingMessage(str: String) {
|
||||||
|
guard str.characters.count != 1 else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var reader = SocketStringReader(message: str)
|
||||||
|
|
||||||
|
while reader.hasNext {
|
||||||
|
if let n = Int(reader.readUntilStringOccurence(":")) {
|
||||||
|
let str = reader.read(n)
|
||||||
|
|
||||||
|
dispatch_async(handleQueue) {
|
||||||
|
self.parseEngineMessage(str, fromPolling: true)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dispatch_async(handleQueue) {
|
||||||
|
self.parseEngineMessage(str, fromPolling: true)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Send polling message.
|
||||||
|
/// Only call on emitQueue
|
||||||
|
public func sendPollMessage(message: String, withType type: SocketEnginePacketType, withData datas: [NSData]) {
|
||||||
|
DefaultSocketLogger.Logger.log("Sending poll: %@ as type: %@", type: "SocketEnginePolling", args: message, type.rawValue)
|
||||||
|
let fixedMessage = doubleEncodeUTF8(message)
|
||||||
|
let strMsg = "\(type.rawValue)\(fixedMessage)"
|
||||||
|
|
||||||
|
postWait.append(strMsg)
|
||||||
|
|
||||||
|
for data in datas {
|
||||||
|
if case let .Right(bin) = createBinaryDataForSend(data) {
|
||||||
|
postWait.append(bin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !waitingForPost {
|
||||||
|
flushWaitingForPost()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func stopPolling() {
|
||||||
|
waitingForPoll = false
|
||||||
|
waitingForPost = false
|
||||||
|
session?.finishTasksAndInvalidate()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -26,17 +26,53 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
@objc public protocol SocketEngineSpec {
|
@objc public protocol SocketEngineSpec {
|
||||||
weak var client: SocketEngineClient? {get set}
|
weak var client: SocketEngineClient? { get set }
|
||||||
var cookies: [NSHTTPCookie]? {get}
|
var closed: Bool { get }
|
||||||
var sid: String {get}
|
var connected: Bool { get }
|
||||||
var socketPath: String {get}
|
var cookies: [NSHTTPCookie]? { get }
|
||||||
var urlPolling: String {get}
|
var extraHeaders: [String: String]? { get }
|
||||||
var urlWebSocket: String {get}
|
var fastUpgrade: Bool { get }
|
||||||
|
var forcePolling: Bool { get }
|
||||||
|
var forceWebsockets: Bool { get }
|
||||||
|
var parseQueue: dispatch_queue_t! { get }
|
||||||
|
var pingTimer: NSTimer? { get }
|
||||||
|
var polling: Bool { get }
|
||||||
|
var probing: Bool { get }
|
||||||
|
var emitQueue: dispatch_queue_t! { get }
|
||||||
|
var handleQueue: dispatch_queue_t! { get }
|
||||||
|
var sid: String { get }
|
||||||
|
var socketPath: String { get }
|
||||||
|
var urlPolling: String { get }
|
||||||
|
var urlWebSocket: String { get }
|
||||||
|
var websocket: Bool { get }
|
||||||
|
|
||||||
init(client: SocketEngineClient, url: String, options: NSDictionary?)
|
init(client: SocketEngineClient, url: String, options: NSDictionary?)
|
||||||
|
|
||||||
func close()
|
func close(reason: String)
|
||||||
|
func didError(error: String)
|
||||||
|
func doFastUpgrade()
|
||||||
|
func flushWaitingForPostToWebSocket()
|
||||||
func open(opts: [String: AnyObject]?)
|
func open(opts: [String: AnyObject]?)
|
||||||
|
func parseEngineData(data: NSData)
|
||||||
|
func parseEngineMessage(message: String, fromPolling: Bool)
|
||||||
func send(msg: String, withData datas: [NSData])
|
func send(msg: String, withData datas: [NSData])
|
||||||
func write(msg: String, withType type: SocketEnginePacketType, withData data: [NSData])
|
func write(msg: String, withType type: SocketEnginePacketType, withData data: [NSData])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension SocketEngineSpec {
|
||||||
|
func createBinaryDataForSend(data: NSData) -> Either<NSData, String> {
|
||||||
|
if websocket {
|
||||||
|
var byteArray = [UInt8](count: 1, repeatedValue: 0x0)
|
||||||
|
byteArray[0] = 4
|
||||||
|
let mutData = NSMutableData(bytes: &byteArray, length: 1)
|
||||||
|
|
||||||
|
mutData.appendData(data)
|
||||||
|
|
||||||
|
return .Left(mutData)
|
||||||
|
} else {
|
||||||
|
let str = "b4" + data.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
|
||||||
|
|
||||||
|
return .Right(str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
64
Source/SocketEngineWebsocket.swift
Normal file
64
Source/SocketEngineWebsocket.swift
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
//
|
||||||
|
// SocketEngineWebsocket.swift
|
||||||
|
// Socket.IO-Client-Swift
|
||||||
|
//
|
||||||
|
// Created by Erik Little on 1/15/16.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
/// Protocol that is used to implement socket.io WebSocket support
|
||||||
|
public protocol SocketEngineWebsocket: SocketEngineSpec, WebSocketDelegate {
|
||||||
|
var ws: WebSocket? { get }
|
||||||
|
|
||||||
|
func sendWebSocketMessage(str: String, withType type: SocketEnginePacketType, withData datas: [NSData])
|
||||||
|
}
|
||||||
|
|
||||||
|
// WebSocket methods
|
||||||
|
extension SocketEngineWebsocket {
|
||||||
|
func probeWebSocket() {
|
||||||
|
if ws?.isConnected ?? false {
|
||||||
|
sendWebSocketMessage("probe", withType: .Ping, withData: [])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Send message on WebSockets
|
||||||
|
/// Only call on emitQueue
|
||||||
|
public func sendWebSocketMessage(str: String, withType type: SocketEnginePacketType, withData datas: [NSData]) {
|
||||||
|
DefaultSocketLogger.Logger.log("Sending ws: %@ as type: %@", type: "SocketEngine", args: str, type.rawValue)
|
||||||
|
|
||||||
|
ws?.writeString("\(type.rawValue)\(str)")
|
||||||
|
|
||||||
|
for data in datas {
|
||||||
|
if case let .Left(bin) = createBinaryDataForSend(data) {
|
||||||
|
ws?.writeData(bin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func websocketDidReceiveMessage(socket: WebSocket, text: String) {
|
||||||
|
parseEngineMessage(text, fromPolling: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func websocketDidReceiveData(socket: WebSocket, data: NSData) {
|
||||||
|
parseEngineData(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -26,10 +26,10 @@ import Foundation
|
|||||||
|
|
||||||
public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable {
|
public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable {
|
||||||
public let socketURL: String
|
public let socketURL: String
|
||||||
|
|
||||||
public private(set) var engine: SocketEngineSpec?
|
public private(set) var engine: SocketEngineSpec?
|
||||||
public private(set) var status = SocketIOClientStatus.NotConnected
|
public private(set) var status = SocketIOClientStatus.NotConnected
|
||||||
|
|
||||||
public var connectParams: [String: AnyObject]?
|
public var connectParams: [String: AnyObject]?
|
||||||
public var forceNew = false
|
public var forceNew = false
|
||||||
public var nsp = "/"
|
public var nsp = "/"
|
||||||
@ -39,35 +39,35 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable
|
|||||||
public var sid: String? {
|
public var sid: String? {
|
||||||
return engine?.sid
|
return engine?.sid
|
||||||
}
|
}
|
||||||
|
|
||||||
private let emitQueue = dispatch_queue_create("com.socketio.emitQueue", DISPATCH_QUEUE_SERIAL)
|
private let emitQueue = dispatch_queue_create("com.socketio.emitQueue", DISPATCH_QUEUE_SERIAL)
|
||||||
private let logType = "SocketIOClient"
|
private let logType = "SocketIOClient"
|
||||||
private let parseQueue = dispatch_queue_create("com.socketio.parseQueue", DISPATCH_QUEUE_SERIAL)
|
private let parseQueue = dispatch_queue_create("com.socketio.parseQueue", DISPATCH_QUEUE_SERIAL)
|
||||||
|
|
||||||
private var anyHandler: ((SocketAnyEvent) -> Void)?
|
private var anyHandler: ((SocketAnyEvent) -> Void)?
|
||||||
private var currentReconnectAttempt = 0
|
private var currentReconnectAttempt = 0
|
||||||
private var handlers = [SocketEventHandler]()
|
private var handlers = [SocketEventHandler]()
|
||||||
private var reconnectTimer: NSTimer?
|
private var reconnectTimer: NSTimer?
|
||||||
private var ackHandlers = SocketAckManager()
|
private var ackHandlers = SocketAckManager()
|
||||||
|
|
||||||
private(set) var currentAck = -1
|
private(set) var currentAck = -1
|
||||||
private(set) var handleQueue = dispatch_get_main_queue()
|
private(set) var handleQueue = dispatch_get_main_queue()
|
||||||
private(set) var reconnectAttempts = -1
|
private(set) var reconnectAttempts = -1
|
||||||
|
|
||||||
var waitingData = [SocketPacket]()
|
var waitingData = [SocketPacket]()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Type safe way to create a new SocketIOClient. opts can be omitted
|
Type safe way to create a new SocketIOClient. opts can be omitted
|
||||||
*/
|
*/
|
||||||
public init(socketURL: String, options: Set<SocketIOClientOption> = []) {
|
public init(socketURL: String, options: Set<SocketIOClientOption> = []) {
|
||||||
self.options = options
|
self.options = options
|
||||||
|
|
||||||
if socketURL["https://"].matches().count != 0 {
|
if socketURL["https://"].matches().count != 0 {
|
||||||
self.options.insertIgnore(.Secure(true))
|
self.options.insertIgnore(.Secure(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
self.socketURL = socketURL["https?://"] ~= ""
|
self.socketURL = socketURL["https?://"] ~= ""
|
||||||
|
|
||||||
for option in options {
|
for option in options {
|
||||||
switch option {
|
switch option {
|
||||||
case let .ConnectParams(params):
|
case let .ConnectParams(params):
|
||||||
@ -92,12 +92,12 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.options.insertIgnore(.Path("/socket.io"))
|
self.options.insertIgnore(.Path("/socket.io"))
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Not so type safe way to create a SocketIOClient, meant for Objective-C compatiblity.
|
Not so type safe way to create a SocketIOClient, meant for Objective-C compatiblity.
|
||||||
If using Swift it's recommended to use `init(var socketURL: String, opts: SocketOptionsDictionary? = nil)`
|
If using Swift it's recommended to use `init(var socketURL: String, opts: SocketOptionsDictionary? = nil)`
|
||||||
@ -106,92 +106,85 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable
|
|||||||
self.init(socketURL: socketURL,
|
self.init(socketURL: socketURL,
|
||||||
options: options?.toSocketOptionsSet() ?? [])
|
options: options?.toSocketOptionsSet() ?? [])
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
DefaultSocketLogger.Logger.log("Client is being deinit", type: logType)
|
DefaultSocketLogger.Logger.log("Client is being deinit", type: logType)
|
||||||
engine?.close()
|
engine?.close("Client Deinit")
|
||||||
}
|
}
|
||||||
|
|
||||||
private func addEngine() -> SocketEngineSpec {
|
private func addEngine() -> SocketEngineSpec {
|
||||||
DefaultSocketLogger.Logger.log("Adding engine", type: logType)
|
DefaultSocketLogger.Logger.log("Adding engine", type: logType)
|
||||||
|
|
||||||
engine = SocketEngine(client: self, url: socketURL, options: options)
|
engine = SocketEngine(client: self, url: socketURL, options: options)
|
||||||
|
|
||||||
return engine!
|
return engine!
|
||||||
}
|
}
|
||||||
|
|
||||||
private func clearReconnectTimer() {
|
private func clearReconnectTimer() {
|
||||||
reconnectTimer?.invalidate()
|
reconnectTimer?.invalidate()
|
||||||
reconnectTimer = nil
|
reconnectTimer = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@available(*, deprecated=6.0)
|
||||||
Closes the socket. Only reopen the same socket if you know what you're doing.
|
|
||||||
Will turn off automatic reconnects.
|
|
||||||
Pass true to fast if you're closing from a background task
|
|
||||||
*/
|
|
||||||
public func close() {
|
public func close() {
|
||||||
DefaultSocketLogger.Logger.log("Closing socket", type: logType)
|
disconnect()
|
||||||
|
|
||||||
reconnects = false
|
|
||||||
didDisconnect("Closed")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Connect to the server.
|
Connect to the server.
|
||||||
*/
|
*/
|
||||||
public func connect() {
|
public func connect() {
|
||||||
connect(timeoutAfter: 0, withTimeoutHandler: nil)
|
connect(timeoutAfter: 0, withTimeoutHandler: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Connect to the server. If we aren't connected after timeoutAfter, call handler
|
Connect to the server. If we aren't connected after timeoutAfter, call handler
|
||||||
*/
|
*/
|
||||||
public func connect(timeoutAfter timeoutAfter: Int, withTimeoutHandler handler: (() -> Void)?) {
|
public func connect(timeoutAfter timeoutAfter: Int, withTimeoutHandler handler: (() -> Void)?) {
|
||||||
assert(timeoutAfter >= 0, "Invalid timeout: \(timeoutAfter)")
|
assert(timeoutAfter >= 0, "Invalid timeout: \(timeoutAfter)")
|
||||||
|
|
||||||
guard status != .Connected else {
|
guard 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: logType)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
status = .Connecting
|
status = .Connecting
|
||||||
|
|
||||||
if engine == nil || forceNew {
|
if engine == nil || forceNew {
|
||||||
addEngine().open(connectParams)
|
addEngine().open(connectParams)
|
||||||
} else {
|
} else {
|
||||||
engine?.open(connectParams)
|
engine?.open(connectParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
guard timeoutAfter != 0 else { return }
|
guard timeoutAfter != 0 else { return }
|
||||||
|
|
||||||
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(timeoutAfter) * Int64(NSEC_PER_SEC))
|
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(timeoutAfter) * Int64(NSEC_PER_SEC))
|
||||||
|
|
||||||
dispatch_after(time, handleQueue) {[weak self] in
|
dispatch_after(time, handleQueue) {[weak self] in
|
||||||
if let this = self where this.status != .Connected {
|
if let this = self where this.status != .Connected {
|
||||||
this.status = .Closed
|
this.status = .Closed
|
||||||
this.engine?.close()
|
this.engine?.close("Connect timeout")
|
||||||
|
|
||||||
handler?()
|
handler?()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func createOnAck(items: [AnyObject]) -> OnAckCallback {
|
private func createOnAck(items: [AnyObject]) -> OnAckCallback {
|
||||||
currentAck += 1
|
currentAck += 1
|
||||||
|
|
||||||
return {[weak self, ack = currentAck] timeout, callback in
|
return {[weak self, ack = currentAck] timeout, callback in
|
||||||
if let this = self {
|
if let this = self {
|
||||||
this.ackHandlers.addAck(ack, callback: callback)
|
this.ackHandlers.addAck(ack, callback: callback)
|
||||||
|
|
||||||
dispatch_async(this.emitQueue) {
|
dispatch_async(this.emitQueue) {
|
||||||
this._emit(items, ack: ack)
|
this._emit(items, ack: ack)
|
||||||
}
|
}
|
||||||
|
|
||||||
if timeout != 0 {
|
if timeout != 0 {
|
||||||
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(timeout * NSEC_PER_SEC))
|
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(timeout * NSEC_PER_SEC))
|
||||||
|
|
||||||
dispatch_after(time, this.handleQueue) {
|
dispatch_after(time, this.handleQueue) {
|
||||||
this.ackHandlers.timeoutAck(ack)
|
this.ackHandlers.timeoutAck(ack)
|
||||||
}
|
}
|
||||||
@ -199,55 +192,51 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func didConnect() {
|
func didConnect() {
|
||||||
DefaultSocketLogger.Logger.log("Socket connected", type: logType)
|
DefaultSocketLogger.Logger.log("Socket connected", type: logType)
|
||||||
status = .Connected
|
status = .Connected
|
||||||
currentReconnectAttempt = 0
|
currentReconnectAttempt = 0
|
||||||
clearReconnectTimer()
|
clearReconnectTimer()
|
||||||
|
|
||||||
// Don't handle as internal because something crazy could happen where
|
// Don't handle as internal because something crazy could happen where
|
||||||
// we disconnect before it's handled
|
// we disconnect before it's handled
|
||||||
handleEvent("connect", data: [], isInternalMessage: false)
|
handleEvent("connect", data: [], isInternalMessage: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func didDisconnect(reason: String) {
|
func didDisconnect(reason: String) {
|
||||||
guard status != .Closed else {
|
guard status != .Closed else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
DefaultSocketLogger.Logger.log("Disconnected: %@", type: logType, args: reason)
|
DefaultSocketLogger.Logger.log("Disconnected: %@", type: logType, args: reason)
|
||||||
|
|
||||||
status = .Closed
|
status = .Closed
|
||||||
reconnects = false
|
reconnects = false
|
||||||
|
|
||||||
// Make sure the engine is actually dead.
|
// Make sure the engine is actually dead.
|
||||||
engine?.close()
|
engine?.close("Client closed")
|
||||||
handleEvent("disconnect", data: [reason], isInternalMessage: true)
|
handleEvent("disconnect", data: [reason], isInternalMessage: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// error
|
|
||||||
public func didError(reason: AnyObject) {
|
|
||||||
DefaultSocketLogger.Logger.error("%@", type: logType, args: reason)
|
|
||||||
|
|
||||||
handleEvent("error", data: reason as? [AnyObject] ?? [reason],
|
|
||||||
isInternalMessage: true)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Same as close
|
Closes the socket. Only reopen the same socket if you know what you're doing.
|
||||||
|
Will turn off automatic reconnects.
|
||||||
*/
|
*/
|
||||||
public func disconnect() {
|
public func disconnect() {
|
||||||
close()
|
DefaultSocketLogger.Logger.log("Closing socket", type: logType)
|
||||||
|
|
||||||
|
reconnects = false
|
||||||
|
didDisconnect("Closed")
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Send a message to the server
|
Send a message to the server
|
||||||
*/
|
*/
|
||||||
public func emit(event: String, _ items: AnyObject...) {
|
public func emit(event: String, _ items: AnyObject...) {
|
||||||
emit(event, withItems: items)
|
emit(event, withItems: items)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Same as emit, but meant for Objective-C
|
Same as emit, but meant for Objective-C
|
||||||
*/
|
*/
|
||||||
@ -256,12 +245,12 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable
|
|||||||
handleEvent("error", data: ["Tried emitting \(event) when not connected"], isInternalMessage: true)
|
handleEvent("error", data: ["Tried emitting \(event) when not connected"], isInternalMessage: true)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch_async(emitQueue) {
|
dispatch_async(emitQueue) {
|
||||||
self._emit([event] + items)
|
self._emit([event] + items)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Sends a message to the server, requesting an ack. Use the onAck method of SocketAckHandler to add
|
Sends a message to the server, requesting an ack. Use the onAck method of SocketAckHandler to add
|
||||||
an ack.
|
an ack.
|
||||||
@ -269,45 +258,45 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable
|
|||||||
public func emitWithAck(event: String, _ items: AnyObject...) -> OnAckCallback {
|
public func emitWithAck(event: String, _ items: AnyObject...) -> OnAckCallback {
|
||||||
return emitWithAck(event, withItems: items)
|
return emitWithAck(event, withItems: items)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Same as emitWithAck, but for Objective-C
|
Same as emitWithAck, but for Objective-C
|
||||||
*/
|
*/
|
||||||
public func emitWithAck(event: String, withItems items: [AnyObject]) -> OnAckCallback {
|
public func emitWithAck(event: String, withItems items: [AnyObject]) -> OnAckCallback {
|
||||||
return createOnAck([event] + items)
|
return createOnAck([event] + items)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func _emit(data: [AnyObject], ack: Int? = nil) {
|
private func _emit(data: [AnyObject], ack: Int? = nil) {
|
||||||
guard status == .Connected else {
|
guard status == .Connected else {
|
||||||
handleEvent("error", data: ["Tried emitting when not connected"], isInternalMessage: true)
|
handleEvent("error", data: ["Tried emitting when not connected"], isInternalMessage: true)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let packet = SocketPacket.packetFromEmit(data, id: ack ?? -1, nsp: nsp, ack: false)
|
let packet = SocketPacket.packetFromEmit(data, id: ack ?? -1, nsp: nsp, ack: false)
|
||||||
let str = packet.packetString
|
let str = packet.packetString
|
||||||
|
|
||||||
DefaultSocketLogger.Logger.log("Emitting: %@", type: logType, args: str)
|
DefaultSocketLogger.Logger.log("Emitting: %@", type: logType, args: str)
|
||||||
|
|
||||||
engine?.send(str, withData: packet.binary)
|
engine?.send(str, withData: packet.binary)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the server wants to know that the client received data
|
// If the server wants to know that the client received data
|
||||||
func emitAck(ack: Int, withItems items: [AnyObject]) {
|
func emitAck(ack: Int, withItems items: [AnyObject]) {
|
||||||
dispatch_async(emitQueue) {
|
dispatch_async(emitQueue) {
|
||||||
if self.status == .Connected {
|
if self.status == .Connected {
|
||||||
let packet = SocketPacket.packetFromEmit(items, id: ack ?? -1, nsp: self.nsp, ack: true)
|
let packet = SocketPacket.packetFromEmit(items, id: ack ?? -1, nsp: self.nsp, ack: true)
|
||||||
let str = packet.packetString
|
let str = packet.packetString
|
||||||
|
|
||||||
DefaultSocketLogger.Logger.log("Emitting Ack: %@", type: self.logType, args: str)
|
DefaultSocketLogger.Logger.log("Emitting Ack: %@", type: self.logType, args: str)
|
||||||
|
|
||||||
self.engine?.send(str, withData: packet.binary)
|
self.engine?.send(str, withData: packet.binary)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func engineDidClose(reason: String) {
|
public func engineDidClose(reason: String) {
|
||||||
waitingData.removeAll()
|
waitingData.removeAll()
|
||||||
|
|
||||||
if status == .Closed || !reconnects {
|
if status == .Closed || !reconnects {
|
||||||
didDisconnect(reason)
|
didDisconnect(reason)
|
||||||
} else if status != .Reconnecting {
|
} else if status != .Reconnecting {
|
||||||
@ -316,16 +305,23 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable
|
|||||||
tryReconnect()
|
tryReconnect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// error
|
||||||
|
public func engineDidError(reason: String) {
|
||||||
|
DefaultSocketLogger.Logger.error("%@", type: logType, args: reason)
|
||||||
|
|
||||||
|
handleEvent("error", data: [reason], isInternalMessage: true)
|
||||||
|
}
|
||||||
|
|
||||||
// Called when the socket gets an ack for something it sent
|
// Called when the socket gets an ack for something it sent
|
||||||
func handleAck(ack: Int, data: [AnyObject]) {
|
func handleAck(ack: Int, data: [AnyObject]) {
|
||||||
guard status == .Connected else {return}
|
guard status == .Connected else {return}
|
||||||
|
|
||||||
DefaultSocketLogger.Logger.log("Handling ack: %@ with data: %@", type: logType, args: ack, data ?? "")
|
DefaultSocketLogger.Logger.log("Handling ack: %@ with data: %@", type: logType, args: ack, data ?? "")
|
||||||
|
|
||||||
ackHandlers.executeAck(ack, items: data)
|
ackHandlers.executeAck(ack, items: data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Causes an event to be handled. Only use if you know what you're doing.
|
Causes an event to be handled. Only use if you know what you're doing.
|
||||||
*/
|
*/
|
||||||
@ -333,18 +329,18 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable
|
|||||||
guard status == .Connected || isInternalMessage else {
|
guard status == .Connected || isInternalMessage else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
DefaultSocketLogger.Logger.log("Handling event: %@ with data: %@", type: logType, args: event, data ?? "")
|
DefaultSocketLogger.Logger.log("Handling event: %@ with data: %@", type: logType, args: event, data ?? "")
|
||||||
|
|
||||||
dispatch_async(handleQueue) {
|
dispatch_async(handleQueue) {
|
||||||
self.anyHandler?(SocketAnyEvent(event: event, items: data))
|
self.anyHandler?(SocketAnyEvent(event: event, items: data))
|
||||||
|
|
||||||
for handler in self.handlers where handler.event == event {
|
for handler in self.handlers where handler.event == event {
|
||||||
handler.executeCallback(data, withAck: ack, withSocket: self)
|
handler.executeCallback(data, withAck: ack, withSocket: self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Leaves nsp and goes back to /
|
Leaves nsp and goes back to /
|
||||||
*/
|
*/
|
||||||
@ -354,105 +350,105 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable
|
|||||||
nsp = "/"
|
nsp = "/"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Joins namespace
|
Joins namespace
|
||||||
*/
|
*/
|
||||||
public func joinNamespace(namespace: String) {
|
public func joinNamespace(namespace: String) {
|
||||||
nsp = namespace
|
nsp = namespace
|
||||||
|
|
||||||
if nsp != "/" {
|
if nsp != "/" {
|
||||||
DefaultSocketLogger.Logger.log("Joining namespace", type: logType)
|
DefaultSocketLogger.Logger.log("Joining namespace", type: logType)
|
||||||
engine?.send("0\(nsp)", withData: [])
|
engine?.send("0\(nsp)", withData: [])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Removes handler(s)
|
Removes handler(s)
|
||||||
*/
|
*/
|
||||||
public func off(event: String) {
|
public func off(event: String) {
|
||||||
DefaultSocketLogger.Logger.log("Removing handler for event: %@", type: logType, args: event)
|
DefaultSocketLogger.Logger.log("Removing handler for event: %@", type: logType, args: event)
|
||||||
|
|
||||||
handlers = handlers.filter { $0.event != event }
|
handlers = handlers.filter { $0.event != event }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Removes a handler with the specified UUID gotten from an `on` or `once`
|
Removes a handler with the specified UUID gotten from an `on` or `once`
|
||||||
*/
|
*/
|
||||||
public func off(id id: NSUUID) {
|
public func off(id id: NSUUID) {
|
||||||
DefaultSocketLogger.Logger.log("Removing handler with id: %@", type: logType, args: id)
|
DefaultSocketLogger.Logger.log("Removing handler with id: %@", type: logType, args: id)
|
||||||
|
|
||||||
handlers = handlers.filter { $0.id != id }
|
handlers = handlers.filter { $0.id != id }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Adds a handler for an event.
|
Adds a handler for an event.
|
||||||
Returns: A unique id for the handler
|
Returns: A unique id for the handler
|
||||||
*/
|
*/
|
||||||
public func on(event: String, callback: NormalCallback) -> NSUUID {
|
public func on(event: String, callback: NormalCallback) -> NSUUID {
|
||||||
DefaultSocketLogger.Logger.log("Adding handler for event: %@", type: logType, args: event)
|
DefaultSocketLogger.Logger.log("Adding handler for event: %@", type: logType, args: event)
|
||||||
|
|
||||||
let handler = SocketEventHandler(event: event, id: NSUUID(), callback: callback)
|
let handler = SocketEventHandler(event: event, id: NSUUID(), callback: callback)
|
||||||
handlers.append(handler)
|
handlers.append(handler)
|
||||||
|
|
||||||
return handler.id
|
return handler.id
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Adds a single-use handler for an event.
|
Adds a single-use handler for an event.
|
||||||
Returns: A unique id for the handler
|
Returns: A unique id for the handler
|
||||||
*/
|
*/
|
||||||
public func once(event: String, callback: NormalCallback) -> NSUUID {
|
public func once(event: String, callback: NormalCallback) -> NSUUID {
|
||||||
DefaultSocketLogger.Logger.log("Adding once handler for event: %@", type: logType, args: event)
|
DefaultSocketLogger.Logger.log("Adding once handler for event: %@", type: logType, args: event)
|
||||||
|
|
||||||
let id = NSUUID()
|
let id = NSUUID()
|
||||||
|
|
||||||
let handler = SocketEventHandler(event: event, id: id) {[weak self] data, ack in
|
let handler = SocketEventHandler(event: event, id: id) {[weak self] data, ack in
|
||||||
guard let this = self else {return}
|
guard let this = self else {return}
|
||||||
this.off(id: id)
|
this.off(id: id)
|
||||||
callback(data, ack)
|
callback(data, ack)
|
||||||
}
|
}
|
||||||
|
|
||||||
handlers.append(handler)
|
handlers.append(handler)
|
||||||
|
|
||||||
return handler.id
|
return handler.id
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Adds a handler that will be called on every event.
|
Adds a handler that will be called on every event.
|
||||||
*/
|
*/
|
||||||
public func onAny(handler: (SocketAnyEvent) -> Void) {
|
public func onAny(handler: (SocketAnyEvent) -> Void) {
|
||||||
anyHandler = handler
|
anyHandler = handler
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Same as connect
|
Same as connect
|
||||||
*/
|
*/
|
||||||
public func open() {
|
public func open() {
|
||||||
connect()
|
connect()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func parseEngineMessage(msg: String) {
|
public func parseEngineMessage(msg: String) {
|
||||||
DefaultSocketLogger.Logger.log("Should parse message: %@", type: "SocketIOClient", args: msg)
|
DefaultSocketLogger.Logger.log("Should parse message: %@", type: "SocketIOClient", args: msg)
|
||||||
|
|
||||||
dispatch_async(parseQueue) {
|
dispatch_async(parseQueue) {
|
||||||
self.parseSocketMessage(msg)
|
self.parseSocketMessage(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func parseEngineBinaryData(data: NSData) {
|
public func parseEngineBinaryData(data: NSData) {
|
||||||
dispatch_async(parseQueue) {
|
dispatch_async(parseQueue) {
|
||||||
self.parseBinaryData(data)
|
self.parseBinaryData(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Tries to reconnect to the server.
|
Tries to reconnect to the server.
|
||||||
*/
|
*/
|
||||||
public func reconnect() {
|
public func reconnect() {
|
||||||
tryReconnect()
|
tryReconnect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
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.
|
||||||
@ -460,38 +456,38 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable
|
|||||||
public func removeAllHandlers() {
|
public func removeAllHandlers() {
|
||||||
handlers.removeAll(keepCapacity: false)
|
handlers.removeAll(keepCapacity: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func tryReconnect() {
|
private func tryReconnect() {
|
||||||
if reconnectTimer == nil {
|
if reconnectTimer == nil {
|
||||||
DefaultSocketLogger.Logger.log("Starting reconnect", type: logType)
|
DefaultSocketLogger.Logger.log("Starting reconnect", type: logType)
|
||||||
|
|
||||||
status = .Reconnecting
|
status = .Reconnecting
|
||||||
|
|
||||||
dispatch_async(dispatch_get_main_queue()) {
|
dispatch_async(dispatch_get_main_queue()) {
|
||||||
self.reconnectTimer = NSTimer.scheduledTimerWithTimeInterval(Double(self.reconnectWait),
|
self.reconnectTimer = NSTimer.scheduledTimerWithTimeInterval(Double(self.reconnectWait),
|
||||||
target: self, selector: "_tryReconnect", userInfo: nil, repeats: true)
|
target: self, selector: "_tryReconnect", userInfo: nil, repeats: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func _tryReconnect() {
|
@objc private func _tryReconnect() {
|
||||||
if status == .Connected {
|
if status == .Connected {
|
||||||
clearReconnectTimer()
|
clearReconnectTimer()
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if reconnectAttempts != -1 && currentReconnectAttempt + 1 > reconnectAttempts || !reconnects {
|
if reconnectAttempts != -1 && currentReconnectAttempt + 1 > reconnectAttempts || !reconnects {
|
||||||
clearReconnectTimer()
|
clearReconnectTimer()
|
||||||
didDisconnect("Reconnect Failed")
|
didDisconnect("Reconnect Failed")
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
DefaultSocketLogger.Logger.log("Trying to reconnect", type: logType)
|
DefaultSocketLogger.Logger.log("Trying to reconnect", type: logType)
|
||||||
handleEvent("reconnectAttempt", data: [reconnectAttempts - currentReconnectAttempt],
|
handleEvent("reconnectAttempt", data: [reconnectAttempts - currentReconnectAttempt],
|
||||||
isInternalMessage: true)
|
isInternalMessage: true)
|
||||||
|
|
||||||
currentReconnectAttempt += 1
|
currentReconnectAttempt += 1
|
||||||
connect()
|
connect()
|
||||||
}
|
}
|
||||||
@ -502,15 +498,15 @@ extension SocketIOClient {
|
|||||||
var testHandlers: [SocketEventHandler] {
|
var testHandlers: [SocketEventHandler] {
|
||||||
return handlers
|
return handlers
|
||||||
}
|
}
|
||||||
|
|
||||||
func setTestable() {
|
func setTestable() {
|
||||||
status = .Connected
|
status = .Connected
|
||||||
}
|
}
|
||||||
|
|
||||||
func setTestEngine(engine: SocketEngineSpec?) {
|
func setTestEngine(engine: SocketEngineSpec?) {
|
||||||
self.engine = engine
|
self.engine = engine
|
||||||
}
|
}
|
||||||
|
|
||||||
func emitTest(event: String, _ data: AnyObject...) {
|
func emitTest(event: String, _ data: AnyObject...) {
|
||||||
self._emit([event] + data)
|
self._emit([event] + data)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,7 +58,7 @@ extension SocketParsable {
|
|||||||
case .Disconnect:
|
case .Disconnect:
|
||||||
didDisconnect("Got Disconnect")
|
didDisconnect("Got Disconnect")
|
||||||
case .Error:
|
case .Error:
|
||||||
didError(pack.data)
|
handleEvent("error", data: pack.data, isInternalMessage: false, withAck: pack.id)
|
||||||
default:
|
default:
|
||||||
DefaultSocketLogger.Logger.log("Got invalid packet: %@", type: "SocketParser", args: pack.description)
|
DefaultSocketLogger.Logger.log("Got invalid packet: %@", type: "SocketParser", args: pack.description)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user