Compare commits
50 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 75721192c9 | |||
| 0c4a99588f | |||
| 4387f497c9 | |||
| d87b422950 | |||
| c5569dff12 | |||
| 6b303eafec | |||
| 0f8dd95f70 | |||
| ede7c9aa89 | |||
| afefdff061 | |||
| 3a59333bac | |||
| 1951d74516 | |||
| 6c34076224 | |||
| f189e7c51f | |||
| 95c91f9dbf | |||
| 398d9c15bf | |||
| 5a85e4e524 | |||
| d6f2c2c409 | |||
| ad91b8f1f3 | |||
| c59125f34a | |||
| ce9062ab81 | |||
| ff64f0b349 | |||
| 65dbee5c94 | |||
| 7927195b05 | |||
| d32dcb2aaa | |||
| aeae316209 | |||
| 4f2201d6b7 | |||
| ec313a376e | |||
| d5f690123f | |||
| b00a84716c | |||
| aa11fd3bbe | |||
| b6dddff56c | |||
| ac4f5ced1e | |||
| 947601b673 | |||
| cea6ce13c8 | |||
| 09c032a138 | |||
| 3fe7363ee9 | |||
| 32925e3847 | |||
| 6ad98fb458 | |||
| f02840355d | |||
| 4bece17d89 | |||
| 3582bab0b8 | |||
| 737fca6e73 | |||
| e9446a57cd | |||
| b6054567ee | |||
| 2b8d6214e2 | |||
| c56e0104c3 | |||
| 2bbc0895d6 | |||
| f1acef9a5f | |||
| b29059a937 | |||
| e1bbc7612e |
@@ -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)
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
BIN
Binary file not shown.
Reference in New Issue
Block a user