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  }