Compare commits

...

50 Commits

Author SHA1 Message Date
daltoniam 75721192c9 Merge branch 'master' of https://github.com/daltoniam/Starscream 2016-02-08 19:04:10 -08:00
daltoniam 0c4a99588f bumped version 2016-02-08 19:03:41 -08:00
Dalton 4387f497c9 Merge pull request #167 from ayking/master
fix : connect to a shutdown server will not get error call back
2016-02-08 18:57:00 -08:00
Dalton d87b422950 Merge pull request #168 from onevcat/master
Fix crashing when reconnecting repeatedly
2016-02-08 18:55:26 -08:00
onevcat c5569dff12 Fix crashing when reconnecting repeatedly 2016-02-08 22:40:11 +08:00
Alan YU 6b303eafec fix : connect to a shutdown server will not get error call back 2016-02-05 17:12:33 +08:00
daltoniam 0f8dd95f70 proper fix for #164 2016-01-29 10:52:18 -08:00
daltoniam ede7c9aa89 Merge branch 'master' of https://github.com/daltoniam/Starscream 2016-01-27 21:39:38 -08:00
daltoniam afefdff061 fixes for #158, #159, #161, #164 2016-01-27 21:39:13 -08:00
Dalton 3a59333bac Merge pull request #160 from kylebshr/master
Simple update to examples for Swift 2 (println() to print())
2016-01-22 13:19:41 -08:00
Kyle Bashour 1951d74516 Simple update to examples for Swift 2 (println() to print()) 2016-01-22 13:00:04 -05:00
daltoniam 6c34076224 another possible fix for #158 2016-01-21 15:44:51 -08:00
daltoniam f189e7c51f possible fix for #158 2016-01-21 13:46:52 -08:00
daltoniam 95c91f9dbf changelog update 2016-01-18 12:34:43 -08:00
daltoniam 398d9c15bf bumped spec 2016-01-18 12:26:32 -08:00
Dalton 5a85e4e524 Merge pull request #157 from dsato80/fragBuffer-fix
set fragBuffer data if processHTTP returns -1
2016-01-18 12:15:57 -08:00
Daisuke Sato d6f2c2c409 set fragBuffer data if processHTTP returns -1 2016-01-18 18:10:30 +09:00
daltoniam ad91b8f1f3 shared queue and bug fixes 2016-01-17 22:39:41 -08:00
daltoniam c59125f34a fixes #139 2016-01-13 18:20:41 -08:00
daltoniam ce9062ab81 fixes #149 2016-01-13 18:16:37 -08:00
Dalton ff64f0b349 Merge pull request #152 from steven851007/master
Fix #151
2016-01-11 15:27:09 -08:00
Istvan Balogh 65dbee5c94 Add default value to origin to keep backward compatibility 2016-01-09 10:53:14 +01:00
Istvan Balogh 7927195b05 Fix #151 2015-12-25 11:19:09 +01:00
Dalton d32dcb2aaa Merge pull request #144 from JamesPrudente/master
call websocketDidConnect delegate after connected is set to prevent race condition
2015-12-23 15:03:49 -08:00
Dalton aeae316209 Merge pull request #146 from mstorsjo/avoid-unaligned
Avoid doing unaligned reads/writes via UnsafePointer
2015-12-12 20:22:57 +02:00
Martin Storsjö 4f2201d6b7 Avoid doing unaligned reads/writes via UnsafePointer
Instead read/write individual bytes via UnsafePointer<UInt8>.

This fixes crashes that only happen when optimization is turned on,
on 32 bit arm builds.

