Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Advanced Delegate and Custom HTTP methods #337

Merged
merged 2 commits into from
Jun 24, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,21 @@ socket.headers["Sec-WebSocket-Version"] = "14"
socket.headers["My-Awesome-Header"] = "Everything is Awesome!"
```

### Custom HTTP Method

Your server may use a different HTTP method when connecting to the websocket:

```swift
socket.httpMethod = .post
```
you can use a custom string:

```swift
socket.httpMethod = .custom(value: "mycustomhttpmethod")
```



### Protocols

If you need to specify a protocol, simple add it to the init:
Expand Down Expand Up @@ -286,6 +301,46 @@ Add the `Starscream.xcodeproj` to your Xcode project. Once that is complete, in

If you are running this in an OSX app or on a physical iOS device you will need to make sure you add the `Starscream.framework` to be included in your app bundle. To do this, in Xcode, navigate to the target configuration window by clicking on the blue project icon, and selecting the application target under the "Targets" heading in the sidebar. In the tab bar at the top of that window, open the "Build Phases" panel. Expand the "Link Binary with Libraries" group, and add `Starscream.framework`. Click on the + button at the top left of the panel and select "New Copy Files Phase". Rename this new phase to "Copy Frameworks", set the "Destination" to "Frameworks", and add `Starscream.framework` respectively.


## WebSocketAdvancedDelegate
The advanced delegate acts just like the simpler delegate but provides some additional information on the connection and incoming frames.

```swift
socket.advancedDelegate = self
```

In most cases you do not need the extra info and should use the normal delegate.

#### websocketDidReceiveMessage
```swift
func websocketDidReceiveMessage(socket: WebSocket, text: String, response: WebSocket.WSResponse {
print("got some text: \(text)")
print("First frame for this message arrived on \(response.firstFrame)")
}
```

#### websocketDidReceiveData
```swift
func websocketDidReceiveData(socket: WebSocket, data: Date, response: WebSocket.WSResponse) {
print("got some data it long: \(data.count)")
print("A total of \(response.frameCount) frames were used to send this data")
}
```

#### websocketHttpUpgrade
These methods are called when the HTTP upgrade request is sent and when the response returns.
```swift
func websocketHttpUpgrade(socket: WebSocket, request: CFHTTPMessage) {
print("the http request was sent we can check the raw http if we need to")
}
```

```swift
func websocketHttpUpgrade(socket: WebSocket, response: CFHTTPMessage) {
print("the http response has returned.")
}
```

## TODOs

- [ ] WatchOS?
Expand Down
57 changes: 51 additions & 6 deletions Source/WebSocket.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,19 @@ public protocol WebSocketPongDelegate: class {
func websocketDidReceivePong(socket: WebSocket, data: Data?)
}

// A Delegate with more advanced info on messages and connection etc.
public protocol WebSocketAdvancedDelegate: class {
func websocketDidConnect(socket: WebSocket)
func websocketDidDisconnect(socket: WebSocket, error: NSError?)
func websocketDidReceiveMessage(socket: WebSocket, text: String, response: WebSocket.WSResponse)
func websocketDidReceiveData(socket: WebSocket, data: Data, response: WebSocket.WSResponse)
func websocketHttpUpgrade(socket: WebSocket, request: CFHTTPMessage)
func websocketHttpUpgrade(socket: WebSocket, response: CFHTTPMessage)
}

open class WebSocket : NSObject, StreamDelegate {

enum OpCode : UInt8 {
public enum OpCode : UInt8 {
case continueFrame = 0x0
case textFrame = 0x1
case binaryFrame = 0x2
Expand Down Expand Up @@ -99,12 +109,15 @@ open class WebSocket : NSObject, StreamDelegate {
let httpSwitchProtocolCode = 101
let supportedSSLSchemes = ["wss", "https"]

class WSResponse {
public class WSResponse {
var isFin = false
var code: OpCode = .continueFrame
public var code: OpCode = .continueFrame
var bytesLeft = 0
var frameCount = 0
var buffer: NSMutableData?
public var frameCount = 0
public var buffer: NSMutableData?
public let firstFrame = {
return Date()
}()
}

// MARK: - Delegates
Expand All @@ -113,18 +126,44 @@ open class WebSocket : NSObject, StreamDelegate {
/// and also connection/disconnect messages.
public weak var delegate: WebSocketDelegate?

/// The optional advanced delegate can be used insteadof of the delegate
public weak var advancedDelegate: WebSocketAdvancedDelegate?

/// Receives a callback for each pong message recived.
public weak var pongDelegate: WebSocketPongDelegate?


// MARK: - Block based API.

public enum HTTPMethod {
case get
case post
case put
case connect
case custom(value: String)
var representation: String {
switch self {
case .get:
return "GET"
case .post:
return "POST"
case .put:
return "PUT"
case .connect:
return "CONNECT"
case .custom(let value):
return value.capitalized
}
}
}

public var onConnect: (() -> Void)?
public var onDisconnect: ((NSError?) -> Void)?
public var onText: ((String) -> Void)?
public var onData: ((Data) -> Void)?
public var onPong: ((Data?) -> Void)?

public var httpMethod: HTTPMethod = .get
public var headers = [String: String]()
public var voipEnabled = false
public var disableSSLCertValidation = false
Expand Down Expand Up @@ -258,7 +297,7 @@ open class WebSocket : NSObject, StreamDelegate {
Private method that starts the connection.
*/
private func createHTTPRequest() {
let urlRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, "GET" as CFString,
let urlRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, httpMethod.representation as CFString,
url as CFURL, kCFHTTPVersion1_1).takeRetainedValue()

var port = url.port
Expand Down Expand Up @@ -286,6 +325,7 @@ open class WebSocket : NSObject, StreamDelegate {
if let cfHTTPMessage = CFHTTPMessageCopySerializedMessage(urlRequest) {
let serializedRequest = cfHTTPMessage.takeRetainedValue()
initStreamsWithData(serializedRequest as Data, Int(port!))
self.advancedDelegate?.websocketHttpUpgrade(socket: self, request: urlRequest)
}
}

Expand Down Expand Up @@ -552,6 +592,7 @@ open class WebSocket : NSObject, StreamDelegate {
guard let s = self else { return }
s.onConnect?()
s.delegate?.websocketDidConnect(socket: s)
s.advancedDelegate?.websocketDidConnect(socket: s)
s.notificationCenter.post(name: NSNotification.Name(WebsocketDidConnectNotification), object: self)
}
}
Expand All @@ -572,6 +613,7 @@ open class WebSocket : NSObject, StreamDelegate {
let response = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, false).takeRetainedValue()
CFHTTPMessageAppendBytes(response, buffer, bufferLen)
let code = CFHTTPMessageGetResponseStatusCode(response)
self.advancedDelegate?.websocketHttpUpgrade(socket: self, response: response)
if code != httpSwitchProtocolCode {
return code
}
Expand Down Expand Up @@ -817,6 +859,7 @@ open class WebSocket : NSObject, StreamDelegate {
guard let s = self else { return }
s.onText?(str! as String)
s.delegate?.websocketDidReceiveMessage(socket: s, text: str! as String)
s.advancedDelegate?.websocketDidReceiveMessage(socket: s, text: str! as String, response: response)
}
}
} else if response.code == .binaryFrame {
Expand All @@ -826,6 +869,7 @@ open class WebSocket : NSObject, StreamDelegate {
guard let s = self else { return }
s.onData?(data as Data)
s.delegate?.websocketDidReceiveData(socket: s, data: data as Data)
s.advancedDelegate?.websocketDidReceiveData(socket: s, data: data as Data, response: response)
}
}
}
Expand Down Expand Up @@ -933,6 +977,7 @@ open class WebSocket : NSObject, StreamDelegate {
guard let s = self else { return }
s.onDisconnect?(error)
s.delegate?.websocketDidDisconnect(socket: s, error: error)
s.advancedDelegate?.websocketDidDisconnect(socket: s, error: error)
let userInfo = error.map{ [WebsocketDisconnectionErrorKeyName: $0] }
s.notificationCenter.post(name: NSNotification.Name(WebsocketDidDisconnectNotification), object: self, userInfo: userInfo)
}
Expand Down