-
Notifications
You must be signed in to change notification settings - Fork 84
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ios: finish bridging between ObjC/Swift (#312)
This PR ties together the upstream Objective-C/++ implementation with the Swift interfaces/bridging implementation. After this change, end-to-end calls from the native Swift library into the Envoy core should be supported. - Implements the streaming and unary request methods - Adds a simple `EnvoyStreamEmitter` which sends requests from Swift down into Objective-C - Updates the header conversion functions and their tests to convert to the proper types (`[String: [String]]` versus `[String: String]`) - Implements `ResponseHandler` as a class which provides a pass-through for setting Objective-C blocks directly from Swift for handling responses - Adds a parser for status codes, as well as tests #349 will use this interface with the Swift demo apps. Signed-off-by: Michael Rebello <me@michaelrebello.com>
- Loading branch information
Showing
12 changed files
with
199 additions
and
77 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 2 additions & 2 deletions
4
library/swift/src/Error.swift → library/swift/src/EnvoyError.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import Foundation | ||
|
||
/// Default implementation of the `StreamEmitter` interface. | ||
@objcMembers | ||
final class EnvoyStreamEmitter { | ||
private let stream: EnvoyHTTPStream | ||
|
||
init(stream: EnvoyHTTPStream) { | ||
self.stream = stream | ||
} | ||
} | ||
|
||
extension EnvoyStreamEmitter: StreamEmitter { | ||
func sendData(_ data: Data) -> StreamEmitter { | ||
self.stream.send(data, close: false) | ||
return self | ||
} | ||
|
||
func sendMetadata(_ metadata: [String: [String]]) -> StreamEmitter { | ||
self.stream.sendMetadata(metadata) | ||
return self | ||
} | ||
|
||
func close(trailers: [String: [String]]) { | ||
self.stream.sendTrailers(trailers) | ||
} | ||
|
||
func cancel() { | ||
_ = self.stream.cancel() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,98 @@ | ||
import Foundation | ||
|
||
/// Callback interface for receiving stream events. | ||
@objc | ||
public protocol ResponseHandler { | ||
/// Dispatch queue upon which callbacks will be called. | ||
var dispatchQueue: DispatchQueue { get } | ||
@objcMembers | ||
public final class ResponseHandler: NSObject { | ||
/// Underlying observer which will be passed to the Envoy Engine. | ||
let underlyingObserver = EnvoyObserver() | ||
|
||
/// Called when response headers are received by the stream. | ||
/// Initialize a new instance of the handler. | ||
/// | ||
/// - parameter headers: The headers of the response. | ||
/// - parameter statusCode: The status code of the response. | ||
func onHeaders(_ headers: [String: [String]], statusCode: Int) | ||
/// - parameter queue: Dispatch queue upon which callbacks will be called. | ||
public init(queue: DispatchQueue = .main) { | ||
self.underlyingObserver.dispatchQueue = queue | ||
} | ||
|
||
/// Called when a data frame is received by the stream. | ||
/// Specify a callback for when response headers are received by the stream. | ||
/// If `endStream` is `true`, the stream is complete. | ||
/// | ||
/// - parameter data: Bytes in the response. | ||
/// - parameter endStream: True if the stream is complete. | ||
func onData(_ data: Data, endStream: Bool) | ||
/// - parameter closure: Closure which will receive the headers, status code, | ||
/// and flag indicating if the stream is headers-only. | ||
@discardableResult | ||
public func onHeaders(_ closure: | ||
@escaping (_ headers: [String: [String]], _ statusCode: Int, _ endStream: Bool) -> Void) | ||
-> ResponseHandler | ||
{ | ||
self.underlyingObserver.onHeaders = { headers, endStream in | ||
closure(headers, ResponseHandler.statusCode(fromHeaders: headers), endStream) | ||
} | ||
|
||
/// Called when response metadata is received by the stream. | ||
return self | ||
} | ||
|
||
/// Specify a callback for when a data frame is received by the stream. | ||
/// If `endStream` is `true`, the stream is complete. | ||
/// | ||
/// - parameter closure: Closure which will receive the data, | ||
/// and flag indicating if the stream is complete. | ||
@discardableResult | ||
public func onData(_ closure: | ||
@escaping (_ data: Data, _ endStream: Bool) -> Void) | ||
-> ResponseHandler | ||
{ | ||
self.underlyingObserver.onData = closure | ||
return self | ||
} | ||
|
||
/// Specify a callback for when trailers are received by the stream. | ||
/// If the closure is called, the stream is complete. | ||
/// | ||
/// - parameter metadata: The metadata of the response. | ||
/// - parameter endStream: True if the stream is complete. | ||
func onMetadata(_ metadata: [String: [String]], endStream: Bool) | ||
/// - parameter closure: Closure which will receive the trailers. | ||
@discardableResult | ||
public func onTrailers(_ closure: | ||
@escaping (_ trailers: [String: [String]]) -> Void) | ||
-> ResponseHandler | ||
{ | ||
self.underlyingObserver.onTrailers = closure | ||
return self | ||
} | ||
|
||
/// Called when response trailers are received by the stream. | ||
/// Specify a callback for when an internal Envoy exception occurs with the stream. | ||
/// If the closure is called, the stream is complete. | ||
/// | ||
/// - parameter trailers: The trailers of the response. | ||
func onTrailers(_ trailers: [String: [String]]) | ||
/// - parameter closure: Closure which will be called when an error occurs. | ||
@discardableResult | ||
public func onError(_ closure: | ||
@escaping () -> Void) | ||
-> ResponseHandler | ||
{ | ||
self.underlyingObserver.onError = closure | ||
return self | ||
} | ||
|
||
/// Called when an internal Envoy exception occurs with the stream. | ||
/// Specify a callback for when the stream is canceled. | ||
/// If the closure is called, the stream is complete. | ||
/// | ||
/// - parameter error: The error that occurred with the stream. | ||
func onError(_ error: Error) | ||
/// - parameter closure: Closure which will be called when the stream is canceled. | ||
@discardableResult | ||
public func onCancel(_ closure: | ||
@escaping () -> Void) | ||
-> ResponseHandler | ||
{ | ||
self.underlyingObserver.onCancel = closure | ||
return self | ||
} | ||
|
||
/// Called when the stream is canceled. | ||
func onCanceled() | ||
// MARK: - Helpers | ||
|
||
/// Called when the stream has been completed. | ||
func onCompletion() | ||
/// Parses out the status code from the provided HTTP headers. | ||
/// | ||
/// - parameter headers: The headers from which to obtain the status. | ||
/// | ||
/// - returns: The HTTP status code from the headers, or 0 if none is set. | ||
static func statusCode(fromHeaders headers: [String: [String]]) -> Int { | ||
return headers[":status"]? | ||
.compactMap(Int.init) | ||
.first ?? 0 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.