Not all processors support unaligned reads/writes of 64 bit values.
Without optimizations, the reads/writes probably end up handling one
byte at a time (like this commit makes it do), while higher
optimization levels convert it to single reads/writes of the full
size, which may require that the pointer is properly aligned.
2015-12-11 20:39:03 +02:00
James Prudente ec313a376e call websocketDidConnect delegate after connected is set to prevent race condition 2015-12-10 16:05:07 -08:00
Dalton d5f690123f Merge pull request #141 from delba/syntax
Syntax
2015-12-07 11:37:30 -08:00
delba b00a84716c Use implicit casting 2015-12-07 18:41:19 +01:00
delba aa11fd3bbe Use guard 2015-12-07 18:39:58 +01:00
delba b6dddff56c Use if-let optional unwrapping 2015-12-07 18:29:22 +01:00
delba ac4f5ced1e Use contains 2015-12-07 18:24:32 +01:00
delba 947601b673 Initialize OpCode from rawValue 2015-12-07 18:15:11 +01:00
delba cea6ce13c8 Remove unneccessary parentheses around conditions 2015-12-07 18:15:11 +01:00
delba 09c032a138 Use reduce 2015-12-07 18:15:11 +01:00
delba 3fe7363ee9 Use an optional parameter 2015-12-07 18:15:11 +01:00
delba 32925e3847 Use the optional method call syntax 2015-12-07 18:15:11 +01:00
delba 6ad98fb458 Use the for-i-in-range syntax 2015-12-07 18:15:11 +01:00
delba f02840355d Use the trailing closure syntax 2015-12-07 18:15:11 +01:00
delba 4bece17d89 Use the shorthand notation for Array and Dictionary 2015-12-07 18:15:11 +01:00
Dalton 3582bab0b8 Merge pull request #140 from markus-k/master
Unwrap header safely when validating response.
2015-11-24 09:58:22 -08:00
Dalton 737fca6e73 Merge pull request #138 from Abizern/error-codes
Make CloseCode enum public
2015-11-24 09:52:38 -08:00
Markus Kasten e9446a57cd Unwrap header safely when validating response.
App will crash otherwise, when the header is missing.
2015-11-24 11:53:02 +01:00
Abizer Nasir b6054567ee Create a WebSocket error domain
Saves using strings, and also the domain of the error can be switched against.
2015-11-22 00:14:52 +00:00
Abizer Nasir 2b8d6214e2 Make CloseCode enum public
Since they get passed to the websocketDidDisconnect delegate method,
making them public means that the codes can be switched against without
needing magic numbers.
2015-11-21 23:59:45 +00:00
Dalton c56e0104c3 Merge pull request #135 from simonbs/master
Sets UIRequiredDeviceCapabilities in tvOS target
2015-11-16 11:10:31 -08:00
Dalton 2bbc0895d6 Merge pull request #133 from mayoff/maintenance-1.0.2
clean up WebSocket.disconnect parameter
2015-11-16 11:10:05 -08:00
Simon Støvring f1acef9a5f Sets UIRequiredDeviceCapabilities in tvOS target 2015-11-16 18:51:41 +01:00
Rob Mayoff b29059a937 clean up WebSocket.disconnect parameter
Now the parameter is properly an Optional<NSTimeInterval>, nil means no timeout, and zero means close immediately and forcibly.
2015-11-12 21:02:02 -06:00
Dalton e1bbc7612e added license to source files 2015-11-12 11:40:48 -08:00
18 changed files with 613 additions and 437 deletions
+25
View File
@@ -2,6 +2,31 @@
All notable changes to this project will be documented in this file.
`Starscream` adheres to [Semantic Versioning](http://semver.org/).
#### [1.1.2](https://github.com/daltoniam/Starscream/tree/1.1.2)
Fixed:
[#158](https://github.com/daltoniam/Starscream/issues/158)
[#161](https://github.com/daltoniam/Starscream/issues/161)
[#164](https://github.com/daltoniam/Starscream/issues/164)
#### [1.1.1](https://github.com/daltoniam/Starscream/tree/1.1.1)
Fixed:
[#157](https://github.com/daltoniam/Starscream/issues/157)
#### [1.1.0](https://github.com/daltoniam/Starscream/tree/1.1.0)
Changed:
Moved over to Runloop/default GCD queues to shared queue.
Fixed:
[#153](https://github.com/daltoniam/Starscream/issues/153)
[#151](https://github.com/daltoniam/Starscream/issues/151)
[#150](https://github.com/daltoniam/Starscream/issues/150)
[#149](https://github.com/daltoniam/Starscream/issues/149)
[#147](https://github.com/daltoniam/Starscream/issues/147)
[#139](https://github.com/daltoniam/Starscream/issues/139)
[#77](https://github.com/daltoniam/Starscream/issues/77)
#### [1.0.2](https://github.com/daltoniam/Starscream/tree/1.0.2)
+4 -29
View File
@@ -1,7 +1,9 @@
Apache License
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
Copyright (c) 2014-2015 Dalton Cherry.
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
@@ -171,31 +173,4 @@ Apache License
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
of your accepting any such warranty or additional liability.
+25
View File
@@ -0,0 +1,25 @@
//
// Package.Swift
// Starscream
//
// Created by Dalton Cherry on 5/16/15.
// Copyright (c) 2014-2015 Dalton Cherry.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import PackageDescription
let package = Package(
name: "Starscream"
)
+27 -29
View File
@@ -4,13 +4,10 @@ Starscream is a conforming WebSocket ([RFC 6455](http://tools.ietf.org/html/rfc6
It's Objective-C counter part can be found here: [Jetfire](https://github.com/acmacalister/jetfire)
This is written Swift 2. (the latest). If you need older legecy support checkout the Swift-1.2 branch [here](https://github.com/daltoniam/Starscream/tree/swift-1.2).
## Features
- Conforms to all of the base [Autobahn test suite](http://autobahn.ws/testsuite/).
- Nonblocking. Everything happens in the background, thanks to GCD.
- Simple delegate pattern design.
- TLS/WSS support.
- Simple concise codebase at just a few hundred LOC.
@@ -22,10 +19,10 @@ First thing is to import the framework. See the Installation instructions on how
import Starscream
```
Once imported, you can open a connection to your WebSocket server. Note that `socket` is probably best as a property, so your delegate can stick around.
Once imported, you can open a connection to your WebSocket server. Note that `socket` is probably best as a property, so it doesn't get deallocated right after being setup.
```swift
var socket = WebSocket(url: NSURL(string: "ws://localhost:8080/")!)
socket = WebSocket(url: NSURL(string: "ws://localhost:8080/")!)
socket.delegate = self
socket.connect()
```
@@ -38,7 +35,7 @@ websocketDidConnect is called as soon as the client connects to the server.
```swift
func websocketDidConnect(socket: WebSocket) {
println("websocket is connected")
print("websocket is connected")
}
```
@@ -48,7 +45,7 @@ websocketDidDisconnect is called as soon as the client is disconnected from the
```swift
func websocketDidDisconnect(socket: WebSocket, error: NSError?) {
println("websocket is disconnected: \(error?.localizedDescription)")
print("websocket is disconnected: \(error?.localizedDescription)")
}
```
@@ -58,7 +55,7 @@ websocketDidReceiveMessage is called when the client gets a text frame from the
```swift
func websocketDidReceiveMessage(socket: WebSocket, text: String) {
println("got some text: \(text)")
print("got some text: \(text)")
}
```
@@ -68,7 +65,7 @@ websocketDidReceiveData is called when the client gets a binary frame from the c
```swift
func websocketDidReceiveData(socket: WebSocket, data: NSData) {
println("got some data: \(data.length)")
print("got some data: \(data.length)")
}
```
@@ -78,29 +75,29 @@ websocketDidReceivePong is called when the client gets a pong response from the
```swift
func websocketDidReceivePong(socket: WebSocket) {
println("Got pong!")
print("Got pong!")
}
```
Or you can use closures.
```swift
var socket = WebSocket(url: NSURL(string: "ws://localhost:8080/")!)
socket = WebSocket(url: NSURL(string: "ws://localhost:8080/")!)
//websocketDidConnect
socket.onConnect = {
println("websocket is connected")
print("websocket is connected")
}
//websocketDidDisconnect
socket.onDisconnect = { (error: NSError?) in
println("websocket is disconnected: \(error?.localizedDescription)")
print("websocket is disconnected: \(error?.localizedDescription)")
}
//websocketDidReceiveMessage
socket.onText = { (text: String) in
println("got some text: \(text)")
print("got some text: \(text)")
}
//websocketDidReceiveData
socket.onData = { (data: NSData) in
println("got some data: \(data.length)")
print("got some data: \(data.length)")
}
//you could do onPong as well.
socket.connect()
@@ -114,7 +111,7 @@ socket.connect()
The writeData method gives you a simple way to send `NSData` (binary) data to the server.
```swift
self.socket.writeData(data) //write some NSData over the socket!
socket.writeData(data) //write some NSData over the socket!
```
### writeString
@@ -122,7 +119,7 @@ self.socket.writeData(data) //write some NSData over the socket!
The writeString method is the same as writeData, but sends text/string.
```swift
self.socket.writeString("Hi Server!") //example on how to write text over the socket!
socket.writeString("Hi Server!") //example on how to write text over the socket!
```
### writePing
@@ -130,7 +127,7 @@ self.socket.writeString("Hi Server!") //example on how to write text over the so
The writePing method is the same as writeData, but sends a ping control frame.
```swift
self.socket.writePing(NSData()) //example on how to write a ping control frame over the socket!
socket.writePing(NSData()) //example on how to write a ping control frame over the socket!
```
### disconnect
@@ -138,7 +135,7 @@ self.socket.writePing(NSData()) //example on how to write a ping control frame o
The disconnect method does what you would expect and closes the socket.
```swift
self.socket.disconnect()
socket.disconnect()
```
### isConnected
@@ -146,7 +143,7 @@ self.socket.disconnect()
Returns if the socket is connected or not.
```swift
if self.socket.isConnected {
if socket.isConnected {
// do cool stuff.
}
```
@@ -167,7 +164,7 @@ If you need to specify a protocol, simple add it to the init:
```swift
//chat and superchat are the example protocols here
var socket = WebSocket(url: NSURL(string: "ws://localhost:8080/")!, protocols: ["chat","superchat"])
socket = WebSocket(url: NSURL(string: "ws://localhost:8080/")!, protocols: ["chat","superchat"])
socket.delegate = self
socket.connect()
```
@@ -177,7 +174,7 @@ socket.connect()
There are a couple of other properties that modify the stream:
```swift
var socket = WebSocket(url: NSURL(string: "ws://localhost:8080/")!, protocols: ["chat","superchat"])
socket = WebSocket(url: NSURL(string: "ws://localhost:8080/")!, protocols: ["chat","superchat"])
//set this if you are planning on using the socket in a VOIP background setting (using the background VOIP service).
socket.voipEnabled = true
@@ -191,7 +188,7 @@ socket.selfSignedSSL = true
SSL Pinning is also supported in Starscream.
```swift
var socket = WebSocket(url: NSURL(string: "ws://localhost:8080/")!, protocols: ["chat","superchat"])
socket = WebSocket(url: NSURL(string: "ws://localhost:8080/")!, protocols: ["chat","superchat"])
let data = ... //load your certificate from disk
socket.security = SSLSecurity(certs: [SSLCert(data: data)], usePublicKeys: true)
//socket.security = SSLSecurity() //uses the .cer files in your app's bundle
@@ -203,7 +200,7 @@ You load either a `NSData` blob of your certificate or you can use a `SecKeyRef`
A custom queue can be specified when delegate methods are called. By default `dispatch_get_main_queue` is used, thus making all delegate methods calls run on the main thread. It is important to note that all WebSocket processing is done on a background thread, only the delegate method calls are changed when modifying the queue. The actual processing is always on a background thread and will not pause your app.
```swift
var socket = WebSocket(url: NSURL(string: "ws://localhost:8080/")!, protocols: ["chat","superchat"])
socket = WebSocket(url: NSURL(string: "ws://localhost:8080/")!, protocols: ["chat","superchat"])
//create a custom queue
socket.queue = dispatch_queue_create("com.vluxe.starscream.myapp", nil)
```
@@ -225,10 +222,10 @@ Check out [Get Started](http://cocoapods.org/) tab on [cocoapods.org](http://coc
To use Starscream in your project add the following 'Podfile' to your project
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
platform :ios, '9.0'
use_frameworks!
pod 'Starscream', '~> 1.0.0'
pod 'Starscream', '~> 1.1.1'
Then run:
@@ -250,7 +247,7 @@ $ brew install carthage
To integrate Starscream into your Xcode project using Carthage, specify it in your `Cartfile`:
```
github "daltoniam/Starscream" >= 1.0.0
github "daltoniam/Starscream" >= 1.1.1
```
### Rogue
@@ -277,8 +274,9 @@ If you are running this in an OSX app or on a physical iOS device you will need
## TODOs
- [ ] WatchOS
- [ ] Add Unit Tests
- [ ] WatchOS?
- [ ] Linux Support?
- [ ] Add Unit Tests - Local Swift websocket server
## License
+30
View File
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.1.2</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
</array>
</dict>
</plist>
+1 -1
View File
@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<string>1.1.2</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
+61 -45
View File
@@ -4,7 +4,19 @@
// Starscream
//
// Created by Dalton Cherry on 5/16/15.
// Copyright (c) 2015 Vluxe. All rights reserved.
// Copyright (c) 2014-2015 Dalton Cherry.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//////////////////////////////////////////////////////////////////////////////////////////////////
@@ -55,13 +67,15 @@ public class SSLSecurity {
*/
public 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) {
collect.append(SSLCert(data: d))
let certs = paths.reduce([SSLCert]()) { (var certs: [SSLCert], path: String) -> [SSLCert] in
if let data = NSData(contentsOfFile: path) {
certs.append(SSLCert(data: data))
}
return certs
}
self.init(certs:collect, usePublicKeys: usePublicKeys)
self.init(certs: certs, usePublicKeys: usePublicKeys)
}
/**
@@ -76,27 +90,28 @@ public class SSLSecurity {
self.usePublicKeys = usePublicKeys
if self.usePublicKeys {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), {
var collect = Array<SecKeyRef>()
for cert in certs {
if let data = cert.certData where cert.key == nil {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)) {
let pubKeys = certs.reduce([SecKeyRef]()) { (var pubKeys: [SecKeyRef], cert: SSLCert) -> [SecKeyRef] in
if let data = cert.certData where cert.key == nil {
cert.key = self.extractPublicKey(data)
}
if let k = cert.key {
collect.append(k)
if let key = cert.key {
pubKeys.append(key)
}
return pubKeys
}
self.pubKeys = collect
self.pubKeys = pubKeys
self.isReady = true
})
} else {
var collect = Array<NSData>()
for cert in certs {
if let d = cert.certData {
collect.append(d)
}
}
self.certificates = collect
} else {
let certificates = certs.reduce([NSData]()) { (var certificates: [NSData], cert: SSLCert) -> [NSData] in
if let data = cert.certData {
certificates.append(data)
}
return certificates
}
self.certificates = certificates
self.isReady = true
}
}
@@ -139,7 +154,7 @@ public class SSLSecurity {
}
} else if let certs = self.certificates {
let serverCerts = certificateChainForTrust(trust)
var collect = Array<SecCertificate>()
var collect = [SecCertificate]()
for cert in certs {
collect.append(SecCertificateCreateWithData(nil,cert)!)
}
@@ -173,11 +188,9 @@ public class SSLSecurity {
- returns: a public key
*/
func extractPublicKey(data: NSData) -> SecKeyRef? {
let possibleCert = SecCertificateCreateWithData(nil,data)
if let cert = possibleCert {
return extractPublicKeyFromCert(cert, policy: SecPolicyCreateBasicX509())
}
return nil
guard let cert = SecCertificateCreateWithData(nil, data) else { return nil }
return extractPublicKeyFromCert(cert, policy: SecPolicyCreateBasicX509())
}
/**
@@ -190,12 +203,12 @@ public class SSLSecurity {
func extractPublicKeyFromCert(cert: SecCertificate, policy: SecPolicy) -> SecKeyRef? {
var possibleTrust: SecTrust?
SecTrustCreateWithCertificates(cert, policy, &possibleTrust)
if let trust = possibleTrust {
var result: SecTrustResultType = 0
SecTrustEvaluate(trust, &result)
return SecTrustCopyPublicKey(trust)
}
return nil
guard let trust = possibleTrust else { return nil }
var result: SecTrustResultType = 0
SecTrustEvaluate(trust, &result)
return SecTrustCopyPublicKey(trust)
}
/**
@@ -205,13 +218,14 @@ public class SSLSecurity {
- returns: the certificate chain for the trust
*/
func certificateChainForTrust(trust: SecTrustRef) -> Array<NSData> {
var collect = Array<NSData>()
for var i = 0; i < SecTrustGetCertificateCount(trust); i++ {
let cert = SecTrustGetCertificateAtIndex(trust,i)
collect.append(SecCertificateCopyData(cert!))
func certificateChainForTrust(trust: SecTrustRef) -> [NSData] {
let certificates = (0..<SecTrustGetCertificateCount(trust)).reduce([NSData]()) { (var certificates: [NSData], index: Int) -> [NSData] in
let cert = SecTrustGetCertificateAtIndex(trust, index)
certificates.append(SecCertificateCopyData(cert!))
return certificates
}
return collect
return certificates
}
/**
@@ -221,16 +235,18 @@ public class SSLSecurity {
- returns: the public keys from the certifcate chain for the trust
*/
func publicKeyChainForTrust(trust: SecTrustRef) -> Array<SecKeyRef> {
var collect = Array<SecKeyRef>()
func publicKeyChainForTrust(trust: SecTrustRef) -> [SecKeyRef] {
let policy = SecPolicyCreateBasicX509()
for var i = 0; i < SecTrustGetCertificateCount(trust); i++ {
let cert = SecTrustGetCertificateAtIndex(trust,i)
let keys = (0..<SecTrustGetCertificateCount(trust)).reduce([SecKeyRef]()) { (var keys: [SecKeyRef], index: Int) -> [SecKeyRef] in
let cert = SecTrustGetCertificateAtIndex(trust, index)
if let key = extractPublicKeyFromCert(cert!, policy: policy) {
collect.append(key)
keys.append(key)
}
return keys
}
return collect
return keys
}
+285 -196
View File
@@ -3,6 +3,19 @@
// Websocket.swift
//
// Created by Dalton Cherry on 7/16/14.
// Copyright (c) 2014-2015 Dalton Cherry.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//////////////////////////////////////////////////////////////////////////////////////////////////
@@ -34,7 +47,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
//B-F reserved.
}
enum CloseCode : UInt16 {
public enum CloseCode : UInt16 {
case Normal = 1000
case GoingAway = 1001
case ProtocolError = 1002
@@ -47,6 +60,8 @@ public class WebSocket : NSObject, NSStreamDelegate {
case MessageTooBig = 1009
}
public static let ErrorDomain = "WebSocket"
enum InternalErrorCode : UInt16 {
// 0-999 WebSocket status codes not used
case OutputStreamWriteError = 1
@@ -55,7 +70,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
//Where the callback is executed. It defaults to the main UI thread queue.
public var queue = dispatch_get_main_queue()
var optionalProtocols : Array<String>?
var optionalProtocols : [String]?
//Constant Values.
let headerWSUpgradeName = "Upgrade"
let headerWSUpgradeValue = "websocket"
@@ -91,80 +106,99 @@ public class WebSocket : NSObject, NSStreamDelegate {
public var onText: ((String) -> Void)?
public var onData: ((NSData) -> Void)?
public var onPong: ((Void) -> Void)?
public var headers = Dictionary<String,String>()
public var headers = [String: String]()
public var voipEnabled = false
public var selfSignedSSL = false
public var security: SSLSecurity?
public var enabledSSLCipherSuites: [SSLCipherSuite]?
public var origin: String?
public var isConnected :Bool {
return connected
}
public var currentURL: NSURL {return url}
private var url: NSURL
private var inputStream: NSInputStream?
private var outputStream: NSOutputStream?
private var isRunLoop = false
private var connected = false
private var isCreated = false
private var writeQueue = NSOperationQueue()
private var readStack = Array<WSResponse>()
private var inputQueue = Array<NSData>()
private var readStack = [WSResponse]()
private var inputQueue = [NSData]()
private var fragBuffer: NSData?
private var certValidated = false
private var didDisconnect = false
//init the websocket with a url
public init(url: NSURL) {
self.url = url
writeQueue.maxConcurrentOperationCount = 1
private var readyToWrite = false
private let mutex = NSLock()
private var canDispatch: Bool {
mutex.lock()
let canWork = readyToWrite
mutex.unlock()
return canWork
}
//the shared processing queue used for all websocket
private static let sharedWorkQueue = dispatch_queue_create("com.vluxe.starscream.websocket", DISPATCH_QUEUE_SERIAL)
//used for setting protocols.
public convenience init(url: NSURL, protocols: Array<String>) {
self.init(url: url)
public init(url: NSURL, protocols: [String]? = nil) {
self.url = url
self.origin = url.absoluteString
writeQueue.maxConcurrentOperationCount = 1
optionalProtocols = protocols
}
///Connect to the websocket server on a background thread
public func connect() {
if isCreated {
return
}
dispatch_async(queue,{ [weak self] in
self?.didDisconnect = false
})
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), { [weak self] in
self?.isCreated = true
self?.createHTTPRequest()
self?.isCreated = false
})
guard !isCreated else { return }
didDisconnect = false
isCreated = true
createHTTPRequest()
isCreated = false
}
///disconnect from the websocket server
public func disconnect(forceTimeout: Int = 0) {
writeError(CloseCode.Normal.rawValue)
if forceTimeout > 0 { //not needed most of the time, for an edge case
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(forceTimeout) * Int64(NSEC_PER_SEC)), queue, { [unowned self] in
/**
Disconnect from the server. I send a Close control frame to the server, then expect the server to respond with a Close control frame and close the socket from its end. I notify my delegate once the socket has been closed.
If you supply a non-nil `forceTimeout`, I wait at most that long (in seconds) for the server to close the socket. After the timeout expires, I close the socket and notify my delegate.
If you supply a zero (or negative) `forceTimeout`, I immediately close the socket (without sending a Close control frame) and notify my delegate.
- Parameter forceTimeout: Maximum time to wait for the server to close the socket.
*/
public func disconnect(forceTimeout forceTimeout: NSTimeInterval? = nil) {
switch forceTimeout {
case .Some(let seconds) where seconds > 0:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(seconds * Double(NSEC_PER_SEC))), queue) { [weak self] in
self?.disconnectStream(nil)
}
fallthrough
case .None:
writeError(CloseCode.Normal.rawValue)
default:
self.disconnectStream(nil)
})
break
}
}
///write a string to the websocket. This sends it as a text frame.
public func writeString(str: String) {
guard isConnected else { return }
dequeueWrite(str.dataUsingEncoding(NSUTF8StringEncoding)!, code: .TextFrame)
}
///write binary data to the websocket. This sends it as a binary frame.
public func writeData(data: NSData) {
guard isConnected else { return }
dequeueWrite(data, code: .BinaryFrame)
}
//write a ping to the websocket. This sends it as a control frame.
//yodel a sound to the planet. This sends it as an astroid. http://youtu.be/Eu5ZJELRiJ8?t=42s
public func writePing(data: NSData) {
guard isConnected else { return }
dequeueWrite(data, code: .Ping)
}
//private methods below!
//private method that starts the connection
private func createHTTPRequest() {
@@ -173,7 +207,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
var port = url.port
if port == nil {
if url.scheme == "wss" || url.scheme == "https" {
if ["wss", "https"].contains(url.scheme) {
port = 443
} else {
port = 80
@@ -186,7 +220,9 @@ public class WebSocket : NSObject, NSStreamDelegate {
}
addHeader(urlRequest, key: headerWSVersionName, val: headerWSVersionValue)
addHeader(urlRequest, key: headerWSKeyName, val: generateWebSocketKey())
addHeader(urlRequest, key: headerOriginName, val: url.absoluteString)
if let origin = origin {
addHeader(urlRequest, key: headerOriginName, val: origin)
}
addHeader(urlRequest, key: headerWSHostName, val: "\(url.host!):\(port!)")
for (key,value) in headers {
addHeader(urlRequest, key: key, val: value)
@@ -196,19 +232,17 @@ public class WebSocket : NSObject, NSStreamDelegate {
initStreamsWithData(serializedRequest, Int(port!))
}
}
//Add a header to the CFHTTPMessage by using the NSString bridges to CFString
private func addHeader(urlRequest: CFHTTPMessage,key: String, val: String) {
let nsKey: NSString = key
let nsVal: NSString = val
CFHTTPMessageSetHeaderFieldValue(urlRequest,
nsKey,
nsVal)
private func addHeader(urlRequest: CFHTTPMessage, key: NSString, val: NSString) {
CFHTTPMessageSetHeaderFieldValue(urlRequest, key, val)
}
//generate a websocket key as needed in rfc
private func generateWebSocketKey() -> String {
var key = ""
let seed = 16
for (var i = 0; i < seed; i++) {
for _ in 0..<seed {
let uni = UnicodeScalar(UInt32(97 + arc4random_uniform(25)))
key += "\(Character(uni))"
}
@@ -216,6 +250,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
let baseKey = data?.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
return baseKey!
}
//Start the stream connection and write the data to the output stream
private func initStreamsWithData(data: NSData, _ port: Int) {
//higher level API we will cut over to at some point
@@ -230,7 +265,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
guard let inStream = inputStream, let outStream = outputStream else { return }
inStream.delegate = self
outStream.delegate = self
if url.scheme == "wss" || url.scheme == "https" {
if ["wss", "https"].contains(url.scheme) {
inStream.setProperty(NSStreamSocketSecurityLevelNegotiatedSSL, forKey: NSStreamSocketSecurityLevelKey)
outStream.setProperty(NSStreamSocketSecurityLevelNegotiatedSSL, forKey: NSStreamSocketSecurityLevelKey)
} else {
@@ -241,7 +276,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
outStream.setProperty(NSStreamNetworkServiceTypeVoIP, forKey: NSStreamNetworkServiceType)
}
if selfSignedSSL {
let settings: Dictionary<NSObject, NSObject> = [kCFStreamSSLValidatesCertificateChain: NSNumber(bool:false), kCFStreamSSLPeerName: kCFNull]
let settings: [NSObject: NSObject] = [kCFStreamSSLValidatesCertificateChain: NSNumber(bool:false), kCFStreamSSLPeerName: kCFNull]
inStream.setProperty(settings, forKey: kCFStreamPropertySSLSettings as String)
outStream.setProperty(settings, forKey: kCFStreamPropertySSLSettings as String)
}
@@ -250,33 +285,48 @@ public class WebSocket : NSObject, NSStreamDelegate {
sslContextOut = CFWriteStreamCopyProperty(outputStream, kCFStreamPropertySSLContext) as! SSLContextRef? {
let resIn = SSLSetEnabledCiphers(sslContextIn, cipherSuites, cipherSuites.count)
let resOut = SSLSetEnabledCiphers(sslContextOut, cipherSuites, cipherSuites.count)
if (resIn != errSecSuccess) {
if resIn != errSecSuccess {
let error = self.errorWithDetail("Error setting ingoing cypher suites", code: UInt16(resIn))
disconnectStream(error)
return
}
if (resOut != errSecSuccess) {
if resOut != errSecSuccess {
let error = self.errorWithDetail("Error setting outgoing cypher suites", code: UInt16(resOut))
disconnectStream(error)
return
}
}
}
isRunLoop = true
inStream.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
outStream.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
CFReadStreamSetDispatchQueue(inStream, WebSocket.sharedWorkQueue)
CFWriteStreamSetDispatchQueue(outStream, WebSocket.sharedWorkQueue)
inStream.open()
outStream.open()
self.mutex.lock()
self.readyToWrite = true
self.mutex.unlock()
let bytes = UnsafePointer<UInt8>(data.bytes)
outStream.write(bytes, maxLength: data.length)
while(isRunLoop) {
NSRunLoop.currentRunLoop().runMode(NSDefaultRunLoopMode, beforeDate: NSDate.distantFuture() as NSDate)
var timeout = 5000000 //wait 5 seconds before giving up
writeQueue.addOperationWithBlock { [weak self] in
while !outStream.hasSpaceAvailable {
usleep(100) //wait until the socket is ready
timeout -= 100
if timeout < 0 {
self?.cleanupStream()
self?.doDisconnect(self?.errorWithDetail("write wait timed out", code: 2))
return
} else if outStream.streamError != nil {
return //disconnectStream will be called.
}
}
outStream.write(bytes, maxLength: data.length)
}
}
//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) {
if let sec = security where !certValidated && [.HasBytesAvailable, .HasSpaceAvailable].contains(eventCode) {
let possibleTrust: AnyObject? = aStream.propertyForKey(kCFStreamPropertySSLPeerTrust as String)
if let trust: AnyObject = possibleTrust {
let domain: AnyObject? = aStream.propertyForKey(kCFStreamSSLPeerName as String)
@@ -290,7 +340,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
}
}
if eventCode == .HasBytesAvailable {
if(aStream == inputStream) {
if aStream == inputStream {
processInputStream()
}
} else if eventCode == .ErrorOccurred {
@@ -301,20 +351,28 @@ public class WebSocket : NSObject, NSStreamDelegate {
}
//disconnect the stream object
private func disconnectStream(error: NSError?) {
writeQueue.waitUntilAllOperationsAreFinished()
if error == nil {
writeQueue.waitUntilAllOperationsAreFinished()
} else {
writeQueue.cancelAllOperations()
}
cleanupStream()
doDisconnect(error)
}
private func cleanupStream() {
outputStream?.delegate = nil
inputStream?.delegate = nil
if let stream = inputStream {
stream.removeFromRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
CFReadStreamSetDispatchQueue(stream, nil)
stream.close()
}
if let stream = outputStream {
stream.removeFromRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
CFWriteStreamSetDispatchQueue(stream, nil)
stream.close()
}
}
outputStream = nil
isRunLoop = false
certValidated = false
doDisconnect(error)
connected = false
inputStream = nil
}
///handles the incoming bytes and sending them to the proper processing method
@@ -322,50 +380,65 @@ public class WebSocket : NSObject, NSStreamDelegate {
let buf = NSMutableData(capacity: BUFFER_MAX)
let buffer = UnsafeMutablePointer<UInt8>(buf!.bytes)
let length = inputStream!.read(buffer, maxLength: BUFFER_MAX)
if length > 0 {
if !connected {
connected = processHTTP(buffer, bufferLen: length)
if !connected {
let response = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, false).takeRetainedValue()
CFHTTPMessageAppendBytes(response, buffer, length)
let code = CFHTTPMessageGetResponseStatusCode(response)
doDisconnect(errorWithDetail("Invalid HTTP upgrade", code: UInt16(code)))
}
} else {
var process = false
if inputQueue.count == 0 {
process = true
}
inputQueue.append(NSData(bytes: buffer, length: length))
if process {
dequeueInput()
}
}
guard length > 0 else { return }
var process = false
if inputQueue.count == 0 {
process = true
}
inputQueue.append(NSData(bytes: buffer, length: length))
if process {
dequeueInput()
}
}
///dequeue the incoming input so it is processed in order
private func dequeueInput() {
if inputQueue.count > 0 {
let data = inputQueue[0]
var work = data
if fragBuffer != nil {
let combine = NSMutableData(data: fragBuffer!)
combine.appendData(data)
work = combine
fragBuffer = nil
guard !inputQueue.isEmpty else { return }
let data = inputQueue[0]
var work = data
if let fragBuffer = fragBuffer {
let combine = NSMutableData(data: fragBuffer)
combine.appendData(data)
work = combine
self.fragBuffer = nil
}
let buffer = UnsafePointer<UInt8>(work.bytes)
let length = work.length
if !connected {
processTCPHandshake(buffer, bufferLen: length)
} else {
processRawMessage(buffer, bufferLen: length)
}
inputQueue = inputQueue.filter{$0 != data}
dequeueInput()
}
//handle checking the inital connection status
private func processTCPHandshake(buffer: UnsafePointer<UInt8>, bufferLen: Int) {
let code = processHTTP(buffer, bufferLen: bufferLen)
switch code {
case 0:
connected = true
guard canDispatch else {return}
dispatch_async(queue) { [weak self] in
guard let s = self else { return }
s.onConnect?()
s.delegate?.websocketDidConnect(s)
}
let buffer = UnsafePointer<UInt8>(work.bytes)
processRawMessage(buffer, bufferLen: work.length)
inputQueue = inputQueue.filter{$0 != data}
dequeueInput()
case -1:
fragBuffer = NSData(bytes: buffer, length: bufferLen)
break //do nothing, we are going to collect more data
default:
doDisconnect(errorWithDetail("Invalid HTTP upgrade", code: UInt16(code)))
}
}
///Finds the HTTP Packet in the TCP stream, by looking for the CRLF.
private func processHTTP(buffer: UnsafePointer<UInt8>, bufferLen: Int) -> Bool {
private func processHTTP(buffer: UnsafePointer<UInt8>, bufferLen: Int) -> Int {
let CRLFBytes = [UInt8(ascii: "\r"), UInt8(ascii: "\n"), UInt8(ascii: "\r"), UInt8(ascii: "\n")]
var k = 0
var totalSize = 0
for var i = 0; i < bufferLen; i++ {
for i in 0..<bufferLen {
if buffer[i] == CRLFBytes[k] {
k++
if k == 3 {
@@ -377,40 +450,64 @@ public class WebSocket : NSObject, NSStreamDelegate {
}
}
if totalSize > 0 {
if validateResponse(buffer, bufferLen: totalSize) {
dispatch_async(queue,{ [weak self] in
guard let s = self else { return }
if let connectBlock = s.onConnect {
connectBlock()
}
s.delegate?.websocketDidConnect(s)
})
totalSize += 1 //skip the last \n
let restSize = bufferLen - totalSize
if restSize > 0 {
processRawMessage((buffer+totalSize),bufferLen: restSize)
}
return true
let code = validateResponse(buffer, bufferLen: totalSize)
if code != 0 {
return code
}
totalSize += 1 //skip the last \n
let restSize = bufferLen - totalSize
if restSize > 0 {
processRawMessage((buffer+totalSize),bufferLen: restSize)
}
return 0 //success
}
return false
return -1 //was unable to find the full TCP header
}
///validates the HTTP is a 101 as per the RFC spec
private func validateResponse(buffer: UnsafePointer<UInt8>, bufferLen: Int) -> Bool {
private func validateResponse(buffer: UnsafePointer<UInt8>, bufferLen: Int) -> Int {
let response = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, false).takeRetainedValue()
CFHTTPMessageAppendBytes(response, buffer, bufferLen)
if CFHTTPMessageGetResponseStatusCode(response) != 101 {
return false
let code = CFHTTPMessageGetResponseStatusCode(response)
if code != 101 {
return code
}
if let cfHeaders = CFHTTPMessageCopyAllHeaderFields(response) {
let headers = cfHeaders.takeRetainedValue() as NSDictionary
let acceptKey = headers[headerWSAcceptName] as! NSString
if acceptKey.length > 0 {
return true
if let acceptKey = headers[headerWSAcceptName] as? NSString {
if acceptKey.length > 0 {
return 0
}
}
}
return false
return -1
}
///read a 16 bit big endian value from a buffer
private static func readUint16(buffer: UnsafePointer<UInt8>, offset: Int) -> UInt16 {
return (UInt16(buffer[offset + 0]) << 8) | UInt16(buffer[offset + 1])
}
///read a 64 bit big endian value from a buffer
private static func readUint64(buffer: UnsafePointer<UInt8>, offset: Int) -> UInt64 {
var value = UInt64(0)
for i in 0...7 {
value = (value << 8) | UInt64(buffer[offset + i])
}
return value
}
///write a 16 bit big endian value to a buffer
private static func writeUint16(buffer: UnsafeMutablePointer<UInt8>, offset: Int, value: UInt16) {
buffer[offset + 0] = UInt8(value >> 8)
buffer[offset + 1] = UInt8(value & 0xff)
}
///write a 64 bit big endian value to a buffer
private static func writeUint64(buffer: UnsafeMutablePointer<UInt8>, offset: Int, value: UInt64) {
for i in 0...7 {
buffer[offset + i] = UInt8((value >> (8*UInt64(7 - i))) & 0xff)
}
}
///process the websocket data
@@ -420,17 +517,16 @@ public class WebSocket : NSObject, NSStreamDelegate {
fragBuffer = NSData(bytes: buffer, length: bufferLen)
return
}
if response != nil && response!.bytesLeft > 0 {
let resp = response!
var len = resp.bytesLeft
var extra = bufferLen - resp.bytesLeft
if resp.bytesLeft > bufferLen {
if let response = response where response.bytesLeft > 0 {
var len = response.bytesLeft
var extra = bufferLen - response.bytesLeft
if response.bytesLeft > bufferLen {
len = bufferLen
extra = 0
}
resp.bytesLeft -= len
resp.buffer?.appendData(NSData(bytes: buffer, length: len))
processResponse(resp)
response.bytesLeft -= len
response.buffer?.appendData(NSData(bytes: buffer, length: len))
processResponse(response)
let offset = bufferLen - extra
if extra > 0 {
processExtra((buffer+offset), bufferLen: extra)
@@ -438,19 +534,19 @@ public class WebSocket : NSObject, NSStreamDelegate {
return
} else {
let isFin = (FinMask & buffer[0])
let receivedOpcode = (OpCodeMask & buffer[0])
let receivedOpcode = OpCode(rawValue: (OpCodeMask & buffer[0]))
let isMasked = (MaskMask & buffer[1])
let payloadLen = (PayloadLenMask & buffer[1])
var offset = 2
if((isMasked > 0 || (RSVMask & buffer[0]) > 0) && receivedOpcode != OpCode.Pong.rawValue) {
if (isMasked > 0 || (RSVMask & buffer[0]) > 0) && receivedOpcode != .Pong {
let errCode = CloseCode.ProtocolError.rawValue
doDisconnect(errorWithDetail("masked and rsv data is not currently supported", code: errCode))
writeError(errCode)
return
}
let isControlFrame = (receivedOpcode == OpCode.ConnectionClose.rawValue || receivedOpcode == OpCode.Ping.rawValue)
if !isControlFrame && (receivedOpcode != OpCode.BinaryFrame.rawValue && receivedOpcode != OpCode.ContinueFrame.rawValue &&
receivedOpcode != OpCode.TextFrame.rawValue && receivedOpcode != OpCode.Pong.rawValue) {
let isControlFrame = (receivedOpcode == .ConnectionClose || receivedOpcode == .Ping)
if !isControlFrame && (receivedOpcode != .BinaryFrame && receivedOpcode != .ContinueFrame &&
receivedOpcode != .TextFrame && receivedOpcode != .Pong) {
let errCode = CloseCode.ProtocolError.rawValue
doDisconnect(errorWithDetail("unknown opcode: \(receivedOpcode)", code: errCode))
writeError(errCode)
@@ -462,13 +558,12 @@ public class WebSocket : NSObject, NSStreamDelegate {
writeError(errCode)
return
}
if receivedOpcode == OpCode.ConnectionClose.rawValue {
if receivedOpcode == .ConnectionClose {
var code = CloseCode.Normal.rawValue
if payloadLen == 1 {
code = CloseCode.ProtocolError.rawValue
} else if payloadLen > 1 {
let codeBuffer = UnsafePointer<UInt16>((buffer+offset))
code = codeBuffer[0].bigEndian
code = WebSocket.readUint16(buffer, offset: offset)
if code < 1000 || (code > 1003 && code < 1007) || (code > 1011 && code < 3000) {
code = CloseCode.ProtocolError.rawValue
}
@@ -494,12 +589,10 @@ public class WebSocket : NSObject, NSStreamDelegate {
}
var dataLength = UInt64(payloadLen)
if dataLength == 127 {
let bytes = UnsafePointer<UInt64>((buffer+offset))
dataLength = bytes[0].bigEndian
dataLength = WebSocket.readUint64(buffer, offset: offset)
offset += sizeof(UInt64)
} else if dataLength == 126 {
let bytes = UnsafePointer<UInt16>((buffer+offset))
dataLength = UInt64(bytes[0].bigEndian)
dataLength = UInt64(WebSocket.readUint16(buffer, offset: offset))
offset += sizeof(UInt16)
}
if bufferLen < offset || UInt64(bufferLen - offset) < dataLength {
@@ -517,15 +610,14 @@ public class WebSocket : NSObject, NSStreamDelegate {
} else {
data = NSData(bytes: UnsafePointer<UInt8>((buffer+offset)), length: Int(len))
}
if receivedOpcode == OpCode.Pong.rawValue {
dispatch_async(queue,{ [weak self] in
guard let s = self else { return }
if let pongBlock = s.onPong {
pongBlock()
if receivedOpcode == .Pong {
if canDispatch {
dispatch_async(queue) { [weak self] in
guard let s = self else { return }
s.onPong?()
s.pongDelegate?.websocketDidReceivePong(s)
}
s.pongDelegate?.websocketDidReceivePong(s)
})
}
let step = Int(offset+numericCast(len))
let extra = bufferLen-step
if extra > 0 {
@@ -537,15 +629,15 @@ public class WebSocket : NSObject, NSStreamDelegate {
if isControlFrame {
response = nil //don't append pings
}
if isFin == 0 && receivedOpcode == OpCode.ContinueFrame.rawValue && response == nil {
if isFin == 0 && receivedOpcode == .ContinueFrame && response == nil {
let errCode = CloseCode.ProtocolError.rawValue
doDisconnect(errorWithDetail("continue frame before a binary or text frame", code: errCode))
writeError(errCode)
return
}
var isNew = false
if(response == nil) {
if receivedOpcode == OpCode.ContinueFrame.rawValue {
if response == nil {
if receivedOpcode == .ContinueFrame {
let errCode = CloseCode.ProtocolError.rawValue
doDisconnect(errorWithDetail("first frame can't be a continue frame",
code: errCode))
@@ -554,11 +646,11 @@ public class WebSocket : NSObject, NSStreamDelegate {
}
isNew = true
response = WSResponse()
response!.code = OpCode(rawValue: receivedOpcode)!
response!.code = receivedOpcode!
response!.bytesLeft = Int(dataLength)
response!.buffer = NSMutableData(data: data)
} else {
if receivedOpcode == OpCode.ContinueFrame.rawValue {
if receivedOpcode == .ContinueFrame {
response!.bytesLeft = Int(dataLength)
} else {
let errCode = CloseCode.ProtocolError.rawValue
@@ -569,19 +661,19 @@ public class WebSocket : NSObject, NSStreamDelegate {
}
response!.buffer!.appendData(data)
}
if response != nil {
response!.bytesLeft -= Int(len)
response!.frameCount++
response!.isFin = isFin > 0 ? true : false
if(isNew) {
readStack.append(response!)
if let response = response {
response.bytesLeft -= Int(len)
response.frameCount++
response.isFin = isFin > 0 ? true : false
if isNew {
readStack.append(response)
}
processResponse(response!)
processResponse(response)
}
let step = Int(offset+numericCast(len))
let extra = bufferLen-step
if(extra > 0) {
if extra > 0 {
processExtra((buffer+step), bufferLen: extra)
}
}
@@ -609,23 +701,22 @@ public class WebSocket : NSObject, NSStreamDelegate {
writeError(CloseCode.Encoding.rawValue)
return false
}
dispatch_async(queue,{ [weak self] in
guard let s = self else { return }
if let textBlock = s.onText {
textBlock(str! as String)
if canDispatch {
dispatch_async(queue) { [weak self] in
guard let s = self else { return }
s.onText?(str! as String)
s.delegate?.websocketDidReceiveMessage(s, text: str! as String)
}
s.delegate?.websocketDidReceiveMessage(s, text: str! as String)
})
}
} else if response.code == .BinaryFrame {
let data = response.buffer! //local copy so it is perverse for writing
dispatch_async(queue,{ [weak self] in
guard let s = self else { return }
if let dataBlock = s.onData {
dataBlock(data)
if canDispatch {
let data = response.buffer! //local copy so it is perverse for writing
dispatch_async(queue) { [weak self] in
guard let s = self else { return }
s.onData?(data)
s.delegate?.websocketDidReceiveData(s, data: data)
}
s.delegate?.websocketDidReceiveData(s, data: data)
})
}
}
readStack.removeLast()
return true
@@ -635,23 +726,20 @@ public class WebSocket : NSObject, NSStreamDelegate {
///Create an error
private func errorWithDetail(detail: String, code: UInt16) -> NSError {
var details = Dictionary<String,String>()
var details = [String: String]()
details[NSLocalizedDescriptionKey] = detail
return NSError(domain: "Websocket", code: Int(code), userInfo: details)
return NSError(domain: WebSocket.ErrorDomain, code: Int(code), userInfo: details)
}
///write a an error to the socket
private func writeError(code: UInt16) {
let buf = NSMutableData(capacity: sizeof(UInt16))
let buffer = UnsafeMutablePointer<UInt16>(buf!.bytes)
buffer[0] = code.bigEndian
let buffer = UnsafeMutablePointer<UInt8>(buf!.bytes)
WebSocket.writeUint16(buffer, offset: 0, value: code)
dequeueWrite(NSData(bytes: buffer, length: sizeof(UInt16)), code: .ConnectionClose)
}
///used to write things to the stream
private func dequeueWrite(data: NSData, code: OpCode) {
if !isConnected {
return
}
writeQueue.addOperationWithBlock { [weak self] in
//stream isn't ready, let's wait
guard let s = self else { return }
@@ -665,13 +753,11 @@ public class WebSocket : NSObject, NSStreamDelegate {
buffer[1] = CUnsignedChar(dataLength)
} else if dataLength <= Int(UInt16.max) {
buffer[1] = 126
let sizeBuffer = UnsafeMutablePointer<UInt16>((buffer+offset))
sizeBuffer[0] = UInt16(dataLength).bigEndian
WebSocket.writeUint16(buffer, offset: offset, value: UInt16(dataLength))
offset += sizeof(UInt16)
} else {
buffer[1] = 127
let sizeBuffer = UnsafeMutablePointer<UInt64>((buffer+offset))
sizeBuffer[0] = UInt64(dataLength).bigEndian
WebSocket.writeUint64(buffer, offset: offset, value: UInt64(dataLength))
offset += sizeof(UInt64)
}
buffer[1] |= s.MaskMask
@@ -679,15 +765,12 @@ public class WebSocket : NSObject, NSStreamDelegate {
SecRandomCopyBytes(kSecRandomDefault, Int(sizeof(UInt32)), maskKey)
offset += sizeof(UInt32)
for (var i = 0; i < dataLength; i++) {
for i in 0..<dataLength {
buffer[offset] = bytes[i] ^ maskKey[i % sizeof(UInt32)]
offset += 1
}
var total = 0
while true {
if !s.isConnected {
break
}
guard let outStream = s.outputStream else { break }
let writeBuffer = UnsafePointer<UInt8>(frame!.bytes+total)
let len = outStream.write(writeBuffer, maxLength: offset-total)
@@ -714,16 +797,22 @@ public class WebSocket : NSObject, NSStreamDelegate {
///used to preform the disconnect delegate
private func doDisconnect(error: NSError?) {
if !didDisconnect {
dispatch_async(queue,{ [weak self] in
guard let s = self else { return }
s.didDisconnect = true
if let disconnect = s.onDisconnect {
disconnect(error)
}
s.delegate?.websocketDidDisconnect(s, error: error)
})
guard !didDisconnect else { return }
didDisconnect = true
connected = false
guard canDispatch else {return}
dispatch_async(queue) { [weak self] in
guard let s = self else { return }
s.onDisconnect?(error)
s.delegate?.websocketDidDisconnect(s, error: error)
}
}
deinit {
mutex.lock()
readyToWrite = false
mutex.unlock()
cleanupStream()
}
}
+2 -2
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "Starscream"
s.version = "1.0.2"
s.version = "1.1.2"
s.summary = "A conforming WebSocket RFC 6455 client library in Swift for iOS and OSX."
s.homepage = "https://github.com/daltoniam/Starscream"
s.license = 'Apache License, Version 2.0'
@@ -10,6 +10,6 @@ Pod::Spec.new do |s|
s.ios.deployment_target = '8.0'
s.osx.deployment_target = '10.9'
s.tvos.deployment_target = '9.0'
s.source_files = '*.swift'
s.source_files = 'Source/*.swift'
s.requires_arc = 'true'
end
+79 -77
View File
@@ -8,19 +8,19 @@
/* Begin PBXBuildFile section */
091277A11BD673A70003036D /* Starscream.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 091277971BD673A70003036D /* Starscream.framework */; };
5C06AE8F1B08050D00D41060 /* SSLSecurity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C06AE8E1B08050D00D41060 /* SSLSecurity.swift */; };
5C06AE901B08050D00D41060 /* SSLSecurity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C06AE8E1B08050D00D41060 /* SSLSecurity.swift */; };
5CADAB2A1BEAC5CF005DE2F0 /* WebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B3E7A0419D48C41006071F7 /* WebSocket.swift */; };
5CADAB2B1BEAC5CF005DE2F0 /* SSLSecurity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C06AE8E1B08050D00D41060 /* SSLSecurity.swift */; };
5CADAB2C1BEAC5DA005DE2F0 /* Starscream.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B3E7A0619D48C5F006071F7 /* Starscream.h */; settings = {ATTRIBUTES = (Public, ); }; };
5C1360021C473BEF00AA3A01 /* SSLSecurity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C135FFF1C473BEF00AA3A01 /* SSLSecurity.swift */; };
5C1360031C473BEF00AA3A01 /* SSLSecurity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C135FFF1C473BEF00AA3A01 /* SSLSecurity.swift */; };
5C1360041C473BEF00AA3A01 /* SSLSecurity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C135FFF1C473BEF00AA3A01 /* SSLSecurity.swift */; };
5C1360051C473BEF00AA3A01 /* Starscream.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C1360001C473BEF00AA3A01 /* Starscream.h */; settings = {ATTRIBUTES = (Public, ); }; };
5C1360061C473BEF00AA3A01 /* Starscream.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C1360001C473BEF00AA3A01 /* Starscream.h */; settings = {ATTRIBUTES = (Public, ); }; };
5C1360071C473BEF00AA3A01 /* Starscream.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C1360001C473BEF00AA3A01 /* Starscream.h */; settings = {ATTRIBUTES = (Public, ); }; };
5C1360081C473BEF00AA3A01 /* WebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1360011C473BEF00AA3A01 /* WebSocket.swift */; };
5C1360091C473BEF00AA3A01 /* WebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1360011C473BEF00AA3A01 /* WebSocket.swift */; };
5C13600A1C473BEF00AA3A01 /* WebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1360011C473BEF00AA3A01 /* WebSocket.swift */; };
5CADAB511BEBD068005DE2F0 /* StarscreamTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B3E7A0119D48C2F006071F7 /* StarscreamTests.swift */; };
6B3E7A0319D48C2F006071F7 /* StarscreamTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B3E7A0119D48C2F006071F7 /* StarscreamTests.swift */; };
6B3E7A0519D48C41006071F7 /* WebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B3E7A0419D48C41006071F7 /* WebSocket.swift */; };
6B3E7A0719D48C5F006071F7 /* Starscream.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B3E7A0619D48C5F006071F7 /* Starscream.h */; settings = {ATTRIBUTES = (Public, ); }; };
D9C3E36A19E48FF1009FC285 /* Starscream.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9C3E35F19E48FF1009FC285 /* Starscream.framework */; };
D9C3E37819E4903F009FC285 /* StarscreamTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B3E7A0119D48C2F006071F7 /* StarscreamTests.swift */; };
D9C3E37919E49051009FC285 /* Starscream.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B3E7A0619D48C5F006071F7 /* Starscream.h */; settings = {ATTRIBUTES = (Public, ); }; };
D9C3E37A19E49058009FC285 /* WebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B3E7A0419D48C41006071F7 /* WebSocket.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -42,17 +42,18 @@
/* Begin PBXFileReference section */
091277971BD673A70003036D /* Starscream.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Starscream.framework; sourceTree = BUILT_PRODUCTS_DIR; };
091277A01BD673A70003036D /* StarscreamTvTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = StarscreamTvTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
5C06AE8E1B08050D00D41060 /* SSLSecurity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SSLSecurity.swift; sourceTree = SOURCE_ROOT; };
091277A01BD673A70003036D /* Starscream tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Starscream tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
5C135FFF1C473BEF00AA3A01 /* SSLSecurity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SSLSecurity.swift; path = Source/SSLSecurity.swift; sourceTree = SOURCE_ROOT; };
5C1360001C473BEF00AA3A01 /* Starscream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Starscream.h; path = Source/Starscream.h; sourceTree = SOURCE_ROOT; };
5C1360011C473BEF00AA3A01 /* WebSocket.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WebSocket.swift; path = Source/WebSocket.swift; sourceTree = SOURCE_ROOT; };
5C13600B1C473BFE00AA3A01 /* Info-tvOS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "Info-tvOS.plist"; path = "Source/Info-tvOS.plist"; sourceTree = SOURCE_ROOT; };
5C13600C1C473BFE00AA3A01 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Source/Info.plist; sourceTree = SOURCE_ROOT; };
6B3E79E619D48B7F006071F7 /* Starscream.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Starscream.framework; sourceTree = BUILT_PRODUCTS_DIR; };
6B3E79EA19D48B7F006071F7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
6B3E79F119D48B7F006071F7 /* StarscreamTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = StarscreamTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
6B3E79F119D48B7F006071F7 /* Starscream iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Starscream iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
6B3E7A0019D48C2F006071F7 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
6B3E7A0119D48C2F006071F7 /* StarscreamTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StarscreamTests.swift; sourceTree = "<group>"; };
6B3E7A0419D48C41006071F7 /* WebSocket.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebSocket.swift; sourceTree = SOURCE_ROOT; };
6B3E7A0619D48C5F006071F7 /* Starscream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Starscream.h; sourceTree = SOURCE_ROOT; };
D9C3E35F19E48FF1009FC285 /* Starscream.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Starscream.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D9C3E36919E48FF1009FC285 /* StarscreamOSXTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = StarscreamOSXTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
D9C3E36919E48FF1009FC285 /* Starscream OSXTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Starscream OSXTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -116,11 +117,11 @@
isa = PBXGroup;
children = (
6B3E79E619D48B7F006071F7 /* Starscream.framework */,
6B3E79F119D48B7F006071F7 /* StarscreamTests.xctest */,
6B3E79F119D48B7F006071F7 /* Starscream iOSTests.xctest */,
D9C3E35F19E48FF1009FC285 /* Starscream.framework */,
D9C3E36919E48FF1009FC285 /* StarscreamOSXTests.xctest */,
D9C3E36919E48FF1009FC285 /* Starscream OSXTests.xctest */,
091277971BD673A70003036D /* Starscream.framework */,
091277A01BD673A70003036D /* StarscreamTvTests.xctest */,
091277A01BD673A70003036D /* Starscream tvOSTests.xctest */,
);
name = Products;
sourceTree = "<group>";
@@ -128,9 +129,9 @@
6B3E79E819D48B7F006071F7 /* Starscream */ = {
isa = PBXGroup;
children = (
6B3E7A0419D48C41006071F7 /* WebSocket.swift */,
5C06AE8E1B08050D00D41060 /* SSLSecurity.swift */,
6B3E7A0619D48C5F006071F7 /* Starscream.h */,
5C1360001C473BEF00AA3A01 /* Starscream.h */,
5C135FFF1C473BEF00AA3A01 /* SSLSecurity.swift */,
5C1360011C473BEF00AA3A01 /* WebSocket.swift */,
6B3E79E919D48B7F006071F7 /* Supporting Files */,
);
path = Starscream;
@@ -139,7 +140,8 @@
6B3E79E919D48B7F006071F7 /* Supporting Files */ = {
isa = PBXGroup;
children = (
6B3E79EA19D48B7F006071F7 /* Info.plist */,
5C13600B1C473BFE00AA3A01 /* Info-tvOS.plist */,
5C13600C1C473BFE00AA3A01 /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "<group>";
@@ -160,7 +162,7 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
5CADAB2C1BEAC5DA005DE2F0 /* Starscream.h in Headers */,
5C1360071C473BEF00AA3A01 /* Starscream.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -168,7 +170,7 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
6B3E7A0719D48C5F006071F7 /* Starscream.h in Headers */,
5C1360051C473BEF00AA3A01 /* Starscream.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -176,16 +178,16 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
D9C3E37919E49051009FC285 /* Starscream.h in Headers */,
5C1360061C473BEF00AA3A01 /* Starscream.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
091277961BD673A70003036D /* StarscreamTv */ = {
091277961BD673A70003036D /* Starscream tvOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = 091277A81BD673A70003036D /* Build configuration list for PBXNativeTarget "StarscreamTv" */;
buildConfigurationList = 091277A81BD673A70003036D /* Build configuration list for PBXNativeTarget "Starscream tvOS" */;
buildPhases = (
091277921BD673A70003036D /* Sources */,
091277931BD673A70003036D /* Frameworks */,
@@ -196,14 +198,14 @@
);
dependencies = (
);
name = StarscreamTv;
name = "Starscream tvOS";
productName = StarscreamTv;
productReference = 091277971BD673A70003036D /* Starscream.framework */;
productType = "com.apple.product-type.framework";
};
0912779F1BD673A70003036D /* StarscreamTvTests */ = {
0912779F1BD673A70003036D /* Starscream tvOSTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 091277AB1BD673A70003036D /* Build configuration list for PBXNativeTarget "StarscreamTvTests" */;
buildConfigurationList = 091277AB1BD673A70003036D /* Build configuration list for PBXNativeTarget "Starscream tvOSTests" */;
buildPhases = (
0912779C1BD673A70003036D /* Sources */,
0912779D1BD673A70003036D /* Frameworks */,
@@ -214,14 +216,14 @@
dependencies = (
091277A31BD673A70003036D /* PBXTargetDependency */,
);
name = StarscreamTvTests;
name = "Starscream tvOSTests";
productName = StarscreamTvTests;
productReference = 091277A01BD673A70003036D /* StarscreamTvTests.xctest */;
productReference = 091277A01BD673A70003036D /* Starscream tvOSTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
6B3E79E519D48B7F006071F7 /* Starscream */ = {
6B3E79E519D48B7F006071F7 /* Starscream iOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = 6B3E79F919D48B7F006071F7 /* Build configuration list for PBXNativeTarget "Starscream" */;
buildConfigurationList = 6B3E79F919D48B7F006071F7 /* Build configuration list for PBXNativeTarget "Starscream iOS" */;
buildPhases = (
6B3E79E119D48B7F006071F7 /* Sources */,
6B3E79E219D48B7F006071F7 /* Frameworks */,
@@ -232,14 +234,14 @@
);
dependencies = (
);
name = Starscream;
name = "Starscream iOS";
productName = Starscream;
productReference = 6B3E79E619D48B7F006071F7 /* Starscream.framework */;
productType = "com.apple.product-type.framework";
};
6B3E79F019D48B7F006071F7 /* StarscreamTests */ = {
6B3E79F019D48B7F006071F7 /* Starscream iOSTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 6B3E79FC19D48B7F006071F7 /* Build configuration list for PBXNativeTarget "StarscreamTests" */;
buildConfigurationList = 6B3E79FC19D48B7F006071F7 /* Build configuration list for PBXNativeTarget "Starscream iOSTests" */;
buildPhases = (
6B3E79ED19D48B7F006071F7 /* Sources */,
6B3E79EE19D48B7F006071F7 /* Frameworks */,
@@ -249,14 +251,14 @@
);
dependencies = (
);
name = StarscreamTests;
name = "Starscream iOSTests";
productName = StarscreamTests;
productReference = 6B3E79F119D48B7F006071F7 /* StarscreamTests.xctest */;
productReference = 6B3E79F119D48B7F006071F7 /* Starscream iOSTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
D9C3E35E19E48FF1009FC285 /* StarscreamOSX */ = {
D9C3E35E19E48FF1009FC285 /* Starscream OSX */ = {
isa = PBXNativeTarget;
buildConfigurationList = D9C3E37619E48FF1009FC285 /* Build configuration list for PBXNativeTarget "StarscreamOSX" */;
buildConfigurationList = D9C3E37619E48FF1009FC285 /* Build configuration list for PBXNativeTarget "Starscream OSX" */;
buildPhases = (
D9C3E35A19E48FF1009FC285 /* Sources */,
D9C3E35B19E48FF1009FC285 /* Frameworks */,
@@ -267,14 +269,14 @@
);
dependencies = (
);
name = StarscreamOSX;
name = "Starscream OSX";
productName = StarscreamOSX;
productReference = D9C3E35F19E48FF1009FC285 /* Starscream.framework */;
productType = "com.apple.product-type.framework";
};
D9C3E36819E48FF1009FC285 /* StarscreamOSXTests */ = {
D9C3E36819E48FF1009FC285 /* Starscream OSXTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = D9C3E37719E48FF1009FC285 /* Build configuration list for PBXNativeTarget "StarscreamOSXTests" */;
buildConfigurationList = D9C3E37719E48FF1009FC285 /* Build configuration list for PBXNativeTarget "Starscream OSXTests" */;
buildPhases = (
D9C3E36519E48FF1009FC285 /* Sources */,
D9C3E36619E48FF1009FC285 /* Frameworks */,
@@ -285,9 +287,9 @@
dependencies = (
D9C3E36C19E48FF1009FC285 /* PBXTargetDependency */,
);
name = StarscreamOSXTests;
name = "Starscream OSXTests";
productName = StarscreamOSXTests;
productReference = D9C3E36919E48FF1009FC285 /* StarscreamOSXTests.xctest */;
productReference = D9C3E36919E48FF1009FC285 /* Starscream OSXTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
@@ -333,12 +335,12 @@
projectDirPath = "";
projectRoot = "";
targets = (
6B3E79E519D48B7F006071F7 /* Starscream */,
6B3E79F019D48B7F006071F7 /* StarscreamTests */,
D9C3E35E19E48FF1009FC285 /* StarscreamOSX */,
D9C3E36819E48FF1009FC285 /* StarscreamOSXTests */,
091277961BD673A70003036D /* StarscreamTv */,
0912779F1BD673A70003036D /* StarscreamTvTests */,
6B3E79E519D48B7F006071F7 /* Starscream iOS */,
6B3E79F019D48B7F006071F7 /* Starscream iOSTests */,
D9C3E35E19E48FF1009FC285 /* Starscream OSX */,
D9C3E36819E48FF1009FC285 /* Starscream OSXTests */,
091277961BD673A70003036D /* Starscream tvOS */,
0912779F1BD673A70003036D /* Starscream tvOSTests */,
);
};
/* End PBXProject section */
@@ -393,8 +395,8 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
5CADAB2A1BEAC5CF005DE2F0 /* WebSocket.swift in Sources */,
5CADAB2B1BEAC5CF005DE2F0 /* SSLSecurity.swift in Sources */,
5C13600A1C473BEF00AA3A01 /* WebSocket.swift in Sources */,
5C1360041C473BEF00AA3A01 /* SSLSecurity.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -410,8 +412,8 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
6B3E7A0519D48C41006071F7 /* WebSocket.swift in Sources */,
5C06AE8F1B08050D00D41060 /* SSLSecurity.swift in Sources */,
5C1360081C473BEF00AA3A01 /* WebSocket.swift in Sources */,
5C1360021C473BEF00AA3A01 /* SSLSecurity.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -427,8 +429,8 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D9C3E37A19E49058009FC285 /* WebSocket.swift in Sources */,
5C06AE901B08050D00D41060 /* SSLSecurity.swift in Sources */,
5C1360091C473BEF00AA3A01 /* WebSocket.swift in Sources */,
5C1360031C473BEF00AA3A01 /* SSLSecurity.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -445,12 +447,12 @@
/* Begin PBXTargetDependency section */
091277A31BD673A70003036D /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 091277961BD673A70003036D /* StarscreamTv */;
target = 091277961BD673A70003036D /* Starscream tvOS */;
targetProxy = 091277A21BD673A70003036D /* PBXContainerItemProxy */;
};
D9C3E36C19E48FF1009FC285 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = D9C3E35E19E48FF1009FC285 /* StarscreamOSX */;
target = D9C3E35E19E48FF1009FC285 /* Starscream OSX */;
targetProxy = D9C3E36B19E48FF1009FC285 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
@@ -468,7 +470,7 @@
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
GCC_NO_COMMON_BLOCKS = YES;
INFOPLIST_FILE = Info.plist;
INFOPLIST_FILE = "$(SRCROOT)/Source/Info-tvOS.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.vluxe.Starscream;
@@ -493,7 +495,7 @@
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
GCC_NO_COMMON_BLOCKS = YES;
INFOPLIST_FILE = Info.plist;
INFOPLIST_FILE = "$(SRCROOT)/Source/Info-tvOS.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.vluxe.Starscream;
@@ -510,7 +512,7 @@
buildSettings = {
DEBUG_INFORMATION_FORMAT = dwarf;
GCC_NO_COMMON_BLOCKS = YES;
INFOPLIST_FILE = Info.plist;
INFOPLIST_FILE = Tests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.vluxe.StarscreamTvTests;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -525,7 +527,7 @@
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_NO_COMMON_BLOCKS = YES;
INFOPLIST_FILE = Info.plist;
INFOPLIST_FILE = Tests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.vluxe.StarscreamTvTests;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -631,13 +633,13 @@
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = Info.plist;
INFOPLIST_FILE = "$(SRCROOT)/Source/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
OTHER_LDFLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = "com.vluxe.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
PRODUCT_NAME = Starscream;
PROVISIONING_PROFILE = "";
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -655,13 +657,13 @@
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = Info.plist;
INFOPLIST_FILE = "$(SRCROOT)/Source/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
OTHER_LDFLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = "com.vluxe.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
PRODUCT_NAME = Starscream;
PROVISIONING_PROFILE = "";
SKIP_INSTALL = YES;
};
@@ -712,7 +714,7 @@
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = Info.plist;
INFOPLIST_FILE = "$(SRCROOT)/Source/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.10;
@@ -734,7 +736,7 @@
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_VERSION = A;
INFOPLIST_FILE = Info.plist;
INFOPLIST_FILE = "$(SRCROOT)/Source/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.10;
@@ -788,7 +790,7 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
091277A81BD673A70003036D /* Build configuration list for PBXNativeTarget "StarscreamTv" */ = {
091277A81BD673A70003036D /* Build configuration list for PBXNativeTarget "Starscream tvOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
091277A91BD673A70003036D /* Debug */,
@@ -797,7 +799,7 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
091277AB1BD673A70003036D /* Build configuration list for PBXNativeTarget "StarscreamTvTests" */ = {
091277AB1BD673A70003036D /* Build configuration list for PBXNativeTarget "Starscream tvOSTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
091277AC1BD673A70003036D /* Debug */,
@@ -815,7 +817,7 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
6B3E79F919D48B7F006071F7 /* Build configuration list for PBXNativeTarget "Starscream" */ = {
6B3E79F919D48B7F006071F7 /* Build configuration list for PBXNativeTarget "Starscream iOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
6B3E79FA19D48B7F006071F7 /* Debug */,
@@ -824,7 +826,7 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
6B3E79FC19D48B7F006071F7 /* Build configuration list for PBXNativeTarget "StarscreamTests" */ = {
6B3E79FC19D48B7F006071F7 /* Build configuration list for PBXNativeTarget "Starscream iOSTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
6B3E79FD19D48B7F006071F7 /* Debug */,
@@ -833,7 +835,7 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
D9C3E37619E48FF1009FC285 /* Build configuration list for PBXNativeTarget "StarscreamOSX" */ = {
D9C3E37619E48FF1009FC285 /* Build configuration list for PBXNativeTarget "Starscream OSX" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D9C3E37219E48FF1009FC285 /* Debug */,
@@ -842,7 +844,7 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
D9C3E37719E48FF1009FC285 /* Build configuration list for PBXNativeTarget "StarscreamOSXTests" */ = {
D9C3E37719E48FF1009FC285 /* Build configuration list for PBXNativeTarget "Starscream OSXTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D9C3E37419E48FF1009FC285 /* Debug */,
@@ -16,7 +16,7 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "6B3E79E519D48B7F006071F7"
BuildableName = "Starscream.framework"
BlueprintName = "Starscream"
BlueprintName = "Starscream iOS"
ReferencedContainer = "container:Starscream.xcodeproj">
</BuildableReference>
</BuildActionEntry>
@@ -47,7 +47,7 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "6B3E79E519D48B7F006071F7"
BuildableName = "Starscream.framework"
BlueprintName = "Starscream"
BlueprintName = "Starscream iOS"
ReferencedContainer = "container:Starscream.xcodeproj">
</BuildableReference>
</MacroExpansion>
@@ -65,7 +65,7 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "6B3E79E519D48B7F006071F7"
BuildableName = "Starscream.framework"
BlueprintName = "Starscream"
BlueprintName = "Starscream iOS"
ReferencedContainer = "container:Starscream.xcodeproj">
</BuildableReference>
</MacroExpansion>
@@ -16,7 +16,7 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "D9C3E35E19E48FF1009FC285"
BuildableName = "Starscream.framework"
BlueprintName = "StarscreamOSX"
BlueprintName = "Starscream OSX"
ReferencedContainer = "container:Starscream.xcodeproj">
</BuildableReference>
</BuildActionEntry>
@@ -29,8 +29,8 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D9C3E36819E48FF1009FC285"
BuildableName = "StarscreamOSXTests.xctest"
BlueprintName = "StarscreamOSXTests"
BuildableName = "Starscream OSXTests.xctest"
BlueprintName = "Starscream OSXTests"
ReferencedContainer = "container:Starscream.xcodeproj">
</BuildableReference>
</BuildActionEntry>
@@ -47,8 +47,8 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D9C3E36819E48FF1009FC285"
BuildableName = "StarscreamOSXTests.xctest"
BlueprintName = "StarscreamOSXTests"
BuildableName = "Starscream OSXTests.xctest"
BlueprintName = "Starscream OSXTests"
ReferencedContainer = "container:Starscream.xcodeproj">
</BuildableReference>
</TestableReference>
@@ -58,7 +58,7 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "D9C3E35E19E48FF1009FC285"
BuildableName = "Starscream.framework"
BlueprintName = "StarscreamOSX"
BlueprintName = "Starscream OSX"
ReferencedContainer = "container:Starscream.xcodeproj">
</BuildableReference>
</MacroExpansion>
@@ -80,7 +80,7 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "D9C3E35E19E48FF1009FC285"
BuildableName = "Starscream.framework"
BlueprintName = "StarscreamOSX"
BlueprintName = "Starscream OSX"
ReferencedContainer = "container:Starscream.xcodeproj">
</BuildableReference>
</MacroExpansion>
@@ -98,7 +98,7 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "D9C3E35E19E48FF1009FC285"
BuildableName = "Starscream.framework"
BlueprintName = "StarscreamOSX"
BlueprintName = "Starscream OSX"
ReferencedContainer = "container:Starscream.xcodeproj">
</BuildableReference>
</MacroExpansion>
@@ -15,8 +15,8 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6B3E79F019D48B7F006071F7"
BuildableName = "StarscreamTests.xctest"
BlueprintName = "StarscreamTests"
BuildableName = "Starscream iOSTests.xctest"
BlueprintName = "Starscream iOSTests"
ReferencedContainer = "container:Starscream.xcodeproj">
</BuildableReference>
</BuildActionEntry>
@@ -33,8 +33,8 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6B3E79F019D48B7F006071F7"
BuildableName = "StarscreamTests.xctest"
BlueprintName = "StarscreamTests"
BuildableName = "Starscream iOSTests.xctest"
BlueprintName = "Starscream iOSTests"
ReferencedContainer = "container:Starscream.xcodeproj">
</BuildableReference>
</TestableReference>
@@ -43,8 +43,8 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6B3E79F019D48B7F006071F7"
BuildableName = "StarscreamTests.xctest"
BlueprintName = "StarscreamTests"
BuildableName = "Starscream iOSTests.xctest"
BlueprintName = "Starscream iOSTests"
ReferencedContainer = "container:Starscream.xcodeproj">
</BuildableReference>
</MacroExpansion>
@@ -65,8 +65,8 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6B3E79F019D48B7F006071F7"
BuildableName = "StarscreamTests.xctest"
BlueprintName = "StarscreamTests"
BuildableName = "Starscream iOSTests.xctest"
BlueprintName = "Starscream iOSTests"
ReferencedContainer = "container:Starscream.xcodeproj">
</BuildableReference>
</MacroExpansion>
@@ -83,8 +83,8 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6B3E79F019D48B7F006071F7"
BuildableName = "StarscreamTests.xctest"
BlueprintName = "StarscreamTests"
BuildableName = "Starscream iOSTests.xctest"
BlueprintName = "Starscream iOSTests"
ReferencedContainer = "container:Starscream.xcodeproj">
</BuildableReference>
</MacroExpansion>
@@ -16,7 +16,7 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "091277961BD673A70003036D"
BuildableName = "Starscream.framework"
BlueprintName = "StarscreamTv"
BlueprintName = "Starscream tvOS"
ReferencedContainer = "container:Starscream.xcodeproj">
</BuildableReference>
</BuildActionEntry>
@@ -29,8 +29,8 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0912779F1BD673A70003036D"
BuildableName = "StarscreamTvTests.xctest"
BlueprintName = "StarscreamTvTests"
BuildableName = "Starscream tvOSTests.xctest"
BlueprintName = "Starscream tvOSTests"
ReferencedContainer = "container:Starscream.xcodeproj">
</BuildableReference>
</BuildActionEntry>
@@ -47,8 +47,8 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0912779F1BD673A70003036D"
BuildableName = "StarscreamTvTests.xctest"
BlueprintName = "StarscreamTvTests"
BuildableName = "Starscream tvOSTests.xctest"
BlueprintName = "Starscream tvOSTests"
ReferencedContainer = "container:Starscream.xcodeproj">
</BuildableReference>
</TestableReference>
@@ -58,7 +58,7 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "091277961BD673A70003036D"
BuildableName = "Starscream.framework"
BlueprintName = "StarscreamTv"
BlueprintName = "Starscream tvOS"
ReferencedContainer = "container:Starscream.xcodeproj">
</BuildableReference>
</MacroExpansion>
@@ -80,7 +80,7 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "091277961BD673A70003036D"
BuildableName = "Starscream.framework"
BlueprintName = "StarscreamTv"
BlueprintName = "Starscream tvOS"
ReferencedContainer = "container:Starscream.xcodeproj">
</BuildableReference>
</MacroExpansion>
@@ -98,7 +98,7 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "091277961BD673A70003036D"
BuildableName = "Starscream.framework"
BlueprintName = "StarscreamTv"
BlueprintName = "Starscream tvOS"
ReferencedContainer = "container:Starscream.xcodeproj">
</BuildableReference>
</MacroExpansion>
@@ -1,13 +1,14 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6211" systemVersion="14A298i" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9531" systemVersion="15C50" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6204"/>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="target" sceneMemberID="viewController">
<viewController id="BYZ-38-t0r" customClass="ViewController" customModule="Autobahn" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
@@ -11,9 +11,9 @@ import Starscream
class ViewController: UIViewController {
static let host = "localhost:9001"
static let scheme = "ws"
var socket = WebSocket(url: NSURL(scheme: scheme, host: host, path: "/getCaseCount")!, protocols: [])
let host = "localhost:9001"
let scheme = "ws"
var socketArray = [WebSocket]()
var caseCount = 300 //starting cases
override func viewDidLoad() {
super.viewDidLoad()
@@ -21,22 +21,30 @@ class ViewController: UIViewController {
//getTestInfo(1)
}
func removeSocket(s: WebSocket) {
self.socketArray = self.socketArray.filter{$0 != s}
}
func getCaseCount() {
socket.onText = {(text: String) in
let s = WebSocket(url: NSURL(scheme: scheme, host: host, path: "/getCaseCount")!, protocols: [])
socketArray.append(s)
s.onText = {[unowned self] (text: String) in
if let c = Int(text) {
print("number of cases is: \(c)")
self.caseCount = c
}
}
socket.onDisconnect = {(error: NSError?) in
s.onDisconnect = {[unowned self] (error: NSError?) in
self.getTestInfo(1)
self.removeSocket(s)
}
socket.connect()
s.connect()
}
func getTestInfo(caseNum: Int) {
socket = createSocket("getCaseInfo",caseNum)
socket.onText = {(text: String) in
let s = createSocket("getCaseInfo",caseNum)
socketArray.append(s)
s.onText = {(text: String) in
// let data = text.dataUsingEncoding(NSUTF8StringEncoding)
// do {
// let resp: AnyObject? = try NSJSONSerialization.JSONObjectWithData(data!,
@@ -54,37 +62,41 @@ class ViewController: UIViewController {
}
var once = false
socket.onDisconnect = {(error: NSError?) in
s.onDisconnect = {[unowned self] (error: NSError?) in
if !once {
once = true
self.runTest(caseNum)
}
self.removeSocket(s)
}
socket.connect()
s.connect()
}
func runTest(caseNum: Int) {
socket = createSocket("runCase",caseNum)
socket.onText = {(text: String) in
self.socket.writeString(text)
let s = createSocket("runCase",caseNum)
self.socketArray.append(s)
s.onText = {(text: String) in
s.writeString(text)
}
socket.onData = {(data: NSData) in
self.socket.writeData(data)
s.onData = {(data: NSData) in
s.writeData(data)
}
var once = false
socket.onDisconnect = {(error: NSError?) in
s.onDisconnect = {[unowned self] (error: NSError?) in
if !once {
once = true
print("case:\(caseNum) finished")
self.verifyTest(caseNum)
self.removeSocket(s)
}
}
socket.connect()
s.connect()
}
func verifyTest(caseNum: Int) {
socket = createSocket("getCaseStatus",caseNum)
socket.onText = {(text: String) in
let s = createSocket("getCaseStatus",caseNum)
self.socketArray.append(s)
s.onText = {(text: String) in
let data = text.dataUsingEncoding(NSUTF8StringEncoding)
do {
let resp: AnyObject? = try NSJSONSerialization.JSONObjectWithData(data!,
@@ -103,7 +115,7 @@ class ViewController: UIViewController {
}
}
var once = false
socket.onDisconnect = {(error: NSError?) in
s.onDisconnect = {[unowned self] (error: NSError?) in
if !once {
once = true
let nextCase = caseNum+1
@@ -113,21 +125,24 @@ class ViewController: UIViewController {
self.finishReports()
}
}
self.removeSocket(s)
}
socket.connect()
s.connect()
}
func finishReports() {
socket = createSocket("updateReports",0)
socket.onDisconnect = {(error: NSError?) in
let s = createSocket("updateReports",0)
self.socketArray.append(s)
s.onDisconnect = {[unowned self] (error: NSError?) in
print("finished all the tests!")
self.removeSocket(s)
}
socket.connect()
s.connect()
}
func createSocket(cmd: String, _ caseNum: Int) -> WebSocket {
return WebSocket(url: NSURL(scheme: ViewController.scheme,
host: ViewController.host, path: buildPath(cmd,caseNum))!, protocols: [])
return WebSocket(url: NSURL(scheme: scheme,
host: host, path: buildPath(cmd,caseNum))!, protocols: [])
}
func buildPath(cmd: String, _ caseNum: Int) -> String {