1 module routeguide.example; 2 3 4 5 import std.stdio; 6 import std.file; 7 import std.getopt; 8 import std.algorithm; 9 import std.math; 10 11 import routeguide.route_guide; 12 import routeguide.route_guiderpc; 13 14 import grpc; 15 16 import hunt.util.Serialize; 17 import hunt.logging; 18 19 __gshared Feature[] list; 20 21 22 23 float convertToRadians(float num) { 24 return num * 3.1415926 /180; 25 } 26 27 float getDistance(Point start , Point end) 28 { 29 float kCoordFactor = 10000000.0; 30 float lat_1 = start.latitude / kCoordFactor; 31 float lat_2 = end.latitude / kCoordFactor; 32 float lon_1 = start.longitude / kCoordFactor; 33 float lon_2 = end.longitude / kCoordFactor; 34 float lat_rad_1 = convertToRadians(lat_1); 35 float lat_rad_2 = convertToRadians(lat_2); 36 float delta_lat_rad = convertToRadians(lat_2-lat_1); 37 float delta_lon_rad = convertToRadians(lon_2-lon_1); 38 float a = pow(sin(delta_lat_rad/2), 2) + cos(lat_rad_1) * cos(lat_rad_2) * 39 pow(sin(delta_lon_rad/2), 2); 40 float c = 2 * atan2(sqrt(a), sqrt(1-a)); 41 int R = 6371000; // metres 42 return R * c; 43 } 44 45 string getFeatureName( Point point, 46 Feature[] feature_list) { 47 foreach ( f ; feature_list) { 48 if (f.location.latitude == point.latitude && 49 f.location.longitude == point.longitude) { 50 return f.name; 51 } 52 } 53 return ""; 54 } 55 56 class RouteGuideImpl : RouteGuideBase 57 { 58 override Status GetFeature( Point point, ref Feature feature){ 59 logInfo("GetFeature ", toJson(point)); 60 feature.name = getFeatureName(point , list); 61 feature.location = point; 62 return Status.OK; 63 } 64 65 override Status ListFeatures(Rectangle rectangle , ServerWriter!Feature writer) { 66 logInfo("ListFeatures ", toJson(rectangle)); 67 auto lo = rectangle.lo; 68 auto hi = rectangle.hi; 69 long left = min(lo.longitude, hi.longitude); 70 long right = max(lo.longitude, hi.longitude); 71 long top = max(lo.latitude, hi.latitude); 72 long bottom = min(lo.latitude, hi.latitude); 73 foreach ( f ; list) { 74 if (f.location.longitude >= left && 75 f.location.longitude <= right && 76 f.location.latitude >= bottom && 77 f.location.latitude <= top) { 78 writer.write(f); 79 } 80 } 81 return Status.OK; 82 } 83 84 override Status RecordRoute(ServerReader!Point reader, ref RouteSummary summary ){ 85 86 Point point; 87 int point_count = 0; 88 int feature_count = 0; 89 float distance = 0.0; 90 Point previous; 91 import core.stdc.time; 92 auto start_time = cast(int)time(null); 93 while (reader.read(point)) { 94 point_count++; 95 if (getFeatureName(point, list) != "") { 96 feature_count++; 97 } 98 if (point_count != 1) { 99 distance += getDistance(previous, point); 100 } 101 previous = point; 102 } 103 104 auto end_time = cast(int)time(null); 105 summary.pointCount = point_count; 106 summary.featureCount = feature_count; 107 summary.distance = cast(int)distance; 108 auto secs = 109 end_time - start_time; 110 summary.elapsedTime = secs; 111 112 return Status.OK; 113 } 114 115 override Status RouteChat(ServerReaderWriter!(RouteNote , RouteNote) stream){ 116 RouteNote[] received_notes; 117 RouteNote note; 118 while (stream.read(note)) { 119 foreach ( n ; received_notes) { 120 if (n.location.latitude == note.location.latitude && 121 n.location.longitude == note.location.longitude) { 122 stream.write(n); 123 } 124 } 125 received_notes ~= note; 126 } 127 return Status.OK; 128 } 129 } 130 131 132 //////////////////////////////client code //////////////////////////////// 133 enum kCoordFactor_ = 10000000.0; 134 135 Point MakePoint(int latitude, int longitude) { 136 Point p = new Point(); 137 p.latitude = latitude; 138 p.longitude = longitude; 139 return p; 140 } 141 142 Feature MakeFeature(string name, 143 int latitude, int longitude) { 144 Feature f = new Feature(); 145 f.name = name ; 146 f.location = MakePoint(latitude, longitude); 147 return f; 148 } 149 150 RouteNote MakeRouteNote(string message, 151 int latitude, int longitude) { 152 RouteNote n = new RouteNote(); 153 n.message = message; 154 n.location = MakePoint(latitude, longitude); 155 return n; 156 } 157 158 159 bool GetOneFeature(RouteGuideClient client , Point point , ref Feature feature ) { 160 point = MakePoint(409146138, -746188906); 161 feature = client.GetFeature(point); 162 if(feature is null){ 163 writeln("GetFeature rpc failed."); 164 return false; 165 } 166 167 if(feature.name == ""){ 168 writeln("Found no feature at " , 169 feature.location.latitude /kCoordFactor_ ,", ", 170 feature.location.longitude /kCoordFactor_ ); 171 }else{ 172 writeln("Found feature called " , 173 feature.location.latitude /kCoordFactor_ ,", ", 174 feature.location.longitude /kCoordFactor_ ); 175 } 176 177 return true; 178 179 } 180 181 void getFeature(RouteGuideClient client) 182 { 183 Point point; 184 Feature feature = new Feature(); 185 point = MakePoint(409146138, -746188906); 186 GetOneFeature(client , point, feature); 187 point = MakePoint(0, 0); 188 feature = new Feature(); 189 GetOneFeature(client ,point, feature); 190 } 191 192 void listFeatures(RouteGuideClient client) { 193 Rectangle rect = new Rectangle(); 194 Feature feature; 195 rect.lo = MakePoint(400000000 ,-750000000); 196 rect.hi = MakePoint(420000000 , -730000000); 197 writeln("Looking for features between 40, -75 and 42, -73"); 198 199 auto reader = client.ListFeatures(rect); 200 while (reader.read(feature)) { 201 writeln("Found feature called ", 202 feature.name , " at ", 203 feature.location.latitude/kCoordFactor_ , ", ", 204 feature.location.longitude/kCoordFactor_ ); 205 } 206 Status status = reader.finish(); 207 if (status.ok()) { 208 writeln("ListFeatures rpc succeeded."); 209 } else { 210 writeln("ListFeatures rpc failed."); 211 } 212 } 213 214 void recordRoute(RouteGuideClient client) { 215 import std.random; 216 import core.stdc.time; 217 import core.time; 218 import core.thread; 219 Point point; 220 RouteSummary stats = new RouteSummary(); 221 const int kPoints = 10; 222 auto rnd = new Random(cast(uint)time(null)); 223 224 225 226 auto writer = client.RecordRoute(stats); 227 for (int i = 0; i < kPoints; i++) { 228 auto f = list[uniform(0,list.length , rnd)]; 229 writeln( "Visiting point " , 230 f.location.latitude/kCoordFactor_ , ", " , 231 f.location.longitude/kCoordFactor_); 232 if (!writer.write(f.location)) { 233 // Broken stream. 234 break; 235 } 236 Thread.sleep(dur!"msecs"(uniform(500,1500))); 237 } 238 239 writer.writesDone(); 240 Status status = writer.finish(); 241 if (status.ok()) { 242 writeln("Finished trip with " , stats.pointCount , " points\n", 243 "Passed " , stats.featureCount , " features\n", 244 "Travelled " , stats.distance , " meters\n", 245 "It took " , stats.elapsedTime , " seconds"); 246 } 247 else { 248 writeln("RecordRoute rpc failed."); 249 } 250 } 251 252 void routeChat(RouteGuideClient client) { 253 import core.thread; 254 auto stream = client.RouteChat(); 255 256 auto thread = new Thread( (){ 257 RouteNote[] notes=[ 258 MakeRouteNote("First message", 0, 0), 259 MakeRouteNote("Second message", 0, 1), 260 MakeRouteNote("Third message", 1, 0), 261 MakeRouteNote("Fourth message", 0, 0)]; 262 foreach (note ; notes) { 263 writeln( "Sending message " , note.message, 264 " at " , note.location.latitude , ", ", 265 note.location.longitude); 266 stream.write(note); 267 } 268 stream.writesDone(); 269 }).start(); 270 271 RouteNote server_note; 272 while (stream.read(server_note)) { 273 writeln( "Got message " , server_note.message, 274 " at " , server_note.location.latitude , ", ", 275 server_note.location.longitude); 276 } 277 thread.join(); 278 Status status = stream.finish(); 279 if (!status.ok()) { 280 writeln( "RouteChat rpc failed."); 281 } 282 } 283 284 285 286 287 288 int main( string []args) 289 { 290 291 string path; 292 // Usage: command --db_path=path/to/route_guide_db.json. 293 auto oprions = getopt(args,"db_path|f","database file",&path); 294 string data = readText(path); 295 auto json = parseJSON(data); 296 list = toObject!(Feature[])(json); 297 writeln("DB parsed, loaded " , list.length , " features."); 298 string host = "0.0.0.0"; 299 ushort port = 30051; 300 301 Server server = new Server(); 302 server.listen(host , port); 303 server.register( new RouteGuideImpl()); 304 server.start(); 305 306 auto channel = new Channel("127.0.0.1" , port); 307 RouteGuideClient client = new RouteGuideClient(channel); 308 309 writeln("-------------- GetFeature --------------"); 310 client.getFeature(); 311 writeln("-------------- ListFeatures --------------"); 312 client.listFeatures(); 313 writeln("-------------- RecordRoute --------------"); 314 client.recordRoute(); 315 writeln("-------------- RouteChat --------------"); 316 client.routeChat(); 317 318 getchar(); 319 return 0; 320 }