/* * Copyright 2019, gRPC Authors All rights reserved. * * 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 import GRPC import NIO import RouteGuideModel import Logging // Quieten the logs. LoggingSystem.bootstrap { var handler = StreamLogHandler.standardOutput(label: $0) handler.logLevel = .critical return handler } /// Makes a `RouteGuide` client for a service hosted on "localhost" and listening on the given port. func makeClient(port: Int, group: EventLoopGroup) -> Routeguide_RouteGuideClient { let channel = ClientConnection.insecure(group: group) .connect(host: "localhost", port: port) return Routeguide_RouteGuideClient(channel: channel) } /// Unary call example. Calls `getFeature` and prints the response. func getFeature(using client: Routeguide_RouteGuideClient, latitude: Int, longitude: Int) { print("→ GetFeature: lat=\(latitude) lon=\(longitude)") let point: Routeguide_Point = .with { $0.latitude = numericCast(latitude) $0.longitude = numericCast(longitude) } let call = client.getFeature(point) let feature: Routeguide_Feature do { feature = try call.response.wait() } catch { print("RPC failed: \(error)") return } let lat = feature.location.latitude let lon = feature.location.longitude if !feature.name.isEmpty { print("Found feature called '\(feature.name)' at \(lat), \(lon)") } else { print("Found no feature at \(lat), \(lon)") } } /// Server-streaming example. Calls `listFeatures` with a rectangle of interest. Prints each /// response feature as it arrives. func listFeatures( using client: Routeguide_RouteGuideClient, lowLatitude: Int, lowLongitude: Int, highLatitude: Int, highLongitude: Int ) { print("→ ListFeatures: lowLat=\(lowLatitude) lowLon=\(lowLongitude), hiLat=\(highLatitude) hiLon=\(highLongitude)") let rectangle: Routeguide_Rectangle = .with { $0.lo = .with { $0.latitude = numericCast(lowLatitude) $0.longitude = numericCast(lowLongitude) } $0.hi = .with { $0.latitude = numericCast(highLatitude) $0.longitude = numericCast(highLongitude) } } var resultCount = 1 let call = client.listFeatures(rectangle) { feature in print("Result #\(resultCount): \(feature)") resultCount += 1 } let status = try! call.status.recover { _ in .processingError }.wait() if status.code != .ok { print("RPC failed: \(status)") } } /// Client-streaming example. Sends `featuresToVisit` randomly chosen points from `features` with /// a variable delay in between. Prints the statistics when they are sent from the server. public func recordRoute( using client: Routeguide_RouteGuideClient, features: [Routeguide_Feature], featuresToVisit: Int ) { print("→ RecordRoute") let options = CallOptions(timeout: .minutes(rounding: 1)) let call = client.recordRoute(callOptions: options) call.response.whenSuccess { summary in print( "Finished trip with \(summary.pointCount) points. Passed \(summary.featureCount) features. " + "Travelled \(summary.distance) meters. It took \(summary.elapsedTime) seconds." ) } call.response.whenFailure { error in print("RecordRoute Failed: \(error)") } call.status.whenComplete { _ in print("Finished RecordRoute") } for _ in 0.. [Routeguide_Feature] { let url = URL(fileURLWithPath: #file) .deletingLastPathComponent() // main.swift .deletingLastPathComponent() // Client/ .appendingPathComponent("route_guide_db.json") let data = try Data(contentsOf: url) return try Routeguide_Feature.array(fromJSONUTF8Data: data) } func main(args: [String]) throws { // arg0 (dropped) is the program name. We expect arg1 to be the port. guard case .some(let port) = args.dropFirst(1).first.flatMap(Int.init) else { print("Usage: \(args[0]) PORT") exit(1) } // Load the features. let features = try loadFeatures() let group = MultiThreadedEventLoopGroup(numberOfThreads: 1) defer { try? group.syncShutdownGracefully() } // Make a client, make sure we close it when we're done. let routeGuide = makeClient(port: port, group: group) defer { try? routeGuide.channel.close().wait() } // Look for a valid feature. getFeature(using: routeGuide, latitude: 409146138, longitude: -746188906) // Look for a missing feature. getFeature(using: routeGuide, latitude: 0, longitude: 0) // Looking for features between 40, -75 and 42, -73. listFeatures( using: routeGuide, lowLatitude: 400000000, lowLongitude: -750000000, highLatitude: 420000000, highLongitude: -730000000 ) // Record a few randomly selected points from the features file. recordRoute(using: routeGuide, features: features, featuresToVisit: 10) // Send and receive some notes. routeChat(using: routeGuide) } try main(args: CommandLine.arguments)