Compare commits
259 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 13859364e3 | |||
| 41c0c5e08b | |||
| 60b27a4388 | |||
| a68bf7c35b | |||
| 33a4551f3b | |||
| b22fae407e | |||
| e9160df255 | |||
| c63e173021 | |||
| ddcc30d200 | |||
| 6bacb6f972 | |||
| aca2ad5332 | |||
| 3ba1963c65 | |||
| 3cc4a60e05 | |||
| 14313df360 | |||
| 162c1d53b8 | |||
| b404f98244 | |||
| 8d0c0c1afa | |||
| 816fe413a4 | |||
| 5cc0d860ba | |||
| 4d2f8dbfee | |||
| 126c021e61 | |||
| c13584b99c | |||
| 178c3e8a49 | |||
| ccc1b703dd | |||
| 1b64f78542 | |||
| 549500a503 | |||
| 22d57dca07 | |||
| dd5119cfce | |||
| a6b2e4329b | |||
| 931e3ba8ae | |||
| 7476f5196e | |||
| 20285cce97 | |||
| 8e1de1d475 | |||
| acf64adc24 | |||
| b0fa08cde4 | |||
| 9d32864ab4 | |||
| 7ef2bc41e0 | |||
| 24e32a78e3 | |||
| d831901ff4 | |||
| 26b03ddaef | |||
| d94c3ff3b4 | |||
| 60d853742c | |||
| 8563f6b85e | |||
| c889a6c977 | |||
| 8f3761215b | |||
| cdf8caeb1a | |||
| 00d8fae6cd | |||
| 46db9a75f0 | |||
| 5a3adc7756 | |||
| b1472f2a99 | |||
| 34ed785564 | |||
| 08d2da1221 | |||
| 5c607a80ce | |||
| 3aac891e83 | |||
| 32fb0aa87e | |||
| 473a1382ac | |||
| 9c210e006e | |||
| c767cb2a54 | |||
| cdd1224a71 | |||
| 7c09aa08b4 | |||
| c2782b5452 | |||
| 14bc9ad90f | |||
| bdab51f4af | |||
| 26297ed3c1 | |||
| 600815b240 | |||
| 5fba5b83b4 | |||
| c39043cc29 | |||
| dd6bfa24b7 | |||
| 64661bc6ce | |||
| 0f03fab95d | |||
| c7b52b4485 | |||
| fc35de78a5 | |||
| d911dc1adf | |||
| f5f777c507 | |||
| cca4af6112 | |||
| afad19ca84 | |||
| b159d03640 | |||
| d5aeefd853 | |||
| f0f2ceee20 | |||
| 10cfb16197 | |||
| bf0146db26 | |||
| cf6def9453 | |||
| 8db1a45c6c | |||
| 592da86d06 | |||
| 43ade49abe | |||
| e32674a1ea | |||
| 7e49eb2458 | |||
| 53c19d2388 | |||
| ab02d55700 | |||
| fa0865fcac | |||
| 5d185b41cb | |||
| ba1d7db873 | |||
| e2eea95ea5 | |||
| 363e331a84 | |||
| 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 | |||
| e10942bc23 | |||
| 9cf2c1f787 | |||
| bc48e654ca | |||
| 5e2768c048 | |||
| 756a42756a | |||
| 4442aed401 | |||
| 5f4db02f99 | |||
| 679d858bbb | |||
| ec32edfb4e | |||
| df98a6e363 | |||
| 47bcdfbe57 | |||
| d69b169970 | |||
| aa2cb1b8fb | |||
| fe2c26b760 | |||
| 357cd532dc | |||
| e0e4b379e7 | |||
| 4c66b22b43 | |||
| e848f186a5 | |||
| c8201ec71c | |||
| f990c68c53 | |||
| 9d37723c4d | |||
| b32048b229 | |||
| a40f448a16 | |||
| dcb046a46c | |||
| 357a178a64 | |||
| 7a15d7d7e6 | |||
| 13f7502163 | |||
| 2e5cb03ac3 | |||
| b26ffa28cd | |||
| fd18936144 | |||
| e30b9a6f78 | |||
| b962e3e532 | |||
| 889d2880eb | |||
| f509d9d485 | |||
| 7b46baf12b | |||
| 5dfe1fc117 | |||
| f46e64b179 | |||
| 4d072de18d | |||
| f0b188606f | |||
| fac69339ba | |||
| e2c3e38a23 | |||
| 5f46a9097e | |||
| 8376a9c70b | |||
| 02f8eac43b | |||
| 6a318b29d2 | |||
| df88d97511 | |||
| ca478d26b2 | |||
| d1f3deee70 | |||
| 4b65324a8d | |||
| 9663215089 | |||
| 5d272a80ef | |||
| 56fb313bc5 | |||
| e39ddeecf5 | |||
| 36d4426888 | |||
| 7b19d84984 | |||
| b3db9d413a | |||
| a69929fbc1 | |||
| 3178fb1705 | |||
| ea6cdfb6ad | |||
| 74a954ecf5 | |||
| 072a3c20b2 | |||
| 115817d85a | |||
| da76eba769 | |||
| 4c4495da75 | |||
| 4f49db32a3 | |||
| b753466d48 | |||
| dce9d6f865 | |||
| d201b8805f | |||
| 3574f7ccca | |||
| 74b1d43d87 | |||
| 5236b39d2f | |||
| 3a0bc019a6 | |||
| 7b8454e729 | |||
| 44e4fc46cb | |||
| 1a2b098896 | |||
| 3d5f525720 | |||
| 01ab7a9d41 | |||
| 553a596ad1 | |||
| cc91478cde | |||
| 9ee175a8f6 | |||
| 2ed6a3ba3f | |||
| f839150743 | |||
| 00b75106ac | |||
| b5241956ce | |||
| 927a02ebe5 | |||
| 647fb4cb68 | |||
| f9241d39ab | |||
| 274c0e94ad | |||
| 8d607623f5 | |||
| ae03601a52 | |||
| e1855398c9 | |||
| 06761dbe51 | |||
| 97f3785287 | |||
| 93f934bfa1 | |||
| b869b321f6 | |||
| c95a83f607 | |||
| 98f48a158e | |||
| 85e0fc1665 | |||
| 25ff7ad6f5 | |||
| 62f1010578 | |||
| a893d21330 | |||
| 4fe0874f96 | |||
| eb603ea8d6 | |||
| 040da0af16 | |||
| 4a2e571e3e | |||
| eae21b74c7 | |||
| f7fe6364f7 | |||
| 9cba9ad105 | |||
| 7e1b61da74 | |||
| c902bf58a9 | |||
| 3701ae7fcf | |||
| f5cde43cbc | |||
| 732cee4ce1 | |||
| 4dc35eb139 | |||
| 323918db35 |
+1
-1
@@ -8,7 +8,7 @@
|
||||
|
||||
# Xcode
|
||||
.DS_Store
|
||||
build/
|
||||
build
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
*.mode1v3
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
3.0
|
||||
@@ -0,0 +1,91 @@
|
||||
# Change Log
|
||||
All notable changes to this project will be documented in this file.
|
||||
`Starscream` adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
#### [2.0.3](https://github.com/daltoniam/Starscream/tree/2.0.3)
|
||||
|
||||
[#302](https://github.com/daltoniam/Starscream/issues/302)
|
||||
[#301](https://github.com/daltoniam/Starscream/issues/301)
|
||||
[#300](https://github.com/daltoniam/Starscream/issues/300)
|
||||
[#296](https://github.com/daltoniam/Starscream/issues/296)
|
||||
[#294](https://github.com/daltoniam/Starscream/issues/294)
|
||||
[#292](https://github.com/daltoniam/Starscream/issues/292)
|
||||
[#289](https://github.com/daltoniam/Starscream/issues/289)
|
||||
[#288](https://github.com/daltoniam/Starscream/issues/288)
|
||||
|
||||
#### [2.0.2](https://github.com/daltoniam/Starscream/tree/2.0.2)
|
||||
|
||||
Fix for the Swift Package Manager.
|
||||
|
||||
Fixed:
|
||||
[#277](https://github.com/daltoniam/Starscream/issues/277)
|
||||
|
||||
#### [2.0.1](https://github.com/daltoniam/Starscream/tree/2.0.1)
|
||||
|
||||
Bug fixes.
|
||||
|
||||
Fixed:
|
||||
[#261](https://github.com/daltoniam/Starscream/issues/261)
|
||||
[#276](https://github.com/daltoniam/Starscream/issues/276)
|
||||
[#267](https://github.com/daltoniam/Starscream/issues/267)
|
||||
[#266](https://github.com/daltoniam/Starscream/issues/266)
|
||||
[#259](https://github.com/daltoniam/Starscream/issues/259)
|
||||
|
||||
#### [2.0.0](https://github.com/daltoniam/Starscream/tree/2.0.0)
|
||||
|
||||
Added Swift 3 support.
|
||||
|
||||
Fixed:
|
||||
[#229](https://github.com/daltoniam/Starscream/issues/229)
|
||||
[#232](https://github.com/daltoniam/Starscream/issues/232)
|
||||
|
||||
#### [1.1.4](https://github.com/daltoniam/Starscream/tree/1.1.4)
|
||||
|
||||
Swift 2.3 support.
|
||||
|
||||
#### [1.1.3](https://github.com/daltoniam/Starscream/tree/1.1.3)
|
||||
|
||||
Changed:
|
||||
[#170](https://github.com/daltoniam/Starscream/issues/170)
|
||||
[#171](https://github.com/daltoniam/Starscream/issues/171)
|
||||
[#174](https://github.com/daltoniam/Starscream/issues/174)
|
||||
[#177](https://github.com/daltoniam/Starscream/issues/177)
|
||||
[#178](https://github.com/daltoniam/Starscream/issues/178)
|
||||
|
||||
#### [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)
|
||||
|
||||
Added TVOS support.
|
||||
|
||||
#### [1.0.1](https://github.com/daltoniam/Starscream/tree/1.0.1)
|
||||
|
||||
Fixes for #121, #123
|
||||
|
||||
#### [1.0.0](https://github.com/daltoniam/Starscream/tree/1.0.0)
|
||||
|
||||
first release of Swift 2 support.
|
||||
@@ -1,7 +1,9 @@
|
||||
Apache License
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
Copyright (c) 2014-2016 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-2016 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"
|
||||
)
|
||||
@@ -1,15 +1,13 @@
|
||||

|
||||

|
||||
|
||||
Starscream is a conforming WebSocket ([RFC 6455](http://tools.ietf.org/html/rfc6455)) client library in Swift for iOS and OSX.
|
||||
|
||||
It's Objective-C counter part can be found here: [Jetfire](https://github.com/acmacalister/jetfire)
|
||||
|
||||
|
||||
## 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.
|
||||
|
||||
@@ -18,16 +16,13 @@ It's Objective-C counter part can be found here: [Jetfire](https://github.com/ac
|
||||
First thing is to import the framework. See the Installation instructions on how to add the framework to your project.
|
||||
|
||||
```swift
|
||||
//iOS
|
||||
import Starscream
|
||||
//OS X
|
||||
import StarscreamOSX
|
||||
```
|
||||
|
||||
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(scheme: "ws", host: "localhost:8080", path: "/"))
|
||||
socket = WebSocket(url: URL(string: "ws://localhost:8080/")!)
|
||||
socket.delegate = self
|
||||
socket.connect()
|
||||
```
|
||||
@@ -40,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")
|
||||
}
|
||||
```
|
||||
|
||||
@@ -50,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)")
|
||||
}
|
||||
```
|
||||
|
||||
@@ -60,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)")
|
||||
}
|
||||
```
|
||||
|
||||
@@ -69,27 +64,72 @@ func websocketDidReceiveMessage(socket: WebSocket, text: String) {
|
||||
websocketDidReceiveData is called when the client gets a binary frame from the connection.
|
||||
|
||||
```swift
|
||||
func websocketDidReceiveData(socket: WebSocket, data: NSData) {
|
||||
println("got some data: \(data.length)")
|
||||
func websocketDidReceiveData(socket: WebSocket, data: Data) {
|
||||
print("got some data: \(data.count)")
|
||||
}
|
||||
```
|
||||
|
||||
The delegate methods give you a simple way to handle data from the server, but how do you send data?
|
||||
### Optional: websocketDidReceivePong *(required protocol: WebSocketPongDelegate)*
|
||||
|
||||
### writeData
|
||||
|
||||
The writeData method gives you a simple way to send `NSData` (binary) data to the server.
|
||||
websocketDidReceivePong is called when the client gets a pong response from the connection. You need to implement the WebSocketPongDelegate protocol and set an additional delegate, eg: ` socket.pongDelegate = self`
|
||||
|
||||
```swift
|
||||
self.socket.writeData(data) //write some NSData over the socket!
|
||||
func websocketDidReceivePong(socket: WebSocket, data: Data?) {
|
||||
print("Got pong! Maybe some data: \(data?.count)")
|
||||
}
|
||||
```
|
||||
|
||||
### writeString
|
||||
Or you can use closures.
|
||||
|
||||
```swift
|
||||
socket = WebSocket(url: URL(string: "ws://localhost:8080/")!)
|
||||
//websocketDidConnect
|
||||
socket.onConnect = {
|
||||
print("websocket is connected")
|
||||
}
|
||||
//websocketDidDisconnect
|
||||
socket.onDisconnect = { (error: NSError?) in
|
||||
print("websocket is disconnected: \(error?.localizedDescription)")
|
||||
}
|
||||
//websocketDidReceiveMessage
|
||||
socket.onText = { (text: String) in
|
||||
print("got some text: \(text)")
|
||||
}
|
||||
//websocketDidReceiveData
|
||||
socket.onData = { (data: Data) in
|
||||
print("got some data: \(data.count)")
|
||||
}
|
||||
//you could do onPong as well.
|
||||
socket.connect()
|
||||
```
|
||||
|
||||
One more: you can listen to socket connection and disconnection via notifications. Starscream posts `WebsocketDidConnectNotification` and `WebsocketDidDisconnectNotification`. You can find an `NSError` that caused the disconection by accessing `WebsocketDisconnectionErrorKeyName` on notification `userInfo`.
|
||||
|
||||
|
||||
## The delegate methods give you a simple way to handle data from the server, but how do you send data?
|
||||
|
||||
### write a binary frame
|
||||
|
||||
The writeData method gives you a simple way to send `Data` (binary) data to the server.
|
||||
|
||||
```swift
|
||||
socket.write(data: data) //write some Data over the socket!
|
||||
```
|
||||
|
||||
### write a string frame
|
||||
|
||||
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.write(string: "Hi Server!") //example on how to write text over the socket!
|
||||
```
|
||||
|
||||
### write a ping frame
|
||||
|
||||
The writePing method is the same as write, but sends a ping control frame.
|
||||
|
||||
```swift
|
||||
socket.write(ping: Data()) //example on how to write a ping control frame over the socket!
|
||||
```
|
||||
|
||||
### disconnect
|
||||
@@ -97,7 +137,7 @@ self.socket.writeString("Hi Server!") //example on how to write text over the so
|
||||
The disconnect method does what you would expect and closes the socket.
|
||||
|
||||
```swift
|
||||
self.socket.disconnect()
|
||||
socket.disconnect()
|
||||
```
|
||||
|
||||
### isConnected
|
||||
@@ -105,7 +145,7 @@ self.socket.disconnect()
|
||||
Returns if the socket is connected or not.
|
||||
|
||||
```swift
|
||||
if self.socket.isConnected {
|
||||
if socket.isConnected {
|
||||
// do cool stuff.
|
||||
}
|
||||
```
|
||||
@@ -126,7 +166,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(scheme: "ws", host: "localhost:8080", path: "/"), protocols: ["chat","superchat"])
|
||||
socket = WebSocket(url: URL(string: "ws://localhost:8080/")!, protocols: ["chat","superchat"])
|
||||
socket.delegate = self
|
||||
socket.connect()
|
||||
```
|
||||
@@ -136,13 +176,35 @@ socket.connect()
|
||||
There are a couple of other properties that modify the stream:
|
||||
|
||||
```swift
|
||||
var socket = WebSocket(url: NSURL(scheme: "ws", host: "localhost:8080", path: "/"), protocols: ["chat","superchat"])
|
||||
socket = WebSocket(url: URL(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
|
||||
|
||||
//set this you want to ignore SSL cert validation, so a self signed SSL certificate can be used.
|
||||
socket.selfSignedSSL = true
|
||||
socket.disableSSLCertValidation = true
|
||||
```
|
||||
|
||||
### SSL Pinning
|
||||
|
||||
SSL Pinning is also supported in Starscream.
|
||||
|
||||
```swift
|
||||
socket = WebSocket(url: URL(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
|
||||
```
|
||||
You load either a `Data` blob of your certificate or you can use a `SecKeyRef` if you have a public key you want to use. The `usePublicKeys` bool is whether to use the certificates for validation or the public keys. The public keys will be extracted from the certificates automatically if `usePublicKeys` is choosen.
|
||||
|
||||
### Custom Queue
|
||||
|
||||
A custom queue can be specified when delegate methods are called. By default `DispatchQueue.main` 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
|
||||
socket = WebSocket(url: URL(string: "ws://localhost:8080/")!, protocols: ["chat","superchat"])
|
||||
//create a custom queue
|
||||
socket.callbackQueue = DispatchQueue(label: "com.vluxe.starscream.myapp")
|
||||
```
|
||||
|
||||
## Example Project
|
||||
@@ -151,58 +213,45 @@ Check out the SimpleTest project in the examples directory to see how to setup a
|
||||
|
||||
## Requirements
|
||||
|
||||
Starscream works with iOS 7/OSX 10.9 or above. It is recommended to use iOS 8/10.10 or above for Cocoapods/framework support.
|
||||
Starscream works with iOS 7/OSX 10.9 or above. It is recommended to use iOS 8/10.10 or above for CocoaPods/framework support. To use Starscream with a project targeting iOS 7, you must include all Swift files directly in your project.
|
||||
|
||||
## Installation
|
||||
|
||||
### [CocoaPods](http://cocoapods.org/)
|
||||
At this time, Cocoapods support for Swift frameworks is supported in a [pre-release](http://blog.cocoapods.org/Pod-Authors-Guide-to-CocoaPods-Frameworks/).
|
||||
### CocoaPods
|
||||
|
||||
Check out [Get Started](http://cocoapods.org/) tab on [cocoapods.org](http://cocoapods.org/).
|
||||
|
||||
To use Starscream in your project add the following 'Podfile' to your project
|
||||
|
||||
source 'https://github.com/CocoaPods/Specs.git'
|
||||
source 'https://github.com/CocoaPods/Specs.git'
|
||||
platform :ios, '9.0'
|
||||
use_frameworks!
|
||||
|
||||
xcodeproj 'YourProjectName.xcodeproj'
|
||||
platform :ios, '8.0'
|
||||
|
||||
pod 'Starscream', :git => "https://github.com/daltoniam/starscream.git", :tag => "0.9.1"
|
||||
|
||||
target 'YourProjectNameTests' do
|
||||
pod 'Starscream', :git => "https://github.com/daltoniam/starscream.git", :tag => "0.9.1"
|
||||
end
|
||||
pod 'Starscream', '~> 2.0.3'
|
||||
|
||||
Then run:
|
||||
|
||||
pod install
|
||||
|
||||
#### Updating the Cocoapod
|
||||
You can validate Starscream.podspec using:
|
||||
|
||||
pod spec lint Starscream.podspec
|
||||
|
||||
This should be tested with a sample project before releasing it. This can be done by adding the following line to a ```Podfile```:
|
||||
|
||||
pod 'Starscream', :git => 'https://github.com/username/starscream.git'
|
||||
|
||||
Then run:
|
||||
|
||||
pod install
|
||||
|
||||
If all goes well you are ready to release. First, create a tag and push:
|
||||
|
||||
git tag 'version'
|
||||
git push --tags
|
||||
|
||||
Once the tag is available you can send the library to the Specs repo. For this you'll have to follow the instructions in [Getting Setup with Trunk](http://guides.cocoapods.org/making/getting-setup-with-trunk.html).
|
||||
|
||||
pod trunk push Starscream.podspec
|
||||
|
||||
### Carthage
|
||||
|
||||
Check out the [Carthage](https://github.com/Carthage/Carthage) docs on how to add a install. The `Starscream` framework is already setup with shared schemes.
|
||||
|
||||
[Carthage Install](https://github.com/Carthage/Carthage#adding-frameworks-to-an-application)
|
||||
|
||||
You can install Carthage with [Homebrew](http://brew.sh/) using the following command:
|
||||
|
||||
```bash
|
||||
$ brew update
|
||||
$ brew install carthage
|
||||
```
|
||||
|
||||
To integrate Starscream into your Xcode project using Carthage, specify it in your `Cartfile`:
|
||||
|
||||
```
|
||||
github "daltoniam/Starscream" >= 2.0.3
|
||||
```
|
||||
|
||||
### Rogue
|
||||
|
||||
First see the [installation docs](https://github.com/acmacalister/Rogue) for how to install Rogue.
|
||||
@@ -223,12 +272,13 @@ Add the `Starscream.xcodeproj` to your Xcode project. Once that is complete, in
|
||||
|
||||
### Add Copy Frameworks Phase
|
||||
|
||||
If you are running this in an OSX app or on a physical iOS device you will need to make sure you add the `Starscream.framework` or `StarscreamOSX.framework` to be included in your app bundle. To do this, in Xcode, navigate to the target configuration window by clicking on the blue project icon, and selecting the application target under the "Targets" heading in the sidebar. In the tab bar at the top of that window, open the "Build Phases" panel. Expand the "Link Binary with Libraries" group, and add `Starscream.framework` or `StarscreamOSX.framework` depending on if you are building an iOS or OSX app. Click on the + button at the top left of the panel and select "New Copy Files Phase". Rename this new phase to "Copy Frameworks", set the "Destination" to "Frameworks", and add `Starscream.framework` or `StarscreamOSX.framework` respectively.
|
||||
If you are running this in an OSX app or on a physical iOS device you will need to make sure you add the `Starscream.framework` to be included in your app bundle. To do this, in Xcode, navigate to the target configuration window by clicking on the blue project icon, and selecting the application target under the "Targets" heading in the sidebar. In the tab bar at the top of that window, open the "Build Phases" panel. Expand the "Link Binary with Libraries" group, and add `Starscream.framework`. Click on the + button at the top left of the panel and select "New Copy Files Phase". Rename this new phase to "Copy Frameworks", set the "Destination" to "Frameworks", and add `Starscream.framework` respectively.
|
||||
|
||||
## TODOs
|
||||
|
||||
- [ ] Complete Docs
|
||||
- [ ] 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>2.0.3</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>
|
||||
@@ -7,7 +7,7 @@
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.vluxe.$(PRODUCT_NAME:rfc1034identifier)</string>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<string>2.0.3</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
@@ -0,0 +1,260 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SSLSecurity.swift
|
||||
// Starscream
|
||||
//
|
||||
// Created by Dalton Cherry on 5/16/15.
|
||||
// Copyright (c) 2014-2016 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 Foundation
|
||||
import Security
|
||||
|
||||
public protocol SSLTrustValidator {
|
||||
func isValid(_ trust: SecTrust, domain: String?) -> Bool
|
||||
}
|
||||
|
||||
open class SSLCert {
|
||||
var certData: Data?
|
||||
var key: SecKey?
|
||||
|
||||
/**
|
||||
Designated init for certificates
|
||||
|
||||
- parameter data: is the binary data of the certificate
|
||||
|
||||
- returns: a representation security object to be used with
|
||||
*/
|
||||
public init(data: Data) {
|
||||
self.certData = data
|
||||
}
|
||||
|
||||
/**
|
||||
Designated init for public keys
|
||||
|
||||
- parameter key: is the public key to be used
|
||||
|
||||
- returns: a representation security object to be used with
|
||||
*/
|
||||
public init(key: SecKey) {
|
||||
self.key = key
|
||||
}
|
||||
}
|
||||
|
||||
open class SSLSecurity : SSLTrustValidator {
|
||||
public var validatedDN = true //should the domain name be validated?
|
||||
|
||||
var isReady = false //is the key processing done?
|
||||
var certificates: [Data]? //the certificates
|
||||
var pubKeys: [SecKey]? //the public keys
|
||||
var usePublicKeys = false //use public keys or certificate validation?
|
||||
|
||||
/**
|
||||
Use certs from main app bundle
|
||||
|
||||
- parameter usePublicKeys: is to specific if the publicKeys or certificates should be used for SSL pinning validation
|
||||
|
||||
- returns: a representation security object to be used with
|
||||
*/
|
||||
public convenience init(usePublicKeys: Bool = false) {
|
||||
let paths = Bundle.main.paths(forResourcesOfType: "cer", inDirectory: ".")
|
||||
|
||||
let certs = paths.reduce([SSLCert]()) { (certs: [SSLCert], path: String) -> [SSLCert] in
|
||||
var certs = certs
|
||||
if let data = NSData(contentsOfFile: path) {
|
||||
certs.append(SSLCert(data: data as Data))
|
||||
}
|
||||
return certs
|
||||
}
|
||||
|
||||
self.init(certs: certs, usePublicKeys: usePublicKeys)
|
||||
}
|
||||
|
||||
/**
|
||||
Designated init
|
||||
|
||||
- parameter certs: is the certificates or public keys to use
|
||||
- parameter usePublicKeys: is to specific if the publicKeys or certificates should be used for SSL pinning validation
|
||||
|
||||
- returns: a representation security object to be used with
|
||||
*/
|
||||
public init(certs: [SSLCert], usePublicKeys: Bool) {
|
||||
self.usePublicKeys = usePublicKeys
|
||||
|
||||
if self.usePublicKeys {
|
||||
DispatchQueue.global(qos: .default).async {
|
||||
let pubKeys = certs.reduce([SecKey]()) { (pubKeys: [SecKey], cert: SSLCert) -> [SecKey] in
|
||||
var pubKeys = pubKeys
|
||||
if let data = cert.certData, cert.key == nil {
|
||||
cert.key = self.extractPublicKey(data)
|
||||
}
|
||||
if let key = cert.key {
|
||||
pubKeys.append(key)
|
||||
}
|
||||
return pubKeys
|
||||
}
|
||||
|
||||
self.pubKeys = pubKeys
|
||||
self.isReady = true
|
||||
}
|
||||
} else {
|
||||
let certificates = certs.reduce([Data]()) { (certificates: [Data], cert: SSLCert) -> [Data] in
|
||||
var certificates = certificates
|
||||
if let data = cert.certData {
|
||||
certificates.append(data)
|
||||
}
|
||||
return certificates
|
||||
}
|
||||
self.certificates = certificates
|
||||
self.isReady = true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Valid the trust and domain name.
|
||||
|
||||
- parameter trust: is the serverTrust to validate
|
||||
- parameter domain: is the CN domain to validate
|
||||
|
||||
- returns: if the key was successfully validated
|
||||
*/
|
||||
public func isValid(_ trust: SecTrust, domain: String?) -> Bool {
|
||||
|
||||
var tries = 0
|
||||
while !self.isReady {
|
||||
usleep(1000)
|
||||
tries += 1
|
||||
if tries > 5 {
|
||||
return false //doesn't appear it is going to ever be ready...
|
||||
}
|
||||
}
|
||||
var policy: SecPolicy
|
||||
if self.validatedDN {
|
||||
policy = SecPolicyCreateSSL(true, domain as NSString?)
|
||||
} else {
|
||||
policy = SecPolicyCreateBasicX509()
|
||||
}
|
||||
SecTrustSetPolicies(trust,policy)
|
||||
if self.usePublicKeys {
|
||||
if let keys = self.pubKeys {
|
||||
let serverPubKeys = publicKeyChain(trust)
|
||||
for serverKey in serverPubKeys as [AnyObject] {
|
||||
for key in keys as [AnyObject] {
|
||||
if serverKey.isEqual(key) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let certs = self.certificates {
|
||||
let serverCerts = certificateChain(trust)
|
||||
var collect = [SecCertificate]()
|
||||
for cert in certs {
|
||||
collect.append(SecCertificateCreateWithData(nil,cert as CFData)!)
|
||||
}
|
||||
SecTrustSetAnchorCertificates(trust,collect as NSArray)
|
||||
var result: SecTrustResultType = .unspecified
|
||||
SecTrustEvaluate(trust,&result)
|
||||
if result == .unspecified || result == .proceed {
|
||||
var trustedCount = 0
|
||||
for serverCert in serverCerts {
|
||||
for cert in certs {
|
||||
if cert == serverCert {
|
||||
trustedCount += 1
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if trustedCount == serverCerts.count {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
Get the public key from a certificate data
|
||||
|
||||
- parameter data: is the certificate to pull the public key from
|
||||
|
||||
- returns: a public key
|
||||
*/
|
||||
func extractPublicKey(_ data: Data) -> SecKey? {
|
||||
guard let cert = SecCertificateCreateWithData(nil, data as CFData) else { return nil }
|
||||
|
||||
return extractPublicKey(cert, policy: SecPolicyCreateBasicX509())
|
||||
}
|
||||
|
||||
/**
|
||||
Get the public key from a certificate
|
||||
|
||||
- parameter data: is the certificate to pull the public key from
|
||||
|
||||
- returns: a public key
|
||||
*/
|
||||
func extractPublicKey(_ cert: SecCertificate, policy: SecPolicy) -> SecKey? {
|
||||
var possibleTrust: SecTrust?
|
||||
SecTrustCreateWithCertificates(cert, policy, &possibleTrust)
|
||||
|
||||
guard let trust = possibleTrust else { return nil }
|
||||
var result: SecTrustResultType = .unspecified
|
||||
SecTrustEvaluate(trust, &result)
|
||||
return SecTrustCopyPublicKey(trust)
|
||||
}
|
||||
|
||||
/**
|
||||
Get the certificate chain for the trust
|
||||
|
||||
- parameter trust: is the trust to lookup the certificate chain for
|
||||
|
||||
- returns: the certificate chain for the trust
|
||||
*/
|
||||
func certificateChain(_ trust: SecTrust) -> [Data] {
|
||||
let certificates = (0..<SecTrustGetCertificateCount(trust)).reduce([Data]()) { (certificates: [Data], index: Int) -> [Data] in
|
||||
var certificates = certificates
|
||||
let cert = SecTrustGetCertificateAtIndex(trust, index)
|
||||
certificates.append(SecCertificateCopyData(cert!) as Data)
|
||||
return certificates
|
||||
}
|
||||
|
||||
return certificates
|
||||
}
|
||||
|
||||
/**
|
||||
Get the public key chain for the trust
|
||||
|
||||
- parameter trust: is the trust to lookup the certificate chain and extract the public keys
|
||||
|
||||
- returns: the public keys from the certifcate chain for the trust
|
||||
*/
|
||||
func publicKeyChain(_ trust: SecTrust) -> [SecKey] {
|
||||
let policy = SecPolicyCreateBasicX509()
|
||||
let keys = (0..<SecTrustGetCertificateCount(trust)).reduce([SecKey]()) { (keys: [SecKey], index: Int) -> [SecKey] in
|
||||
var keys = keys
|
||||
let cert = SecTrustGetCertificateAtIndex(trust, index)
|
||||
if let key = extractPublicKey(cert!, policy: policy) {
|
||||
keys.append(key)
|
||||
}
|
||||
|
||||
return keys
|
||||
}
|
||||
|
||||
return keys
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -6,13 +6,7 @@
|
||||
// Copyright (c) 2014 Vluxe. All rights reserved.
|
||||
//
|
||||
|
||||
#import <TargetConditionals.h>
|
||||
|
||||
#ifdef TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
|
||||
#import <UIKit/UIKit.h>
|
||||
#else
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#endif
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
//! Project version number for Starscream.
|
||||
FOUNDATION_EXPORT double StarscreamVersionNumber;
|
||||
@@ -0,0 +1,968 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Websocket.swift
|
||||
//
|
||||
// Created by Dalton Cherry on 7/16/14.
|
||||
// Copyright (c) 2014-2016 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 Foundation
|
||||
import CoreFoundation
|
||||
import Security
|
||||
|
||||
public let WebsocketDidConnectNotification = "WebsocketDidConnectNotification"
|
||||
public let WebsocketDidDisconnectNotification = "WebsocketDidDisconnectNotification"
|
||||
public let WebsocketDisconnectionErrorKeyName = "WebsocketDisconnectionErrorKeyName"
|
||||
|
||||
public protocol WebSocketDelegate: class {
|
||||
func websocketDidConnect(socket: WebSocket)
|
||||
func websocketDidDisconnect(socket: WebSocket, error: NSError?)
|
||||
func websocketDidReceiveMessage(socket: WebSocket, text: String)
|
||||
func websocketDidReceiveData(socket: WebSocket, data: Data)
|
||||
}
|
||||
|
||||
public protocol WebSocketPongDelegate: class {
|
||||
func websocketDidReceivePong(socket: WebSocket, data: Data?)
|
||||
}
|
||||
|
||||
open class WebSocket : NSObject, StreamDelegate {
|
||||
|
||||
enum OpCode : UInt8 {
|
||||
case continueFrame = 0x0
|
||||
case textFrame = 0x1
|
||||
case binaryFrame = 0x2
|
||||
// 3-7 are reserved.
|
||||
case connectionClose = 0x8
|
||||
case ping = 0x9
|
||||
case pong = 0xA
|
||||
// B-F reserved.
|
||||
}
|
||||
|
||||
public enum CloseCode : UInt16 {
|
||||
case normal = 1000
|
||||
case goingAway = 1001
|
||||
case protocolError = 1002
|
||||
case protocolUnhandledType = 1003
|
||||
// 1004 reserved.
|
||||
case noStatusReceived = 1005
|
||||
//1006 reserved.
|
||||
case encoding = 1007
|
||||
case policyViolated = 1008
|
||||
case messageTooBig = 1009
|
||||
}
|
||||
|
||||
public static let ErrorDomain = "WebSocket"
|
||||
|
||||
enum InternalErrorCode: UInt16 {
|
||||
// 0-999 WebSocket status codes not used
|
||||
case outputStreamWriteError = 1
|
||||
}
|
||||
|
||||
// Where the callback is executed. It defaults to the main UI thread queue.
|
||||
public var callbackQueue = DispatchQueue.main
|
||||
|
||||
var optionalProtocols: [String]?
|
||||
|
||||
// MARK: - Constants
|
||||
|
||||
let headerWSUpgradeName = "Upgrade"
|
||||
let headerWSUpgradeValue = "websocket"
|
||||
let headerWSHostName = "Host"
|
||||
let headerWSConnectionName = "Connection"
|
||||
let headerWSConnectionValue = "Upgrade"
|
||||
let headerWSProtocolName = "Sec-WebSocket-Protocol"
|
||||
let headerWSVersionName = "Sec-WebSocket-Version"
|
||||
let headerWSVersionValue = "13"
|
||||
let headerWSKeyName = "Sec-WebSocket-Key"
|
||||
let headerOriginName = "Origin"
|
||||
let headerWSAcceptName = "Sec-WebSocket-Accept"
|
||||
let BUFFER_MAX = 4096
|
||||
let FinMask: UInt8 = 0x80
|
||||
let OpCodeMask: UInt8 = 0x0F
|
||||
let RSVMask: UInt8 = 0x70
|
||||
let MaskMask: UInt8 = 0x80
|
||||
let PayloadLenMask: UInt8 = 0x7F
|
||||
let MaxFrameSize: Int = 32
|
||||
let httpSwitchProtocolCode = 101
|
||||
let supportedSSLSchemes = ["wss", "https"]
|
||||
|
||||
class WSResponse {
|
||||
var isFin = false
|
||||
var code: OpCode = .continueFrame
|
||||
var bytesLeft = 0
|
||||
var frameCount = 0
|
||||
var buffer: NSMutableData?
|
||||
}
|
||||
|
||||
// MARK: - Delegates
|
||||
|
||||
/// Responds to callback about new messages coming in over the WebSocket
|
||||
/// and also connection/disconnect messages.
|
||||
public weak var delegate: WebSocketDelegate?
|
||||
|
||||
/// Receives a callback for each pong message recived.
|
||||
public weak var pongDelegate: WebSocketPongDelegate?
|
||||
|
||||
|
||||
// MARK: - Block based API.
|
||||
|
||||
public var onConnect: ((Void) -> Void)?
|
||||
public var onDisconnect: ((NSError?) -> Void)?
|
||||
public var onText: ((String) -> Void)?
|
||||
public var onData: ((Data) -> Void)?
|
||||
public var onPong: ((Data?) -> Void)?
|
||||
|
||||
public var headers = [String: String]()
|
||||
public var voipEnabled = false
|
||||
public var disableSSLCertValidation = false
|
||||
public var security: SSLTrustValidator?
|
||||
public var enabledSSLCipherSuites: [SSLCipherSuite]?
|
||||
public var origin: String?
|
||||
public var timeout = 5
|
||||
public var isConnected: Bool {
|
||||
return connected
|
||||
}
|
||||
|
||||
public var currentURL: URL { return url }
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private var url: URL
|
||||
private var inputStream: InputStream?
|
||||
private var outputStream: OutputStream?
|
||||
private var connected = false
|
||||
private var isConnecting = false
|
||||
private var writeQueue = OperationQueue()
|
||||
private var readStack = [WSResponse]()
|
||||
private var inputQueue = [Data]()
|
||||
private var fragBuffer: Data?
|
||||
private var certValidated = false
|
||||
private var didDisconnect = false
|
||||
private var readyToWrite = false
|
||||
private let mutex = NSLock()
|
||||
private let notificationCenter = NotificationCenter.default
|
||||
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 = DispatchQueue(label: "com.vluxe.starscream.websocket", attributes: [])
|
||||
|
||||
/// Used for setting protocols.
|
||||
public init(url: URL, protocols: [String]? = nil) {
|
||||
self.url = url
|
||||
self.origin = url.absoluteString
|
||||
if let hostUrl = URL (string: "/", relativeTo: url) {
|
||||
var origin = hostUrl.absoluteString
|
||||
origin.remove(at: origin.index(before: origin.endIndex))
|
||||
self.origin = origin
|
||||
}
|
||||
writeQueue.maxConcurrentOperationCount = 1
|
||||
optionalProtocols = protocols
|
||||
}
|
||||
|
||||
// Used for specifically setting the QOS for the write queue.
|
||||
public convenience init(url: URL, writeQueueQOS: QualityOfService, protocols: [String]? = nil) {
|
||||
self.init(url: url, protocols: protocols)
|
||||
writeQueue.qualityOfService = writeQueueQOS
|
||||
}
|
||||
|
||||
/**
|
||||
Connect to the WebSocket server on a background thread.
|
||||
*/
|
||||
open func connect() {
|
||||
guard !isConnecting else { return }
|
||||
didDisconnect = false
|
||||
isConnecting = true
|
||||
createHTTPRequest()
|
||||
}
|
||||
|
||||
/**
|
||||
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.
|
||||
- Parameter closeCode: The code to send on disconnect. The default is the normal close code for cleanly disconnecting a webSocket.
|
||||
*/
|
||||
open func disconnect(forceTimeout: TimeInterval? = nil, closeCode: UInt16 = CloseCode.normal.rawValue) {
|
||||
guard isConnected else { return }
|
||||
switch forceTimeout {
|
||||
case .some(let seconds) where seconds > 0:
|
||||
let milliseconds = Int(seconds * 1_000)
|
||||
callbackQueue.asyncAfter(deadline: .now() + .milliseconds(milliseconds)) { [weak self] in
|
||||
self?.disconnectStream(nil)
|
||||
}
|
||||
fallthrough
|
||||
case .none:
|
||||
writeError(closeCode)
|
||||
default:
|
||||
disconnectStream(nil)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Write a string to the websocket. This sends it as a text frame.
|
||||
|
||||
If you supply a non-nil completion block, I will perform it when the write completes.
|
||||
|
||||
- parameter string: The string to write.
|
||||
- parameter completion: The (optional) completion handler.
|
||||
*/
|
||||
open func write(string: String, completion: (() -> ())? = nil) {
|
||||
guard isConnected else { return }
|
||||
dequeueWrite(string.data(using: String.Encoding.utf8)!, code: .textFrame, writeCompletion: completion)
|
||||
}
|
||||
|
||||
/**
|
||||
Write binary data to the websocket. This sends it as a binary frame.
|
||||
|
||||
If you supply a non-nil completion block, I will perform it when the write completes.
|
||||
|
||||
- parameter data: The data to write.
|
||||
- parameter completion: The (optional) completion handler.
|
||||
*/
|
||||
open func write(data: Data, completion: (() -> ())? = nil) {
|
||||
guard isConnected else { return }
|
||||
dequeueWrite(data, code: .binaryFrame, writeCompletion: completion)
|
||||
}
|
||||
|
||||
/**
|
||||
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
|
||||
*/
|
||||
open func write(ping: Data, completion: (() -> ())? = nil) {
|
||||
guard isConnected else { return }
|
||||
dequeueWrite(ping, code: .ping, writeCompletion: completion)
|
||||
}
|
||||
|
||||
/**
|
||||
Private method that starts the connection.
|
||||
*/
|
||||
private func createHTTPRequest() {
|
||||
|
||||
let urlRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, "GET" as CFString,
|
||||
url as CFURL, kCFHTTPVersion1_1).takeRetainedValue()
|
||||
|
||||
var port = url.port
|
||||
if port == nil {
|
||||
if supportedSSLSchemes.contains(url.scheme!) {
|
||||
port = 443
|
||||
} else {
|
||||
port = 80
|
||||
}
|
||||
}
|
||||
addHeader(urlRequest, key: headerWSUpgradeName, val: headerWSUpgradeValue)
|
||||
addHeader(urlRequest, key: headerWSConnectionName, val: headerWSConnectionValue)
|
||||
if let protocols = optionalProtocols {
|
||||
addHeader(urlRequest, key: headerWSProtocolName, val: protocols.joined(separator: ","))
|
||||
}
|
||||
addHeader(urlRequest, key: headerWSVersionName, val: headerWSVersionValue)
|
||||
addHeader(urlRequest, key: headerWSKeyName, val: generateWebSocketKey())
|
||||
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)
|
||||
}
|
||||
if let cfHTTPMessage = CFHTTPMessageCopySerializedMessage(urlRequest) {
|
||||
let serializedRequest = cfHTTPMessage.takeRetainedValue()
|
||||
initStreamsWithData(serializedRequest as Data, Int(port!))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Add a header to the CFHTTPMessage by using the NSString bridges to CFString
|
||||
*/
|
||||
private func addHeader(_ urlRequest: CFHTTPMessage, key: String, val: String) {
|
||||
CFHTTPMessageSetHeaderFieldValue(urlRequest, key as CFString, val as CFString)
|
||||
}
|
||||
|
||||
/**
|
||||
Generate a WebSocket key as needed in RFC.
|
||||
*/
|
||||
private func generateWebSocketKey() -> String {
|
||||
var key = ""
|
||||
let seed = 16
|
||||
for _ in 0..<seed {
|
||||
let uni = UnicodeScalar(UInt32(97 + arc4random_uniform(25)))
|
||||
key += "\(Character(uni!))"
|
||||
}
|
||||
let data = key.data(using: String.Encoding.utf8)
|
||||
let baseKey = data?.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))
|
||||
return baseKey!
|
||||
}
|
||||
|
||||
/**
|
||||
Start the stream connection and write the data to the output stream.
|
||||
*/
|
||||
private func initStreamsWithData(_ data: Data, _ port: Int) {
|
||||
//higher level API we will cut over to at some point
|
||||
//NSStream.getStreamsToHostWithName(url.host, port: url.port.integerValue, inputStream: &inputStream, outputStream: &outputStream)
|
||||
|
||||
// Disconnect and clean up any existing streams before setting up a new pair
|
||||
disconnectStream(nil, runDelegate: false)
|
||||
|
||||
var readStream: Unmanaged<CFReadStream>?
|
||||
var writeStream: Unmanaged<CFWriteStream>?
|
||||
let h = url.host! as NSString
|
||||
CFStreamCreatePairWithSocketToHost(nil, h, UInt32(port), &readStream, &writeStream)
|
||||
inputStream = readStream!.takeRetainedValue()
|
||||
outputStream = writeStream!.takeRetainedValue()
|
||||
guard let inStream = inputStream, let outStream = outputStream else { return }
|
||||
inStream.delegate = self
|
||||
outStream.delegate = self
|
||||
if supportedSSLSchemes.contains(url.scheme!) {
|
||||
inStream.setProperty(StreamSocketSecurityLevel.negotiatedSSL as AnyObject, forKey: Stream.PropertyKey.socketSecurityLevelKey)
|
||||
outStream.setProperty(StreamSocketSecurityLevel.negotiatedSSL as AnyObject, forKey: Stream.PropertyKey.socketSecurityLevelKey)
|
||||
if disableSSLCertValidation {
|
||||
let settings: [NSObject: NSObject] = [kCFStreamSSLValidatesCertificateChain: NSNumber(value: false), kCFStreamSSLPeerName: kCFNull]
|
||||
inStream.setProperty(settings, forKey: kCFStreamPropertySSLSettings as Stream.PropertyKey)
|
||||
outStream.setProperty(settings, forKey: kCFStreamPropertySSLSettings as Stream.PropertyKey)
|
||||
}
|
||||
if let cipherSuites = self.enabledSSLCipherSuites {
|
||||
if let sslContextIn = CFReadStreamCopyProperty(inputStream, CFStreamPropertyKey(rawValue: kCFStreamPropertySSLContext)) as! SSLContext?,
|
||||
let sslContextOut = CFWriteStreamCopyProperty(outputStream, CFStreamPropertyKey(rawValue: kCFStreamPropertySSLContext)) as! SSLContext? {
|
||||
let resIn = SSLSetEnabledCiphers(sslContextIn, cipherSuites, cipherSuites.count)
|
||||
let resOut = SSLSetEnabledCiphers(sslContextOut, cipherSuites, cipherSuites.count)
|
||||
if resIn != errSecSuccess {
|
||||
let error = self.errorWithDetail("Error setting ingoing cypher suites", code: UInt16(resIn))
|
||||
disconnectStream(error)
|
||||
return
|
||||
}
|
||||
if resOut != errSecSuccess {
|
||||
let error = self.errorWithDetail("Error setting outgoing cypher suites", code: UInt16(resOut))
|
||||
disconnectStream(error)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
certValidated = true //not a https session, so no need to check SSL pinning
|
||||
}
|
||||
if voipEnabled {
|
||||
inStream.setProperty(StreamNetworkServiceTypeValue.voIP as AnyObject, forKey: Stream.PropertyKey.networkServiceType)
|
||||
outStream.setProperty(StreamNetworkServiceTypeValue.voIP as AnyObject, forKey: Stream.PropertyKey.networkServiceType)
|
||||
}
|
||||
|
||||
CFReadStreamSetDispatchQueue(inStream, WebSocket.sharedWorkQueue)
|
||||
CFWriteStreamSetDispatchQueue(outStream, WebSocket.sharedWorkQueue)
|
||||
inStream.open()
|
||||
outStream.open()
|
||||
|
||||
self.mutex.lock()
|
||||
self.readyToWrite = true
|
||||
self.mutex.unlock()
|
||||
|
||||
let bytes = UnsafeRawPointer((data as NSData).bytes).assumingMemoryBound(to: UInt8.self)
|
||||
var out = timeout * 1_000_000 // wait 5 seconds before giving up
|
||||
let operation = BlockOperation()
|
||||
operation.addExecutionBlock { [weak self, weak operation] in
|
||||
guard let sOperation = operation else { return }
|
||||
while !outStream.hasSpaceAvailable && !sOperation.isCancelled {
|
||||
usleep(100) // wait until the socket is ready
|
||||
guard !sOperation.isCancelled else { return }
|
||||
out -= 100
|
||||
if out < 0 {
|
||||
self?.cleanupStream()
|
||||
self?.doDisconnect(self?.errorWithDetail("write wait timed out", code: 2))
|
||||
return
|
||||
} else if outStream.streamError != nil {
|
||||
return // disconnectStream will be called.
|
||||
}
|
||||
}
|
||||
guard !sOperation.isCancelled else { return }
|
||||
outStream.write(bytes, maxLength: data.count)
|
||||
}
|
||||
writeQueue.addOperation(operation)
|
||||
}
|
||||
|
||||
/**
|
||||
Delegate for the stream methods. Processes incoming bytes
|
||||
*/
|
||||
open func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
|
||||
if let sec = security, !certValidated && [.hasBytesAvailable, .hasSpaceAvailable].contains(eventCode) {
|
||||
let trust = aStream.property(forKey: kCFStreamPropertySSLPeerTrust as Stream.PropertyKey) as! SecTrust
|
||||
let domain = aStream.property(forKey: kCFStreamSSLPeerName as Stream.PropertyKey) as? String
|
||||
if sec.isValid(trust, domain: domain) {
|
||||
certValidated = true
|
||||
} else {
|
||||
let error = errorWithDetail("Invalid SSL certificate", code: 1)
|
||||
disconnectStream(error)
|
||||
return
|
||||
}
|
||||
}
|
||||
if eventCode == .hasBytesAvailable {
|
||||
if aStream == inputStream {
|
||||
processInputStream()
|
||||
}
|
||||
} else if eventCode == .errorOccurred {
|
||||
disconnectStream(aStream.streamError as NSError?)
|
||||
} else if eventCode == .endEncountered {
|
||||
disconnectStream(nil)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Disconnect the stream object and notifies the delegate.
|
||||
*/
|
||||
private func disconnectStream(_ error: NSError?, runDelegate: Bool = true) {
|
||||
if error == nil {
|
||||
writeQueue.waitUntilAllOperationsAreFinished()
|
||||
} else {
|
||||
writeQueue.cancelAllOperations()
|
||||
}
|
||||
cleanupStream()
|
||||
connected = false
|
||||
if runDelegate {
|
||||
doDisconnect(error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
cleanup the streams.
|
||||
*/
|
||||
private func cleanupStream() {
|
||||
outputStream?.delegate = nil
|
||||
inputStream?.delegate = nil
|
||||
if let stream = inputStream {
|
||||
CFReadStreamSetDispatchQueue(stream, nil)
|
||||
stream.close()
|
||||
}
|
||||
if let stream = outputStream {
|
||||
CFWriteStreamSetDispatchQueue(stream, nil)
|
||||
stream.close()
|
||||
}
|
||||
outputStream = nil
|
||||
inputStream = nil
|
||||
fragBuffer = nil
|
||||
}
|
||||
|
||||
/**
|
||||
Handles the incoming bytes and sending them to the proper processing method.
|
||||
*/
|
||||
private func processInputStream() {
|
||||
let buf = NSMutableData(capacity: BUFFER_MAX)
|
||||
let buffer = UnsafeMutableRawPointer(mutating: buf!.bytes).assumingMemoryBound(to: UInt8.self)
|
||||
let length = inputStream!.read(buffer, maxLength: BUFFER_MAX)
|
||||
guard length > 0 else { return }
|
||||
var process = false
|
||||
if inputQueue.count == 0 {
|
||||
process = true
|
||||
}
|
||||
inputQueue.append(Data(bytes: buffer, count: length))
|
||||
if process {
|
||||
dequeueInput()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Dequeue the incoming input so it is processed in order.
|
||||
*/
|
||||
private func dequeueInput() {
|
||||
while !inputQueue.isEmpty {
|
||||
autoreleasepool {
|
||||
let data = inputQueue[0]
|
||||
var work = data
|
||||
if let buffer = fragBuffer {
|
||||
var combine = NSData(data: buffer) as Data
|
||||
combine.append(data)
|
||||
work = combine
|
||||
fragBuffer = nil
|
||||
}
|
||||
let buffer = UnsafeRawPointer((work as NSData).bytes).assumingMemoryBound(to: UInt8.self)
|
||||
let length = work.count
|
||||
if !connected {
|
||||
processTCPHandshake(buffer, bufferLen: length)
|
||||
} else {
|
||||
processRawMessagesInBuffer(buffer, bufferLen: length)
|
||||
}
|
||||
inputQueue = inputQueue.filter{ $0 != data }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Handle checking the inital connection status
|
||||
*/
|
||||
private func processTCPHandshake(_ buffer: UnsafePointer<UInt8>, bufferLen: Int) {
|
||||
let code = processHTTP(buffer, bufferLen: bufferLen)
|
||||
switch code {
|
||||
case 0:
|
||||
break
|
||||
case -1:
|
||||
fragBuffer = Data(bytes: buffer, count: 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) -> Int {
|
||||
let CRLFBytes = [UInt8(ascii: "\r"), UInt8(ascii: "\n"), UInt8(ascii: "\r"), UInt8(ascii: "\n")]
|
||||
var k = 0
|
||||
var totalSize = 0
|
||||
for i in 0..<bufferLen {
|
||||
if buffer[i] == CRLFBytes[k] {
|
||||
k += 1
|
||||
if k == 3 {
|
||||
totalSize = i + 1
|
||||
break
|
||||
}
|
||||
} else {
|
||||
k = 0
|
||||
}
|
||||
}
|
||||
if totalSize > 0 {
|
||||
let code = validateResponse(buffer, bufferLen: totalSize)
|
||||
if code != 0 {
|
||||
return code
|
||||
}
|
||||
isConnecting = false
|
||||
connected = true
|
||||
didDisconnect = false
|
||||
if canDispatch {
|
||||
callbackQueue.async { [weak self] in
|
||||
guard let s = self else { return }
|
||||
s.onConnect?()
|
||||
s.delegate?.websocketDidConnect(socket: s)
|
||||
s.notificationCenter.post(name: NSNotification.Name(WebsocketDidConnectNotification), object: self)
|
||||
}
|
||||
}
|
||||
totalSize += 1 //skip the last \n
|
||||
let restSize = bufferLen - totalSize
|
||||
if restSize > 0 {
|
||||
processRawMessagesInBuffer(buffer + totalSize, bufferLen: restSize)
|
||||
}
|
||||
return 0 //success
|
||||
}
|
||||
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) -> Int {
|
||||
let response = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, false).takeRetainedValue()
|
||||
CFHTTPMessageAppendBytes(response, buffer, bufferLen)
|
||||
let code = CFHTTPMessageGetResponseStatusCode(response)
|
||||
if code != httpSwitchProtocolCode {
|
||||
return code
|
||||
}
|
||||
if let cfHeaders = CFHTTPMessageCopyAllHeaderFields(response) {
|
||||
let headers = cfHeaders.takeRetainedValue() as NSDictionary
|
||||
if let acceptKey = headers[headerWSAcceptName as NSString] as? NSString {
|
||||
if acceptKey.length > 0 {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
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 one message at the start of `buffer`. Return another buffer (sharing storage) that contains the leftover contents of `buffer` that I didn't process.
|
||||
*/
|
||||
private func processOneRawMessage(inBuffer buffer: UnsafeBufferPointer<UInt8>) -> UnsafeBufferPointer<UInt8> {
|
||||
let response = readStack.last
|
||||
guard let baseAddress = buffer.baseAddress else {return emptyBuffer}
|
||||
let bufferLen = buffer.count
|
||||
if response != nil && bufferLen < 2 {
|
||||
fragBuffer = Data(buffer: buffer)
|
||||
return emptyBuffer
|
||||
}
|
||||
if let response = response, response.bytesLeft > 0 {
|
||||
var len = response.bytesLeft
|
||||
var extra = bufferLen - response.bytesLeft
|
||||
if response.bytesLeft > bufferLen {
|
||||
len = bufferLen
|
||||
extra = 0
|
||||
}
|
||||
response.bytesLeft -= len
|
||||
response.buffer?.append(Data(bytes: baseAddress, count: len))
|
||||
_ = processResponse(response)
|
||||
return buffer.fromOffset(bufferLen - extra)
|
||||
} else {
|
||||
let isFin = (FinMask & baseAddress[0])
|
||||
let receivedOpcode = OpCode(rawValue: (OpCodeMask & baseAddress[0]))
|
||||
let isMasked = (MaskMask & baseAddress[1])
|
||||
let payloadLen = (PayloadLenMask & baseAddress[1])
|
||||
var offset = 2
|
||||
if (isMasked > 0 || (RSVMask & baseAddress[0]) > 0) && receivedOpcode != .pong {
|
||||
let errCode = CloseCode.protocolError.rawValue
|
||||
doDisconnect(errorWithDetail("masked and rsv data is not currently supported", code: errCode))
|
||||
writeError(errCode)
|
||||
return emptyBuffer
|
||||
}
|
||||
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)
|
||||
return emptyBuffer
|
||||
}
|
||||
if isControlFrame && isFin == 0 {
|
||||
let errCode = CloseCode.protocolError.rawValue
|
||||
doDisconnect(errorWithDetail("control frames can't be fragmented", code: errCode))
|
||||
writeError(errCode)
|
||||
return emptyBuffer
|
||||
}
|
||||
var closeCode = CloseCode.normal.rawValue
|
||||
if receivedOpcode == .connectionClose {
|
||||
if payloadLen == 1 {
|
||||
closeCode = CloseCode.protocolError.rawValue
|
||||
} else if payloadLen > 1 {
|
||||
closeCode = WebSocket.readUint16(baseAddress, offset: offset)
|
||||
if closeCode < 1000 || (closeCode > 1003 && closeCode < 1007) || (closeCode > 1011 && closeCode < 3000) {
|
||||
closeCode = CloseCode.protocolError.rawValue
|
||||
}
|
||||
}
|
||||
if payloadLen < 2 {
|
||||
doDisconnect(errorWithDetail("connection closed by server", code: closeCode))
|
||||
writeError(closeCode)
|
||||
return emptyBuffer
|
||||
}
|
||||
} else if isControlFrame && payloadLen > 125 {
|
||||
writeError(CloseCode.protocolError.rawValue)
|
||||
return emptyBuffer
|
||||
}
|
||||
var dataLength = UInt64(payloadLen)
|
||||
if dataLength == 127 {
|
||||
dataLength = WebSocket.readUint64(baseAddress, offset: offset)
|
||||
offset += MemoryLayout<UInt64>.size
|
||||
} else if dataLength == 126 {
|
||||
dataLength = UInt64(WebSocket.readUint16(baseAddress, offset: offset))
|
||||
offset += MemoryLayout<UInt16>.size
|
||||
}
|
||||
if bufferLen < offset || UInt64(bufferLen - offset) < dataLength {
|
||||
fragBuffer = Data(bytes: baseAddress, count: bufferLen)
|
||||
return emptyBuffer
|
||||
}
|
||||
var len = dataLength
|
||||
if dataLength > UInt64(bufferLen) {
|
||||
len = UInt64(bufferLen-offset)
|
||||
}
|
||||
let data: Data
|
||||
if len < 0 {
|
||||
len = 0
|
||||
data = Data()
|
||||
} else {
|
||||
if receivedOpcode == .connectionClose && len > 0 {
|
||||
let size = MemoryLayout<UInt16>.size
|
||||
offset += size
|
||||
len -= UInt64(size)
|
||||
}
|
||||
data = Data(bytes: baseAddress+offset, count: Int(len))
|
||||
}
|
||||
if receivedOpcode == .connectionClose {
|
||||
var closeReason = "connection closed by server"
|
||||
if let customCloseReason = String(data: data, encoding: .utf8) {
|
||||
closeReason = customCloseReason
|
||||
} else {
|
||||
closeCode = CloseCode.protocolError.rawValue
|
||||
}
|
||||
doDisconnect(errorWithDetail(closeReason, code: closeCode))
|
||||
writeError(closeCode)
|
||||
return emptyBuffer
|
||||
}
|
||||
if receivedOpcode == .pong {
|
||||
if canDispatch {
|
||||
callbackQueue.async { [weak self] in
|
||||
guard let s = self else { return }
|
||||
let pongData: Data? = data.count > 0 ? data : nil
|
||||
s.onPong?(pongData)
|
||||
s.pongDelegate?.websocketDidReceivePong(socket: s, data: pongData)
|
||||
}
|
||||
}
|
||||
return buffer.fromOffset(offset + Int(len))
|
||||
}
|
||||
var response = readStack.last
|
||||
if isControlFrame {
|
||||
response = nil // Don't append pings.
|
||||
}
|
||||
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 emptyBuffer
|
||||
}
|
||||
var isNew = false
|
||||
if response == nil {
|
||||
if receivedOpcode == .continueFrame {
|
||||
let errCode = CloseCode.protocolError.rawValue
|
||||
doDisconnect(errorWithDetail("first frame can't be a continue frame",
|
||||
code: errCode))
|
||||
writeError(errCode)
|
||||
return emptyBuffer
|
||||
}
|
||||
isNew = true
|
||||
response = WSResponse()
|
||||
response!.code = receivedOpcode!
|
||||
response!.bytesLeft = Int(dataLength)
|
||||
response!.buffer = NSMutableData(data: data)
|
||||
} else {
|
||||
if receivedOpcode == .continueFrame {
|
||||
response!.bytesLeft = Int(dataLength)
|
||||
} else {
|
||||
let errCode = CloseCode.protocolError.rawValue
|
||||
doDisconnect(errorWithDetail("second and beyond of fragment message must be a continue frame",
|
||||
code: errCode))
|
||||
writeError(errCode)
|
||||
return emptyBuffer
|
||||
}
|
||||
response!.buffer!.append(data)
|
||||
}
|
||||
if let response = response {
|
||||
response.bytesLeft -= Int(len)
|
||||
response.frameCount += 1
|
||||
response.isFin = isFin > 0 ? true : false
|
||||
if isNew {
|
||||
readStack.append(response)
|
||||
}
|
||||
_ = processResponse(response)
|
||||
}
|
||||
|
||||
let step = Int(offset + numericCast(len))
|
||||
return buffer.fromOffset(step)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Process all messages in the buffer if possible.
|
||||
*/
|
||||
private func processRawMessagesInBuffer(_ pointer: UnsafePointer<UInt8>, bufferLen: Int) {
|
||||
var buffer = UnsafeBufferPointer(start: pointer, count: bufferLen)
|
||||
repeat {
|
||||
buffer = processOneRawMessage(inBuffer: buffer)
|
||||
} while buffer.count >= 2
|
||||
if buffer.count > 0 {
|
||||
fragBuffer = Data(buffer: buffer)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Process the finished response of a buffer.
|
||||
*/
|
||||
private func processResponse(_ response: WSResponse) -> Bool {
|
||||
if response.isFin && response.bytesLeft <= 0 {
|
||||
if response.code == .ping {
|
||||
let data = response.buffer! // local copy so it is perverse for writing
|
||||
dequeueWrite(data as Data, code: .pong)
|
||||
} else if response.code == .textFrame {
|
||||
let str: NSString? = NSString(data: response.buffer! as Data, encoding: String.Encoding.utf8.rawValue)
|
||||
if str == nil {
|
||||
writeError(CloseCode.encoding.rawValue)
|
||||
return false
|
||||
}
|
||||
if canDispatch {
|
||||
callbackQueue.async { [weak self] in
|
||||
guard let s = self else { return }
|
||||
s.onText?(str! as String)
|
||||
s.delegate?.websocketDidReceiveMessage(socket: s, text: str! as String)
|
||||
}
|
||||
}
|
||||
} else if response.code == .binaryFrame {
|
||||
if canDispatch {
|
||||
let data = response.buffer! // local copy so it is perverse for writing
|
||||
callbackQueue.async { [weak self] in
|
||||
guard let s = self else { return }
|
||||
s.onData?(data as Data)
|
||||
s.delegate?.websocketDidReceiveData(socket: s, data: data as Data)
|
||||
}
|
||||
}
|
||||
}
|
||||
readStack.removeLast()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
Create an error
|
||||
*/
|
||||
private func errorWithDetail(_ detail: String, code: UInt16) -> NSError {
|
||||
var details = [String: String]()
|
||||
details[NSLocalizedDescriptionKey] = detail
|
||||
return NSError(domain: WebSocket.ErrorDomain, code: Int(code), userInfo: details)
|
||||
}
|
||||
|
||||
/**
|
||||
Write an error to the socket
|
||||
*/
|
||||
private func writeError(_ code: UInt16) {
|
||||
let buf = NSMutableData(capacity: MemoryLayout<UInt16>.size)
|
||||
let buffer = UnsafeMutableRawPointer(mutating: buf!.bytes).assumingMemoryBound(to: UInt8.self)
|
||||
WebSocket.writeUint16(buffer, offset: 0, value: code)
|
||||
dequeueWrite(Data(bytes: buffer, count: MemoryLayout<UInt16>.size), code: .connectionClose)
|
||||
}
|
||||
|
||||
/**
|
||||
Used to write things to the stream
|
||||
*/
|
||||
private func dequeueWrite(_ data: Data, code: OpCode, writeCompletion: (() -> ())? = nil) {
|
||||
let operation = BlockOperation()
|
||||
operation.addExecutionBlock { [weak self, weak operation] in
|
||||
//stream isn't ready, let's wait
|
||||
guard let s = self else { return }
|
||||
guard let sOperation = operation else { return }
|
||||
var offset = 2
|
||||
let dataLength = data.count
|
||||
let frame = NSMutableData(capacity: dataLength + s.MaxFrameSize)
|
||||
let buffer = UnsafeMutableRawPointer(frame!.mutableBytes).assumingMemoryBound(to: UInt8.self)
|
||||
buffer[0] = s.FinMask | code.rawValue
|
||||
if dataLength < 126 {
|
||||
buffer[1] = CUnsignedChar(dataLength)
|
||||
} else if dataLength <= Int(UInt16.max) {
|
||||
buffer[1] = 126
|
||||
WebSocket.writeUint16(buffer, offset: offset, value: UInt16(dataLength))
|
||||
offset += MemoryLayout<UInt16>.size
|
||||
} else {
|
||||
buffer[1] = 127
|
||||
WebSocket.writeUint64(buffer, offset: offset, value: UInt64(dataLength))
|
||||
offset += MemoryLayout<UInt64>.size
|
||||
}
|
||||
buffer[1] |= s.MaskMask
|
||||
let maskKey = UnsafeMutablePointer<UInt8>(buffer + offset)
|
||||
_ = SecRandomCopyBytes(kSecRandomDefault, Int(MemoryLayout<UInt32>.size), maskKey)
|
||||
offset += MemoryLayout<UInt32>.size
|
||||
|
||||
for i in 0..<dataLength {
|
||||
buffer[offset] = data[i] ^ maskKey[i % MemoryLayout<UInt32>.size]
|
||||
offset += 1
|
||||
}
|
||||
var total = 0
|
||||
while !sOperation.isCancelled {
|
||||
guard let outStream = s.outputStream else { break }
|
||||
let writeBuffer = UnsafeRawPointer(frame!.bytes+total).assumingMemoryBound(to: UInt8.self)
|
||||
let len = outStream.write(writeBuffer, maxLength: offset-total)
|
||||
if len < 0 {
|
||||
var error: Error?
|
||||
if let streamError = outStream.streamError {
|
||||
error = streamError
|
||||
} else {
|
||||
let errCode = InternalErrorCode.outputStreamWriteError.rawValue
|
||||
error = s.errorWithDetail("output stream error during write", code: errCode)
|
||||
}
|
||||
s.doDisconnect(error as NSError?)
|
||||
break
|
||||
} else {
|
||||
total += len
|
||||
}
|
||||
if total >= offset {
|
||||
if let queue = self?.callbackQueue, let callback = writeCompletion {
|
||||
queue.async {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
writeQueue.addOperation(operation)
|
||||
}
|
||||
|
||||
/**
|
||||
Used to preform the disconnect delegate
|
||||
*/
|
||||
private func doDisconnect(_ error: NSError?) {
|
||||
guard !didDisconnect else { return }
|
||||
didDisconnect = true
|
||||
isConnecting = false
|
||||
connected = false
|
||||
guard canDispatch else {return}
|
||||
callbackQueue.async { [weak self] in
|
||||
guard let s = self else { return }
|
||||
s.onDisconnect?(error)
|
||||
s.delegate?.websocketDidDisconnect(socket: s, error: error)
|
||||
let userInfo = error.map{ [WebsocketDisconnectionErrorKeyName: $0] }
|
||||
s.notificationCenter.post(name: NSNotification.Name(WebsocketDidDisconnectNotification), object: self, userInfo: userInfo)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Deinit
|
||||
|
||||
deinit {
|
||||
mutex.lock()
|
||||
readyToWrite = false
|
||||
mutex.unlock()
|
||||
cleanupStream()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private extension Data {
|
||||
|
||||
init(buffer: UnsafeBufferPointer<UInt8>) {
|
||||
self.init(bytes: buffer.baseAddress!, count: buffer.count)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private extension UnsafeBufferPointer {
|
||||
|
||||
func fromOffset(_ offset: Int) -> UnsafeBufferPointer<Element> {
|
||||
return UnsafeBufferPointer<Element>(start: baseAddress?.advanced(by: offset), count: count - offset)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private let emptyBuffer = UnsafeBufferPointer<UInt8>(start: nil, count: 0)
|
||||
+4
-3
@@ -1,6 +1,6 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "Starscream"
|
||||
s.version = "0.9.2"
|
||||
s.version = "2.0.3"
|
||||
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'
|
||||
@@ -8,7 +8,8 @@ Pod::Spec.new do |s|
|
||||
s.source = { :git => 'https://github.com/daltoniam/Starscream.git', :tag => "#{s.version}"}
|
||||
s.social_media_url = 'http://twitter.com/daltoniam'
|
||||
s.ios.deployment_target = '8.0'
|
||||
s.osx.deployment_target = '10.9'
|
||||
s.source_files = '*.swift'
|
||||
s.osx.deployment_target = '10.10'
|
||||
s.tvos.deployment_target = '9.0'
|
||||
s.source_files = 'Source/*.swift'
|
||||
s.requires_arc = 'true'
|
||||
end
|
||||
|
||||
@@ -7,16 +7,30 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
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 /* StarscreamOSX.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9C3E35F19E48FF1009FC285 /* StarscreamOSX.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 */; };
|
||||
091277A11BD673A70003036D /* Starscream.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 091277971BD673A70003036D /* Starscream.framework */; };
|
||||
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 */; };
|
||||
742419BC1DC6BDBA003ACE43 /* StarscreamTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 742419BB1DC6BDBA003ACE43 /* StarscreamTests.swift */; };
|
||||
742419BD1DC6BDBA003ACE43 /* StarscreamTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 742419BB1DC6BDBA003ACE43 /* StarscreamTests.swift */; };
|
||||
742419BE1DC6BDBA003ACE43 /* StarscreamTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 742419BB1DC6BDBA003ACE43 /* StarscreamTests.swift */; };
|
||||
D9C3E36A19E48FF1009FC285 /* Starscream.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9C3E35F19E48FF1009FC285 /* Starscream.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
091277A21BD673A70003036D /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 6B3E79DD19D48B7F006071F7 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 091277961BD673A70003036D;
|
||||
remoteInfo = StarscreamTv;
|
||||
};
|
||||
D9C3E36B19E48FF1009FC285 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 6B3E79DD19D48B7F006071F7 /* Project object */;
|
||||
@@ -27,18 +41,37 @@
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
091277971BD673A70003036D /* Starscream.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Starscream.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
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 /* StarscreamOSX.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = StarscreamOSX.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D9C3E36919E48FF1009FC285 /* StarscreamOSXTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = StarscreamOSXTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
742419BB1DC6BDBA003ACE43 /* StarscreamTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = StarscreamTests.swift; path = StarscreamTests/StarscreamTests.swift; sourceTree = "<group>"; };
|
||||
D9C3E35F19E48FF1009FC285 /* Starscream.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Starscream.framework; 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 */
|
||||
091277931BD673A70003036D /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
0912779D1BD673A70003036D /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
091277A11BD673A70003036D /* Starscream.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
6B3E79E219D48B7F006071F7 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -64,7 +97,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D9C3E36A19E48FF1009FC285 /* StarscreamOSX.framework in Frameworks */,
|
||||
D9C3E36A19E48FF1009FC285 /* Starscream.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -84,9 +117,11 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6B3E79E619D48B7F006071F7 /* Starscream.framework */,
|
||||
6B3E79F119D48B7F006071F7 /* StarscreamTests.xctest */,
|
||||
D9C3E35F19E48FF1009FC285 /* StarscreamOSX.framework */,
|
||||
D9C3E36919E48FF1009FC285 /* StarscreamOSXTests.xctest */,
|
||||
6B3E79F119D48B7F006071F7 /* Starscream iOSTests.xctest */,
|
||||
D9C3E35F19E48FF1009FC285 /* Starscream.framework */,
|
||||
D9C3E36919E48FF1009FC285 /* Starscream OSXTests.xctest */,
|
||||
091277971BD673A70003036D /* Starscream.framework */,
|
||||
091277A01BD673A70003036D /* Starscream tvOSTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -94,8 +129,9 @@
|
||||
6B3E79E819D48B7F006071F7 /* Starscream */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6B3E7A0419D48C41006071F7 /* WebSocket.swift */,
|
||||
6B3E7A0619D48C5F006071F7 /* Starscream.h */,
|
||||
5C1360001C473BEF00AA3A01 /* Starscream.h */,
|
||||
5C135FFF1C473BEF00AA3A01 /* SSLSecurity.swift */,
|
||||
5C1360011C473BEF00AA3A01 /* WebSocket.swift */,
|
||||
6B3E79E919D48B7F006071F7 /* Supporting Files */,
|
||||
);
|
||||
path = Starscream;
|
||||
@@ -104,7 +140,8 @@
|
||||
6B3E79E919D48B7F006071F7 /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6B3E79EA19D48B7F006071F7 /* Info.plist */,
|
||||
5C13600B1C473BFE00AA3A01 /* Info-tvOS.plist */,
|
||||
5C13600C1C473BFE00AA3A01 /* Info.plist */,
|
||||
);
|
||||
name = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
@@ -113,7 +150,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6B3E7A0019D48C2F006071F7 /* Info.plist */,
|
||||
6B3E7A0119D48C2F006071F7 /* StarscreamTests.swift */,
|
||||
742419BB1DC6BDBA003ACE43 /* StarscreamTests.swift */,
|
||||
);
|
||||
path = Tests;
|
||||
sourceTree = "<group>";
|
||||
@@ -121,11 +158,19 @@
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
091277941BD673A70003036D /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5C1360071C473BEF00AA3A01 /* Starscream.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
6B3E79E319D48B7F006071F7 /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
6B3E7A0719D48C5F006071F7 /* Starscream.h in Headers */,
|
||||
5C1360051C473BEF00AA3A01 /* Starscream.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -133,16 +178,52 @@
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D9C3E37919E49051009FC285 /* Starscream.h in Headers */,
|
||||
5C1360061C473BEF00AA3A01 /* Starscream.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
6B3E79E519D48B7F006071F7 /* Starscream */ = {
|
||||
091277961BD673A70003036D /* Starscream tvOS */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 6B3E79F919D48B7F006071F7 /* Build configuration list for PBXNativeTarget "Starscream" */;
|
||||
buildConfigurationList = 091277A81BD673A70003036D /* Build configuration list for PBXNativeTarget "Starscream tvOS" */;
|
||||
buildPhases = (
|
||||
091277921BD673A70003036D /* Sources */,
|
||||
091277931BD673A70003036D /* Frameworks */,
|
||||
091277941BD673A70003036D /* Headers */,
|
||||
091277951BD673A70003036D /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = "Starscream tvOS";
|
||||
productName = StarscreamTv;
|
||||
productReference = 091277971BD673A70003036D /* Starscream.framework */;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
0912779F1BD673A70003036D /* Starscream tvOSTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 091277AB1BD673A70003036D /* Build configuration list for PBXNativeTarget "Starscream tvOSTests" */;
|
||||
buildPhases = (
|
||||
0912779C1BD673A70003036D /* Sources */,
|
||||
0912779D1BD673A70003036D /* Frameworks */,
|
||||
0912779E1BD673A70003036D /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
091277A31BD673A70003036D /* PBXTargetDependency */,
|
||||
);
|
||||
name = "Starscream tvOSTests";
|
||||
productName = StarscreamTvTests;
|
||||
productReference = 091277A01BD673A70003036D /* Starscream tvOSTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
6B3E79E519D48B7F006071F7 /* Starscream iOS */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 6B3E79F919D48B7F006071F7 /* Build configuration list for PBXNativeTarget "Starscream iOS" */;
|
||||
buildPhases = (
|
||||
6B3E79E119D48B7F006071F7 /* Sources */,
|
||||
6B3E79E219D48B7F006071F7 /* Frameworks */,
|
||||
@@ -153,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 */,
|
||||
@@ -170,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 */,
|
||||
@@ -188,14 +269,14 @@
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = StarscreamOSX;
|
||||
name = "Starscream OSX";
|
||||
productName = StarscreamOSX;
|
||||
productReference = D9C3E35F19E48FF1009FC285 /* StarscreamOSX.framework */;
|
||||
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 */,
|
||||
@@ -206,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 */
|
||||
@@ -217,20 +298,32 @@
|
||||
6B3E79DD19D48B7F006071F7 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0600;
|
||||
LastSwiftMigration = 0700;
|
||||
LastSwiftUpdateCheck = 0700;
|
||||
LastUpgradeCheck = 0800;
|
||||
ORGANIZATIONNAME = Vluxe;
|
||||
TargetAttributes = {
|
||||
091277961BD673A70003036D = {
|
||||
CreatedOnToolsVersion = 7.1;
|
||||
};
|
||||
0912779F1BD673A70003036D = {
|
||||
CreatedOnToolsVersion = 7.1;
|
||||
LastSwiftMigration = 0810;
|
||||
};
|
||||
6B3E79E519D48B7F006071F7 = {
|
||||
CreatedOnToolsVersion = 6.0.1;
|
||||
LastSwiftMigration = 0800;
|
||||
};
|
||||
6B3E79F019D48B7F006071F7 = {
|
||||
CreatedOnToolsVersion = 6.0.1;
|
||||
LastSwiftMigration = 0810;
|
||||
};
|
||||
D9C3E35E19E48FF1009FC285 = {
|
||||
CreatedOnToolsVersion = 6.1;
|
||||
};
|
||||
D9C3E36819E48FF1009FC285 = {
|
||||
CreatedOnToolsVersion = 6.1;
|
||||
LastSwiftMigration = 0810;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -246,15 +339,31 @@
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
6B3E79E519D48B7F006071F7 /* Starscream */,
|
||||
6B3E79F019D48B7F006071F7 /* StarscreamTests */,
|
||||
D9C3E35E19E48FF1009FC285 /* StarscreamOSX */,
|
||||
D9C3E36819E48FF1009FC285 /* StarscreamOSXTests */,
|
||||
6B3E79E519D48B7F006071F7 /* Starscream iOS */,
|
||||
6B3E79F019D48B7F006071F7 /* Starscream iOSTests */,
|
||||
D9C3E35E19E48FF1009FC285 /* Starscream OSX */,
|
||||
D9C3E36819E48FF1009FC285 /* Starscream OSXTests */,
|
||||
091277961BD673A70003036D /* Starscream tvOS */,
|
||||
0912779F1BD673A70003036D /* Starscream tvOSTests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
091277951BD673A70003036D /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
0912779E1BD673A70003036D /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
6B3E79E419D48B7F006071F7 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -286,11 +395,29 @@
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
091277921BD673A70003036D /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5C13600A1C473BEF00AA3A01 /* WebSocket.swift in Sources */,
|
||||
5C1360041C473BEF00AA3A01 /* SSLSecurity.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
0912779C1BD673A70003036D /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
742419BE1DC6BDBA003ACE43 /* StarscreamTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
6B3E79E119D48B7F006071F7 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
6B3E7A0519D48C41006071F7 /* WebSocket.swift in Sources */,
|
||||
5C1360081C473BEF00AA3A01 /* WebSocket.swift in Sources */,
|
||||
5C1360021C473BEF00AA3A01 /* SSLSecurity.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -298,7 +425,7 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
6B3E7A0319D48C2F006071F7 /* StarscreamTests.swift in Sources */,
|
||||
742419BC1DC6BDBA003ACE43 /* StarscreamTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -306,7 +433,8 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D9C3E37A19E49058009FC285 /* WebSocket.swift in Sources */,
|
||||
5C1360091C473BEF00AA3A01 /* WebSocket.swift in Sources */,
|
||||
5C1360031C473BEF00AA3A01 /* SSLSecurity.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -314,25 +442,120 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D9C3E37819E4903F009FC285 /* StarscreamTests.swift in Sources */,
|
||||
742419BD1DC6BDBA003ACE43 /* StarscreamTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
091277A31BD673A70003036D /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 091277961BD673A70003036D /* Starscream tvOS */;
|
||||
targetProxy = 091277A21BD673A70003036D /* PBXContainerItemProxy */;
|
||||
};
|
||||
D9C3E36C19E48FF1009FC285 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = D9C3E35E19E48FF1009FC285 /* StarscreamOSX */;
|
||||
target = D9C3E35E19E48FF1009FC285 /* Starscream OSX */;
|
||||
targetProxy = D9C3E36B19E48FF1009FC285 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
091277A91BD673A70003036D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
BITCODE_GENERATION_MODE = marker;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
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;
|
||||
PRODUCT_NAME = Starscream;
|
||||
SDKROOT = appletvos;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 3.0;
|
||||
TARGETED_DEVICE_FAMILY = 3;
|
||||
TVOS_DEPLOYMENT_TARGET = 9.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
091277AA1BD673A70003036D /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
BITCODE_GENERATION_MODE = bitcode;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
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;
|
||||
PRODUCT_NAME = Starscream;
|
||||
SDKROOT = appletvos;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 3.0;
|
||||
TARGETED_DEVICE_FAMILY = 3;
|
||||
TVOS_DEPLOYMENT_TARGET = 9.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
091277AC1BD673A70003036D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = NO;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
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)";
|
||||
SDKROOT = appletvos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 3.0;
|
||||
TVOS_DEPLOYMENT_TARGET = 9.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
091277AD1BD673A70003036D /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = NO;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
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)";
|
||||
SDKROOT = appletvos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 3.0;
|
||||
TVOS_DEPLOYMENT_TARGET = 9.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
6B3E79F719D48B7F006071F7 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
@@ -342,16 +565,20 @@
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
@@ -379,6 +606,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
@@ -388,8 +616,10 @@
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
@@ -398,6 +628,7 @@
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
@@ -417,6 +648,7 @@
|
||||
6B3E79FA19D48B7F006071F7 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BITCODE_GENERATION_MODE = marker;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
@@ -424,21 +656,24 @@
|
||||
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_NAME = "$(TARGET_NAME)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.vluxe.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = Starscream;
|
||||
PROVISIONING_PROFILE = "";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
6B3E79FB19D48B7F006071F7 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BITCODE_GENERATION_MODE = bitcode;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
@@ -446,20 +681,25 @@
|
||||
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_NAME = "$(TARGET_NAME)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.vluxe.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = Starscream;
|
||||
PROVISIONING_PROFILE = "";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
6B3E79FD19D48B7F006071F7 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = NO;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(inherited)",
|
||||
@@ -470,20 +710,28 @@
|
||||
);
|
||||
INFOPLIST_FILE = Tests/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.vluxe.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
6B3E79FE19D48B7F006071F7 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = NO;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(inherited)",
|
||||
);
|
||||
INFOPLIST_FILE = Tests/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.vluxe.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@@ -500,13 +748,16 @@
|
||||
"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;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.vluxe.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = Starscream;
|
||||
SDKROOT = macosx;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 3.0;
|
||||
VALID_ARCHS = x86_64;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -520,19 +771,25 @@
|
||||
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;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.vluxe.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = Starscream;
|
||||
SDKROOT = macosx;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 3.0;
|
||||
VALID_ARCHS = x86_64;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
D9C3E37419E48FF1009FC285 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = NO;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(DEVELOPER_FRAMEWORKS_DIR)",
|
||||
@@ -545,14 +802,19 @@
|
||||
INFOPLIST_FILE = Tests/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.vluxe.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = macosx;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
D9C3E37519E48FF1009FC285 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = NO;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
@@ -562,14 +824,35 @@
|
||||
INFOPLIST_FILE = Tests/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.vluxe.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = macosx;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
091277A81BD673A70003036D /* Build configuration list for PBXNativeTarget "Starscream tvOS" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
091277A91BD673A70003036D /* Debug */,
|
||||
091277AA1BD673A70003036D /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
091277AB1BD673A70003036D /* Build configuration list for PBXNativeTarget "Starscream tvOSTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
091277AC1BD673A70003036D /* Debug */,
|
||||
091277AD1BD673A70003036D /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
6B3E79E019D48B7F006071F7 /* Build configuration list for PBXProject "Starscream" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
@@ -579,7 +862,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 */,
|
||||
@@ -588,7 +871,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 */,
|
||||
@@ -597,7 +880,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 */,
|
||||
@@ -606,7 +889,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 */,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0610"
|
||||
LastUpgradeVersion = "0810"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -16,35 +16,38 @@
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "6B3E79E519D48B7F006071F7"
|
||||
BuildableName = "Starscream.framework"
|
||||
BlueprintName = "Starscream"
|
||||
BlueprintName = "Starscream iOS"
|
||||
ReferencedContainer = "container:Starscream.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
buildConfiguration = "Debug">
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Debug"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "6B3E79E519D48B7F006071F7"
|
||||
BuildableName = "Starscream.framework"
|
||||
BlueprintName = "Starscream"
|
||||
BlueprintName = "Starscream iOS"
|
||||
ReferencedContainer = "container:Starscream.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
@@ -52,17 +55,17 @@
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Release"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "6B3E79E519D48B7F006071F7"
|
||||
BuildableName = "Starscream.framework"
|
||||
BlueprintName = "Starscream"
|
||||
BlueprintName = "Starscream iOS"
|
||||
ReferencedContainer = "container:Starscream.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0610"
|
||||
LastUpgradeVersion = "0810"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -15,8 +15,8 @@
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D9C3E35E19E48FF1009FC285"
|
||||
BuildableName = "StarscreamOSX.framework"
|
||||
BlueprintName = "StarscreamOSX"
|
||||
BuildableName = "Starscream.framework"
|
||||
BlueprintName = "Starscream OSX"
|
||||
ReferencedContainer = "container:Starscream.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
@@ -29,26 +29,26 @@
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D9C3E36819E48FF1009FC285"
|
||||
BuildableName = "StarscreamOSXTests.xctest"
|
||||
BlueprintName = "StarscreamOSXTests"
|
||||
BuildableName = "Starscream OSXTests.xctest"
|
||||
BlueprintName = "Starscream OSXTests"
|
||||
ReferencedContainer = "container:Starscream.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
buildConfiguration = "Debug">
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D9C3E36819E48FF1009FC285"
|
||||
BuildableName = "StarscreamOSXTests.xctest"
|
||||
BlueprintName = "StarscreamOSXTests"
|
||||
BuildableName = "Starscream OSXTests.xctest"
|
||||
BlueprintName = "Starscream OSXTests"
|
||||
ReferencedContainer = "container:Starscream.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
@@ -57,27 +57,30 @@
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D9C3E35E19E48FF1009FC285"
|
||||
BuildableName = "StarscreamOSX.framework"
|
||||
BlueprintName = "StarscreamOSX"
|
||||
BuildableName = "Starscream.framework"
|
||||
BlueprintName = "Starscream OSX"
|
||||
ReferencedContainer = "container:Starscream.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Debug"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D9C3E35E19E48FF1009FC285"
|
||||
BuildableName = "StarscreamOSX.framework"
|
||||
BlueprintName = "StarscreamOSX"
|
||||
BuildableName = "Starscream.framework"
|
||||
BlueprintName = "Starscream OSX"
|
||||
ReferencedContainer = "container:Starscream.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
@@ -85,17 +88,17 @@
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Release"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D9C3E35E19E48FF1009FC285"
|
||||
BuildableName = "StarscreamOSX.framework"
|
||||
BlueprintName = "StarscreamOSX"
|
||||
BuildableName = "Starscream.framework"
|
||||
BlueprintName = "Starscream OSX"
|
||||
ReferencedContainer = "container:Starscream.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0610"
|
||||
LastUpgradeVersion = "0810"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -15,26 +15,26 @@
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "6B3E79F019D48B7F006071F7"
|
||||
BuildableName = "StarscreamTests.xctest"
|
||||
BlueprintName = "StarscreamTests"
|
||||
BuildableName = "Starscream iOSTests.xctest"
|
||||
BlueprintName = "Starscream iOSTests"
|
||||
ReferencedContainer = "container:Starscream.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
buildConfiguration = "Debug">
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "6B3E79F019D48B7F006071F7"
|
||||
BuildableName = "StarscreamTests.xctest"
|
||||
BlueprintName = "StarscreamTests"
|
||||
BuildableName = "Starscream iOSTests.xctest"
|
||||
BlueprintName = "Starscream iOSTests"
|
||||
ReferencedContainer = "container:Starscream.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
@@ -43,27 +43,30 @@
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "6B3E79F019D48B7F006071F7"
|
||||
BuildableName = "StarscreamTests.xctest"
|
||||
BlueprintName = "StarscreamTests"
|
||||
BuildableName = "Starscream iOSTests.xctest"
|
||||
BlueprintName = "Starscream iOSTests"
|
||||
ReferencedContainer = "container:Starscream.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Debug"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "6B3E79F019D48B7F006071F7"
|
||||
BuildableName = "StarscreamTests.xctest"
|
||||
BlueprintName = "StarscreamTests"
|
||||
BuildableName = "Starscream iOSTests.xctest"
|
||||
BlueprintName = "Starscream iOSTests"
|
||||
ReferencedContainer = "container:Starscream.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
@@ -71,17 +74,17 @@
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Release"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "6B3E79F019D48B7F006071F7"
|
||||
BuildableName = "StarscreamTests.xctest"
|
||||
BlueprintName = "StarscreamTests"
|
||||
BuildableName = "Starscream iOSTests.xctest"
|
||||
BlueprintName = "Starscream iOSTests"
|
||||
ReferencedContainer = "container:Starscream.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0810"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "091277961BD673A70003036D"
|
||||
BuildableName = "Starscream.framework"
|
||||
BlueprintName = "Starscream tvOS"
|
||||
ReferencedContainer = "container:Starscream.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "NO"
|
||||
buildForArchiving = "NO"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0912779F1BD673A70003036D"
|
||||
BuildableName = "Starscream tvOSTests.xctest"
|
||||
BlueprintName = "Starscream tvOSTests"
|
||||
ReferencedContainer = "container:Starscream.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0912779F1BD673A70003036D"
|
||||
BuildableName = "Starscream tvOSTests.xctest"
|
||||
BlueprintName = "Starscream tvOSTests"
|
||||
ReferencedContainer = "container:Starscream.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "091277961BD673A70003036D"
|
||||
BuildableName = "Starscream.framework"
|
||||
BlueprintName = "Starscream tvOS"
|
||||
ReferencedContainer = "container:Starscream.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "091277961BD673A70003036D"
|
||||
BuildableName = "Starscream.framework"
|
||||
BlueprintName = "Starscream tvOS"
|
||||
ReferencedContainer = "container:Starscream.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "091277961BD673A70003036D"
|
||||
BuildableName = "Starscream.framework"
|
||||
BlueprintName = "Starscream tvOS"
|
||||
ReferencedContainer = "container:Starscream.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.vluxe.$(PRODUCT_NAME:rfc1034identifier)</string>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
|
||||
@@ -27,7 +27,7 @@ class StarscreamTests: XCTestCase {
|
||||
|
||||
func testPerformanceExample() {
|
||||
// This is an example of a performance test case.
|
||||
self.measureBlock() {
|
||||
self.measure() {
|
||||
// Put the code you want to measure the time of here.
|
||||
}
|
||||
}
|
||||
-687
@@ -1,687 +0,0 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Websocket.swift
|
||||
//
|
||||
// Created by Dalton Cherry on 7/16/14.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
import Foundation
|
||||
import CoreFoundation
|
||||
|
||||
public protocol WebSocketDelegate: class {
|
||||
func websocketDidConnect(socket: WebSocket)
|
||||
func websocketDidDisconnect(socket: WebSocket, error: NSError?)
|
||||
func websocketDidReceiveMessage(socket: WebSocket, text: String)
|
||||
func websocketDidReceiveData(socket: WebSocket, data: NSData)
|
||||
}
|
||||
|
||||
public class WebSocket : NSObject, NSStreamDelegate {
|
||||
|
||||
enum OpCode : UInt8 {
|
||||
case ContinueFrame = 0x0
|
||||
case TextFrame = 0x1
|
||||
case BinaryFrame = 0x2
|
||||
//3-7 are reserved.
|
||||
case ConnectionClose = 0x8
|
||||
case Ping = 0x9
|
||||
case Pong = 0xA
|
||||
//B-F reserved.
|
||||
}
|
||||
|
||||
enum CloseCode : UInt16 {
|
||||
case Normal = 1000
|
||||
case GoingAway = 1001
|
||||
case ProtocolError = 1002
|
||||
case ProtocolUnhandledType = 1003
|
||||
// 1004 reserved.
|
||||
case NoStatusReceived = 1005
|
||||
//1006 reserved.
|
||||
case Encoding = 1007
|
||||
case PolicyViolated = 1008
|
||||
case MessageTooBig = 1009
|
||||
}
|
||||
var optionalProtocols : Array<String>?
|
||||
//Constant Values.
|
||||
let headerWSUpgradeName = "Upgrade"
|
||||
let headerWSUpgradeValue = "websocket"
|
||||
let headerWSHostName = "Host"
|
||||
let headerWSConnectionName = "Connection"
|
||||
let headerWSConnectionValue = "Upgrade"
|
||||
let headerWSProtocolName = "Sec-WebSocket-Protocol"
|
||||
let headerWSVersionName = "Sec-WebSocket-Version"
|
||||
let headerWSVersionValue = "13"
|
||||
let headerWSKeyName = "Sec-WebSocket-Key"
|
||||
let headerOriginName = "Origin"
|
||||
let headerWSAcceptName = "Sec-WebSocket-Accept"
|
||||
let BUFFER_MAX = 2048
|
||||
let FinMask: UInt8 = 0x80
|
||||
let OpCodeMask: UInt8 = 0x0F
|
||||
let RSVMask: UInt8 = 0x70
|
||||
let MaskMask: UInt8 = 0x80
|
||||
let PayloadLenMask: UInt8 = 0x7F
|
||||
let MaxFrameSize: Int = 32
|
||||
|
||||
class WSResponse {
|
||||
var isFin = false
|
||||
var code: OpCode = .ContinueFrame
|
||||
var bytesLeft = 0
|
||||
var frameCount = 0
|
||||
var buffer: NSMutableData?
|
||||
}
|
||||
|
||||
public weak var delegate: WebSocketDelegate?
|
||||
private var url: NSURL
|
||||
private var inputStream: NSInputStream?
|
||||
private var outputStream: NSOutputStream?
|
||||
private var isRunLoop = false
|
||||
private var connected = false
|
||||
private var writeQueue: NSOperationQueue?
|
||||
private var readStack = Array<WSResponse>()
|
||||
private var inputQueue = Array<NSData>()
|
||||
private var fragBuffer: NSData?
|
||||
public var headers = Dictionary<String,String>()
|
||||
public var voipEnabled = false
|
||||
public var selfSignedSSL = false
|
||||
private var connectedBlock: ((Void) -> Void)? = nil
|
||||
private var disconnectedBlock: ((NSError?) -> Void)? = nil
|
||||
private var receivedTextBlock: ((String) -> Void)? = nil
|
||||
private var receivedDataBlock: ((NSData) -> Void)? = nil
|
||||
public var isConnected :Bool {
|
||||
return connected
|
||||
}
|
||||
|
||||
//init the websocket with a url
|
||||
public init(url: NSURL) {
|
||||
self.url = url
|
||||
}
|
||||
//used for setting protocols.
|
||||
public convenience init(url: NSURL, protocols: Array<String>) {
|
||||
self.init(url: url)
|
||||
optionalProtocols = protocols
|
||||
}
|
||||
//closure based instead of the delegate
|
||||
public convenience init(url: NSURL, protocols: Array<String>, connect:((Void) -> Void), disconnect:((NSError?) -> Void), text:((String) -> Void), data:(NSData) -> Void) {
|
||||
self.init(url: url, protocols: protocols)
|
||||
connectedBlock = connect
|
||||
disconnectedBlock = disconnect
|
||||
receivedTextBlock = text
|
||||
receivedDataBlock = data
|
||||
}
|
||||
//same as above, just shorter
|
||||
public convenience init(url: NSURL, connect:((Void) -> Void), disconnect:((NSError?) -> Void), text:((String) -> Void)) {
|
||||
self.init(url: url)
|
||||
connectedBlock = connect
|
||||
disconnectedBlock = disconnect
|
||||
receivedTextBlock = text
|
||||
}
|
||||
//same as above, just shorter
|
||||
public convenience init(url: NSURL, connect:((Void) -> Void), disconnect:((NSError?) -> Void), data:((NSData) -> Void)) {
|
||||
self.init(url: url)
|
||||
connectedBlock = connect
|
||||
disconnectedBlock = disconnect
|
||||
receivedDataBlock = data
|
||||
}
|
||||
|
||||
///Connect to the websocket server on a background thread
|
||||
public func connect() {
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), {
|
||||
self.createHTTPRequest()
|
||||
})
|
||||
}
|
||||
|
||||
///disconnect from the websocket server
|
||||
public func disconnect() {
|
||||
writeError(CloseCode.Normal.rawValue)
|
||||
}
|
||||
|
||||
///write a string to the websocket. This sends it as a text frame.
|
||||
public func writeString(str: String) {
|
||||
dequeueWrite(str.dataUsingEncoding(NSUTF8StringEncoding)!, code: .TextFrame)
|
||||
}
|
||||
|
||||
///write binary data to the websocket. This sends it as a binary frame.
|
||||
public func writeData(data: NSData) {
|
||||
dequeueWrite(data, code: .BinaryFrame)
|
||||
}
|
||||
//private methods below!
|
||||
|
||||
//private method that starts the connection
|
||||
private func createHTTPRequest() {
|
||||
|
||||
let str: NSString = url.absoluteString!
|
||||
let urlRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, "GET",
|
||||
url, kCFHTTPVersion1_1)
|
||||
|
||||
var port = url.port
|
||||
if port == nil {
|
||||
if url.scheme == "wss" || url.scheme == "https" {
|
||||
port = 443
|
||||
} else {
|
||||
port = 80
|
||||
}
|
||||
}
|
||||
self.addHeader(urlRequest, key: headerWSUpgradeName, val: headerWSUpgradeValue)
|
||||
self.addHeader(urlRequest, key: headerWSConnectionName, val: headerWSConnectionValue)
|
||||
if let protocols = optionalProtocols {
|
||||
self.addHeader(urlRequest, key: headerWSProtocolName, val: ",".join(protocols))
|
||||
}
|
||||
self.addHeader(urlRequest, key: headerWSVersionName, val: headerWSVersionValue)
|
||||
self.addHeader(urlRequest, key: headerWSKeyName, val: self.generateWebSocketKey())
|
||||
self.addHeader(urlRequest, key: headerOriginName, val: url.absoluteString!)
|
||||
self.addHeader(urlRequest, key: headerWSHostName, val: "\(url.host!):\(port!)")
|
||||
for (key,value) in headers {
|
||||
self.addHeader(urlRequest, key: key, val: value)
|
||||
}
|
||||
|
||||
let serializedRequest: NSData = CFHTTPMessageCopySerializedMessage(urlRequest.takeUnretainedValue()).takeUnretainedValue()
|
||||
self.initStreamsWithData(serializedRequest, Int(port!))
|
||||
}
|
||||
//Add a header to the CFHTTPMessage by using the NSString bridges to CFString
|
||||
private func addHeader(urlRequest: Unmanaged<CFHTTPMessage>,key: String, val: String) {
|
||||
let nsKey: NSString = key
|
||||
let nsVal: NSString = val
|
||||
CFHTTPMessageSetHeaderFieldValue(urlRequest.takeUnretainedValue(),
|
||||
nsKey,
|
||||
nsVal)
|
||||
}
|
||||
//generate a websocket key as needed in rfc
|
||||
private func generateWebSocketKey() -> String {
|
||||
var key = ""
|
||||
let seed = 16
|
||||
for (var i = 0; i < seed; i++) {
|
||||
let uni = UnicodeScalar(UInt32(97 + arc4random_uniform(25)))
|
||||
key += "\(Character(uni))"
|
||||
}
|
||||
var data = key.dataUsingEncoding(NSUTF8StringEncoding)
|
||||
var baseKey = data?.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(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
|
||||
//NSStream.getStreamsToHostWithName(url.host, port: url.port.integerValue, inputStream: &inputStream, outputStream: &outputStream)
|
||||
|
||||
var readStream: Unmanaged<CFReadStream>?
|
||||
var writeStream: Unmanaged<CFWriteStream>?
|
||||
let h: NSString = url.host!
|
||||
CFStreamCreatePairWithSocketToHost(nil, h, UInt32(port), &readStream, &writeStream)
|
||||
inputStream = readStream!.takeUnretainedValue()
|
||||
outputStream = writeStream!.takeUnretainedValue()
|
||||
|
||||
inputStream!.delegate = self
|
||||
outputStream!.delegate = self
|
||||
if url.scheme == "wss" || url.scheme == "https" {
|
||||
inputStream!.setProperty(NSStreamSocketSecurityLevelNegotiatedSSL, forKey: NSStreamSocketSecurityLevelKey)
|
||||
outputStream!.setProperty(NSStreamSocketSecurityLevelNegotiatedSSL, forKey: NSStreamSocketSecurityLevelKey)
|
||||
}
|
||||
if self.voipEnabled {
|
||||
inputStream!.setProperty(NSStreamNetworkServiceTypeVoIP, forKey: NSStreamNetworkServiceType)
|
||||
outputStream!.setProperty(NSStreamNetworkServiceTypeVoIP, forKey: NSStreamNetworkServiceType)
|
||||
}
|
||||
if self.selfSignedSSL {
|
||||
let settings: Dictionary<NSObject, NSObject> = [kCFStreamSSLValidatesCertificateChain: NSNumber(bool:false), kCFStreamSSLPeerName: kCFNull]
|
||||
inputStream!.setProperty(settings, forKey: kCFStreamPropertySSLSettings)
|
||||
outputStream!.setProperty(settings, forKey: kCFStreamPropertySSLSettings)
|
||||
}
|
||||
isRunLoop = true
|
||||
inputStream!.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
|
||||
outputStream!.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
|
||||
inputStream!.open()
|
||||
outputStream!.open()
|
||||
let bytes = UnsafePointer<UInt8>(data.bytes)
|
||||
outputStream!.write(bytes, maxLength: data.length)
|
||||
while(isRunLoop) {
|
||||
NSRunLoop.currentRunLoop().runMode(NSDefaultRunLoopMode, beforeDate: NSDate.distantFuture() as NSDate)
|
||||
}
|
||||
}
|
||||
//delegate for the stream methods. Processes incoming bytes
|
||||
func stream(aStream: NSStream!, handleEvent eventCode: NSStreamEvent) {
|
||||
|
||||
if eventCode == .HasBytesAvailable {
|
||||
if(aStream == inputStream) {
|
||||
processInputStream()
|
||||
}
|
||||
} else if eventCode == .ErrorOccurred {
|
||||
disconnectStream(aStream!.streamError)
|
||||
} else if eventCode == .EndEncountered {
|
||||
disconnectStream(nil)
|
||||
}
|
||||
}
|
||||
//disconnect the stream object
|
||||
private func disconnectStream(error: NSError?) {
|
||||
if writeQueue != nil {
|
||||
writeQueue!.waitUntilAllOperationsAreFinished()
|
||||
}
|
||||
inputStream!.removeFromRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
|
||||
outputStream!.removeFromRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
|
||||
inputStream!.close()
|
||||
outputStream!.close()
|
||||
inputStream = nil
|
||||
outputStream = nil
|
||||
isRunLoop = false
|
||||
connected = false
|
||||
dispatch_async(dispatch_get_main_queue(),{
|
||||
if let disconnectBlock = self.disconnectedBlock {
|
||||
disconnectBlock(error)
|
||||
}
|
||||
self.delegate?.websocketDidDisconnect(self, error: error)
|
||||
})
|
||||
}
|
||||
|
||||
///handles the incoming bytes and sending them to the proper processing method
|
||||
private func processInputStream() {
|
||||
let buf = NSMutableData(capacity: BUFFER_MAX)
|
||||
var buffer = UnsafeMutablePointer<UInt8>(buf!.bytes)
|
||||
let length = inputStream!.read(buffer, maxLength: BUFFER_MAX)
|
||||
if length > 0 {
|
||||
if !connected {
|
||||
connected = processHTTP(buffer, bufferLen: length)
|
||||
if !connected {
|
||||
dispatch_async(dispatch_get_main_queue(),{
|
||||
//self.workaroundMethod()
|
||||
let error = self.errorWithDetail("Invalid HTTP upgrade", code: 1)
|
||||
if let disconnect = self.disconnectedBlock {
|
||||
disconnect(error)
|
||||
}
|
||||
self.delegate?.websocketDidDisconnect(self, error: error)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
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) {
|
||||
var combine = NSMutableData(data: fragBuffer!)
|
||||
combine.appendData(data)
|
||||
work = combine
|
||||
fragBuffer = nil
|
||||
}
|
||||
let buffer = UnsafePointer<UInt8>(work.bytes)
|
||||
processRawMessage(buffer, bufferLen: work.length)
|
||||
inputQueue = inputQueue.filter{$0 != data}
|
||||
dequeueInput()
|
||||
}
|
||||
}
|
||||
///Finds the HTTP Packet in the TCP stream, by looking for the CRLF.
|
||||
private func processHTTP(buffer: UnsafePointer<UInt8>, bufferLen: Int) -> Bool {
|
||||
let CRLFBytes = [UInt8("\r"), UInt8("\n"), UInt8("\r"), UInt8("\n")]
|
||||
var k = 0
|
||||
var totalSize = 0
|
||||
for var i = 0; i < bufferLen; i++ {
|
||||
if buffer[i] == CRLFBytes[k] {
|
||||
k++
|
||||
if k == 3 {
|
||||
totalSize = i + 1
|
||||
break
|
||||
}
|
||||
} else {
|
||||
k = 0
|
||||
}
|
||||
}
|
||||
if totalSize > 0 {
|
||||
if validateResponse(buffer, bufferLen: totalSize) {
|
||||
dispatch_async(dispatch_get_main_queue(),{
|
||||
//self.workaroundMethod()
|
||||
if let connectBlock = self.connectedBlock {
|
||||
connectBlock()
|
||||
}
|
||||
self.delegate?.websocketDidConnect(self)
|
||||
})
|
||||
totalSize += 1 //skip the last \n
|
||||
let restSize = bufferLen - totalSize
|
||||
if restSize > 0 {
|
||||
processRawMessage((buffer+totalSize),bufferLen: restSize)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
///validates the HTTP is a 101 as per the RFC spec
|
||||
private func validateResponse(buffer: UnsafePointer<UInt8>, bufferLen: Int) -> Bool {
|
||||
let response = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, 0)
|
||||
CFHTTPMessageAppendBytes(response.takeUnretainedValue(), buffer, bufferLen)
|
||||
if CFHTTPMessageGetResponseStatusCode(response.takeUnretainedValue()) != 101 {
|
||||
return false
|
||||
}
|
||||
let cfHeaders = CFHTTPMessageCopyAllHeaderFields(response.takeUnretainedValue())
|
||||
let headers: NSDictionary = cfHeaders.takeUnretainedValue()
|
||||
let acceptKey = headers[headerWSAcceptName] as NSString
|
||||
if acceptKey.length > 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
///process the websocket data
|
||||
private func processRawMessage(buffer: UnsafePointer<UInt8>, bufferLen: Int) {
|
||||
var response = readStack.last
|
||||
if response != nil && bufferLen < 2 {
|
||||
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 {
|
||||
len = bufferLen
|
||||
extra = 0
|
||||
}
|
||||
resp.bytesLeft -= len
|
||||
resp.buffer?.appendData(NSData(bytes: buffer, length: len))
|
||||
processResponse(resp)
|
||||
var offset = bufferLen - extra
|
||||
if extra > 0 {
|
||||
processExtra((buffer+offset), bufferLen: extra)
|
||||
}
|
||||
return
|
||||
} else {
|
||||
let isFin = (FinMask & buffer[0])
|
||||
let receivedOpcode = (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) {
|
||||
let errCode = CloseCode.ProtocolError.rawValue
|
||||
let error = self.errorWithDetail("masked and rsv data is not currently supported", code: errCode)
|
||||
if let disconnect = self.disconnectedBlock {
|
||||
disconnect(error)
|
||||
}
|
||||
self.delegate?.websocketDidDisconnect(self, error: error)
|
||||
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 errCode = CloseCode.ProtocolError.rawValue
|
||||
let error = self.errorWithDetail("unknown opcode: \(receivedOpcode)", code: errCode)
|
||||
if let disconnect = self.disconnectedBlock {
|
||||
disconnect(error)
|
||||
}
|
||||
self.delegate?.websocketDidDisconnect(self, error: error)
|
||||
writeError(errCode)
|
||||
return
|
||||
}
|
||||
if isControlFrame && isFin == 0 {
|
||||
let errCode = CloseCode.ProtocolError.rawValue
|
||||
let error = self.errorWithDetail("control frames can't be fragmented", code: errCode)
|
||||
if let disconnect = self.disconnectedBlock {
|
||||
disconnect(error)
|
||||
}
|
||||
self.delegate?.websocketDidDisconnect(self, error: error)
|
||||
writeError(errCode)
|
||||
return
|
||||
}
|
||||
if receivedOpcode == OpCode.ConnectionClose.rawValue {
|
||||
var code = CloseCode.Normal.rawValue
|
||||
if payloadLen == 1 {
|
||||
code = CloseCode.ProtocolError.rawValue
|
||||
} else if payloadLen > 1 {
|
||||
var codeBuffer = UnsafePointer<UInt16>((buffer+offset))
|
||||
code = codeBuffer[0].byteSwapped
|
||||
if code < 1000 || (code > 1003 && code < 1007) || (code > 1011 && code < 3000) {
|
||||
code = CloseCode.ProtocolError.rawValue
|
||||
}
|
||||
offset += 2
|
||||
}
|
||||
if payloadLen > 2 {
|
||||
let len = Int(payloadLen-2)
|
||||
if len > 0 {
|
||||
let bytes = UnsafePointer<UInt8>((buffer+offset))
|
||||
var str: NSString? = NSString(data: NSData(bytes: bytes, length: len), encoding: NSUTF8StringEncoding)
|
||||
if str == nil {
|
||||
code = CloseCode.ProtocolError.rawValue
|
||||
}
|
||||
}
|
||||
}
|
||||
writeError(code)
|
||||
return
|
||||
}
|
||||
if isControlFrame && payloadLen > 125 {
|
||||
writeError(CloseCode.ProtocolError.rawValue)
|
||||
return
|
||||
}
|
||||
var dataLength = UInt64(payloadLen)
|
||||
if dataLength == 127 {
|
||||
let bytes = UnsafePointer<UInt64>((buffer+offset))
|
||||
dataLength = bytes[0].byteSwapped
|
||||
offset += sizeof(UInt64)
|
||||
} else if dataLength == 126 {
|
||||
let bytes = UnsafePointer<UInt16>((buffer+offset))
|
||||
dataLength = UInt64(bytes[0].byteSwapped)
|
||||
offset += sizeof(UInt16)
|
||||
}
|
||||
var len = dataLength
|
||||
if dataLength > UInt64(bufferLen) {
|
||||
len = UInt64(bufferLen-offset)
|
||||
}
|
||||
var data: NSData!
|
||||
if len < 0 {
|
||||
len = 0
|
||||
data = NSData()
|
||||
} else {
|
||||
data = NSData(bytes: UnsafePointer<UInt8>((buffer+offset)), length: Int(len))
|
||||
}
|
||||
if receivedOpcode == OpCode.Pong.rawValue {
|
||||
let step = Int(offset+len)
|
||||
let extra = bufferLen-step
|
||||
if extra > 0 {
|
||||
processRawMessage((buffer+step), bufferLen: extra)
|
||||
}
|
||||
return
|
||||
}
|
||||
var response = readStack.last
|
||||
if isControlFrame {
|
||||
response = nil //don't append pings
|
||||
}
|
||||
if isFin == 0 && receivedOpcode == OpCode.ContinueFrame.rawValue && response == nil {
|
||||
let errCode = CloseCode.ProtocolError.rawValue
|
||||
let error = self.errorWithDetail("continue frame before a binary or text frame", code: errCode)
|
||||
if let disconnect = self.disconnectedBlock {
|
||||
disconnect(error)
|
||||
}
|
||||
self.delegate?.websocketDidDisconnect(self, error: error)
|
||||
writeError(errCode)
|
||||
return
|
||||
}
|
||||
var isNew = false
|
||||
if(response == nil) {
|
||||
if receivedOpcode == OpCode.ContinueFrame.rawValue {
|
||||
let errCode = CloseCode.ProtocolError.rawValue
|
||||
let error = self.errorWithDetail("first frame can't be a continue frame",
|
||||
code: errCode)
|
||||
if let disconnect = self.disconnectedBlock {
|
||||
disconnect(error)
|
||||
}
|
||||
self.delegate?.websocketDidDisconnect(self, error: error)
|
||||
writeError(errCode)
|
||||
return
|
||||
}
|
||||
isNew = true
|
||||
response = WSResponse()
|
||||
response!.code = OpCode(rawValue: receivedOpcode)!
|
||||
response!.bytesLeft = Int(dataLength)
|
||||
response!.buffer = NSMutableData(data: data)
|
||||
} else {
|
||||
if receivedOpcode == OpCode.ContinueFrame.rawValue {
|
||||
response!.bytesLeft = Int(dataLength)
|
||||
} else {
|
||||
let errCode = CloseCode.ProtocolError.rawValue
|
||||
let error = self.errorWithDetail("second and beyond of fragment message must be a continue frame",
|
||||
code: errCode)
|
||||
if let disconnect = self.disconnectedBlock {
|
||||
disconnect(error)
|
||||
}
|
||||
self.delegate?.websocketDidDisconnect(self, error: error)
|
||||
writeError(errCode)
|
||||
return
|
||||
}
|
||||
response!.buffer!.appendData(data)
|
||||
}
|
||||
if response != nil {
|
||||
response!.bytesLeft -= Int(len)
|
||||
response!.frameCount++
|
||||
response!.isFin = isFin > 0 ? true : false
|
||||
if(isNew) {
|
||||
readStack.append(response!)
|
||||
}
|
||||
processResponse(response!)
|
||||
}
|
||||
|
||||
let step = Int(offset+len)
|
||||
let extra = bufferLen-step
|
||||
if(extra > 0) {
|
||||
processExtra((buffer+step), bufferLen: extra)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
///process the extra of a buffer
|
||||
private func processExtra(buffer: UnsafePointer<UInt8>, bufferLen: Int) {
|
||||
if bufferLen < 2 {
|
||||
fragBuffer = NSData(bytes: buffer, length: bufferLen)
|
||||
} else {
|
||||
processRawMessage(buffer, bufferLen: bufferLen)
|
||||
}
|
||||
}
|
||||
|
||||
///process the finished response of a buffer
|
||||
private func processResponse(response: WSResponse) -> Bool {
|
||||
if response.isFin && response.bytesLeft <= 0 {
|
||||
if response.code == .Ping {
|
||||
let data = response.buffer! //local copy so it is perverse for writing
|
||||
dequeueWrite(data, code: OpCode.Pong)
|
||||
} else if response.code == .TextFrame {
|
||||
var str: NSString? = NSString(data: response.buffer!, encoding: NSUTF8StringEncoding)
|
||||
if str == nil {
|
||||
writeError(CloseCode.Encoding.rawValue)
|
||||
return false
|
||||
}
|
||||
dispatch_async(dispatch_get_main_queue(),{
|
||||
if let textBlock = self.receivedTextBlock{
|
||||
textBlock(str!)
|
||||
}
|
||||
self.delegate?.websocketDidReceiveMessage(self, text: str!)
|
||||
})
|
||||
} else if response.code == .BinaryFrame {
|
||||
let data = response.buffer! //local copy so it is perverse for writing
|
||||
dispatch_async(dispatch_get_main_queue(),{
|
||||
//self.workaroundMethod()
|
||||
if let dataBlock = self.receivedDataBlock{
|
||||
dataBlock(data)
|
||||
}
|
||||
self.delegate?.websocketDidReceiveData(self, data: data)
|
||||
})
|
||||
}
|
||||
readStack.removeLast()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
///Create an error
|
||||
private func errorWithDetail(detail: String, code: UInt16) -> NSError {
|
||||
var details = Dictionary<String,String>()
|
||||
details[NSLocalizedDescriptionKey] = detail
|
||||
return NSError(domain: "Websocket", code: Int(code), userInfo: details)
|
||||
}
|
||||
|
||||
///write a an error to the socket
|
||||
private func writeError(code: UInt16) {
|
||||
let buf = NSMutableData(capacity: sizeof(UInt16))
|
||||
var buffer = UnsafeMutablePointer<UInt16>(buf!.bytes)
|
||||
buffer[0] = code.byteSwapped
|
||||
dequeueWrite(NSData(bytes: buffer, length: sizeof(UInt16)), code: .ConnectionClose)
|
||||
}
|
||||
///used to write things to the stream in a
|
||||
private func dequeueWrite(data: NSData, code: OpCode) {
|
||||
if writeQueue == nil {
|
||||
writeQueue = NSOperationQueue()
|
||||
writeQueue!.maxConcurrentOperationCount = 1
|
||||
}
|
||||
writeQueue!.addOperationWithBlock {
|
||||
//stream isn't ready, let's wait
|
||||
var tries = 0;
|
||||
while self.outputStream == nil || !self.connected {
|
||||
if(tries < 5) {
|
||||
sleep(1);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
tries++;
|
||||
}
|
||||
if !self.connected {
|
||||
return
|
||||
}
|
||||
var offset = 2
|
||||
UINT16_MAX
|
||||
let bytes = UnsafeMutablePointer<UInt8>(data.bytes)
|
||||
let dataLength = data.length
|
||||
let frame = NSMutableData(capacity: dataLength + self.MaxFrameSize)
|
||||
let buffer = UnsafeMutablePointer<UInt8>(frame!.mutableBytes)
|
||||
buffer[0] = self.FinMask | code.rawValue
|
||||
if dataLength < 126 {
|
||||
buffer[1] = CUnsignedChar(dataLength)
|
||||
} else if dataLength <= Int(UInt16.max) {
|
||||
buffer[1] = 126
|
||||
var sizeBuffer = UnsafeMutablePointer<UInt16>((buffer+offset))
|
||||
sizeBuffer[0] = UInt16(dataLength).byteSwapped
|
||||
offset += sizeof(UInt16)
|
||||
} else {
|
||||
buffer[1] = 127
|
||||
var sizeBuffer = UnsafeMutablePointer<UInt64>((buffer+offset))
|
||||
sizeBuffer[0] = UInt64(dataLength).byteSwapped
|
||||
offset += sizeof(UInt64)
|
||||
}
|
||||
buffer[1] |= self.MaskMask
|
||||
var maskKey = UnsafeMutablePointer<UInt8>(buffer + offset)
|
||||
SecRandomCopyBytes(kSecRandomDefault, UInt(sizeof(UInt32)), maskKey)
|
||||
offset += sizeof(UInt32)
|
||||
|
||||
for (var i = 0; i < dataLength; i++) {
|
||||
buffer[offset] = bytes[i] ^ maskKey[i % sizeof(UInt32)]
|
||||
offset += 1
|
||||
}
|
||||
var total = 0
|
||||
while true {
|
||||
if self.outputStream == nil {
|
||||
break
|
||||
}
|
||||
let writeBuffer = UnsafePointer<UInt8>(frame!.bytes+total)
|
||||
var len = self.outputStream!.write(writeBuffer, maxLength: offset-total)
|
||||
if len < 0 {
|
||||
if let disconnect = self.disconnectedBlock {
|
||||
disconnect(self.outputStream!.streamError!)
|
||||
}
|
||||
self.delegate?.websocketDidDisconnect(self, error: self.outputStream!.streamError)
|
||||
break
|
||||
} else {
|
||||
total += len
|
||||
}
|
||||
if total >= offset {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
# CocoaPods
|
||||
#
|
||||
# We recommend against adding the Pods directory to your .gitignore. However
|
||||
# you should judge for yourself, the pros and cons are mentioned at:
|
||||
# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control?
|
||||
#
|
||||
# Pods/
|
||||
|
||||
# Xcode
|
||||
.DS_Store
|
||||
build
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
*.mode1v3
|
||||
!default.mode1v3
|
||||
*.mode2v3
|
||||
!default.mode2v3
|
||||
*.perspectivev3
|
||||
!default.perspectivev3
|
||||
xcuserdata
|
||||
profile
|
||||
*.moved-aside
|
||||
DerivedData
|
||||
.idea/
|
||||
*.hmap
|
||||
*.xccheckout
|
||||
*.xcodeproj/*.xcworkspace
|
||||
@@ -0,0 +1,559 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
5C178E221B62D0B900A97204 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C178E211B62D0B900A97204 /* AppDelegate.swift */; };
|
||||
5C178E241B62D0B900A97204 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C178E231B62D0B900A97204 /* ViewController.swift */; };
|
||||
5C178E271B62D0B900A97204 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5C178E251B62D0B900A97204 /* Main.storyboard */; };
|
||||
5C178E291B62D0B900A97204 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5C178E281B62D0B900A97204 /* Images.xcassets */; };
|
||||
5C178E2C1B62D0B900A97204 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5C178E2A1B62D0B900A97204 /* LaunchScreen.xib */; };
|
||||
5C178E381B62D0B900A97204 /* AutobahnTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C178E371B62D0B900A97204 /* AutobahnTests.swift */; };
|
||||
5C178E521B62D11200A97204 /* Starscream.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C178E491B62D0EF00A97204 /* Starscream.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
5C178E321B62D0B900A97204 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 5C178E141B62D0B900A97204 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 5C178E1B1B62D0B900A97204;
|
||||
remoteInfo = Autobahn;
|
||||
};
|
||||
5C178E481B62D0EF00A97204 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 5C178E411B62D0EF00A97204 /* Starscream.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 6B3E79E619D48B7F006071F7;
|
||||
remoteInfo = Starscream;
|
||||
};
|
||||
5C178E4A1B62D0EF00A97204 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 5C178E411B62D0EF00A97204 /* Starscream.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 6B3E79F119D48B7F006071F7;
|
||||
remoteInfo = StarscreamTests;
|
||||
};
|
||||
5C178E4C1B62D0EF00A97204 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 5C178E411B62D0EF00A97204 /* Starscream.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = D9C3E35F19E48FF1009FC285;
|
||||
remoteInfo = StarscreamOSX;
|
||||
};
|
||||
5C178E4E1B62D0EF00A97204 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 5C178E411B62D0EF00A97204 /* Starscream.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = D9C3E36919E48FF1009FC285;
|
||||
remoteInfo = StarscreamOSXTests;
|
||||
};
|
||||
5C178E501B62D10A00A97204 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 5C178E411B62D0EF00A97204 /* Starscream.xcodeproj */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 6B3E79E519D48B7F006071F7;
|
||||
remoteInfo = Starscream;
|
||||
};
|
||||
5C42C3D51D8DF51C00947AA2 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 5C178E411B62D0EF00A97204 /* Starscream.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 091277971BD673A70003036D;
|
||||
remoteInfo = "Starscream tvOS";
|
||||
};
|
||||
5C42C3D71D8DF51C00947AA2 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 5C178E411B62D0EF00A97204 /* Starscream.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 091277A01BD673A70003036D;
|
||||
remoteInfo = "Starscream tvOSTests";
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
5C178E1C1B62D0B900A97204 /* Autobahn.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Autobahn.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
5C178E201B62D0B900A97204 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
5C178E211B62D0B900A97204 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
5C178E231B62D0B900A97204 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
||||
5C178E261B62D0B900A97204 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
5C178E281B62D0B900A97204 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
||||
5C178E2B1B62D0B900A97204 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
|
||||
5C178E311B62D0B900A97204 /* AutobahnTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AutobahnTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
5C178E361B62D0B900A97204 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
5C178E371B62D0B900A97204 /* AutobahnTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutobahnTests.swift; sourceTree = "<group>"; };
|
||||
5C178E411B62D0EF00A97204 /* Starscream.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Starscream.xcodeproj; path = ../../Starscream.xcodeproj; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
5C178E191B62D0B900A97204 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5C178E521B62D11200A97204 /* Starscream.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
5C178E2E1B62D0B900A97204 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
5C178E131B62D0B900A97204 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5C178E1E1B62D0B900A97204 /* Autobahn */,
|
||||
5C178E341B62D0B900A97204 /* AutobahnTests */,
|
||||
5C178E1D1B62D0B900A97204 /* Products */,
|
||||
5C178E411B62D0EF00A97204 /* Starscream.xcodeproj */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5C178E1D1B62D0B900A97204 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5C178E1C1B62D0B900A97204 /* Autobahn.app */,
|
||||
5C178E311B62D0B900A97204 /* AutobahnTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5C178E1E1B62D0B900A97204 /* Autobahn */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5C178E211B62D0B900A97204 /* AppDelegate.swift */,
|
||||
5C178E231B62D0B900A97204 /* ViewController.swift */,
|
||||
5C178E251B62D0B900A97204 /* Main.storyboard */,
|
||||
5C178E281B62D0B900A97204 /* Images.xcassets */,
|
||||
5C178E2A1B62D0B900A97204 /* LaunchScreen.xib */,
|
||||
5C178E1F1B62D0B900A97204 /* Supporting Files */,
|
||||
);
|
||||
path = Autobahn;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5C178E1F1B62D0B900A97204 /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5C178E201B62D0B900A97204 /* Info.plist */,
|
||||
);
|
||||
name = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5C178E341B62D0B900A97204 /* AutobahnTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5C178E371B62D0B900A97204 /* AutobahnTests.swift */,
|
||||
5C178E351B62D0B900A97204 /* Supporting Files */,
|
||||
);
|
||||
path = AutobahnTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5C178E351B62D0B900A97204 /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5C178E361B62D0B900A97204 /* Info.plist */,
|
||||
);
|
||||
name = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5C178E421B62D0EF00A97204 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5C178E491B62D0EF00A97204 /* Starscream.framework */,
|
||||
5C178E4B1B62D0EF00A97204 /* StarscreamTests.xctest */,
|
||||
5C178E4D1B62D0EF00A97204 /* Starscream.framework */,
|
||||
5C178E4F1B62D0EF00A97204 /* StarscreamOSXTests.xctest */,
|
||||
5C42C3D61D8DF51C00947AA2 /* Starscream.framework */,
|
||||
5C42C3D81D8DF51C00947AA2 /* Starscream tvOSTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
5C178E1B1B62D0B900A97204 /* Autobahn */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 5C178E3B1B62D0B900A97204 /* Build configuration list for PBXNativeTarget "Autobahn" */;
|
||||
buildPhases = (
|
||||
5C178E181B62D0B900A97204 /* Sources */,
|
||||
5C178E191B62D0B900A97204 /* Frameworks */,
|
||||
5C178E1A1B62D0B900A97204 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
5C178E511B62D10A00A97204 /* PBXTargetDependency */,
|
||||
);
|
||||
name = Autobahn;
|
||||
productName = Autobahn;
|
||||
productReference = 5C178E1C1B62D0B900A97204 /* Autobahn.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
5C178E301B62D0B900A97204 /* AutobahnTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 5C178E3E1B62D0B900A97204 /* Build configuration list for PBXNativeTarget "AutobahnTests" */;
|
||||
buildPhases = (
|
||||
5C178E2D1B62D0B900A97204 /* Sources */,
|
||||
5C178E2E1B62D0B900A97204 /* Frameworks */,
|
||||
5C178E2F1B62D0B900A97204 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
5C178E331B62D0B900A97204 /* PBXTargetDependency */,
|
||||
);
|
||||
name = AutobahnTests;
|
||||
productName = AutobahnTests;
|
||||
productReference = 5C178E311B62D0B900A97204 /* AutobahnTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
5C178E141B62D0B900A97204 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftMigration = 0700;
|
||||
LastSwiftUpdateCheck = 0700;
|
||||
LastUpgradeCheck = 0640;
|
||||
ORGANIZATIONNAME = vluxe;
|
||||
TargetAttributes = {
|
||||
5C178E1B1B62D0B900A97204 = {
|
||||
CreatedOnToolsVersion = 6.4;
|
||||
LastSwiftMigration = 0800;
|
||||
};
|
||||
5C178E301B62D0B900A97204 = {
|
||||
CreatedOnToolsVersion = 6.4;
|
||||
LastSwiftMigration = 0800;
|
||||
TestTargetID = 5C178E1B1B62D0B900A97204;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 5C178E171B62D0B900A97204 /* Build configuration list for PBXProject "Autobahn" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 5C178E131B62D0B900A97204;
|
||||
productRefGroup = 5C178E1D1B62D0B900A97204 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectReferences = (
|
||||
{
|
||||
ProductGroup = 5C178E421B62D0EF00A97204 /* Products */;
|
||||
ProjectRef = 5C178E411B62D0EF00A97204 /* Starscream.xcodeproj */;
|
||||
},
|
||||
);
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
5C178E1B1B62D0B900A97204 /* Autobahn */,
|
||||
5C178E301B62D0B900A97204 /* AutobahnTests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXReferenceProxy section */
|
||||
5C178E491B62D0EF00A97204 /* Starscream.framework */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.framework;
|
||||
path = Starscream.framework;
|
||||
remoteRef = 5C178E481B62D0EF00A97204 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
5C178E4B1B62D0EF00A97204 /* StarscreamTests.xctest */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.cfbundle;
|
||||
path = "Starscream iOSTests.xctest";
|
||||
remoteRef = 5C178E4A1B62D0EF00A97204 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
5C178E4D1B62D0EF00A97204 /* Starscream.framework */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.framework;
|
||||
path = Starscream.framework;
|
||||
remoteRef = 5C178E4C1B62D0EF00A97204 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
5C178E4F1B62D0EF00A97204 /* StarscreamOSXTests.xctest */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.cfbundle;
|
||||
path = "Starscream OSXTests.xctest";
|
||||
remoteRef = 5C178E4E1B62D0EF00A97204 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
5C42C3D61D8DF51C00947AA2 /* Starscream.framework */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.framework;
|
||||
path = Starscream.framework;
|
||||
remoteRef = 5C42C3D51D8DF51C00947AA2 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
5C42C3D81D8DF51C00947AA2 /* Starscream tvOSTests.xctest */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.cfbundle;
|
||||
path = "Starscream tvOSTests.xctest";
|
||||
remoteRef = 5C42C3D71D8DF51C00947AA2 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
/* End PBXReferenceProxy section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
5C178E1A1B62D0B900A97204 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5C178E271B62D0B900A97204 /* Main.storyboard in Resources */,
|
||||
5C178E2C1B62D0B900A97204 /* LaunchScreen.xib in Resources */,
|
||||
5C178E291B62D0B900A97204 /* Images.xcassets in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
5C178E2F1B62D0B900A97204 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
5C178E181B62D0B900A97204 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5C178E241B62D0B900A97204 /* ViewController.swift in Sources */,
|
||||
5C178E221B62D0B900A97204 /* AppDelegate.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
5C178E2D1B62D0B900A97204 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5C178E381B62D0B900A97204 /* AutobahnTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
5C178E331B62D0B900A97204 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 5C178E1B1B62D0B900A97204 /* Autobahn */;
|
||||
targetProxy = 5C178E321B62D0B900A97204 /* PBXContainerItemProxy */;
|
||||
};
|
||||
5C178E511B62D10A00A97204 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
name = Starscream;
|
||||
targetProxy = 5C178E501B62D10A00A97204 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
5C178E251B62D0B900A97204 /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
5C178E261B62D0B900A97204 /* Base */,
|
||||
);
|
||||
name = Main.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5C178E2A1B62D0B900A97204 /* LaunchScreen.xib */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
5C178E2B1B62D0B900A97204 /* Base */,
|
||||
);
|
||||
name = LaunchScreen.xib;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
5C178E391B62D0B900A97204 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.4;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
5C178E3A1B62D0B900A97204 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.4;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
5C178E3C1B62D0B900A97204 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
INFOPLIST_FILE = Autobahn/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
5C178E3D1B62D0B900A97204 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
INFOPLIST_FILE = Autobahn/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
5C178E3F1B62D0B900A97204 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
INFOPLIST_FILE = AutobahnTests/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 3.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Autobahn.app/Autobahn";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
5C178E401B62D0B900A97204 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(inherited)",
|
||||
);
|
||||
INFOPLIST_FILE = AutobahnTests/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 3.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Autobahn.app/Autobahn";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
5C178E171B62D0B900A97204 /* Build configuration list for PBXProject "Autobahn" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
5C178E391B62D0B900A97204 /* Debug */,
|
||||
5C178E3A1B62D0B900A97204 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
5C178E3B1B62D0B900A97204 /* Build configuration list for PBXNativeTarget "Autobahn" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
5C178E3C1B62D0B900A97204 /* Debug */,
|
||||
5C178E3D1B62D0B900A97204 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
5C178E3E1B62D0B900A97204 /* Build configuration list for PBXNativeTarget "AutobahnTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
5C178E3F1B62D0B900A97204 /* Debug */,
|
||||
5C178E401B62D0B900A97204 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 5C178E141B62D0B900A97204 /* Project object */;
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:Autobahn.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// AppDelegate.swift
|
||||
// Autobahn
|
||||
//
|
||||
// Created by Dalton Cherry on 7/24/15.
|
||||
// Copyright (c) 2015 vluxe. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
|
||||
// Override point for customization after application launch.
|
||||
return true
|
||||
}
|
||||
|
||||
func applicationWillResignActive(_ application: UIApplication) {
|
||||
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
|
||||
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
|
||||
}
|
||||
|
||||
func applicationDidEnterBackground(_ application: UIApplication) {
|
||||
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
|
||||
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
|
||||
}
|
||||
|
||||
func applicationWillEnterForeground(_ application: UIApplication) {
|
||||
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
|
||||
}
|
||||
|
||||
func applicationDidBecomeActive(_ application: UIApplication) {
|
||||
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
|
||||
}
|
||||
|
||||
func applicationWillTerminate(_ application: UIApplication) {
|
||||
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6214" systemVersion="14A314h" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6207"/>
|
||||
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="iN0-l3-epB">
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2015 vluxe. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
|
||||
<rect key="frame" x="20" y="439" width="441" height="21"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Autobahn" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
|
||||
<rect key="frame" x="20" y="140" width="441" height="43"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
|
||||
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
|
||||
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
|
||||
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
|
||||
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
|
||||
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
|
||||
</constraints>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<point key="canvasLocation" x="548" y="455"/>
|
||||
</view>
|
||||
</objects>
|
||||
</document>
|
||||
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<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>
|
||||
<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" customModule="Autobahn" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "2x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?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>com.vluxe.$(PRODUCT_NAME:rfc1034identifier)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,158 @@
|
||||
//
|
||||
// ViewController.swift
|
||||
// Autobahn
|
||||
//
|
||||
// Created by Dalton Cherry on 7/24/15.
|
||||
// Copyright (c) 2015 vluxe. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Starscream
|
||||
|
||||
class ViewController: UIViewController {
|
||||
|
||||
let host = "localhost:9001"
|
||||
var socketArray = [WebSocket]()
|
||||
var caseCount = 300 //starting cases
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
getCaseCount()
|
||||
//getTestInfo(1)
|
||||
}
|
||||
|
||||
func removeSocket(_ s: WebSocket) {
|
||||
socketArray = socketArray.filter{$0 != s}
|
||||
}
|
||||
|
||||
func getCaseCount() {
|
||||
|
||||
let s = WebSocket(url: URL(string: "ws://\(host)/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
|
||||
}
|
||||
}
|
||||
s.onDisconnect = {[unowned self] (error: NSError?) in
|
||||
self.getTestInfo(1)
|
||||
self.removeSocket(s)
|
||||
}
|
||||
s.connect()
|
||||
}
|
||||
|
||||
func getTestInfo(_ caseNum: Int) {
|
||||
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!,
|
||||
// options: NSJSONReadingOptions())
|
||||
// if let dict = resp as? Dictionary<String,String> {
|
||||
// let num = dict["id"]
|
||||
// let summary = dict["description"]
|
||||
// if let n = num, let sum = summary {
|
||||
// print("running case:\(caseNum) id:\(n) summary: \(sum)")
|
||||
// }
|
||||
// }
|
||||
// } catch {
|
||||
// print("error parsing the json")
|
||||
// }
|
||||
|
||||
}
|
||||
var once = false
|
||||
s.onDisconnect = {[unowned self] (error: NSError?) in
|
||||
if !once {
|
||||
once = true
|
||||
self.runTest(caseNum)
|
||||
}
|
||||
self.removeSocket(s)
|
||||
}
|
||||
s.connect()
|
||||
}
|
||||
|
||||
func runTest(_ caseNum: Int) {
|
||||
let s = createSocket("runCase",caseNum)
|
||||
self.socketArray.append(s)
|
||||
s.onText = {(text: String) in
|
||||
s.write(string: text)
|
||||
}
|
||||
s.onData = {(data: Data) in
|
||||
s.write(data: data)
|
||||
}
|
||||
var once = false
|
||||
s.onDisconnect = {[unowned self] (error: NSError?) in
|
||||
if !once {
|
||||
once = true
|
||||
print("case:\(caseNum) finished")
|
||||
self.verifyTest(caseNum)
|
||||
self.removeSocket(s)
|
||||
}
|
||||
}
|
||||
s.connect()
|
||||
}
|
||||
|
||||
func verifyTest(_ caseNum: Int) {
|
||||
let s = createSocket("getCaseStatus",caseNum)
|
||||
self.socketArray.append(s)
|
||||
s.onText = {(text: String) in
|
||||
let data = text.data(using: String.Encoding.utf8)
|
||||
do {
|
||||
let resp: Any? = try JSONSerialization.jsonObject(with: data!,
|
||||
options: JSONSerialization.ReadingOptions())
|
||||
if let dict = resp as? Dictionary<String,String> {
|
||||
if let status = dict["behavior"] {
|
||||
if status == "OK" {
|
||||
print("SUCCESS: \(caseNum)")
|
||||
return
|
||||
}
|
||||
}
|
||||
print("FAILURE: \(caseNum)")
|
||||
}
|
||||
} catch {
|
||||
print("error parsing the json")
|
||||
}
|
||||
}
|
||||
var once = false
|
||||
s.onDisconnect = {[unowned self] (error: NSError?) in
|
||||
if !once {
|
||||
once = true
|
||||
let nextCase = caseNum+1
|
||||
if nextCase <= self.caseCount {
|
||||
self.getTestInfo(nextCase)
|
||||
} else {
|
||||
self.finishReports()
|
||||
}
|
||||
}
|
||||
self.removeSocket(s)
|
||||
}
|
||||
s.connect()
|
||||
}
|
||||
|
||||
func finishReports() {
|
||||
let s = createSocket("updateReports",0)
|
||||
self.socketArray.append(s)
|
||||
s.onDisconnect = {[unowned self] (error: NSError?) in
|
||||
print("finished all the tests!")
|
||||
self.removeSocket(s)
|
||||
}
|
||||
s.connect()
|
||||
}
|
||||
|
||||
func createSocket(_ cmd: String, _ caseNum: Int) -> WebSocket {
|
||||
return WebSocket(url: URL(string: "ws://\(host)\(buildPath(cmd,caseNum))")!, protocols: [])
|
||||
}
|
||||
|
||||
func buildPath(_ cmd: String, _ caseNum: Int) -> String {
|
||||
return "/\(cmd)?case=\(caseNum)&agent=Starscream"
|
||||
}
|
||||
|
||||
override func didReceiveMemoryWarning() {
|
||||
super.didReceiveMemoryWarning()
|
||||
// Dispose of any resources that can be recreated.
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// AutobahnTests.swift
|
||||
// AutobahnTests
|
||||
//
|
||||
// Created by Dalton Cherry on 7/24/15.
|
||||
// Copyright (c) 2015 vluxe. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import XCTest
|
||||
|
||||
class AutobahnTests: XCTestCase {
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testExample() {
|
||||
// This is an example of a functional test case.
|
||||
XCTAssert(true, "Pass")
|
||||
}
|
||||
|
||||
func testPerformanceExample() {
|
||||
// This is an example of a performance test case.
|
||||
self.measure() {
|
||||
// Put the code you want to measure the time of here.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?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>com.vluxe.$(PRODUCT_NAME:rfc1034identifier)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,27 @@
|
||||
# CocoaPods
|
||||
#
|
||||
# We recommend against adding the Pods directory to your .gitignore. However
|
||||
# you should judge for yourself, the pros and cons are mentioned at:
|
||||
# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control?
|
||||
#
|
||||
# Pods/
|
||||
|
||||
# Xcode
|
||||
.DS_Store
|
||||
build
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
*.mode1v3
|
||||
!default.mode1v3
|
||||
*.mode2v3
|
||||
!default.mode2v3
|
||||
*.perspectivev3
|
||||
!default.perspectivev3
|
||||
xcuserdata
|
||||
profile
|
||||
*.moved-aside
|
||||
DerivedData
|
||||
.idea/
|
||||
*.hmap
|
||||
*.xccheckout
|
||||
*.xcodeproj/*.xcworkspace
|
||||
@@ -16,6 +16,41 @@
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
5C06AE841B08044600D41060 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 6B3E7A0819D48D00006071F7 /* Starscream.xcodeproj */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 6B3E79E519D48B7F006071F7;
|
||||
remoteInfo = Starscream;
|
||||
};
|
||||
5C06AE8A1B08044600D41060 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 6B3E7A0819D48D00006071F7 /* Starscream.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = D9C3E35F19E48FF1009FC285;
|
||||
remoteInfo = StarscreamOSX;
|
||||
};
|
||||
5C06AE8C1B08044600D41060 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 6B3E7A0819D48D00006071F7 /* Starscream.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = D9C3E36919E48FF1009FC285;
|
||||
remoteInfo = StarscreamOSXTests;
|
||||
};
|
||||
5C42C3E01D8F31DC00947AA2 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 6B3E7A0819D48D00006071F7 /* Starscream.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 091277971BD673A70003036D;
|
||||
remoteInfo = "Starscream tvOS";
|
||||
};
|
||||
5C42C3E21D8F31DC00947AA2 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 6B3E7A0819D48D00006071F7 /* Starscream.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 091277A01BD673A70003036D;
|
||||
remoteInfo = "Starscream tvOSTests";
|
||||
};
|
||||
6B3E7A0D19D48D00006071F7 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 6B3E7A0819D48D00006071F7 /* Starscream.xcodeproj */;
|
||||
@@ -108,7 +143,11 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6B3E7A0E19D48D00006071F7 /* Starscream.framework */,
|
||||
6B3E7A1019D48D00006071F7 /* StarscreamTests.xctest */,
|
||||
6B3E7A1019D48D00006071F7 /* Starscream iOSTests.xctest */,
|
||||
5C06AE8B1B08044600D41060 /* Starscream.framework */,
|
||||
5C06AE8D1B08044600D41060 /* StarscreamOSXTests.xctest */,
|
||||
5C42C3E11D8F31DC00947AA2 /* Starscream.framework */,
|
||||
5C42C3E31D8F31DC00947AA2 /* Starscream tvOSTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -128,6 +167,7 @@
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
5C06AE851B08044600D41060 /* PBXTargetDependency */,
|
||||
);
|
||||
name = SimpleTest;
|
||||
productName = SimpleTest;
|
||||
@@ -140,11 +180,13 @@
|
||||
5C765AD3199A6DAA003D9110 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0600;
|
||||
LastSwiftUpdateCheck = 0700;
|
||||
LastUpgradeCheck = 0800;
|
||||
ORGANIZATIONNAME = vluxe;
|
||||
TargetAttributes = {
|
||||
5C765ADA199A6DAA003D9110 = {
|
||||
CreatedOnToolsVersion = 6.0;
|
||||
LastSwiftMigration = 0800;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -173,6 +215,34 @@
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXReferenceProxy section */
|
||||
5C06AE8B1B08044600D41060 /* Starscream.framework */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.framework;
|
||||
path = Starscream.framework;
|
||||
remoteRef = 5C06AE8A1B08044600D41060 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
5C06AE8D1B08044600D41060 /* Starscream OSXTests.xctest */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.cfbundle;
|
||||
path = "Starscream OSXTests.xctest";
|
||||
remoteRef = 5C06AE8C1B08044600D41060 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
5C42C3E11D8F31DC00947AA2 /* Starscream.framework */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.framework;
|
||||
path = Starscream.framework;
|
||||
remoteRef = 5C42C3E01D8F31DC00947AA2 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
5C42C3E31D8F31DC00947AA2 /* Starscream tvOSTests.xctest */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.cfbundle;
|
||||
path = "Starscream tvOSTests.xctest";
|
||||
remoteRef = 5C42C3E21D8F31DC00947AA2 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
6B3E7A0E19D48D00006071F7 /* Starscream.framework */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.framework;
|
||||
@@ -180,10 +250,10 @@
|
||||
remoteRef = 6B3E7A0D19D48D00006071F7 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
6B3E7A1019D48D00006071F7 /* StarscreamTests.xctest */ = {
|
||||
6B3E7A1019D48D00006071F7 /* Starscream iOSTests.xctest */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.cfbundle;
|
||||
path = StarscreamTests.xctest;
|
||||
path = "Starscream iOSTests.xctest";
|
||||
remoteRef = 6B3E7A0F19D48D00006071F7 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
@@ -213,6 +283,14 @@
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
5C06AE851B08044600D41060 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
name = Starscream;
|
||||
targetProxy = 5C06AE841B08044600D41060 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
5C765AE4199A6DAA003D9110 /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
@@ -238,15 +316,19 @@
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
@@ -281,8 +363,10 @@
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
@@ -290,6 +374,7 @@
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
@@ -299,6 +384,7 @@
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
@@ -311,7 +397,9 @@
|
||||
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
|
||||
INFOPLIST_FILE = SimpleTest/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.vluxe.io.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -322,7 +410,9 @@
|
||||
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
|
||||
INFOPLIST_FILE = SimpleTest/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.vluxe.io.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
||||
+3
-3
@@ -11,7 +11,7 @@
|
||||
<key>IDESourceControlProjectOriginsDictionary</key>
|
||||
<dict>
|
||||
<key>C86D95FCAEB1FEA0694B5D4AC7241D7E5F42F31D</key>
|
||||
<string>https://github.com/daltoniam/starscream.git</string>
|
||||
<string>https://github.com/daltoniam/Starscream</string>
|
||||
</dict>
|
||||
<key>IDESourceControlProjectPath</key>
|
||||
<string>examples/SimpleTest/SimpleTest.xcodeproj</string>
|
||||
@@ -21,7 +21,7 @@
|
||||
<string>../../../..</string>
|
||||
</dict>
|
||||
<key>IDESourceControlProjectURL</key>
|
||||
<string>https://github.com/daltoniam/starscream.git</string>
|
||||
<string>https://github.com/daltoniam/Starscream</string>
|
||||
<key>IDESourceControlProjectVersion</key>
|
||||
<integer>111</integer>
|
||||
<key>IDESourceControlProjectWCCIdentifier</key>
|
||||
@@ -34,7 +34,7 @@
|
||||
<key>IDESourceControlWCCIdentifierKey</key>
|
||||
<string>C86D95FCAEB1FEA0694B5D4AC7241D7E5F42F31D</string>
|
||||
<key>IDESourceControlWCCName</key>
|
||||
<string>starscream</string>
|
||||
<string>Starscream</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
|
||||
BIN
Binary file not shown.
+19
-7
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0600"
|
||||
LastUpgradeVersion = "0800"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -37,10 +37,10 @@
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
buildConfiguration = "Debug">
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
@@ -62,17 +62,21 @@
|
||||
ReferencedContainer = "container:SimpleTest.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Debug"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable>
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "5C765ADA199A6DAA003D9110"
|
||||
@@ -81,16 +85,24 @@
|
||||
ReferencedContainer = "container:SimpleTest.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<EnvironmentVariables>
|
||||
<EnvironmentVariable
|
||||
key = "OS_ACTIVITY_MODE"
|
||||
value = "disable"
|
||||
isEnabled = "YES">
|
||||
</EnvironmentVariable>
|
||||
</EnvironmentVariables>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Release"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable>
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "5C765ADA199A6DAA003D9110"
|
||||
|
||||
@@ -14,30 +14,30 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
var window: UIWindow?
|
||||
|
||||
|
||||
func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool {
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
|
||||
// Override point for customization after application launch.
|
||||
return true
|
||||
}
|
||||
|
||||
func applicationWillResignActive(application: UIApplication!) {
|
||||
func applicationWillResignActive(_ application: UIApplication) {
|
||||
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
|
||||
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
|
||||
}
|
||||
|
||||
func applicationDidEnterBackground(application: UIApplication!) {
|
||||
func applicationDidEnterBackground(_ application: UIApplication) {
|
||||
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
|
||||
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
|
||||
}
|
||||
|
||||
func applicationWillEnterForeground(application: UIApplication!) {
|
||||
func applicationWillEnterForeground(_ application: UIApplication) {
|
||||
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
|
||||
}
|
||||
|
||||
func applicationDidBecomeActive(application: UIApplication!) {
|
||||
func applicationDidBecomeActive(_ application: UIApplication) {
|
||||
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
|
||||
}
|
||||
|
||||
func applicationWillTerminate(application: UIApplication!) {
|
||||
func applicationWillTerminate(_ application: UIApplication) {
|
||||
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.vluxe.io.$(PRODUCT_NAME:rfc1034identifier)</string>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
|
||||
@@ -10,7 +10,7 @@ import UIKit
|
||||
import Starscream
|
||||
|
||||
class ViewController: UIViewController, WebSocketDelegate {
|
||||
var socket = WebSocket(url: NSURL(scheme: "ws", host: "localhost:8080", path: "/")!, protocols: ["chat", "superchat"])
|
||||
var socket = WebSocket(url: URL(string: "ws://localhost:8080/")!, protocols: ["chat", "superchat"])
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
@@ -20,39 +20,35 @@ class ViewController: UIViewController, WebSocketDelegate {
|
||||
|
||||
// MARK: Websocket Delegate Methods.
|
||||
|
||||
func websocketDidConnect() {
|
||||
println("websocket is connected")
|
||||
func websocketDidConnect(socket: WebSocket) {
|
||||
print("websocket is connected")
|
||||
}
|
||||
|
||||
func websocketDidDisconnect(error: NSError?) {
|
||||
func websocketDidDisconnect(socket: WebSocket, error: NSError?) {
|
||||
if let e = error {
|
||||
println("websocket is disconnected: \(e.localizedDescription)")
|
||||
print("websocket is disconnected: \(e.localizedDescription)")
|
||||
} else {
|
||||
print("websocket disconnected")
|
||||
}
|
||||
}
|
||||
|
||||
func websocketDidWriteError(error: NSError?) {
|
||||
if let e = error {
|
||||
println("wez got an error from the websocket: \(e.localizedDescription)")
|
||||
}
|
||||
func websocketDidReceiveMessage(socket: WebSocket, text: String) {
|
||||
print("Received text: \(text)")
|
||||
}
|
||||
|
||||
func websocketDidReceiveMessage(text: String) {
|
||||
println("Received text: \(text)")
|
||||
}
|
||||
|
||||
func websocketDidReceiveData(data: NSData) {
|
||||
println("Received data: \(data.length)")
|
||||
func websocketDidReceiveData(socket: WebSocket, data: Data) {
|
||||
print("Received data: \(data.count)")
|
||||
}
|
||||
|
||||
// MARK: Write Text Action
|
||||
|
||||
@IBAction func writeText(sender: UIBarButtonItem) {
|
||||
socket.writeString("hello there!")
|
||||
@IBAction func writeText(_ sender: UIBarButtonItem) {
|
||||
socket.write(string: "hello there!")
|
||||
}
|
||||
|
||||
// MARK: Disconnect Action
|
||||
|
||||
@IBAction func disconnect(sender: UIBarButtonItem) {
|
||||
@IBAction func disconnect(_ sender: UIBarButtonItem) {
|
||||
if socket.isConnected {
|
||||
sender.title = "Connect"
|
||||
socket.disconnect()
|
||||
|
||||
@@ -22,4 +22,4 @@ EM.run {
|
||||
ws.send Faker::Hacker.say_something_smart
|
||||
}
|
||||
end
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user