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 }