1 use std::collections::HashMap; 2 use std::pin::Pin; 3 use std::sync::Arc; 4 use std::time::Instant; 5 6 use tokio::sync::mpsc; 7 use tokio_stream::{wrappers::ReceiverStream, Stream, StreamExt}; 8 use tonic::transport::Server; 9 use tonic::{Request, Response, Status}; 10 11 use routeguide::route_guide_server::{RouteGuide, RouteGuideServer}; 12 use routeguide::{Feature, Point, Rectangle, RouteNote, RouteSummary}; 13 14 pub mod routeguide { 15 tonic::include_proto!("routeguide"); 16 } 17 18 mod data; 19 20 #[derive(Debug)] 21 pub struct RouteGuideService { 22 features: Arc<Vec<Feature>>, 23 } 24 25 #[tonic::async_trait] 26 impl RouteGuide for RouteGuideService { 27 async fn get_feature(&self, request: Request<Point>) -> Result<Response<Feature>, Status> { 28 println!("GetFeature = {:?}", request); 29 30 for feature in &self.features[..] { 31 if feature.location.as_ref() == Some(request.get_ref()) { 32 return Ok(Response::new(feature.clone())); 33 } 34 } 35 36 Ok(Response::new(Feature::default())) 37 } 38 39 type ListFeaturesStream = ReceiverStream<Result<Feature, Status>>; 40 41 async fn list_features( 42 &self, 43 request: Request<Rectangle>, 44 ) -> Result<Response<Self::ListFeaturesStream>, Status> { 45 println!("ListFeatures = {:?}", request); 46 47 let (tx, rx) = mpsc::channel(4); 48 let features = self.features.clone(); 49 50 tokio::spawn(async move { 51 for feature in &features[..] { 52 if in_range(feature.location.as_ref().unwrap(), request.get_ref()) { 53 println!(" => send {:?}", feature); 54 tx.send(Ok(feature.clone())).await.unwrap(); 55 } 56 } 57 58 println!(" /// done sending"); 59 }); 60 61 Ok(Response::new(ReceiverStream::new(rx))) 62 } 63 64 async fn record_route( 65 &self, 66 request: Request<tonic::Streaming<Point>>, 67 ) -> Result<Response<RouteSummary>, Status> { 68 println!("RecordRoute"); 69 70 let mut stream = request.into_inner(); 71 72 let mut summary = RouteSummary::default(); 73 let mut last_point = None; 74 let now = Instant::now(); 75 76 while let Some(point) = stream.next().await { 77 let point = point?; 78 79 println!(" ==> Point = {:?}", point); 80 81 // Increment the point count 82 summary.point_count += 1; 83 84 // Find features 85 for feature in &self.features[..] { 86 if feature.location.as_ref() == Some(&point) { 87 summary.feature_count += 1; 88 } 89 } 90 91 // Calculate the distance 92 if let Some(ref last_point) = last_point { 93 summary.distance += calc_distance(last_point, &point); 94 } 95 96 last_point = Some(point); 97 } 98 99 summary.elapsed_time = now.elapsed().as_secs() as i32; 100 101 Ok(Response::new(summary)) 102 } 103 104 type RouteChatStream = Pin<Box<dyn Stream<Item = Result<RouteNote, Status>> + Send + 'static>>; 105 106 async fn route_chat( 107 &self, 108 request: Request<tonic::Streaming<RouteNote>>, 109 ) -> Result<Response<Self::RouteChatStream>, Status> { 110 println!("RouteChat"); 111 112 let mut notes = HashMap::new(); 113 let mut stream = request.into_inner(); 114 115 let output = async_stream::try_stream! { 116 while let Some(note) = stream.next().await { 117 let note = note?; 118 119 let location = note.location.clone().unwrap(); 120 121 let location_notes = notes.entry(location).or_insert(vec![]); 122 location_notes.push(note); 123 124 for note in location_notes { 125 yield note.clone(); 126 } 127 } 128 }; 129 130 Ok(Response::new(Box::pin(output) as Self::RouteChatStream)) 131 } 132 } 133 134 #[tokio::main] 135 async fn main() -> Result<(), Box<dyn std::error::Error>> { 136 let addr = "[::1]:10000".parse().unwrap(); 137 138 println!("RouteGuideServer listening on: {}", addr); 139 140 let route_guide = RouteGuideService { 141 features: Arc::new(data::load()), 142 }; 143 144 let svc = RouteGuideServer::new(route_guide); 145 146 Server::builder().add_service(svc).serve(addr).await?; 147 148 Ok(()) 149 } 150 151 impl Eq for Point {} 152 153 fn in_range(point: &Point, rect: &Rectangle) -> bool { 154 use std::cmp; 155 156 let lo = rect.lo.as_ref().unwrap(); 157 let hi = rect.hi.as_ref().unwrap(); 158 159 let left = cmp::min(lo.longitude, hi.longitude); 160 let right = cmp::max(lo.longitude, hi.longitude); 161 let top = cmp::max(lo.latitude, hi.latitude); 162 let bottom = cmp::min(lo.latitude, hi.latitude); 163 164 point.longitude >= left 165 && point.longitude <= right 166 && point.latitude >= bottom 167 && point.latitude <= top 168 } 169 170 /// Calculates the distance between two points using the "haversine" formula. 171 /// This code was taken from http://www.movable-type.co.uk/scripts/latlong.html. 172 fn calc_distance(p1: &Point, p2: &Point) -> i32 { 173 const CORD_FACTOR: f64 = 1e7; 174 const R: f64 = 6_371_000.0; // meters 175 176 let lat1 = p1.latitude as f64 / CORD_FACTOR; 177 let lat2 = p2.latitude as f64 / CORD_FACTOR; 178 let lng1 = p1.longitude as f64 / CORD_FACTOR; 179 let lng2 = p2.longitude as f64 / CORD_FACTOR; 180 181 let lat_rad1 = lat1.to_radians(); 182 let lat_rad2 = lat2.to_radians(); 183 184 let delta_lat = (lat2 - lat1).to_radians(); 185 let delta_lng = (lng2 - lng1).to_radians(); 186 187 let a = (delta_lat / 2f64).sin() * (delta_lat / 2f64).sin() 188 + (lat_rad1).cos() * (lat_rad2).cos() * (delta_lng / 2f64).sin() * (delta_lng / 2f64).sin(); 189 190 let c = 2f64 * a.sqrt().atan2((1f64 - a).sqrt()); 191 192 (R * c) as i32 193 } 194