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
.AppleDouble
.LSOverride
*.xcodeproj
# Icon must end with two \r
Icon
@ -41,3 +42,5 @@ DerivedData
*.hmap
*.ipa
*.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
if let cur = data?[0] as? Double {
socket.emitWithAck("canUpdate", cur)(timeout: 0) {data in
socket.emitWithAck("canUpdate", cur)(timeoutAfter: 0) {data in
socket.emit("update", ["amount": cur + 2.50])
}
@ -26,11 +26,11 @@ socket.connect()
```objective-c
SocketIOClient* socket = [[SocketIOClient alloc] initWithSocketURL:@"localhost:8080" options:nil];
[socket on:@"connect" callback:^(NSArray* data, void (^ack)(NSArray*)) {
[socket onObjectiveC:@"connect" callback:^(NSArray* data, void (^ack)(NSArray*)) {
NSLog(@"socket connected");
}];
[socket on:@"currentAmount" callback:^(NSArray* data, void (^ack)(NSArray*)) {
[socket onObjectiveC:@"currentAmount" callback:^(NSArray* data, void (^ack)(NSArray*)) {
double cur = [[data objectAtIndex:0] floatValue];
[socket emitWithAck:@"canUpdate" withItems:@[@(cur)]](0, ^(NSArray* data) {
@ -52,15 +52,16 @@ SocketIOClient* socket = [[SocketIOClient alloc] initWithSocketURL:@"localhost:8
- Can be used from Objective-C
##Installation
Requires Swift 1.2/Xcode 6.3
Requires Swift 2/Xcode 7
If you need Swift 1.2/Xcode 6.3/4 use v2 (Pre-Swift 2 support is no longer maintained)
If you need Swift 1.1/Xcode 6.2 use v1.5.2. (Pre-Swift 1.2 support is no longer maintained)
Carthage
-----------------
Add this line to your `Cartfile`:
```
github "socketio/socket.io-client-swift" ~> 2.3.10 # Or latest version
github "socketio/socket.io-client-swift" ~> 2.4.3 # Or latest version
```
Run `carthage update`.
@ -79,7 +80,7 @@ source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!
pod 'Socket.IO-Client-Swift', '~> 2.3.10' # Or latest version
pod 'Socket.IO-Client-Swift', '~> 2.4.3' # Or latest version
```
Install pods:
@ -121,21 +122,23 @@ Options
- `sessionDelegate: NSURLSessionDelegate` Sets an NSURLSessionDelegate for the underlying engine. Useful if you need to handle self-signed certs. Default is nil.
- `path: String` - If the server uses a custom path. ex: `"/swift"`. Default is `""`
- `extraHeaders: [String: String]?` - Adds custom headers to the initial request. Default is nil.
- `handleQueue: dispatch_queue_t` - The dispatch queue that handlers are run on. Default is the main queue.
Methods
-------
1. `on(name:String, callback:((data:NSArray?, ack:AckEmitter?) -> Void))` - Adds a handler for an event. Items are passed by an array. `ack` can be used to send an ack when one is requested. See example.
2. `onAny(callback:((event:String, items:AnyObject?)) -> Void)` - Adds a handler for all events. It will be called on any received event.
3. `emit(event:String, _ items:AnyObject...)` - Sends a message. Can send multiple items.
4. `emit(event:String, withItems items:[AnyObject])` - `emit` for Objective-C
5. `emitWithAck(event:String, _ items:AnyObject...) -> (timeout:UInt64, callback:(NSArray?) -> Void) -> Void` - Sends a message that requests an acknowledgement from the server. Returns a function which you can use to add a handler. See example. Note: The message is not sent until you call the returned function.
6. `emitWithAck(event:String, withItems items:[AnyObject]) -> (UInt64, (NSArray?) -> Void) -> Void` - `emitWithAck` for Objective-C. Note: The message is not sent until you call the returned function.
7. `connect()` - Establishes a connection to the server. A "connect" event is fired upon successful connection.
8. `connect(#timeoutAfter:Int, withTimeoutHandler handler:(() -> Void)?)` - Connect to the server. If it isn't connected after timeoutAfter seconds, the handler is called.
9. `close(#fast:Bool)` - Closes the socket. Once a socket is closed it should not be reopened. Pass true to fast if you're closing from a background task.
10. `reconnect()` - Causes the client to reconnect to the server.
11. `joinNamespace()` - Causes the client to join nsp. Shouldn't need to be called unless you change nsp manually.
12. `leaveNamespace()` - Causes the client to leave the nsp and go back to /
2. `onObjectiveC(name:String, callback:((data:NSArray?, ack:AckEmitter?) -> Void))` - Adds a handler for an event. Items are passed by an array. `ack` can be used to send an ack when one is requested. See example.
3. `onAny(callback:((event:String, items:AnyObject?)) -> Void)` - Adds a handler for all events. It will be called on any received event.
4. `emit(event:String, _ items:AnyObject...)` - Sends a message. Can send multiple items.
5. `emit(event:String, withItems items:[AnyObject])` - `emit` for Objective-C
6. `emitWithAck(event:String, _ items:AnyObject...) -> (timeoutAfter:UInt64, callback:(NSArray?) -> Void) -> Void` - Sends a message that requests an acknowledgement from the server. Returns a function which you can use to add a handler. See example. Note: The message is not sent until you call the returned function.
7. `emitWithAck(event:String, withItems items:[AnyObject]) -> (UInt64, (NSArray?) -> Void) -> Void` - `emitWithAck` for Objective-C. Note: The message is not sent until you call the returned function.
8. `connect()` - Establishes a connection to the server. A "connect" event is fired upon successful connection.
9. `connect(#timeoutAfter:Int, withTimeoutHandler handler:(() -> Void)?)` - Connect to the server. If it isn't connected after timeoutAfter seconds, the handler is called.
10. `close(#fast:Bool)` - Closes the socket. Once a socket is closed it should not be reopened. Pass true to fast if you're closing from a background task.
11. `reconnect()` - Causes the client to reconnect to the server.
12. `joinNamespace()` - Causes the client to join nsp. Shouldn't need to be called unless you change nsp manually.
13. `leaveNamespace()` - Causes the client to leave the nsp and go back to /
Client Events
------

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "Socket.IO-Client-Swift"
s.version = "2.3.10"
s.version = "2.4.3"
s.summary = "Socket.IO-client for iOS and OS X"
s.description = <<-DESC
Socket.IO-client for iOS and OS X.
@ -12,7 +12,7 @@ Pod::Spec.new do |s|
s.author = { "Erik" => "nuclear.ace@gmail.com" }
s.ios.deployment_target = '8.0'
s.osx.deployment_target = '10.10'
s.source = { :git => "https://github.com/socketio/socket.io-client-swift.git", :tag => 'v2.3.10' }
s.source = { :git => "https://github.com/socketio/socket.io-client-swift.git", :tag => 'v2.4.3' }
s.source_files = "SocketIOClientSwift/**/*.swift"
s.requires_arc = true
# s.dependency 'Starscream', '~> 0.9' # currently this repo includes Starscream swift files

View File

@ -9,7 +9,6 @@
/* Begin PBXBuildFile section */
572EF21F1B51F16C00EEBB58 /* SocketIO-iOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 572EF21E1B51F16C00EEBB58 /* SocketIO-iOS.h */; settings = {ATTRIBUTES = (Public, ); }; };
572EF2251B51F16C00EEBB58 /* SocketIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 572EF2191B51F16C00EEBB58 /* SocketIO.framework */; };
572EF22C1B51F16C00EEBB58 /* SocketIO_iOSTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 572EF22B1B51F16C00EEBB58 /* SocketIO_iOSTests.swift */; };
572EF23D1B51F18A00EEBB58 /* SocketIO-Mac.h in Headers */ = {isa = PBXBuildFile; fileRef = 572EF23C1B51F18A00EEBB58 /* SocketIO-Mac.h */; settings = {ATTRIBUTES = (Public, ); }; };
572EF2431B51F18A00EEBB58 /* SocketIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 572EF2381B51F18A00EEBB58 /* SocketIO.framework */; };
572EF24A1B51F18A00EEBB58 /* SocketIO_MacTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 572EF2491B51F18A00EEBB58 /* SocketIO_MacTests.swift */; };
@ -39,6 +38,30 @@
5764DFA01B51F254004FF46E /* SwiftRegex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF871B51F254004FF46E /* SwiftRegex.swift */; };
5764DFA11B51F254004FF46E /* WebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF881B51F254004FF46E /* WebSocket.swift */; };
5764DFA21B51F254004FF46E /* WebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF881B51F254004FF46E /* WebSocket.swift */; };
74781D5A1B7E83930042CACA /* SocketIOClientStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74781D591B7E83930042CACA /* SocketIOClientStatus.swift */; };
74781D5B1B7E83930042CACA /* SocketIOClientStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74781D591B7E83930042CACA /* SocketIOClientStatus.swift */; };
74781D5C1B7E83930042CACA /* SocketIOClientStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74781D591B7E83930042CACA /* SocketIOClientStatus.swift */; };
74781D5D1B7E83930042CACA /* SocketIOClientStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74781D591B7E83930042CACA /* SocketIOClientStatus.swift */; };
941A4ABA1B67A56C00C42318 /* TestKind.swift in Sources */ = {isa = PBXBuildFile; fileRef = 941A4AB91B67A56C00C42318 /* TestKind.swift */; };
94242BB81B67B0E500AAAC9D /* SocketNamespaceAcknowledgementTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94242BB71B67B0E500AAAC9D /* SocketNamespaceAcknowledgementTest.swift */; };
945B65351B5FCEEA0081E995 /* SocketAckManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF7C1B51F254004FF46E /* SocketAckManager.swift */; };
945B65361B5FCEEA0081E995 /* SocketAnyEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF7D1B51F254004FF46E /* SocketAnyEvent.swift */; };
945B65371B5FCEEA0081E995 /* SocketEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF7E1B51F254004FF46E /* SocketEngine.swift */; };
945B65381B5FCEEA0081E995 /* SocketEngineClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF7F1B51F254004FF46E /* SocketEngineClient.swift */; };
945B65391B5FCEEA0081E995 /* SocketEventHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF801B51F254004FF46E /* SocketEventHandler.swift */; };
945B653A1B5FCEEA0081E995 /* SocketFixUTF8.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF811B51F254004FF46E /* SocketFixUTF8.swift */; };
945B653B1B5FCEEA0081E995 /* SocketIOClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF821B51F254004FF46E /* SocketIOClient.swift */; };
945B653C1B5FCEEA0081E995 /* SocketLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF831B51F254004FF46E /* SocketLogger.swift */; };
945B653D1B5FCEEA0081E995 /* SocketPacket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF841B51F254004FF46E /* SocketPacket.swift */; };
945B653E1B5FCEEA0081E995 /* SocketParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF851B51F254004FF46E /* SocketParser.swift */; };
945B653F1B5FCEEA0081E995 /* SocketTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF861B51F254004FF46E /* SocketTypes.swift */; };
945B65401B5FCEEA0081E995 /* SwiftRegex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF871B51F254004FF46E /* SwiftRegex.swift */; };
945B65411B5FCEEA0081E995 /* WebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF881B51F254004FF46E /* WebSocket.swift */; };
945B65431B63D9DB0081E995 /* SocketEmitTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 945B65421B63D9DB0081E995 /* SocketEmitTest.swift */; };
94ADAC491B652D3300FD79AE /* SocketNamespaceEmitTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94ADAC481B652D3300FD79AE /* SocketNamespaceEmitTest.swift */; };
94ADAC4B1B6632DD00FD79AE /* SocketAcknowledgementTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94ADAC4A1B6632DD00FD79AE /* SocketAcknowledgementTest.swift */; };
94CB8F0B1B6E48B90019ED53 /* SocketTestCases.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94CB8F0A1B6E48B90019ED53 /* SocketTestCases.swift */; };
94CB8F0D1B6E66E60019ED53 /* AbstractSocketTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94CB8F0C1B6E66E60019ED53 /* AbstractSocketTest.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -64,7 +87,6 @@
572EF21E1B51F16C00EEBB58 /* SocketIO-iOS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SocketIO-iOS.h"; sourceTree = "<group>"; };
572EF2241B51F16C00EEBB58 /* SocketIO-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SocketIO-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
572EF22A1B51F16C00EEBB58 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
572EF22B1B51F16C00EEBB58 /* SocketIO_iOSTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketIO_iOSTests.swift; sourceTree = "<group>"; };
572EF2381B51F18A00EEBB58 /* SocketIO.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SocketIO.framework; sourceTree = BUILT_PRODUCTS_DIR; };
572EF23B1B51F18A00EEBB58 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
572EF23C1B51F18A00EEBB58 /* SocketIO-Mac.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SocketIO-Mac.h"; sourceTree = "<group>"; };
@ -84,6 +106,14 @@
5764DF861B51F254004FF46E /* SocketTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketTypes.swift; path = SocketIOClientSwift/SocketTypes.swift; sourceTree = "<group>"; };
5764DF871B51F254004FF46E /* SwiftRegex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SwiftRegex.swift; path = SocketIOClientSwift/SwiftRegex.swift; sourceTree = "<group>"; };
5764DF881B51F254004FF46E /* WebSocket.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WebSocket.swift; path = SocketIOClientSwift/WebSocket.swift; sourceTree = "<group>"; };
74781D591B7E83930042CACA /* SocketIOClientStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketIOClientStatus.swift; path = SocketIOClientSwift/SocketIOClientStatus.swift; sourceTree = "<group>"; };
941A4AB91B67A56C00C42318 /* TestKind.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestKind.swift; sourceTree = "<group>"; };
94242BB71B67B0E500AAAC9D /* SocketNamespaceAcknowledgementTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketNamespaceAcknowledgementTest.swift; sourceTree = "<group>"; };
945B65421B63D9DB0081E995 /* SocketEmitTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketEmitTest.swift; sourceTree = "<group>"; };
94ADAC481B652D3300FD79AE /* SocketNamespaceEmitTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketNamespaceEmitTest.swift; sourceTree = "<group>"; };
94ADAC4A1B6632DD00FD79AE /* SocketAcknowledgementTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketAcknowledgementTest.swift; sourceTree = "<group>"; };
94CB8F0A1B6E48B90019ED53 /* SocketTestCases.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketTestCases.swift; sourceTree = "<group>"; };
94CB8F0C1B6E66E60019ED53 /* AbstractSocketTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AbstractSocketTest.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -163,7 +193,13 @@
572EF2281B51F16C00EEBB58 /* SocketIO-iOSTests */ = {
isa = PBXGroup;
children = (
572EF22B1B51F16C00EEBB58 /* SocketIO_iOSTests.swift */,
945B65421B63D9DB0081E995 /* SocketEmitTest.swift */,
94ADAC4A1B6632DD00FD79AE /* SocketAcknowledgementTest.swift */,
94ADAC481B652D3300FD79AE /* SocketNamespaceEmitTest.swift */,
94242BB71B67B0E500AAAC9D /* SocketNamespaceAcknowledgementTest.swift */,
941A4AB91B67A56C00C42318 /* TestKind.swift */,
94CB8F0A1B6E48B90019ED53 /* SocketTestCases.swift */,
94CB8F0C1B6E66E60019ED53 /* AbstractSocketTest.swift */,
572EF2291B51F16C00EEBB58 /* Supporting Files */,
);
path = "SocketIO-iOSTests";
@ -221,6 +257,7 @@
5764DF801B51F254004FF46E /* SocketEventHandler.swift */,
5764DF811B51F254004FF46E /* SocketFixUTF8.swift */,
5764DF821B51F254004FF46E /* SocketIOClient.swift */,
74781D591B7E83930042CACA /* SocketIOClientStatus.swift */,
5764DF831B51F254004FF46E /* SocketLogger.swift */,
5764DF841B51F254004FF46E /* SocketPacket.swift */,
5764DF851B51F254004FF46E /* SocketParser.swift */,
@ -413,6 +450,7 @@
5764DF951B51F254004FF46E /* SocketIOClient.swift in Sources */,
5764DF8B1B51F254004FF46E /* SocketAnyEvent.swift in Sources */,
5764DF971B51F254004FF46E /* SocketLogger.swift in Sources */,
74781D5A1B7E83930042CACA /* SocketIOClientStatus.swift in Sources */,
5764DFA11B51F254004FF46E /* WebSocket.swift in Sources */,
5764DF991B51F254004FF46E /* SocketPacket.swift in Sources */,
5764DF891B51F254004FF46E /* SocketAckManager.swift in Sources */,
@ -424,7 +462,27 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
572EF22C1B51F16C00EEBB58 /* SocketIO_iOSTests.swift in Sources */,
945B653E1B5FCEEA0081E995 /* SocketParser.swift in Sources */,
945B653D1B5FCEEA0081E995 /* SocketPacket.swift in Sources */,
945B653A1B5FCEEA0081E995 /* SocketFixUTF8.swift in Sources */,
945B65391B5FCEEA0081E995 /* SocketEventHandler.swift in Sources */,
94CB8F0B1B6E48B90019ED53 /* SocketTestCases.swift in Sources */,
945B65371B5FCEEA0081E995 /* SocketEngine.swift in Sources */,
945B65351B5FCEEA0081E995 /* SocketAckManager.swift in Sources */,
941A4ABA1B67A56C00C42318 /* TestKind.swift in Sources */,
94CB8F0D1B6E66E60019ED53 /* AbstractSocketTest.swift in Sources */,
945B65431B63D9DB0081E995 /* SocketEmitTest.swift in Sources */,
945B65401B5FCEEA0081E995 /* SwiftRegex.swift in Sources */,
945B653C1B5FCEEA0081E995 /* SocketLogger.swift in Sources */,
945B65381B5FCEEA0081E995 /* SocketEngineClient.swift in Sources */,
945B65361B5FCEEA0081E995 /* SocketAnyEvent.swift in Sources */,
94ADAC4B1B6632DD00FD79AE /* SocketAcknowledgementTest.swift in Sources */,
945B653F1B5FCEEA0081E995 /* SocketTypes.swift in Sources */,
74781D5B1B7E83930042CACA /* SocketIOClientStatus.swift in Sources */,
945B653B1B5FCEEA0081E995 /* SocketIOClient.swift in Sources */,
94ADAC491B652D3300FD79AE /* SocketNamespaceEmitTest.swift in Sources */,
945B65411B5FCEEA0081E995 /* WebSocket.swift in Sources */,
94242BB81B67B0E500AAAC9D /* SocketNamespaceAcknowledgementTest.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -441,6 +499,7 @@
5764DF961B51F254004FF46E /* SocketIOClient.swift in Sources */,
5764DF8C1B51F254004FF46E /* SocketAnyEvent.swift in Sources */,
5764DF981B51F254004FF46E /* SocketLogger.swift in Sources */,
74781D5C1B7E83930042CACA /* SocketIOClientStatus.swift in Sources */,
5764DFA21B51F254004FF46E /* WebSocket.swift in Sources */,
5764DF9A1B51F254004FF46E /* SocketPacket.swift in Sources */,
5764DF8A1B51F254004FF46E /* SocketAckManager.swift in Sources */,
@ -453,6 +512,7 @@
buildActionMask = 2147483647;
files = (
572EF24A1B51F18A00EEBB58 /* SocketIO_MacTests.swift in Sources */,
74781D5D1B7E83930042CACA /* SocketIOClientStatus.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -485,7 +545,7 @@
isa = XCBuildConfiguration;
buildSettings = {
PRODUCT_NAME = SocketIO;
SWIFT_WHOLE_MODULE_OPTIMIZATION = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
};
name = Release;
};

View File

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

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

View File

@ -1,6 +1,6 @@
//
// SocketAnyEvent.swift
// Socket.IO-Swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 3/28/15.
//
@ -24,11 +24,14 @@
import Foundation
@objc public final class SocketAnyEvent {
public let event:String!
public let items:NSArray?
@objc public final class SocketAnyEvent: NSObject {
public let event: String!
public let items: NSArray?
override public var description: String {
return "SocketAnyEvent: Event: \(event) items: \(items ?? nil)"
}
init(event:String, items:NSArray?) {
init(event: String, items: NSArray?) {
self.event = event
self.items = items
}

View File

@ -1,6 +1,6 @@
//
// SocketEngine.swift
// Socket.IO-Swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 3/3/15.
//
@ -25,24 +25,23 @@
import Foundation
public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
private typealias Probe = (msg:String, type:PacketType, data:ContiguousArray<NSData>?)
private typealias Probe = (msg: String, type: PacketType, data: [NSData]?)
private typealias ProbeWaitQueue = [Probe]
private let allowedCharacterSet = NSCharacterSet(charactersInString: "!*'();:@&=+$,/?%#[]\" {}").invertedSet
private let workQueue = NSOperationQueue()
private let emitQueue = dispatch_queue_create("engineEmitQueue", DISPATCH_QUEUE_SERIAL)
private let parseQueue = dispatch_queue_create("engineParseQueue", DISPATCH_QUEUE_SERIAL)
private let handleQueue = dispatch_queue_create("engineHandleQueue", DISPATCH_QUEUE_SERIAL)
private let session:NSURLSession!
private let session: NSURLSession!
private var closed = false
private var _connected = false
private var extraHeaders:[String: String]?
private var extraHeaders: [String: String]?
private var fastUpgrade = false
private var forcePolling = false
private var forceWebsockets = false
private var pingInterval:Double?
private var pingTimer:NSTimer?
private var pingInterval: Double?
private var pingTimer: NSTimer?
private var pingTimeout = 0.0 {
didSet {
pongsMissedMax = Int(pingTimeout / (pingInterval ?? 25))
@ -51,117 +50,102 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
private var pongsMissed = 0
private var pongsMissedMax = 0
private var postWait = [String]()
private var _polling = true
private var probing = false
private var probeWait = ProbeWaitQueue()
private var waitingForPoll = false
private var waitingForPost = false
private var _websocket = false
private var websocketConnected = false
let logType = "SocketEngine"
var connected:Bool {
return _connected
}
weak var client:SocketEngineClient?
var cookies:[NSHTTPCookie]?
var log = false
var polling:Bool {
return _polling
}
private(set) var connected = false
private(set) var polling = true
private(set) var websocket = false
weak var client: SocketEngineClient?
var cookies: [NSHTTPCookie]?
var sid = ""
var socketPath = ""
var urlPolling:String?
var urlWebSocket:String?
var websocket:Bool {
return _websocket
}
var urlPolling: String?
var urlWebSocket: String?
var ws:WebSocket?
public enum PacketType:Int {
case OPEN = 0
case CLOSE = 1
case PING = 2
case PONG = 3
case MESSAGE = 4
case UPGRADE = 5
case NOOP = 6
init?(str:String?) {
if let value = str?.toInt(), raw = PacketType(rawValue: value) {
public enum PacketType: Int {
case Open, Close, Ping, Pong, Message, Upgrade, Noop
init?(str: String?) {
if let value = Int(str ?? ""), raw = PacketType(rawValue: value) {
self = raw
} else {
return nil
}
}
}
public init(client:SocketEngineClient, sessionDelegate:NSURLSessionDelegate?) {
public init(client: SocketEngineClient, sessionDelegate: NSURLSessionDelegate?) {
self.client = client
self.session = NSURLSession(configuration: NSURLSessionConfiguration.ephemeralSessionConfiguration(),
self.session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration(),
delegate: sessionDelegate, delegateQueue: workQueue)
}
public convenience init(client:SocketEngineClient, opts:NSDictionary?) {
public convenience init(client: SocketEngineClient, opts: NSDictionary?) {
self.init(client: client, sessionDelegate: opts?["sessionDelegate"] as? NSURLSessionDelegate)
forceWebsockets = opts?["forceWebsockets"] as? Bool ?? false
forcePolling = opts?["forcePolling"] as? Bool ?? false
cookies = opts?["cookies"] as? [NSHTTPCookie]
log = opts?["log"] as? Bool ?? false
socketPath = opts?["path"] as? String ?? ""
extraHeaders = opts?["extraHeaders"] as? [String: String]
}
deinit {
SocketLogger.log("Engine is being deinit", client: self)
}
public func close(#fast:Bool) {
public func close(fast fast: Bool) {
SocketLogger.log("Engine is being closed. Fast: %@", client: self, args: fast)
pingTimer?.invalidate()
closed = true
ws?.disconnect()
if fast || polling {
write("", withType: PacketType.CLOSE, withData: nil)
write("", withType: PacketType.Close, withData: nil)
client?.engineDidClose("Disconnect")
}
stopPolling()
}
private func createBinaryDataForSend(data:NSData) -> (NSData?, String?) {
private func createBinaryDataForSend(data: NSData) -> (NSData?, String?) {
if websocket {
var byteArray = [UInt8](count: 1, repeatedValue: 0x0)
byteArray[0] = 4
var mutData = NSMutableData(bytes: &byteArray, length: 1)
let mutData = NSMutableData(bytes: &byteArray, length: 1)
mutData.appendData(data)
return (mutData, nil)
} else {
var str = "b4"
str += data.base64EncodedStringWithOptions(
NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
return (nil, str)
}
}
private func createURLs(params:[String: AnyObject]?) -> (String?, String?) {
private func createURLs(params: [String: AnyObject]?) -> (String?, String?) {
if client == nil {
return (nil, nil)
}
let path = socketPath == "" ? "/socket.io" : socketPath
var url = "\(client!.socketURL)\(path)/?transport="
var urlPolling:String
var urlWebSocket:String
let url = "\(client!.socketURL)\(path)/?transport="
var urlPolling: String
var urlWebSocket: String
if client!.secure {
urlPolling = "https://" + url + "polling"
urlWebSocket = "wss://" + url + "websocket"
@ -169,15 +153,15 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
urlPolling = "http://" + url + "polling"
urlWebSocket = "ws://" + url + "websocket"
}
if params != nil {
for (key, value) in params! {
let keyEsc = key.stringByAddingPercentEncodingWithAllowedCharacters(
allowedCharacterSet)!
urlPolling += "&\(keyEsc)="
urlWebSocket += "&\(keyEsc)="
if value is String {
let valueEsc = (value as! String).stringByAddingPercentEncodingWithAllowedCharacters(
allowedCharacterSet)!
@ -189,11 +173,11 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
}
}
}
return (urlPolling, urlWebSocket)
}
private func createWebsocket(andConnect connect:Bool) {
private func createWebsocket(andConnect connect: Bool) {
let wsUrl = urlWebSocket! + (sid == "" ? "" : "&sid=\(sid)")
ws = WebSocket(url: NSURL(string: wsUrl)!,
@ -207,34 +191,34 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
ws?.queue = handleQueue
ws?.delegate = self
if connect {
ws?.connect()
}
}
private func doFastUpgrade() {
if waitingForPoll {
SocketLogger.err("Outstanding poll when switched to WebSockets," +
"we'll probably disconnect soon. You should report this.", client: self)
}
sendWebSocketMessage("", withType: PacketType.UPGRADE, datas: nil)
_websocket = true
_polling = false
sendWebSocketMessage("", withType: PacketType.Upgrade, datas: nil)
websocket = true
polling = false
fastUpgrade = false
probing = false
flushProbeWait()
}
private func doPoll() {
if websocket || waitingForPoll || !connected {
return
}
waitingForPoll = true
let req = NSMutableURLRequest(URL: NSURL(string: urlPolling! + "&sid=\(sid)&b64=1")!)
if cookies != nil {
let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies!)
req.allHTTPHeaderFields = headers
@ -248,37 +232,37 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
doRequest(req)
}
private func doRequest(req:NSMutableURLRequest) {
private func doRequest(req: NSMutableURLRequest) {
if !polling {
return
}
req.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalAndRemoteCacheData
SocketLogger.log("Doing polling request", client: self)
session.dataTaskWithRequest(req) {[weak self] data, res, err in
if let this = self {
if err != nil {
if err != nil || data == nil {
if this.polling {
this.handlePollingFailed(err.localizedDescription)
this.handlePollingFailed(err?.localizedDescription ?? "Error")
} else {
SocketLogger.err(err.localizedDescription, client: this)
SocketLogger.err(err?.localizedDescription ?? "Error", client: this)
}
return
}
SocketLogger.log("Got polling response", client: this)
if let str = NSString(data: data, encoding: NSUTF8StringEncoding) as? String {
if let str = NSString(data: data!, encoding: NSUTF8StringEncoding) as? String {
dispatch_async(this.parseQueue) {[weak this] in
this?.parsePollingMessage(str)
}
}
this.waitingForPoll = false
if this.fastUpgrade {
this.doFastUpgrade()
} else if !this.closed && this.polling {
@ -286,25 +270,25 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
}
}}.resume()
}
private func flushProbeWait() {
SocketLogger.log("Flushing probe wait", client: self)
dispatch_async(emitQueue) {[weak self] in
if let this = self {
for waiter in this.probeWait {
this.write(waiter.msg, withType: waiter.type, withData: waiter.data)
}
this.probeWait.removeAll(keepCapacity: false)
if this.postWait.count != 0 {
this.flushWaitingForPostToWebSocket()
}
}
}
}
private func flushWaitingForPost() {
if postWait.count == 0 || !connected {
return
@ -312,49 +296,49 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
flushWaitingForPostToWebSocket()
return
}
var postStr = ""
for packet in postWait {
let len = count(packet)
let len = packet.characters.count
postStr += "\(len):\(packet)"
}
postWait.removeAll(keepCapacity: false)
let req = NSMutableURLRequest(URL: NSURL(string: urlPolling! + "&sid=\(sid)")!)
if cookies != nil {
let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies!)
if let cookies = cookies {
let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies)
req.allHTTPHeaderFields = headers
}
req.HTTPMethod = "POST"
req.setValue("text/plain; charset=UTF-8", forHTTPHeaderField: "Content-Type")
let postData = postStr.dataUsingEncoding(NSUTF8StringEncoding,
allowLossyConversion: false)!
req.HTTPBody = postData
req.setValue(String(postData.length), forHTTPHeaderField: "Content-Length")
waitingForPost = true
SocketLogger.log("POSTing: %@", client: self, args: postStr)
session.dataTaskWithRequest(req) {[weak self] data, res, err in
if let this = self {
if err != nil && this.polling {
this.handlePollingFailed(err.localizedDescription)
this.handlePollingFailed(err?.localizedDescription ?? "Error")
return
} else if err != nil {
NSLog(err.localizedDescription)
NSLog(err?.localizedDescription ?? "Error")
return
}
this.waitingForPost = false
dispatch_async(this.emitQueue) {[weak this] in
if !(this?.fastUpgrade ?? true) {
this?.flushWaitingForPost()
@ -363,253 +347,250 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
}
}}.resume()
}
// We had packets waiting for send when we upgraded
// Send them raw
private func flushWaitingForPostToWebSocket() {
for msg in postWait {
ws?.writeString(msg)
}
postWait.removeAll(keepCapacity: true)
}
private func handleClose() {
if polling {
client?.engineDidClose("Disconnect")
if let client = client where polling == true {
client.engineDidClose("Disconnect")
}
}
private func checkIfMessageIsBase64Binary(var message:String) {
private func checkIfMessageIsBase64Binary(var message: String) {
if message.hasPrefix("b4") {
// binary in base64 string
message.removeRange(Range<String.Index>(start: message.startIndex,
end: advance(message.startIndex, 2)))
end: message.startIndex.advancedBy(2)))
if let data = NSData(base64EncodedString: message,
options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters), client = client {
dispatch_async(client.handleQueue) {[weak self] in
self?.client?.parseBinaryData(data)
}
options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters) {
client?.parseBinaryData(data)
}
}
}
private func handleMessage(message:String) {
if let client = client {
dispatch_async(client.handleQueue) {[weak client] in
client?.parseSocketMessage(message)
}
}
private func handleMessage(message: String) {
client?.parseSocketMessage(message)
}
private func handleNOOP() {
doPoll()
}
private func handleOpen(openData:String) {
var err:NSError?
private func handleOpen(openData: String) {
let mesData = openData.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
if let json = NSJSONSerialization.JSONObjectWithData(mesData,
options: NSJSONReadingOptions.AllowFragments,
error: &err) as? NSDictionary, sid = json["sid"] as? String {
do {
let json = try NSJSONSerialization.JSONObjectWithData(mesData,
options: NSJSONReadingOptions.AllowFragments) as? NSDictionary
if let sid = json?["sid"] as? String {
let upgradeWs: Bool
self.sid = sid
_connected = true
connected = true
if !forcePolling && !forceWebsockets {
createWebsocket(andConnect: true)
if let upgrades = json?["upgrades"] as? [String] {
upgradeWs = upgrades.filter {$0 == "websocket"}.count != 0
} else {
upgradeWs = false
}
if let pingInterval = json["pingInterval"] as? Double, pingTimeout = json["pingTimeout"] as? Double {
if let pingInterval = json?["pingInterval"] as? Double, pingTimeout = json?["pingTimeout"] as? Double {
self.pingInterval = pingInterval / 1000.0
self.pingTimeout = pingTimeout / 1000.0
}
} else {
client?.didError("Engine failed to handshake")
if !forcePolling && !forceWebsockets && upgradeWs {
createWebsocket(andConnect: true)
}
}
} catch {
SocketLogger.err("Error parsing open packet", client: self)
return
}
startPingTimer()
if !forceWebsockets {
doPoll()
}
}
private func handlePong(pongMessage:String) {
private func handlePong(pongMessage: String) {
pongsMissed = 0
// We should upgrade
if pongMessage == "3probe" {
upgradeTransport()
}
}
// A poll failed, tell the client about it
private func handlePollingFailed(reason:String) {
_connected = false
private func handlePollingFailed(reason: String) {
connected = false
ws?.disconnect()
pingTimer?.invalidate()
waitingForPoll = false
waitingForPost = false
// If cancelled we were already closing
if client == nil || reason == "cancelled" {
return
}
if !closed {
client?.didError(reason)
client?.engineDidClose(reason)
}
}
public func open(opts:[String: AnyObject]? = nil) {
public func open(opts: [String: AnyObject]? = nil) {
if connected {
SocketLogger.err("Tried to open while connected", client: self)
client?.didError("Tried to open while connected")
return
}
SocketLogger.log("Starting engine", client: self)
SocketLogger.log("Handshaking", client: self)
closed = false
(urlPolling, urlWebSocket) = createURLs(opts)
if forceWebsockets {
_polling = false
_websocket = true
polling = false
websocket = true
createWebsocket(andConnect: true)
return
}
let reqPolling = NSMutableURLRequest(URL: NSURL(string: urlPolling! + "&b64=1")!)
if cookies != nil {
let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies!)
reqPolling.allHTTPHeaderFields = headers
}
if extraHeaders != nil {
for (headerName, value) in extraHeaders! {
if let extraHeaders = extraHeaders {
for (headerName, value) in extraHeaders {
reqPolling.setValue(value, forHTTPHeaderField: headerName)
}
}
doRequest(reqPolling)
}
// Translatation of engine.io-parser#decodePayload
private func parsePollingMessage(str:String) {
if count(str) == 1 {
guard str.characters.count != 1 else {
return
}
// println(str)
let strArray = Array(str)
let strArray = Array(str.characters)
var length = ""
var n = 0
var msg = ""
func testLength(length:String, inout n:Int) -> Bool {
if let num = length.toInt() {
if let num = Int(length) {
n = num
return false
} else {
return true
}
}
for var i = 0, l = count(str); i < l; i++ {
for var i = 0, l = str.characters.count; i < l; i++ {
let chr = String(strArray[i])
if chr != ":" {
length += chr
} else {
if length == "" || testLength(length, &n) {
if length == "" || testLength(length, n: &n) {
SocketLogger.err("Parsing error: %@", client: self, args: str)
handlePollingFailed("Error parsing XHR message")
return
}
msg = String(strArray[i+1...i+n])
if let lengthInt = length.toInt() where lengthInt != count(msg) {
if let lengthInt = Int(length) where lengthInt != msg.characters.count {
SocketLogger.err("Parsing error: %@", client: self, args: str)
return
}
if count(msg) != 0 {
if msg.characters.count != 0 {
// Be sure to capture the value of the msg
dispatch_async(handleQueue) {[weak self, msg] in
self?.parseEngineMessage(msg, fromPolling: true)
}
}
i += n
length = ""
}
}
}
private func parseEngineData(data:NSData) {
if let client = client {
dispatch_async(client.handleQueue) {[weak self] in
self?.client?.parseBinaryData(data.subdataWithRange(NSMakeRange(1, data.length - 1)))
}
}
private func parseEngineData(data: NSData) {
client?.parseBinaryData(data.subdataWithRange(NSMakeRange(1, data.length - 1)))
}
private func parseEngineMessage(var message:String, fromPolling:Bool) {
private func parseEngineMessage(var message: String, fromPolling: Bool) {
SocketLogger.log("Got message: %@", client: self, args: message)
if fromPolling {
fixDoubleUTF8(&message)
}
let type = PacketType(str: (message["^(\\d)"].groups()?[1])) ?? {
self.checkIfMessageIsBase64Binary(message)
return PacketType.NOOP
}()
return PacketType.Noop
}()
switch type {
case PacketType.MESSAGE:
case PacketType.Message:
message.removeAtIndex(message.startIndex)
handleMessage(message)
case PacketType.NOOP:
case PacketType.Noop:
handleNOOP()
case PacketType.PONG:
case PacketType.Pong:
handlePong(message)
case PacketType.OPEN:
case PacketType.Open:
message.removeAtIndex(message.startIndex)
handleOpen(message)
case PacketType.CLOSE:
case PacketType.Close:
handleClose()
default:
SocketLogger.log("Got unknown packet type", client: self)
}
}
private func probeWebSocket() {
if websocketConnected {
sendWebSocketMessage("probe", withType: PacketType.PING)
sendWebSocketMessage("probe", withType: PacketType.Ping)
}
}
/// Send an engine message (4)
public func send(msg:String, withData datas:ContiguousArray<NSData>?) {
public func send(msg: String, withData datas: [NSData]?) {
if probing {
probeWait.append((msg, PacketType.MESSAGE, datas))
probeWait.append((msg, PacketType.Message, datas))
} else {
write(msg, withType: PacketType.MESSAGE, withData: datas)
write(msg, withType: PacketType.Message, withData: datas)
}
}
@objc private func sendPing() {
//Server is not responding
if pongsMissed > pongsMissedMax {
@ -617,59 +598,59 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
client?.engineDidClose("Ping timeout")
return
}
++pongsMissed
write("", withType: PacketType.PING, withData: nil)
write("", withType: PacketType.Ping, withData: nil)
}
/// Send polling message.
/// Only call on emitQueue
private func sendPollMessage(var msg:String, withType type:PacketType,
datas:ContiguousArray<NSData>? = nil) {
private func sendPollMessage(var msg: String, withType type: PacketType,
datas:[NSData]? = nil) {
SocketLogger.log("Sending poll: %@ as type: %@", client: self, args: msg, type.rawValue)
doubleEncodeUTF8(&msg)
let strMsg = "\(type.rawValue)\(msg)"
postWait.append(strMsg)
if datas != nil {
for data in datas! {
let (nilData, b64Data) = createBinaryDataForSend(data)
if let datas = datas {
for data in datas {
let (_, b64Data) = createBinaryDataForSend(data)
postWait.append(b64Data!)
}
}
if !waitingForPost {
flushWaitingForPost()
}
}
/// Send message on WebSockets
/// Only call on emitQueue
private func sendWebSocketMessage(str:String, withType type:PacketType,
datas:ContiguousArray<NSData>? = nil) {
private func sendWebSocketMessage(str: String, withType type: PacketType,
datas:[NSData]? = nil) {
SocketLogger.log("Sending ws: %@ as type: %@", client: self, args: str, type.rawValue)
ws?.writeString("\(type.rawValue)\(str)")
if datas != nil {
for data in datas! {
let (data, nilString) = createBinaryDataForSend(data)
if let datas = datas {
for data in datas {
let (data, _) = createBinaryDataForSend(data)
if data != nil {
ws?.writeData(data!)
}
}
}
}
// Starts the ping timer
private func startPingTimer() {
if pingInterval == nil {
guard pingInterval != nil else {
return
}
pingTimer?.invalidate()
dispatch_async(dispatch_get_main_queue()) {[weak self] in
if let this = self {
@ -678,25 +659,25 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
}
}
}
func stopPolling() {
session.invalidateAndCancel()
}
private func upgradeTransport() {
if websocketConnected {
SocketLogger.log("Upgrading transport to WebSockets", client: self)
fastUpgrade = true
sendPollMessage("", withType: PacketType.NOOP)
sendPollMessage("", withType: PacketType.Noop)
// After this point, we should not send anymore polling messages
}
}
/**
Write a message, independent of transport.
*/
public func write(msg:String, withType type:PacketType, withData data:ContiguousArray<NSData>?) {
public func write(msg: String, withType type: PacketType, withData data: [NSData]?) {
dispatch_async(emitQueue) {[weak self] in
if let this = self where this.connected {
if this.websocket {
@ -711,55 +692,55 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
}
}
}
/**
Write a message, independent of transport. For Objective-C. withData should be an NSArray of NSData
*/
public func writeObjc(msg:String, withType type:Int, withData data:NSArray?) {
public func writeObjc(msg: String, withType type: Int, withData data: NSArray?) {
if let pType = PacketType(rawValue: type) {
var arr = ContiguousArray<NSData>()
if data != nil {
for d in data! {
var arr = [NSData]()
if let data = data {
for d in data {
arr.append(d as! NSData)
}
}
write(msg, withType: pType, withData: arr)
}
}
// Delagate methods
public func websocketDidConnect(socket:WebSocket) {
websocketConnected = true
if !forceWebsockets {
probing = true
probeWebSocket()
} else {
_connected = true
connected = true
probing = false
_polling = false
polling = false
}
}
public func websocketDidDisconnect(socket:WebSocket, error:NSError?) {
public func websocketDidDisconnect(socket: WebSocket, error: NSError?) {
websocketConnected = false
probing = false
if closed {
client?.engineDidClose("Disconnect")
return
}
if websocket {
pingTimer?.invalidate()
_connected = false
_websocket = false
connected = false
websocket = false
let reason = error?.localizedDescription ?? "Socket Disconnected"
if error != nil {
client?.didError(reason)
}
@ -769,12 +750,12 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
flushProbeWait()
}
}
public func websocketDidReceiveMessage(socket:WebSocket, text:String) {
public func websocketDidReceiveMessage(socket: WebSocket, text: String) {
parseEngineMessage(text, fromPolling: false)
}
public func websocketDidReceiveData(socket:WebSocket, data:NSData) {
public func websocketDidReceiveData(socket: WebSocket, data: NSData) {
parseEngineData(data)
}
}

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
//
// SocketTypes.swift
// SocketIO-Swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 4/8/15.
//
@ -24,11 +24,10 @@
import Foundation
// @objc_block is undocumented, but is used because Swift assumes that all
// Objective-C blocks are copied, but Objective-C assumes that Swift will copy it.
// And the way things are done here, the bridging fails to copy the block in
// SocketAckMap#addAck
public typealias AckCallback = @objc_block (NSArray?) -> Void
public typealias AckCallback = (NSArray?) -> Void
public typealias AckEmitter = (AnyObject...) -> Void
public typealias AckEmitterObjectiveC = (NSArray) -> Void
public typealias NormalCallback = (NSArray?, AckEmitter?) -> Void
public typealias OnAckCallback = (timeout:UInt64, callback:AckCallback) -> Void
public typealias NormalCallbackObjectiveC = (NSArray?, AckEmitterObjectiveC?) -> Void
public typealias OnAckCallback = (timeoutAfter:UInt64, callback:AckCallback) -> Void

View File

@ -18,34 +18,34 @@ var swiftRegexCache = [String: NSRegularExpression]()
public class SwiftRegex: NSObject, BooleanType {
var target:String
var regex: NSRegularExpression
init(target:String, pattern:String, options:NSRegularExpressionOptions = nil) {
init(target:String, pattern:String, options:NSRegularExpressionOptions?) {
self.target = target
if let regex = swiftRegexCache[pattern] {
self.regex = regex
} else {
var error: NSError?
if let regex = NSRegularExpression(pattern: pattern, options:options, error:&error) {
do {
let regex = try NSRegularExpression(pattern: pattern, options:
NSRegularExpressionOptions.DotMatchesLineSeparators)
swiftRegexCache[pattern] = regex
self.regex = regex
}
else {
SwiftRegex.failure("Error in pattern: \(pattern) - \(error)")
} catch let error1 as NSError {
SwiftRegex.failure("Error in pattern: \(pattern) - \(error1)")
self.regex = NSRegularExpression()
}
}
super.init()
}
class func failure(message: String) {
println("SwiftRegex: "+message)
print("SwiftRegex: "+message)
//assert(false,"SwiftRegex: failed")
}
final var targetRange: NSRange {
return NSRange(location: 0,length: count(target.utf16))
return NSRange(location: 0,length: target.utf16.count)
}
final func substring(range: NSRange) -> String? {
if ( range.location != NSNotFound ) {
return (target as NSString).substringWithRange(range)
@ -53,23 +53,24 @@ public class SwiftRegex: NSObject, BooleanType {
return nil
}
}
public func doesMatch(options: NSMatchingOptions = nil) -> Bool {
return range(options: options).location != NSNotFound
public func doesMatch(options: NSMatchingOptions!) -> Bool {
return range(options).location != NSNotFound
}
public func range(options: NSMatchingOptions = nil) -> NSRange {
return regex.rangeOfFirstMatchInString(target as String, options: nil, range: targetRange)
public func range(options: NSMatchingOptions) -> NSRange {
return regex.rangeOfFirstMatchInString(target as String, options: [], range: targetRange)
}
public func match(options: NSMatchingOptions = nil) -> String? {
return substring(range(options: options))
public func match(options: NSMatchingOptions) -> String? {
return substring(range(options))
}
public func groups(options: NSMatchingOptions = nil) -> [String]? {
return groupsForMatch(regex.firstMatchInString(target as String, options: options, range: targetRange))
public func groups() -> [String]? {
return groupsForMatch(regex.firstMatchInString(target as String, options:
NSMatchingOptions.WithoutAnchoringBounds, range: targetRange))
}
func groupsForMatch(match: NSTextCheckingResult!) -> [String]? {
if match != nil {
var groups = [String]()
@ -85,80 +86,75 @@ public class SwiftRegex: NSObject, BooleanType {
return nil
}
}
public subscript(groupno: Int) -> String? {
get {
return groups()?[groupno]
}
set(newValue) {
if newValue == nil {
return
}
for match in matchResults()!.reverse() {
for match in Array(matchResults().reverse()) {
let replacement = regex.replacementStringForResult(match,
inString: target as String, offset: 0, template: newValue!)
let mut = NSMutableString(string: target)
mut.replaceCharactersInRange(match.rangeAtIndex(groupno), withString: replacement)
target = mut as String
}
}
}
func matchResults(options: NSMatchingOptions = nil) -> [NSTextCheckingResult]? {
let matches = regex.matchesInString(target as String, options: options, range: targetRange)
as? [NSTextCheckingResult]
if matches != nil {
return matches!
} else {
return nil
}
func matchResults() -> [NSTextCheckingResult] {
let matches = regex.matchesInString(target as String, options:
NSMatchingOptions.WithoutAnchoringBounds, range: targetRange)
as [NSTextCheckingResult]
return matches
}
public func ranges(options: NSMatchingOptions = nil) -> [NSRange] {
return matchResults(options: options)!.map { $0.range }
public func ranges() -> [NSRange] {
return matchResults().map { $0.range }
}
public func matches(options: NSMatchingOptions = nil) -> [String] {
return matchResults(options: options)!.map( { self.substring($0.range)!})
public func matches() -> [String] {
return matchResults().map( { self.substring($0.range)!})
}
public func allGroups(options: NSMatchingOptions = nil) -> [[String]?] {
return matchResults(options: options)!.map {self.groupsForMatch($0)}
public func allGroups() -> [[String]?] {
return matchResults().map {self.groupsForMatch($0)}
}
public func dictionary(options: NSMatchingOptions = nil) -> Dictionary<String,String> {
public func dictionary(options: NSMatchingOptions!) -> Dictionary<String,String> {
var out = Dictionary<String,String>()
for match in matchResults(options: options)! {
for match in matchResults() {
out[substring(match.rangeAtIndex(1))!] = substring(match.rangeAtIndex(2))!
}
return out
}
func substituteMatches(substitution: ((NSTextCheckingResult, UnsafeMutablePointer<ObjCBool>) -> String),
options:NSMatchingOptions = nil) -> String {
options:NSMatchingOptions) -> String {
let out = NSMutableString()
var pos = 0
regex.enumerateMatchesInString(target as String, options: options, range: targetRange ) {
(match: NSTextCheckingResult!, flags: NSMatchingFlags, stop: UnsafeMutablePointer<ObjCBool>) in
let matchRange = match.range
regex.enumerateMatchesInString(target as String, options: options, range: targetRange ) {match, flags, stop in
let matchRange = match!.range
out.appendString( self.substring(NSRange(location:pos, length:matchRange.location-pos))!)
out.appendString( substitution(match, stop) )
out.appendString( substitution(match!, stop) )
pos = matchRange.location + matchRange.length
}
out.appendString(substring(NSRange(location:pos, length:targetRange.length-pos))!)
return out as String
}
public var boolValue: Bool {
return doesMatch()
return doesMatch(nil)
}
}
@ -170,7 +166,7 @@ extension String {
extension String {
public subscript(pattern: String) -> SwiftRegex {
return SwiftRegex(target: self, pattern: pattern)
return SwiftRegex(target: self, pattern: pattern, options: nil)
}
}
@ -178,20 +174,20 @@ public func ~= (left: SwiftRegex, right: String) -> String {
return left.substituteMatches({match, stop in
return left.regex.replacementStringForResult( match,
inString: left.target as String, offset: 0, template: right )
}, options: nil)
}, options: [])
}
public func ~= (left: SwiftRegex, right: [String]) -> String {
var matchNumber = 0
return left.substituteMatches({match, stop -> String in
if ++matchNumber == right.count {
stop.memory = true
}
return left.regex.replacementStringForResult( match,
inString: left.target as String, offset: 0, template: right[matchNumber-1] )
}, options: nil)
}, options: [])
}
public func ~= (left: SwiftRegex, right: (String) -> String) -> String {
@ -199,11 +195,11 @@ public func ~= (left: SwiftRegex, right: (String) -> String) -> String {
return left.substituteMatches(
{match, stop -> String in
right(left.substring(match.range)!)
}, options: nil)
}, options: [])
}
public func ~= (left: SwiftRegex, right: ([String]?) -> String) -> String {
return left.substituteMatches({match, stop -> String in
return right(left.groupsForMatch(match))
}, options: nil)
}, options: [])
}

View File

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