Merge branch 'socketio/swift-2'
This commit is contained in:
commit
80d7622095
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,6 +1,7 @@
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
*.xcodeproj
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
@ -41,3 +42,5 @@ DerivedData
|
||||
*.hmap
|
||||
*.ipa
|
||||
*.xcuserstate
|
||||
|
||||
Socket.IO-Test-Server/node_modules/*
|
||||
|
||||
37
README.md
37
README.md
@ -11,7 +11,7 @@ socket.on("connect") {data, ack in
|
||||
|
||||
socket.on("currentAmount") {data, ack in
|
||||
if let cur = data?[0] as? Double {
|
||||
socket.emitWithAck("canUpdate", cur)(timeout: 0) {data in
|
||||
socket.emitWithAck("canUpdate", cur)(timeoutAfter: 0) {data in
|
||||
socket.emit("update", ["amount": cur + 2.50])
|
||||
}
|
||||
|
||||
@ -26,11 +26,11 @@ socket.connect()
|
||||
```objective-c
|
||||
SocketIOClient* socket = [[SocketIOClient alloc] initWithSocketURL:@"localhost:8080" options:nil];
|
||||
|
||||
[socket on:@"connect" callback:^(NSArray* data, void (^ack)(NSArray*)) {
|
||||
[socket onObjectiveC:@"connect" callback:^(NSArray* data, void (^ack)(NSArray*)) {
|
||||
NSLog(@"socket connected");
|
||||
}];
|
||||
|
||||
[socket on:@"currentAmount" callback:^(NSArray* data, void (^ack)(NSArray*)) {
|
||||
[socket onObjectiveC:@"currentAmount" callback:^(NSArray* data, void (^ack)(NSArray*)) {
|
||||
double cur = [[data objectAtIndex:0] floatValue];
|
||||
|
||||
[socket emitWithAck:@"canUpdate" withItems:@[@(cur)]](0, ^(NSArray* data) {
|
||||
@ -52,15 +52,16 @@ SocketIOClient* socket = [[SocketIOClient alloc] initWithSocketURL:@"localhost:8
|
||||
- Can be used from Objective-C
|
||||
|
||||
##Installation
|
||||
Requires Swift 1.2/Xcode 6.3
|
||||
Requires Swift 2/Xcode 7
|
||||
|
||||
If you need Swift 1.2/Xcode 6.3/4 use v2 (Pre-Swift 2 support is no longer maintained)
|
||||
If you need Swift 1.1/Xcode 6.2 use v1.5.2. (Pre-Swift 1.2 support is no longer maintained)
|
||||
|
||||
Carthage
|
||||
-----------------
|
||||
Add this line to your `Cartfile`:
|
||||
```
|
||||
github "socketio/socket.io-client-swift" ~> 2.3.10 # Or latest version
|
||||
github "socketio/socket.io-client-swift" ~> 2.4.3 # Or latest version
|
||||
```
|
||||
|
||||
Run `carthage update`.
|
||||
@ -79,7 +80,7 @@ source 'https://github.com/CocoaPods/Specs.git'
|
||||
platform :ios, '8.0'
|
||||
use_frameworks!
|
||||
|
||||
pod 'Socket.IO-Client-Swift', '~> 2.3.10' # Or latest version
|
||||
pod 'Socket.IO-Client-Swift', '~> 2.4.3' # Or latest version
|
||||
```
|
||||
|
||||
Install pods:
|
||||
@ -121,21 +122,23 @@ Options
|
||||
- `sessionDelegate: NSURLSessionDelegate` Sets an NSURLSessionDelegate for the underlying engine. Useful if you need to handle self-signed certs. Default is nil.
|
||||
- `path: String` - If the server uses a custom path. ex: `"/swift"`. Default is `""`
|
||||
- `extraHeaders: [String: String]?` - Adds custom headers to the initial request. Default is nil.
|
||||
- `handleQueue: dispatch_queue_t` - The dispatch queue that handlers are run on. Default is the main queue.
|
||||
|
||||
Methods
|
||||
-------
|
||||
1. `on(name:String, callback:((data:NSArray?, ack:AckEmitter?) -> Void))` - Adds a handler for an event. Items are passed by an array. `ack` can be used to send an ack when one is requested. See example.
|
||||
2. `onAny(callback:((event:String, items:AnyObject?)) -> Void)` - Adds a handler for all events. It will be called on any received event.
|
||||
3. `emit(event:String, _ items:AnyObject...)` - Sends a message. Can send multiple items.
|
||||
4. `emit(event:String, withItems items:[AnyObject])` - `emit` for Objective-C
|
||||
5. `emitWithAck(event:String, _ items:AnyObject...) -> (timeout:UInt64, callback:(NSArray?) -> Void) -> Void` - Sends a message that requests an acknowledgement from the server. Returns a function which you can use to add a handler. See example. Note: The message is not sent until you call the returned function.
|
||||
6. `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. `connect()` - Establishes a connection to the server. A "connect" event is fired upon successful connection.
|
||||
8. `connect(#timeoutAfter:Int, withTimeoutHandler handler:(() -> Void)?)` - Connect to the server. If it isn't connected after timeoutAfter seconds, the handler is called.
|
||||
9. `close(#fast:Bool)` - Closes the socket. Once a socket is closed it should not be reopened. Pass true to fast if you're closing from a background task.
|
||||
10. `reconnect()` - Causes the client to reconnect to the server.
|
||||
11. `joinNamespace()` - Causes the client to join nsp. Shouldn't need to be called unless you change nsp manually.
|
||||
12. `leaveNamespace()` - Causes the client to leave the nsp and go back to /
|
||||
2. `onObjectiveC(name:String, callback:((data:NSArray?, ack:AckEmitter?) -> Void))` - Adds a handler for an event. Items are passed by an array. `ack` can be used to send an ack when one is requested. See example.
|
||||
3. `onAny(callback:((event:String, items:AnyObject?)) -> Void)` - Adds a handler for all events. It will be called on any received event.
|
||||
4. `emit(event:String, _ items:AnyObject...)` - Sends a message. Can send multiple items.
|
||||
5. `emit(event:String, withItems items:[AnyObject])` - `emit` for Objective-C
|
||||
6. `emitWithAck(event:String, _ items:AnyObject...) -> (timeoutAfter:UInt64, callback:(NSArray?) -> Void) -> Void` - Sends a message that requests an acknowledgement from the server. Returns a function which you can use to add a handler. See example. 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.
|
||||
9. `connect(#timeoutAfter:Int, withTimeoutHandler handler:(() -> Void)?)` - Connect to the server. If it isn't connected after timeoutAfter seconds, the handler is called.
|
||||
10. `close(#fast:Bool)` - Closes the socket. Once a socket is closed it should not be reopened. Pass true to fast if you're closing from a background task.
|
||||
11. `reconnect()` - Causes the client to reconnect to the server.
|
||||
12. `joinNamespace()` - Causes the client to join nsp. Shouldn't need to be called unless you change nsp manually.
|
||||
13. `leaveNamespace()` - Causes the client to leave the nsp and go back to /
|
||||
|
||||
Client Events
|
||||
------
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "Socket.IO-Client-Swift"
|
||||
s.version = "2.3.10"
|
||||
s.version = "2.4.3"
|
||||
s.summary = "Socket.IO-client for iOS and OS X"
|
||||
s.description = <<-DESC
|
||||
Socket.IO-client for iOS and OS X.
|
||||
@ -12,7 +12,7 @@ Pod::Spec.new do |s|
|
||||
s.author = { "Erik" => "nuclear.ace@gmail.com" }
|
||||
s.ios.deployment_target = '8.0'
|
||||
s.osx.deployment_target = '10.10'
|
||||
s.source = { :git => "https://github.com/socketio/socket.io-client-swift.git", :tag => 'v2.3.10' }
|
||||
s.source = { :git => "https://github.com/socketio/socket.io-client-swift.git", :tag => 'v2.4.3' }
|
||||
s.source_files = "SocketIOClientSwift/**/*.swift"
|
||||
s.requires_arc = true
|
||||
# s.dependency 'Starscream', '~> 0.9' # currently this repo includes Starscream swift files
|
||||
|
||||
@ -9,7 +9,6 @@
|
||||
/* Begin PBXBuildFile section */
|
||||
572EF21F1B51F16C00EEBB58 /* SocketIO-iOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 572EF21E1B51F16C00EEBB58 /* SocketIO-iOS.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
572EF2251B51F16C00EEBB58 /* SocketIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 572EF2191B51F16C00EEBB58 /* SocketIO.framework */; };
|
||||
572EF22C1B51F16C00EEBB58 /* SocketIO_iOSTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 572EF22B1B51F16C00EEBB58 /* SocketIO_iOSTests.swift */; };
|
||||
572EF23D1B51F18A00EEBB58 /* SocketIO-Mac.h in Headers */ = {isa = PBXBuildFile; fileRef = 572EF23C1B51F18A00EEBB58 /* SocketIO-Mac.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
572EF2431B51F18A00EEBB58 /* SocketIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 572EF2381B51F18A00EEBB58 /* SocketIO.framework */; };
|
||||
572EF24A1B51F18A00EEBB58 /* SocketIO_MacTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 572EF2491B51F18A00EEBB58 /* SocketIO_MacTests.swift */; };
|
||||
@ -39,6 +38,30 @@
|
||||
5764DFA01B51F254004FF46E /* SwiftRegex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF871B51F254004FF46E /* SwiftRegex.swift */; };
|
||||
5764DFA11B51F254004FF46E /* WebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF881B51F254004FF46E /* WebSocket.swift */; };
|
||||
5764DFA21B51F254004FF46E /* WebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF881B51F254004FF46E /* WebSocket.swift */; };
|
||||
74781D5A1B7E83930042CACA /* SocketIOClientStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74781D591B7E83930042CACA /* SocketIOClientStatus.swift */; };
|
||||
74781D5B1B7E83930042CACA /* SocketIOClientStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74781D591B7E83930042CACA /* SocketIOClientStatus.swift */; };
|
||||
74781D5C1B7E83930042CACA /* SocketIOClientStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74781D591B7E83930042CACA /* SocketIOClientStatus.swift */; };
|
||||
74781D5D1B7E83930042CACA /* SocketIOClientStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74781D591B7E83930042CACA /* SocketIOClientStatus.swift */; };
|
||||
941A4ABA1B67A56C00C42318 /* TestKind.swift in Sources */ = {isa = PBXBuildFile; fileRef = 941A4AB91B67A56C00C42318 /* TestKind.swift */; };
|
||||
94242BB81B67B0E500AAAC9D /* SocketNamespaceAcknowledgementTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94242BB71B67B0E500AAAC9D /* SocketNamespaceAcknowledgementTest.swift */; };
|
||||
945B65351B5FCEEA0081E995 /* SocketAckManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF7C1B51F254004FF46E /* SocketAckManager.swift */; };
|
||||
945B65361B5FCEEA0081E995 /* SocketAnyEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF7D1B51F254004FF46E /* SocketAnyEvent.swift */; };
|
||||
945B65371B5FCEEA0081E995 /* SocketEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF7E1B51F254004FF46E /* SocketEngine.swift */; };
|
||||
945B65381B5FCEEA0081E995 /* SocketEngineClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF7F1B51F254004FF46E /* SocketEngineClient.swift */; };
|
||||
945B65391B5FCEEA0081E995 /* SocketEventHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF801B51F254004FF46E /* SocketEventHandler.swift */; };
|
||||
945B653A1B5FCEEA0081E995 /* SocketFixUTF8.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF811B51F254004FF46E /* SocketFixUTF8.swift */; };
|
||||
945B653B1B5FCEEA0081E995 /* SocketIOClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF821B51F254004FF46E /* SocketIOClient.swift */; };
|
||||
945B653C1B5FCEEA0081E995 /* SocketLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF831B51F254004FF46E /* SocketLogger.swift */; };
|
||||
945B653D1B5FCEEA0081E995 /* SocketPacket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF841B51F254004FF46E /* SocketPacket.swift */; };
|
||||
945B653E1B5FCEEA0081E995 /* SocketParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF851B51F254004FF46E /* SocketParser.swift */; };
|
||||
945B653F1B5FCEEA0081E995 /* SocketTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF861B51F254004FF46E /* SocketTypes.swift */; };
|
||||
945B65401B5FCEEA0081E995 /* SwiftRegex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF871B51F254004FF46E /* SwiftRegex.swift */; };
|
||||
945B65411B5FCEEA0081E995 /* WebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF881B51F254004FF46E /* WebSocket.swift */; };
|
||||
945B65431B63D9DB0081E995 /* SocketEmitTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 945B65421B63D9DB0081E995 /* SocketEmitTest.swift */; };
|
||||
94ADAC491B652D3300FD79AE /* SocketNamespaceEmitTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94ADAC481B652D3300FD79AE /* SocketNamespaceEmitTest.swift */; };
|
||||
94ADAC4B1B6632DD00FD79AE /* SocketAcknowledgementTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94ADAC4A1B6632DD00FD79AE /* SocketAcknowledgementTest.swift */; };
|
||||
94CB8F0B1B6E48B90019ED53 /* SocketTestCases.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94CB8F0A1B6E48B90019ED53 /* SocketTestCases.swift */; };
|
||||
94CB8F0D1B6E66E60019ED53 /* AbstractSocketTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94CB8F0C1B6E66E60019ED53 /* AbstractSocketTest.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@ -64,7 +87,6 @@
|
||||
572EF21E1B51F16C00EEBB58 /* SocketIO-iOS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SocketIO-iOS.h"; sourceTree = "<group>"; };
|
||||
572EF2241B51F16C00EEBB58 /* SocketIO-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SocketIO-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
572EF22A1B51F16C00EEBB58 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
572EF22B1B51F16C00EEBB58 /* SocketIO_iOSTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketIO_iOSTests.swift; sourceTree = "<group>"; };
|
||||
572EF2381B51F18A00EEBB58 /* SocketIO.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SocketIO.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
572EF23B1B51F18A00EEBB58 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
572EF23C1B51F18A00EEBB58 /* SocketIO-Mac.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SocketIO-Mac.h"; sourceTree = "<group>"; };
|
||||
@ -84,6 +106,14 @@
|
||||
5764DF861B51F254004FF46E /* SocketTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketTypes.swift; path = SocketIOClientSwift/SocketTypes.swift; sourceTree = "<group>"; };
|
||||
5764DF871B51F254004FF46E /* SwiftRegex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SwiftRegex.swift; path = SocketIOClientSwift/SwiftRegex.swift; sourceTree = "<group>"; };
|
||||
5764DF881B51F254004FF46E /* WebSocket.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WebSocket.swift; path = SocketIOClientSwift/WebSocket.swift; sourceTree = "<group>"; };
|
||||
74781D591B7E83930042CACA /* SocketIOClientStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketIOClientStatus.swift; path = SocketIOClientSwift/SocketIOClientStatus.swift; sourceTree = "<group>"; };
|
||||
941A4AB91B67A56C00C42318 /* TestKind.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestKind.swift; sourceTree = "<group>"; };
|
||||
94242BB71B67B0E500AAAC9D /* SocketNamespaceAcknowledgementTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketNamespaceAcknowledgementTest.swift; sourceTree = "<group>"; };
|
||||
945B65421B63D9DB0081E995 /* SocketEmitTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketEmitTest.swift; sourceTree = "<group>"; };
|
||||
94ADAC481B652D3300FD79AE /* SocketNamespaceEmitTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketNamespaceEmitTest.swift; sourceTree = "<group>"; };
|
||||
94ADAC4A1B6632DD00FD79AE /* SocketAcknowledgementTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketAcknowledgementTest.swift; sourceTree = "<group>"; };
|
||||
94CB8F0A1B6E48B90019ED53 /* SocketTestCases.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketTestCases.swift; sourceTree = "<group>"; };
|
||||
94CB8F0C1B6E66E60019ED53 /* AbstractSocketTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AbstractSocketTest.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -163,7 +193,13 @@
|
||||
572EF2281B51F16C00EEBB58 /* SocketIO-iOSTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
572EF22B1B51F16C00EEBB58 /* SocketIO_iOSTests.swift */,
|
||||
945B65421B63D9DB0081E995 /* SocketEmitTest.swift */,
|
||||
94ADAC4A1B6632DD00FD79AE /* SocketAcknowledgementTest.swift */,
|
||||
94ADAC481B652D3300FD79AE /* SocketNamespaceEmitTest.swift */,
|
||||
94242BB71B67B0E500AAAC9D /* SocketNamespaceAcknowledgementTest.swift */,
|
||||
941A4AB91B67A56C00C42318 /* TestKind.swift */,
|
||||
94CB8F0A1B6E48B90019ED53 /* SocketTestCases.swift */,
|
||||
94CB8F0C1B6E66E60019ED53 /* AbstractSocketTest.swift */,
|
||||
572EF2291B51F16C00EEBB58 /* Supporting Files */,
|
||||
);
|
||||
path = "SocketIO-iOSTests";
|
||||
@ -221,6 +257,7 @@
|
||||
5764DF801B51F254004FF46E /* SocketEventHandler.swift */,
|
||||
5764DF811B51F254004FF46E /* SocketFixUTF8.swift */,
|
||||
5764DF821B51F254004FF46E /* SocketIOClient.swift */,
|
||||
74781D591B7E83930042CACA /* SocketIOClientStatus.swift */,
|
||||
5764DF831B51F254004FF46E /* SocketLogger.swift */,
|
||||
5764DF841B51F254004FF46E /* SocketPacket.swift */,
|
||||
5764DF851B51F254004FF46E /* SocketParser.swift */,
|
||||
@ -413,6 +450,7 @@
|
||||
5764DF951B51F254004FF46E /* SocketIOClient.swift in Sources */,
|
||||
5764DF8B1B51F254004FF46E /* SocketAnyEvent.swift in Sources */,
|
||||
5764DF971B51F254004FF46E /* SocketLogger.swift in Sources */,
|
||||
74781D5A1B7E83930042CACA /* SocketIOClientStatus.swift in Sources */,
|
||||
5764DFA11B51F254004FF46E /* WebSocket.swift in Sources */,
|
||||
5764DF991B51F254004FF46E /* SocketPacket.swift in Sources */,
|
||||
5764DF891B51F254004FF46E /* SocketAckManager.swift in Sources */,
|
||||
@ -424,7 +462,27 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
572EF22C1B51F16C00EEBB58 /* SocketIO_iOSTests.swift in Sources */,
|
||||
945B653E1B5FCEEA0081E995 /* SocketParser.swift in Sources */,
|
||||
945B653D1B5FCEEA0081E995 /* SocketPacket.swift in Sources */,
|
||||
945B653A1B5FCEEA0081E995 /* SocketFixUTF8.swift in Sources */,
|
||||
945B65391B5FCEEA0081E995 /* SocketEventHandler.swift in Sources */,
|
||||
94CB8F0B1B6E48B90019ED53 /* SocketTestCases.swift in Sources */,
|
||||
945B65371B5FCEEA0081E995 /* SocketEngine.swift in Sources */,
|
||||
945B65351B5FCEEA0081E995 /* SocketAckManager.swift in Sources */,
|
||||
941A4ABA1B67A56C00C42318 /* TestKind.swift in Sources */,
|
||||
94CB8F0D1B6E66E60019ED53 /* AbstractSocketTest.swift in Sources */,
|
||||
945B65431B63D9DB0081E995 /* SocketEmitTest.swift in Sources */,
|
||||
945B65401B5FCEEA0081E995 /* SwiftRegex.swift in Sources */,
|
||||
945B653C1B5FCEEA0081E995 /* SocketLogger.swift in Sources */,
|
||||
945B65381B5FCEEA0081E995 /* SocketEngineClient.swift in Sources */,
|
||||
945B65361B5FCEEA0081E995 /* SocketAnyEvent.swift in Sources */,
|
||||
94ADAC4B1B6632DD00FD79AE /* SocketAcknowledgementTest.swift in Sources */,
|
||||
945B653F1B5FCEEA0081E995 /* SocketTypes.swift in Sources */,
|
||||
74781D5B1B7E83930042CACA /* SocketIOClientStatus.swift in Sources */,
|
||||
945B653B1B5FCEEA0081E995 /* SocketIOClient.swift in Sources */,
|
||||
94ADAC491B652D3300FD79AE /* SocketNamespaceEmitTest.swift in Sources */,
|
||||
945B65411B5FCEEA0081E995 /* WebSocket.swift in Sources */,
|
||||
94242BB81B67B0E500AAAC9D /* SocketNamespaceAcknowledgementTest.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -441,6 +499,7 @@
|
||||
5764DF961B51F254004FF46E /* SocketIOClient.swift in Sources */,
|
||||
5764DF8C1B51F254004FF46E /* SocketAnyEvent.swift in Sources */,
|
||||
5764DF981B51F254004FF46E /* SocketLogger.swift in Sources */,
|
||||
74781D5C1B7E83930042CACA /* SocketIOClientStatus.swift in Sources */,
|
||||
5764DFA21B51F254004FF46E /* WebSocket.swift in Sources */,
|
||||
5764DF9A1B51F254004FF46E /* SocketPacket.swift in Sources */,
|
||||
5764DF8A1B51F254004FF46E /* SocketAckManager.swift in Sources */,
|
||||
@ -453,6 +512,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
572EF24A1B51F18A00EEBB58 /* SocketIO_MacTests.swift in Sources */,
|
||||
74781D5D1B7E83930042CACA /* SocketIOClientStatus.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -485,7 +545,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
PRODUCT_NAME = SocketIO;
|
||||
SWIFT_WHOLE_MODULE_OPTIMIZATION = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
||||
@ -37,10 +37,11 @@
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
buildConfiguration = "Debug">
|
||||
codeCoverageEnabled = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
@ -62,15 +63,18 @@
|
||||
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Debug"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
@ -85,10 +89,10 @@
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Release"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
|
||||
95
Socket.IO-Test-Server/TestCases.js
Normal file
95
Socket.IO-Test-Server/TestCases.js
Normal file
@ -0,0 +1,95 @@
|
||||
var assert = require("assert")
|
||||
|
||||
module.exports = {
|
||||
basicTest: {
|
||||
assert: function(inputData) {
|
||||
|
||||
},
|
||||
returnData: []
|
||||
},
|
||||
testNull: {
|
||||
assert: function(inputData) {
|
||||
assert(!inputData)
|
||||
},
|
||||
returnData: [null]
|
||||
},
|
||||
testBinary: {
|
||||
assert: function(inputData) {
|
||||
assert.equal(inputData.toString(), "gakgakgak2")
|
||||
},
|
||||
returnData: [new Buffer("gakgakgak2", "utf-8")]
|
||||
},
|
||||
testArray: {
|
||||
assert: function(inputData) {
|
||||
assert.equal(inputData.length, 2)
|
||||
assert.equal(inputData[0], "test1")
|
||||
assert.equal(inputData[1], "test2")
|
||||
},
|
||||
returnData: [["test3", "test4"]]
|
||||
},
|
||||
testString: {
|
||||
assert: function(inputData) {
|
||||
assert.equal(inputData, "marco")
|
||||
},
|
||||
returnData: ["polo"]
|
||||
},
|
||||
testBool: {
|
||||
assert: function(inputData) {
|
||||
assert(!inputData)
|
||||
},
|
||||
returnData: [true]
|
||||
},
|
||||
testInteger: {
|
||||
assert: function(inputData) {
|
||||
assert.equal(inputData, 10)
|
||||
},
|
||||
returnData: [20]
|
||||
},
|
||||
testDouble: {
|
||||
assert: function(inputData) {
|
||||
assert.equal(inputData, 1.1)
|
||||
},
|
||||
returnData: [1.2]
|
||||
},
|
||||
testJSON: {
|
||||
assert: function(inputData) {
|
||||
assert.equal(inputData.name, "test")
|
||||
assert.equal(inputData.nestedTest.test, "test")
|
||||
assert.equal(inputData.testArray.length, 1)
|
||||
},
|
||||
returnData: [{testString: "test", testNumber: 15, nestedTest: {test: "test"}, testArray: [1, 1]}]
|
||||
},
|
||||
testJSONWithBuffer: {
|
||||
assert: function(inputData) {
|
||||
assert.equal(inputData.name, "test")
|
||||
assert.equal(inputData.nestedTest.test, "test")
|
||||
assert.equal(inputData.testArray.length, 1)
|
||||
},
|
||||
returnData: [{testString: "test", testNumber: 15, nestedTest: {test: "test"}, testArray: [new Buffer("gakgakgak2", "utf-8"), 1]}]
|
||||
},testUnicode: {
|
||||
assert: function(inputData) {
|
||||
assert.equal(inputData, "🚀")
|
||||
},
|
||||
returnData: ["🚄"]
|
||||
},testMultipleItems: {
|
||||
assert: function(array, object, number, string, bool) {
|
||||
assert.equal(array.length, 2)
|
||||
assert.equal(array[0], "test1")
|
||||
assert.equal(array[1], "test2")
|
||||
assert.equal(number, 15)
|
||||
assert.equal(string, "marco")
|
||||
assert.equal(bool, false)
|
||||
},
|
||||
returnData: [[1, 2], {test: "bob"}, 25, "polo", false]
|
||||
},testMultipleItemsWithBuffer: {
|
||||
assert: function(array, object, number, string, binary) {
|
||||
assert.equal(array.length, 2)
|
||||
assert.equal(array[0], "test1")
|
||||
assert.equal(array[1], "test2")
|
||||
assert.equal(number, 15)
|
||||
assert.equal(string, "marco")
|
||||
assert.equal(binary.toString(), "gakgakgak2")
|
||||
},
|
||||
returnData: [[1, 2], {test: "bob"}, 25, "polo", new Buffer("gakgakgak2")]
|
||||
}
|
||||
}
|
||||
10
Socket.IO-Test-Server/acknowledgementEvents.js
Normal file
10
Socket.IO-Test-Server/acknowledgementEvents.js
Normal file
@ -0,0 +1,10 @@
|
||||
function socketCallback(testKey, socket, testCase) {
|
||||
return function() {
|
||||
testCase.assert.apply(undefined , arguments)
|
||||
var emitArguments = testCase.returnData;
|
||||
var ack = arguments[arguments.length - 1]
|
||||
ack.apply(socket, emitArguments)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.socketCallback = socketCallback
|
||||
20
Socket.IO-Test-Server/emitEvents.js
Normal file
20
Socket.IO-Test-Server/emitEvents.js
Normal file
@ -0,0 +1,20 @@
|
||||
function socketCallback(testKey, socket, testCase) {
|
||||
return function() {
|
||||
testCase.assert.apply(undefined , arguments)
|
||||
|
||||
var emitArguments = addArrays([testKey + "EmitReturn"], testCase.returnData)
|
||||
socket.emit.apply(socket, emitArguments)
|
||||
}
|
||||
}
|
||||
|
||||
function addArrays(firstArray, secondArray) {
|
||||
var length = secondArray.length
|
||||
var i;
|
||||
for(i = 0; i < length; i++) {
|
||||
firstArray.push(secondArray[i])
|
||||
}
|
||||
|
||||
return firstArray;
|
||||
}
|
||||
|
||||
module.exports.socketCallback = socketCallback
|
||||
13
Socket.IO-Test-Server/main.js
Normal file
13
Socket.IO-Test-Server/main.js
Normal file
@ -0,0 +1,13 @@
|
||||
var app = require('express')()
|
||||
var server = app.listen(8080)
|
||||
var io = require('socket.io')(server)
|
||||
var acknowledgementsEvents = require("./acknowledgementEvents.js")
|
||||
var emitEvents = require("./emitEvents.js")
|
||||
var socketEventRegister = require("./socketEventRegister.js")
|
||||
|
||||
socketEventRegister.register(io, emitEvents.socketCallback, "Emit")
|
||||
socketEventRegister.register(io, acknowledgementsEvents.socketCallback, "Acknowledgement")
|
||||
|
||||
var nsp = io.of("/swift")
|
||||
socketEventRegister.register(nsp, emitEvents.socketCallback, "Emit")
|
||||
socketEventRegister.register(nsp, acknowledgementsEvents.socketCallback, "Acknowledgement")
|
||||
15
Socket.IO-Test-Server/package.json
Normal file
15
Socket.IO-Test-Server/package.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "socket.io-client-swift-test-server",
|
||||
"version": "0.0.1",
|
||||
"description": "A simple server to test aginst",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "Lukas Schmidt",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"express": "^4.13.1",
|
||||
"socket.io": "^1.3.6"
|
||||
}
|
||||
}
|
||||
13
Socket.IO-Test-Server/socketEventRegister.js
Normal file
13
Socket.IO-Test-Server/socketEventRegister.js
Normal file
@ -0,0 +1,13 @@
|
||||
var testCases = require("./TestCases.js")
|
||||
|
||||
function registerSocketForEvents(ioSocket, socketCallback, testKind) {
|
||||
ioSocket.on('connection', function(socket) {
|
||||
var testCase;
|
||||
for(testKey in testCases) {
|
||||
testCase = testCases[testKey]
|
||||
socket.on((testKey + testKind), socketCallback(testKey, socket, testCase))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
module.exports.register = registerSocketForEvents
|
||||
111
SocketIO-iOSTests/AbstractSocketTest.swift
Normal file
111
SocketIO-iOSTests/AbstractSocketTest.swift
Normal file
@ -0,0 +1,111 @@
|
||||
//
|
||||
// AbstractSocketTest.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Lukas Schmidt on 02.08.15.
|
||||
//
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
class AbstractSocketTest: XCTestCase {
|
||||
static let TEST_TIMEOUT = 8.0
|
||||
var socket:SocketIOClient!
|
||||
var testKind:TestKind?
|
||||
|
||||
override func tearDown() {
|
||||
super.tearDown()
|
||||
socket.close(fast: false)
|
||||
}
|
||||
|
||||
func openConnection() {
|
||||
let expection = self.expectationWithDescription("connect")
|
||||
XCTAssertTrue(socket.status == SocketIOClientStatus.NotConnected)
|
||||
socket.on("connect") {data, ack in
|
||||
expection.fulfill()
|
||||
}
|
||||
socket.connect()
|
||||
XCTAssertEqual(socket.status, SocketIOClientStatus.Connecting)
|
||||
waitForExpectationsWithTimeout(AbstractSocketTest.TEST_TIMEOUT, handler: nil)
|
||||
}
|
||||
|
||||
func generateTestName(rawTestName:String) ->String {
|
||||
return rawTestName + testKind!.rawValue
|
||||
}
|
||||
|
||||
func checkConnectionStatus() {
|
||||
XCTAssertEqual(socket.status, SocketIOClientStatus.Connected)
|
||||
XCTAssertFalse(socket.secure)
|
||||
}
|
||||
|
||||
func socketMultipleEmit(testName:String, emitData:Array<AnyObject>, callback:NormalCallback){
|
||||
let finalTestname = generateTestName(testName)
|
||||
weak var expection = self.expectationWithDescription(finalTestname)
|
||||
func didGetEmit(result:NSArray?, ack:AckEmitter?) {
|
||||
callback(result, ack)
|
||||
if let expection = expection {
|
||||
expection.fulfill()
|
||||
}
|
||||
}
|
||||
|
||||
socket.emit(finalTestname, withItems: emitData)
|
||||
socket.on(finalTestname + "Return", callback: didGetEmit)
|
||||
waitForExpectationsWithTimeout(SocketEmitTest.TEST_TIMEOUT, handler: nil)
|
||||
}
|
||||
|
||||
|
||||
func socketEmit(testName:String, emitData:AnyObject?, callback:NormalCallback){
|
||||
let finalTestname = generateTestName(testName)
|
||||
weak var expection = self.expectationWithDescription(finalTestname)
|
||||
func didGetEmit(result:NSArray?, ack:AckEmitter?) {
|
||||
callback(result, ack)
|
||||
if let expection = expection {
|
||||
expection.fulfill()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
socket.on(finalTestname + "Return", callback: didGetEmit)
|
||||
if let emitData = emitData {
|
||||
socket.emit(finalTestname, emitData)
|
||||
} else {
|
||||
socket.emit(finalTestname)
|
||||
}
|
||||
|
||||
waitForExpectationsWithTimeout(SocketEmitTest.TEST_TIMEOUT, handler: nil)
|
||||
}
|
||||
|
||||
func socketAcknwoledgeMultiple(testName:String, Data:Array<AnyObject>, callback:NormalCallback){
|
||||
let finalTestname = generateTestName(testName)
|
||||
weak var expection = self.expectationWithDescription(finalTestname)
|
||||
func didGetResult(result:NSArray?) {
|
||||
callback(result, nil)
|
||||
if let expection = expection {
|
||||
expection.fulfill()
|
||||
}
|
||||
}
|
||||
|
||||
socket.emitWithAck(finalTestname, withItems: Data)(timeoutAfter: 5, callback: didGetResult)
|
||||
waitForExpectationsWithTimeout(SocketEmitTest.TEST_TIMEOUT, handler: nil)
|
||||
}
|
||||
|
||||
func socketAcknwoledge(testName:String, Data:AnyObject?, callback:NormalCallback){
|
||||
let finalTestname = generateTestName(testName)
|
||||
weak var expection = self.expectationWithDescription(finalTestname)
|
||||
func didGet(result:NSArray?) {
|
||||
callback(result, nil)
|
||||
if let expection = expection {
|
||||
expection.fulfill()
|
||||
}
|
||||
}
|
||||
var ack:OnAckCallback!
|
||||
if let Data = Data {
|
||||
ack = socket.emitWithAck(finalTestname, Data)
|
||||
} else {
|
||||
ack = socket.emitWithAck(finalTestname)
|
||||
}
|
||||
ack(timeoutAfter: 20, callback: didGet)
|
||||
|
||||
waitForExpectationsWithTimeout(SocketEmitTest.TEST_TIMEOUT, handler: nil)
|
||||
}
|
||||
}
|
||||
82
SocketIO-iOSTests/SocketAcknowledgementTest.swift
Normal file
82
SocketIO-iOSTests/SocketAcknowledgementTest.swift
Normal file
@ -0,0 +1,82 @@
|
||||
//
|
||||
// SocketAcknowledgementTest.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Lukas Schmidt on 27.07.15.
|
||||
//
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
class SocketAcknowledgementTest: AbstractSocketTest {
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
testKind = TestKind.Acknowledgement
|
||||
socket = SocketIOClient(socketURL: "127.0.0.1:8080", opts: [
|
||||
"reconnects": true, // default true
|
||||
"reconnectAttempts": -1, // default -1
|
||||
"reconnectWait": 5, // default 10
|
||||
"forcePolling": false,
|
||||
"forceWebsockets": false,// default false
|
||||
"path": ""])
|
||||
openConnection()
|
||||
}
|
||||
|
||||
func testConnectionStatus() {
|
||||
super.checkConnectionStatus()
|
||||
}
|
||||
|
||||
func testBasic() {
|
||||
SocketTestCases.testBasic(socketAcknwoledge)
|
||||
}
|
||||
|
||||
func testNull() {
|
||||
SocketTestCases.testNull(socketAcknwoledge)
|
||||
}
|
||||
|
||||
func testBinary() {
|
||||
SocketTestCases.testBinary(socketAcknwoledge)
|
||||
}
|
||||
|
||||
func testArray() {
|
||||
SocketTestCases.testArray(socketAcknwoledge)
|
||||
}
|
||||
|
||||
func testString() {
|
||||
SocketTestCases.testString(socketAcknwoledge)
|
||||
}
|
||||
|
||||
func testBool() {
|
||||
SocketTestCases.testBool(socketAcknwoledge)
|
||||
}
|
||||
|
||||
func testInteger() {
|
||||
SocketTestCases.testInteger(socketAcknwoledge)
|
||||
}
|
||||
|
||||
func testDouble() {
|
||||
SocketTestCases.testDouble(socketAcknwoledge)
|
||||
}
|
||||
|
||||
func testJSON() {
|
||||
SocketTestCases.testJSON(socketAcknwoledge)
|
||||
}
|
||||
|
||||
func testJSONWithBuffer() {
|
||||
SocketTestCases.testJSONWithBuffer(socketAcknwoledge)
|
||||
}
|
||||
|
||||
func testUnicode() {
|
||||
SocketTestCases.testUnicode(socketAcknwoledge)
|
||||
}
|
||||
|
||||
func testMultipleItems() {
|
||||
SocketTestCases.testMultipleItems(socketAcknwoledgeMultiple)
|
||||
}
|
||||
|
||||
func testMultipleWithBuffer() {
|
||||
SocketTestCases.testMultipleItemsWithBuffer(socketAcknwoledgeMultiple)
|
||||
}
|
||||
|
||||
}
|
||||
88
SocketIO-iOSTests/SocketEmitTest.swift
Normal file
88
SocketIO-iOSTests/SocketEmitTest.swift
Normal file
@ -0,0 +1,88 @@
|
||||
//
|
||||
// ConvertedSocketTest.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Lukas Schmidt on 25.07.15.
|
||||
//
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Foundation
|
||||
|
||||
class SocketEmitTest: AbstractSocketTest {
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
testKind = TestKind.Emit
|
||||
socket = SocketIOClient(socketURL: "127.0.0.1:8080", opts: [
|
||||
"reconnects": true, // default true
|
||||
"reconnectAttempts": -1, // default -1
|
||||
"reconnectWait": 5, // default 10
|
||||
"forcePolling": false,
|
||||
"forceWebsockets": false,// default false
|
||||
"path": ""]
|
||||
)
|
||||
openConnection()
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
socket.close(fast: false)
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testConnectionStatus() {
|
||||
super.checkConnectionStatus()
|
||||
}
|
||||
|
||||
func testBasic() {
|
||||
SocketTestCases.testBasic(socketEmit)
|
||||
}
|
||||
|
||||
func testNull() {
|
||||
SocketTestCases.testNull(socketEmit)
|
||||
}
|
||||
|
||||
func testBinary() {
|
||||
SocketTestCases.testBinary(socketEmit)
|
||||
}
|
||||
|
||||
func testArray() {
|
||||
SocketTestCases.testArray(socketEmit)
|
||||
}
|
||||
|
||||
func testString() {
|
||||
SocketTestCases.testString(socketEmit)
|
||||
}
|
||||
|
||||
func testBool() {
|
||||
SocketTestCases.testBool(socketEmit)
|
||||
}
|
||||
|
||||
func testInteger() {
|
||||
SocketTestCases.testInteger(socketEmit)
|
||||
}
|
||||
|
||||
func testDouble() {
|
||||
SocketTestCases.testDouble(socketEmit)
|
||||
}
|
||||
|
||||
func testJSON() {
|
||||
SocketTestCases.testJSON(socketEmit)
|
||||
}
|
||||
|
||||
func testJSONWithBuffer() {
|
||||
SocketTestCases.testJSONWithBuffer(socketEmit)
|
||||
}
|
||||
|
||||
func testUnicode() {
|
||||
SocketTestCases.testUnicode(socketEmit)
|
||||
}
|
||||
|
||||
func testMultipleItems() {
|
||||
SocketTestCases.testMultipleItems(socketMultipleEmit)
|
||||
}
|
||||
|
||||
func testMultipleWithBuffer() {
|
||||
SocketTestCases.testMultipleItemsWithBuffer(socketMultipleEmit)
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,36 +0,0 @@
|
||||
//
|
||||
// SocketIO_iOSTests.swift
|
||||
// SocketIO-iOSTests
|
||||
//
|
||||
// Created by Nacho Soto on 7/11/15.
|
||||
//
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import XCTest
|
||||
|
||||
class SocketIO_iOSTests: XCTestCase {
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testExample() {
|
||||
// This is an example of a functional test case.
|
||||
XCTAssert(true, "Pass")
|
||||
}
|
||||
|
||||
func testPerformanceExample() {
|
||||
// This is an example of a performance test case.
|
||||
self.measureBlock() {
|
||||
// Put the code you want to measure the time of here.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
82
SocketIO-iOSTests/SocketNamespaceAcknowledgementTest.swift
Normal file
82
SocketIO-iOSTests/SocketNamespaceAcknowledgementTest.swift
Normal file
@ -0,0 +1,82 @@
|
||||
//
|
||||
// SocketNamespaceAcknowledgementTest.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Lukas Schmidt on 28.07.15.
|
||||
//
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
class SocketNamespaceAcknowledgementTest: AbstractSocketTest {
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
testKind = TestKind.Acknowledgement
|
||||
socket = SocketIOClient(socketURL: "127.0.0.1:8080", opts: [
|
||||
"reconnects": true, // default true
|
||||
"reconnectAttempts": -1, // default -1
|
||||
"reconnectWait": 5, // default 10
|
||||
"forcePolling": false,
|
||||
"forceWebsockets": false,// default false
|
||||
"path": "",
|
||||
"nsp": "/swift"])
|
||||
openConnection()
|
||||
}
|
||||
|
||||
func testConnectionStatus() {
|
||||
super.checkConnectionStatus()
|
||||
}
|
||||
|
||||
func testBasic() {
|
||||
SocketTestCases.testBasic(socketAcknwoledge)
|
||||
}
|
||||
|
||||
func testNull() {
|
||||
SocketTestCases.testNull(socketAcknwoledge)
|
||||
}
|
||||
|
||||
func testBinary() {
|
||||
SocketTestCases.testBinary(socketAcknwoledge)
|
||||
}
|
||||
|
||||
func testArray() {
|
||||
SocketTestCases.testArray(socketAcknwoledge)
|
||||
}
|
||||
|
||||
func testString() {
|
||||
SocketTestCases.testString(socketAcknwoledge)
|
||||
}
|
||||
|
||||
func testBool() {
|
||||
SocketTestCases.testBool(socketAcknwoledge)
|
||||
}
|
||||
|
||||
func testInteger() {
|
||||
SocketTestCases.testInteger(socketAcknwoledge)
|
||||
}
|
||||
|
||||
func testDouble() {
|
||||
SocketTestCases.testDouble(socketAcknwoledge)
|
||||
}
|
||||
|
||||
func testJSON() {
|
||||
SocketTestCases.testJSON(socketAcknwoledge)
|
||||
}
|
||||
|
||||
func testJSONWithBuffer() {
|
||||
SocketTestCases.testJSONWithBuffer(socketAcknwoledge)
|
||||
}
|
||||
|
||||
func testUnicode() {
|
||||
SocketTestCases.testUnicode(socketAcknwoledge)
|
||||
}
|
||||
|
||||
func testMultipleItems() {
|
||||
SocketTestCases.testMultipleItems(socketAcknwoledgeMultiple)
|
||||
}
|
||||
|
||||
func testMultipleWithBuffer() {
|
||||
SocketTestCases.testMultipleItemsWithBuffer(socketAcknwoledgeMultiple)
|
||||
}
|
||||
}
|
||||
83
SocketIO-iOSTests/SocketNamespaceEmitTest.swift
Normal file
83
SocketIO-iOSTests/SocketNamespaceEmitTest.swift
Normal file
@ -0,0 +1,83 @@
|
||||
//
|
||||
// SocketNamespaceEmitTest.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Lukas Schmidt on 26.07.15.
|
||||
//
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
class SocketNamespaceEmitTest: AbstractSocketTest {
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
testKind = TestKind.Emit
|
||||
socket = SocketIOClient(socketURL: "127.0.0.1:8080", opts: [
|
||||
"reconnects": true, // default true
|
||||
"reconnectAttempts": -1, // default -1
|
||||
"reconnectWait": 5, // default 10
|
||||
"forcePolling": false,
|
||||
"forceWebsockets": false,// default false
|
||||
"path": "",
|
||||
"nsp": "/swift"])
|
||||
openConnection()
|
||||
}
|
||||
|
||||
func testConnectionStatus() {
|
||||
super.checkConnectionStatus()
|
||||
}
|
||||
|
||||
func testBasic() {
|
||||
SocketTestCases.testBasic(socketEmit)
|
||||
}
|
||||
|
||||
func testNull() {
|
||||
SocketTestCases.testNull(socketEmit)
|
||||
}
|
||||
|
||||
func testBinary() {
|
||||
SocketTestCases.testBinary(socketEmit)
|
||||
}
|
||||
|
||||
func testArray() {
|
||||
SocketTestCases.testArray(socketEmit)
|
||||
}
|
||||
|
||||
func testString() {
|
||||
SocketTestCases.testString(socketEmit)
|
||||
}
|
||||
|
||||
func testBool() {
|
||||
SocketTestCases.testBool(socketEmit)
|
||||
}
|
||||
|
||||
func testInteger() {
|
||||
SocketTestCases.testInteger(socketEmit)
|
||||
}
|
||||
|
||||
func testDouble() {
|
||||
SocketTestCases.testDouble(socketEmit)
|
||||
}
|
||||
|
||||
func testJSON() {
|
||||
SocketTestCases.testJSON(socketEmit)
|
||||
}
|
||||
|
||||
func testJSONWithBuffer() {
|
||||
SocketTestCases.testJSONWithBuffer(socketEmit)
|
||||
}
|
||||
|
||||
func testUnicode() {
|
||||
SocketTestCases.testUnicode(socketEmit)
|
||||
}
|
||||
|
||||
func testMultipleItems() {
|
||||
SocketTestCases.testMultipleItems(socketMultipleEmit)
|
||||
}
|
||||
|
||||
func testMultipleWithBuffer() {
|
||||
SocketTestCases.testMultipleItemsWithBuffer(socketMultipleEmit)
|
||||
}
|
||||
|
||||
}
|
||||
246
SocketIO-iOSTests/SocketTestCases.swift
Normal file
246
SocketIO-iOSTests/SocketTestCases.swift
Normal file
@ -0,0 +1,246 @@
|
||||
//
|
||||
// SocketTestCases.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Lukas Schmidt on 02.08.15.
|
||||
//
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Foundation
|
||||
|
||||
class SocketTestCases: NSObject {
|
||||
typealias SocketSendFunction = (testName:String, emitData:AnyObject?, callback:NormalCallback)->()
|
||||
|
||||
static func testBasic(abstractSocketSend:SocketSendFunction) {
|
||||
let testName = "basicTest"
|
||||
func didGetResult(result:NSArray?, ack:AckEmitter?) {
|
||||
|
||||
}
|
||||
abstractSocketSend(testName: testName, emitData: nil, callback: didGetResult)
|
||||
}
|
||||
|
||||
static func testNull(abstractSocketSend:SocketSendFunction) {
|
||||
let testName = "testNull"
|
||||
func didGetResult(result:NSArray?, ack:AckEmitter?) {
|
||||
if let _ = result?.firstObject as? NSNull {
|
||||
|
||||
}else
|
||||
{
|
||||
XCTFail("Should have NSNull as result")
|
||||
}
|
||||
}
|
||||
abstractSocketSend(testName: testName, emitData: NSNull(), callback: didGetResult)
|
||||
}
|
||||
|
||||
static func testBinary(abstractSocketSend:SocketSendFunction) {
|
||||
let testName = "testBinary"
|
||||
func didGetResult(result:NSArray?, ack:AckEmitter?) {
|
||||
if let data = result?.firstObject as? NSData {
|
||||
let string = NSString(data: data, encoding: NSUTF8StringEncoding)!
|
||||
XCTAssertEqual(string, "gakgakgak2")
|
||||
}else {
|
||||
XCTFail("Should have NSData as result")
|
||||
}
|
||||
}
|
||||
let data = NSString(string: "gakgakgak2").dataUsingEncoding(NSUTF8StringEncoding)!
|
||||
abstractSocketSend(testName: testName, emitData: data, callback: didGetResult)
|
||||
}
|
||||
|
||||
static func testArray(abstractSocketSend:SocketSendFunction) {
|
||||
let testName = "testArray"
|
||||
func didGetResult(result:NSArray?, ack:AckEmitter?) {
|
||||
if let array = result?.firstObject as? NSArray {
|
||||
XCTAssertEqual(array.count, 2)
|
||||
XCTAssertEqual((array.firstObject! as! String), "test3")
|
||||
XCTAssertEqual((array.lastObject! as! String), "test4")
|
||||
}else {
|
||||
XCTFail("Should have NSArray as result")
|
||||
}
|
||||
}
|
||||
abstractSocketSend(testName: testName, emitData: ["test1", "test2"], callback: didGetResult)
|
||||
}
|
||||
|
||||
static func testString(abstractSocketSend:SocketSendFunction) {
|
||||
let testName = "testString"
|
||||
func didGetResult(result:NSArray?, ack:AckEmitter?) {
|
||||
if let string = result?.firstObject as? String {
|
||||
XCTAssertEqual(string, "polo")
|
||||
}else {
|
||||
XCTFail("Should have String as result")
|
||||
}
|
||||
}
|
||||
abstractSocketSend(testName: testName, emitData: "marco", callback: didGetResult)
|
||||
}
|
||||
|
||||
static func testBool(abstractSocketSend:SocketSendFunction) {
|
||||
let testName = "testBool"
|
||||
func didGetResult(result:NSArray?, ack:AckEmitter?) {
|
||||
if let bool = result?.firstObject as? NSNumber {
|
||||
XCTAssertTrue(bool.boolValue)
|
||||
}else {
|
||||
XCTFail("Should have Boolean as result")
|
||||
}
|
||||
}
|
||||
abstractSocketSend(testName: testName, emitData: false, callback: didGetResult)
|
||||
}
|
||||
|
||||
static func testInteger(abstractSocketSend:SocketSendFunction) {
|
||||
let testName = "testInteger"
|
||||
func didGetResult(result:NSArray?, ack:AckEmitter?) {
|
||||
if let integer = result?.firstObject as? Int {
|
||||
XCTAssertEqual(integer, 20)
|
||||
}else {
|
||||
XCTFail("Should have Integer as result")
|
||||
}
|
||||
}
|
||||
abstractSocketSend(testName: testName, emitData: 10, callback: didGetResult)
|
||||
}
|
||||
|
||||
static func testDouble(abstractSocketSend:SocketSendFunction) {
|
||||
let testName = "testDouble"
|
||||
func didGetResult(result:NSArray?, ack:AckEmitter?) {
|
||||
if let double = result?.firstObject as? NSNumber {
|
||||
XCTAssertEqual(double.floatValue, 1.2)
|
||||
}else {
|
||||
XCTFail("Should have Double as result")
|
||||
}
|
||||
}
|
||||
abstractSocketSend(testName: testName, emitData: 1.1, callback: didGetResult)
|
||||
}
|
||||
|
||||
static func testJSONWithBuffer(abstractSocketSend:SocketSendFunction) {
|
||||
let testName = "testJSONWithBuffer"
|
||||
func didGetResult(result:NSArray?, ack:AckEmitter?) {
|
||||
if let json = result?.firstObject as? NSDictionary {
|
||||
XCTAssertEqual((json.valueForKey("testString")! as! String), "test")
|
||||
XCTAssertEqual((json.valueForKey("testNumber")! as! Int), 15)
|
||||
XCTAssertEqual((json.valueForKey("testArray")! as! Array<AnyObject>).count, 2)
|
||||
XCTAssertEqual(((json.valueForKey("testArray")! as! Array<AnyObject>).last! as! Int), 1)
|
||||
let string = NSString(data: (json.valueForKey("testArray")! as! Array<AnyObject>).first! as! NSData, encoding: NSUTF8StringEncoding)!
|
||||
XCTAssertEqual(string, "gakgakgak2")
|
||||
}else {
|
||||
XCTFail("Should have NSDictionary as result")
|
||||
}
|
||||
}
|
||||
let json = ["name": "test", "testArray": ["hallo"], "nestedTest": ["test": "test"], "number": 15]
|
||||
|
||||
abstractSocketSend(testName: testName, emitData: json, callback: didGetResult)
|
||||
}
|
||||
|
||||
static func testJSON(abstractSocketSend:SocketSendFunction) {
|
||||
let testName = "testJSON"
|
||||
func didGetResult(result:NSArray?, ack:AckEmitter?) {
|
||||
if let json = result?.firstObject as? NSDictionary {
|
||||
XCTAssertEqual((json.valueForKey("testString")! as! String), "test")
|
||||
XCTAssertEqual(json.valueForKey("testNumber")! as? Int, 15)
|
||||
XCTAssertEqual((json.valueForKey("testArray")! as! Array<AnyObject>).count, 2)
|
||||
XCTAssertEqual((json.valueForKey("testArray")! as! Array<AnyObject>).first! as? Int, 1)
|
||||
XCTAssertEqual((json.valueForKey("testArray")! as! Array<AnyObject>).last! as? Int, 1)
|
||||
|
||||
}else {
|
||||
XCTFail("Should have NSDictionary as result")
|
||||
}
|
||||
}
|
||||
let json = ["name": "test", "testArray": ["hallo"], "nestedTest": ["test": "test"], "number": 15]
|
||||
|
||||
abstractSocketSend(testName: testName, emitData: json, callback: didGetResult)
|
||||
}
|
||||
|
||||
static func testUnicode(abstractSocketSend:SocketSendFunction) {
|
||||
let testName = "testUnicode"
|
||||
func didGetResult(result:NSArray?, ack:AckEmitter?) {
|
||||
if let unicode = result?.firstObject as? String {
|
||||
XCTAssertEqual(unicode, "🚄")
|
||||
}else {
|
||||
XCTFail("Should have String as result")
|
||||
}
|
||||
}
|
||||
abstractSocketSend(testName: testName, emitData: "🚀", callback: didGetResult)
|
||||
}
|
||||
|
||||
static func testMultipleItemsWithBuffer(abstractSocketMultipleSend:(testName:String, emitData:Array<AnyObject>, callback:NormalCallback)->()) {
|
||||
let testName = "testMultipleItemsWithBuffer"
|
||||
func didGetResult(result:NSArray?, ack:AckEmitter?) {
|
||||
XCTAssertEqual(result!.count, 5)
|
||||
if result!.count != 5 {
|
||||
XCTFail("Fatal Fail. Lost some Data")
|
||||
return
|
||||
}
|
||||
if let array = result?.firstObject as? Array<AnyObject> {
|
||||
XCTAssertEqual((array.last! as! Int), 2)
|
||||
XCTAssertEqual((array.first! as! Int), 1)
|
||||
}else {
|
||||
XCTFail("Should have Array as result")
|
||||
}
|
||||
if let dict = result?[1] as? NSDictionary {
|
||||
XCTAssertEqual((dict.valueForKey("test") as! String), "bob")
|
||||
|
||||
}else {
|
||||
XCTFail("Should have NSDictionary as result")
|
||||
}
|
||||
if let number = result?[2] as? Int {
|
||||
XCTAssertEqual(number, 25)
|
||||
|
||||
}else {
|
||||
XCTFail("Should have Integer as result")
|
||||
}
|
||||
if let string = result?[3] as? String {
|
||||
XCTAssertEqual(string, "polo")
|
||||
|
||||
}else {
|
||||
XCTFail("Should have Integer as result")
|
||||
}
|
||||
if let data = result?[4] as? NSData {
|
||||
let string = NSString(data: data, encoding: NSUTF8StringEncoding)!
|
||||
XCTAssertEqual(string, "gakgakgak2")
|
||||
}else {
|
||||
XCTFail("Should have NSData as result")
|
||||
}
|
||||
}
|
||||
let data = NSString(string: "gakgakgak2").dataUsingEncoding(NSUTF8StringEncoding)!
|
||||
let emitArray = [["test1", "test2"], ["test": "test"], 15, "marco", data]
|
||||
abstractSocketMultipleSend(testName: testName, emitData: emitArray, callback: didGetResult)
|
||||
}
|
||||
|
||||
static func testMultipleItems(abstractSocketMultipleSend:(testName:String, emitData:Array<AnyObject>, callback:NormalCallback)->()) {
|
||||
let testName = "testMultipleItems"
|
||||
func didGetResult(result:NSArray?, ack:AckEmitter?) {
|
||||
XCTAssertEqual(result!.count, 5)
|
||||
if result!.count != 5 {
|
||||
XCTFail("Fatal Fail. Lost some Data")
|
||||
return
|
||||
}
|
||||
if let array = result?.firstObject as? Array<AnyObject> {
|
||||
XCTAssertEqual((array.last! as! Int), 2)
|
||||
XCTAssertEqual((array.first! as! Int), 1)
|
||||
}else {
|
||||
XCTFail("Should have Array as result")
|
||||
}
|
||||
if let dict = result?[1] as? NSDictionary {
|
||||
XCTAssertEqual((dict.valueForKey("test") as! String), "bob")
|
||||
|
||||
}else {
|
||||
XCTFail("Should have NSDictionary as result")
|
||||
}
|
||||
if let number = result?[2] as? Int {
|
||||
XCTAssertEqual(number, 25)
|
||||
|
||||
}else {
|
||||
XCTFail("Should have Integer as result")
|
||||
}
|
||||
if let string = result?[3] as? String {
|
||||
XCTAssertEqual(string, "polo")
|
||||
}else {
|
||||
XCTFail("Should have Integer as result")
|
||||
}
|
||||
if let bool = result?[4] as? NSNumber {
|
||||
XCTAssertFalse(bool.boolValue)
|
||||
}else {
|
||||
XCTFail("Should have NSNumber as result")
|
||||
}
|
||||
}
|
||||
let emitArray = [["test1", "test2"], ["test": "test"], 15, "marco", false]
|
||||
abstractSocketMultipleSend(testName: testName, emitData: emitArray, callback: didGetResult)
|
||||
}
|
||||
}
|
||||
13
SocketIO-iOSTests/TestKind.swift
Normal file
13
SocketIO-iOSTests/TestKind.swift
Normal file
@ -0,0 +1,13 @@
|
||||
//
|
||||
// TestKind.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Lukas Schmidt on 28.07.15.
|
||||
//
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum TestKind: String {
|
||||
case Emit, Acknowledgement
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
//
|
||||
// SocketAckManager.swift
|
||||
// SocketIO-Swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 4/3/15.
|
||||
//
|
||||
@ -25,38 +25,38 @@
|
||||
import Foundation
|
||||
|
||||
private struct SocketAck: Hashable, Equatable {
|
||||
let ack:Int
|
||||
var callback:AckCallback!
|
||||
var hashValue:Int {
|
||||
let ack: Int
|
||||
var callback: AckCallback!
|
||||
var hashValue: Int {
|
||||
return ack.hashValue
|
||||
}
|
||||
|
||||
init(ack:Int) {
|
||||
init(ack: Int) {
|
||||
self.ack = ack
|
||||
}
|
||||
|
||||
init(ack:Int, callback:AckCallback) {
|
||||
init(ack: Int, callback: AckCallback) {
|
||||
self.ack = ack
|
||||
self.callback = callback
|
||||
}
|
||||
}
|
||||
|
||||
private func <(lhs:SocketAck, rhs:SocketAck) -> Bool {
|
||||
private func <(lhs: SocketAck, rhs: SocketAck) -> Bool {
|
||||
return lhs.ack < rhs.ack
|
||||
}
|
||||
|
||||
private func ==(lhs:SocketAck, rhs:SocketAck) -> Bool {
|
||||
private func ==(lhs: SocketAck, rhs: SocketAck) -> Bool {
|
||||
return lhs.ack == rhs.ack
|
||||
}
|
||||
|
||||
struct SocketAckManager {
|
||||
private var acks = Set<SocketAck>(minimumCapacity: 1)
|
||||
|
||||
mutating func addAck(ack:Int, callback:AckCallback) {
|
||||
mutating func addAck(ack: Int, callback: AckCallback) {
|
||||
acks.insert(SocketAck(ack: ack, callback: callback))
|
||||
}
|
||||
|
||||
mutating func executeAck(ack:Int, items:[AnyObject]?) {
|
||||
mutating func executeAck(ack: Int, items: [AnyObject]?) {
|
||||
let callback = acks.remove(SocketAck(ack: ack))
|
||||
|
||||
dispatch_async(dispatch_get_main_queue()) {
|
||||
@ -64,7 +64,7 @@ struct SocketAckManager {
|
||||
}
|
||||
}
|
||||
|
||||
mutating func timeoutAck(ack:Int) {
|
||||
mutating func timeoutAck(ack: Int) {
|
||||
let callback = acks.remove(SocketAck(ack: ack))
|
||||
|
||||
dispatch_async(dispatch_get_main_queue()) {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
//
|
||||
// SocketAnyEvent.swift
|
||||
// Socket.IO-Swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 3/28/15.
|
||||
//
|
||||
@ -24,11 +24,14 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
@objc public final class SocketAnyEvent {
|
||||
public let event:String!
|
||||
public let items:NSArray?
|
||||
@objc public final class SocketAnyEvent: NSObject {
|
||||
public let event: String!
|
||||
public let items: NSArray?
|
||||
override public var description: String {
|
||||
return "SocketAnyEvent: Event: \(event) items: \(items ?? nil)"
|
||||
}
|
||||
|
||||
init(event:String, items:NSArray?) {
|
||||
init(event: String, items: NSArray?) {
|
||||
self.event = event
|
||||
self.items = items
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
//
|
||||
// SocketEngine.swift
|
||||
// Socket.IO-Swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 3/3/15.
|
||||
//
|
||||
@ -25,24 +25,23 @@
|
||||
import Foundation
|
||||
|
||||
public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
|
||||
private typealias Probe = (msg:String, type:PacketType, data:ContiguousArray<NSData>?)
|
||||
private typealias Probe = (msg: String, type: PacketType, data: [NSData]?)
|
||||
private typealias ProbeWaitQueue = [Probe]
|
||||
|
||||
|
||||
private let allowedCharacterSet = NSCharacterSet(charactersInString: "!*'();:@&=+$,/?%#[]\" {}").invertedSet
|
||||
private let workQueue = NSOperationQueue()
|
||||
private let emitQueue = dispatch_queue_create("engineEmitQueue", DISPATCH_QUEUE_SERIAL)
|
||||
private let parseQueue = dispatch_queue_create("engineParseQueue", DISPATCH_QUEUE_SERIAL)
|
||||
private let handleQueue = dispatch_queue_create("engineHandleQueue", DISPATCH_QUEUE_SERIAL)
|
||||
private let session:NSURLSession!
|
||||
|
||||
private let session: NSURLSession!
|
||||
|
||||
private var closed = false
|
||||
private var _connected = false
|
||||
private var extraHeaders:[String: String]?
|
||||
private var extraHeaders: [String: String]?
|
||||
private var fastUpgrade = false
|
||||
private var forcePolling = false
|
||||
private var forceWebsockets = false
|
||||
private var pingInterval:Double?
|
||||
private var pingTimer:NSTimer?
|
||||
private var pingInterval: Double?
|
||||
private var pingTimer: NSTimer?
|
||||
private var pingTimeout = 0.0 {
|
||||
didSet {
|
||||
pongsMissedMax = Int(pingTimeout / (pingInterval ?? 25))
|
||||
@ -51,117 +50,102 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
|
||||
private var pongsMissed = 0
|
||||
private var pongsMissedMax = 0
|
||||
private var postWait = [String]()
|
||||
private var _polling = true
|
||||
private var probing = false
|
||||
private var probeWait = ProbeWaitQueue()
|
||||
private var waitingForPoll = false
|
||||
private var waitingForPost = false
|
||||
private var _websocket = false
|
||||
private var websocketConnected = false
|
||||
|
||||
|
||||
let logType = "SocketEngine"
|
||||
|
||||
var connected:Bool {
|
||||
return _connected
|
||||
}
|
||||
weak var client:SocketEngineClient?
|
||||
var cookies:[NSHTTPCookie]?
|
||||
var log = false
|
||||
var polling:Bool {
|
||||
return _polling
|
||||
}
|
||||
|
||||
private(set) var connected = false
|
||||
private(set) var polling = true
|
||||
private(set) var websocket = false
|
||||
|
||||
weak var client: SocketEngineClient?
|
||||
var cookies: [NSHTTPCookie]?
|
||||
var sid = ""
|
||||
var socketPath = ""
|
||||
var urlPolling:String?
|
||||
var urlWebSocket:String?
|
||||
var websocket:Bool {
|
||||
return _websocket
|
||||
}
|
||||
var urlPolling: String?
|
||||
var urlWebSocket: String?
|
||||
var ws:WebSocket?
|
||||
|
||||
public enum PacketType:Int {
|
||||
case OPEN = 0
|
||||
case CLOSE = 1
|
||||
case PING = 2
|
||||
case PONG = 3
|
||||
case MESSAGE = 4
|
||||
case UPGRADE = 5
|
||||
case NOOP = 6
|
||||
|
||||
init?(str:String?) {
|
||||
if let value = str?.toInt(), raw = PacketType(rawValue: value) {
|
||||
|
||||
public enum PacketType: Int {
|
||||
case Open, Close, Ping, Pong, Message, Upgrade, Noop
|
||||
|
||||
init?(str: String?) {
|
||||
if let value = Int(str ?? ""), raw = PacketType(rawValue: value) {
|
||||
self = raw
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public init(client:SocketEngineClient, sessionDelegate:NSURLSessionDelegate?) {
|
||||
|
||||
public init(client: SocketEngineClient, sessionDelegate: NSURLSessionDelegate?) {
|
||||
self.client = client
|
||||
self.session = NSURLSession(configuration: NSURLSessionConfiguration.ephemeralSessionConfiguration(),
|
||||
self.session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration(),
|
||||
delegate: sessionDelegate, delegateQueue: workQueue)
|
||||
}
|
||||
|
||||
public convenience init(client:SocketEngineClient, opts:NSDictionary?) {
|
||||
|
||||
public convenience init(client: SocketEngineClient, opts: NSDictionary?) {
|
||||
self.init(client: client, sessionDelegate: opts?["sessionDelegate"] as? NSURLSessionDelegate)
|
||||
forceWebsockets = opts?["forceWebsockets"] as? Bool ?? false
|
||||
forcePolling = opts?["forcePolling"] as? Bool ?? false
|
||||
cookies = opts?["cookies"] as? [NSHTTPCookie]
|
||||
log = opts?["log"] as? Bool ?? false
|
||||
socketPath = opts?["path"] as? String ?? ""
|
||||
extraHeaders = opts?["extraHeaders"] as? [String: String]
|
||||
}
|
||||
|
||||
|
||||
deinit {
|
||||
SocketLogger.log("Engine is being deinit", client: self)
|
||||
}
|
||||
|
||||
public func close(#fast:Bool) {
|
||||
|
||||
public func close(fast fast: Bool) {
|
||||
SocketLogger.log("Engine is being closed. Fast: %@", client: self, args: fast)
|
||||
|
||||
|
||||
pingTimer?.invalidate()
|
||||
closed = true
|
||||
|
||||
|
||||
ws?.disconnect()
|
||||
|
||||
|
||||
if fast || polling {
|
||||
write("", withType: PacketType.CLOSE, withData: nil)
|
||||
write("", withType: PacketType.Close, withData: nil)
|
||||
client?.engineDidClose("Disconnect")
|
||||
}
|
||||
|
||||
|
||||
stopPolling()
|
||||
}
|
||||
|
||||
private func createBinaryDataForSend(data:NSData) -> (NSData?, String?) {
|
||||
|
||||
private func createBinaryDataForSend(data: NSData) -> (NSData?, String?) {
|
||||
if websocket {
|
||||
var byteArray = [UInt8](count: 1, repeatedValue: 0x0)
|
||||
byteArray[0] = 4
|
||||
var mutData = NSMutableData(bytes: &byteArray, length: 1)
|
||||
|
||||
let mutData = NSMutableData(bytes: &byteArray, length: 1)
|
||||
|
||||
mutData.appendData(data)
|
||||
|
||||
|
||||
return (mutData, nil)
|
||||
} else {
|
||||
var str = "b4"
|
||||
str += data.base64EncodedStringWithOptions(
|
||||
NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
|
||||
|
||||
|
||||
return (nil, str)
|
||||
}
|
||||
}
|
||||
|
||||
private func createURLs(params:[String: AnyObject]?) -> (String?, String?) {
|
||||
|
||||
private func createURLs(params: [String: AnyObject]?) -> (String?, String?) {
|
||||
if client == nil {
|
||||
return (nil, nil)
|
||||
}
|
||||
|
||||
|
||||
let path = socketPath == "" ? "/socket.io" : socketPath
|
||||
|
||||
var url = "\(client!.socketURL)\(path)/?transport="
|
||||
var urlPolling:String
|
||||
var urlWebSocket:String
|
||||
|
||||
|
||||
let url = "\(client!.socketURL)\(path)/?transport="
|
||||
var urlPolling: String
|
||||
var urlWebSocket: String
|
||||
|
||||
if client!.secure {
|
||||
urlPolling = "https://" + url + "polling"
|
||||
urlWebSocket = "wss://" + url + "websocket"
|
||||
@ -169,15 +153,15 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
|
||||
urlPolling = "http://" + url + "polling"
|
||||
urlWebSocket = "ws://" + url + "websocket"
|
||||
}
|
||||
|
||||
|
||||
if params != nil {
|
||||
|
||||
|
||||
for (key, value) in params! {
|
||||
let keyEsc = key.stringByAddingPercentEncodingWithAllowedCharacters(
|
||||
allowedCharacterSet)!
|
||||
urlPolling += "&\(keyEsc)="
|
||||
urlWebSocket += "&\(keyEsc)="
|
||||
|
||||
|
||||
if value is String {
|
||||
let valueEsc = (value as! String).stringByAddingPercentEncodingWithAllowedCharacters(
|
||||
allowedCharacterSet)!
|
||||
@ -189,11 +173,11 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (urlPolling, urlWebSocket)
|
||||
}
|
||||
|
||||
private func createWebsocket(andConnect connect:Bool) {
|
||||
|
||||
private func createWebsocket(andConnect connect: Bool) {
|
||||
let wsUrl = urlWebSocket! + (sid == "" ? "" : "&sid=\(sid)")
|
||||
|
||||
ws = WebSocket(url: NSURL(string: wsUrl)!,
|
||||
@ -207,34 +191,34 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
|
||||
|
||||
ws?.queue = handleQueue
|
||||
ws?.delegate = self
|
||||
|
||||
|
||||
if connect {
|
||||
ws?.connect()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func doFastUpgrade() {
|
||||
if waitingForPoll {
|
||||
SocketLogger.err("Outstanding poll when switched to WebSockets," +
|
||||
"we'll probably disconnect soon. You should report this.", client: self)
|
||||
}
|
||||
|
||||
sendWebSocketMessage("", withType: PacketType.UPGRADE, datas: nil)
|
||||
_websocket = true
|
||||
_polling = false
|
||||
|
||||
sendWebSocketMessage("", withType: PacketType.Upgrade, datas: nil)
|
||||
websocket = true
|
||||
polling = false
|
||||
fastUpgrade = false
|
||||
probing = false
|
||||
flushProbeWait()
|
||||
}
|
||||
|
||||
|
||||
private func doPoll() {
|
||||
if websocket || waitingForPoll || !connected {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
waitingForPoll = true
|
||||
let req = NSMutableURLRequest(URL: NSURL(string: urlPolling! + "&sid=\(sid)&b64=1")!)
|
||||
|
||||
|
||||
if cookies != nil {
|
||||
let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies!)
|
||||
req.allHTTPHeaderFields = headers
|
||||
@ -248,37 +232,37 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
|
||||
|
||||
doRequest(req)
|
||||
}
|
||||
|
||||
private func doRequest(req:NSMutableURLRequest) {
|
||||
|
||||
private func doRequest(req: NSMutableURLRequest) {
|
||||
if !polling {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
req.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalAndRemoteCacheData
|
||||
|
||||
|
||||
SocketLogger.log("Doing polling request", client: self)
|
||||
|
||||
|
||||
session.dataTaskWithRequest(req) {[weak self] data, res, err in
|
||||
if let this = self {
|
||||
if err != nil {
|
||||
if err != nil || data == nil {
|
||||
if this.polling {
|
||||
this.handlePollingFailed(err.localizedDescription)
|
||||
this.handlePollingFailed(err?.localizedDescription ?? "Error")
|
||||
} else {
|
||||
SocketLogger.err(err.localizedDescription, client: this)
|
||||
SocketLogger.err(err?.localizedDescription ?? "Error", client: this)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
SocketLogger.log("Got polling response", client: this)
|
||||
|
||||
if let str = NSString(data: data, encoding: NSUTF8StringEncoding) as? String {
|
||||
|
||||
if let str = NSString(data: data!, encoding: NSUTF8StringEncoding) as? String {
|
||||
dispatch_async(this.parseQueue) {[weak this] in
|
||||
this?.parsePollingMessage(str)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.waitingForPoll = false
|
||||
|
||||
|
||||
if this.fastUpgrade {
|
||||
this.doFastUpgrade()
|
||||
} else if !this.closed && this.polling {
|
||||
@ -286,25 +270,25 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
|
||||
}
|
||||
}}.resume()
|
||||
}
|
||||
|
||||
|
||||
private func flushProbeWait() {
|
||||
SocketLogger.log("Flushing probe wait", client: self)
|
||||
|
||||
|
||||
dispatch_async(emitQueue) {[weak self] in
|
||||
if let this = self {
|
||||
for waiter in this.probeWait {
|
||||
this.write(waiter.msg, withType: waiter.type, withData: waiter.data)
|
||||
}
|
||||
|
||||
|
||||
this.probeWait.removeAll(keepCapacity: false)
|
||||
|
||||
|
||||
if this.postWait.count != 0 {
|
||||
this.flushWaitingForPostToWebSocket()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func flushWaitingForPost() {
|
||||
if postWait.count == 0 || !connected {
|
||||
return
|
||||
@ -312,49 +296,49 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
|
||||
flushWaitingForPostToWebSocket()
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
var postStr = ""
|
||||
|
||||
|
||||
for packet in postWait {
|
||||
let len = count(packet)
|
||||
|
||||
let len = packet.characters.count
|
||||
|
||||
postStr += "\(len):\(packet)"
|
||||
}
|
||||
|
||||
|
||||
postWait.removeAll(keepCapacity: false)
|
||||
|
||||
|
||||
let req = NSMutableURLRequest(URL: NSURL(string: urlPolling! + "&sid=\(sid)")!)
|
||||
|
||||
if cookies != nil {
|
||||
let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies!)
|
||||
|
||||
if let cookies = cookies {
|
||||
let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies)
|
||||
req.allHTTPHeaderFields = headers
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
SocketLogger.log("POSTing: %@", client: self, args: postStr)
|
||||
|
||||
|
||||
session.dataTaskWithRequest(req) {[weak self] data, res, err in
|
||||
if let this = self {
|
||||
if err != nil && this.polling {
|
||||
this.handlePollingFailed(err.localizedDescription)
|
||||
this.handlePollingFailed(err?.localizedDescription ?? "Error")
|
||||
return
|
||||
} else if err != nil {
|
||||
NSLog(err.localizedDescription)
|
||||
NSLog(err?.localizedDescription ?? "Error")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
this.waitingForPost = false
|
||||
|
||||
|
||||
dispatch_async(this.emitQueue) {[weak this] in
|
||||
if !(this?.fastUpgrade ?? true) {
|
||||
this?.flushWaitingForPost()
|
||||
@ -363,253 +347,250 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
|
||||
}
|
||||
}}.resume()
|
||||
}
|
||||
|
||||
|
||||
// We had packets waiting for send when we upgraded
|
||||
// Send them raw
|
||||
private func flushWaitingForPostToWebSocket() {
|
||||
for msg in postWait {
|
||||
ws?.writeString(msg)
|
||||
}
|
||||
|
||||
|
||||
postWait.removeAll(keepCapacity: true)
|
||||
}
|
||||
|
||||
|
||||
private func handleClose() {
|
||||
if polling {
|
||||
client?.engineDidClose("Disconnect")
|
||||
if let client = client where polling == true {
|
||||
client.engineDidClose("Disconnect")
|
||||
}
|
||||
}
|
||||
|
||||
private func checkIfMessageIsBase64Binary(var message:String) {
|
||||
|
||||
private func checkIfMessageIsBase64Binary(var message: String) {
|
||||
if message.hasPrefix("b4") {
|
||||
// binary in base64 string
|
||||
message.removeRange(Range<String.Index>(start: message.startIndex,
|
||||
end: advance(message.startIndex, 2)))
|
||||
|
||||
end: message.startIndex.advancedBy(2)))
|
||||
|
||||
if let data = NSData(base64EncodedString: message,
|
||||
options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters), client = client {
|
||||
dispatch_async(client.handleQueue) {[weak self] in
|
||||
self?.client?.parseBinaryData(data)
|
||||
}
|
||||
options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters) {
|
||||
client?.parseBinaryData(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func handleMessage(message:String) {
|
||||
if let client = client {
|
||||
dispatch_async(client.handleQueue) {[weak client] in
|
||||
client?.parseSocketMessage(message)
|
||||
}
|
||||
}
|
||||
|
||||
private func handleMessage(message: String) {
|
||||
client?.parseSocketMessage(message)
|
||||
}
|
||||
|
||||
|
||||
private func handleNOOP() {
|
||||
doPoll()
|
||||
}
|
||||
|
||||
private func handleOpen(openData:String) {
|
||||
var err:NSError?
|
||||
|
||||
private func handleOpen(openData: String) {
|
||||
let mesData = openData.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
|
||||
|
||||
if let json = NSJSONSerialization.JSONObjectWithData(mesData,
|
||||
options: NSJSONReadingOptions.AllowFragments,
|
||||
error: &err) as? NSDictionary, sid = json["sid"] as? String {
|
||||
do {
|
||||
let json = try NSJSONSerialization.JSONObjectWithData(mesData,
|
||||
options: NSJSONReadingOptions.AllowFragments) as? NSDictionary
|
||||
if let sid = json?["sid"] as? String {
|
||||
let upgradeWs: Bool
|
||||
|
||||
self.sid = sid
|
||||
_connected = true
|
||||
connected = true
|
||||
|
||||
if !forcePolling && !forceWebsockets {
|
||||
createWebsocket(andConnect: true)
|
||||
if let upgrades = json?["upgrades"] as? [String] {
|
||||
upgradeWs = upgrades.filter {$0 == "websocket"}.count != 0
|
||||
} else {
|
||||
upgradeWs = false
|
||||
}
|
||||
|
||||
if let pingInterval = json["pingInterval"] as? Double, pingTimeout = json["pingTimeout"] as? Double {
|
||||
if let pingInterval = json?["pingInterval"] as? Double, pingTimeout = json?["pingTimeout"] as? Double {
|
||||
self.pingInterval = pingInterval / 1000.0
|
||||
self.pingTimeout = pingTimeout / 1000.0
|
||||
}
|
||||
} else {
|
||||
client?.didError("Engine failed to handshake")
|
||||
|
||||
if !forcePolling && !forceWebsockets && upgradeWs {
|
||||
createWebsocket(andConnect: true)
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
SocketLogger.err("Error parsing open packet", client: self)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
startPingTimer()
|
||||
|
||||
|
||||
if !forceWebsockets {
|
||||
doPoll()
|
||||
}
|
||||
}
|
||||
|
||||
private func handlePong(pongMessage:String) {
|
||||
|
||||
private func handlePong(pongMessage: String) {
|
||||
pongsMissed = 0
|
||||
|
||||
|
||||
// We should upgrade
|
||||
if pongMessage == "3probe" {
|
||||
upgradeTransport()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// A poll failed, tell the client about it
|
||||
private func handlePollingFailed(reason:String) {
|
||||
_connected = false
|
||||
private func handlePollingFailed(reason: String) {
|
||||
connected = false
|
||||
ws?.disconnect()
|
||||
pingTimer?.invalidate()
|
||||
waitingForPoll = false
|
||||
waitingForPost = false
|
||||
|
||||
|
||||
// If cancelled we were already closing
|
||||
if client == nil || reason == "cancelled" {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if !closed {
|
||||
client?.didError(reason)
|
||||
client?.engineDidClose(reason)
|
||||
}
|
||||
}
|
||||
|
||||
public func open(opts:[String: AnyObject]? = nil) {
|
||||
|
||||
public func open(opts: [String: AnyObject]? = nil) {
|
||||
if connected {
|
||||
SocketLogger.err("Tried to open while connected", client: self)
|
||||
|
||||
client?.didError("Tried to open while connected")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
SocketLogger.log("Starting engine", client: self)
|
||||
SocketLogger.log("Handshaking", client: self)
|
||||
|
||||
|
||||
closed = false
|
||||
|
||||
|
||||
(urlPolling, urlWebSocket) = createURLs(opts)
|
||||
|
||||
|
||||
if forceWebsockets {
|
||||
_polling = false
|
||||
_websocket = true
|
||||
polling = false
|
||||
websocket = true
|
||||
createWebsocket(andConnect: true)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
let reqPolling = NSMutableURLRequest(URL: NSURL(string: urlPolling! + "&b64=1")!)
|
||||
|
||||
|
||||
if cookies != nil {
|
||||
let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies!)
|
||||
reqPolling.allHTTPHeaderFields = headers
|
||||
}
|
||||
|
||||
if extraHeaders != nil {
|
||||
for (headerName, value) in extraHeaders! {
|
||||
|
||||
if let extraHeaders = extraHeaders {
|
||||
for (headerName, value) in extraHeaders {
|
||||
reqPolling.setValue(value, forHTTPHeaderField: headerName)
|
||||
}
|
||||
}
|
||||
|
||||
doRequest(reqPolling)
|
||||
}
|
||||
|
||||
|
||||
// Translatation of engine.io-parser#decodePayload
|
||||
private func parsePollingMessage(str:String) {
|
||||
if count(str) == 1 {
|
||||
guard str.characters.count != 1 else {
|
||||
return
|
||||
}
|
||||
|
||||
// println(str)
|
||||
|
||||
let strArray = Array(str)
|
||||
|
||||
let strArray = Array(str.characters)
|
||||
var length = ""
|
||||
var n = 0
|
||||
var msg = ""
|
||||
|
||||
|
||||
func testLength(length:String, inout n:Int) -> Bool {
|
||||
if let num = length.toInt() {
|
||||
if let num = Int(length) {
|
||||
n = num
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
for var i = 0, l = count(str); i < l; i++ {
|
||||
|
||||
for var i = 0, l = str.characters.count; i < l; i++ {
|
||||
let chr = String(strArray[i])
|
||||
|
||||
|
||||
if chr != ":" {
|
||||
length += chr
|
||||
} else {
|
||||
if length == "" || testLength(length, &n) {
|
||||
if length == "" || testLength(length, n: &n) {
|
||||
SocketLogger.err("Parsing error: %@", client: self, args: str)
|
||||
handlePollingFailed("Error parsing XHR message")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
msg = String(strArray[i+1...i+n])
|
||||
|
||||
if let lengthInt = length.toInt() where lengthInt != count(msg) {
|
||||
|
||||
if let lengthInt = Int(length) where lengthInt != msg.characters.count {
|
||||
SocketLogger.err("Parsing error: %@", client: self, args: str)
|
||||
return
|
||||
}
|
||||
|
||||
if count(msg) != 0 {
|
||||
|
||||
if msg.characters.count != 0 {
|
||||
// Be sure to capture the value of the msg
|
||||
dispatch_async(handleQueue) {[weak self, msg] in
|
||||
self?.parseEngineMessage(msg, fromPolling: true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
i += n
|
||||
length = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func parseEngineData(data:NSData) {
|
||||
if let client = client {
|
||||
dispatch_async(client.handleQueue) {[weak self] in
|
||||
self?.client?.parseBinaryData(data.subdataWithRange(NSMakeRange(1, data.length - 1)))
|
||||
}
|
||||
}
|
||||
|
||||
private func parseEngineData(data: NSData) {
|
||||
client?.parseBinaryData(data.subdataWithRange(NSMakeRange(1, data.length - 1)))
|
||||
}
|
||||
|
||||
private func parseEngineMessage(var message:String, fromPolling:Bool) {
|
||||
|
||||
private func parseEngineMessage(var message: String, fromPolling: Bool) {
|
||||
SocketLogger.log("Got message: %@", client: self, args: message)
|
||||
|
||||
|
||||
if fromPolling {
|
||||
fixDoubleUTF8(&message)
|
||||
}
|
||||
|
||||
|
||||
let type = PacketType(str: (message["^(\\d)"].groups()?[1])) ?? {
|
||||
self.checkIfMessageIsBase64Binary(message)
|
||||
return PacketType.NOOP
|
||||
}()
|
||||
|
||||
return PacketType.Noop
|
||||
}()
|
||||
|
||||
switch type {
|
||||
case PacketType.MESSAGE:
|
||||
case PacketType.Message:
|
||||
message.removeAtIndex(message.startIndex)
|
||||
handleMessage(message)
|
||||
case PacketType.NOOP:
|
||||
case PacketType.Noop:
|
||||
handleNOOP()
|
||||
case PacketType.PONG:
|
||||
case PacketType.Pong:
|
||||
handlePong(message)
|
||||
case PacketType.OPEN:
|
||||
case PacketType.Open:
|
||||
message.removeAtIndex(message.startIndex)
|
||||
handleOpen(message)
|
||||
case PacketType.CLOSE:
|
||||
case PacketType.Close:
|
||||
handleClose()
|
||||
default:
|
||||
SocketLogger.log("Got unknown packet type", client: self)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func probeWebSocket() {
|
||||
if websocketConnected {
|
||||
sendWebSocketMessage("probe", withType: PacketType.PING)
|
||||
sendWebSocketMessage("probe", withType: PacketType.Ping)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Send an engine message (4)
|
||||
public func send(msg:String, withData datas:ContiguousArray<NSData>?) {
|
||||
public func send(msg: String, withData datas: [NSData]?) {
|
||||
if probing {
|
||||
probeWait.append((msg, PacketType.MESSAGE, datas))
|
||||
probeWait.append((msg, PacketType.Message, datas))
|
||||
} else {
|
||||
write(msg, withType: PacketType.MESSAGE, withData: datas)
|
||||
write(msg, withType: PacketType.Message, withData: datas)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@objc private func sendPing() {
|
||||
//Server is not responding
|
||||
if pongsMissed > pongsMissedMax {
|
||||
@ -617,59 +598,59 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
|
||||
client?.engineDidClose("Ping timeout")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
++pongsMissed
|
||||
write("", withType: PacketType.PING, withData: nil)
|
||||
write("", withType: PacketType.Ping, withData: nil)
|
||||
}
|
||||
|
||||
|
||||
/// Send polling message.
|
||||
/// Only call on emitQueue
|
||||
private func sendPollMessage(var msg:String, withType type:PacketType,
|
||||
datas:ContiguousArray<NSData>? = nil) {
|
||||
private func sendPollMessage(var msg: String, withType type: PacketType,
|
||||
datas:[NSData]? = nil) {
|
||||
SocketLogger.log("Sending poll: %@ as type: %@", client: self, args: msg, type.rawValue)
|
||||
|
||||
|
||||
doubleEncodeUTF8(&msg)
|
||||
let strMsg = "\(type.rawValue)\(msg)"
|
||||
|
||||
|
||||
postWait.append(strMsg)
|
||||
|
||||
if datas != nil {
|
||||
for data in datas! {
|
||||
let (nilData, b64Data) = createBinaryDataForSend(data)
|
||||
|
||||
|
||||
if let datas = datas {
|
||||
for data in datas {
|
||||
let (_, b64Data) = createBinaryDataForSend(data)
|
||||
|
||||
postWait.append(b64Data!)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if !waitingForPost {
|
||||
flushWaitingForPost()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Send message on WebSockets
|
||||
/// Only call on emitQueue
|
||||
private func sendWebSocketMessage(str:String, withType type:PacketType,
|
||||
datas:ContiguousArray<NSData>? = nil) {
|
||||
private func sendWebSocketMessage(str: String, withType type: PacketType,
|
||||
datas:[NSData]? = nil) {
|
||||
SocketLogger.log("Sending ws: %@ as type: %@", client: self, args: str, type.rawValue)
|
||||
|
||||
|
||||
ws?.writeString("\(type.rawValue)\(str)")
|
||||
|
||||
if datas != nil {
|
||||
for data in datas! {
|
||||
let (data, nilString) = createBinaryDataForSend(data)
|
||||
|
||||
if let datas = datas {
|
||||
for data in datas {
|
||||
let (data, _) = createBinaryDataForSend(data)
|
||||
if data != nil {
|
||||
ws?.writeData(data!)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Starts the ping timer
|
||||
private func startPingTimer() {
|
||||
if pingInterval == nil {
|
||||
guard pingInterval != nil else {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
pingTimer?.invalidate()
|
||||
dispatch_async(dispatch_get_main_queue()) {[weak self] in
|
||||
if let this = self {
|
||||
@ -678,25 +659,25 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func stopPolling() {
|
||||
session.invalidateAndCancel()
|
||||
}
|
||||
|
||||
|
||||
private func upgradeTransport() {
|
||||
if websocketConnected {
|
||||
SocketLogger.log("Upgrading transport to WebSockets", client: self)
|
||||
|
||||
|
||||
fastUpgrade = true
|
||||
sendPollMessage("", withType: PacketType.NOOP)
|
||||
sendPollMessage("", withType: PacketType.Noop)
|
||||
// After this point, we should not send anymore polling messages
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Write a message, independent of transport.
|
||||
*/
|
||||
public func write(msg:String, withType type:PacketType, withData data:ContiguousArray<NSData>?) {
|
||||
public func write(msg: String, withType type: PacketType, withData data: [NSData]?) {
|
||||
dispatch_async(emitQueue) {[weak self] in
|
||||
if let this = self where this.connected {
|
||||
if this.websocket {
|
||||
@ -711,55 +692,55 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Write a message, independent of transport. For Objective-C. withData should be an NSArray of NSData
|
||||
*/
|
||||
public func writeObjc(msg:String, withType type:Int, withData data:NSArray?) {
|
||||
public func writeObjc(msg: String, withType type: Int, withData data: NSArray?) {
|
||||
if let pType = PacketType(rawValue: type) {
|
||||
var arr = ContiguousArray<NSData>()
|
||||
|
||||
if data != nil {
|
||||
for d in data! {
|
||||
var arr = [NSData]()
|
||||
|
||||
if let data = data {
|
||||
for d in data {
|
||||
arr.append(d as! NSData)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
write(msg, withType: pType, withData: arr)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Delagate methods
|
||||
|
||||
|
||||
public func websocketDidConnect(socket:WebSocket) {
|
||||
websocketConnected = true
|
||||
|
||||
|
||||
if !forceWebsockets {
|
||||
probing = true
|
||||
probeWebSocket()
|
||||
} else {
|
||||
_connected = true
|
||||
connected = true
|
||||
probing = false
|
||||
_polling = false
|
||||
polling = false
|
||||
}
|
||||
}
|
||||
|
||||
public func websocketDidDisconnect(socket:WebSocket, error:NSError?) {
|
||||
|
||||
public func websocketDidDisconnect(socket: WebSocket, error: NSError?) {
|
||||
websocketConnected = false
|
||||
probing = false
|
||||
|
||||
|
||||
if closed {
|
||||
client?.engineDidClose("Disconnect")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if websocket {
|
||||
pingTimer?.invalidate()
|
||||
_connected = false
|
||||
_websocket = false
|
||||
|
||||
connected = false
|
||||
websocket = false
|
||||
|
||||
let reason = error?.localizedDescription ?? "Socket Disconnected"
|
||||
|
||||
|
||||
if error != nil {
|
||||
client?.didError(reason)
|
||||
}
|
||||
@ -769,12 +750,12 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
|
||||
flushProbeWait()
|
||||
}
|
||||
}
|
||||
|
||||
public func websocketDidReceiveMessage(socket:WebSocket, text:String) {
|
||||
|
||||
public func websocketDidReceiveMessage(socket: WebSocket, text: String) {
|
||||
parseEngineMessage(text, fromPolling: false)
|
||||
}
|
||||
|
||||
public func websocketDidReceiveData(socket:WebSocket, data:NSData) {
|
||||
|
||||
public func websocketDidReceiveData(socket: WebSocket, data: NSData) {
|
||||
parseEngineData(data)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
//
|
||||
// SocketEngineClient.swift
|
||||
// Socket.IO-Swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 3/19/15.
|
||||
//
|
||||
@ -26,12 +26,11 @@
|
||||
import Foundation
|
||||
|
||||
@objc public protocol SocketEngineClient {
|
||||
var handleQueue:dispatch_queue_attr_t! {get}
|
||||
var socketURL:String {get}
|
||||
var secure:Bool {get}
|
||||
var socketURL: String {get}
|
||||
var secure: Bool {get}
|
||||
|
||||
func didError(reason:AnyObject)
|
||||
func engineDidClose(reason:String)
|
||||
func parseSocketMessage(msg:String)
|
||||
func parseBinaryData(data:NSData)
|
||||
func didError(reason: AnyObject)
|
||||
func engineDidClose(reason: String)
|
||||
func parseSocketMessage(msg: String)
|
||||
func parseBinaryData(data: NSData)
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
//
|
||||
// EventHandler.swift
|
||||
// Socket.IO-Swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 1/18/15.
|
||||
//
|
||||
@ -24,24 +24,37 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
private func emitAckCallback(socket:SocketIOClient, num:Int)
|
||||
(items:AnyObject...) -> Void {
|
||||
socket.emitAck(num, withData: items)
|
||||
private func emitAckCallback(socket: SocketIOClient?, num: Int?)
|
||||
(items: AnyObject...) -> Void {
|
||||
socket?.emitAck(num ?? -1, withItems: items)
|
||||
}
|
||||
|
||||
final class SocketEventHandler {
|
||||
let event:String!
|
||||
let callback:NormalCallback?
|
||||
private func emitAckCallbackObjectiveC(socket: SocketIOClient?, num: Int?)
|
||||
(items: NSArray) -> Void {
|
||||
socket?.emitAck(num ?? -1, withItems: items as [AnyObject])
|
||||
}
|
||||
|
||||
struct SocketEventHandler {
|
||||
let event: String
|
||||
let callback: NormalCallback?
|
||||
let callBackObjectiveC: NormalCallbackObjectiveC?
|
||||
|
||||
init(event:String, callback:NormalCallback) {
|
||||
init(event: String, callback: NormalCallback) {
|
||||
self.event = event
|
||||
self.callback = callback
|
||||
self.callBackObjectiveC = nil
|
||||
}
|
||||
|
||||
func executeCallback(_ items:NSArray? = nil, withAck ack:Int? = nil, withAckType type:Int? = nil,
|
||||
init(event: String, callback: NormalCallbackObjectiveC) {
|
||||
self.event = event
|
||||
self.callback = nil
|
||||
self.callBackObjectiveC = callback
|
||||
}
|
||||
|
||||
func executeCallback(items:NSArray? = nil, withAck ack:Int? = nil, withAckType type:Int? = nil,
|
||||
withSocket socket:SocketIOClient? = nil) {
|
||||
dispatch_async(dispatch_get_main_queue()) {[weak self] in
|
||||
self?.callback?(items, ack != nil ? emitAckCallback(socket!, ack!) : nil)
|
||||
}
|
||||
self.callback != nil ?
|
||||
self.callback?(items, emitAckCallback(socket, num: ack))
|
||||
: self.callBackObjectiveC?(items, emitAckCallbackObjectiveC(socket, num: ack))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
//
|
||||
// SocketFixUTF8.swift
|
||||
// Socket.IO-Swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 3/16/15.
|
||||
//
|
||||
@ -25,13 +25,13 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
func fixDoubleUTF8(inout name:String) {
|
||||
func fixDoubleUTF8(inout name: String) {
|
||||
let utf8 = name.dataUsingEncoding(NSISOLatin1StringEncoding)!
|
||||
let latin1 = NSString(data: utf8, encoding: NSUTF8StringEncoding)!
|
||||
name = latin1 as String
|
||||
}
|
||||
|
||||
func doubleEncodeUTF8(inout str:String) {
|
||||
func doubleEncodeUTF8(inout str: String) {
|
||||
let latin1 = str.dataUsingEncoding(NSUTF8StringEncoding)!
|
||||
let utf8 = NSString(data: latin1, encoding: NSISOLatin1StringEncoding)!
|
||||
str = utf8 as String
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
//
|
||||
// SocketIOClient.swift
|
||||
// Socket.IO-Swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 11/23/14.
|
||||
//
|
||||
@ -25,59 +25,40 @@
|
||||
import Foundation
|
||||
|
||||
public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient {
|
||||
private var anyHandler:((SocketAnyEvent) -> Void)?
|
||||
private var _closed = false
|
||||
private var _connected = false
|
||||
private var _connecting = false
|
||||
private var anyHandler: ((SocketAnyEvent) -> Void)?
|
||||
private var currentReconnectAttempt = 0
|
||||
private var handlers = ContiguousArray<SocketEventHandler>()
|
||||
private var connectParams:[String: AnyObject]?
|
||||
private var _secure = false
|
||||
private var _reconnecting = false
|
||||
private var reconnectTimer:NSTimer?
|
||||
private var connectParams: [String: AnyObject]?
|
||||
private var reconnectTimer: NSTimer?
|
||||
|
||||
let reconnectAttempts:Int!
|
||||
let reconnectAttempts: Int!
|
||||
let logType = "SocketClient"
|
||||
var ackHandlers = SocketAckManager()
|
||||
var currentAck = -1
|
||||
var log = false
|
||||
var waitingData = ContiguousArray<SocketPacket>()
|
||||
var sessionDelegate:NSURLSessionDelegate?
|
||||
var waitingData = [SocketPacket]()
|
||||
|
||||
public let socketURL:String
|
||||
public let handleAckQueue = dispatch_queue_create("handleAckQueue", DISPATCH_QUEUE_SERIAL)
|
||||
public let handleQueue = dispatch_queue_create("handleQueue", DISPATCH_QUEUE_SERIAL)
|
||||
public let emitQueue = dispatch_queue_create("emitQueue", DISPATCH_QUEUE_SERIAL)
|
||||
public var closed:Bool {
|
||||
return _closed
|
||||
}
|
||||
public var connected:Bool {
|
||||
return _connected
|
||||
}
|
||||
public var connecting:Bool {
|
||||
return _connecting
|
||||
}
|
||||
public var engine:SocketEngine?
|
||||
public let handleQueue: dispatch_queue_t!
|
||||
public let socketURL: String
|
||||
|
||||
public private(set) var engine: SocketEngine?
|
||||
public private(set) var secure = false
|
||||
public private(set) var status = SocketIOClientStatus.NotConnected
|
||||
|
||||
public var nsp = "/"
|
||||
public var opts:[String: AnyObject]?
|
||||
public var opts: [String: AnyObject]?
|
||||
public var reconnects = true
|
||||
public var reconnecting:Bool {
|
||||
return _reconnecting
|
||||
}
|
||||
public var reconnectWait = 10
|
||||
public var secure:Bool {
|
||||
return _secure
|
||||
}
|
||||
public var sid:String? {
|
||||
public var sid: String? {
|
||||
return engine?.sid
|
||||
}
|
||||
|
||||
/**
|
||||
Create a new SocketIOClient. opts can be omitted
|
||||
*/
|
||||
public init(var socketURL:String, opts:[String: AnyObject]? = nil) {
|
||||
public init(var socketURL: String, opts: [String: AnyObject]? = nil) {
|
||||
if socketURL["https://"].matches().count != 0 {
|
||||
self._secure = true
|
||||
self.secure = true
|
||||
}
|
||||
|
||||
socketURL = socketURL["http://"] ~= ""
|
||||
@ -86,24 +67,15 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
|
||||
self.socketURL = socketURL
|
||||
self.opts = opts
|
||||
|
||||
// Set options
|
||||
if let sessionDelegate = opts?["sessionDelegate"] as? NSURLSessionDelegate {
|
||||
self.sessionDelegate = sessionDelegate
|
||||
}
|
||||
|
||||
if let connectParams = opts?["connectParams"] as? [String: AnyObject] {
|
||||
self.connectParams = connectParams
|
||||
}
|
||||
|
||||
if let log = opts?["log"] as? Bool {
|
||||
self.log = log
|
||||
SocketLogger.log = log
|
||||
}
|
||||
|
||||
if var nsp = opts?["nsp"] as? String {
|
||||
if nsp != "/" && nsp.hasPrefix("/") {
|
||||
nsp.removeAtIndex(nsp.startIndex)
|
||||
}
|
||||
|
||||
if let nsp = opts?["nsp"] as? String {
|
||||
self.nsp = nsp
|
||||
}
|
||||
|
||||
@ -121,13 +93,15 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
|
||||
self.reconnectWait = abs(reconnectWait)
|
||||
}
|
||||
|
||||
if let handleQueue = opts?["handleQueue"] as? dispatch_queue_t {
|
||||
self.handleQueue = handleQueue
|
||||
} else {
|
||||
self.handleQueue = dispatch_get_main_queue()
|
||||
}
|
||||
|
||||
super.init()
|
||||
}
|
||||
|
||||
public convenience init(socketURL:String, options:[String: AnyObject]?) {
|
||||
self.init(socketURL: socketURL, opts: options)
|
||||
}
|
||||
|
||||
deinit {
|
||||
SocketLogger.log("Client is being deinit", client: self)
|
||||
engine?.close(fast: true)
|
||||
@ -149,15 +123,12 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
|
||||
Will turn off automatic reconnects.
|
||||
Pass true to fast if you're closing from a background task
|
||||
*/
|
||||
public func close(#fast:Bool) {
|
||||
public func close(fast fast: Bool) {
|
||||
SocketLogger.log("Closing socket", client: self)
|
||||
|
||||
reconnects = false
|
||||
_connecting = false
|
||||
_connected = false
|
||||
_reconnecting = false
|
||||
status = SocketIOClientStatus.Closed
|
||||
engine?.close(fast: fast)
|
||||
engine = nil
|
||||
}
|
||||
|
||||
/**
|
||||
@ -170,42 +141,42 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
|
||||
/**
|
||||
Connect to the server. If we aren't connected after timeoutAfter, call handler
|
||||
*/
|
||||
public func connect(#timeoutAfter:Int, withTimeoutHandler handler:(() -> Void)?) {
|
||||
if closed {
|
||||
SocketLogger.log("Warning! This socket was previously closed. This might be dangerous!", client: self)
|
||||
_closed = false
|
||||
} else if connected {
|
||||
return
|
||||
}
|
||||
|
||||
_connecting = true
|
||||
addEngine()
|
||||
engine?.open(opts: connectParams)
|
||||
|
||||
if timeoutAfter == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(timeoutAfter) * Int64(NSEC_PER_SEC))
|
||||
|
||||
dispatch_after(time, dispatch_get_main_queue()) {[weak self] in
|
||||
if let this = self where !this.connected {
|
||||
this._closed = true
|
||||
this._connecting = false
|
||||
this.engine?.close(fast: true)
|
||||
|
||||
handler?()
|
||||
public func connect(timeoutAfter timeoutAfter:Int,
|
||||
withTimeoutHandler handler:(() -> Void)?) {
|
||||
guard status != SocketIOClientStatus.Connected else {
|
||||
return
|
||||
}
|
||||
if status == SocketIOClientStatus.Closed {
|
||||
SocketLogger.log("Warning! This socket was previously closed. This might be dangerous!", client: self)
|
||||
}
|
||||
|
||||
status = SocketIOClientStatus.Connecting
|
||||
addEngine()
|
||||
engine?.open(connectParams)
|
||||
|
||||
guard timeoutAfter != 0 else {
|
||||
return
|
||||
}
|
||||
|
||||
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(timeoutAfter) * Int64(NSEC_PER_SEC))
|
||||
|
||||
dispatch_after(time, dispatch_get_main_queue()) {[weak self] in
|
||||
if let this = self where this.status != SocketIOClientStatus.Connected {
|
||||
this.status = SocketIOClientStatus.Closed
|
||||
this.engine?.close(fast: true)
|
||||
|
||||
handler?()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func createOnAck(event:String, items:[AnyObject]) -> OnAckCallback {
|
||||
private func createOnAck(items: [AnyObject]) -> OnAckCallback {
|
||||
return {[weak self, ack = ++currentAck] timeout, callback in
|
||||
if let this = self {
|
||||
this.ackHandlers.addAck(ack, callback: callback)
|
||||
|
||||
dispatch_async(this.emitQueue) {[weak this] in
|
||||
this?._emit(event, items, ack: ack)
|
||||
this?._emit(items, ack: ack)
|
||||
}
|
||||
|
||||
if timeout != 0 {
|
||||
@ -221,11 +192,7 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
|
||||
|
||||
func didConnect() {
|
||||
SocketLogger.log("Socket connected", client: self)
|
||||
|
||||
_closed = false
|
||||
_connected = true
|
||||
_connecting = false
|
||||
_reconnecting = false
|
||||
status = SocketIOClientStatus.Connected
|
||||
currentReconnectAttempt = 0
|
||||
clearReconnectTimer()
|
||||
|
||||
@ -234,18 +201,16 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
|
||||
handleEvent("connect", data: nil, isInternalMessage: false)
|
||||
}
|
||||
|
||||
func didDisconnect(reason:String) {
|
||||
if closed {
|
||||
func didDisconnect(reason: String) {
|
||||
guard status != SocketIOClientStatus.Closed else {
|
||||
return
|
||||
}
|
||||
|
||||
SocketLogger.log("Disconnected: %@", client: self, args: reason)
|
||||
|
||||
_closed = true
|
||||
_connected = false
|
||||
status = SocketIOClientStatus.Closed
|
||||
|
||||
reconnects = false
|
||||
_connecting = false
|
||||
_reconnecting = false
|
||||
|
||||
// Make sure the engine is actually dead.
|
||||
engine?.close(fast: true)
|
||||
@ -253,7 +218,7 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
|
||||
}
|
||||
|
||||
/// error
|
||||
public func didError(reason:AnyObject) {
|
||||
public func didError(reason: AnyObject) {
|
||||
SocketLogger.err("%@", client: self, args: reason)
|
||||
|
||||
handleEvent("error", data: reason as? [AnyObject] ?? [reason],
|
||||
@ -263,33 +228,27 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
|
||||
/**
|
||||
Same as close
|
||||
*/
|
||||
public func disconnect(#fast:Bool) {
|
||||
public func disconnect(fast fast: Bool) {
|
||||
close(fast: fast)
|
||||
}
|
||||
|
||||
/**
|
||||
Send a message to the server
|
||||
*/
|
||||
public func emit(event:String, _ items:AnyObject...) {
|
||||
if !connected {
|
||||
return
|
||||
}
|
||||
|
||||
dispatch_async(emitQueue) {[weak self] in
|
||||
self?._emit(event, items)
|
||||
}
|
||||
public func emit(event: String, _ items: AnyObject...) {
|
||||
emit(event, withItems: items)
|
||||
}
|
||||
|
||||
/**
|
||||
Same as emit, but meant for Objective-C
|
||||
*/
|
||||
public func emit(event:String, withItems items:[AnyObject]) {
|
||||
if !connected {
|
||||
public func emit(event: String, withItems items: [AnyObject]) {
|
||||
guard status == SocketIOClientStatus.Connected else {
|
||||
return
|
||||
}
|
||||
|
||||
dispatch_async(emitQueue) {[weak self] in
|
||||
self?._emit(event, items)
|
||||
self?._emit([event] + items)
|
||||
}
|
||||
}
|
||||
|
||||
@ -297,39 +256,28 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
|
||||
Sends a message to the server, requesting an ack. Use the onAck method of SocketAckHandler to add
|
||||
an ack.
|
||||
*/
|
||||
public func emitWithAck(event:String, _ items:AnyObject...) -> OnAckCallback {
|
||||
if !connected {
|
||||
return createOnAck(event, items: items)
|
||||
}
|
||||
|
||||
return createOnAck(event, items: items)
|
||||
public func emitWithAck(event: String, _ items: AnyObject...) -> OnAckCallback {
|
||||
return emitWithAck(event, withItems: items)
|
||||
}
|
||||
|
||||
/**
|
||||
Same as emitWithAck, but for Objective-C
|
||||
*/
|
||||
public func emitWithAck(event:String, withItems items:[AnyObject]) -> OnAckCallback {
|
||||
if !connected {
|
||||
return createOnAck(event, items: items)
|
||||
}
|
||||
|
||||
return createOnAck(event, items: items)
|
||||
public func emitWithAck(event: String, withItems items: [AnyObject]) -> OnAckCallback {
|
||||
return createOnAck([event] + items)
|
||||
}
|
||||
|
||||
private func _emit(event:String, _ args:[AnyObject], ack:Int? = nil) {
|
||||
if !connected {
|
||||
private func _emit(data: [AnyObject], ack: Int? = nil) {
|
||||
guard status == SocketIOClientStatus.Connected else {
|
||||
return
|
||||
}
|
||||
|
||||
let packet = SocketPacket(type: nil, data: args, nsp: nsp, id: ack)
|
||||
let str:String
|
||||
|
||||
SocketParser.parseForEmit(packet)
|
||||
str = packet.createMessageForEvent(event)
|
||||
let packet = SocketPacket.packetFromEmit(data, id: ack ?? -1, nsp: nsp, ack: false)
|
||||
let str = packet.packetString
|
||||
|
||||
SocketLogger.log("Emitting: %@", client: self, args: str)
|
||||
|
||||
if packet.type == SocketPacket.PacketType.BINARY_EVENT {
|
||||
if packet.type == SocketPacket.PacketType.BinaryEvent {
|
||||
engine?.send(str, withData: packet.binary)
|
||||
} else {
|
||||
engine?.send(str, withData: nil)
|
||||
@ -337,18 +285,15 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
|
||||
}
|
||||
|
||||
// If the server wants to know that the client received data
|
||||
func emitAck(ack:Int, withData args:[AnyObject]) {
|
||||
func emitAck(ack: Int, withItems items: [AnyObject]) {
|
||||
dispatch_async(emitQueue) {[weak self] in
|
||||
if let this = self where this.connected {
|
||||
let packet = SocketPacket(type: nil, data: args, nsp: this.nsp, id: ack)
|
||||
let str:String
|
||||
|
||||
SocketParser.parseForEmit(packet)
|
||||
str = packet.createAck()
|
||||
if let this = self where this.status == SocketIOClientStatus.Connected {
|
||||
let packet = SocketPacket.packetFromEmit(items, id: ack ?? -1, nsp: this.nsp, ack: true)
|
||||
let str = packet.packetString
|
||||
|
||||
SocketLogger.log("Emitting Ack: %@", client: this, args: str)
|
||||
|
||||
if packet.type == SocketPacket.PacketType.BINARY_ACK {
|
||||
if packet.type == SocketPacket.PacketType.BinaryAck {
|
||||
this.engine?.send(str, withData: packet.binary)
|
||||
} else {
|
||||
this.engine?.send(str, withData: nil)
|
||||
@ -358,20 +303,20 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
|
||||
}
|
||||
}
|
||||
|
||||
public func engineDidClose(reason:String) {
|
||||
_connected = false
|
||||
_connecting = false
|
||||
public func engineDidClose(reason: String) {
|
||||
waitingData.removeAll()
|
||||
|
||||
if closed || !reconnects {
|
||||
if status == SocketIOClientStatus.Closed || !reconnects {
|
||||
didDisconnect(reason)
|
||||
} else if !reconnecting {
|
||||
} else if status != SocketIOClientStatus.Reconnecting {
|
||||
status = SocketIOClientStatus.Reconnecting
|
||||
handleEvent("reconnect", data: [reason], isInternalMessage: true)
|
||||
tryReconnect()
|
||||
}
|
||||
}
|
||||
|
||||
// Called when the socket gets an ack for something it sent
|
||||
func handleAck(ack:Int, data:AnyObject?) {
|
||||
func handleAck(ack: Int, data: AnyObject?) {
|
||||
SocketLogger.log("Handling ack: %@ with data: %@", client: self,
|
||||
args: ack, data ?? "")
|
||||
|
||||
@ -382,27 +327,29 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
|
||||
/**
|
||||
Causes an event to be handled. Only use if you know what you're doing.
|
||||
*/
|
||||
public func handleEvent(event:String, data:[AnyObject]?, isInternalMessage:Bool = false,
|
||||
wantsAck ack:Int? = nil) {
|
||||
// println("Should do event: \(event) with data: \(data)")
|
||||
if !connected && !isInternalMessage {
|
||||
public func handleEvent(event: String, data: [AnyObject]?, isInternalMessage: Bool,
|
||||
wantsAck ack: Int? = nil) {
|
||||
guard status == SocketIOClientStatus.Connected || isInternalMessage else {
|
||||
return
|
||||
}
|
||||
// println("Should do event: \(event) with data: \(data)")
|
||||
|
||||
SocketLogger.log("Handling event: %@ with data: %@", client: self,
|
||||
args: event, data ?? "")
|
||||
|
||||
if anyHandler != nil {
|
||||
dispatch_async(dispatch_get_main_queue()) {[weak self] in
|
||||
dispatch_async(handleQueue) {[weak self] in
|
||||
self?.anyHandler?(SocketAnyEvent(event: event, items: data))
|
||||
}
|
||||
}
|
||||
|
||||
for handler in handlers {
|
||||
if handler.event == event {
|
||||
if ack != nil {
|
||||
handler.executeCallback(data, withAck: ack!, withSocket: self)
|
||||
} else {
|
||||
for handler in handlers where handler.event == event {
|
||||
if let ack = ack {
|
||||
dispatch_async(handleQueue) {[weak self] in
|
||||
handler.executeCallback(data, withAck: ack, withSocket: self)
|
||||
}
|
||||
} else {
|
||||
dispatch_async(handleQueue) {
|
||||
handler.executeCallback(data)
|
||||
}
|
||||
}
|
||||
@ -414,7 +361,7 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
|
||||
*/
|
||||
public func leaveNamespace() {
|
||||
if nsp != "/" {
|
||||
engine?.send("1/\(nsp)", withData: nil)
|
||||
engine?.send("1\(nsp)", withData: nil)
|
||||
nsp = "/"
|
||||
}
|
||||
}
|
||||
@ -426,41 +373,59 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
|
||||
SocketLogger.log("Joining namespace", client: self)
|
||||
|
||||
if nsp != "/" {
|
||||
engine?.send("0/\(nsp)", withData: nil)
|
||||
engine?.send("0\(nsp)", withData: nil)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Joins namespace /
|
||||
*/
|
||||
public func joinNamespace(namespace: String) {
|
||||
self.nsp = namespace
|
||||
joinNamespace()
|
||||
}
|
||||
|
||||
/**
|
||||
Removes handler(s)
|
||||
*/
|
||||
public func off(event:String) {
|
||||
public func off(event: String) {
|
||||
SocketLogger.log("Removing handler for event: %@", client: self, args: event)
|
||||
|
||||
handlers = handlers.filter {$0.event == event ? false : true}
|
||||
handlers = ContiguousArray(handlers.filter {!($0.event == event)})
|
||||
}
|
||||
|
||||
/**
|
||||
Adds a handler for an event.
|
||||
*/
|
||||
public func on(event:String, callback:NormalCallback) {
|
||||
public func on(event: String, callback: NormalCallback) {
|
||||
SocketLogger.log("Adding handler for event: %@", client: self, args: event)
|
||||
|
||||
let handler = SocketEventHandler(event: event, callback: callback)
|
||||
handlers.append(handler)
|
||||
}
|
||||
|
||||
/**
|
||||
Removes all handlers.
|
||||
Can be used after disconnecting to break any potential remaining retain cycles.
|
||||
*/
|
||||
public func removeAllHandlers() {
|
||||
handlers.removeAll(keepCapacity: false)
|
||||
}
|
||||
|
||||
/**
|
||||
Adds a handler for an event.
|
||||
*/
|
||||
public func onObjectiveC(event: String, callback: NormalCallbackObjectiveC) {
|
||||
SocketLogger.log("Adding handler for event: %@", client: self, args: event)
|
||||
|
||||
let handler = SocketEventHandler(event: event, callback: callback)
|
||||
handlers.append(handler)
|
||||
}
|
||||
|
||||
/**
|
||||
Removes all handlers.
|
||||
Can be used after disconnecting to break any potential remaining retain cycles.
|
||||
*/
|
||||
public func removeAllHandlers() {
|
||||
handlers.removeAll(keepCapacity: false)
|
||||
}
|
||||
|
||||
/**
|
||||
Adds a handler that will be called on every event.
|
||||
*/
|
||||
public func onAny(handler:(SocketAnyEvent) -> Void) {
|
||||
public func onAny(handler: (SocketAnyEvent) -> Void) {
|
||||
anyHandler = handler
|
||||
}
|
||||
|
||||
@ -471,50 +436,58 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
|
||||
connect()
|
||||
}
|
||||
|
||||
public func parseSocketMessage(msg:String) {
|
||||
SocketParser.parseSocketMessage(msg, socket: self)
|
||||
public func parseSocketMessage(msg: String) {
|
||||
dispatch_async(handleQueue) {[weak self] in
|
||||
if let this = self {
|
||||
SocketParser.parseSocketMessage(msg, socket: this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func parseBinaryData(data:NSData) {
|
||||
SocketParser.parseBinaryData(data, socket: self)
|
||||
public func parseBinaryData(data: NSData) {
|
||||
dispatch_async(handleQueue) {[weak self] in
|
||||
if let this = self {
|
||||
SocketParser.parseBinaryData(data, socket: this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Trieds to reconnect to the server.
|
||||
Tries to reconnect to the server.
|
||||
*/
|
||||
public func reconnect() {
|
||||
_connected = false
|
||||
_connecting = false
|
||||
_reconnecting = false
|
||||
|
||||
engine?.stopPolling()
|
||||
tryReconnect()
|
||||
}
|
||||
|
||||
// We lost connection and should attempt to reestablish
|
||||
@objc private func tryReconnect() {
|
||||
private func tryReconnect() {
|
||||
if reconnectTimer == nil {
|
||||
SocketLogger.log("Starting reconnect", client: self)
|
||||
|
||||
status = SocketIOClientStatus.Reconnecting
|
||||
|
||||
dispatch_async(dispatch_get_main_queue()) {[weak self] in
|
||||
if let this = self {
|
||||
this.reconnectTimer = NSTimer.scheduledTimerWithTimeInterval(Double(this.reconnectWait),
|
||||
target: this, selector: "_tryReconnect", userInfo: nil, repeats: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func _tryReconnect() {
|
||||
if status == SocketIOClientStatus.Connected {
|
||||
clearReconnectTimer()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if reconnectAttempts != -1 && currentReconnectAttempt + 1 > reconnectAttempts || !reconnects {
|
||||
clearReconnectTimer()
|
||||
didDisconnect("Reconnect Failed")
|
||||
|
||||
return
|
||||
} else if connected {
|
||||
_connecting = false
|
||||
_reconnecting = false
|
||||
return
|
||||
}
|
||||
|
||||
if reconnectTimer == nil {
|
||||
SocketLogger.log("Starting reconnect", client: self)
|
||||
|
||||
_reconnecting = true
|
||||
|
||||
dispatch_async(dispatch_get_main_queue()) {[weak self] in
|
||||
if let this = self {
|
||||
this.reconnectTimer = NSTimer.scheduledTimerWithTimeInterval(Double(this.reconnectWait),
|
||||
target: this, selector: "tryReconnect", userInfo: nil, repeats: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SocketLogger.log("Trying to reconnect", client: self)
|
||||
|
||||
51
SocketIOClientSwift/SocketIOClientStatus.swift
Normal file
51
SocketIOClientSwift/SocketIOClientStatus.swift
Normal file
@ -0,0 +1,51 @@
|
||||
//
|
||||
// SocketIOClientStatus.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 8/14/15.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
import Foundation
|
||||
|
||||
@objc public enum SocketIOClientStatus: Int, CustomStringConvertible {
|
||||
public var description: String {
|
||||
let des: String
|
||||
|
||||
switch rawValue {
|
||||
case 0:
|
||||
des = "Not Connected"
|
||||
case 1:
|
||||
des = "Closed"
|
||||
case 2:
|
||||
des = "Connecting"
|
||||
case 3:
|
||||
des = "Connected"
|
||||
case 4:
|
||||
des = "Reconnecting"
|
||||
default:
|
||||
des = "Unknown State"
|
||||
}
|
||||
|
||||
return des
|
||||
}
|
||||
|
||||
case NotConnected, Closed, Connecting, Connected, Reconnecting
|
||||
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
//
|
||||
// SocketLogger.swift
|
||||
// SocketIO-Swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 4/11/15.
|
||||
//
|
||||
@ -24,48 +24,38 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
private let MESSAGE_LENGTH_MAX = 10000
|
||||
|
||||
protocol SocketLogClient {
|
||||
var log:Bool {get set}
|
||||
var logType:String {get}
|
||||
var logType: String {get}
|
||||
}
|
||||
|
||||
final class SocketLogger {
|
||||
private static let printQueue = dispatch_queue_create("printQueue", DISPATCH_QUEUE_SERIAL)
|
||||
static var log = false
|
||||
|
||||
private static func shorten(item:AnyObject) -> CVarArgType {
|
||||
var str = toString(item)
|
||||
|
||||
if count(str) > MESSAGE_LENGTH_MAX {
|
||||
let endIndex = advance(str.startIndex, MESSAGE_LENGTH_MAX)
|
||||
|
||||
str = str.substringToIndex(endIndex)
|
||||
}
|
||||
|
||||
return str
|
||||
private static func toCVArgType(item: AnyObject) -> CVarArgType {
|
||||
return String(item)
|
||||
}
|
||||
|
||||
static func log(message:String, client:SocketLogClient, altType:String? = nil, args:AnyObject...) {
|
||||
if !client.log {
|
||||
static func log(message: String, client: SocketLogClient, altType: String? = nil, args: AnyObject...) {
|
||||
if !log {
|
||||
return
|
||||
}
|
||||
|
||||
dispatch_async(printQueue) {[type = client.logType] in
|
||||
let newArgs = args.map(SocketLogger.shorten)
|
||||
let newArgs = args.map(SocketLogger.toCVArgType)
|
||||
let replaced = String(format: message, arguments: newArgs)
|
||||
|
||||
NSLog("%@: %@", altType ?? type, replaced)
|
||||
}
|
||||
}
|
||||
|
||||
static func err(message:String, client:SocketLogClient, altType:String? = nil, args:AnyObject...) {
|
||||
if !client.log {
|
||||
static func err(message: String, client: SocketLogClient, altType: String? = nil, args: AnyObject...) {
|
||||
if !log {
|
||||
return
|
||||
}
|
||||
|
||||
dispatch_async(printQueue) {[type = client.logType] in
|
||||
let newArgs = args.map(SocketLogger.shorten)
|
||||
let newArgs = args.map(SocketLogger.toCVArgType)
|
||||
let replaced = String(format: message, arguments: newArgs)
|
||||
|
||||
NSLog("ERROR %@: %@", altType ?? type, replaced)
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
//
|
||||
// SocketPacket.swift
|
||||
// Socket.IO-Swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 1/18/15.
|
||||
//
|
||||
@ -24,38 +24,19 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
final class SocketPacket: Printable {
|
||||
var binary = ContiguousArray<NSData>()
|
||||
var currentPlace = 0
|
||||
var data:[AnyObject]?
|
||||
var description:String {
|
||||
var better = "SocketPacket {type: ~~0; data: ~~1; " +
|
||||
"id: ~~2; placeholders: ~~3;}"
|
||||
|
||||
better = better["~~0"] ~= (type != nil ? String(type!.rawValue) : "nil")
|
||||
better = better["~~1"] ~= (data != nil ? "\(data!)" : "nil")
|
||||
better = better["~~2"] ~= (id != nil ? String(id!) : "nil")
|
||||
better = better["~~3"] ~= (placeholders != nil ? String(placeholders!) : "nil")
|
||||
|
||||
return better
|
||||
}
|
||||
var id:Int?
|
||||
var justAck = false
|
||||
var nsp = ""
|
||||
var placeholders:Int?
|
||||
var type:PacketType?
|
||||
struct SocketPacket {
|
||||
private var currentPlace = 0
|
||||
private let placeholders: Int
|
||||
|
||||
let nsp: String
|
||||
let id: Int
|
||||
let type: PacketType
|
||||
|
||||
enum PacketType:Int {
|
||||
case CONNECT = 0
|
||||
case DISCONNECT = 1
|
||||
case EVENT = 2
|
||||
case ACK = 3
|
||||
case ERROR = 4
|
||||
case BINARY_EVENT = 5
|
||||
case BINARY_ACK = 6
|
||||
enum PacketType: Int {
|
||||
case Connect, Disconnect, Event, Ack, Error, BinaryEvent, BinaryAck
|
||||
|
||||
init?(str:String) {
|
||||
if let int = str.toInt(), raw = PacketType(rawValue: int) {
|
||||
init?(str: String) {
|
||||
if let int = Int(str), raw = PacketType(rawValue: int) {
|
||||
self = raw
|
||||
} else {
|
||||
return nil
|
||||
@ -63,20 +44,54 @@ final class SocketPacket: Printable {
|
||||
}
|
||||
}
|
||||
|
||||
init(type:PacketType?, data:[AnyObject]? = nil, nsp:String = "",
|
||||
placeholders:Int? = nil, id:Int? = nil) {
|
||||
self.type = type
|
||||
self.data = data
|
||||
self.nsp = nsp
|
||||
self.placeholders = placeholders
|
||||
self.id = id
|
||||
var args: [AnyObject]? {
|
||||
var arr = data
|
||||
|
||||
if data.count == 0 {
|
||||
return nil
|
||||
} else {
|
||||
if type == PacketType.Event || type == PacketType.BinaryEvent {
|
||||
arr.removeAtIndex(0)
|
||||
return arr
|
||||
} else {
|
||||
return arr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getEvent() -> String {
|
||||
return data?.removeAtIndex(0) as! String
|
||||
var binary: [NSData]
|
||||
var data: [AnyObject]
|
||||
var description: String {
|
||||
var better = "SocketPacket {type: ~~0; data: ~~1; " +
|
||||
"id: ~~2; placeholders: ~~3;}"
|
||||
|
||||
better = better["~~0"] ~= String(type.rawValue)
|
||||
better = better["~~1"] ~= String(data)
|
||||
better = better["~~2"] ~= String(id)
|
||||
better = better["~~3"] ~= String(placeholders)
|
||||
|
||||
return better
|
||||
}
|
||||
|
||||
func addData(data:NSData) -> Bool {
|
||||
var event: String {
|
||||
return data[0] as! String
|
||||
}
|
||||
|
||||
var packetString: String {
|
||||
return createPacketString()
|
||||
}
|
||||
|
||||
init(type: SocketPacket.PacketType, data: [AnyObject] = [AnyObject](), id: Int = -1,
|
||||
nsp: String, placeholders: Int = 0, binary: [NSData] = [NSData]()) {
|
||||
self.data = data
|
||||
self.id = id
|
||||
self.nsp = nsp
|
||||
self.type = type
|
||||
self.placeholders = placeholders
|
||||
self.binary = binary
|
||||
}
|
||||
|
||||
mutating func addData(data: NSData) -> Bool {
|
||||
if placeholders == currentPlace {
|
||||
return true
|
||||
}
|
||||
@ -92,86 +107,22 @@ final class SocketPacket: Printable {
|
||||
}
|
||||
}
|
||||
|
||||
func createMessageForEvent(event:String) -> String {
|
||||
let message:String
|
||||
|
||||
if binary.count == 0 {
|
||||
type = PacketType.EVENT
|
||||
|
||||
if nsp == "/" {
|
||||
if id == nil {
|
||||
message = "2[\"\(event)\""
|
||||
} else {
|
||||
message = "2\(id!)[\"\(event)\""
|
||||
}
|
||||
} else {
|
||||
if id == nil {
|
||||
message = "2/\(nsp),[\"\(event)\""
|
||||
} else {
|
||||
message = "2/\(nsp),\(id!)[\"\(event)\""
|
||||
}
|
||||
}
|
||||
} else {
|
||||
type = PacketType.BINARY_EVENT
|
||||
|
||||
if nsp == "/" {
|
||||
if id == nil {
|
||||
message = "5\(binary.count)-[\"\(event)\""
|
||||
} else {
|
||||
message = "5\(binary.count)-\(id!)[\"\(event)\""
|
||||
}
|
||||
} else {
|
||||
if id == nil {
|
||||
message = "5\(binary.count)-/\(nsp),[\"\(event)\""
|
||||
} else {
|
||||
message = "5\(binary.count)-/\(nsp),\(id!)[\"\(event)\""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return completeMessage(message)
|
||||
}
|
||||
|
||||
func createAck() -> String {
|
||||
var msg:String
|
||||
|
||||
if binary.count == 0 {
|
||||
type = PacketType.ACK
|
||||
|
||||
if nsp == "/" {
|
||||
msg = "3\(id!)["
|
||||
} else {
|
||||
msg = "3/\(nsp),\(id!)["
|
||||
}
|
||||
} else {
|
||||
type = PacketType.BINARY_ACK
|
||||
|
||||
if nsp == "/" {
|
||||
msg = "6\(binary.count)-\(id!)["
|
||||
} else {
|
||||
msg = "6\(binary.count)-/\(nsp),\(id!)["
|
||||
}
|
||||
}
|
||||
|
||||
return completeMessage(msg, ack: true)
|
||||
}
|
||||
|
||||
private func completeMessage(var message:String, ack:Bool = false) -> String {
|
||||
var err:NSError?
|
||||
|
||||
if data == nil || data!.count == 0 {
|
||||
private func completeMessage(var message: String, ack: Bool) -> String {
|
||||
if data.count == 0 {
|
||||
return message + "]"
|
||||
} else if !ack {
|
||||
message += ","
|
||||
}
|
||||
|
||||
for arg in data! {
|
||||
for arg in data {
|
||||
if arg is NSDictionary || arg is [AnyObject] {
|
||||
let jsonSend = NSJSONSerialization.dataWithJSONObject(arg,
|
||||
options: NSJSONWritingOptions(0), error: &err)
|
||||
let jsonString = NSString(data: jsonSend!, encoding: NSUTF8StringEncoding)
|
||||
|
||||
message += jsonString! as String + ","
|
||||
do {
|
||||
let jsonSend = try NSJSONSerialization.dataWithJSONObject(arg,
|
||||
options: NSJSONWritingOptions(rawValue: 0))
|
||||
let jsonString = NSString(data: jsonSend, encoding: NSUTF8StringEncoding)
|
||||
|
||||
message += jsonString! as String + ","
|
||||
} catch {
|
||||
print("Error creating JSON object in SocketPacket.completeMessage")
|
||||
}
|
||||
} else if var str = arg as? String {
|
||||
str = str["\n"] ~= "\\\\n"
|
||||
str = str["\r"] ~= "\\\\r"
|
||||
@ -191,29 +142,98 @@ final class SocketPacket: Printable {
|
||||
return message + "]"
|
||||
}
|
||||
|
||||
func fillInPlaceholders() {
|
||||
var newArr = NSMutableArray(array: data!)
|
||||
private func createAck() -> String {
|
||||
let msg: String
|
||||
|
||||
for i in 0..<data!.count {
|
||||
if let str = data?[i] as? String, num = str["~~(\\d)"].groups() {
|
||||
newArr[i] = binary[num[1].toInt()!]
|
||||
} else if data?[i] is NSDictionary || data?[i] is NSArray {
|
||||
newArr[i] = _fillInPlaceholders(data![i])
|
||||
if type == PacketType.Ack {
|
||||
if nsp == "/" {
|
||||
msg = "3\(id)["
|
||||
} else {
|
||||
msg = "3\(nsp),\(id)["
|
||||
}
|
||||
} else {
|
||||
if nsp == "/" {
|
||||
msg = "6\(binary.count)-\(id)["
|
||||
} else {
|
||||
msg = "6\(binary.count)-/\(nsp),\(id)["
|
||||
}
|
||||
}
|
||||
|
||||
return completeMessage(msg, ack: true)
|
||||
}
|
||||
|
||||
|
||||
private func createMessageForEvent() -> String {
|
||||
let message: String
|
||||
|
||||
if type == PacketType.Event {
|
||||
if nsp == "/" {
|
||||
if id == -1 {
|
||||
message = "2["
|
||||
} else {
|
||||
message = "2\(id)["
|
||||
}
|
||||
} else {
|
||||
if id == -1 {
|
||||
message = "2\(nsp),["
|
||||
} else {
|
||||
message = "2\(nsp),\(id)["
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if nsp == "/" {
|
||||
if id == -1 {
|
||||
message = "5\(binary.count)-["
|
||||
} else {
|
||||
message = "5\(binary.count)-\(id)["
|
||||
}
|
||||
} else {
|
||||
if id == -1 {
|
||||
message = "5\(binary.count)-\(nsp),["
|
||||
} else {
|
||||
message = "5\(binary.count)-\(nsp),\(id)["
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return completeMessage(message, ack: false)
|
||||
}
|
||||
|
||||
private func createPacketString() -> String {
|
||||
let str: String
|
||||
|
||||
if type == PacketType.Event || type == PacketType.BinaryEvent {
|
||||
str = createMessageForEvent()
|
||||
} else {
|
||||
str = createAck()
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
mutating func fillInPlaceholders() {
|
||||
let newArr = NSMutableArray(array: data)
|
||||
|
||||
for i in 0..<data.count {
|
||||
if let str = data[i] as? String, num = str["~~(\\d)"].groups() {
|
||||
newArr[i] = binary[Int(num[1])!]
|
||||
} else if data[i] is NSDictionary || data[i] is NSArray {
|
||||
newArr[i] = _fillInPlaceholders(data[i])
|
||||
}
|
||||
}
|
||||
|
||||
data = newArr as [AnyObject]
|
||||
}
|
||||
|
||||
private func _fillInPlaceholders(data:AnyObject) -> AnyObject {
|
||||
private mutating func _fillInPlaceholders(data: AnyObject) -> AnyObject {
|
||||
if let str = data as? String {
|
||||
if let num = str["~~(\\d)"].groups() {
|
||||
return binary[num[1].toInt()!]
|
||||
return binary[Int(num[1])!]
|
||||
} else {
|
||||
return str
|
||||
}
|
||||
} else if let dict = data as? NSDictionary {
|
||||
var newDict = NSMutableDictionary(dictionary: dict)
|
||||
let newDict = NSMutableDictionary(dictionary: dict)
|
||||
|
||||
for (key, value) in dict {
|
||||
newDict[key as! NSCopying] = _fillInPlaceholders(value)
|
||||
@ -221,7 +241,7 @@ final class SocketPacket: Printable {
|
||||
|
||||
return newDict
|
||||
} else if let arr = data as? NSArray {
|
||||
var newArr = NSMutableArray(array: arr)
|
||||
let newArr = NSMutableArray(array: arr)
|
||||
|
||||
for i in 0..<arr.count {
|
||||
newArr[i] = _fillInPlaceholders(arr[i])
|
||||
@ -233,3 +253,73 @@ final class SocketPacket: Printable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension SocketPacket {
|
||||
private static func findType(binCount: Int, ack: Bool) -> PacketType {
|
||||
switch binCount {
|
||||
case 0 where !ack:
|
||||
return PacketType.Event
|
||||
case 0 where ack:
|
||||
return PacketType.Ack
|
||||
case _ where !ack:
|
||||
return PacketType.BinaryEvent
|
||||
case _ where ack:
|
||||
return PacketType.BinaryAck
|
||||
default:
|
||||
return PacketType.Error
|
||||
}
|
||||
}
|
||||
|
||||
static func packetFromEmit(items: [AnyObject], id: Int, nsp: String, ack: Bool) -> SocketPacket {
|
||||
let (parsedData, binary) = deconstructData(items)
|
||||
let packet = SocketPacket(type: findType(binary.count, ack: ack), data: parsedData,
|
||||
id: id, nsp: nsp, placeholders: -1, binary: binary)
|
||||
|
||||
return packet
|
||||
}
|
||||
}
|
||||
|
||||
private extension SocketPacket {
|
||||
static func shred(data: AnyObject, inout binary: [NSData]) -> AnyObject {
|
||||
if let bin = data as? NSData {
|
||||
let placeholder = ["_placeholder" :true, "num": binary.count]
|
||||
|
||||
binary.append(bin)
|
||||
|
||||
return placeholder
|
||||
} else if let arr = data as? NSArray {
|
||||
let newArr = NSMutableArray(array: arr)
|
||||
|
||||
for i in 0..<arr.count {
|
||||
newArr[i] = shred(arr[i], binary: &binary)
|
||||
}
|
||||
|
||||
return newArr
|
||||
} else if let dict = data as? NSDictionary {
|
||||
let newDict = NSMutableDictionary(dictionary: dict)
|
||||
|
||||
for (key, value) in newDict {
|
||||
newDict[key as! NSCopying] = shred(value, binary: &binary)
|
||||
}
|
||||
|
||||
return newDict
|
||||
} else {
|
||||
return data
|
||||
}
|
||||
}
|
||||
|
||||
static func deconstructData(var data: [AnyObject]) -> ([AnyObject], [NSData]) {
|
||||
var binary = [NSData]()
|
||||
|
||||
for i in 0..<data.count {
|
||||
if data[i] is NSArray || data[i] is NSDictionary {
|
||||
data[i] = shred(data[i], binary: &binary)
|
||||
} else if let bin = data[i] as? NSData {
|
||||
data[i] = ["_placeholder" :true, "num": binary.count]
|
||||
binary.append(bin)
|
||||
}
|
||||
}
|
||||
|
||||
return (data, binary)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
//
|
||||
// SocketParser.swift
|
||||
// Socket.IO-Swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
@ -22,74 +22,65 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
class SocketParser {
|
||||
private static let shredder = SocketParser.PacketShredder()
|
||||
class SocketParser {
|
||||
private static func isCorrectNamespace(nsp: String, _ socket: SocketIOClient) -> Bool {
|
||||
return nsp == socket.nsp
|
||||
}
|
||||
|
||||
// Translation of socket.io-parser#deconstructPacket
|
||||
private final class PacketShredder {
|
||||
var buf = ContiguousArray<NSData>()
|
||||
|
||||
func shred(data:AnyObject) -> AnyObject {
|
||||
if let bin = data as? NSData {
|
||||
let placeholder = ["_placeholder" :true, "num": buf.count]
|
||||
|
||||
buf.append(bin)
|
||||
|
||||
return placeholder
|
||||
} else if let arr = data as? NSArray {
|
||||
var newArr = NSMutableArray(array: arr)
|
||||
|
||||
for i in 0..<arr.count {
|
||||
newArr[i] = shred(arr[i])
|
||||
}
|
||||
|
||||
return newArr
|
||||
} else if let dict = data as? NSDictionary {
|
||||
var newDict = NSMutableDictionary(dictionary: dict)
|
||||
|
||||
for (key, value) in newDict {
|
||||
newDict[key as! NSCopying] = shred(value)
|
||||
}
|
||||
|
||||
return newDict
|
||||
} else {
|
||||
return data
|
||||
}
|
||||
private static func handleAck(p: SocketPacket, socket: SocketIOClient) {
|
||||
if !isCorrectNamespace(p.nsp, socket) {
|
||||
return
|
||||
}
|
||||
|
||||
func deconstructPacket(packet:SocketPacket) {
|
||||
if packet.data == nil {
|
||||
return
|
||||
}
|
||||
|
||||
var data = packet.data!
|
||||
|
||||
for i in 0..<data.count {
|
||||
if data[i] is NSArray || data[i] is NSDictionary {
|
||||
data[i] = shred(data[i])
|
||||
} else if let bin = data[i] as? NSData {
|
||||
data[i] = ["_placeholder" :true, "num": buf.count]
|
||||
buf.append(bin)
|
||||
}
|
||||
}
|
||||
|
||||
packet.data = data
|
||||
packet.binary = buf
|
||||
buf.removeAll(keepCapacity: true)
|
||||
socket.handleAck(p.id, data: p.data)
|
||||
}
|
||||
|
||||
private static func handleBinaryAck(p: SocketPacket, socket: SocketIOClient) {
|
||||
if !isCorrectNamespace(p.nsp, socket) {
|
||||
return
|
||||
}
|
||||
|
||||
socket.waitingData.append(p)
|
||||
}
|
||||
|
||||
private static func handleBinaryEvent(p: SocketPacket, socket: SocketIOClient) {
|
||||
if !isCorrectNamespace(p.nsp, socket) {
|
||||
return
|
||||
}
|
||||
|
||||
socket.waitingData.append(p)
|
||||
}
|
||||
|
||||
private static func handleConnect(p: SocketPacket, socket: SocketIOClient) {
|
||||
if p.nsp == "/" && socket.nsp != "/" {
|
||||
socket.joinNamespace()
|
||||
} else if p.nsp != "/" && socket.nsp == "/" {
|
||||
socket.didConnect()
|
||||
} else {
|
||||
socket.didConnect()
|
||||
}
|
||||
}
|
||||
|
||||
private static func handleEvent(p: SocketPacket, socket: SocketIOClient) {
|
||||
if !isCorrectNamespace(p.nsp, socket) {
|
||||
return
|
||||
}
|
||||
|
||||
socket.handleEvent(p.event, data: p.args,
|
||||
isInternalMessage: false, wantsAck: p.id)
|
||||
}
|
||||
|
||||
// Translation of socket.io-client#decodeString
|
||||
static func parseString(str:String) -> SocketPacket? {
|
||||
let arr = Array(str)
|
||||
static func parseString(str: String) -> SocketPacket? {
|
||||
let arr = Array(str.characters)
|
||||
let type = String(arr[0])
|
||||
|
||||
if arr.count == 1 {
|
||||
return SocketPacket(type: SocketPacket.PacketType(str: type))
|
||||
return SocketPacket(type: SocketPacket.PacketType(str: type)!, nsp: "/")
|
||||
}
|
||||
|
||||
var id = nil as Int?
|
||||
var nsp = ""
|
||||
var id: Int?
|
||||
var nsp:String?
|
||||
var i = 0
|
||||
var placeholders = -1
|
||||
|
||||
@ -103,7 +94,7 @@ class SocketParser {
|
||||
}
|
||||
}
|
||||
|
||||
if let holders = buf.toInt() where arr[i] == "-" {
|
||||
if let holders = Int(buf) where arr[i] == "-" {
|
||||
placeholders = holders
|
||||
} else {
|
||||
NSLog("Error parsing \(str)")
|
||||
@ -112,6 +103,8 @@ class SocketParser {
|
||||
}
|
||||
|
||||
if arr[i + 1] == "/" {
|
||||
nsp = ""
|
||||
|
||||
while ++i < arr.count {
|
||||
let c = arr[i]
|
||||
|
||||
@ -119,49 +112,56 @@ class SocketParser {
|
||||
break
|
||||
}
|
||||
|
||||
nsp += String(c)
|
||||
nsp! += String(c)
|
||||
}
|
||||
}
|
||||
|
||||
if i + 1 >= arr.count {
|
||||
return SocketPacket(type: SocketPacket.PacketType(str: type),
|
||||
nsp: nsp, placeholders: placeholders, id: id)
|
||||
return SocketPacket(type: SocketPacket.PacketType(str: type)!, id: id ?? -1,
|
||||
nsp: nsp ?? "/", placeholders: placeholders)
|
||||
}
|
||||
|
||||
let next = String(arr[i + 1])
|
||||
|
||||
if next.toInt() != nil {
|
||||
if Int(next) != nil {
|
||||
var c = ""
|
||||
while ++i < arr.count {
|
||||
if let int = String(arr[i]).toInt() {
|
||||
c += String(arr[i])
|
||||
if let int = Int(String(arr[i])) {
|
||||
c += String(int)
|
||||
} else {
|
||||
--i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
id = c.toInt()
|
||||
id = Int(c)
|
||||
}
|
||||
|
||||
if ++i < arr.count {
|
||||
let d = str[advance(str.startIndex, i)...advance(str.startIndex, count(str)-1)]
|
||||
let d = str[str.startIndex.advancedBy(i)...str.startIndex.advancedBy(str.characters.count-1)]
|
||||
let noPlaceholders = d["(\\{\"_placeholder\":true,\"num\":(\\d*)\\})"] ~= "\"~~$2\""
|
||||
let data = SocketParser.parseData(noPlaceholders) as? [AnyObject] ?? [noPlaceholders]
|
||||
|
||||
return SocketPacket(type: SocketPacket.PacketType(str: type), data: data,
|
||||
nsp: nsp, placeholders: placeholders, id: id)
|
||||
return SocketPacket(type: SocketPacket.PacketType(str: type)!, data: data, id: id ?? -1,
|
||||
nsp: nsp ?? "/", placeholders: placeholders)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Parses data for events
|
||||
static func parseData(data:String) -> AnyObject? {
|
||||
var err:NSError?
|
||||
static func parseData(data: String) -> AnyObject? {
|
||||
var err: NSError?
|
||||
let stringData = data.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
|
||||
let parsed:AnyObject? = NSJSONSerialization.JSONObjectWithData(stringData!,
|
||||
options: NSJSONReadingOptions.MutableContainers, error: &err)
|
||||
let parsed: AnyObject?
|
||||
|
||||
do {
|
||||
parsed = try NSJSONSerialization.JSONObjectWithData(stringData!,
|
||||
options: NSJSONReadingOptions.MutableContainers)
|
||||
} catch let error as NSError {
|
||||
err = error
|
||||
parsed = nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
// println(err)
|
||||
@ -171,23 +171,15 @@ class SocketParser {
|
||||
return parsed
|
||||
}
|
||||
|
||||
static func parseForEmit(packet:SocketPacket) {
|
||||
shredder.deconstructPacket(packet)
|
||||
}
|
||||
|
||||
// Parses messages recieved
|
||||
static func parseSocketMessage(stringMessage:String, socket:SocketIOClient) {
|
||||
static func parseSocketMessage(stringMessage: String, socket: SocketIOClient) {
|
||||
if stringMessage == "" {
|
||||
return
|
||||
}
|
||||
|
||||
func checkNSP(nsp:String) -> Bool {
|
||||
return nsp == "" && socket.nsp != "/"
|
||||
}
|
||||
|
||||
SocketLogger.log("Parsing %@", client: socket, altType: "SocketParser", args: stringMessage)
|
||||
|
||||
let p:SocketPacket
|
||||
let p: SocketPacket
|
||||
|
||||
if let pack = parseString(stringMessage) {
|
||||
p = pack
|
||||
@ -196,50 +188,27 @@ class SocketParser {
|
||||
return
|
||||
}
|
||||
|
||||
SocketLogger.log("Decoded packet as: %@", client: socket, altType: "SocketParser", args: p)
|
||||
SocketLogger.log("Decoded packet as: %@", client: socket, altType: "SocketParser", args: p.description)
|
||||
|
||||
if p.type == SocketPacket.PacketType.EVENT {
|
||||
if checkNSP(p.nsp) {
|
||||
return
|
||||
}
|
||||
|
||||
socket.handleEvent(p.getEvent(), data: p.data,
|
||||
isInternalMessage: false, wantsAck: p.id)
|
||||
} else if p.type == SocketPacket.PacketType.ACK {
|
||||
if checkNSP(p.nsp) {
|
||||
return
|
||||
}
|
||||
|
||||
socket.handleAck(p.id!, data: p.data)
|
||||
} else if p.type == SocketPacket.PacketType.BINARY_EVENT {
|
||||
if checkNSP(p.nsp) {
|
||||
return
|
||||
}
|
||||
|
||||
socket.waitingData.append(p)
|
||||
} else if p.type == SocketPacket.PacketType.BINARY_ACK {
|
||||
if checkNSP(p.nsp) {
|
||||
return
|
||||
}
|
||||
|
||||
p.justAck = true
|
||||
socket.waitingData.append(p)
|
||||
} else if p.type == SocketPacket.PacketType.CONNECT {
|
||||
if p.nsp == "" && socket.nsp != "/" {
|
||||
socket.joinNamespace()
|
||||
} else if p.nsp != "" && socket.nsp == "/" {
|
||||
socket.didConnect()
|
||||
} else {
|
||||
socket.didConnect()
|
||||
}
|
||||
} else if p.type == SocketPacket.PacketType.DISCONNECT {
|
||||
switch p.type {
|
||||
case SocketPacket.PacketType.Event:
|
||||
handleEvent(p, socket: socket)
|
||||
case SocketPacket.PacketType.Ack:
|
||||
handleAck(p, socket: socket)
|
||||
case SocketPacket.PacketType.BinaryEvent:
|
||||
handleBinaryEvent(p, socket: socket)
|
||||
case SocketPacket.PacketType.BinaryAck:
|
||||
handleBinaryAck(p, socket: socket)
|
||||
case SocketPacket.PacketType.Connect:
|
||||
handleConnect(p, socket: socket)
|
||||
case SocketPacket.PacketType.Disconnect:
|
||||
socket.didDisconnect("Got Disconnect")
|
||||
} else if p.type == SocketPacket.PacketType.ERROR {
|
||||
socket.didError(p.data == nil ? "Error" : p.data!)
|
||||
case SocketPacket.PacketType.Error:
|
||||
socket.didError("Error: \(p.data)")
|
||||
}
|
||||
}
|
||||
|
||||
static func parseBinaryData(data:NSData, socket:SocketIOClient) {
|
||||
static func parseBinaryData(data: NSData, socket: SocketIOClient) {
|
||||
if socket.waitingData.count == 0 {
|
||||
SocketLogger.err("Got data when not remaking packet", client: socket, altType: "SocketParser")
|
||||
return
|
||||
@ -251,14 +220,14 @@ class SocketParser {
|
||||
return
|
||||
}
|
||||
|
||||
let packet = socket.waitingData.removeAtIndex(0)
|
||||
var packet = socket.waitingData.removeAtIndex(0)
|
||||
packet.fillInPlaceholders()
|
||||
|
||||
if !packet.justAck {
|
||||
socket.handleEvent(packet.getEvent(), data: packet.data,
|
||||
wantsAck: packet.id)
|
||||
if packet.type != SocketPacket.PacketType.BinaryAck {
|
||||
socket.handleEvent(packet.event, data: packet.args,
|
||||
isInternalMessage: false, wantsAck: packet.id)
|
||||
} else {
|
||||
socket.handleAck(packet.id!, data: packet.data)
|
||||
socket.handleAck(packet.id, data: packet.args)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
//
|
||||
// SocketTypes.swift
|
||||
// SocketIO-Swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 4/8/15.
|
||||
//
|
||||
@ -24,11 +24,10 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
// @objc_block is undocumented, but is used because Swift assumes that all
|
||||
// Objective-C blocks are copied, but Objective-C assumes that Swift will copy it.
|
||||
// And the way things are done here, the bridging fails to copy the block in
|
||||
// SocketAckMap#addAck
|
||||
public typealias AckCallback = @objc_block (NSArray?) -> Void
|
||||
public typealias AckCallback = (NSArray?) -> Void
|
||||
public typealias AckEmitter = (AnyObject...) -> Void
|
||||
public typealias AckEmitterObjectiveC = (NSArray) -> Void
|
||||
public typealias NormalCallback = (NSArray?, AckEmitter?) -> Void
|
||||
public typealias OnAckCallback = (timeout:UInt64, callback:AckCallback) -> Void
|
||||
public typealias NormalCallbackObjectiveC = (NSArray?, AckEmitterObjectiveC?) -> Void
|
||||
public typealias OnAckCallback = (timeoutAfter:UInt64, callback:AckCallback) -> Void
|
||||
|
||||
|
||||
@ -18,34 +18,34 @@ var swiftRegexCache = [String: NSRegularExpression]()
|
||||
public class SwiftRegex: NSObject, BooleanType {
|
||||
var target:String
|
||||
var regex: NSRegularExpression
|
||||
|
||||
init(target:String, pattern:String, options:NSRegularExpressionOptions = nil) {
|
||||
|
||||
init(target:String, pattern:String, options:NSRegularExpressionOptions?) {
|
||||
self.target = target
|
||||
if let regex = swiftRegexCache[pattern] {
|
||||
self.regex = regex
|
||||
} else {
|
||||
var error: NSError?
|
||||
if let regex = NSRegularExpression(pattern: pattern, options:options, error:&error) {
|
||||
do {
|
||||
let regex = try NSRegularExpression(pattern: pattern, options:
|
||||
NSRegularExpressionOptions.DotMatchesLineSeparators)
|
||||
swiftRegexCache[pattern] = regex
|
||||
self.regex = regex
|
||||
}
|
||||
else {
|
||||
SwiftRegex.failure("Error in pattern: \(pattern) - \(error)")
|
||||
} catch let error1 as NSError {
|
||||
SwiftRegex.failure("Error in pattern: \(pattern) - \(error1)")
|
||||
self.regex = NSRegularExpression()
|
||||
}
|
||||
}
|
||||
super.init()
|
||||
}
|
||||
|
||||
|
||||
class func failure(message: String) {
|
||||
println("SwiftRegex: "+message)
|
||||
print("SwiftRegex: "+message)
|
||||
//assert(false,"SwiftRegex: failed")
|
||||
}
|
||||
|
||||
|
||||
final var targetRange: NSRange {
|
||||
return NSRange(location: 0,length: count(target.utf16))
|
||||
return NSRange(location: 0,length: target.utf16.count)
|
||||
}
|
||||
|
||||
|
||||
final func substring(range: NSRange) -> String? {
|
||||
if ( range.location != NSNotFound ) {
|
||||
return (target as NSString).substringWithRange(range)
|
||||
@ -53,23 +53,24 @@ public class SwiftRegex: NSObject, BooleanType {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
public func doesMatch(options: NSMatchingOptions = nil) -> Bool {
|
||||
return range(options: options).location != NSNotFound
|
||||
|
||||
public func doesMatch(options: NSMatchingOptions!) -> Bool {
|
||||
return range(options).location != NSNotFound
|
||||
}
|
||||
|
||||
public func range(options: NSMatchingOptions = nil) -> NSRange {
|
||||
return regex.rangeOfFirstMatchInString(target as String, options: nil, range: targetRange)
|
||||
|
||||
public func range(options: NSMatchingOptions) -> NSRange {
|
||||
return regex.rangeOfFirstMatchInString(target as String, options: [], range: targetRange)
|
||||
}
|
||||
|
||||
public func match(options: NSMatchingOptions = nil) -> String? {
|
||||
return substring(range(options: options))
|
||||
|
||||
public func match(options: NSMatchingOptions) -> String? {
|
||||
return substring(range(options))
|
||||
}
|
||||
|
||||
public func groups(options: NSMatchingOptions = nil) -> [String]? {
|
||||
return groupsForMatch(regex.firstMatchInString(target as String, options: options, range: targetRange))
|
||||
|
||||
public func groups() -> [String]? {
|
||||
return groupsForMatch(regex.firstMatchInString(target as String, options:
|
||||
NSMatchingOptions.WithoutAnchoringBounds, range: targetRange))
|
||||
}
|
||||
|
||||
|
||||
func groupsForMatch(match: NSTextCheckingResult!) -> [String]? {
|
||||
if match != nil {
|
||||
var groups = [String]()
|
||||
@ -85,80 +86,75 @@ public class SwiftRegex: NSObject, BooleanType {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public subscript(groupno: Int) -> String? {
|
||||
get {
|
||||
return groups()?[groupno]
|
||||
}
|
||||
|
||||
|
||||
set(newValue) {
|
||||
if newValue == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for match in matchResults()!.reverse() {
|
||||
|
||||
for match in Array(matchResults().reverse()) {
|
||||
let replacement = regex.replacementStringForResult(match,
|
||||
inString: target as String, offset: 0, template: newValue!)
|
||||
let mut = NSMutableString(string: target)
|
||||
mut.replaceCharactersInRange(match.rangeAtIndex(groupno), withString: replacement)
|
||||
|
||||
|
||||
target = mut as String
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func matchResults(options: NSMatchingOptions = nil) -> [NSTextCheckingResult]? {
|
||||
let matches = regex.matchesInString(target as String, options: options, range: targetRange)
|
||||
as? [NSTextCheckingResult]
|
||||
|
||||
if matches != nil {
|
||||
return matches!
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
||||
func matchResults() -> [NSTextCheckingResult] {
|
||||
let matches = regex.matchesInString(target as String, options:
|
||||
NSMatchingOptions.WithoutAnchoringBounds, range: targetRange)
|
||||
as [NSTextCheckingResult]
|
||||
|
||||
return matches
|
||||
}
|
||||
|
||||
public func ranges(options: NSMatchingOptions = nil) -> [NSRange] {
|
||||
return matchResults(options: options)!.map { $0.range }
|
||||
|
||||
public func ranges() -> [NSRange] {
|
||||
return matchResults().map { $0.range }
|
||||
}
|
||||
|
||||
public func matches(options: NSMatchingOptions = nil) -> [String] {
|
||||
return matchResults(options: options)!.map( { self.substring($0.range)!})
|
||||
|
||||
public func matches() -> [String] {
|
||||
return matchResults().map( { self.substring($0.range)!})
|
||||
}
|
||||
|
||||
public func allGroups(options: NSMatchingOptions = nil) -> [[String]?] {
|
||||
return matchResults(options: options)!.map {self.groupsForMatch($0)}
|
||||
|
||||
public func allGroups() -> [[String]?] {
|
||||
return matchResults().map {self.groupsForMatch($0)}
|
||||
}
|
||||
|
||||
public func dictionary(options: NSMatchingOptions = nil) -> Dictionary<String,String> {
|
||||
|
||||
public func dictionary(options: NSMatchingOptions!) -> Dictionary<String,String> {
|
||||
var out = Dictionary<String,String>()
|
||||
for match in matchResults(options: options)! {
|
||||
for match in matchResults() {
|
||||
out[substring(match.rangeAtIndex(1))!] = substring(match.rangeAtIndex(2))!
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
|
||||
func substituteMatches(substitution: ((NSTextCheckingResult, UnsafeMutablePointer<ObjCBool>) -> String),
|
||||
options:NSMatchingOptions = nil) -> String {
|
||||
options:NSMatchingOptions) -> String {
|
||||
let out = NSMutableString()
|
||||
var pos = 0
|
||||
|
||||
regex.enumerateMatchesInString(target as String, options: options, range: targetRange ) {
|
||||
(match: NSTextCheckingResult!, flags: NSMatchingFlags, stop: UnsafeMutablePointer<ObjCBool>) in
|
||||
|
||||
let matchRange = match.range
|
||||
|
||||
regex.enumerateMatchesInString(target as String, options: options, range: targetRange ) {match, flags, stop in
|
||||
let matchRange = match!.range
|
||||
out.appendString( self.substring(NSRange(location:pos, length:matchRange.location-pos))!)
|
||||
out.appendString( substitution(match, stop) )
|
||||
out.appendString( substitution(match!, stop) )
|
||||
pos = matchRange.location + matchRange.length
|
||||
}
|
||||
|
||||
|
||||
out.appendString(substring(NSRange(location:pos, length:targetRange.length-pos))!)
|
||||
|
||||
|
||||
return out as String
|
||||
}
|
||||
|
||||
|
||||
public var boolValue: Bool {
|
||||
return doesMatch()
|
||||
return doesMatch(nil)
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,7 +166,7 @@ extension String {
|
||||
|
||||
extension String {
|
||||
public subscript(pattern: String) -> SwiftRegex {
|
||||
return SwiftRegex(target: self, pattern: pattern)
|
||||
return SwiftRegex(target: self, pattern: pattern, options: nil)
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,20 +174,20 @@ public func ~= (left: SwiftRegex, right: String) -> String {
|
||||
return left.substituteMatches({match, stop in
|
||||
return left.regex.replacementStringForResult( match,
|
||||
inString: left.target as String, offset: 0, template: right )
|
||||
}, options: nil)
|
||||
}, options: [])
|
||||
}
|
||||
|
||||
public func ~= (left: SwiftRegex, right: [String]) -> String {
|
||||
var matchNumber = 0
|
||||
return left.substituteMatches({match, stop -> String in
|
||||
|
||||
|
||||
if ++matchNumber == right.count {
|
||||
stop.memory = true
|
||||
}
|
||||
|
||||
|
||||
return left.regex.replacementStringForResult( match,
|
||||
inString: left.target as String, offset: 0, template: right[matchNumber-1] )
|
||||
}, options: nil)
|
||||
}, options: [])
|
||||
}
|
||||
|
||||
public func ~= (left: SwiftRegex, right: (String) -> String) -> String {
|
||||
@ -199,11 +195,11 @@ public func ~= (left: SwiftRegex, right: (String) -> String) -> String {
|
||||
return left.substituteMatches(
|
||||
{match, stop -> String in
|
||||
right(left.substring(match.range)!)
|
||||
}, options: nil)
|
||||
}, options: [])
|
||||
}
|
||||
|
||||
public func ~= (left: SwiftRegex, right: ([String]?) -> String) -> String {
|
||||
return left.substituteMatches({match, stop -> String in
|
||||
return right(left.groupsForMatch(match))
|
||||
}, options: nil)
|
||||
}, options: [])
|
||||
}
|
||||
|
||||
@ -93,7 +93,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
||||
public var headers = Dictionary<String,String>()
|
||||
public var voipEnabled = false
|
||||
public var selfSignedSSL = false
|
||||
public var security: Security?
|
||||
private var security: Security?
|
||||
public var isConnected :Bool {
|
||||
return connected
|
||||
}
|
||||
@ -168,7 +168,6 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
||||
//private method that starts the connection
|
||||
private func createHTTPRequest() {
|
||||
|
||||
let str: NSString = url.absoluteString!
|
||||
let urlRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, "GET",
|
||||
url, kCFHTTPVersion1_1).takeRetainedValue()
|
||||
|
||||
@ -184,24 +183,25 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
||||
if self.cookies != nil {
|
||||
let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(self.cookies!)
|
||||
for (key, value) in headers {
|
||||
self.addHeader(urlRequest, key: key as! String, val: value as! String)
|
||||
self.addHeader(urlRequest, key: key as String, val: value as String)
|
||||
}
|
||||
}
|
||||
|
||||
self.addHeader(urlRequest, key: headerWSUpgradeName, val: headerWSUpgradeValue)
|
||||
self.addHeader(urlRequest, key: headerWSConnectionName, val: headerWSConnectionValue)
|
||||
if let protocols = optionalProtocols {
|
||||
self.addHeader(urlRequest, key: headerWSProtocolName, val: ",".join(protocols))
|
||||
self.addHeader(urlRequest, key: headerWSProtocolName, val: protocols.joinWithSeparator(","))
|
||||
}
|
||||
self.addHeader(urlRequest, key: headerWSVersionName, val: headerWSVersionValue)
|
||||
self.addHeader(urlRequest, key: headerWSKeyName, val: self.generateWebSocketKey())
|
||||
self.addHeader(urlRequest, key: headerOriginName, val: url.absoluteString!)
|
||||
self.addHeader(urlRequest, key: headerOriginName, val: url.absoluteString)
|
||||
self.addHeader(urlRequest, key: headerWSHostName, val: "\(url.host!):\(port!)")
|
||||
for (key,value) in headers {
|
||||
self.addHeader(urlRequest, key: key, val: value)
|
||||
}
|
||||
|
||||
let serializedRequest: NSData = CFHTTPMessageCopySerializedMessage(urlRequest).takeRetainedValue()
|
||||
|
||||
let serializedRequest: NSData = CFHTTPMessageCopySerializedMessage(urlRequest)!.takeRetainedValue()
|
||||
self.initStreamsWithData(serializedRequest, Int(port!))
|
||||
}
|
||||
//Add a header to the CFHTTPMessage by using the NSString bridges to CFString
|
||||
@ -220,8 +220,8 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
||||
let uni = UnicodeScalar(UInt32(97 + arc4random_uniform(25)))
|
||||
key += "\(Character(uni))"
|
||||
}
|
||||
var data = key.dataUsingEncoding(NSUTF8StringEncoding)
|
||||
var baseKey = data?.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(0))
|
||||
let data = key.dataUsingEncoding(NSUTF8StringEncoding)
|
||||
let baseKey = data?.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
|
||||
return baseKey!
|
||||
}
|
||||
//Start the stream connection and write the data to the output stream
|
||||
@ -250,8 +250,8 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
||||
}
|
||||
if self.selfSignedSSL {
|
||||
let settings: Dictionary<NSObject, NSObject> = [kCFStreamSSLValidatesCertificateChain: NSNumber(bool:false), kCFStreamSSLPeerName: kCFNull]
|
||||
inputStream!.setProperty(settings, forKey: kCFStreamPropertySSLSettings as! String)
|
||||
outputStream!.setProperty(settings, forKey: kCFStreamPropertySSLSettings as! String)
|
||||
inputStream!.setProperty(settings, forKey: kCFStreamPropertySSLSettings as String)
|
||||
outputStream!.setProperty(settings, forKey: kCFStreamPropertySSLSettings as String)
|
||||
}
|
||||
isRunLoop = true
|
||||
inputStream!.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
|
||||
@ -261,16 +261,16 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
||||
let bytes = UnsafePointer<UInt8>(data.bytes)
|
||||
outputStream!.write(bytes, maxLength: data.length)
|
||||
while(isRunLoop) {
|
||||
NSRunLoop.currentRunLoop().runMode(NSDefaultRunLoopMode, beforeDate: NSDate.distantFuture() as! NSDate)
|
||||
NSRunLoop.currentRunLoop().runMode(NSDefaultRunLoopMode, beforeDate: NSDate.distantFuture() as NSDate)
|
||||
}
|
||||
}
|
||||
//delegate for the stream methods. Processes incoming bytes
|
||||
public func stream(aStream: NSStream, handleEvent eventCode: NSStreamEvent) {
|
||||
|
||||
if let sec = security where !certValidated && (eventCode == .HasBytesAvailable || eventCode == .HasSpaceAvailable) {
|
||||
var possibleTrust: AnyObject? = aStream.propertyForKey(kCFStreamPropertySSLPeerTrust as! String)
|
||||
let possibleTrust: AnyObject? = aStream.propertyForKey(kCFStreamPropertySSLPeerTrust as String)
|
||||
if let trust: AnyObject = possibleTrust {
|
||||
var domain: AnyObject? = aStream.propertyForKey(kCFStreamSSLPeerName as! String)
|
||||
let domain: AnyObject? = aStream.propertyForKey(kCFStreamSSLPeerName as String)
|
||||
if sec.isValid(trust as! SecTrustRef, domain: domain as! String?) {
|
||||
certValidated = true
|
||||
} else {
|
||||
@ -314,7 +314,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
||||
///handles the incoming bytes and sending them to the proper processing method
|
||||
private func processInputStream() {
|
||||
let buf = NSMutableData(capacity: BUFFER_MAX)
|
||||
var buffer = UnsafeMutablePointer<UInt8>(buf!.bytes)
|
||||
let buffer = UnsafeMutablePointer<UInt8>(buf!.bytes)
|
||||
let length = inputStream!.read(buffer, maxLength: BUFFER_MAX)
|
||||
if length > 0 {
|
||||
if !connected {
|
||||
@ -340,7 +340,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
||||
let data = inputQueue[0]
|
||||
var work = data
|
||||
if (fragBuffer != nil) {
|
||||
var combine = NSMutableData(data: fragBuffer!)
|
||||
let combine = NSMutableData(data: fragBuffer!)
|
||||
combine.appendData(data)
|
||||
work = combine
|
||||
fragBuffer = nil
|
||||
@ -388,14 +388,14 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
||||
|
||||
///validates the HTTP is a 101 as per the RFC spec
|
||||
private func validateResponse(buffer: UnsafePointer<UInt8>, bufferLen: Int) -> Bool {
|
||||
let response = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, 0).takeRetainedValue()
|
||||
let response = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, false).takeRetainedValue()
|
||||
CFHTTPMessageAppendBytes(response, buffer, bufferLen)
|
||||
if CFHTTPMessageGetResponseStatusCode(response) != 101 {
|
||||
return false
|
||||
}
|
||||
let cfHeaders = CFHTTPMessageCopyAllHeaderFields(response)
|
||||
let headers: NSDictionary = cfHeaders.takeRetainedValue()
|
||||
let acceptKey = headers[headerWSAcceptName] as! NSString
|
||||
let headers:NSDictionary? = cfHeaders?.takeRetainedValue()
|
||||
let acceptKey = headers?[headerWSAcceptName] as! NSString
|
||||
if acceptKey.length > 0 {
|
||||
return true
|
||||
}
|
||||
@ -404,7 +404,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
||||
|
||||
///process the websocket data
|
||||
private func processRawMessage(buffer: UnsafePointer<UInt8>, bufferLen: Int) {
|
||||
var response = readStack.last
|
||||
let response = readStack.last
|
||||
if response != nil && bufferLen < 2 {
|
||||
fragBuffer = NSData(bytes: buffer, length: bufferLen)
|
||||
return
|
||||
@ -420,7 +420,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
||||
resp.bytesLeft -= len
|
||||
resp.buffer?.appendData(NSData(bytes: buffer, length: len))
|
||||
processResponse(resp)
|
||||
var offset = bufferLen - extra
|
||||
let offset = bufferLen - extra
|
||||
if extra > 0 {
|
||||
processExtra((buffer+offset), bufferLen: extra)
|
||||
}
|
||||
@ -459,7 +459,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
||||
if payloadLen == 1 {
|
||||
code = CloseCode.ProtocolError.rawValue
|
||||
} else if payloadLen > 1 {
|
||||
var codeBuffer = UnsafePointer<UInt16>((buffer+offset))
|
||||
let codeBuffer = UnsafePointer<UInt16>((buffer+offset))
|
||||
code = codeBuffer[0].bigEndian
|
||||
if code < 1000 || (code > 1003 && code < 1007) || (code > 1011 && code < 3000) {
|
||||
code = CloseCode.ProtocolError.rawValue
|
||||
@ -470,7 +470,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
||||
let len = Int(payloadLen-2)
|
||||
if len > 0 {
|
||||
let bytes = UnsafePointer<UInt8>((buffer+offset))
|
||||
var str: NSString? = NSString(data: NSData(bytes: bytes, length: len), encoding: NSUTF8StringEncoding)
|
||||
let str: NSString? = NSString(data: NSData(bytes: bytes, length: len), encoding: NSUTF8StringEncoding)
|
||||
if str == nil {
|
||||
code = CloseCode.ProtocolError.rawValue
|
||||
}
|
||||
@ -495,7 +495,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
||||
dataLength = UInt64(bytes[0].bigEndian)
|
||||
offset += sizeof(UInt16)
|
||||
}
|
||||
if bufferLen < offset {
|
||||
if bufferLen < offset || UInt64(bufferLen - offset) < dataLength {
|
||||
fragBuffer = NSData(bytes: buffer, length: bufferLen)
|
||||
return
|
||||
}
|
||||
@ -599,16 +599,16 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
||||
let data = response.buffer! //local copy so it is perverse for writing
|
||||
dequeueWrite(data, code: OpCode.Pong)
|
||||
} else if response.code == .TextFrame {
|
||||
var str: NSString? = NSString(data: response.buffer!, encoding: NSUTF8StringEncoding)
|
||||
let str: NSString? = NSString(data: response.buffer!, encoding: NSUTF8StringEncoding)
|
||||
if str == nil {
|
||||
writeError(CloseCode.Encoding.rawValue)
|
||||
return false
|
||||
}
|
||||
dispatch_async(queue,{
|
||||
if let textBlock = self.onText {
|
||||
textBlock(str! as! String)
|
||||
textBlock(str! as String)
|
||||
}
|
||||
self.delegate?.websocketDidReceiveMessage(self, text: str! as! String)
|
||||
self.delegate?.websocketDidReceiveMessage(self, text: str! as String)
|
||||
})
|
||||
} else if response.code == .BinaryFrame {
|
||||
let data = response.buffer! //local copy so it is perverse for writing
|
||||
@ -635,7 +635,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
||||
///write a an error to the socket
|
||||
private func writeError(code: UInt16) {
|
||||
let buf = NSMutableData(capacity: sizeof(UInt16))
|
||||
var buffer = UnsafeMutablePointer<UInt16>(buf!.bytes)
|
||||
let buffer = UnsafeMutablePointer<UInt16>(buf!.bytes)
|
||||
buffer[0] = code.bigEndian
|
||||
dequeueWrite(NSData(bytes: buffer, length: sizeof(UInt16)), code: .ConnectionClose)
|
||||
}
|
||||
@ -670,17 +670,17 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
||||
buffer[1] = CUnsignedChar(dataLength)
|
||||
} else if dataLength <= Int(UInt16.max) {
|
||||
buffer[1] = 126
|
||||
var sizeBuffer = UnsafeMutablePointer<UInt16>((buffer+offset))
|
||||
let sizeBuffer = UnsafeMutablePointer<UInt16>((buffer+offset))
|
||||
sizeBuffer[0] = UInt16(dataLength).bigEndian
|
||||
offset += sizeof(UInt16)
|
||||
} else {
|
||||
buffer[1] = 127
|
||||
var sizeBuffer = UnsafeMutablePointer<UInt64>((buffer+offset))
|
||||
let sizeBuffer = UnsafeMutablePointer<UInt64>((buffer+offset))
|
||||
sizeBuffer[0] = UInt64(dataLength).bigEndian
|
||||
offset += sizeof(UInt64)
|
||||
}
|
||||
buffer[1] |= self.MaskMask
|
||||
var maskKey = UnsafeMutablePointer<UInt8>(buffer + offset)
|
||||
let maskKey = UnsafeMutablePointer<UInt8>(buffer + offset)
|
||||
SecRandomCopyBytes(kSecRandomDefault, Int(sizeof(UInt32)), maskKey)
|
||||
offset += sizeof(UInt32)
|
||||
|
||||
@ -694,7 +694,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
|
||||
break
|
||||
}
|
||||
let writeBuffer = UnsafePointer<UInt8>(frame!.bytes+total)
|
||||
var len = self.outputStream?.write(writeBuffer, maxLength: offset-total)
|
||||
let len = self.outputStream?.write(writeBuffer, maxLength: offset-total)
|
||||
if len == nil || len! < 0 {
|
||||
var error: NSError?
|
||||
if let streamError = self.outputStream?.streamError {
|
||||
@ -771,8 +771,8 @@ public class SSLCert {
|
||||
}
|
||||
}
|
||||
|
||||
public class Security {
|
||||
public var validatedDN = true //should the domain name be validated?
|
||||
private class Security {
|
||||
private var validatedDN = true //should the domain name be validated?
|
||||
|
||||
var isReady = false //is the key processing done?
|
||||
var certificates: [NSData]? //the certificates
|
||||
@ -786,11 +786,11 @@ public class Security {
|
||||
|
||||
:returns: a representation security object to be used with
|
||||
*/
|
||||
public convenience init(usePublicKeys: Bool = false) {
|
||||
private convenience init(usePublicKeys: Bool = false) {
|
||||
let paths = NSBundle.mainBundle().pathsForResourcesOfType("cer", inDirectory: ".")
|
||||
var collect = Array<SSLCert>()
|
||||
for path in paths {
|
||||
if let d = NSData(contentsOfFile: path as! String) {
|
||||
if let d = NSData(contentsOfFile: path as String) {
|
||||
collect.append(SSLCert(data: d))
|
||||
}
|
||||
}
|
||||
@ -805,7 +805,7 @@ public class Security {
|
||||
|
||||
:returns: a representation security object to be used with
|
||||
*/
|
||||
public init(certs: [SSLCert], usePublicKeys: Bool) {
|
||||
private init(certs: [SSLCert], usePublicKeys: Bool) {
|
||||
self.usePublicKeys = usePublicKeys
|
||||
|
||||
if self.usePublicKeys {
|
||||
@ -842,7 +842,7 @@ public class Security {
|
||||
|
||||
:returns: if the key was successfully validated
|
||||
*/
|
||||
public func isValid(trust: SecTrustRef, domain: String?) -> Bool {
|
||||
private func isValid(trust: SecTrustRef, domain: String?) -> Bool {
|
||||
|
||||
var tries = 0
|
||||
while(!self.isReady) {
|
||||
@ -854,9 +854,9 @@ public class Security {
|
||||
}
|
||||
var policy: SecPolicyRef
|
||||
if self.validatedDN {
|
||||
policy = SecPolicyCreateSSL(1, domain).takeRetainedValue()
|
||||
policy = SecPolicyCreateSSL(true, domain)
|
||||
} else {
|
||||
policy = SecPolicyCreateBasicX509().takeRetainedValue()
|
||||
policy = SecPolicyCreateBasicX509()
|
||||
}
|
||||
SecTrustSetPolicies(trust,policy)
|
||||
if self.usePublicKeys {
|
||||
@ -879,7 +879,7 @@ public class Security {
|
||||
let serverCerts = certificateChainForTrust(trust)
|
||||
var collect = Array<SecCertificate>()
|
||||
for cert in certs {
|
||||
collect.append(SecCertificateCreateWithData(nil,cert).takeRetainedValue())
|
||||
collect.append(SecCertificateCreateWithData(nil,cert)!)
|
||||
}
|
||||
SecTrustSetAnchorCertificates(trust,collect)
|
||||
var result: SecTrustResultType = 0
|
||||
@ -911,10 +911,9 @@ public class Security {
|
||||
:returns: a public key
|
||||
*/
|
||||
func extractPublicKey(data: NSData) -> SecKeyRef? {
|
||||
var publicKey: NSData?
|
||||
let possibleCert = SecCertificateCreateWithData(nil,data)
|
||||
if let cert = possibleCert {
|
||||
return extractPublicKeyFromCert(cert.takeRetainedValue(),policy: SecPolicyCreateBasicX509().takeRetainedValue())
|
||||
return extractPublicKeyFromCert(cert,policy: SecPolicyCreateBasicX509())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -927,13 +926,12 @@ public class Security {
|
||||
:returns: a public key
|
||||
*/
|
||||
func extractPublicKeyFromCert(cert: SecCertificate, policy: SecPolicy) -> SecKeyRef? {
|
||||
var possibleTrust: Unmanaged<SecTrust>?
|
||||
SecTrustCreateWithCertificates(cert,policy, &possibleTrust)
|
||||
if let trust = possibleTrust {
|
||||
let t = trust.takeRetainedValue()
|
||||
let possibleTrust = UnsafeMutablePointer<SecTrust?>.alloc(1)
|
||||
SecTrustCreateWithCertificates( cert, policy, possibleTrust)
|
||||
if let trust = possibleTrust.memory {
|
||||
var result: SecTrustResultType = 0
|
||||
SecTrustEvaluate(t,&result)
|
||||
return SecTrustCopyPublicKey(t).takeRetainedValue()
|
||||
SecTrustEvaluate(trust,&result)
|
||||
return SecTrustCopyPublicKey(trust)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -949,7 +947,7 @@ public class Security {
|
||||
var collect = Array<NSData>()
|
||||
for var i = 0; i < SecTrustGetCertificateCount(trust); i++ {
|
||||
let cert = SecTrustGetCertificateAtIndex(trust,i)
|
||||
collect.append(SecCertificateCopyData(cert.takeRetainedValue()).takeRetainedValue())
|
||||
collect.append(SecCertificateCopyData(cert!))
|
||||
}
|
||||
return collect
|
||||
}
|
||||
@ -963,10 +961,10 @@ public class Security {
|
||||
*/
|
||||
func publicKeyChainForTrust(trust: SecTrustRef) -> Array<SecKeyRef> {
|
||||
var collect = Array<SecKeyRef>()
|
||||
let policy = SecPolicyCreateBasicX509().takeRetainedValue()
|
||||
let policy = SecPolicyCreateBasicX509()
|
||||
for var i = 0; i < SecTrustGetCertificateCount(trust); i++ {
|
||||
let cert = SecTrustGetCertificateAtIndex(trust,i)
|
||||
if let key = extractPublicKeyFromCert(cert.takeRetainedValue(), policy: policy) {
|
||||
if let key = extractPublicKeyFromCert(cert!, policy: policy) {
|
||||
collect.append(key)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user