Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a063fda2b8 | |||
| e6b65c6d90 | |||
| 7ce91f71ca | |||
| a2ed45c0b2 | |||
| ccb32575e5 | |||
| 9164a09cf5 | |||
| a9625bf474 | |||
| e68b2f7427 | |||
| 1d81b781e9 | |||
| 692d55c76a | |||
| 9c03ef715d | |||
| 7860785cf3 | |||
| b1312f8af1 | |||
| 514eb3ddb9 | |||
| 4c48638295 | |||
| 429bd1a0b7 | |||
| 5ecb5fd499 | |||
| fbd80c2367 | |||
| 40cda44e40 | |||
| 51ee77cf6c | |||
| de293c4b26 | |||
| 688bd32df8 | |||
| ee00c1dfdd | |||
| 07e09a8ab3 | |||
| d58f0a4436 | |||
| 36254e8945 |
+1
-1
@@ -1,4 +1,4 @@
|
||||
osx_image: xcode10
|
||||
osx_image: xcode10.2
|
||||
language: objective-c
|
||||
before_install:
|
||||
- gem install cocoapods --pre
|
||||
|
||||
+15
-7
@@ -2,6 +2,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
`Starscream` adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
### [3.1.1](https://github.com/daltoniam/Starscream/tree/3.1.1)
|
||||
|
||||
Small version number fix for 3.1.0: [#703](https://github.com/daltoniam/Starscream/issues/703)
|
||||
|
||||
### [3.1.0](https://github.com/daltoniam/Starscream/tree/3.1.0)
|
||||
|
||||
* Swift 5.0 and Xcode 10.2 support
|
||||
|
||||
#### [3.0.6](https://github.com/daltoniam/Starscream/tree/3.0.6)
|
||||
|
||||
* Swift 4.2 and Xcode 10 support
|
||||
@@ -149,14 +157,14 @@ Warning fixes for Swift 3.1
|
||||
|
||||
Fix for the Swift Package Manager.
|
||||
|
||||
Fixed:
|
||||
Fixed:
|
||||
[#277](https://github.com/daltoniam/Starscream/issues/277)
|
||||
|
||||
#### [2.0.1](https://github.com/daltoniam/Starscream/tree/2.0.1)
|
||||
|
||||
Bug fixes.
|
||||
|
||||
Fixed:
|
||||
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)
|
||||
@@ -167,7 +175,7 @@ Fixed:
|
||||
|
||||
Added Swift 3 support.
|
||||
|
||||
Fixed:
|
||||
Fixed:
|
||||
[#229](https://github.com/daltoniam/Starscream/issues/229)
|
||||
[#232](https://github.com/daltoniam/Starscream/issues/232)
|
||||
|
||||
@@ -177,7 +185,7 @@ Swift 2.3 support.
|
||||
|
||||
#### [1.1.3](https://github.com/daltoniam/Starscream/tree/1.1.3)
|
||||
|
||||
Changed:
|
||||
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)
|
||||
@@ -186,14 +194,14 @@ Changed:
|
||||
|
||||
#### [1.1.2](https://github.com/daltoniam/Starscream/tree/1.1.2)
|
||||
|
||||
Fixed:
|
||||
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:
|
||||
Fixed:
|
||||
[#157](https://github.com/daltoniam/Starscream/issues/157)
|
||||
|
||||
#### [1.1.0](https://github.com/daltoniam/Starscream/tree/1.1.0)
|
||||
@@ -201,7 +209,7 @@ Fixed:
|
||||
Changed:
|
||||
Moved over to Runloop/default GCD queues to shared queue.
|
||||
|
||||
Fixed:
|
||||
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)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
source "https://rubygems.org"
|
||||
|
||||
gem "fastlane"
|
||||
gem "cocoapods", ">= 1.6.0.beta.1"
|
||||
gem "cocoapods"
|
||||
|
||||
+53
-42
@@ -2,22 +2,22 @@ GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
CFPropertyList (3.0.0)
|
||||
activesupport (4.2.10)
|
||||
activesupport (4.2.11.1)
|
||||
i18n (~> 0.7)
|
||||
minitest (~> 5.1)
|
||||
thread_safe (~> 0.3, >= 0.3.4)
|
||||
tzinfo (~> 1.1)
|
||||
addressable (2.5.2)
|
||||
addressable (2.6.0)
|
||||
public_suffix (>= 2.0.2, < 4.0)
|
||||
atomos (0.1.3)
|
||||
babosa (1.0.2)
|
||||
claide (1.0.2)
|
||||
cocoapods (1.6.0.beta.1)
|
||||
cocoapods (1.6.1)
|
||||
activesupport (>= 4.0.2, < 5)
|
||||
claide (>= 1.0.2, < 2.0)
|
||||
cocoapods-core (= 1.6.0.beta.1)
|
||||
cocoapods-core (= 1.6.1)
|
||||
cocoapods-deintegrate (>= 1.0.2, < 2.0)
|
||||
cocoapods-downloader (>= 1.2.1, < 2.0)
|
||||
cocoapods-downloader (>= 1.2.2, < 2.0)
|
||||
cocoapods-plugins (>= 1.0.0, < 2.0)
|
||||
cocoapods-search (>= 1.0.0, < 2.0)
|
||||
cocoapods-stats (>= 1.0.0, < 2.0)
|
||||
@@ -25,22 +25,22 @@ GEM
|
||||
cocoapods-try (>= 1.1.0, < 2.0)
|
||||
colored2 (~> 3.1)
|
||||
escape (~> 0.0.4)
|
||||
fourflusher (~> 2.0.1)
|
||||
fourflusher (>= 2.2.0, < 3.0)
|
||||
gh_inspector (~> 1.0)
|
||||
molinillo (~> 0.6.6)
|
||||
nap (~> 1.0)
|
||||
ruby-macho (~> 1.2)
|
||||
xcodeproj (>= 1.6.0, < 2.0)
|
||||
cocoapods-core (1.6.0.beta.1)
|
||||
ruby-macho (~> 1.4)
|
||||
xcodeproj (>= 1.8.1, < 2.0)
|
||||
cocoapods-core (1.6.1)
|
||||
activesupport (>= 4.0.2, < 6)
|
||||
fuzzy_match (~> 2.0.4)
|
||||
nap (~> 1.0)
|
||||
cocoapods-deintegrate (1.0.2)
|
||||
cocoapods-downloader (1.2.1)
|
||||
cocoapods-deintegrate (1.0.4)
|
||||
cocoapods-downloader (1.2.2)
|
||||
cocoapods-plugins (1.0.0)
|
||||
nap
|
||||
cocoapods-search (1.0.0)
|
||||
cocoapods-stats (1.0.0)
|
||||
cocoapods-stats (1.1.0)
|
||||
cocoapods-trunk (1.3.1)
|
||||
nap (>= 0.8, < 2.0)
|
||||
netrc (~> 0.11)
|
||||
@@ -49,32 +49,33 @@ GEM
|
||||
colored2 (3.1.2)
|
||||
commander-fastlane (4.4.6)
|
||||
highline (~> 1.7.2)
|
||||
concurrent-ruby (1.0.5)
|
||||
concurrent-ruby (1.1.5)
|
||||
declarative (0.0.10)
|
||||
declarative-option (0.1.0)
|
||||
digest-crc (0.4.1)
|
||||
domain_name (0.5.20180417)
|
||||
unf (>= 0.0.5, < 1.0.0)
|
||||
dotenv (2.5.0)
|
||||
emoji_regex (0.1.1)
|
||||
dotenv (2.7.2)
|
||||
emoji_regex (1.0.1)
|
||||
escape (0.0.4)
|
||||
excon (0.62.0)
|
||||
faraday (0.15.3)
|
||||
excon (0.64.0)
|
||||
faraday (0.15.4)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
faraday-cookie_jar (0.0.6)
|
||||
faraday (>= 0.7.4)
|
||||
http-cookie (~> 1.0.0)
|
||||
faraday_middleware (0.12.2)
|
||||
faraday_middleware (0.13.1)
|
||||
faraday (>= 0.7.4, < 1.0)
|
||||
fastimage (2.1.4)
|
||||
fastlane (2.105.2)
|
||||
fastimage (2.1.5)
|
||||
fastlane (2.122.0)
|
||||
CFPropertyList (>= 2.3, < 4.0.0)
|
||||
addressable (>= 2.3, < 3.0.0)
|
||||
babosa (>= 1.0.2, < 2.0.0)
|
||||
bundler (>= 1.12.0, < 2.0.0)
|
||||
bundler (>= 1.12.0, < 3.0.0)
|
||||
colored
|
||||
commander-fastlane (>= 4.4.6, < 5.0.0)
|
||||
dotenv (>= 2.1.1, < 3.0.0)
|
||||
emoji_regex (~> 0.1)
|
||||
emoji_regex (>= 0.1, < 2.0)
|
||||
excon (>= 0.45.0, < 1.0.0)
|
||||
faraday (~> 0.9)
|
||||
faraday-cookie_jar (~> 0.0.6)
|
||||
@@ -82,6 +83,7 @@ GEM
|
||||
fastimage (>= 2.1.0, < 3.0.0)
|
||||
gh_inspector (>= 1.1.2, < 2.0.0)
|
||||
google-api-client (>= 0.21.2, < 0.24.0)
|
||||
google-cloud-storage (>= 1.15.0, < 2.0.0)
|
||||
highline (>= 1.7.2, < 2.0.0)
|
||||
json (< 3.0.0)
|
||||
mini_magick (~> 4.5.1)
|
||||
@@ -94,15 +96,15 @@ GEM
|
||||
security (= 0.1.3)
|
||||
simctl (~> 1.6.3)
|
||||
slack-notifier (>= 2.0.0, < 3.0.0)
|
||||
terminal-notifier (>= 1.6.2, < 2.0.0)
|
||||
terminal-notifier (>= 2.0.0, < 3.0.0)
|
||||
terminal-table (>= 1.4.5, < 2.0.0)
|
||||
tty-screen (>= 0.6.3, < 1.0.0)
|
||||
tty-spinner (>= 0.8.0, < 1.0.0)
|
||||
word_wrap (~> 1.0.0)
|
||||
xcodeproj (>= 1.6.0, < 2.0.0)
|
||||
xcodeproj (>= 1.8.1, < 2.0.0)
|
||||
xcpretty (~> 0.3.0)
|
||||
xcpretty-travis-formatter (>= 0.0.3)
|
||||
fourflusher (2.0.1)
|
||||
fourflusher (2.2.0)
|
||||
fuzzy_match (2.0.4)
|
||||
gh_inspector (1.1.3)
|
||||
google-api-client (0.23.9)
|
||||
@@ -113,10 +115,19 @@ GEM
|
||||
representable (~> 3.0)
|
||||
retriable (>= 2.0, < 4.0)
|
||||
signet (~> 0.9)
|
||||
googleauth (0.6.6)
|
||||
google-cloud-core (1.3.0)
|
||||
google-cloud-env (~> 1.0)
|
||||
google-cloud-env (1.0.5)
|
||||
faraday (~> 0.11)
|
||||
google-cloud-storage (1.16.0)
|
||||
digest-crc (~> 0.4)
|
||||
google-api-client (~> 0.23)
|
||||
google-cloud-core (~> 1.2)
|
||||
googleauth (>= 0.6.2, < 0.10.0)
|
||||
googleauth (0.6.7)
|
||||
faraday (~> 0.12)
|
||||
jwt (>= 1.4, < 3.0)
|
||||
memoist (~> 0.12)
|
||||
memoist (~> 0.16)
|
||||
multi_json (~> 1.11)
|
||||
os (>= 0.9, < 2.0)
|
||||
signet (~> 0.7)
|
||||
@@ -126,12 +137,12 @@ GEM
|
||||
httpclient (2.8.3)
|
||||
i18n (0.9.5)
|
||||
concurrent-ruby (~> 1.0)
|
||||
json (2.1.0)
|
||||
json (2.2.0)
|
||||
jwt (2.1.0)
|
||||
memoist (0.16.0)
|
||||
mime-types (3.2.2)
|
||||
mime-types-data (~> 3.2015)
|
||||
mime-types-data (3.2018.0812)
|
||||
mime-types-data (3.2019.0331)
|
||||
mini_magick (4.5.1)
|
||||
minitest (5.11.3)
|
||||
molinillo (0.6.6)
|
||||
@@ -142,8 +153,8 @@ GEM
|
||||
nap (1.1.0)
|
||||
naturally (2.2.0)
|
||||
netrc (0.11.0)
|
||||
os (1.0.0)
|
||||
plist (3.4.0)
|
||||
os (1.0.1)
|
||||
plist (3.5.0)
|
||||
public_suffix (2.0.5)
|
||||
representable (3.0.4)
|
||||
declarative (< 0.1.0)
|
||||
@@ -151,10 +162,10 @@ GEM
|
||||
uber (< 0.2.0)
|
||||
retriable (3.1.2)
|
||||
rouge (2.0.7)
|
||||
ruby-macho (1.3.1)
|
||||
ruby-macho (1.4.0)
|
||||
rubyzip (1.2.2)
|
||||
security (0.1.3)
|
||||
signet (0.10.0)
|
||||
signet (0.11.0)
|
||||
addressable (~> 2.3)
|
||||
faraday (~> 0.9)
|
||||
jwt (>= 1.5, < 3.0)
|
||||
@@ -163,23 +174,23 @@ GEM
|
||||
CFPropertyList
|
||||
naturally
|
||||
slack-notifier (2.3.2)
|
||||
terminal-notifier (1.8.0)
|
||||
terminal-notifier (2.0.0)
|
||||
terminal-table (1.8.0)
|
||||
unicode-display_width (~> 1.1, >= 1.1.1)
|
||||
thread_safe (0.3.6)
|
||||
tty-cursor (0.6.0)
|
||||
tty-cursor (0.6.1)
|
||||
tty-screen (0.6.5)
|
||||
tty-spinner (0.8.0)
|
||||
tty-cursor (>= 0.5.0)
|
||||
tty-spinner (0.9.0)
|
||||
tty-cursor (~> 0.6.0)
|
||||
tzinfo (1.2.5)
|
||||
thread_safe (~> 0.1)
|
||||
uber (0.1.0)
|
||||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.7.5)
|
||||
unicode-display_width (1.4.0)
|
||||
unf_ext (0.0.7.6)
|
||||
unicode-display_width (1.5.0)
|
||||
word_wrap (1.0.0)
|
||||
xcodeproj (1.6.0)
|
||||
xcodeproj (1.9.0)
|
||||
CFPropertyList (>= 2.3.3, < 4.0)
|
||||
atomos (~> 0.1.3)
|
||||
claide (>= 1.0.2, < 2.0)
|
||||
@@ -194,8 +205,8 @@ PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
cocoapods (>= 1.6.0.beta.1)
|
||||
cocoapods
|
||||
fastlane
|
||||
|
||||
BUNDLED WITH
|
||||
1.16.1
|
||||
1.17.2
|
||||
|
||||
+9
-1
@@ -1,7 +1,15 @@
|
||||
{
|
||||
"object": {
|
||||
"pins": [
|
||||
|
||||
{
|
||||
"package": "swift-nio-zlib-support",
|
||||
"repositoryURL": "https://github.com/apple/swift-nio-zlib-support.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "37760e9a52030bb9011972c5213c3350fa9d41fd",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": 1
|
||||
|
||||
@@ -32,3 +32,7 @@ let package = Package(
|
||||
.target(name: "Starscream")
|
||||
]
|
||||
)
|
||||
|
||||
#if os(Linux)
|
||||
package.dependencies.append(.package(url: "https://github.com/apple/swift-nio-zlib-support.git", from: "1.0.0"))
|
||||
#endif
|
||||
|
||||
@@ -311,6 +311,29 @@ To integrate Starscream into your Xcode project using Carthage, specify it in yo
|
||||
github "daltoniam/Starscream" >= 3.0.2
|
||||
```
|
||||
|
||||
### Accio
|
||||
|
||||
Check out the [Accio](https://github.com/JamitLabs/Accio) docs on how to add a install.
|
||||
|
||||
Add the following to your Package.swift:
|
||||
|
||||
```swift
|
||||
.package(url: "https://github.com/daltoniam/Starscream.git", .upToNextMajor(from: "3.1.0")),
|
||||
```
|
||||
|
||||
Next, add `Starscream` to your App targets dependencies like so:
|
||||
|
||||
```swift
|
||||
.target(
|
||||
name: "App",
|
||||
dependencies: [
|
||||
"Starscream",
|
||||
]
|
||||
),
|
||||
```
|
||||
|
||||
Then run `accio update`.
|
||||
|
||||
### Rogue
|
||||
|
||||
First see the [installation docs](https://github.com/acmacalister/Rogue) for how to install Rogue.
|
||||
@@ -385,6 +408,10 @@ func websocketHttpUpgrade(socket: WebSocketClient, response: CFHTTPMessage) {
|
||||
}
|
||||
```
|
||||
|
||||
## Swift versions
|
||||
|
||||
* Swift 4.2 - 3.0.6
|
||||
|
||||
## KNOWN ISSUES
|
||||
- WatchOS does not have the the CFNetwork String constants to modify the stream's SSL behavior. It will be the default Foundation SSL behavior. This means watchOS CANNOT use `SSLCiphers`, `disableSSLCertValidation`, or SSL pinning. All these values set on watchOS will do nothing.
|
||||
- Linux does not have the security framework, so it CANNOT use SSL pinning or `SSLCiphers` either.
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.0.5</string>
|
||||
<string>3.1.1</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
||||
@@ -1,165 +0,0 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// FoundationStream.swift
|
||||
// Starscream
|
||||
//
|
||||
// Created by Dalton Cherry on 7/23/18.
|
||||
// Copyright (c) 2014-2018 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
|
||||
|
||||
///
|
||||
open class FoundationStream: NSObject, WSStream, StreamDelegate {
|
||||
private static let sharedWorkQueue = DispatchQueue(label: "com.vluxe.starscream.foundationstream", attributes: [])
|
||||
private var inputStream: InputStream?
|
||||
private var outputStream: OutputStream?
|
||||
private let security: FoundationSecurity
|
||||
public weak var delegate: WSStreamDelegate?
|
||||
let BUFFER_MAX = 4096
|
||||
var isConnected = false
|
||||
|
||||
public var enableSOCKSProxy = false
|
||||
|
||||
public init(security: FoundationSecurity = FoundationSecurity()) {
|
||||
self.security = security
|
||||
}
|
||||
|
||||
public func connect(url: URL, port: Int, timeout: TimeInterval, useSSL: Bool, completion: @escaping ((Error?) -> Void)) {
|
||||
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()
|
||||
|
||||
#if os(watchOS) //watchOS is unfortunately missing the kCFStream properties to make this work
|
||||
#else
|
||||
if enableSOCKSProxy {
|
||||
let proxyDict = CFNetworkCopySystemProxySettings()
|
||||
let socksConfig = CFDictionaryCreateMutableCopy(nil, 0, proxyDict!.takeRetainedValue())
|
||||
let propertyKey = CFStreamPropertyKey(rawValue: kCFStreamPropertySOCKSProxy)
|
||||
CFWriteStreamSetProperty(outputStream, propertyKey, socksConfig)
|
||||
CFReadStreamSetProperty(inputStream, propertyKey, socksConfig)
|
||||
}
|
||||
#endif
|
||||
|
||||
guard let inStream = inputStream, let outStream = outputStream else { return }
|
||||
inStream.delegate = self
|
||||
outStream.delegate = self
|
||||
|
||||
if useSSL, let error = security.configure(inputStream: inStream, outputStream: outStream) {
|
||||
completion(error)
|
||||
return
|
||||
}
|
||||
|
||||
CFReadStreamSetDispatchQueue(inStream, FoundationStream.sharedWorkQueue)
|
||||
CFWriteStreamSetDispatchQueue(outStream, FoundationStream.sharedWorkQueue)
|
||||
inStream.open()
|
||||
outStream.open()
|
||||
isConnected = true
|
||||
|
||||
var out = timeout// wait X seconds before giving up
|
||||
FoundationStream.sharedWorkQueue.async { [weak self] in
|
||||
while !outStream.hasSpaceAvailable {
|
||||
usleep(100) // wait until the socket is ready
|
||||
out -= 100
|
||||
if out < 0 {
|
||||
completion(WSError(type: .writeTimeoutError, message: "Timed out waiting for the socket to be ready for a write", code: 0))
|
||||
return
|
||||
} else if let error = outStream.streamError {
|
||||
completion(error)
|
||||
return // disconnectStream will be called.
|
||||
} else if self == nil {
|
||||
completion(WSError(type: .closeError, message: "socket object has been dereferenced", code: 0))
|
||||
return
|
||||
}
|
||||
}
|
||||
completion(nil) //success!
|
||||
}
|
||||
}
|
||||
|
||||
public func write(data: Data, completion: @escaping ((Error?) -> Void)) {
|
||||
guard isConnected else {return} //don't write to a dead socket
|
||||
var written = 0
|
||||
let total = data.count
|
||||
while written < total {
|
||||
guard let outStream = outputStream else {
|
||||
completion(WSError(type: .outputStreamWriteError, message: "output stream had an error during write", code: 0))
|
||||
return
|
||||
}
|
||||
data.withUnsafeBytes { (pointer: UnsafePointer<UInt8>) in
|
||||
guard let buffer = UnsafeBufferPointer(start: pointer, count: total).fromOffset(written).baseAddress else {
|
||||
completion(WSError(type: .outputStreamWriteError, message: "buffer error during write", code: 0))
|
||||
return
|
||||
}
|
||||
written += outStream.write(buffer, maxLength: total - written)
|
||||
if written < 0 {
|
||||
completion(WSError(type: .outputStreamWriteError, message: "buffer error during write", code: 0))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
completion(nil)
|
||||
}
|
||||
|
||||
/// read data from the stream.
|
||||
public func read() -> Data? {
|
||||
guard let stream = inputStream else {return nil}
|
||||
let buf = NSMutableData(capacity: BUFFER_MAX)
|
||||
let buffer = UnsafeMutableRawPointer(mutating: buf!.bytes).assumingMemoryBound(to: UInt8.self)
|
||||
let length = stream.read(buffer, maxLength: BUFFER_MAX)
|
||||
if length < 1 {
|
||||
return nil
|
||||
}
|
||||
return Data(bytes: buffer, count: length)
|
||||
}
|
||||
|
||||
public func cleanup() {
|
||||
isConnected = false
|
||||
if let stream = inputStream {
|
||||
stream.delegate = nil
|
||||
CFReadStreamSetDispatchQueue(stream, nil)
|
||||
stream.close()
|
||||
}
|
||||
if let stream = outputStream {
|
||||
stream.delegate = nil
|
||||
CFWriteStreamSetDispatchQueue(stream, nil)
|
||||
stream.close()
|
||||
}
|
||||
outputStream = nil
|
||||
inputStream = nil
|
||||
}
|
||||
|
||||
public func isValidSSLCertificate() -> Bool {
|
||||
guard let outputStream = outputStream else {return false} //the stream is already invalid
|
||||
return security.checkTrust(outputStream: outputStream)
|
||||
}
|
||||
|
||||
/// MARK: - StreamDelegate
|
||||
open func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
|
||||
if eventCode == .hasBytesAvailable {
|
||||
if aStream == inputStream {
|
||||
delegate?.newBytesInStream()
|
||||
}
|
||||
} else if eventCode == .errorOccurred {
|
||||
delegate?.streamDidError(error: aStream.streamError)
|
||||
} else if eventCode == .endEncountered {
|
||||
delegate?.streamDidError(error: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// NetworkStream.swift
|
||||
// Starscream
|
||||
//
|
||||
// Created by Dalton Cherry on 7/23/18.
|
||||
// Copyright (c) 2014-2018 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
|
||||
#if canImport(Network)
|
||||
import Network
|
||||
#endif
|
||||
|
||||
/// Implementation of the Network framework that was introduced in iOS 12/MacOS 10.14.
|
||||
/// This class will probably replace the Foundation one in the future, but because Foundation is battle-tested
|
||||
/// it will continue to be provided for backwards compatibility reasons.
|
||||
@available(iOS 12.0, *)
|
||||
@available(iOSApplicationExtension 12.0, tvOSApplicationExtension 12.0, OSXApplicationExtension 10.14, *)
|
||||
open class NetworkStream: WSStream {
|
||||
public weak var delegate: WSStreamDelegate?
|
||||
private var stream: NWConnection?
|
||||
private static let sharedWorkQueue = DispatchQueue(label: "com.vluxe.starscream.networkstream", attributes: [])
|
||||
private var readQueue = [Data]()
|
||||
var running = false
|
||||
var connected = false
|
||||
|
||||
//need security stuff
|
||||
public init() {
|
||||
|
||||
}
|
||||
|
||||
/// connect to the websocket server and start the read loop
|
||||
public func connect(url: URL, port: Int, timeout: TimeInterval, useSSL: Bool, completion: @escaping ((Error?) -> Void)) {
|
||||
let parameters: NWParameters = useSSL ? .tls : .tcp
|
||||
let conn = NWConnection(host: NWEndpoint.Host.name(url.host!, nil), port: NWEndpoint.Port(rawValue: UInt16(port))!, using: parameters)
|
||||
connected = false
|
||||
func doConnect(_ error: Error?) {
|
||||
if !connected {
|
||||
completion(error)
|
||||
connected = true
|
||||
running = true
|
||||
} else {
|
||||
running = false
|
||||
}
|
||||
}
|
||||
conn.stateUpdateHandler = { [weak self] (newState) in
|
||||
switch newState {
|
||||
case .ready:
|
||||
doConnect(nil)
|
||||
case .waiting:
|
||||
self?.delegate?.streamIsWaitingForConnectivity()
|
||||
case .cancelled:
|
||||
doConnect(nil)
|
||||
case .failed(let error):
|
||||
doConnect(error)
|
||||
self?.delegate?.streamDidError(error: error)
|
||||
case .setup, .preparing:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
conn.viabilityUpdateHandler = { [weak self] (isViable) in
|
||||
self?.delegate?.streamPathViabilityUpdate(isViable: isViable)
|
||||
}
|
||||
|
||||
conn.betterPathUpdateHandler = { [weak self] (isBetter) in
|
||||
self?.delegate?.streamBetterPathUpdate(isBetter: isBetter)
|
||||
}
|
||||
|
||||
conn.start(queue: NetworkStream.sharedWorkQueue)
|
||||
stream = conn
|
||||
running = true
|
||||
readLoop()
|
||||
}
|
||||
|
||||
/// Write data over the socket to the websocket server
|
||||
/// From how I understand the documentation for send, we might need to optimize with queued writes.
|
||||
public func write(data: Data, completion: @escaping ((Error?) -> Void)) {
|
||||
stream?.send(content: data, completion: .contentProcessed { (sendError) in
|
||||
completion(nil) //sendError
|
||||
})
|
||||
}
|
||||
|
||||
/// get hte latest message from the read queue
|
||||
public func read() -> Data? {
|
||||
return readQueue.removeFirst()
|
||||
}
|
||||
|
||||
/// stream isn't to be used anymore
|
||||
public func cleanup() {
|
||||
running = false
|
||||
stream?.cancel()
|
||||
}
|
||||
|
||||
public func isValidSSLCertificate() -> Bool {
|
||||
return false //TODO: SSL pinning for the network framework
|
||||
}
|
||||
|
||||
//continually read from the stream waiting for more content to process
|
||||
func readLoop() {
|
||||
if !running {
|
||||
return
|
||||
}
|
||||
stream?.receive(minimumIncompleteLength: 2, maximumLength: 4096, completion: {[weak self] (data, context, isComplete, error) in
|
||||
guard let s = self else {return}
|
||||
if let err = error {
|
||||
s.delegate?.streamDidError(error: err)
|
||||
return
|
||||
}
|
||||
if let data = data {
|
||||
s.readQueue.append(data)
|
||||
s.delegate?.newBytesInStream()
|
||||
}
|
||||
// I'm not sure why this is needed (might be a bug),
|
||||
// but this indicates the stream is "dead" and should be closed
|
||||
// even though we never got that state update
|
||||
if isComplete && data == nil, context == nil, error == nil {
|
||||
s.delegate?.streamDidError(error: nil)
|
||||
s.cleanup()
|
||||
return
|
||||
}
|
||||
s.readLoop()
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
// Starscream
|
||||
//
|
||||
// Created by Dalton Cherry on 5/16/15.
|
||||
// Copyright (c) 2014-2018 Dalton Cherry.
|
||||
// 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.
|
||||
@@ -24,115 +24,10 @@
|
||||
import Foundation
|
||||
import Security
|
||||
|
||||
public protocol FoundationSSLValidator {
|
||||
func checkTrust(outputStream: OutputStream) -> Bool
|
||||
func configure(inputStream: InputStream, outputStream: OutputStream) -> WSError?
|
||||
}
|
||||
|
||||
open class FoundationSecurity: FoundationSSLValidator {
|
||||
public var pinner: SSLPinnerTrustValidator?
|
||||
public var desiredTrustHostname: String?
|
||||
public var disableCertValidation: Bool
|
||||
public var disableSSL = false
|
||||
public var overrideTrustHostname = false
|
||||
public var cipherSuites: [SSLCipherSuite]?
|
||||
public var clientCertificate: SSLClientCertificate?
|
||||
|
||||
/**
|
||||
Designated init for FoundationSecurity
|
||||
|
||||
- parameter sslPinner: is SSL pinning class you want to use
|
||||
- parameter desiredTrustHostname: is SSL hostname you want to validate
|
||||
- parameter disableCertValidation: is to disable the SSL certificate chain validation
|
||||
- parameter clientCertificate: is to configure client side authentication
|
||||
|
||||
- returns: a security object that is used with the FoundationStream
|
||||
*/
|
||||
public init(pinner: SSLPinnerTrustValidator? = nil, desiredTrustHostname: String? = nil, disableCertValidation: Bool = false, clientCertificate: SSLClientCertificate? = nil) {
|
||||
self.pinner = pinner
|
||||
self.desiredTrustHostname = desiredTrustHostname
|
||||
self.disableCertValidation = disableCertValidation
|
||||
self.self.clientCertificate = clientCertificate
|
||||
if desiredTrustHostname != nil {
|
||||
self.overrideTrustHostname = true
|
||||
}
|
||||
}
|
||||
|
||||
public func configure(inputStream: InputStream, outputStream: OutputStream) -> WSError? {
|
||||
if disableSSL {
|
||||
return nil
|
||||
}
|
||||
inputStream.setProperty(StreamSocketSecurityLevel.negotiatedSSL as AnyObject, forKey: Stream.PropertyKey.socketSecurityLevelKey)
|
||||
outputStream.setProperty(StreamSocketSecurityLevel.negotiatedSSL as AnyObject, forKey: Stream.PropertyKey.socketSecurityLevelKey)
|
||||
#if os(watchOS) //watchOS is unfortunately missing the kCFStream properties to make this work
|
||||
#else
|
||||
var settings = [NSObject: NSObject]()
|
||||
if disableCertValidation {
|
||||
settings[kCFStreamSSLValidatesCertificateChain] = NSNumber(value: false)
|
||||
}
|
||||
if let hostname = desiredTrustHostname {
|
||||
settings[kCFStreamSSLPeerName] = hostname as NSString
|
||||
} else if overrideTrustHostname {
|
||||
settings[kCFStreamSSLPeerName] = kCFNull
|
||||
}
|
||||
if let clientCertificate = clientCertificate {
|
||||
settings[kCFStreamSSLCertificates] = clientCertificate.streamSSLCertificates
|
||||
}
|
||||
|
||||
inputStream.setProperty(settings, forKey: kCFStreamPropertySSLSettings as Stream.PropertyKey)
|
||||
outputStream.setProperty(settings, forKey: kCFStreamPropertySSLSettings as Stream.PropertyKey)
|
||||
#endif
|
||||
|
||||
if let cipherSuites = cipherSuites {
|
||||
#if os(watchOS) //watchOS is unfortunately missing the kCFStream properties to make this work
|
||||
#else
|
||||
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 {
|
||||
return WSError(type: .invalidSSLError, message: "Error setting incoming cypher suites", code: UInt16(resIn))
|
||||
} else if resOut != errSecSuccess {
|
||||
return WSError(type: .invalidSSLError, message: "Error setting outgoing cypher suites", code: UInt16(resOut))
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
public func checkTrust(outputStream: OutputStream) -> Bool {
|
||||
#if os(watchOS) //watchOS is unfortunately missing the kCFStream properties to make this work
|
||||
return true
|
||||
#else
|
||||
guard let pinner = pinner else {return true} //true because we don't validated.
|
||||
|
||||
let trust = outputStream.property(forKey: kCFStreamPropertySSLPeerTrust as Stream.PropertyKey) as! SecTrust?
|
||||
var domain = outputStream.property(forKey: kCFStreamSSLPeerName as Stream.PropertyKey) as! String?
|
||||
if domain == nil, let sslContextOut = CFWriteStreamCopyProperty(outputStream, CFStreamPropertyKey(rawValue: kCFStreamPropertySSLContext)) as! SSLContext? {
|
||||
var peerNameLen: Int = 0
|
||||
SSLGetPeerDomainNameLength(sslContextOut, &peerNameLen)
|
||||
var peerName = Data(count: peerNameLen)
|
||||
let _ = peerName.withUnsafeMutableBytes { (peerNamePtr: UnsafeMutablePointer<Int8>) in
|
||||
SSLGetPeerDomainName(sslContextOut, peerNamePtr, &peerNameLen)
|
||||
}
|
||||
if let peerDomain = String(bytes: peerName, encoding: .utf8), peerDomain.count > 0 {
|
||||
domain = peerDomain
|
||||
}
|
||||
}
|
||||
guard let t = trust else {return true} //true because this probably isn't and SSL stream without a trust.
|
||||
return pinner.isValid(t, domain: domain)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/// SSLPinnerTrustValidator is the base protocol needed to do SSL pinning on the FoundationStream.
|
||||
public protocol SSLPinnerTrustValidator {
|
||||
public protocol SSLTrustValidator {
|
||||
func isValid(_ trust: SecTrust, domain: String?) -> Bool
|
||||
}
|
||||
|
||||
|
||||
/// SSLCert the object to hold and use an SSL key or certificate.
|
||||
open class SSLCert {
|
||||
var certData: Data?
|
||||
var key: SecKey?
|
||||
@@ -160,9 +55,7 @@ open class SSLCert {
|
||||
}
|
||||
}
|
||||
|
||||
/// FoundationPinner is a very simple SSL pinning implementation.
|
||||
/// Also See TrustKit...more words.
|
||||
open class FoundationPinner : SSLPinnerTrustValidator {
|
||||
open class SSLSecurity : SSLTrustValidator {
|
||||
public var validatedDN = true //should the domain name be validated?
|
||||
public var validateEntireChain = true //should the entire cert chain be validated
|
||||
|
||||
|
||||
@@ -1,538 +0,0 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WSMessageParser.swift
|
||||
// Starscream
|
||||
//
|
||||
// Created by Dalton Cherry on 7/25/18.
|
||||
// Copyright (c) 2014-2018 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.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
|
||||
// Processes and converts raw data into websocket frames
|
||||
// The messages
|
||||
|
||||
import Foundation
|
||||
import CommonCrypto
|
||||
|
||||
struct WSMessage {
|
||||
let code: WebSocket.OpCode
|
||||
let data: Data
|
||||
}
|
||||
|
||||
struct WSFrame {
|
||||
let code: WebSocket.OpCode
|
||||
let bytesLeft: Int
|
||||
let data: Data
|
||||
}
|
||||
|
||||
protocol WSMessageParserDelegate: class {
|
||||
func didReceive(message: WSMessage)
|
||||
func didEncounter(error: WSError)
|
||||
func didParseHTTP(response: String)
|
||||
}
|
||||
|
||||
protocol WSMessageParserClient {
|
||||
func append(data: Data)
|
||||
func createSendFrame(data: Data, code: WebSocket.OpCode) -> Data
|
||||
func reset()
|
||||
}
|
||||
|
||||
class WSMessageParser: WSMessageParserClient {
|
||||
public weak var delegate: WSMessageParserDelegate?
|
||||
public var headerSecurityKey: String {
|
||||
return headerSecKey
|
||||
}
|
||||
|
||||
struct CompressionState {
|
||||
var supportsCompression = false
|
||||
var messageNeedsDecompression = false
|
||||
var serverMaxWindowBits = 15
|
||||
var clientMaxWindowBits = 15
|
||||
var clientNoContextTakeover = false
|
||||
var serverNoContextTakeover = false
|
||||
var decompressor: Decompressor? = nil
|
||||
var compressor: Compressor? = nil
|
||||
}
|
||||
|
||||
let FinMask: UInt8 = 0x80
|
||||
let OpCodeMask: UInt8 = 0x0F
|
||||
let RSVMask: UInt8 = 0x70
|
||||
let RSV1Mask: UInt8 = 0x40
|
||||
let MaskMask: UInt8 = 0x80
|
||||
let PayloadLenMask: UInt8 = 0x7F
|
||||
let httpSwitchProtocolCode = 101
|
||||
let MaxFrameSize: Int = 32
|
||||
|
||||
private var inputQueue = [Data]()
|
||||
private var fragBuffer: Data?
|
||||
private let queue = DispatchQueue(label: "com.vluxe.starscream.messages", attributes: [])
|
||||
private var readStack = [WSFrame]()
|
||||
private let emptyBuffer = UnsafeBufferPointer<UInt8>(start: nil, count: 0)
|
||||
private var didHandshake = false
|
||||
private var compressionState = CompressionState()
|
||||
private var headerSecKey = WSMessageParser.generateWebSocketKey()
|
||||
private let frameHeaderLength = MemoryLayout<UInt8>.size * 2
|
||||
|
||||
// add the data to the queue to be processed
|
||||
func append(data: Data) {
|
||||
queue.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
let process = self.inputQueue.count == 0
|
||||
self.inputQueue.append(data)
|
||||
if process {
|
||||
self.dequeue()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// creates a websocket frame out of the data you wish to send to the WebSocket server
|
||||
func createSendFrame(data: Data, code: WebSocket.OpCode) -> Data {
|
||||
var offset = frameHeaderLength
|
||||
var firstByte: UInt8 = FinMask | code.rawValue
|
||||
var data = data
|
||||
if [.text, .binary].contains(code), let compressor = compressionState.compressor {
|
||||
do {
|
||||
data = try compressor.compress(data)
|
||||
if compressionState.clientNoContextTakeover {
|
||||
try compressor.reset()
|
||||
}
|
||||
firstByte |= RSV1Mask
|
||||
} catch {
|
||||
//report error? We can just send the uncompressed frame.
|
||||
}
|
||||
}
|
||||
let dataLength = data.count
|
||||
var dataBuffer = Data(capacity: dataLength + MaxFrameSize)
|
||||
|
||||
let frame = dataBuffer.withUnsafeMutableBytes { (buffer: UnsafeMutablePointer<UInt8>) -> Data in
|
||||
buffer[0] = firstByte
|
||||
if dataLength < 126 {
|
||||
buffer[1] = CUnsignedChar(dataLength)
|
||||
} else if dataLength <= Int(UInt16.max) {
|
||||
buffer[1] = 126
|
||||
WSMessageParser.writeUint16(buffer, offset: offset, value: UInt16(dataLength))
|
||||
offset += MemoryLayout<UInt16>.size
|
||||
} else {
|
||||
buffer[1] = 127
|
||||
WSMessageParser.writeUint64(buffer, offset: offset, value: UInt64(dataLength))
|
||||
offset += MemoryLayout<UInt64>.size
|
||||
}
|
||||
buffer[1] |= 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
|
||||
}
|
||||
return Data(bytes: buffer, count: offset)
|
||||
}
|
||||
return frame
|
||||
}
|
||||
|
||||
func reset() {
|
||||
queue.async { [weak self] in
|
||||
self?.didHandshake = false
|
||||
}
|
||||
}
|
||||
|
||||
///MARK: - parsing methods
|
||||
|
||||
/// read from the input queue until it is empty
|
||||
private func dequeue() {
|
||||
while !inputQueue.isEmpty {
|
||||
autoreleasepool {
|
||||
let data = inputQueue.removeFirst()
|
||||
var work = data
|
||||
if let buffer = fragBuffer {
|
||||
var combine = buffer
|
||||
combine.append(data)
|
||||
work = combine
|
||||
fragBuffer = nil
|
||||
}
|
||||
let length = work.count
|
||||
work.withUnsafeBytes { (buffer: UnsafePointer<UInt8>) in
|
||||
if !didHandshake {
|
||||
processTCPHandshake(buffer, bufferLen: length)
|
||||
} else {
|
||||
processRawMessagesInBuffer(buffer, bufferLen: length)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 >= frameHeaderLength
|
||||
if buffer.count > 0 {
|
||||
fragBuffer = Data(buffer: buffer)
|
||||
}
|
||||
}
|
||||
|
||||
/// process the raw data buffer and parse it into the websocket frames it represents
|
||||
private func processOneRawMessage(inBuffer buffer: UnsafeBufferPointer<UInt8>) -> UnsafeBufferPointer<UInt8> {
|
||||
guard let baseAddress = buffer.baseAddress else {return emptyBuffer}
|
||||
let bytesAvailable = buffer.count
|
||||
|
||||
//need at least two bytes to know what kind of frame it is.
|
||||
if readStack.last != nil && bytesAvailable < frameHeaderLength {
|
||||
fragBuffer = Data(buffer: buffer)
|
||||
return emptyBuffer
|
||||
}
|
||||
|
||||
//handle the current frame
|
||||
if let currentFrame = readStack.last, currentFrame.bytesLeft > 0 {
|
||||
var appendLength = currentFrame.bytesLeft
|
||||
var extraLength = bytesAvailable - currentFrame.bytesLeft
|
||||
|
||||
//this frame still needs more content before it is full
|
||||
let isPartialFrame = currentFrame.bytesLeft > bytesAvailable
|
||||
if isPartialFrame {
|
||||
appendLength = bytesAvailable
|
||||
extraLength = 0 //update for the offset
|
||||
}
|
||||
|
||||
//build buffer
|
||||
var combine = currentFrame.data
|
||||
combine.append(baseAddress, count: appendLength)
|
||||
|
||||
_ = readStack.popLast()
|
||||
if isPartialFrame {
|
||||
readStack.append(WSFrame(code: currentFrame.code, bytesLeft: currentFrame.bytesLeft - appendLength, data: combine))
|
||||
} else {
|
||||
delegate?.didReceive(message: WSMessage(code: currentFrame.code, data: combine))
|
||||
}
|
||||
return buffer.fromOffset(bytesAvailable - extraLength)
|
||||
}
|
||||
|
||||
//new frame!
|
||||
let isFin = (FinMask & baseAddress[0])
|
||||
let receivedOpcodeRawValue = (OpCodeMask & baseAddress[0])
|
||||
let receivedOpcode = WebSocket.OpCode(rawValue: receivedOpcodeRawValue)
|
||||
let isMasked = (MaskMask & baseAddress[1])
|
||||
let payloadLen = (PayloadLenMask & baseAddress[1])
|
||||
var offset = frameHeaderLength //skip past the control opcodes of the frame
|
||||
|
||||
//validate the frame is proper frame
|
||||
if compressionState.supportsCompression && receivedOpcode != .continueFrame {
|
||||
compressionState.messageNeedsDecompression = (RSV1Mask & baseAddress[0]) > 0
|
||||
}
|
||||
|
||||
if (isMasked > 0 || (RSVMask & baseAddress[0]) > 0) && receivedOpcode != .pong && !compressionState.messageNeedsDecompression {
|
||||
delegate?.didEncounter(error: WSError(type: .protocolError, message: "masked and rsv data is not currently supported", code: CloseCode.protocolError.rawValue))
|
||||
return emptyBuffer
|
||||
}
|
||||
let isControlFrame = (receivedOpcode == .connectionClose || receivedOpcode == .ping)
|
||||
if !isControlFrame && (receivedOpcode != .binary && receivedOpcode != .continueFrame &&
|
||||
receivedOpcode != .text && receivedOpcode != .pong) {
|
||||
delegate?.didEncounter(error: WSError(type: .protocolError, message: "unknown opcode: \(receivedOpcodeRawValue)", code: CloseCode.protocolError.rawValue))
|
||||
return emptyBuffer
|
||||
}
|
||||
if isControlFrame && isFin == 0 {
|
||||
delegate?.didEncounter(error: WSError(type: .protocolError, message: "control frames can't be fragmented", code: CloseCode.protocolError.rawValue))
|
||||
return emptyBuffer
|
||||
}
|
||||
|
||||
//process the close code
|
||||
var closeCode = CloseCode.normal.rawValue
|
||||
if receivedOpcode == .connectionClose {
|
||||
if payloadLen == 1 {
|
||||
closeCode = CloseCode.protocolError.rawValue
|
||||
} else if payloadLen > 1 {
|
||||
closeCode = WSMessageParser.readUint16(baseAddress, offset: offset)
|
||||
if closeCode < 1000 || (closeCode > 1003 && closeCode < 1007) || (closeCode > 1013 && closeCode < 3000) {
|
||||
closeCode = CloseCode.protocolError.rawValue
|
||||
}
|
||||
}
|
||||
if payloadLen < 2 {
|
||||
delegate?.didEncounter(error: WSError(type: .expectedClose, message: "connection closed by server", code: closeCode))
|
||||
return emptyBuffer
|
||||
}
|
||||
} else if isControlFrame && payloadLen > 125 {
|
||||
delegate?.didEncounter(error: WSError(type: .protocolError, message: "control frame using extend payload", code: CloseCode.protocolError.rawValue))
|
||||
return emptyBuffer
|
||||
}
|
||||
|
||||
//handle the "body" of the message
|
||||
var dataLength = UInt64(payloadLen)
|
||||
if dataLength == 127 {
|
||||
dataLength = WSMessageParser.readUint64(baseAddress, offset: offset)
|
||||
offset += MemoryLayout<UInt64>.size
|
||||
} else if dataLength == 126 {
|
||||
dataLength = UInt64(WSMessageParser.readUint16(baseAddress, offset: offset))
|
||||
offset += MemoryLayout<UInt16>.size
|
||||
}
|
||||
if bytesAvailable < offset || UInt64(bytesAvailable - offset) < dataLength {
|
||||
fragBuffer = Data(bytes: baseAddress, count: bytesAvailable)
|
||||
return emptyBuffer
|
||||
}
|
||||
var appendLength = dataLength
|
||||
if dataLength > UInt64(bytesAvailable) {
|
||||
appendLength = UInt64(bytesAvailable-offset)
|
||||
}
|
||||
if receivedOpcode == .connectionClose && appendLength > 0 {
|
||||
let size = MemoryLayout<UInt16>.size
|
||||
offset += size
|
||||
appendLength -= UInt64(size)
|
||||
}
|
||||
|
||||
let data: Data
|
||||
if compressionState.messageNeedsDecompression, let decompressor = compressionState.decompressor {
|
||||
do {
|
||||
data = try decompressor.decompress(bytes: baseAddress+offset, count: Int(appendLength), finish: isFin > 0)
|
||||
if isFin > 0 && compressionState.serverNoContextTakeover {
|
||||
try decompressor.reset()
|
||||
}
|
||||
} catch {
|
||||
delegate?.didEncounter(error: WSError(type: .protocolError, message: "Decompression failed: \(error)", code: CloseCode.protocolError.rawValue))
|
||||
return emptyBuffer
|
||||
}
|
||||
} else {
|
||||
data = Data(bytes: baseAddress+offset, count: Int(appendLength))
|
||||
}
|
||||
|
||||
//handle frames by opcodes
|
||||
if receivedOpcode == .connectionClose {
|
||||
var closeReason = "connection closed by server"
|
||||
if let customCloseReason = String(data: data, encoding: .utf8) {
|
||||
closeReason = customCloseReason
|
||||
} else {
|
||||
closeCode = CloseCode.protocolError.rawValue
|
||||
}
|
||||
delegate?.didEncounter(error: WSError(type: .expectedClose, message: closeReason, code: closeCode))
|
||||
return emptyBuffer
|
||||
}
|
||||
if receivedOpcode == .pong || receivedOpcode == .ping {
|
||||
delegate?.didReceive(message: WSMessage(code: receivedOpcode!, data: data))
|
||||
return buffer.fromOffset(offset + Int(appendLength))
|
||||
}
|
||||
|
||||
if let currentFrame = readStack.last {
|
||||
//handle "old" frame
|
||||
if receivedOpcode != .continueFrame {
|
||||
delegate?.didEncounter(error: WSError(type: .protocolError, message: "second and beyond of fragment message must be a continue frame", code: CloseCode.protocolError.rawValue))
|
||||
return emptyBuffer
|
||||
}
|
||||
var combine = currentFrame.data
|
||||
combine.append(data)
|
||||
_ = readStack.popLast()
|
||||
readStack.append(WSFrame(code: currentFrame.code, bytesLeft: currentFrame.bytesLeft - Int(appendLength), data: combine))
|
||||
} else {
|
||||
//handle new frame
|
||||
if receivedOpcode == .continueFrame {
|
||||
delegate?.didEncounter(error: WSError(type: .protocolError, message: "first frame can't be a continue frame", code: CloseCode.protocolError.rawValue))
|
||||
return emptyBuffer
|
||||
}
|
||||
let left = dataLength - appendLength
|
||||
readStack.append(WSFrame(code: receivedOpcode!, bytesLeft: Int(left), data: data))
|
||||
}
|
||||
|
||||
//process response
|
||||
if let currentFrame = readStack.last, currentFrame.bytesLeft <= 0 && isFin > 0 {
|
||||
_ = readStack.popLast()
|
||||
delegate?.didReceive(message: WSMessage(code: currentFrame.code, data: currentFrame.data))
|
||||
}
|
||||
|
||||
let step = Int(offset + numericCast(appendLength))
|
||||
return buffer.fromOffset(step)
|
||||
}
|
||||
|
||||
///MARK: - TCP/HTTP handling
|
||||
|
||||
/// 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:
|
||||
delegate?.didEncounter(error: WSError(type: .upgradeError, message: "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 == 4 {
|
||||
totalSize = i + 1
|
||||
break
|
||||
}
|
||||
} else {
|
||||
k = 0
|
||||
}
|
||||
}
|
||||
if totalSize > 0 {
|
||||
let code = validateResponse(buffer, bufferLen: totalSize)
|
||||
if code != 0 {
|
||||
return code
|
||||
}
|
||||
didHandshake = true
|
||||
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 {
|
||||
guard let str = String(data: Data(bytes: buffer, count: bufferLen), encoding: .utf8) else { return -1 }
|
||||
let splitArr = str.components(separatedBy: "\r\n")
|
||||
var code = -1
|
||||
var i = 0
|
||||
var headers = [String: String]()
|
||||
for str in splitArr {
|
||||
if i == 0 {
|
||||
let responseSplit = str.components(separatedBy: .whitespaces)
|
||||
guard responseSplit.count > 1 else { return -1 }
|
||||
if let c = Int(responseSplit[1]) {
|
||||
code = c
|
||||
}
|
||||
} else {
|
||||
let responseSplit = str.components(separatedBy: ":")
|
||||
guard responseSplit.count > 1 else { break }
|
||||
let key = responseSplit[0].trimmingCharacters(in: .whitespaces)
|
||||
let val = responseSplit[1].trimmingCharacters(in: .whitespaces)
|
||||
headers[key.lowercased()] = val
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
|
||||
if code != httpSwitchProtocolCode {
|
||||
return code
|
||||
}
|
||||
|
||||
if let extensionHeader = headers[WebSocket.headerWSExtensionName.lowercased()] {
|
||||
processExtensionHeader(extensionHeader)
|
||||
}
|
||||
|
||||
if let acceptKey = headers[WebSocket.headerWSAcceptName.lowercased()] {
|
||||
if acceptKey.count > 0 {
|
||||
if headerSecKey.count > 0 {
|
||||
let sha = "\(headerSecKey)258EAFA5-E914-47DA-95CA-C5AB0DC85B11".sha1Base64()
|
||||
if sha != acceptKey as String {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
delegate?.didParseHTTP(response: str)
|
||||
return 0
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
|
||||
/// Parses the extension header, setting up the compression parameters.
|
||||
func processExtensionHeader(_ extensionHeader: String) {
|
||||
let parts = extensionHeader.components(separatedBy: ";")
|
||||
for p in parts {
|
||||
let part = p.trimmingCharacters(in: .whitespaces)
|
||||
if part == "permessage-deflate" {
|
||||
compressionState.supportsCompression = true
|
||||
} else if part.hasPrefix("server_max_window_bits=") {
|
||||
let valString = part.components(separatedBy: "=")[1]
|
||||
if let val = Int(valString.trimmingCharacters(in: .whitespaces)) {
|
||||
compressionState.serverMaxWindowBits = val
|
||||
}
|
||||
} else if part.hasPrefix("client_max_window_bits=") {
|
||||
let valString = part.components(separatedBy: "=")[1]
|
||||
if let val = Int(valString.trimmingCharacters(in: .whitespaces)) {
|
||||
compressionState.clientMaxWindowBits = val
|
||||
}
|
||||
} else if part == "client_no_context_takeover" {
|
||||
compressionState.clientNoContextTakeover = true
|
||||
} else if part == "server_no_context_takeover" {
|
||||
compressionState.serverNoContextTakeover = true
|
||||
}
|
||||
}
|
||||
if compressionState.supportsCompression {
|
||||
compressionState.decompressor = Decompressor(windowBits: compressionState.serverMaxWindowBits)
|
||||
compressionState.compressor = Compressor(windowBits: compressionState.clientMaxWindowBits)
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a WebSocket key as needed in RFC.
|
||||
static 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!
|
||||
}
|
||||
|
||||
/// 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.
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension UnsafeBufferPointer {
|
||||
func fromOffset(_ offset: Int) -> UnsafeBufferPointer<Element> {
|
||||
return UnsafeBufferPointer<Element>(start: baseAddress?.advanced(by: offset), count: count - offset)
|
||||
}
|
||||
}
|
||||
|
||||
private extension String {
|
||||
func sha1Base64() -> String {
|
||||
let data = self.data(using: String.Encoding.utf8)!
|
||||
var digest = [UInt8](repeating: 0, count:Int(CC_SHA1_DIGEST_LENGTH))
|
||||
data.withUnsafeBytes { _ = CC_SHA1($0, CC_LONG(data.count), &digest) }
|
||||
return Data(bytes: digest).base64EncodedString()
|
||||
}
|
||||
}
|
||||
+964
-275
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -1,6 +1,6 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "Starscream"
|
||||
s.version = "3.0.6"
|
||||
s.version = "3.1.1"
|
||||
s.summary = "A conforming WebSocket RFC 6455 client library in Swift."
|
||||
s.homepage = "https://github.com/daltoniam/Starscream"
|
||||
s.license = 'Apache License, Version 2.0'
|
||||
@@ -12,5 +12,5 @@ Pod::Spec.new do |s|
|
||||
s.tvos.deployment_target = '9.0'
|
||||
s.watchos.deployment_target = '2.0'
|
||||
s.source_files = 'Sources/**/*.swift'
|
||||
s.swift_version = '4.2'
|
||||
s.swift_version = '5.0'
|
||||
end
|
||||
|
||||
@@ -12,9 +12,7 @@
|
||||
335FA1FC1F5DF71D00F6D2EC /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D88EAF811ED4DFD3004FE2C3 /* libz.tbd */; };
|
||||
33CCF08A1F5DDC030099B092 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D88EAF811ED4DFD3004FE2C3 /* libz.tbd */; };
|
||||
33CCF08C1F5DDC030099B092 /* Starscream.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C1360001C473BEF00AA3A01 /* Starscream.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
633624AF219AD2F80053CB46 /* NetworkStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 633624AC219AD2F80053CB46 /* NetworkStream.swift */; };
|
||||
633624B0219AD2F80053CB46 /* FoundationStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 633624AD219AD2F80053CB46 /* FoundationStream.swift */; };
|
||||
633624B1219AD2F80053CB46 /* WSMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 633624AE219AD2F80053CB46 /* WSMessage.swift */; };
|
||||
48F1584221FBC1200093F06A /* Starscream.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 33CCF0921F5DDC030099B092 /* Starscream.framework */; };
|
||||
BBB5ABE5215E2217005B48B6 /* Compression.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBB5ABE1215E2217005B48B6 /* Compression.swift */; };
|
||||
BBB5ABE6215E2217005B48B6 /* SSLClientCertificate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBB5ABE2215E2217005B48B6 /* SSLClientCertificate.swift */; };
|
||||
BBB5ABE7215E2217005B48B6 /* SSLSecurity.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBB5ABE3215E2217005B48B6 /* SSLSecurity.swift */; };
|
||||
@@ -26,10 +24,6 @@
|
||||
33CCF0921F5DDC030099B092 /* Starscream.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Starscream.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
5C1360001C473BEF00AA3A01 /* Starscream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Starscream.h; path = Sources/Starscream.h; sourceTree = SOURCE_ROOT; };
|
||||
5C13600C1C473BFE00AA3A01 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Sources/Info.plist; sourceTree = SOURCE_ROOT; };
|
||||
633624AC219AD2F80053CB46 /* NetworkStream.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NetworkStream.swift; path = Starscream/NetworkStream.swift; sourceTree = "<group>"; };
|
||||
633624AD219AD2F80053CB46 /* FoundationStream.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FoundationStream.swift; path = Starscream/FoundationStream.swift; sourceTree = "<group>"; };
|
||||
633624AE219AD2F80053CB46 /* WSMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WSMessage.swift; path = Starscream/WSMessage.swift; sourceTree = "<group>"; };
|
||||
63895636219AD95900C3C085 /* TestConnection.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = TestConnection.playground; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
|
||||
6B3E7A0019D48C2F006071F7 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
742419BB1DC6BDBA003ACE43 /* StarscreamTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = StarscreamTests.swift; path = StarscreamTests/StarscreamTests.swift; sourceTree = "<group>"; };
|
||||
BBB5ABE1215E2217005B48B6 /* Compression.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Compression.swift; path = Starscream/Compression.swift; sourceTree = "<group>"; };
|
||||
@@ -45,6 +39,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
48F1584221FBC1200093F06A /* Starscream.framework in Frameworks */,
|
||||
335FA1FC1F5DF71D00F6D2EC /* libz.tbd in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -63,7 +58,6 @@
|
||||
6B3E79DC19D48B7F006071F7 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
63895636219AD95900C3C085 /* TestConnection.playground */,
|
||||
6B3E79E819D48B7F006071F7 /* Sources */,
|
||||
6B3E79FF19D48C2F006071F7 /* Tests */,
|
||||
6B3E79E719D48B7F006071F7 /* Products */,
|
||||
@@ -83,9 +77,6 @@
|
||||
6B3E79E819D48B7F006071F7 /* Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
633624AD219AD2F80053CB46 /* FoundationStream.swift */,
|
||||
633624AC219AD2F80053CB46 /* NetworkStream.swift */,
|
||||
633624AE219AD2F80053CB46 /* WSMessage.swift */,
|
||||
BBB5ABE1215E2217005B48B6 /* Compression.swift */,
|
||||
BBB5ABE2215E2217005B48B6 /* SSLClientCertificate.swift */,
|
||||
BBB5ABE3215E2217005B48B6 /* SSLSecurity.swift */,
|
||||
@@ -179,7 +170,7 @@
|
||||
attributes = {
|
||||
LastSwiftMigration = 0700;
|
||||
LastSwiftUpdateCheck = 0700;
|
||||
LastUpgradeCheck = 0900;
|
||||
LastUpgradeCheck = 1020;
|
||||
ORGANIZATIONNAME = Vluxe;
|
||||
TargetAttributes = {
|
||||
335FA1F41F5DF71D00F6D2EC = {
|
||||
@@ -187,7 +178,6 @@
|
||||
};
|
||||
33CCF0841F5DDC030099B092 = {
|
||||
LastSwiftMigration = 0940;
|
||||
ProvisioningStyle = Manual;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -196,6 +186,7 @@
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
English,
|
||||
en,
|
||||
);
|
||||
mainGroup = 6B3E79DC19D48B7F006071F7;
|
||||
@@ -242,11 +233,8 @@
|
||||
files = (
|
||||
BBB5ABE5215E2217005B48B6 /* Compression.swift in Sources */,
|
||||
BBB5ABE8215E2217005B48B6 /* WebSocket.swift in Sources */,
|
||||
633624B0219AD2F80053CB46 /* FoundationStream.swift in Sources */,
|
||||
633624B1219AD2F80053CB46 /* WSMessage.swift in Sources */,
|
||||
BBB5ABE7215E2217005B48B6 /* SSLSecurity.swift in Sources */,
|
||||
BBB5ABE6215E2217005B48B6 /* SSLClientCertificate.swift in Sources */,
|
||||
633624AF219AD2F80053CB46 /* NetworkStream.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -258,11 +246,6 @@
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = NO;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
@@ -272,12 +255,11 @@
|
||||
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.vluxe.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = "";
|
||||
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvos appletvsimulator macosx";
|
||||
SWIFT_INSTALL_OBJC_HEADER = NO;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
|
||||
SWIFT_VERSION = 4.0;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -286,22 +268,16 @@
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = NO;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(inherited)",
|
||||
);
|
||||
INFOPLIST_FILE = "$(SRCROOT)/Tests/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.vluxe.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = "";
|
||||
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvos appletvsimulator macosx";
|
||||
SWIFT_INSTALL_OBJC_HEADER = NO;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
|
||||
SWIFT_VERSION = 4.0;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@@ -310,11 +286,7 @@
|
||||
buildSettings = {
|
||||
BITCODE_GENERATION_MODE = marker;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
@@ -326,16 +298,11 @@
|
||||
OTHER_LDFLAGS = "-all_load";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.vluxe.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE = "";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SDKROOT = "";
|
||||
SKIP_INSTALL = YES;
|
||||
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx appletvsimulator appletvos watchos watchsimulator";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
|
||||
SWIFT_VERSION = 4.0;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TVOS_DEPLOYMENT_TARGET = 9.0;
|
||||
VALID_ARCHS = "x86_64 i386 arm64 armv7s armv7 armv7k";
|
||||
WATCHOS_DEPLOYMENT_TARGET = 2.0;
|
||||
};
|
||||
name = Debug;
|
||||
@@ -345,11 +312,7 @@
|
||||
buildSettings = {
|
||||
BITCODE_GENERATION_MODE = bitcode;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
@@ -361,16 +324,11 @@
|
||||
OTHER_LDFLAGS = "-all_load";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.vluxe.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE = "";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SDKROOT = "";
|
||||
SKIP_INSTALL = YES;
|
||||
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx appletvsimulator appletvos watchos watchsimulator";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
|
||||
SWIFT_VERSION = 4.0;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TVOS_DEPLOYMENT_TARGET = 9.0;
|
||||
VALID_ARCHS = "x86_64 i386 arm64 armv7s armv7 armv7k";
|
||||
WATCHOS_DEPLOYMENT_TARGET = 2.0;
|
||||
};
|
||||
name = Release;
|
||||
@@ -380,6 +338,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
@@ -388,12 +347,14 @@
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
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_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
@@ -401,7 +362,6 @@
|
||||
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;
|
||||
@@ -424,12 +384,10 @@
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = "";
|
||||
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx appletvos appletvsimulator watchsimulator watchos";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 4.0;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2,3,4";
|
||||
VALID_ARCHS = "x86_64 i386";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
@@ -440,6 +398,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
@@ -448,12 +407,14 @@
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
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_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
@@ -461,7 +422,6 @@
|
||||
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 = YES;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
@@ -476,12 +436,10 @@
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = "";
|
||||
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx appletvos appletvsimulator watchsimulator watchos";
|
||||
SWIFT_VERSION = 4.0;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2,3,4";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
VALID_ARCHS = "x86_64 i386";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0900"
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -26,9 +26,8 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
codeCoverageEnabled = "YES">
|
||||
codeCoverageEnabled = "YES"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
@@ -61,7 +60,6 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
import Starscream
|
||||
import PlaygroundSupport
|
||||
|
||||
PlaygroundPage.current.needsIndefiniteExecution = true
|
||||
|
||||
let websocket = WebSocket(request: URLRequest(url: URL(string: "ws://echo.websocket.org")!), stream: NetworkStream())
|
||||
|
||||
websocket.onConnect = {
|
||||
print("connected")
|
||||
|
||||
websocket.write(string: "Hello")
|
||||
}
|
||||
|
||||
websocket.onDisconnect = { error in
|
||||
print("error:", error)
|
||||
}
|
||||
|
||||
websocket.onText = { text in
|
||||
print(text)
|
||||
}
|
||||
|
||||
websocket.connect()
|
||||
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<playground version='5.0' target-platform='macos' executeOnSourceChanges='false'>
|
||||
<timeline fileName='timeline.xctimeline'/>
|
||||
</playground>
|
||||
@@ -1,55 +0,0 @@
|
||||
//
|
||||
// FakeStream.swift
|
||||
// Starscream
|
||||
//
|
||||
// Created by Dalton Cherry on 7/26/18.
|
||||
// Copyright © 2018 Vluxe. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class FakeStream: WSStream, TestServerDelegate {
|
||||
var delegate: WSStreamDelegate?
|
||||
let server: TestServer
|
||||
var buffer: Data?
|
||||
|
||||
init(server: TestServer) {
|
||||
self.server = server
|
||||
self.server.delegate = self
|
||||
}
|
||||
|
||||
func connect(url: URL, port: Int, timeout: TimeInterval, useSSL: Bool, completion: @escaping ((Error?) -> Void)) {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {
|
||||
self.server.start()
|
||||
completion(nil)
|
||||
})
|
||||
}
|
||||
|
||||
func write(data: Data, completion: @escaping ((Error?) -> Void)) {
|
||||
server.receive(data: data)
|
||||
}
|
||||
|
||||
func read() -> Data? {
|
||||
let data = buffer
|
||||
buffer = nil
|
||||
return data
|
||||
}
|
||||
|
||||
func cleanup() {
|
||||
buffer = nil
|
||||
}
|
||||
|
||||
func isValidSSLCertificate() -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
///MARK: - TestServerDelegate
|
||||
func didSend(data: Data) {
|
||||
if buffer != nil {
|
||||
buffer?.append(data)
|
||||
} else {
|
||||
buffer = data
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,55 +10,21 @@ import XCTest
|
||||
|
||||
class StarscreamTests: XCTestCase {
|
||||
|
||||
var socket: WebSocket!
|
||||
let testServer = TestServer()
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
let url = URL(string: "http://fakedomain.com")! //not a real request
|
||||
let req = URLRequest(url: url)
|
||||
let fakeStream = FakeStream(server: testServer)
|
||||
socket = WebSocket(request: req, protocols: nil, stream: fakeStream)
|
||||
// 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 runSocket() {
|
||||
socket.onText = { [weak self] (text: String) in
|
||||
self?.socket.write(string: text)
|
||||
}
|
||||
socket.onData = { [weak self] (data: Data) in
|
||||
self?.socket.write(data: data)
|
||||
}
|
||||
var once = false
|
||||
socket.onDisconnect = {[weak self] (error: Error?) in
|
||||
if !once {
|
||||
once = true
|
||||
let status = self?.testServer.passed ?? false
|
||||
if status {
|
||||
XCTAssert(true, "Pass")
|
||||
} else {
|
||||
XCTAssert(false, "Failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
socket.connect()
|
||||
}
|
||||
|
||||
func testExample() {
|
||||
// This is an example of a functional test case.
|
||||
XCTAssert(true, "Pass")
|
||||
}
|
||||
|
||||
// func testCase1() {
|
||||
// testServer.testCase = .case1
|
||||
// runSocket()
|
||||
// }
|
||||
|
||||
|
||||
|
||||
func testPerformanceExample() {
|
||||
// This is an example of a performance test case.
|
||||
self.measure() {
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
//
|
||||
// TestServer.swift
|
||||
// Starscream
|
||||
//
|
||||
// Created by Dalton Cherry on 7/26/18.
|
||||
// Copyright © 2018 Vluxe. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum TestCase {
|
||||
case case1
|
||||
case case2
|
||||
}
|
||||
|
||||
protocol TestServerDelegate: class {
|
||||
func didSend(data: Data)
|
||||
}
|
||||
|
||||
class TestServer {
|
||||
var testCase: TestCase?
|
||||
weak var delegate: TestServerDelegate?
|
||||
var buffer = Data()
|
||||
var passed = false
|
||||
|
||||
func start() {
|
||||
guard let testCase = testCase else { return }
|
||||
switch testCase {
|
||||
case .case1:
|
||||
case1()
|
||||
case .case2:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
func receive(data: Data) {
|
||||
buffer.append(data)
|
||||
}
|
||||
|
||||
func cleanup() {
|
||||
buffer = Data()
|
||||
}
|
||||
|
||||
//MARK: - the cases!
|
||||
|
||||
func case1() {
|
||||
//TODO: Websocket server framing
|
||||
//let data = "".data(using: .utf8)!
|
||||
//delegate?.didSend(data: frame)
|
||||
}
|
||||
}
|
||||
@@ -3,4 +3,4 @@
|
||||
set -o pipefail && xcodebuild -project Starscream.xcodeproj -scheme Starscream CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO clean build | xcpretty
|
||||
swift build
|
||||
pod repo update
|
||||
pod lib lint --verbose
|
||||
pod lib lint --verbose --allow-warnings
|
||||
|
||||
@@ -31,19 +31,47 @@
|
||||
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 = 33CCF0841F5DDC030099B092;
|
||||
remoteGlobalIDString = 6B3E79E519D48B7F006071F7;
|
||||
remoteInfo = Starscream;
|
||||
};
|
||||
5CF15740210A738400869246 /* PBXContainerItemProxy */ = {
|
||||
5C42C3D51D8DF51C00947AA2 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 5C178E411B62D0EF00A97204 /* Starscream.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 335FA2021F5DF71D00F6D2EC;
|
||||
remoteInfo = "Starscream Tests";
|
||||
remoteGlobalIDString = 091277971BD673A70003036D;
|
||||
remoteInfo = "Starscream tvOS";
|
||||
};
|
||||
5C42C3D71D8DF51C00947AA2 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 5C178E411B62D0EF00A97204 /* Starscream.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 091277A01BD673A70003036D;
|
||||
remoteInfo = "Starscream tvOSTests";
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
@@ -141,7 +169,11 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5C178E491B62D0EF00A97204 /* Starscream.framework */,
|
||||
5CF15741210A738400869246 /* Starscream Tests.xctest */,
|
||||
5C178E4B1B62D0EF00A97204 /* StarscreamTests.xctest */,
|
||||
5C178E4D1B62D0EF00A97204 /* Starscream.framework */,
|
||||
5C178E4F1B62D0EF00A97204 /* StarscreamOSXTests.xctest */,
|
||||
5C42C3D61D8DF51C00947AA2 /* Starscream.framework */,
|
||||
5C42C3D81D8DF51C00947AA2 /* Starscream tvOSTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -198,11 +230,11 @@
|
||||
TargetAttributes = {
|
||||
5C178E1B1B62D0B900A97204 = {
|
||||
CreatedOnToolsVersion = 6.4;
|
||||
LastSwiftMigration = 1000;
|
||||
LastSwiftMigration = 0800;
|
||||
};
|
||||
5C178E301B62D0B900A97204 = {
|
||||
CreatedOnToolsVersion = 6.4;
|
||||
LastSwiftMigration = 1000;
|
||||
LastSwiftMigration = 0800;
|
||||
TestTargetID = 5C178E1B1B62D0B900A97204;
|
||||
};
|
||||
};
|
||||
@@ -240,11 +272,39 @@
|
||||
remoteRef = 5C178E481B62D0EF00A97204 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
5CF15741210A738400869246 /* Starscream Tests.xctest */ = {
|
||||
5C178E4B1B62D0EF00A97204 /* StarscreamTests.xctest */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.cfbundle;
|
||||
path = "Starscream Tests.xctest";
|
||||
remoteRef = 5CF15740210A738400869246 /* PBXContainerItemProxy */;
|
||||
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 */
|
||||
@@ -409,12 +469,10 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
INFOPLIST_FILE = Autobahn/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = On;
|
||||
SWIFT_VERSION = 4.2;
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -422,12 +480,10 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
INFOPLIST_FILE = Autobahn/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = On;
|
||||
SWIFT_VERSION = 4.2;
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@@ -446,8 +502,7 @@
|
||||
INFOPLIST_FILE = AutobahnTests/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = On;
|
||||
SWIFT_VERSION = 4.2;
|
||||
SWIFT_VERSION = 3.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Autobahn.app/Autobahn";
|
||||
};
|
||||
name = Debug;
|
||||
@@ -463,8 +518,7 @@
|
||||
INFOPLIST_FILE = AutobahnTests/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = On;
|
||||
SWIFT_VERSION = 4.2;
|
||||
SWIFT_VERSION = 3.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Autobahn.app/Autobahn";
|
||||
};
|
||||
name = Release;
|
||||
|
||||
@@ -14,7 +14,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
var window: UIWindow?
|
||||
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
|
||||
// Override point for customization after application launch.
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -13,12 +13,11 @@ class ViewController: UIViewController {
|
||||
|
||||
let host = "localhost:9001"
|
||||
var socketArray = [WebSocket]()
|
||||
var caseCount = 320 //starting cases
|
||||
var caseCount = 300 //starting cases
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
getCaseCount()
|
||||
//getTestInfo(1)
|
||||
//runTest(1)
|
||||
}
|
||||
|
||||
func removeSocket(_ s: WebSocket?) {
|
||||
@@ -27,7 +26,7 @@ class ViewController: UIViewController {
|
||||
|
||||
func getCaseCount() {
|
||||
|
||||
let s = WebSocket(url: URL(string: "ws://\(host)/getCaseCount")!, protocols: [], stream: FoundationStream()) //NetworkStream
|
||||
let s = WebSocket(url: URL(string: "ws://\(host)/getCaseCount")!, protocols: [])
|
||||
socketArray.append(s)
|
||||
s.onText = { [weak self] (text: String) in
|
||||
if let c = Int(text) {
|
||||
@@ -99,12 +98,6 @@ class ViewController: UIViewController {
|
||||
}
|
||||
}
|
||||
s.connect()
|
||||
//timeout
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 480, execute: {
|
||||
if !once {
|
||||
s.disconnect(forceTimeout: 0, closeCode: CloseCode.normal.rawValue)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func verifyTest(_ caseNum: Int) {
|
||||
@@ -156,7 +149,7 @@ class ViewController: UIViewController {
|
||||
}
|
||||
|
||||
func createSocket(_ cmd: String, _ caseNum: Int) -> WebSocket {
|
||||
return WebSocket(url: URL(string: "ws://\(host)\(buildPath(cmd,caseNum))")!, protocols: [], stream: FoundationStream()) //NetworkStream
|
||||
return WebSocket(url: URL(string: "ws://\(host)\(buildPath(cmd,caseNum))")!, protocols: [])
|
||||
}
|
||||
|
||||
func buildPath(_ cmd: String, _ caseNum: Int) -> String {
|
||||
|
||||
BIN
Binary file not shown.
@@ -19,7 +19,7 @@ EM.run {
|
||||
|
||||
ws.onmessage { |msg|
|
||||
puts "message from client: #{msg}"
|
||||
ws.send Faker::Hacker.say_something_smart
|
||||
ws.send +Faker::Hacker.say_something_smart
|
||||
}
|
||||
end
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@ EXTERNAL SOURCES:
|
||||
:path: "../../"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Starscream: ef3ece99d765eeccb67de105bfa143f929026cf5
|
||||
Starscream: 96cd79a6b7ef6a2ff2d00638c73bd195a5322586
|
||||
|
||||
PODFILE CHECKSUM: 96d91933fe13671aaa81af8a8675ff7698068845
|
||||
|
||||
COCOAPODS: 1.6.0.beta.2
|
||||
COCOAPODS: 1.6.0.beta.1
|
||||
|
||||
+2
-2
@@ -9,8 +9,8 @@ EXTERNAL SOURCES:
|
||||
:path: "../../"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Starscream: ef3ece99d765eeccb67de105bfa143f929026cf5
|
||||
Starscream: 96cd79a6b7ef6a2ff2d00638c73bd195a5322586
|
||||
|
||||
PODFILE CHECKSUM: 96d91933fe13671aaa81af8a8675ff7698068845
|
||||
|
||||
COCOAPODS: 1.6.0.beta.2
|
||||
COCOAPODS: 1.6.0.beta.1
|
||||
|
||||
+1
-210
@@ -1,214 +1,5 @@
|
||||
<?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>PreferenceSpecifiers</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>This application makes use of the following third party libraries:</string>
|
||||
<key>Title</key>
|
||||
<string>Acknowledgements</string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string> 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.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
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.</string>
|
||||
<key>License</key>
|
||||
<string>Apache License, Version 2.0</string>
|
||||
<key>Title</key>
|
||||
<string>Starscream</string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>Generated by CocoaPods - https://cocoapods.org</string>
|
||||
<key>Title</key>
|
||||
<string></string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>StringsTable</key>
|
||||
<string>Acknowledgements</string>
|
||||
<key>Title</key>
|
||||
<string>Acknowledgements</string>
|
||||
</dict>
|
||||
<string></string>
|
||||
</plist>
|
||||
|
||||
+7
-12
@@ -3,15 +3,10 @@ set -e
|
||||
set -u
|
||||
set -o pipefail
|
||||
|
||||
function on_error {
|
||||
echo "$(realpath -mq "${0}"):$1: error: Unexpected failure"
|
||||
}
|
||||
trap 'on_error $LINENO' ERR
|
||||
|
||||
if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then
|
||||
# If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy
|
||||
# frameworks to, so exit 0 (signalling the script phase was successful).
|
||||
exit 0
|
||||
# If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy
|
||||
# frameworks to, so exit 0 (signalling the script phase was successful).
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
|
||||
@@ -41,8 +36,8 @@ install_framework()
|
||||
local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
|
||||
|
||||
if [ -L "${source}" ]; then
|
||||
echo "Symlinked..."
|
||||
source="$(readlink "${source}")"
|
||||
echo "Symlinked..."
|
||||
source="$(readlink "${source}")"
|
||||
fi
|
||||
|
||||
# Use filter instead of exclude so missing patterns don't throw errors.
|
||||
@@ -72,7 +67,7 @@ install_framework()
|
||||
# Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
|
||||
if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
|
||||
local swift_runtime_libs
|
||||
swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u)
|
||||
swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]})
|
||||
for lib in $swift_runtime_libs; do
|
||||
echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
|
||||
rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
|
||||
@@ -141,7 +136,7 @@ strip_invalid_archs() {
|
||||
for arch in $binary_archs; do
|
||||
if ! [[ "${ARCHS}" == *"$arch"* ]]; then
|
||||
# Strip non-valid architectures in-place
|
||||
lipo -remove "$arch" -output "$binary" "$binary"
|
||||
lipo -remove "$arch" -output "$binary" "$binary" || exit 1
|
||||
stripped="$stripped $arch"
|
||||
fi
|
||||
done
|
||||
|
||||
+1
-1
@@ -1,8 +1,8 @@
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Starscream"
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Starscream/Starscream.framework/Headers"
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
|
||||
OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/Starscream/Starscream.framework/Headers"
|
||||
OTHER_LDFLAGS = $(inherited) -framework "Starscream"
|
||||
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
|
||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||
|
||||
+1
-1
@@ -1,8 +1,8 @@
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Starscream"
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Starscream/Starscream.framework/Headers"
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
|
||||
OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/Starscream/Starscream.framework/Headers"
|
||||
OTHER_LDFLAGS = $(inherited) -framework "Starscream"
|
||||
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
|
||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||
|
||||
@@ -11,20 +11,7 @@ import UIKit
|
||||
import Starscream
|
||||
|
||||
class ViewController: UIViewController, WebSocketDelegate {
|
||||
func websocketIsWaitingForConnectivity(socket: WebSocketClient) {
|
||||
|
||||
}
|
||||
|
||||
func websocket(_ socket: WebSocketClient, isPathViable: Bool) {
|
||||
|
||||
}
|
||||
|
||||
func websocket(_ socket: WebSocketClient, isBetterPathAvailable: Bool) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
// var socket: WebSocket = WebSocket(url: URL(staticString: "wss://echo.websocket.org"), stream: NetworkStream())
|
||||
var socket: WebSocket = WebSocket(url: URL(staticString: "wss://echo.websocket.org"))
|
||||
|
||||
func websocketDidConnect(socket: WebSocketClient) {
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ default_platform(:ios)
|
||||
update_fastlane
|
||||
|
||||
platform :ios do
|
||||
desc "Depoy new version"
|
||||
desc "Deploy new version"
|
||||
lane :release do
|
||||
ensure_git_branch
|
||||
version = version_get_podspec(path: "Starscream.podspec")
|
||||
|
||||
Reference in New Issue
Block a user