Merge branch 'socketio/swift-2'

This commit is contained in:
Lukas Schmidt 2015-08-31 20:58:07 +02:00
commit 80d7622095
33 changed files with 1941 additions and 974 deletions

3
.gitignore vendored
View File

@ -1,6 +1,7 @@
.DS_Store .DS_Store
.AppleDouble .AppleDouble
.LSOverride .LSOverride
*.xcodeproj
# Icon must end with two \r # Icon must end with two \r
Icon Icon
@ -41,3 +42,5 @@ DerivedData
*.hmap *.hmap
*.ipa *.ipa
*.xcuserstate *.xcuserstate
Socket.IO-Test-Server/node_modules/*

View File

@ -11,7 +11,7 @@ socket.on("connect") {data, ack in
socket.on("currentAmount") {data, ack in socket.on("currentAmount") {data, ack in
if let cur = data?[0] as? Double { 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]) socket.emit("update", ["amount": cur + 2.50])
} }
@ -26,11 +26,11 @@ socket.connect()
```objective-c ```objective-c
SocketIOClient* socket = [[SocketIOClient alloc] initWithSocketURL:@"localhost:8080" options:nil]; 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"); 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]; double cur = [[data objectAtIndex:0] floatValue];
[socket emitWithAck:@"canUpdate" withItems:@[@(cur)]](0, ^(NSArray* data) { [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 - Can be used from Objective-C
##Installation ##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) If you need Swift 1.1/Xcode 6.2 use v1.5.2. (Pre-Swift 1.2 support is no longer maintained)
Carthage Carthage
----------------- -----------------
Add this line to your `Cartfile`: 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`. Run `carthage update`.
@ -79,7 +80,7 @@ source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0' platform :ios, '8.0'
use_frameworks! use_frameworks!
pod 'Socket.IO-Client-Swift', '~> 2.3.10' # Or latest version pod 'Socket.IO-Client-Swift', '~> 2.4.3' # Or latest version
``` ```
Install pods: 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. - `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 `""` - `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. - `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 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. 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. 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. `emit(event:String, _ items:AnyObject...)` - Sends a message. Can send multiple items. 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, withItems items:[AnyObject])` - `emit` for Objective-C 4. `emit(event:String, _ items:AnyObject...)` - Sends a message. Can send multiple items.
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. 5. `emit(event:String, withItems items:[AnyObject])` - `emit` for Objective-C
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. 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. `connect()` - Establishes a connection to the server. A "connect" event is fired upon successful connection. 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(#timeoutAfter:Int, withTimeoutHandler handler:(() -> Void)?)` - Connect to the server. If it isn't connected after timeoutAfter seconds, the handler is called. 8. `connect()` - Establishes a connection to the server. A "connect" event is fired upon successful connection.
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. 9. `connect(#timeoutAfter:Int, withTimeoutHandler handler:(() -> Void)?)` - Connect to the server. If it isn't connected after timeoutAfter seconds, the handler is called.
10. `reconnect()` - Causes the client to reconnect to the server. 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. `joinNamespace()` - Causes the client to join nsp. Shouldn't need to be called unless you change nsp manually. 11. `reconnect()` - Causes the client to reconnect to the server.
12. `leaveNamespace()` - Causes the client to leave the nsp and go back to / 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 Client Events
------ ------

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = "Socket.IO-Client-Swift" 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.summary = "Socket.IO-client for iOS and OS X"
s.description = <<-DESC s.description = <<-DESC
Socket.IO-client for iOS and OS X. Socket.IO-client for iOS and OS X.
@ -12,7 +12,7 @@ Pod::Spec.new do |s|
s.author = { "Erik" => "nuclear.ace@gmail.com" } s.author = { "Erik" => "nuclear.ace@gmail.com" }
s.ios.deployment_target = '8.0' s.ios.deployment_target = '8.0'
s.osx.deployment_target = '10.10' s.osx.deployment_target = '10.10'
s.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.source_files = "SocketIOClientSwift/**/*.swift"
s.requires_arc = true s.requires_arc = true
# s.dependency 'Starscream', '~> 0.9' # currently this repo includes Starscream swift files # s.dependency 'Starscream', '~> 0.9' # currently this repo includes Starscream swift files

View File

