github.com/stackb/rules_proto@v0.0.0-20240221195024-5428336c51f1/example/routeguide/scala/RouteGuideService.scala (about) 1 package example.routeguide.scala 2 3 import java.util.logging.Logger 4 import java.util.concurrent.TimeUnit.NANOSECONDS 5 6 import io.grpc.stub.StreamObserver 7 import scala.concurrent.Future 8 9 import example.routeguide.{Feature, Point, RouteNote, RouteSummary, Rectangle, RouteGuideGrpc} 10 11 class RouteGuideService(features: Seq[Feature]) extends RouteGuideGrpc.RouteGuide { 12 13 val logger: Logger = Logger.getLogger(classOf[RouteGuideService].getName) 14 15 private val routeNotes: AtomicRef[Map[Point, Seq[RouteNote]]] = new AtomicRef(Map.empty) 16 17 /** 18 * Gets the {@link Feature} at the requested {@link Point}. If no feature at 19 * that location exists, an unnamed feature is returned at the provided 20 * location. 21 * 22 * @param request the requested location for the feature. 23 */ 24 override def getFeature(request: Point): Future[Feature] = { 25 Future.successful(findFeature(request)) 26 } 27 28 /** 29 * Gets all features contained within the given bounding {@link Rectangle}. 30 * 31 * @param request the bounding rectangle for the requested features. 32 * @param responseObserver the observer that will receive the features. 33 */ 34 override def listFeatures(request: Rectangle, responseObserver: StreamObserver[Feature]): Unit = { 35 val left = Math.min(request.getLo.longitude, request.getHi.longitude) 36 val right = Math.max(request.getLo.longitude, request.getHi.longitude) 37 val top = Math.max(request.getLo.latitude, request.getHi.latitude) 38 val bottom = Math.min(request.getLo.latitude, request.getHi.latitude) 39 40 features.foreach { feature => 41 if (RouteGuideServiceUtil.isValid(feature)) { 42 val lat = feature.getLocation.latitude 43 val lon = feature.getLocation.longitude 44 if (lon >= left && lon <= right && lat >= bottom && lat <= top) { 45 responseObserver.onNext(feature) 46 } 47 } 48 } 49 responseObserver.onCompleted() 50 } 51 52 /** 53 * Gets a stream of points, and responds with statistics about the "trip": 54 * number of points, number of known features visited, total distance 55 * traveled, and total time spent. 56 * 57 * @param responseObserver an observer to receive the response summary. 58 * @return an observer to receive the requested route points. 59 */ 60 override def recordRoute(responseObserver: StreamObserver[RouteSummary]): StreamObserver[Point] = 61 new StreamObserver[Point] { 62 var pointCount: Int = 0 63 var featureCount: Int = 0 64 var distance: Int = 0 65 var previous: Option[Point] = None 66 var startTime: Long = System.nanoTime 67 68 override def onNext(point: Point): Unit = { 69 pointCount += 1 70 if (RouteGuideServiceUtil.isValid(findFeature(point))) { 71 featureCount += 1 72 } 73 // For each point after the first, add the incremental distance from the 74 // previous point to the total distance value. 75 previous.foreach{ prev => 76 distance += RouteGuideServiceUtil.calcDistance(prev, point) 77 } 78 previous = Some(point) 79 } 80 override def onCompleted(): Unit = { 81 val seconds = NANOSECONDS.toSeconds(System.nanoTime - startTime) 82 responseObserver.onNext(RouteSummary(pointCount, featureCount, distance, seconds.toInt)) 83 responseObserver.onCompleted 84 } 85 86 override def onError(t: Throwable): Unit = 87 logger.warning("recordRoute cancelled") 88 } 89 90 /** 91 * Receives a stream of message/location pairs, and responds with a stream of 92 * all previous messages at each of those locations. 93 * 94 * @param responseObserver an observer to receive the stream of previous 95 * messages. 96 * @return an observer to handle requested message/location pairs. 97 */ 98 override def routeChat(responseObserver: StreamObserver[RouteNote]): StreamObserver[RouteNote] = 99 new StreamObserver[RouteNote]() { 100 override def onNext(note: RouteNote): Unit = { 101 val notes = getNotes(note.getLocation) 102 // Respond with all previous notes at this location 103 notes.foreach(responseObserver.onNext) 104 // Now add the new note to the list 105 addNote(note) 106 } 107 108 override def onError(t: Throwable): Unit = { 109 logger.warning("routeChat cancelled") 110 } 111 112 override def onCompleted(): Unit = { 113 responseObserver.onCompleted 114 } 115 } 116 117 private def findFeature(point: Point): Feature = { 118 features.find { feature => 119 feature.getLocation.latitude == point.latitude && feature.getLocation.longitude == point.longitude 120 } getOrElse new Feature(location = Some(point)) 121 } 122 123 private def getNotes(point: Point): Seq[RouteNote] = { 124 routeNotes.get.getOrElse(point, Seq.empty) 125 } 126 127 private def addNote(note: RouteNote): Unit = { 128 routeNotes.updateAndGet { notes => 129 val existingNotes = notes.getOrElse(note.getLocation, Seq.empty) 130 val updatedNotes = existingNotes :+ note 131 notes + (note.getLocation -> updatedNotes) 132 } 133 } 134 }