github.com/stackb/rules_proto@v0.0.0-20240221195024-5428336c51f1/example/routeguide/nodejs/server.js (about)

     1  const grpc = require('@grpc/grpc-js');
     2  
     3  const features = require('../../../example/routeguide/features');
     4  const messages = require('../../../example/routeguide/routeguide_pb')
     5  const services = require('../../../example/routeguide/routeguide_grpc_pb')
     6  
     7  const COORD_FACTOR = 1e7;
     8  let feature_list = [];
     9  
    10  
    11  function checkFeature(point) {
    12      // Check if there is already a feature object for the given point
    13      for (const feature of feature_list) {
    14          if (feature.getLocation().getLatitude() === point.getLatitude() &&
    15              feature.getLocation().getLongitude() === point.getLongitude()) {
    16              return feature;
    17          }
    18      }
    19  
    20      // Create empty feature
    21      const name = '';
    22      const feature = new messages.Feature();
    23      feature.setName(name);
    24      feature.setLocation(point);
    25      return feature;
    26  }
    27  
    28  
    29  function getFeature(call, callback) {
    30      callback(null, checkFeature(call.request));
    31  }
    32  
    33  
    34  function listFeatures(call) {
    35      const lo = call.request.getLo();
    36      const hi = call.request.getHi();
    37      const left = Math.min([lo.getLongitude(), hi.getLongitude()]);
    38      const right = Math.max([lo.getLongitude(), hi.getLongitude()]);
    39      const top = Math.max([lo.getLatitude(), hi.getLatitude()]);
    40      const bottom = Math.min([lo.getLatitude(), hi.getLatitude()]);
    41  
    42      // For each feature, check if it is in the given bounding box
    43      feature_list.forEach((feature) => {
    44          if (feature.getName() === '') return;
    45          if (feature.getLocation().getLongitude() >= left &&
    46              feature.getLocation().getLongitude() <= right &&
    47              feature.getLocation().getLatitude() >= bottom &&
    48              feature.getLocation().getLatitude() <= top) {
    49              call.write(feature);
    50          }
    51      });
    52  
    53      call.end();
    54  }
    55  
    56  
    57  function getDistance(start, end) {
    58      function toRadians(num) {
    59          return num * Math.PI / 180;
    60      }
    61  
    62      const R = 6371000;  // earth radius in metres
    63      const lat1 = toRadians(start.getLatitude() / COORD_FACTOR);
    64      const lat2 = toRadians(end.getLatitude() / COORD_FACTOR);
    65      const lon1 = toRadians(start.getLongitude() / COORD_FACTOR);
    66      const lon2 = toRadians(end.getLongitude() / COORD_FACTOR);
    67  
    68      const deltalat = lat2 - lat1;
    69      const deltalon = lon2 - lon1;
    70      const a = Math.sin(deltalat / 2) * Math.sin(deltalat / 2) +
    71          Math.cos(lat1) * Math.cos(lat2) *
    72          Math.sin(deltalon / 2) * Math.sin(deltalon / 2);
    73      const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    74      return R * c;
    75  }
    76  
    77  
    78  function recordRoute(call, callback) {
    79      let pointCount = 0;
    80      let featureCount = 0;
    81      let distance = 0;
    82      let previous = null;
    83  
    84      // Start a timer
    85      const start_time = process.hrtime();
    86      call.on('data', (point) => {
    87          pointCount++;
    88          if (checkFeature(point).name !== '') featureCount += 1;
    89          if (previous != null) distance += getDistance(previous, point);
    90          previous = point;
    91      });
    92  
    93      call.on('end', () => {
    94          const summary = new messages.RouteSummary();
    95          summary.setPointCount(pointCount);
    96          summary.setFeatureCount(featureCount);
    97          summary.setDistance(distance | 0);
    98          summary.setElapsedTime(process.hrtime(start_time)[0]);
    99          callback(null, summary);
   100      });
   101  }
   102  
   103  
   104  const route_notes = new Map();
   105  
   106  function pointKey(point) {
   107      return point.getLatitude() + ' ' + point.getLongitude();
   108  }
   109  
   110  
   111  function routeChat(call) {
   112      call.on('data', function (note) {
   113          const key = pointKey(note.getLocation());
   114          if (route_notes.has(key)) {
   115              route_notes[key].forEach((note) => {
   116                  call.write(note);
   117              });
   118          } else {
   119              route_notes[key] = [];
   120          }
   121  
   122          // Then add the new note to the list
   123          route_notes[key].push(note);
   124      });
   125  
   126      call.on('end', call.end);
   127  }
   128  
   129  
   130  if (require.main === module) {
   131      let port = '50055';
   132      if (process.env.SERVER_PORT) port = process.env.SERVER_PORT;
   133      const addr = '0.0.0.0:' + port;
   134      const routeServer = new grpc.Server();
   135      routeServer.addService(services.RouteGuideService, {
   136          getFeature: getFeature,
   137          listFeatures: listFeatures,
   138          recordRoute: recordRoute,
   139          routeChat: routeChat
   140      });
   141  
   142      routeServer.bindAsync(addr, grpc.ServerCredentials.createInsecure(), () => {
   143          // Transform the loaded features to Feature objects
   144          feature_list = features.map(function (value) {
   145              const feature = new messages.Feature();
   146              feature.setName(value.name);
   147              const location = new messages.Point();
   148              location.setLatitude(value.location.latitude);
   149              location.setLongitude(value.location.longitude);
   150              feature.setLocation(location);
   151              return feature;
   152          });
   153  
   154          console.log(`Feature database contains ${feature_list.length} entries.`);
   155          console.log(`Node server listening at ${addr}...`)
   156          routeServer.start();
   157      });
   158  }