github.com/stackb/rules_proto@v0.0.0-20240221195024-5428336c51f1/example/routeguide/scala/RouteGuideClient.scala (about) 1 /** 2 * Copied from https://github.com/btlines/grpcexample/blob/master/src/main/scala/io/grpc/routeguide/RouteGuideClient.scala 3 * License: MIT 4 */ 5 package example.routeguide.scala 6 7 import java.io.IOException 8 import java.util.concurrent.{CountDownLatch, TimeUnit} 9 import java.util.logging.Logger 10 import io.grpc.{ManagedChannelBuilder, Status} 11 import io.grpc.stub.StreamObserver 12 import scala.io.StdIn 13 import scala.util.{Random, Try, Success, Failure} 14 15 import example.routeguide.{Feature, Point, RouteNote, RouteSummary, Rectangle, RouteGuideGrpc} 16 17 class RouteGuideClient(host: String, port: Int) { 18 19 val logger: Logger = Logger.getLogger(classOf[RouteGuideClient].getName) 20 21 val channel = 22 ManagedChannelBuilder 23 .forAddress(host, port) 24 .usePlaintext() 25 .build() 26 27 val blockingStub = RouteGuideGrpc.blockingStub(channel) 28 val asyncStub = RouteGuideGrpc.stub(channel) 29 30 def shutdown(): Unit = channel.shutdown().awaitTermination(5, TimeUnit.SECONDS) 31 32 import io.grpc.StatusRuntimeException 33 34 /** 35 * Blocking unary call example. Calls getFeature and prints the response. 36 */ 37 def getFeature(lat: Int, lon: Int): Unit = { 38 logger.info(s"*** GetFeature: lat=$lat lon=$lon") 39 val request = Point(lat, lon) 40 try { 41 val feature = blockingStub.getFeature(request) 42 val lat = RouteGuideServiceUtil.getLatitude(feature.getLocation) 43 val lon = RouteGuideServiceUtil.getLongitude(feature.getLocation) 44 if (RouteGuideServiceUtil.isValid(feature)) { 45 logger.info(s"Found feature called '${feature.name}' at $lat, $lon") 46 } else { 47 logger.info(s"Found no feature at $lat, $lon") 48 } 49 } catch { 50 case e: StatusRuntimeException => 51 logger.warning(s"RPC failed:${e.getStatus}") 52 sys.exit(1) 53 } 54 } 55 56 import io.grpc.StatusRuntimeException 57 58 /** 59 * Blocking server-streaming example. Calls listFeatures with a rectangle of interest. Prints each 60 * response feature as it arrives. 61 */ 62 def listFeatures(lowLat: Int, lowLon: Int, hiLat: Int, hiLon: Int): Unit = { 63 logger.info(s"*** ListFeatures: lowLat=$lowLat lowLon=$lowLon hiLat=$hiLat hiLon=$hiLon") 64 val request = Rectangle( 65 lo = Some(Point(lowLat, lowLon)), 66 hi = Some(Point(hiLat, hiLon)) 67 ) 68 try { 69 val features = blockingStub.listFeatures(request) 70 features.zipWithIndex.foreach { case (feature, index) => 71 logger.info(s"Result #$index: $feature") 72 } 73 } catch { 74 case e: StatusRuntimeException => 75 logger.warning(s"RPC failed: ${e.getStatus}") 76 sys.exit(1) 77 } 78 } 79 80 /** 81 * Async client-streaming example. Sends {@code numPoints} randomly chosen points from {@code 82 * features} with a variable delay in between. Prints the statistics when they are sent from the 83 * server. 84 */ 85 @throws[InterruptedException] 86 def recordRoute(features: Seq[Feature], numPoints: Int): Unit = { 87 logger.info("*** RecordRoute features=" + features.size) 88 val finishLatch = new CountDownLatch(1) 89 val responseObserver = new StreamObserver[RouteSummary]() { 90 override def onNext(summary: RouteSummary): Unit = { 91 logger.info(s"Finished trip with ${summary.pointCount} points. Passed ${summary.featureCount} features. " + s"Travelled ${summary.distance} meters. It took ${summary.elapsedTime} seconds.") 92 } 93 94 override def onError(t: Throwable): Unit = { 95 logger.warning(s"RecordRoute Failed: ${Status.fromThrowable(t)}") 96 finishLatch.countDown() 97 sys.exit(1) 98 } 99 100 override def onCompleted(): Unit = { 101 logger.info("Finished RecordRoute") 102 finishLatch.countDown() 103 } 104 } 105 val requestObserver = asyncStub.recordRoute(responseObserver) 106 try { // Send numPoints points randomly selected from the features list. 107 (0 to numPoints).foreach { i => 108 if (finishLatch.getCount > 0) { 109 val index = Random.nextInt(features.size) 110 val point = features(index).getLocation 111 logger.info(s"Visiting point ${point.latitude}, ${point.longitude}") 112 requestObserver.onNext(point) 113 // Sleep for a bit before sending the next one. 114 Thread.sleep(Random.nextInt(1000) + 500) 115 } 116 } 117 } catch { 118 case e: RuntimeException => 119 // Cancel RPC 120 requestObserver.onError(e) 121 throw e 122 } 123 // Mark the end of requests 124 requestObserver.onCompleted() 125 // Receiving happens asynchronously 126 if (!finishLatch.await(1, TimeUnit.MINUTES)) logger.warning("recordRoute can not finish within 1 minutes") 127 } 128 129 /** 130 * Bi-directional example, which can only be asynchronous. Send some chat messages, and print any 131 * chat messages that are sent from the server. 132 */ 133 def routeChat: CountDownLatch = { 134 logger.info("*** RouteChat") 135 val finishLatch = new CountDownLatch(1) 136 val requestObserver = asyncStub.routeChat(new StreamObserver[RouteNote]() { 137 override def onNext(note: RouteNote): Unit = { 138 logger.info(s"Got message '${note.message}' at ${note.getLocation.latitude}, ${note.getLocation.longitude}") 139 } 140 141 override def onError(t: Throwable): Unit = { 142 logger.warning(s"RouteChat Failed: ${Status.fromThrowable(t)}") 143 finishLatch.countDown() 144 sys.exit(1) 145 } 146 147 override def onCompleted(): Unit = { 148 logger.info("Finished RouteChat") 149 finishLatch.countDown() 150 } 151 }) 152 try { 153 val requests = Seq( 154 RouteNote(message = "First message", location = Some(Point(0, 0))), 155 RouteNote(message = "Second message", location = Some(Point(0, 1))), 156 RouteNote(message = "Third message", location = Some(Point(1, 0))), 157 RouteNote(message = "Fourth message", location = Some(Point(1, 1))) 158 ) 159 for (request <- requests) { 160 logger.info(s"Sending message '${request.message}' at ${request.getLocation.latitude}, ${request.getLocation.longitude}") 161 requestObserver.onNext(request) 162 } 163 } catch { 164 case e: RuntimeException => 165 // Cancel RPC 166 requestObserver.onError(e) 167 throw e 168 } 169 // Mark the end of requests 170 requestObserver.onCompleted() 171 // return the latch while receiving happens asynchronously 172 finishLatch 173 } 174 175 } 176 177 object RouteGuideClient extends App { 178 val logger = Logger.getLogger(getClass.getName) 179 180 // This isn't working due to some issue with the json4s library - not a priority to solve it 181 // 182 // val features: Seq[Feature] = Try { 183 // RouteGuidePersistence.parseFeatures(RouteGuidePersistence.defaultFeatureFile) 184 // } recoverWith { 185 // case e: Throwable => 186 // logger.warning("features load failed: " + e) 187 // Failure(e) 188 // } getOrElse { 189 // logger.warning("Can't load feature list from file") 190 // Seq.empty 191 // } 192 193 val features = RouteGuideUtil.getFeatures 194 195 val port = if (System.getenv("SERVER_PORT") != null) { 196 System.getenv("SERVER_PORT").toInt 197 } else 50056 198 199 val client = new RouteGuideClient("localhost", port) 200 var stop = false 201 202 try { 203 client.getFeature(409146138, -746188906) 204 client.listFeatures(400000000, -750000000, 420000000, -730000000) 205 client.recordRoute(features, 2) 206 val finishLatch = client.routeChat 207 if (!finishLatch.await(1, TimeUnit.MINUTES)) logger.warning("routeChat can not finish within 1 minutes") 208 } finally client.shutdown() 209 210 }