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 }