Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 13859364e3 | |||
| 41c0c5e08b | |||
| 60b27a4388 | |||
| a68bf7c35b | |||
| 33a4551f3b | |||
| b22fae407e | |||
| e9160df255 | |||
| c63e173021 | |||
| ddcc30d200 | |||
| 6bacb6f972 | |||
| aca2ad5332 | |||
| 3ba1963c65 | |||
| 3cc4a60e05 | |||
| 14313df360 | |||
| 162c1d53b8 | |||
| b404f98244 | |||
| 8d0c0c1afa | |||
| 816fe413a4 | |||
| 5cc0d860ba | |||
| 4d2f8dbfee | |||
| 126c021e61 |
@@ -2,6 +2,17 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
`Starscream` adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
#### [2.0.3](https://github.com/daltoniam/Starscream/tree/2.0.3)
|
||||
|
||||
[#302](https://github.com/daltoniam/Starscream/issues/302)
|
||||
[#301](https://github.com/daltoniam/Starscream/issues/301)
|
||||
[#300](https://github.com/daltoniam/Starscream/issues/300)
|
||||
[#296](https://github.com/daltoniam/Starscream/issues/296)
|
||||
[#294](https://github.com/daltoniam/Starscream/issues/294)
|
||||
[#292](https://github.com/daltoniam/Starscream/issues/292)
|
||||
[#289](https://github.com/daltoniam/Starscream/issues/289)
|
||||
[#288](https://github.com/daltoniam/Starscream/issues/288)
|
||||
|
||||
#### [2.0.2](https://github.com/daltoniam/Starscream/tree/2.0.2)
|
||||
|
||||
Fix for the Swift Package Manager.
|
||||
|
||||
@@ -11,10 +11,6 @@ It's Objective-C counter part can be found here: [Jetfire](https://github.com/ac
|
||||
- TLS/WSS support.
|
||||
- Simple concise codebase at just a few hundred LOC.
|
||||
|
||||
## Swift 2.3
|
||||
|
||||
See release/tag 1.1.4 for Swift 2.3 support.
|
||||
|
||||
## Example
|
||||
|
||||
First thing is to import the framework. See the Installation instructions on how to add the framework to your project.
|
||||
@@ -231,7 +227,7 @@ To use Starscream in your project add the following 'Podfile' to your project
|
||||
platform :ios, '9.0'
|
||||
use_frameworks!
|
||||
|
||||
pod 'Starscream', '~> 2.0.0'
|
||||
pod 'Starscream', '~> 2.0.3'
|
||||
|
||||
Then run:
|
||||
|
||||
@@ -253,7 +249,7 @@ $ brew install carthage
|
||||
To integrate Starscream into your Xcode project using Carthage, specify it in your `Cartfile`:
|
||||
|
||||
```
|
||||
github "daltoniam/Starscream" >= 2.0.0
|
||||
github "daltoniam/Starscream" >= 2.0.3
|
||||
```
|
||||
|
||||
### Rogue
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.0.2</string>
|
||||
<string>2.0.3</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.0.2</string>
|
||||
<string>2.0.3</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
||||
+64
-38
@@ -167,6 +167,11 @@ open class WebSocket : NSObject, StreamDelegate {
|
||||
public init(url: URL, protocols: [String]? = nil) {
|
||||
self.url = url
|
||||
self.origin = url.absoluteString
|
||||
if let hostUrl = URL (string: "/", relativeTo: url) {
|
||||
var origin = hostUrl.absoluteString
|
||||
origin.remove(at: origin.index(before: origin.endIndex))
|
||||
self.origin = origin
|
||||
}
|
||||
writeQueue.maxConcurrentOperationCount = 1
|
||||
optionalProtocols = protocols
|
||||
}
|
||||
@@ -180,12 +185,11 @@ open class WebSocket : NSObject, StreamDelegate {
|
||||
/**
|
||||
Connect to the WebSocket server on a background thread.
|
||||
*/
|
||||
public func connect() {
|
||||
open func connect() {
|
||||
guard !isConnecting else { return }
|
||||
didDisconnect = false
|
||||
isConnecting = true
|
||||
createHTTPRequest()
|
||||
isConnecting = false
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -198,7 +202,8 @@ open class WebSocket : NSObject, StreamDelegate {
|
||||
- Parameter forceTimeout: Maximum time to wait for the server to close the socket.
|
||||
- Parameter closeCode: The code to send on disconnect. The default is the normal close code for cleanly disconnecting a webSocket.
|
||||
*/
|
||||
public func disconnect(forceTimeout: TimeInterval? = nil, closeCode: UInt16 = CloseCode.normal.rawValue) {
|
||||
open func disconnect(forceTimeout: TimeInterval? = nil, closeCode: UInt16 = CloseCode.normal.rawValue) {
|
||||
guard isConnected else { return }
|
||||
switch forceTimeout {
|
||||
case .some(let seconds) where seconds > 0:
|
||||
let milliseconds = Int(seconds * 1_000)
|
||||
@@ -222,7 +227,7 @@ open class WebSocket : NSObject, StreamDelegate {
|
||||
- parameter string: The string to write.
|
||||
- parameter completion: The (optional) completion handler.
|
||||
*/
|
||||
public func write(string: String, completion: (() -> ())? = nil) {
|
||||
open func write(string: String, completion: (() -> ())? = nil) {
|
||||
guard isConnected else { return }
|
||||
dequeueWrite(string.data(using: String.Encoding.utf8)!, code: .textFrame, writeCompletion: completion)
|
||||
}
|
||||
@@ -235,7 +240,7 @@ open class WebSocket : NSObject, StreamDelegate {
|
||||
- parameter data: The data to write.
|
||||
- parameter completion: The (optional) completion handler.
|
||||
*/
|
||||
public func write(data: Data, completion: (() -> ())? = nil) {
|
||||
open func write(data: Data, completion: (() -> ())? = nil) {
|
||||
guard isConnected else { return }
|
||||
dequeueWrite(data, code: .binaryFrame, writeCompletion: completion)
|
||||
}
|
||||
@@ -244,7 +249,7 @@ open class WebSocket : NSObject, StreamDelegate {
|
||||
Write a ping to the websocket. This sends it as a control frame.
|
||||
Yodel a sound to the planet. This sends it as an astroid. http://youtu.be/Eu5ZJELRiJ8?t=42s
|
||||
*/
|
||||
public func write(ping: Data, completion: (() -> ())? = nil) {
|
||||
open func write(ping: Data, completion: (() -> ())? = nil) {
|
||||
guard isConnected else { return }
|
||||
dequeueWrite(ping, code: .ping, writeCompletion: completion)
|
||||
}
|
||||
@@ -314,6 +319,9 @@ open class WebSocket : NSObject, StreamDelegate {
|
||||
//higher level API we will cut over to at some point
|
||||
//NSStream.getStreamsToHostWithName(url.host, port: url.port.integerValue, inputStream: &inputStream, outputStream: &outputStream)
|
||||
|
||||
// Disconnect and clean up any existing streams before setting up a new pair
|
||||
disconnectStream(nil, runDelegate: false)
|
||||
|
||||
var readStream: Unmanaged<CFReadStream>?
|
||||
var writeStream: Unmanaged<CFWriteStream>?
|
||||
let h = url.host! as NSString
|
||||
@@ -367,9 +375,12 @@ open class WebSocket : NSObject, StreamDelegate {
|
||||
|
||||
let bytes = UnsafeRawPointer((data as NSData).bytes).assumingMemoryBound(to: UInt8.self)
|
||||
var out = timeout * 1_000_000 // wait 5 seconds before giving up
|
||||
writeQueue.addOperation { [weak self] in
|
||||
while !outStream.hasSpaceAvailable {
|
||||
let operation = BlockOperation()
|
||||
operation.addExecutionBlock { [weak self, weak operation] in
|
||||
guard let sOperation = operation else { return }
|
||||
while !outStream.hasSpaceAvailable && !sOperation.isCancelled {
|
||||
usleep(100) // wait until the socket is ready
|
||||
guard !sOperation.isCancelled else { return }
|
||||
out -= 100
|
||||
if out < 0 {
|
||||
self?.cleanupStream()
|
||||
@@ -379,14 +390,16 @@ open class WebSocket : NSObject, StreamDelegate {
|
||||
return // disconnectStream will be called.
|
||||
}
|
||||
}
|
||||
guard !sOperation.isCancelled else { return }
|
||||
outStream.write(bytes, maxLength: data.count)
|
||||
}
|
||||
writeQueue.addOperation(operation)
|
||||
}
|
||||
|
||||
/**
|
||||
Delegate for the stream methods. Processes incoming bytes
|
||||
*/
|
||||
public func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
|
||||
open func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
|
||||
if let sec = security, !certValidated && [.hasBytesAvailable, .hasSpaceAvailable].contains(eventCode) {
|
||||
let trust = aStream.property(forKey: kCFStreamPropertySSLPeerTrust as Stream.PropertyKey) as! SecTrust
|
||||
let domain = aStream.property(forKey: kCFStreamSSLPeerName as Stream.PropertyKey) as? String
|
||||
@@ -412,14 +425,17 @@ open class WebSocket : NSObject, StreamDelegate {
|
||||
/**
|
||||
Disconnect the stream object and notifies the delegate.
|
||||
*/
|
||||
private func disconnectStream(_ error: NSError?) {
|
||||
private func disconnectStream(_ error: NSError?, runDelegate: Bool = true) {
|
||||
if error == nil {
|
||||
writeQueue.waitUntilAllOperationsAreFinished()
|
||||
} else {
|
||||
writeQueue.cancelAllOperations()
|
||||
}
|
||||
cleanupStream()
|
||||
doDisconnect(error)
|
||||
connected = false
|
||||
if runDelegate {
|
||||
doDisconnect(error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -438,6 +454,7 @@ open class WebSocket : NSObject, StreamDelegate {
|
||||
}
|
||||
outputStream = nil
|
||||
inputStream = nil
|
||||
fragBuffer = nil
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -463,22 +480,24 @@ open class WebSocket : NSObject, StreamDelegate {
|
||||
*/
|
||||
private func dequeueInput() {
|
||||
while !inputQueue.isEmpty {
|
||||
let data = inputQueue[0]
|
||||
var work = data
|
||||
if let fragBuffer = fragBuffer {
|
||||
var combine = NSData(data: fragBuffer) as Data
|
||||
combine.append(data)
|
||||
work = combine
|
||||
self.fragBuffer = nil
|
||||
autoreleasepool {
|
||||
let data = inputQueue[0]
|
||||
var work = data
|
||||
if let buffer = fragBuffer {
|
||||
var combine = NSData(data: buffer) as Data
|
||||
combine.append(data)
|
||||
work = combine
|
||||
fragBuffer = nil
|
||||
}
|
||||
let buffer = UnsafeRawPointer((work as NSData).bytes).assumingMemoryBound(to: UInt8.self)
|
||||
let length = work.count
|
||||
if !connected {
|
||||
processTCPHandshake(buffer, bufferLen: length)
|
||||
} else {
|
||||
processRawMessagesInBuffer(buffer, bufferLen: length)
|
||||
}
|
||||
inputQueue = inputQueue.filter{ $0 != data }
|
||||
}
|
||||
let buffer = UnsafeRawPointer((work as NSData).bytes).assumingMemoryBound(to: UInt8.self)
|
||||
let length = work.count
|
||||
if !connected {
|
||||
processTCPHandshake(buffer, bufferLen: length)
|
||||
} else {
|
||||
processRawMessagesInBuffer(buffer, bufferLen: length)
|
||||
}
|
||||
inputQueue = inputQueue.filter{ $0 != data }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -489,17 +508,10 @@ open class WebSocket : NSObject, StreamDelegate {
|
||||
let code = processHTTP(buffer, bufferLen: bufferLen)
|
||||
switch code {
|
||||
case 0:
|
||||
connected = true
|
||||
guard canDispatch else {return}
|
||||
callbackQueue.async { [weak self] in
|
||||
guard let s = self else { return }
|
||||
s.onConnect?()
|
||||
s.delegate?.websocketDidConnect(socket: s)
|
||||
s.notificationCenter.post(name: NSNotification.Name(WebsocketDidConnectNotification), object: self)
|
||||
}
|
||||
break
|
||||
case -1:
|
||||
fragBuffer = Data(bytes: buffer, count: bufferLen)
|
||||
break // do nothing, we are going to collect more data
|
||||
break // do nothing, we are going to collect more data
|
||||
default:
|
||||
doDisconnect(errorWithDetail("Invalid HTTP upgrade", code: UInt16(code)))
|
||||
}
|
||||
@@ -528,6 +540,17 @@ open class WebSocket : NSObject, StreamDelegate {
|
||||
if code != 0 {
|
||||
return code
|
||||
}
|
||||
isConnecting = false
|
||||
connected = true
|
||||
didDisconnect = false
|
||||
if canDispatch {
|
||||
callbackQueue.async { [weak self] in
|
||||
guard let s = self else { return }
|
||||
s.onConnect?()
|
||||
s.delegate?.websocketDidConnect(socket: s)
|
||||
s.notificationCenter.post(name: NSNotification.Name(WebsocketDidConnectNotification), object: self)
|
||||
}
|
||||
}
|
||||
totalSize += 1 //skip the last \n
|
||||
let restSize = bufferLen - totalSize
|
||||
if restSize > 0 {
|
||||
@@ -835,9 +858,11 @@ open class WebSocket : NSObject, StreamDelegate {
|
||||
Used to write things to the stream
|
||||
*/
|
||||
private func dequeueWrite(_ data: Data, code: OpCode, writeCompletion: (() -> ())? = nil) {
|
||||
writeQueue.addOperation { [weak self] in
|
||||
let operation = BlockOperation()
|
||||
operation.addExecutionBlock { [weak self, weak operation] in
|
||||
//stream isn't ready, let's wait
|
||||
guard let s = self else { return }
|
||||
guard let sOperation = operation else { return }
|
||||
var offset = 2
|
||||
let dataLength = data.count
|
||||
let frame = NSMutableData(capacity: dataLength + s.MaxFrameSize)
|
||||
@@ -864,7 +889,7 @@ open class WebSocket : NSObject, StreamDelegate {
|
||||
offset += 1
|
||||
}
|
||||
var total = 0
|
||||
while true {
|
||||
while !sOperation.isCancelled {
|
||||
guard let outStream = s.outputStream else { break }
|
||||
let writeBuffer = UnsafeRawPointer(frame!.bytes+total).assumingMemoryBound(to: UInt8.self)
|
||||
let len = outStream.write(writeBuffer, maxLength: offset-total)
|
||||
@@ -891,8 +916,8 @@ open class WebSocket : NSObject, StreamDelegate {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
writeQueue.addOperation(operation)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -901,6 +926,7 @@ open class WebSocket : NSObject, StreamDelegate {
|
||||
private func doDisconnect(_ error: NSError?) {
|
||||
guard !didDisconnect else { return }
|
||||
didDisconnect = true
|
||||
isConnecting = false
|
||||
connected = false
|
||||
guard canDispatch else {return}
|
||||
callbackQueue.async { [weak self] in
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "Starscream"
|
||||
s.version = "2.0.2"
|
||||
s.version = "2.0.3"
|
||||
s.summary = "A conforming WebSocket RFC 6455 client library in Swift for iOS and OSX."
|
||||
s.homepage = "https://github.com/daltoniam/Starscream"
|
||||
s.license = 'Apache License, Version 2.0'
|
||||
|
||||
BIN
Binary file not shown.
@@ -22,4 +22,4 @@ EM.run {
|
||||
ws.send Faker::Hacker.say_something_smart
|
||||
}
|
||||
end
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user