From 1ba8309ffbbd6992f4ec07166d07d13289adcd89 Mon Sep 17 00:00:00 2001 From: Michael Rebello Date: Tue, 20 Aug 2019 14:13:04 -0700 Subject: [PATCH] swift: update demos to use direct API (#349) **This is a working end-to-end iOS implementation using Envoy Mobile as a library!** Depends on https://github.com/lyft/envoy-mobile/pull/312 and https://github.com/lyft/envoy-mobile/pull/353. Updates our Swift example app to use the Envoy Mobile direct interfaces rather than using `URLSession` and Envoy as a listener. Note: For now, we are no longer showing the text response of the response body due to the fact that the underlying implementation is not yet complete for bodied requests (headers-only). Signed-off-by: Michael Rebello ![Simulator Screen Shot - TestDevice - 2019-08-20 at 13 57 44](https://user-images.githubusercontent.com/2643476/63383898-8f466280-c352-11e9-8c2e-944efda59ea2.png) --- examples/swift/hello_world/AppDelegate.swift | 5 +- .../swift/hello_world/ViewController.swift | 85 +++++++++---------- 2 files changed, 40 insertions(+), 50 deletions(-) diff --git a/examples/swift/hello_world/AppDelegate.swift b/examples/swift/hello_world/AppDelegate.swift index 293a4da12c..2f161c9b3e 100644 --- a/examples/swift/hello_world/AppDelegate.swift +++ b/examples/swift/hello_world/AppDelegate.swift @@ -1,10 +1,7 @@ -import Envoy import UIKit @UIApplicationMain final class AppDelegate: UIResponder, UIApplicationDelegate { - private let envoy = try! EnvoyBuilder().build() - var window: UIWindow? func application( @@ -15,8 +12,8 @@ final class AppDelegate: UIResponder, UIApplicationDelegate { window.rootViewController = ViewController() window.makeKeyAndVisible() self.window = window - NSLog("Finished launching!") + NSLog("Finished launching!") return true } } diff --git a/examples/swift/hello_world/ViewController.swift b/examples/swift/hello_world/ViewController.swift index deb168b2f7..0de67483c9 100644 --- a/examples/swift/hello_world/ViewController.swift +++ b/examples/swift/hello_world/ViewController.swift @@ -1,22 +1,28 @@ +import Envoy import UIKit private let kCellID = "cell-id" -// swiftlint:disable:next force_unwrapping -private let kURL = URL(string: "http://localhost:9001/api.lyft.com/static/demo/hello_world.txt")! +private let kRequestAuthority = "s3.amazonaws.com" +private let kRequestPath = "/api.lyft.com/static/demo/hello_world.txt" +private let kRequestScheme = "http" final class ViewController: UITableViewController { - private let session: URLSession = { - let configuration = URLSessionConfiguration.default - configuration.urlCache = nil - configuration.timeoutIntervalForRequest = 10 - return URLSession(configuration: configuration) - }() private var requestCount = 0 private var results = [Result]() private var timer: Timer? + private var envoy: Envoy? override func viewDidLoad() { super.viewDidLoad() + do { + NSLog("Starting Envoy...") + self.envoy = try EnvoyBuilder() + .build() + } catch let error { + NSLog("Starting Envoy failed: \(error)") + } + + NSLog("Started Envoy, beginning requests...") self.startRequests() } @@ -34,47 +40,34 @@ final class ViewController: UITableViewController { } private func performRequest() { - self.requestCount += 1 - let requestID = self.requestCount - var request = URLRequest(url: kURL) - request.addValue("s3.amazonaws.com", forHTTPHeaderField: "host") - - // Note that the request is sent to the envoy thread listening locally on port 9001. - NSLog("Starting request to '\(kURL.path)'") - self.session.dataTask(with: request) { [weak self] data, response, error in - DispatchQueue.main.async { - self?.handle(response: response, with: data, error: error, id: requestID) - } - }.resume() - } - - private func handle(response: URLResponse?, with data: Data?, error: Error?, id: Int) { - if let error = error { - return self.add(result: .failure(RequestError(id: id, message: "\(error)"))) - } - - guard let response = response as? HTTPURLResponse, let data = data else { - return self.add(result: .failure(RequestError(id: id, message: "missing response data"))) + guard let envoy = self.envoy else { + NSLog("Failed to start request - Envoy is not running") + return } - guard response.statusCode == 200 else { - let error = RequestError(id: id, message: "failed with status \(response.statusCode)") - return self.add(result: .failure(error)) - } - - guard let body = String(data: data, encoding: .utf8) else { - return self.add(result: .failure(RequestError(id: id, message: "failed to deserialize body"))) - } + self.requestCount += 1 + NSLog("Starting request to '\(kRequestPath)'") - let untypedHeaders = response.allHeaderFields - let headers = Dictionary(uniqueKeysWithValues: untypedHeaders.map - { header -> (String, String) in - return (header.key as? String ?? String(describing: header.key), "\(header.value)") - }) + let requestID = self.requestCount + let request = RequestBuilder(method: .get, scheme: kRequestScheme, + authority: kRequestAuthority, + path: kRequestPath).build() + let handler = ResponseHandler() + .onHeaders { [weak self] headers, statusCode, _ in + NSLog("Response status (\(requestID)): \(statusCode)\n\(headers)") + self?.add(result: .success(Response(id: requestID, body: "Status: \(statusCode)", + serverHeader: headers["server"]?.first ?? ""))) + } + .onData { data, _ in + NSLog("Response data (\(requestID)): \(data.count) bytes") + } + .onError { [weak self] in + NSLog("Error (\(requestID)): Request failed") + self?.add(result: .failure(RequestError(id: requestID, + message: "failed within Envoy library"))) + } - // Deserialize the response, which will include a `Server` header set by Envoy. - NSLog("Response:\n\(data.count) bytes\n\(body)\n\(headers)") - self.add(result: .success(Response(id: id, body: body, serverHeader: headers["Server"] ?? ""))) + envoy.sendUnary(request, handler: handler) } private func add(result: Result) { @@ -102,7 +95,7 @@ final class ViewController: UITableViewController { switch result { case .success(let response): cell.textLabel?.text = "[\(response.id)] \(response.body)" - cell.detailTextLabel?.text = "'Server' header: \(response.serverHeader)" + cell.detailTextLabel?.text = "'server' header: \(response.serverHeader)" cell.textLabel?.textColor = .black cell.detailTextLabel?.textColor = .black