@ -9,7 +9,6 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
572EF21F1B51F16C00EEBB58 /* SocketIO-iOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 572EF21E1B51F16C00EEBB58 /* SocketIO-iOS.h */; settings = {ATTRIBUTES = (Public, ); }; }; 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 */; }; 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, ); }; }; 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 */; }; 572EF2431B51F18A00EEBB58 /* SocketIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 572EF2381B51F18A00EEBB58 /* SocketIO.framework */; };
572EF24A1B51F18A00EEBB58 /* SocketIO_MacTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 572EF2491B51F18A00EEBB58 /* SocketIO_MacTests.swift */; }; 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 */; }; 5764DFA01B51F254004FF46E /* SwiftRegex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF871B51F254004FF46E /* SwiftRegex.swift */; };
5764DFA11B51F254004FF46E /* WebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF881B51F254004FF46E /* WebSocket.swift */; }; 5764DFA11B51F254004FF46E /* WebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF881B51F254004FF46E /* WebSocket.swift */; };
5764DFA21B51F254004FF46E /* 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 */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
@ -64,7 +87,6 @@
572EF21E1B51F16C00EEBB58 /* SocketIO-iOS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SocketIO-iOS.h"; sourceTree = "<group>"; }; 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; }; 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>"; }; 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; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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 */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@ -163,7 +193,13 @@
572EF2281B51F16C00EEBB58 /* SocketIO-iOSTests */ = { 572EF2281B51F16C00EEBB58 /* SocketIO-iOSTests */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( 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 */, 572EF2291B51F16C00EEBB58 /* Supporting Files */,
); );
path = "SocketIO-iOSTests"; path = "SocketIO-iOSTests";
@ -221,6 +257,7 @@
5764DF801B51F254004FF46E /* SocketEventHandler.swift */, 5764DF801B51F254004FF46E /* SocketEventHandler.swift */,
5764DF811B51F254004FF46E /* SocketFixUTF8.swift */, 5764DF811B51F254004FF46E /* SocketFixUTF8.swift */,
5764DF821B51F254004FF46E /* SocketIOClient.swift */, 5764DF821B51F254004FF46E /* SocketIOClient.swift */,
74781D591B7E83930042CACA /* SocketIOClientStatus.swift */,
5764DF831B51F254004FF46E /* SocketLogger.swift */, 5764DF831B51F254004FF46E /* SocketLogger.swift */,
5764DF841B51F254004FF46E /* SocketPacket.swift */, 5764DF841B51F254004FF46E /* SocketPacket.swift */,
5764DF851B51F254004FF46E /* SocketParser.swift */, 5764DF851B51F254004FF46E /* SocketParser.swift */,
@ -413,6 +450,7 @@
5764DF951B51F254004FF46E /* SocketIOClient.swift in Sources */, 5764DF951B51F254004FF46E /* SocketIOClient.swift in Sources */,
5764DF8B1B51F254004FF46E /* SocketAnyEvent.swift in Sources */, 5764DF8B1B51F254004FF46E /* SocketAnyEvent.swift in Sources */,
5764DF971B51F254004FF46E /* SocketLogger.swift in Sources */, 5764DF971B51F254004FF46E /* SocketLogger.swift in Sources */,
74781D5A1B7E83930042CACA /* SocketIOClientStatus.swift in Sources */,
5764DFA11B51F254004FF46E /* WebSocket.swift in Sources */, 5764DFA11B51F254004FF46E /* WebSocket.swift in Sources */,
5764DF991B51F254004FF46E /* SocketPacket.swift in Sources */, 5764DF991B51F254004FF46E /* SocketPacket.swift in Sources */,
5764DF891B51F254004FF46E /* SocketAckManager.swift in Sources */, 5764DF891B51F254004FF46E /* SocketAckManager.swift in Sources */,
@ -424,7 +462,27 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( 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; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -441,6 +499,7 @@
5764DF961B51F254004FF46E /* SocketIOClient.swift in Sources */, 5764DF961B51F254004FF46E /* SocketIOClient.swift in Sources */,
5764DF8C1B51F254004FF46E /* SocketAnyEvent.swift in Sources */, 5764DF8C1B51F254004FF46E /* SocketAnyEvent.swift in Sources */,
5764DF981B51F254004FF46E /* SocketLogger.swift in Sources */, 5764DF981B51F254004FF46E /* SocketLogger.swift in Sources */,
74781D5C1B7E83930042CACA /* SocketIOClientStatus.swift in Sources */,
5764DFA21B51F254004FF46E /* WebSocket.swift in Sources */, 5764DFA21B51F254004FF46E /* WebSocket.swift in Sources */,
5764DF9A1B51F254004FF46E /* SocketPacket.swift in Sources */, 5764DF9A1B51F254004FF46E /* SocketPacket.swift in Sources */,
5764DF8A1B51F254004FF46E /* SocketAckManager.swift in Sources */, 5764DF8A1B51F254004FF46E /* SocketAckManager.swift in Sources */,
@ -453,6 +512,7 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
572EF24A1B51F18A00EEBB58 /* SocketIO_MacTests.swift in Sources */, 572EF24A1B51F18A00EEBB58 /* SocketIO_MacTests.swift in Sources */,
74781D5D1B7E83930042CACA /* SocketIOClientStatus.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -485,7 +545,7 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
PRODUCT_NAME = SocketIO; PRODUCT_NAME = SocketIO;
SWIFT_WHOLE_MODULE_OPTIMIZATION = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
}; };
name = Release; name = Release;
}; };

View File

@ -37,10 +37,11 @@
</BuildActionEntries> </BuildActionEntries>
</BuildAction> </BuildAction>
<TestAction <TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES" shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug"> codeCoverageEnabled = "YES">
<Testables> <Testables>
<TestableReference <TestableReference
skipped = "NO"> skipped = "NO">
@ -62,15 +63,18 @@
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj"> ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
</BuildableReference> </BuildableReference>
</MacroExpansion> </MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction> </TestAction>
<LaunchAction <LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0" launchStyle = "0"
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES" debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES"> allowLocationSimulation = "YES">
<MacroExpansion> <MacroExpansion>
<BuildableReference <BuildableReference
@ -85,10 +89,10 @@
</AdditionalOptions> </AdditionalOptions>
</LaunchAction> </LaunchAction>
<ProfileAction <ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES" shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = "" savedToolIdentifier = ""
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
debugDocumentVersioning = "YES"> debugDocumentVersioning = "YES">
<MacroExpansion> <MacroExpansion>
<BuildableReference <BuildableReference

View 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")]
}
}

View 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

View 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

View 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")

View 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"
}
}

View 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

View 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)
}
}

View 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)
}
}

View 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)
}
}

View File

@ -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.
}
}
}

View 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)
}
}

View 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)
}
}

View 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)
}
}

View 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
}

View File

@ -1,6 +1,6 @@
// //
// SocketAckManager.swift // SocketAckManager.swift
// SocketIO-Swift // Socket.IO-Client-Swift
// //
// Created by Erik Little on 4/3/15. // Created by Erik Little on 4/3/15.
// //
@ -25,38 +25,38 @@
import Foundation import Foundation
private struct SocketAck: Hashable, Equatable { private struct SocketAck: Hashable, Equatable {
let ack:Int let ack: Int
var callback:AckCallback! var callback: AckCallback!
var hashValue:Int { var hashValue: Int {
return ack.hashValue return ack.hashValue
} }
init(ack:Int) { init(ack: Int) {
self.ack = ack self.ack = ack
} }
init(ack:Int, callback:AckCallback) { init(ack: Int, callback: AckCallback) {
self.ack = ack self.ack = ack
self.callback = callback self.callback = callback
} }
} }
private func <(lhs:SocketAck, rhs:SocketAck) -> Bool { private func <(lhs: SocketAck, rhs: SocketAck) -> Bool {
return lhs.ack < rhs.ack return lhs.ack < rhs.ack
} }
private func ==(lhs:SocketAck, rhs:SocketAck) -> Bool { private func ==(lhs: SocketAck, rhs: SocketAck) -> Bool {
return lhs.ack == rhs.ack return lhs.ack == rhs.ack
} }
struct SocketAckManager { struct SocketAckManager {
private var acks = Set<SocketAck>(minimumCapacity: 1) 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)) 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)) let callback = acks.remove(SocketAck(ack: ack))
dispatch_async(dispatch_get_main_queue()) { 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)) let callback = acks.remove(SocketAck(ack: ack))
dispatch_async(dispatch_get_main_queue()) { dispatch_async(dispatch_get_main_queue()) {

View File

@ -1,6 +1,6 @@
// //
// SocketAnyEvent.swift // SocketAnyEvent.swift
// Socket.IO-Swift // Socket.IO-Client-Swift
// //
// Created by Erik Little on 3/28/15. // Created by Erik Little on 3/28/15.
// //
@ -24,11 +24,14 @@
import Foundation import Foundation
@objc public final class SocketAnyEvent { @objc public final class SocketAnyEvent: NSObject {
public let event:String! public let event: String!
public let items:NSArray? 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.event = event
self.items = items self.items = items
} }

View File

@ -1,6 +1,6 @@
// //
// SocketEngine.swift // SocketEngine.swift
// Socket.IO-Swift // Socket.IO-Client-Swift
// //
// Created by Erik Little on 3/3/15. // Created by Erik Little on 3/3/15.
// //
@ -25,7 +25,7 @@
import Foundation import Foundation
public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient { 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 typealias ProbeWaitQueue = [Probe]
private let allowedCharacterSet = NSCharacterSet(charactersInString: "!*'();:@&=+$,/?%#[]\" {}").invertedSet private let allowedCharacterSet = NSCharacterSet(charactersInString: "!*'();:@&=+$,/?%#[]\" {}").invertedSet
@ -33,16 +33,15 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
private let emitQueue = dispatch_queue_create("engineEmitQueue", DISPATCH_QUEUE_SERIAL) private let emitQueue = dispatch_queue_create("engineEmitQueue", DISPATCH_QUEUE_SERIAL)
private let parseQueue = dispatch_queue_create("engineParseQueue", 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 handleQueue = dispatch_queue_create("engineHandleQueue", DISPATCH_QUEUE_SERIAL)
private let session:NSURLSession! private let session: NSURLSession!
private var closed = false private var closed = false
private var _connected = false private var extraHeaders: [String: String]?
private var extraHeaders:[String: String]?
private var fastUpgrade = false private var fastUpgrade = false
private var forcePolling = false private var forcePolling = false
private var forceWebsockets = false private var forceWebsockets = false
private var pingInterval:Double? private var pingInterval: Double?
private var pingTimer:NSTimer? private var pingTimer: NSTimer?
private var pingTimeout = 0.0 { private var pingTimeout = 0.0 {
didSet { didSet {
pongsMissedMax = Int(pingTimeout / (pingInterval ?? 25)) pongsMissedMax = Int(pingTimeout / (pingInterval ?? 25))
@ -51,45 +50,31 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
private var pongsMissed = 0 private var pongsMissed = 0
private var pongsMissedMax = 0 private var pongsMissedMax = 0
private var postWait = [String]() private var postWait = [String]()
private var _polling = true
private var probing = false private var probing = false
private var probeWait = ProbeWaitQueue() private var probeWait = ProbeWaitQueue()
private var waitingForPoll = false private var waitingForPoll = false
private var waitingForPost = false private var waitingForPost = false
private var _websocket = false
private var websocketConnected = false private var websocketConnected = false
let logType = "SocketEngine" let logType = "SocketEngine"
var connected:Bool { private(set) var connected = false
return _connected private(set) var polling = true
} private(set) var websocket = false
weak var client:SocketEngineClient?
var cookies:[NSHTTPCookie]? weak var client: SocketEngineClient?
var log = false var cookies: [NSHTTPCookie]?
var polling:Bool {
return _polling
}
var sid = "" var sid = ""
var socketPath = "" var socketPath = ""
var urlPolling:String? var urlPolling: String?
var urlWebSocket:String? var urlWebSocket: String?
var websocket:Bool {
return _websocket
}
var ws:WebSocket? var ws:WebSocket?
public enum PacketType:Int { public enum PacketType: Int {
case OPEN = 0 case Open, Close, Ping, Pong, Message, Upgrade, Noop
case CLOSE = 1
case PING = 2
case PONG = 3
case MESSAGE = 4
case UPGRADE = 5
case NOOP = 6
init?(str:String?) { init?(str: String?) {
if let value = str?.toInt(), raw = PacketType(rawValue: value) { if let value = Int(str ?? ""), raw = PacketType(rawValue: value) {
self = raw self = raw
} else { } else {
return nil return nil
@ -97,18 +82,17 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
} }
} }
public init(client:SocketEngineClient, sessionDelegate:NSURLSessionDelegate?) { public init(client: SocketEngineClient, sessionDelegate: NSURLSessionDelegate?) {
self.client = client self.client = client
self.session = NSURLSession(configuration: NSURLSessionConfiguration.ephemeralSessionConfiguration(), self.session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration(),
delegate: sessionDelegate, delegateQueue: workQueue) 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) self.init(client: client, sessionDelegate: opts?["sessionDelegate"] as? NSURLSessionDelegate)
forceWebsockets = opts?["forceWebsockets"] as? Bool ?? false forceWebsockets = opts?["forceWebsockets"] as? Bool ?? false
forcePolling = opts?["forcePolling"] as? Bool ?? false forcePolling = opts?["forcePolling"] as? Bool ?? false
cookies = opts?["cookies"] as? [NSHTTPCookie] cookies = opts?["cookies"] as? [NSHTTPCookie]
log = opts?["log"] as? Bool ?? false
socketPath = opts?["path"] as? String ?? "" socketPath = opts?["path"] as? String ?? ""
extraHeaders = opts?["extraHeaders"] as? [String: String] extraHeaders = opts?["extraHeaders"] as? [String: String]
} }
@ -117,7 +101,7 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
SocketLogger.log("Engine is being deinit", client: self) 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) SocketLogger.log("Engine is being closed. Fast: %@", client: self, args: fast)
pingTimer?.invalidate() pingTimer?.invalidate()
@ -126,18 +110,18 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
ws?.disconnect() ws?.disconnect()
if fast || polling { if fast || polling {
write("", withType: PacketType.CLOSE, withData: nil) write("", withType: PacketType.Close, withData: nil)
client?.engineDidClose("Disconnect") client?.engineDidClose("Disconnect")
} }
stopPolling() stopPolling()
} }
private func createBinaryDataForSend(data:NSData) -> (NSData?, String?) { private func createBinaryDataForSend(data: NSData) -> (NSData?, String?) {
if websocket { if websocket {
var byteArray = [UInt8](count: 1, repeatedValue: 0x0) var byteArray = [UInt8](count: 1, repeatedValue: 0x0)
byteArray[0] = 4 byteArray[0] = 4
var mutData = NSMutableData(bytes: &byteArray, length: 1) let mutData = NSMutableData(bytes: &byteArray, length: 1)
mutData.appendData(data) mutData.appendData(data)
@ -151,16 +135,16 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
} }
} }
private func createURLs(params:[String: AnyObject]?) -> (String?, String?) { private func createURLs(params: [String: AnyObject]?) -> (String?, String?) {
if client == nil { if client == nil {
return (nil, nil) return (nil, nil)
} }
let path = socketPath == "" ? "/socket.io" : socketPath let path = socketPath == "" ? "/socket.io" : socketPath
var url = "\(client!.socketURL)\(path)/?transport=" let url = "\(client!.socketURL)\(path)/?transport="
var urlPolling:String var urlPolling: String
var urlWebSocket:String var urlWebSocket: String
if client!.secure { if client!.secure {
urlPolling = "https://" + url + "polling" urlPolling = "https://" + url + "polling"
@ -193,7 +177,7 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
return (urlPolling, urlWebSocket) return (urlPolling, urlWebSocket)
} }
private func createWebsocket(andConnect connect:Bool) { private func createWebsocket(andConnect connect: Bool) {
let wsUrl = urlWebSocket! + (sid == "" ? "" : "&sid=\(sid)") let wsUrl = urlWebSocket! + (sid == "" ? "" : "&sid=\(sid)")
ws = WebSocket(url: NSURL(string: wsUrl)!, ws = WebSocket(url: NSURL(string: wsUrl)!,
@ -219,9 +203,9 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
"we'll probably disconnect soon. You should report this.", client: self) "we'll probably disconnect soon. You should report this.", client: self)
} }
sendWebSocketMessage("", withType: PacketType.UPGRADE, datas: nil) sendWebSocketMessage("", withType: PacketType.Upgrade, datas: nil)
_websocket = true websocket = true
_polling = false polling = false
fastUpgrade = false fastUpgrade = false
probing = false probing = false
flushProbeWait() flushProbeWait()
@ -249,7 +233,7 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
doRequest(req) doRequest(req)
} }
private func doRequest(req:NSMutableURLRequest) { private func doRequest(req: NSMutableURLRequest) {
if !polling { if !polling {
return return
} }
@ -260,18 +244,18 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
session.dataTaskWithRequest(req) {[weak self] data, res, err in session.dataTaskWithRequest(req) {[weak self] data, res, err in
if let this = self { if let this = self {
if err != nil { if err != nil || data == nil {
if this.polling { if this.polling {
this.handlePollingFailed(err.localizedDescription) this.handlePollingFailed(err?.localizedDescription ?? "Error")
} else { } else {
SocketLogger.err(err.localizedDescription, client: this) SocketLogger.err(err?.localizedDescription ?? "Error", client: this)
} }
return return
} }
SocketLogger.log("Got polling response", client: this) 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 dispatch_async(this.parseQueue) {[weak this] in
this?.parsePollingMessage(str) this?.parsePollingMessage(str)
} }
@ -316,7 +300,7 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
var postStr = "" var postStr = ""
for packet in postWait { for packet in postWait {
let len = count(packet) let len = packet.characters.count
postStr += "\(len):\(packet)" postStr += "\(len):\(packet)"
} }
@ -325,8 +309,8 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
let req = NSMutableURLRequest(URL: NSURL(string: urlPolling! + "&sid=\(sid)")!) let req = NSMutableURLRequest(URL: NSURL(string: urlPolling! + "&sid=\(sid)")!)
if cookies != nil { if let cookies = cookies {
let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies!) let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies)
req.allHTTPHeaderFields = headers req.allHTTPHeaderFields = headers
} }
@ -346,10 +330,10 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
session.dataTaskWithRequest(req) {[weak self] data, res, err in session.dataTaskWithRequest(req) {[weak self] data, res, err in
if let this = self { if let this = self {
if err != nil && this.polling { if err != nil && this.polling {
this.handlePollingFailed(err.localizedDescription) this.handlePollingFailed(err?.localizedDescription ?? "Error")
return return
} else if err != nil { } else if err != nil {
NSLog(err.localizedDescription) NSLog(err?.localizedDescription ?? "Error")
return return
} }
@ -375,58 +359,60 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
} }
private func handleClose() { private func handleClose() {
if polling { if let client = client where polling == true {
client?.engineDidClose("Disconnect") client.engineDidClose("Disconnect")
} }
} }
private func checkIfMessageIsBase64Binary(var message:String) { private func checkIfMessageIsBase64Binary(var message: String) {
if message.hasPrefix("b4") { if message.hasPrefix("b4") {
// binary in base64 string // binary in base64 string
message.removeRange(Range<String.Index>(start: message.startIndex, message.removeRange(Range<String.Index>(start: message.startIndex,
end: advance(message.startIndex, 2))) end: message.startIndex.advancedBy(2)))
if let data = NSData(base64EncodedString: message, if let data = NSData(base64EncodedString: message,
options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters), client = client { options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters) {
dispatch_async(client.handleQueue) {[weak self] in client?.parseBinaryData(data)
self?.client?.parseBinaryData(data)
}
} }
} }
} }
private func handleMessage(message:String) { private func handleMessage(message: String) {
if let client = client { client?.parseSocketMessage(message)
dispatch_async(client.handleQueue) {[weak client] in
client?.parseSocketMessage(message)
}
}
} }
private func handleNOOP() { private func handleNOOP() {
doPoll() doPoll()
} }
private func handleOpen(openData:String) { private func handleOpen(openData: String) {
var err:NSError?
let mesData = openData.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! let mesData = openData.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
do {
let json = try NSJSONSerialization.JSONObjectWithData(mesData,
options: NSJSONReadingOptions.AllowFragments) as? NSDictionary
if let sid = json?["sid"] as? String {
let upgradeWs: Bool
if let json = NSJSONSerialization.JSONObjectWithData(mesData,
options: NSJSONReadingOptions.AllowFragments,
error: &err) as? NSDictionary, sid = json["sid"] as? String {
self.sid = sid self.sid = sid
_connected = true connected = true
if !forcePolling && !forceWebsockets { if let upgrades = json?["upgrades"] as? [String] {
createWebsocket(andConnect: true) 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.pingInterval = pingInterval / 1000.0
self.pingTimeout = pingTimeout / 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 return
} }
@ -437,7 +423,7 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
} }
} }
private func handlePong(pongMessage:String) { private func handlePong(pongMessage: String) {
pongsMissed = 0 pongsMissed = 0
// We should upgrade // We should upgrade
@ -447,8 +433,8 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
} }
// A poll failed, tell the client about it // A poll failed, tell the client about it
private func handlePollingFailed(reason:String) { private func handlePollingFailed(reason: String) {
_connected = false connected = false
ws?.disconnect() ws?.disconnect()
pingTimer?.invalidate() pingTimer?.invalidate()
waitingForPoll = false waitingForPoll = false
@ -465,11 +451,11 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
} }
} }
public func open(opts:[String: AnyObject]? = nil) { public func open(opts: [String: AnyObject]? = nil) {
if connected { if connected {
SocketLogger.err("Tried to open while connected", client: self) SocketLogger.err("Tried to open while connected", client: self)
client?.didError("Tried to open while connected") client?.didError("Tried to open while connected")
return return
} }
@ -481,8 +467,8 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
(urlPolling, urlWebSocket) = createURLs(opts) (urlPolling, urlWebSocket) = createURLs(opts)
if forceWebsockets { if forceWebsockets {
_polling = false polling = false
_websocket = true websocket = true
createWebsocket(andConnect: true) createWebsocket(andConnect: true)
return return
} }
@ -494,8 +480,8 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
reqPolling.allHTTPHeaderFields = headers reqPolling.allHTTPHeaderFields = headers
} }
if extraHeaders != nil { if let extraHeaders = extraHeaders {
for (headerName, value) in extraHeaders! { for (headerName, value) in extraHeaders {
reqPolling.setValue(value, forHTTPHeaderField: headerName) reqPolling.setValue(value, forHTTPHeaderField: headerName)
} }
} }
@ -505,19 +491,18 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
// Translatation of engine.io-parser#decodePayload // Translatation of engine.io-parser#decodePayload
private func parsePollingMessage(str:String) { private func parsePollingMessage(str:String) {
if count(str) == 1 { guard str.characters.count != 1 else {
return return
} }
// println(str) // println(str)
let strArray = Array(str) let strArray = Array(str.characters)
var length = "" var length = ""
var n = 0 var n = 0
var msg = "" var msg = ""
func testLength(length:String, inout n:Int) -> Bool { func testLength(length:String, inout n:Int) -> Bool {
if let num = length.toInt() { if let num = Int(length) {
n = num n = num
return false return false
} else { } else {
@ -525,13 +510,13 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
} }
} }
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]) let chr = String(strArray[i])
if chr != ":" { if chr != ":" {
length += chr length += chr
} else { } else {
if length == "" || testLength(length, &n) { if length == "" || testLength(length, n: &n) {
SocketLogger.err("Parsing error: %@", client: self, args: str) SocketLogger.err("Parsing error: %@", client: self, args: str)
handlePollingFailed("Error parsing XHR message") handlePollingFailed("Error parsing XHR message")
return return
@ -539,12 +524,12 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
msg = String(strArray[i+1...i+n]) 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) SocketLogger.err("Parsing error: %@", client: self, args: str)
return return
} }
if count(msg) != 0 { if msg.characters.count != 0 {
// Be sure to capture the value of the msg // Be sure to capture the value of the msg
dispatch_async(handleQueue) {[weak self, msg] in dispatch_async(handleQueue) {[weak self, msg] in
self?.parseEngineMessage(msg, fromPolling: true) self?.parseEngineMessage(msg, fromPolling: true)
@ -557,15 +542,11 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
} }
} }
private func parseEngineData(data:NSData) { private func parseEngineData(data: NSData) {
if let client = client { client?.parseBinaryData(data.subdataWithRange(NSMakeRange(1, data.length - 1)))
dispatch_async(client.handleQueue) {[weak self] in
self?.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) SocketLogger.log("Got message: %@", client: self, args: message)
if fromPolling { if fromPolling {
@ -574,21 +555,21 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
let type = PacketType(str: (message["^(\\d)"].groups()?[1])) ?? { let type = PacketType(str: (message["^(\\d)"].groups()?[1])) ?? {
self.checkIfMessageIsBase64Binary(message) self.checkIfMessageIsBase64Binary(message)
return PacketType.NOOP return PacketType.Noop
}() }()
switch type { switch type {
case PacketType.MESSAGE: case PacketType.Message:
message.removeAtIndex(message.startIndex) message.removeAtIndex(message.startIndex)
handleMessage(message) handleMessage(message)
case PacketType.NOOP: case PacketType.Noop:
handleNOOP() handleNOOP()
case PacketType.PONG: case PacketType.Pong:
handlePong(message) handlePong(message)
case PacketType.OPEN: case PacketType.Open:
message.removeAtIndex(message.startIndex) message.removeAtIndex(message.startIndex)
handleOpen(message) handleOpen(message)
case PacketType.CLOSE: case PacketType.Close:
handleClose() handleClose()
default: default:
SocketLogger.log("Got unknown packet type", client: self) SocketLogger.log("Got unknown packet type", client: self)
@ -597,16 +578,16 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
private func probeWebSocket() { private func probeWebSocket() {
if websocketConnected { if websocketConnected {
sendWebSocketMessage("probe", withType: PacketType.PING) sendWebSocketMessage("probe", withType: PacketType.Ping)
} }
} }
/// Send an engine message (4) /// Send an engine message (4)
public func send(msg:String, withData datas:ContiguousArray<NSData>?) { public func send(msg: String, withData datas: [NSData]?) {
if probing { if probing {
probeWait.append((msg, PacketType.MESSAGE, datas)) probeWait.append((msg, PacketType.Message, datas))
} else { } else {
write(msg, withType: PacketType.MESSAGE, withData: datas) write(msg, withType: PacketType.Message, withData: datas)
} }
} }
@ -619,13 +600,13 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
} }
++pongsMissed ++pongsMissed
write("", withType: PacketType.PING, withData: nil) write("", withType: PacketType.Ping, withData: nil)
} }
/// Send polling message. /// Send polling message.
/// Only call on emitQueue /// Only call on emitQueue
private func sendPollMessage(var msg:String, withType type:PacketType, private func sendPollMessage(var msg: String, withType type: PacketType,
datas:ContiguousArray<NSData>? = nil) { datas:[NSData]? = nil) {
SocketLogger.log("Sending poll: %@ as type: %@", client: self, args: msg, type.rawValue) SocketLogger.log("Sending poll: %@ as type: %@", client: self, args: msg, type.rawValue)
doubleEncodeUTF8(&msg) doubleEncodeUTF8(&msg)
@ -633,9 +614,9 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
postWait.append(strMsg) postWait.append(strMsg)
if datas != nil { if let datas = datas {
for data in datas! { for data in datas {
let (nilData, b64Data) = createBinaryDataForSend(data) let (_, b64Data) = createBinaryDataForSend(data)
postWait.append(b64Data!) postWait.append(b64Data!)
} }
@ -648,15 +629,15 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
/// Send message on WebSockets /// Send message on WebSockets
/// Only call on emitQueue /// Only call on emitQueue
private func sendWebSocketMessage(str:String, withType type:PacketType, private func sendWebSocketMessage(str: String, withType type: PacketType,
datas:ContiguousArray<NSData>? = nil) { datas:[NSData]? = nil) {
SocketLogger.log("Sending ws: %@ as type: %@", client: self, args: str, type.rawValue) SocketLogger.log("Sending ws: %@ as type: %@", client: self, args: str, type.rawValue)
ws?.writeString("\(type.rawValue)\(str)") ws?.writeString("\(type.rawValue)\(str)")
if datas != nil { if let datas = datas {
for data in datas! { for data in datas {
let (data, nilString) = createBinaryDataForSend(data) let (data, _) = createBinaryDataForSend(data)
if data != nil { if data != nil {
ws?.writeData(data!) ws?.writeData(data!)
} }
@ -666,7 +647,7 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
// Starts the ping timer // Starts the ping timer
private func startPingTimer() { private func startPingTimer() {
if pingInterval == nil { guard pingInterval != nil else {
return return
} }
@ -688,7 +669,7 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
SocketLogger.log("Upgrading transport to WebSockets", client: self) SocketLogger.log("Upgrading transport to WebSockets", client: self)
fastUpgrade = true fastUpgrade = true
sendPollMessage("", withType: PacketType.NOOP) sendPollMessage("", withType: PacketType.Noop)
// After this point, we should not send anymore polling messages // After this point, we should not send anymore polling messages
} }
} }
@ -696,7 +677,7 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
/** /**
Write a message, independent of transport. 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 dispatch_async(emitQueue) {[weak self] in
if let this = self where this.connected { if let this = self where this.connected {
if this.websocket { if this.websocket {
@ -715,12 +696,12 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
/** /**
Write a message, independent of transport. For Objective-C. withData should be an NSArray of NSData 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) { if let pType = PacketType(rawValue: type) {
var arr = ContiguousArray<NSData>() var arr = [NSData]()
if data != nil { if let data = data {
for d in data! { for d in data {
arr.append(d as! NSData) arr.append(d as! NSData)
} }
} }
@ -738,13 +719,13 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
probing = true probing = true
probeWebSocket() probeWebSocket()
} else { } else {
_connected = true connected = true
probing = false probing = false
_polling = false polling = false
} }
} }
public func websocketDidDisconnect(socket:WebSocket, error:NSError?) { public func websocketDidDisconnect(socket: WebSocket, error: NSError?) {
websocketConnected = false websocketConnected = false
probing = false probing = false
@ -755,8 +736,8 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
if websocket { if websocket {
pingTimer?.invalidate() pingTimer?.invalidate()
_connected = false connected = false
_websocket = false websocket = false
let reason = error?.localizedDescription ?? "Socket Disconnected" let reason = error?.localizedDescription ?? "Socket Disconnected"
@ -770,11 +751,11 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
} }
} }
public func websocketDidReceiveMessage(socket:WebSocket, text:String) { public func websocketDidReceiveMessage(socket: WebSocket, text: String) {
parseEngineMessage(text, fromPolling: false) parseEngineMessage(text, fromPolling: false)
} }
public func websocketDidReceiveData(socket:WebSocket, data:NSData) { public func websocketDidReceiveData(socket: WebSocket, data: NSData) {
parseEngineData(data) parseEngineData(data)
} }
} }

View File

@ -1,6 +1,6 @@
// //
// SocketEngineClient.swift // SocketEngineClient.swift
// Socket.IO-Swift // Socket.IO-Client-Swift
// //
// Created by Erik Little on 3/19/15. // Created by Erik Little on 3/19/15.
// //
@ -26,12 +26,11 @@
import Foundation import Foundation
@objc public protocol SocketEngineClient { @objc public protocol SocketEngineClient {
var handleQueue:dispatch_queue_attr_t! {get} var socketURL: String {get}
var socketURL:String {get} var secure: Bool {get}
var secure:Bool {get}
func didError(reason:AnyObject) func didError(reason: AnyObject)
func engineDidClose(reason:String) func engineDidClose(reason: String)
func parseSocketMessage(msg:String) func parseSocketMessage(msg: String)
func parseBinaryData(data:NSData) func parseBinaryData(data: NSData)
} }

View File

@ -1,6 +1,6 @@
// //
// EventHandler.swift // EventHandler.swift
// Socket.IO-Swift // Socket.IO-Client-Swift
// //
// Created by Erik Little on 1/18/15. // Created by Erik Little on 1/18/15.
// //
@ -24,24 +24,37 @@
import Foundation import Foundation
private func emitAckCallback(socket:SocketIOClient, num:Int) private func emitAckCallback(socket: SocketIOClient?, num: Int?)
(items:AnyObject...) -> Void { (items: AnyObject...) -> Void {
socket.emitAck(num, withData: items) socket?.emitAck(num ?? -1, withItems: items)
} }
final class SocketEventHandler { private func emitAckCallbackObjectiveC(socket: SocketIOClient?, num: Int?)
let event:String! (items: NSArray) -> Void {
let callback:NormalCallback? socket?.emitAck(num ?? -1, withItems: items as [AnyObject])
}
init(event:String, callback:NormalCallback) { struct SocketEventHandler {
let event: String
let callback: NormalCallback?
let callBackObjectiveC: NormalCallbackObjectiveC?
init(event: String, callback: NormalCallback) {
self.event = event self.event = event
self.callback = callback 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) { withSocket socket:SocketIOClient? = nil) {
dispatch_async(dispatch_get_main_queue()) {[weak self] in self.callback != nil ?
self?.callback?(items, ack != nil ? emitAckCallback(socket!, ack!) : nil) self.callback?(items, emitAckCallback(socket, num: ack))
} : self.callBackObjectiveC?(items, emitAckCallbackObjectiveC(socket, num: ack))
} }
} }

View File

@ -1,6 +1,6 @@
// //
// SocketFixUTF8.swift // SocketFixUTF8.swift
// Socket.IO-Swift // Socket.IO-Client-Swift
// //
// Created by Erik Little on 3/16/15. // Created by Erik Little on 3/16/15.
// //
@ -25,13 +25,13 @@
import Foundation import Foundation
func fixDoubleUTF8(inout name:String) { func fixDoubleUTF8(inout name: String) {
let utf8 = name.dataUsingEncoding(NSISOLatin1StringEncoding)! let utf8 = name.dataUsingEncoding(NSISOLatin1StringEncoding)!
let latin1 = NSString(data: utf8, encoding: NSUTF8StringEncoding)! let latin1 = NSString(data: utf8, encoding: NSUTF8StringEncoding)!
name = latin1 as String name = latin1 as String
} }
func doubleEncodeUTF8(inout str:String) { func doubleEncodeUTF8(inout str: String) {
let latin1 = str.dataUsingEncoding(NSUTF8StringEncoding)! let latin1 = str.dataUsingEncoding(NSUTF8StringEncoding)!
let utf8 = NSString(data: latin1, encoding: NSISOLatin1StringEncoding)! let utf8 = NSString(data: latin1, encoding: NSISOLatin1StringEncoding)!
str = utf8 as String str = utf8 as String

View File

@ -1,6 +1,6 @@
// //
// SocketIOClient.swift // SocketIOClient.swift
// Socket.IO-Swift // Socket.IO-Client-Swift
// //
// Created by Erik Little on 11/23/14. // Created by Erik Little on 11/23/14.
// //
@ -25,59 +25,40 @@
import Foundation import Foundation
public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient { public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient {
private var anyHandler:((SocketAnyEvent) -> Void)? private var anyHandler: ((SocketAnyEvent) -> Void)?
private var _closed = false
private var _connected = false
private var _connecting = false
private var currentReconnectAttempt = 0 private var currentReconnectAttempt = 0
private var handlers = ContiguousArray<SocketEventHandler>() private var handlers = ContiguousArray<SocketEventHandler>()
private var connectParams:[String: AnyObject]? private var connectParams: [String: AnyObject]?
private var _secure = false private var reconnectTimer: NSTimer?
private var _reconnecting = false
private var reconnectTimer:NSTimer?
let reconnectAttempts:Int! let reconnectAttempts: Int!
let logType = "SocketClient" let logType = "SocketClient"
var ackHandlers = SocketAckManager() var ackHandlers = SocketAckManager()
var currentAck = -1 var currentAck = -1
var log = false var waitingData = [SocketPacket]()
var waitingData = ContiguousArray<SocketPacket>()
var sessionDelegate:NSURLSessionDelegate?
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 let emitQueue = dispatch_queue_create("emitQueue", DISPATCH_QUEUE_SERIAL)
public var closed:Bool { public let handleQueue: dispatch_queue_t!
return _closed public let socketURL: String
}
public var connected:Bool { public private(set) var engine: SocketEngine?
return _connected public private(set) var secure = false
} public private(set) var status = SocketIOClientStatus.NotConnected
public var connecting:Bool {
return _connecting
}
public var engine:SocketEngine?
public var nsp = "/" public var nsp = "/"
public var opts:[String: AnyObject]? public var opts: [String: AnyObject]?
public var reconnects = true public var reconnects = true
public var reconnecting:Bool {
return _reconnecting
}
public var reconnectWait = 10 public var reconnectWait = 10
public var secure:Bool { public var sid: String? {
return _secure
}
public var sid:String? {
return engine?.sid return engine?.sid
} }
/** /**
Create a new SocketIOClient. opts can be omitted 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 { if socketURL["https://"].matches().count != 0 {
self._secure = true self.secure = true
} }
socketURL = socketURL["http://"] ~= "" socketURL = socketURL["http://"] ~= ""
@ -86,24 +67,15 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
self.socketURL = socketURL self.socketURL = socketURL
self.opts = opts self.opts = opts
// Set options
if let sessionDelegate = opts?["sessionDelegate"] as? NSURLSessionDelegate {
self.sessionDelegate = sessionDelegate
}
if let connectParams = opts?["connectParams"] as? [String: AnyObject] { if let connectParams = opts?["connectParams"] as? [String: AnyObject] {
self.connectParams = connectParams self.connectParams = connectParams
} }
if let log = opts?["log"] as? Bool { if let log = opts?["log"] as? Bool {
self.log = log SocketLogger.log = log
} }
if var nsp = opts?["nsp"] as? String { if let nsp = opts?["nsp"] as? String {
if nsp != "/" && nsp.hasPrefix("/") {
nsp.removeAtIndex(nsp.startIndex)
}
self.nsp = nsp self.nsp = nsp
} }
@ -121,11 +93,13 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
self.reconnectWait = abs(reconnectWait) self.reconnectWait = abs(reconnectWait)
} }
super.init() if let handleQueue = opts?["handleQueue"] as? dispatch_queue_t {
} self.handleQueue = handleQueue
} else {
self.handleQueue = dispatch_get_main_queue()
}
public convenience init(socketURL:String, options:[String: AnyObject]?) { super.init()
self.init(socketURL: socketURL, opts: options)
} }
deinit { deinit {
@ -149,15 +123,12 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
Will turn off automatic reconnects. Will turn off automatic reconnects.
Pass true to fast if you're closing from a background task 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) SocketLogger.log("Closing socket", client: self)
reconnects = false reconnects = false
_connecting = false status = SocketIOClientStatus.Closed
_connected = false
_reconnecting = false
engine?.close(fast: fast) 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 Connect to the server. If we aren't connected after timeoutAfter, call handler
*/ */
public func connect(#timeoutAfter:Int, withTimeoutHandler handler:(() -> Void)?) { public func connect(timeoutAfter timeoutAfter:Int,
if closed { withTimeoutHandler handler:(() -> Void)?) {
SocketLogger.log("Warning! This socket was previously closed. This might be dangerous!", client: self) guard status != SocketIOClientStatus.Connected else {
_closed = false return
} else if connected { }
return if status == SocketIOClientStatus.Closed {
} SocketLogger.log("Warning! This socket was previously closed. This might be dangerous!", client: self)
}
_connecting = true
addEngine() status = SocketIOClientStatus.Connecting
engine?.open(opts: connectParams) addEngine()
engine?.open(connectParams)
if timeoutAfter == 0 {
return guard timeoutAfter != 0 else {
} return
}
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(timeoutAfter) * Int64(NSEC_PER_SEC))
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(timeoutAfter) * Int64(NSEC_PER_SEC))
dispatch_after(time, dispatch_get_main_queue()) {[weak self] in
if let this = self where !this.connected { dispatch_after(time, dispatch_get_main_queue()) {[weak self] in
this._closed = true if let this = self where this.status != SocketIOClientStatus.Connected {
this._connecting = false this.status = SocketIOClientStatus.Closed
this.engine?.close(fast: true) this.engine?.close(fast: true)
handler?() handler?()
}
} }
}
} }
private func createOnAck(event:String, items:[AnyObject]) -> OnAckCallback { private func createOnAck(items: [AnyObject]) -> OnAckCallback {
return {[weak self, ack = ++currentAck] timeout, callback in return {[weak self, ack = ++currentAck] timeout, callback in
if let this = self { if let this = self {
this.ackHandlers.addAck(ack, callback: callback) this.ackHandlers.addAck(ack, callback: callback)
dispatch_async(this.emitQueue) {[weak this] in dispatch_async(this.emitQueue) {[weak this] in
this?._emit(event, items, ack: ack) this?._emit(items, ack: ack)
} }
if timeout != 0 { if timeout != 0 {
@ -221,11 +192,7 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
func didConnect() { func didConnect() {
SocketLogger.log("Socket connected", client: self) SocketLogger.log("Socket connected", client: self)
status = SocketIOClientStatus.Connected
_closed = false
_connected = true
_connecting = false
_reconnecting = false
currentReconnectAttempt = 0 currentReconnectAttempt = 0
clearReconnectTimer() clearReconnectTimer()
@ -234,18 +201,16 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
handleEvent("connect", data: nil, isInternalMessage: false) handleEvent("connect", data: nil, isInternalMessage: false)
} }
func didDisconnect(reason:String) { func didDisconnect(reason: String) {
if closed { guard status != SocketIOClientStatus.Closed else {
return return
} }
SocketLogger.log("Disconnected: %@", client: self, args: reason) SocketLogger.log("Disconnected: %@", client: self, args: reason)
_closed = true status = SocketIOClientStatus.Closed
_connected = false
reconnects = false reconnects = false
_connecting = false
_reconnecting = false
// Make sure the engine is actually dead. // Make sure the engine is actually dead.
engine?.close(fast: true) engine?.close(fast: true)
@ -253,7 +218,7 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
} }
/// error /// error
public func didError(reason:AnyObject) { public func didError(reason: AnyObject) {
SocketLogger.err("%@", client: self, args: reason) SocketLogger.err("%@", client: self, args: reason)
handleEvent("error", data: reason as? [AnyObject] ?? [reason], handleEvent("error", data: reason as? [AnyObject] ?? [reason],
@ -263,33 +228,27 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
/** /**
Same as close Same as close
*/ */
public func disconnect(#fast:Bool) { public func disconnect(fast fast: Bool) {
close(fast: fast) close(fast: fast)
} }
/** /**
Send a message to the server Send a message to the server
*/ */
public func emit(event:String, _ items:AnyObject...) { public func emit(event: String, _ items: AnyObject...) {
if !connected { emit(event, withItems: items)
return
}
dispatch_async(emitQueue) {[weak self] in
self?._emit(event, items)
}
} }
/** /**
Same as emit, but meant for Objective-C Same as emit, but meant for Objective-C
*/ */
public func emit(event:String, withItems items:[AnyObject]) { public func emit(event: String, withItems items: [AnyObject]) {
if !connected { guard status == SocketIOClientStatus.Connected else {
return return
} }
dispatch_async(emitQueue) {[weak self] in 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 Sends a message to the server, requesting an ack. Use the onAck method of SocketAckHandler to add
an ack. an ack.
*/ */
public func emitWithAck(event:String, _ items:AnyObject...) -> OnAckCallback { public func emitWithAck(event: String, _ items: AnyObject...) -> OnAckCallback {
if !connected { return emitWithAck(event, withItems: items)
return createOnAck(event, items: items)
}
return createOnAck(event, items: items)
} }
/** /**
Same as emitWithAck, but for Objective-C Same as emitWithAck, but for Objective-C
*/ */
public func emitWithAck(event:String, withItems items:[AnyObject]) -> OnAckCallback { public func emitWithAck(event: String, withItems items: [AnyObject]) -> OnAckCallback {
if !connected { return createOnAck([event] + items)
return createOnAck(event, items: items)
}
return createOnAck(event, items: items)
} }
private func _emit(event:String, _ args:[AnyObject], ack:Int? = nil) { private func _emit(data: [AnyObject], ack: Int? = nil) {
if !connected { guard status == SocketIOClientStatus.Connected else {
return return
} }
let packet = SocketPacket(type: nil, data: args, nsp: nsp, id: ack) let packet = SocketPacket.packetFromEmit(data, id: ack ?? -1, nsp: nsp, ack: false)
let str:String let str = packet.packetString
SocketParser.parseForEmit(packet)
str = packet.createMessageForEvent(event)
SocketLogger.log("Emitting: %@", client: self, args: str) 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) engine?.send(str, withData: packet.binary)
} else { } else {
engine?.send(str, withData: nil) 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 // 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 dispatch_async(emitQueue) {[weak self] in
if let this = self where this.connected { if let this = self where this.status == SocketIOClientStatus.Connected {
let packet = SocketPacket(type: nil, data: args, nsp: this.nsp, id: ack) let packet = SocketPacket.packetFromEmit(items, id: ack ?? -1, nsp: this.nsp, ack: true)
let str:String let str = packet.packetString
SocketParser.parseForEmit(packet)
str = packet.createAck()
SocketLogger.log("Emitting Ack: %@", client: this, args: str) 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) this.engine?.send(str, withData: packet.binary)
} else { } else {
this.engine?.send(str, withData: nil) this.engine?.send(str, withData: nil)
@ -358,20 +303,20 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
} }
} }
public func engineDidClose(reason:String) { public func engineDidClose(reason: String) {
_connected = false waitingData.removeAll()
_connecting = false
if closed || !reconnects { if status == SocketIOClientStatus.Closed || !reconnects {
didDisconnect(reason) didDisconnect(reason)
} else if !reconnecting { } else if status != SocketIOClientStatus.Reconnecting {
status = SocketIOClientStatus.Reconnecting
handleEvent("reconnect", data: [reason], isInternalMessage: true) handleEvent("reconnect", data: [reason], isInternalMessage: true)
tryReconnect() tryReconnect()
} }
} }
// Called when the socket gets an ack for something it sent // Called when the socket gets an ack for something it sent
func handleAck(ack:Int, data:AnyObject?) { func handleAck(ack: Int, data: AnyObject?) {
SocketLogger.log("Handling ack: %@ with data: %@", client: self, SocketLogger.log("Handling ack: %@ with data: %@", client: self,
args: ack, data ?? "") 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. 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, public func handleEvent(event: String, data: [AnyObject]?, isInternalMessage: Bool,
wantsAck ack:Int? = nil) { wantsAck ack: Int? = nil) {
// println("Should do event: \(event) with data: \(data)") guard status == SocketIOClientStatus.Connected || isInternalMessage else {
if !connected && !isInternalMessage {
return return
} }
// println("Should do event: \(event) with data: \(data)")
SocketLogger.log("Handling event: %@ with data: %@", client: self, SocketLogger.log("Handling event: %@ with data: %@", client: self,
args: event, data ?? "") args: event, data ?? "")
if anyHandler != nil { 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)) self?.anyHandler?(SocketAnyEvent(event: event, items: data))
} }
} }
for handler in handlers { for handler in handlers where handler.event == event {
if handler.event == event { if let ack = ack {
if ack != nil { dispatch_async(handleQueue) {[weak self] in
handler.executeCallback(data, withAck: ack!, withSocket: self) handler.executeCallback(data, withAck: ack, withSocket: self)
} else { }
} else {
dispatch_async(handleQueue) {
handler.executeCallback(data) handler.executeCallback(data)
} }
} }
@ -414,7 +361,7 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
*/ */
public func leaveNamespace() { public func leaveNamespace() {
if nsp != "/" { if nsp != "/" {
engine?.send("1/\(nsp)", withData: nil) engine?.send("1\(nsp)", withData: nil)
nsp = "/" nsp = "/"
} }
} }
@ -426,41 +373,59 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
SocketLogger.log("Joining namespace", client: self) SocketLogger.log("Joining namespace", client: self)
if nsp != "/" { 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) Removes handler(s)
*/ */
public func off(event:String) { public func off(event: String) {
SocketLogger.log("Removing handler for event: %@", client: self, args: event) 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. 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) SocketLogger.log("Adding handler for event: %@", client: self, args: event)
let handler = SocketEventHandler(event: event, callback: callback) let handler = SocketEventHandler(event: event, callback: callback)
handlers.append(handler) handlers.append(handler)
} }
/** /**
Removes all handlers. Adds a handler for an event.
Can be used after disconnecting to break any potential remaining retain cycles. */
*/ public func onObjectiveC(event: String, callback: NormalCallbackObjectiveC) {
public func removeAllHandlers() { SocketLogger.log("Adding handler for event: %@", client: self, args: event)
handlers.removeAll(keepCapacity: false)
} 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. Adds a handler that will be called on every event.
*/ */
public func onAny(handler:(SocketAnyEvent) -> Void) { public func onAny(handler: (SocketAnyEvent) -> Void) {
anyHandler = handler anyHandler = handler
} }
@ -471,50 +436,58 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
connect() connect()
} }
public func parseSocketMessage(msg:String) { public func parseSocketMessage(msg: String) {
SocketParser.parseSocketMessage(msg, socket: self) dispatch_async(handleQueue) {[weak self] in
if let this = self {
SocketParser.parseSocketMessage(msg, socket: this)
}
}
} }
public func parseBinaryData(data:NSData) { public func parseBinaryData(data: NSData) {
SocketParser.parseBinaryData(data, socket: self) 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() { public func reconnect() {
_connected = false
_connecting = false
_reconnecting = false
engine?.stopPolling() engine?.stopPolling()
tryReconnect() tryReconnect()
} }
// We lost connection and should attempt to reestablish private func tryReconnect() {
@objc 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 { if reconnectAttempts != -1 && currentReconnectAttempt + 1 > reconnectAttempts || !reconnects {
clearReconnectTimer() clearReconnectTimer()
didDisconnect("Reconnect Failed") didDisconnect("Reconnect Failed")
return 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) SocketLogger.log("Trying to reconnect", client: self)

View 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
}

View File

@ -1,6 +1,6 @@
// //
// SocketLogger.swift // SocketLogger.swift
// SocketIO-Swift // Socket.IO-Client-Swift
// //
// Created by Erik Little on 4/11/15. // Created by Erik Little on 4/11/15.
// //
@ -24,48 +24,38 @@
import Foundation import Foundation
private let MESSAGE_LENGTH_MAX = 10000
protocol SocketLogClient { protocol SocketLogClient {
var log:Bool {get set} var logType: String {get}
var logType:String {get}
} }
final class SocketLogger { final class SocketLogger {
private static let printQueue = dispatch_queue_create("printQueue", DISPATCH_QUEUE_SERIAL) private static let printQueue = dispatch_queue_create("printQueue", DISPATCH_QUEUE_SERIAL)
static var log = false
private static func shorten(item:AnyObject) -> CVarArgType { private static func toCVArgType(item: AnyObject) -> CVarArgType {
var str = toString(item) return String(item)
if count(str) > MESSAGE_LENGTH_MAX {
let endIndex = advance(str.startIndex, MESSAGE_LENGTH_MAX)
str = str.substringToIndex(endIndex)
}
return str
} }
static func log(message:String, client:SocketLogClient, altType:String? = nil, args:AnyObject...) { static func log(message: String, client: SocketLogClient, altType: String? = nil, args: AnyObject...) {
if !client.log { if !log {
return return
} }
dispatch_async(printQueue) {[type = client.logType] in 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) let replaced = String(format: message, arguments: newArgs)
NSLog("%@: %@", altType ?? type, replaced) NSLog("%@: %@", altType ?? type, replaced)
} }
} }
static func err(message:String, client:SocketLogClient, altType:String? = nil, args:AnyObject...) { static func err(message: String, client: SocketLogClient, altType: String? = nil, args: AnyObject...) {
if !client.log { if !log {
return return
} }
dispatch_async(printQueue) {[type = client.logType] in 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) let replaced = String(format: message, arguments: newArgs)
NSLog("ERROR %@: %@", altType ?? type, replaced) NSLog("ERROR %@: %@", altType ?? type, replaced)

View File

@ -1,6 +1,6 @@
// //
// SocketPacket.swift // SocketPacket.swift
// Socket.IO-Swift // Socket.IO-Client-Swift
// //
// Created by Erik Little on 1/18/15. // Created by Erik Little on 1/18/15.
// //
@ -24,38 +24,19 @@
import Foundation import Foundation
final class SocketPacket: Printable { struct SocketPacket {
var binary = ContiguousArray<NSData>() private var currentPlace = 0
var currentPlace = 0 private let placeholders: Int
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") let nsp: String
better = better["~~1"] ~= (data != nil ? "\(data!)" : "nil") let id: Int
better = better["~~2"] ~= (id != nil ? String(id!) : "nil") let type: PacketType
better = better["~~3"] ~= (placeholders != nil ? String(placeholders!) : "nil")
return better enum PacketType: Int {
} case Connect, Disconnect, Event, Ack, Error, BinaryEvent, BinaryAck
var id:Int?
var justAck = false
var nsp = ""
var placeholders:Int?
var type:PacketType?
enum PacketType:Int { init?(str: String) {
case CONNECT = 0 if let int = Int(str), raw = PacketType(rawValue: int) {
case DISCONNECT = 1
case EVENT = 2
case ACK = 3
case ERROR = 4
case BINARY_EVENT = 5
case BINARY_ACK = 6
init?(str:String) {
if let int = str.toInt(), raw = PacketType(rawValue: int) {
self = raw self = raw
} else { } else {
return nil return nil
@ -63,20 +44,54 @@ final class SocketPacket: Printable {
} }
} }
init(type:PacketType?, data:[AnyObject]? = nil, nsp:String = "", var args: [AnyObject]? {
placeholders:Int? = nil, id:Int? = nil) { var arr = data
self.type = type
self.data = data if data.count == 0 {
self.nsp = nsp return nil
self.placeholders = placeholders } else {
self.id = id if type == PacketType.Event || type == PacketType.BinaryEvent {
arr.removeAtIndex(0)
return arr
} else {
return arr
}
}
} }
func getEvent() -> String { var binary: [NSData]
return data?.removeAtIndex(0) as! String 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 { if placeholders == currentPlace {
return true return true
} }
@ -92,86 +107,22 @@ final class SocketPacket: Printable {
} }
} }
func createMessageForEvent(event:String) -> String { private func completeMessage(var message: String, ack: Bool) -> String {
let message:String if data.count == 0 {
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 {
return message + "]" return message + "]"
} else if !ack {
message += ","
} }
for arg in data! { for arg in data {
if arg is NSDictionary || arg is [AnyObject] { if arg is NSDictionary || arg is [AnyObject] {
let jsonSend = NSJSONSerialization.dataWithJSONObject(arg, do {
options: NSJSONWritingOptions(0), error: &err) let jsonSend = try NSJSONSerialization.dataWithJSONObject(arg,
let jsonString = NSString(data: jsonSend!, encoding: NSUTF8StringEncoding) options: NSJSONWritingOptions(rawValue: 0))
let jsonString = NSString(data: jsonSend, encoding: NSUTF8StringEncoding)
message += jsonString! as String + "," message += jsonString! as String + ","
} catch {
print("Error creating JSON object in SocketPacket.completeMessage")
}
} else if var str = arg as? String { } else if var str = arg as? String {
str = str["\n"] ~= "\\\\n" str = str["\n"] ~= "\\\\n"
str = str["\r"] ~= "\\\\r" str = str["\r"] ~= "\\\\r"
@ -191,29 +142,98 @@ final class SocketPacket: Printable {
return message + "]" return message + "]"
} }
func fillInPlaceholders() { private func createAck() -> String {
var newArr = NSMutableArray(array: data!) let msg: String
for i in 0..<data!.count { if type == PacketType.Ack {
if let str = data?[i] as? String, num = str["~~(\\d)"].groups() { if nsp == "/" {
newArr[i] = binary[num[1].toInt()!] msg = "3\(id)["
} else if data?[i] is NSDictionary || data?[i] is NSArray { } else {
newArr[i] = _fillInPlaceholders(data![i]) 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] 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 str = data as? String {
if let num = str["~~(\\d)"].groups() { if let num = str["~~(\\d)"].groups() {
return binary[num[1].toInt()!] return binary[Int(num[1])!]
} else { } else {
return str return str
} }
} else if let dict = data as? NSDictionary { } else if let dict = data as? NSDictionary {
var newDict = NSMutableDictionary(dictionary: dict) let newDict = NSMutableDictionary(dictionary: dict)
for (key, value) in dict { for (key, value) in dict {
newDict[key as! NSCopying] = _fillInPlaceholders(value) newDict[key as! NSCopying] = _fillInPlaceholders(value)
@ -221,7 +241,7 @@ final class SocketPacket: Printable {
return newDict return newDict
} else if let arr = data as? NSArray { } else if let arr = data as? NSArray {
var newArr = NSMutableArray(array: arr) let newArr = NSMutableArray(array: arr)
for i in 0..<arr.count { for i in 0..<arr.count {
newArr[i] = _fillInPlaceholders(arr[i]) 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)
}
}

View File

@ -1,6 +1,6 @@
// //
// SocketParser.swift // SocketParser.swift
// Socket.IO-Swift // Socket.IO-Client-Swift
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@ -23,73 +23,64 @@
import Foundation import Foundation
class SocketParser { class SocketParser {
private static let shredder = SocketParser.PacketShredder() private static func isCorrectNamespace(nsp: String, _ socket: SocketIOClient) -> Bool {
return nsp == socket.nsp
}
// Translation of socket.io-parser#deconstructPacket private static func handleAck(p: SocketPacket, socket: SocketIOClient) {
private final class PacketShredder { if !isCorrectNamespace(p.nsp, socket) {
var buf = ContiguousArray<NSData>() return
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
}
} }
func deconstructPacket(packet:SocketPacket) { socket.handleAck(p.id, data: p.data)
if packet.data == nil { }
return
}
var data = packet.data! private static func handleBinaryAck(p: SocketPacket, socket: SocketIOClient) {
if !isCorrectNamespace(p.nsp, socket) {
return
}
for i in 0..<data.count { socket.waitingData.append(p)
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 private static func handleBinaryEvent(p: SocketPacket, socket: SocketIOClient) {
packet.binary = buf if !isCorrectNamespace(p.nsp, socket) {
buf.removeAll(keepCapacity: true) 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 // Translation of socket.io-client#decodeString
static func parseString(str:String) -> SocketPacket? { static func parseString(str: String) -> SocketPacket? {
let arr = Array(str) let arr = Array(str.characters)
let type = String(arr[0]) let type = String(arr[0])
if arr.count == 1 { 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 id: Int?
var nsp = "" var nsp:String?
var i = 0 var i = 0
var placeholders = -1 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 placeholders = holders
} else { } else {
NSLog("Error parsing \(str)") NSLog("Error parsing \(str)")
@ -112,6 +103,8 @@ class SocketParser {
} }
if arr[i + 1] == "/" { if arr[i + 1] == "/" {
nsp = ""
while ++i < arr.count { while ++i < arr.count {
let c = arr[i] let c = arr[i]
@ -119,49 +112,56 @@ class SocketParser {
break break
} }
nsp += String(c) nsp! += String(c)
} }
} }
if i + 1 >= arr.count { if i + 1 >= arr.count {
return SocketPacket(type: SocketPacket.PacketType(str: type), return SocketPacket(type: SocketPacket.PacketType(str: type)!, id: id ?? -1,
nsp: nsp, placeholders: placeholders, id: id) nsp: nsp ?? "/", placeholders: placeholders)
} }
let next = String(arr[i + 1]) let next = String(arr[i + 1])
if next.toInt() != nil { if Int(next) != nil {
var c = "" var c = ""
while ++i < arr.count { while ++i < arr.count {
if let int = String(arr[i]).toInt() { if let int = Int(String(arr[i])) {
c += String(arr[i]) c += String(int)
} else { } else {
--i --i
break break
} }
} }
id = c.toInt() id = Int(c)
} }
if ++i < arr.count { 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 noPlaceholders = d["(\\{\"_placeholder\":true,\"num\":(\\d*)\\})"] ~= "\"~~$2\""
let data = SocketParser.parseData(noPlaceholders) as? [AnyObject] ?? [noPlaceholders] let data = SocketParser.parseData(noPlaceholders) as? [AnyObject] ?? [noPlaceholders]
return SocketPacket(type: SocketPacket.PacketType(str: type), data: data, return SocketPacket(type: SocketPacket.PacketType(str: type)!, data: data, id: id ?? -1,
nsp: nsp, placeholders: placeholders, id: id) nsp: nsp ?? "/", placeholders: placeholders)
} }
return nil return nil
} }
// Parses data for events // Parses data for events
static func parseData(data:String) -> AnyObject? { static func parseData(data: String) -> AnyObject? {
var err:NSError? var err: NSError?
let stringData = data.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) let stringData = data.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
let parsed:AnyObject? = NSJSONSerialization.JSONObjectWithData(stringData!, let parsed: AnyObject?
options: NSJSONReadingOptions.MutableContainers, error: &err)
do {
parsed = try NSJSONSerialization.JSONObjectWithData(stringData!,
options: NSJSONReadingOptions.MutableContainers)
} catch let error as NSError {
err = error
parsed = nil
}
if err != nil { if err != nil {
// println(err) // println(err)
@ -171,23 +171,15 @@ class SocketParser {
return parsed return parsed
} }
static func parseForEmit(packet:SocketPacket) {
shredder.deconstructPacket(packet)
}
// Parses messages recieved // Parses messages recieved
static func parseSocketMessage(stringMessage:String, socket:SocketIOClient) { static func parseSocketMessage(stringMessage: String, socket: SocketIOClient) {
if stringMessage == "" { if stringMessage == "" {
return return
} }
func checkNSP(nsp:String) -> Bool {
return nsp == "" && socket.nsp != "/"
}
SocketLogger.log("Parsing %@", client: socket, altType: "SocketParser", args: stringMessage) SocketLogger.log("Parsing %@", client: socket, altType: "SocketParser", args: stringMessage)
let p:SocketPacket let p: SocketPacket
if let pack = parseString(stringMessage) { if let pack = parseString(stringMessage) {
p = pack p = pack
@ -196,50 +188,27 @@ class SocketParser {
return 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 { switch p.type {
if checkNSP(p.nsp) { case SocketPacket.PacketType.Event:
return handleEvent(p, socket: socket)
} case SocketPacket.PacketType.Ack:
handleAck(p, socket: socket)
socket.handleEvent(p.getEvent(), data: p.data, case SocketPacket.PacketType.BinaryEvent:
isInternalMessage: false, wantsAck: p.id) handleBinaryEvent(p, socket: socket)
} else if p.type == SocketPacket.PacketType.ACK { case SocketPacket.PacketType.BinaryAck:
if checkNSP(p.nsp) { handleBinaryAck(p, socket: socket)
return case SocketPacket.PacketType.Connect:
} handleConnect(p, socket: socket)
case SocketPacket.PacketType.Disconnect:
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 {
socket.didDisconnect("Got Disconnect") socket.didDisconnect("Got Disconnect")
} else if p.type == SocketPacket.PacketType.ERROR { case SocketPacket.PacketType.Error:
socket.didError(p.data == nil ? "Error" : p.data!) socket.didError("Error: \(p.data)")
} }
} }
static func parseBinaryData(data:NSData, socket:SocketIOClient) { static func parseBinaryData(data: NSData, socket: SocketIOClient) {
if socket.waitingData.count == 0 { if socket.waitingData.count == 0 {
SocketLogger.err("Got data when not remaking packet", client: socket, altType: "SocketParser") SocketLogger.err("Got data when not remaking packet", client: socket, altType: "SocketParser")
return return
@ -251,14 +220,14 @@ class SocketParser {
return return
} }
let packet = socket.waitingData.removeAtIndex(0) var packet = socket.waitingData.removeAtIndex(0)
packet.fillInPlaceholders() packet.fillInPlaceholders()
if !packet.justAck { if packet.type != SocketPacket.PacketType.BinaryAck {
socket.handleEvent(packet.getEvent(), data: packet.data, socket.handleEvent(packet.event, data: packet.args,
wantsAck: packet.id) isInternalMessage: false, wantsAck: packet.id)
} else { } else {
socket.handleAck(packet.id!, data: packet.data) socket.handleAck(packet.id, data: packet.args)
} }
} }
} }

View File

@ -1,6 +1,6 @@
// //
// SocketTypes.swift // SocketTypes.swift
// SocketIO-Swift // Socket.IO-Client-Swift
// //
// Created by Erik Little on 4/8/15. // Created by Erik Little on 4/8/15.
// //
@ -24,11 +24,10 @@
import Foundation import Foundation
// @objc_block is undocumented, but is used because Swift assumes that all public typealias AckCallback = (NSArray?) -> Void
// 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 AckEmitter = (AnyObject...) -> Void public typealias AckEmitter = (AnyObject...) -> Void
public typealias AckEmitterObjectiveC = (NSArray) -> Void
public typealias NormalCallback = (NSArray?, AckEmitter?) -> 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

View File

@ -19,18 +19,18 @@ public class SwiftRegex: NSObject, BooleanType {
var target:String var target:String
var regex: NSRegularExpression var regex: NSRegularExpression
init(target:String, pattern:String, options:NSRegularExpressionOptions = nil) { init(target:String, pattern:String, options:NSRegularExpressionOptions?) {
self.target = target self.target = target
if let regex = swiftRegexCache[pattern] { if let regex = swiftRegexCache[pattern] {
self.regex = regex self.regex = regex
} else { } else {
var error: NSError? do {
if let regex = NSRegularExpression(pattern: pattern, options:options, error:&error) { let regex = try NSRegularExpression(pattern: pattern, options:
NSRegularExpressionOptions.DotMatchesLineSeparators)
swiftRegexCache[pattern] = regex swiftRegexCache[pattern] = regex
self.regex = regex self.regex = regex
} } catch let error1 as NSError {
else { SwiftRegex.failure("Error in pattern: \(pattern) - \(error1)")
SwiftRegex.failure("Error in pattern: \(pattern) - \(error)")
self.regex = NSRegularExpression() self.regex = NSRegularExpression()
} }
} }
@ -38,12 +38,12 @@ public class SwiftRegex: NSObject, BooleanType {
} }
class func failure(message: String) { class func failure(message: String) {
println("SwiftRegex: "+message) print("SwiftRegex: "+message)
//assert(false,"SwiftRegex: failed") //assert(false,"SwiftRegex: failed")
} }
final var targetRange: NSRange { 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? { final func substring(range: NSRange) -> String? {
@ -54,20 +54,21 @@ public class SwiftRegex: NSObject, BooleanType {
} }
} }
public func doesMatch(options: NSMatchingOptions = nil) -> Bool { public func doesMatch(options: NSMatchingOptions!) -> Bool {
return range(options: options).location != NSNotFound return range(options).location != NSNotFound
} }
public func range(options: NSMatchingOptions = nil) -> NSRange { public func range(options: NSMatchingOptions) -> NSRange {
return regex.rangeOfFirstMatchInString(target as String, options: nil, range: targetRange) return regex.rangeOfFirstMatchInString(target as String, options: [], range: targetRange)
} }
public func match(options: NSMatchingOptions = nil) -> String? { public func match(options: NSMatchingOptions) -> String? {
return substring(range(options: options)) return substring(range(options))
} }
public func groups(options: NSMatchingOptions = nil) -> [String]? { public func groups() -> [String]? {
return groupsForMatch(regex.firstMatchInString(target as String, options: options, range: targetRange)) return groupsForMatch(regex.firstMatchInString(target as String, options:
NSMatchingOptions.WithoutAnchoringBounds, range: targetRange))
} }
func groupsForMatch(match: NSTextCheckingResult!) -> [String]? { func groupsForMatch(match: NSTextCheckingResult!) -> [String]? {
@ -96,7 +97,7 @@ public class SwiftRegex: NSObject, BooleanType {
return return
} }
for match in matchResults()!.reverse() { for match in Array(matchResults().reverse()) {
let replacement = regex.replacementStringForResult(match, let replacement = regex.replacementStringForResult(match,
inString: target as String, offset: 0, template: newValue!) inString: target as String, offset: 0, template: newValue!)
let mut = NSMutableString(string: target) let mut = NSMutableString(string: target)
@ -107,48 +108,43 @@ public class SwiftRegex: NSObject, BooleanType {
} }
} }
func matchResults(options: NSMatchingOptions = nil) -> [NSTextCheckingResult]? { func matchResults() -> [NSTextCheckingResult] {
let matches = regex.matchesInString(target as String, options: options, range: targetRange) let matches = regex.matchesInString(target as String, options:
as? [NSTextCheckingResult] NSMatchingOptions.WithoutAnchoringBounds, range: targetRange)
as [NSTextCheckingResult]
if matches != nil { return matches
return matches!
} else {
return nil
}
} }
public func ranges(options: NSMatchingOptions = nil) -> [NSRange] { public func ranges() -> [NSRange] {
return matchResults(options: options)!.map { $0.range } return matchResults().map { $0.range }
} }
public func matches(options: NSMatchingOptions = nil) -> [String] { public func matches() -> [String] {
return matchResults(options: options)!.map( { self.substring($0.range)!}) return matchResults().map( { self.substring($0.range)!})
} }
public func allGroups(options: NSMatchingOptions = nil) -> [[String]?] { public func allGroups() -> [[String]?] {
return matchResults(options: options)!.map {self.groupsForMatch($0)} 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>() var out = Dictionary<String,String>()
for match in matchResults(options: options)! { for match in matchResults() {
out[substring(match.rangeAtIndex(1))!] = substring(match.rangeAtIndex(2))! out[substring(match.rangeAtIndex(1))!] = substring(match.rangeAtIndex(2))!
} }
return out return out
} }
func substituteMatches(substitution: ((NSTextCheckingResult, UnsafeMutablePointer<ObjCBool>) -> String), func substituteMatches(substitution: ((NSTextCheckingResult, UnsafeMutablePointer<ObjCBool>) -> String),
options:NSMatchingOptions = nil) -> String { options:NSMatchingOptions) -> String {
let out = NSMutableString() let out = NSMutableString()
var pos = 0 var pos = 0
regex.enumerateMatchesInString(target as String, options: options, range: targetRange ) { regex.enumerateMatchesInString(target as String, options: options, range: targetRange ) {match, flags, stop in
(match: NSTextCheckingResult!, flags: NSMatchingFlags, stop: UnsafeMutablePointer<ObjCBool>) in let matchRange = match!.range
let matchRange = match.range
out.appendString( self.substring(NSRange(location:pos, length:matchRange.location-pos))!) 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 pos = matchRange.location + matchRange.length
} }
@ -158,7 +154,7 @@ public class SwiftRegex: NSObject, BooleanType {
} }
public var boolValue: Bool { public var boolValue: Bool {
return doesMatch() return doesMatch(nil)
} }
} }
@ -170,7 +166,7 @@ extension String {
extension String { extension String {
public subscript(pattern: String) -> SwiftRegex { public subscript(pattern: String) -> SwiftRegex {
return SwiftRegex(target: self, pattern: pattern) return SwiftRegex(target: self, pattern: pattern, options: nil)
} }
} }
@ -178,7 +174,7 @@ public func ~= (left: SwiftRegex, right: String) -> String {
return left.substituteMatches({match, stop in return left.substituteMatches({match, stop in
return left.regex.replacementStringForResult( match, return left.regex.replacementStringForResult( match,
inString: left.target as String, offset: 0, template: right ) inString: left.target as String, offset: 0, template: right )
}, options: nil) }, options: [])
} }
public func ~= (left: SwiftRegex, right: [String]) -> String { public func ~= (left: SwiftRegex, right: [String]) -> String {
@ -191,7 +187,7 @@ public func ~= (left: SwiftRegex, right: [String]) -> String {
return left.regex.replacementStringForResult( match, return left.regex.replacementStringForResult( match,
inString: left.target as String, offset: 0, template: right[matchNumber-1] ) inString: left.target as String, offset: 0, template: right[matchNumber-1] )
}, options: nil) }, options: [])
} }
public func ~= (left: SwiftRegex, right: (String) -> String) -> String { public func ~= (left: SwiftRegex, right: (String) -> String) -> String {
@ -199,11 +195,11 @@ public func ~= (left: SwiftRegex, right: (String) -> String) -> String {
return left.substituteMatches( return left.substituteMatches(
{match, stop -> String in {match, stop -> String in
right(left.substring(match.range)!) right(left.substring(match.range)!)
}, options: nil) }, options: [])
} }
public func ~= (left: SwiftRegex, right: ([String]?) -> String) -> String { public func ~= (left: SwiftRegex, right: ([String]?) -> String) -> String {
return left.substituteMatches({match, stop -> String in return left.substituteMatches({match, stop -> String in
return right(left.groupsForMatch(match)) return right(left.groupsForMatch(match))
}, options: nil) }, options: [])
} }

View File

@ -93,7 +93,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
public var headers = Dictionary<String,String>() public var headers = Dictionary<String,String>()
public var voipEnabled = false public var voipEnabled = false
public var selfSignedSSL = false public var selfSignedSSL = false
public var security: Security? private var security: Security?
public var isConnected :Bool { public var isConnected :Bool {
return connected return connected
} }
@ -168,7 +168,6 @@ public class WebSocket : NSObject, NSStreamDelegate {
//private method that starts the connection //private method that starts the connection
private func createHTTPRequest() { private func createHTTPRequest() {
let str: NSString = url.absoluteString!
let urlRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, "GET", let urlRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, "GET",
url, kCFHTTPVersion1_1).takeRetainedValue() url, kCFHTTPVersion1_1).takeRetainedValue()
@ -184,24 +183,25 @@ public class WebSocket : NSObject, NSStreamDelegate {
if self.cookies != nil { if self.cookies != nil {
let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(self.cookies!) let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(self.cookies!)
for (key, value) in headers { 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: headerWSUpgradeName, val: headerWSUpgradeValue)
self.addHeader(urlRequest, key: headerWSConnectionName, val: headerWSConnectionValue) self.addHeader(urlRequest, key: headerWSConnectionName, val: headerWSConnectionValue)
if let protocols = optionalProtocols { 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: headerWSVersionName, val: headerWSVersionValue)
self.addHeader(urlRequest, key: headerWSKeyName, val: self.generateWebSocketKey()) 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!)") self.addHeader(urlRequest, key: headerWSHostName, val: "\(url.host!):\(port!)")
for (key,value) in headers { for (key,value) in headers {
self.addHeader(urlRequest, key: key, val: value) self.addHeader(urlRequest, key: key, val: value)
} }
let serializedRequest: NSData = CFHTTPMessageCopySerializedMessage(urlRequest).takeRetainedValue()
let serializedRequest: NSData = CFHTTPMessageCopySerializedMessage(urlRequest)!.takeRetainedValue()
self.initStreamsWithData(serializedRequest, Int(port!)) self.initStreamsWithData(serializedRequest, Int(port!))
} }
//Add a header to the CFHTTPMessage by using the NSString bridges to CFString //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))) let uni = UnicodeScalar(UInt32(97 + arc4random_uniform(25)))
key += "\(Character(uni))" key += "\(Character(uni))"
} }
var data = key.dataUsingEncoding(NSUTF8StringEncoding) let data = key.dataUsingEncoding(NSUTF8StringEncoding)
var baseKey = data?.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(0)) let baseKey = data?.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
return baseKey! return baseKey!
} }
//Start the stream connection and write the data to the output stream //Start the stream connection and write the data to the output stream
@ -250,8 +250,8 @@ public class WebSocket : NSObject, NSStreamDelegate {
} }
if self.selfSignedSSL { if self.selfSignedSSL {
let settings: Dictionary<NSObject, NSObject> = [kCFStreamSSLValidatesCertificateChain: NSNumber(bool:false), kCFStreamSSLPeerName: kCFNull] let settings: Dictionary<NSObject, NSObject> = [kCFStreamSSLValidatesCertificateChain: NSNumber(bool:false), kCFStreamSSLPeerName: kCFNull]
inputStream!.setProperty(settings, forKey: kCFStreamPropertySSLSettings as! String) inputStream!.setProperty(settings, forKey: kCFStreamPropertySSLSettings as String)
outputStream!.setProperty(settings, forKey: kCFStreamPropertySSLSettings as! String) outputStream!.setProperty(settings, forKey: kCFStreamPropertySSLSettings as String)
} }
isRunLoop = true isRunLoop = true
inputStream!.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode) inputStream!.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
@ -261,16 +261,16 @@ public class WebSocket : NSObject, NSStreamDelegate {
let bytes = UnsafePointer<UInt8>(data.bytes) let bytes = UnsafePointer<UInt8>(data.bytes)
outputStream!.write(bytes, maxLength: data.length) outputStream!.write(bytes, maxLength: data.length)
while(isRunLoop) { 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 //delegate for the stream methods. Processes incoming bytes
public func stream(aStream: NSStream, handleEvent eventCode: NSStreamEvent) { public func stream(aStream: NSStream, handleEvent eventCode: NSStreamEvent) {
if let sec = security where !certValidated && (eventCode == .HasBytesAvailable || eventCode == .HasSpaceAvailable) { 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 { 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?) { if sec.isValid(trust as! SecTrustRef, domain: domain as! String?) {
certValidated = true certValidated = true
} else { } else {
@ -314,7 +314,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
///handles the incoming bytes and sending them to the proper processing method ///handles the incoming bytes and sending them to the proper processing method
private func processInputStream() { private func processInputStream() {
let buf = NSMutableData(capacity: BUFFER_MAX) 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) let length = inputStream!.read(buffer, maxLength: BUFFER_MAX)
if length > 0 { if length > 0 {
if !connected { if !connected {
@ -340,7 +340,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
let data = inputQueue[0] let data = inputQueue[0]
var work = data var work = data
if (fragBuffer != nil) { if (fragBuffer != nil) {
var combine = NSMutableData(data: fragBuffer!) let combine = NSMutableData(data: fragBuffer!)
combine.appendData(data) combine.appendData(data)
work = combine work = combine
fragBuffer = nil fragBuffer = nil
@ -388,14 +388,14 @@ public class WebSocket : NSObject, NSStreamDelegate {
///validates the HTTP is a 101 as per the RFC spec ///validates the HTTP is a 101 as per the RFC spec
private func validateResponse(buffer: UnsafePointer<UInt8>, bufferLen: Int) -> Bool { 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) CFHTTPMessageAppendBytes(response, buffer, bufferLen)
if CFHTTPMessageGetResponseStatusCode(response) != 101 { if CFHTTPMessageGetResponseStatusCode(response) != 101 {
return false return false
} }
let cfHeaders = CFHTTPMessageCopyAllHeaderFields(response) let cfHeaders = CFHTTPMessageCopyAllHeaderFields(response)
let headers: NSDictionary = cfHeaders.takeRetainedValue() let headers:NSDictionary? = cfHeaders?.takeRetainedValue()
let acceptKey = headers[headerWSAcceptName] as! NSString let acceptKey = headers?[headerWSAcceptName] as! NSString
if acceptKey.length > 0 { if acceptKey.length > 0 {
return true return true
} }
@ -404,7 +404,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
///process the websocket data ///process the websocket data
private func processRawMessage(buffer: UnsafePointer<UInt8>, bufferLen: Int) { private func processRawMessage(buffer: UnsafePointer<UInt8>, bufferLen: Int) {
var response = readStack.last let response = readStack.last
if response != nil && bufferLen < 2 { if response != nil && bufferLen < 2 {
fragBuffer = NSData(bytes: buffer, length: bufferLen) fragBuffer = NSData(bytes: buffer, length: bufferLen)
return return
@ -420,7 +420,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
resp.bytesLeft -= len resp.bytesLeft -= len
resp.buffer?.appendData(NSData(bytes: buffer, length: len)) resp.buffer?.appendData(NSData(bytes: buffer, length: len))
processResponse(resp) processResponse(resp)
var offset = bufferLen - extra let offset = bufferLen - extra
if extra > 0 { if extra > 0 {
processExtra((buffer+offset), bufferLen: extra) processExtra((buffer+offset), bufferLen: extra)
} }
@ -459,7 +459,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
if payloadLen == 1 { if payloadLen == 1 {
code = CloseCode.ProtocolError.rawValue code = CloseCode.ProtocolError.rawValue
} else if payloadLen > 1 { } else if payloadLen > 1 {
var codeBuffer = UnsafePointer<UInt16>((buffer+offset)) let codeBuffer = UnsafePointer<UInt16>((buffer+offset))
code = codeBuffer[0].bigEndian code = codeBuffer[0].bigEndian
if code < 1000 || (code > 1003 && code < 1007) || (code > 1011 && code < 3000) { if code < 1000 || (code > 1003 && code < 1007) || (code > 1011 && code < 3000) {
code = CloseCode.ProtocolError.rawValue code = CloseCode.ProtocolError.rawValue
@ -470,7 +470,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
let len = Int(payloadLen-2) let len = Int(payloadLen-2)
if len > 0 { if len > 0 {
let bytes = UnsafePointer<UInt8>((buffer+offset)) 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 { if str == nil {
code = CloseCode.ProtocolError.rawValue code = CloseCode.ProtocolError.rawValue
} }
@ -495,7 +495,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
dataLength = UInt64(bytes[0].bigEndian) dataLength = UInt64(bytes[0].bigEndian)
offset += sizeof(UInt16) offset += sizeof(UInt16)
} }
if bufferLen < offset { if bufferLen < offset || UInt64(bufferLen - offset) < dataLength {
fragBuffer = NSData(bytes: buffer, length: bufferLen) fragBuffer = NSData(bytes: buffer, length: bufferLen)
return return
} }
@ -599,16 +599,16 @@ public class WebSocket : NSObject, NSStreamDelegate {
let data = response.buffer! //local copy so it is perverse for writing let data = response.buffer! //local copy so it is perverse for writing
dequeueWrite(data, code: OpCode.Pong) dequeueWrite(data, code: OpCode.Pong)
} else if response.code == .TextFrame { } 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 { if str == nil {
writeError(CloseCode.Encoding.rawValue) writeError(CloseCode.Encoding.rawValue)
return false return false
} }
dispatch_async(queue,{ dispatch_async(queue,{
if let textBlock = self.onText { 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 { } else if response.code == .BinaryFrame {
let data = response.buffer! //local copy so it is perverse for writing 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 ///write a an error to the socket
private func writeError(code: UInt16) { private func writeError(code: UInt16) {
let buf = NSMutableData(capacity: sizeof(UInt16)) let buf = NSMutableData(capacity: sizeof(UInt16))
var buffer = UnsafeMutablePointer<UInt16>(buf!.bytes) let buffer = UnsafeMutablePointer<UInt16>(buf!.bytes)
buffer[0] = code.bigEndian buffer[0] = code.bigEndian
dequeueWrite(NSData(bytes: buffer, length: sizeof(UInt16)), code: .ConnectionClose) dequeueWrite(NSData(bytes: buffer, length: sizeof(UInt16)), code: .ConnectionClose)
} }
@ -670,17 +670,17 @@ public class WebSocket : NSObject, NSStreamDelegate {
buffer[1] = CUnsignedChar(dataLength) buffer[1] = CUnsignedChar(dataLength)
} else if dataLength <= Int(UInt16.max) { } else if dataLength <= Int(UInt16.max) {
buffer[1] = 126 buffer[1] = 126
var sizeBuffer = UnsafeMutablePointer<UInt16>((buffer+offset)) let sizeBuffer = UnsafeMutablePointer<UInt16>((buffer+offset))
sizeBuffer[0] = UInt16(dataLength).bigEndian sizeBuffer[0] = UInt16(dataLength).bigEndian
offset += sizeof(UInt16) offset += sizeof(UInt16)
} else { } else {
buffer[1] = 127 buffer[1] = 127
var sizeBuffer = UnsafeMutablePointer<UInt64>((buffer+offset)) let sizeBuffer = UnsafeMutablePointer<UInt64>((buffer+offset))
sizeBuffer[0] = UInt64(dataLength).bigEndian sizeBuffer[0] = UInt64(dataLength).bigEndian
offset += sizeof(UInt64) offset += sizeof(UInt64)
} }
buffer[1] |= self.MaskMask buffer[1] |= self.MaskMask
var maskKey = UnsafeMutablePointer<UInt8>(buffer + offset) let maskKey = UnsafeMutablePointer<UInt8>(buffer + offset)
SecRandomCopyBytes(kSecRandomDefault, Int(sizeof(UInt32)), maskKey) SecRandomCopyBytes(kSecRandomDefault, Int(sizeof(UInt32)), maskKey)
offset += sizeof(UInt32) offset += sizeof(UInt32)
@ -694,7 +694,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
break break
} }
let writeBuffer = UnsafePointer<UInt8>(frame!.bytes+total) 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 { if len == nil || len! < 0 {
var error: NSError? var error: NSError?
if let streamError = self.outputStream?.streamError { if let streamError = self.outputStream?.streamError {
@ -771,8 +771,8 @@ public class SSLCert {
} }
} }
public class Security { private class Security {
public var validatedDN = true //should the domain name be validated? private var validatedDN = true //should the domain name be validated?
var isReady = false //is the key processing done? var isReady = false //is the key processing done?
var certificates: [NSData]? //the certificates var certificates: [NSData]? //the certificates
@ -786,11 +786,11 @@ public class Security {
:returns: a representation security object to be used with :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: ".") let paths = NSBundle.mainBundle().pathsForResourcesOfType("cer", inDirectory: ".")
var collect = Array<SSLCert>() var collect = Array<SSLCert>()
for path in paths { 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)) collect.append(SSLCert(data: d))
} }
} }
@ -805,7 +805,7 @@ public class Security {
:returns: a representation security object to be used with :returns: a representation security object to be used with
*/ */
public init(certs: [SSLCert], usePublicKeys: Bool) { private init(certs: [SSLCert], usePublicKeys: Bool) {
self.usePublicKeys = usePublicKeys self.usePublicKeys = usePublicKeys
if self.usePublicKeys { if self.usePublicKeys {
@ -842,7 +842,7 @@ public class Security {
:returns: if the key was successfully validated :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 var tries = 0
while(!self.isReady) { while(!self.isReady) {
@ -854,9 +854,9 @@ public class Security {
} }
var policy: SecPolicyRef var policy: SecPolicyRef
if self.validatedDN { if self.validatedDN {
policy = SecPolicyCreateSSL(1, domain).takeRetainedValue() policy = SecPolicyCreateSSL(true, domain)
} else { } else {
policy = SecPolicyCreateBasicX509().takeRetainedValue() policy = SecPolicyCreateBasicX509()
} }
SecTrustSetPolicies(trust,policy) SecTrustSetPolicies(trust,policy)
if self.usePublicKeys { if self.usePublicKeys {
@ -879,7 +879,7 @@ public class Security {
let serverCerts = certificateChainForTrust(trust) let serverCerts = certificateChainForTrust(trust)
var collect = Array<SecCertificate>() var collect = Array<SecCertificate>()
for cert in certs { for cert in certs {
collect.append(SecCertificateCreateWithData(nil,cert).takeRetainedValue()) collect.append(SecCertificateCreateWithData(nil,cert)!)
} }
SecTrustSetAnchorCertificates(trust,collect) SecTrustSetAnchorCertificates(trust,collect)
var result: SecTrustResultType = 0 var result: SecTrustResultType = 0
@ -911,10 +911,9 @@ public class Security {
:returns: a public key :returns: a public key
*/ */
func extractPublicKey(data: NSData) -> SecKeyRef? { func extractPublicKey(data: NSData) -> SecKeyRef? {
var publicKey: NSData?
let possibleCert = SecCertificateCreateWithData(nil,data) let possibleCert = SecCertificateCreateWithData(nil,data)
if let cert = possibleCert { if let cert = possibleCert {
return extractPublicKeyFromCert(cert.takeRetainedValue(),policy: SecPolicyCreateBasicX509().takeRetainedValue()) return extractPublicKeyFromCert(cert,policy: SecPolicyCreateBasicX509())
} }
return nil return nil
} }
@ -927,13 +926,12 @@ public class Security {
:returns: a public key :returns: a public key
*/ */
func extractPublicKeyFromCert(cert: SecCertificate, policy: SecPolicy) -> SecKeyRef? { func extractPublicKeyFromCert(cert: SecCertificate, policy: SecPolicy) -> SecKeyRef? {
var possibleTrust: Unmanaged<SecTrust>? let possibleTrust = UnsafeMutablePointer<SecTrust?>.alloc(1)
SecTrustCreateWithCertificates(cert,policy, &possibleTrust) SecTrustCreateWithCertificates( cert, policy, possibleTrust)
if let trust = possibleTrust { if let trust = possibleTrust.memory {
let t = trust.takeRetainedValue()
var result: SecTrustResultType = 0 var result: SecTrustResultType = 0
SecTrustEvaluate(t,&result) SecTrustEvaluate(trust,&result)
return SecTrustCopyPublicKey(t).takeRetainedValue() return SecTrustCopyPublicKey(trust)
} }
return nil return nil
} }
@ -949,7 +947,7 @@ public class Security {
var collect = Array<NSData>() var collect = Array<NSData>()
for var i = 0; i < SecTrustGetCertificateCount(trust); i++ { for var i = 0; i < SecTrustGetCertificateCount(trust); i++ {
let cert = SecTrustGetCertificateAtIndex(trust,i) let cert = SecTrustGetCertificateAtIndex(trust,i)
collect.append(SecCertificateCopyData(cert.takeRetainedValue()).takeRetainedValue()) collect.append(SecCertificateCopyData(cert!))
} }
return collect return collect
} }
@ -963,10 +961,10 @@ public class Security {
*/ */
func publicKeyChainForTrust(trust: SecTrustRef) -> Array<SecKeyRef> { func publicKeyChainForTrust(trust: SecTrustRef) -> Array<SecKeyRef> {
var collect = Array<SecKeyRef>() var collect = Array<SecKeyRef>()
let policy = SecPolicyCreateBasicX509().takeRetainedValue() let policy = SecPolicyCreateBasicX509()
for var i = 0; i < SecTrustGetCertificateCount(trust); i++ { for var i = 0; i < SecTrustGetCertificateCount(trust); i++ {
let cert = SecTrustGetCertificateAtIndex(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) collect.append(key)
} }
} }