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