forked from vert-x3/vertx-examples
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathServer.java
202 lines (168 loc) · 6.43 KB
/
Server.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
package io.vertx.example.grpc.routeguide;
import io.grpc.examples.routeguide.Feature;
import io.grpc.examples.routeguide.Point;
import io.grpc.examples.routeguide.Rectangle;
import io.grpc.examples.routeguide.RouteGuideGrpc;
import io.grpc.examples.routeguide.RouteNote;
import io.grpc.examples.routeguide.RouteSummary;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.example.grpc.util.Runner;
import io.vertx.grpc.GrpcBidiExchange;
import io.vertx.grpc.GrpcReadStream;
import io.vertx.grpc.GrpcWriteStream;
import io.vertx.grpc.VertxServer;
import io.vertx.grpc.VertxServerBuilder;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
/**
* @author <a href="mailto:[email protected]">Julien Viet</a>
*/
public class Server extends AbstractVerticle {
public static void main(String[] args) {
Runner.runExample(Server.class);
}
private List<Feature> features;
private final Map<Point, List<RouteNote>> routeNotes = new HashMap<>();
@Override
public void start() throws Exception {
URL featureFile = Util.getDefaultFeaturesFile();
features = Util.parseFeatures(featureFile);
VertxServer server = VertxServerBuilder.forAddress(vertx, "localhost", 8080).addService(new RouteGuideGrpc.RouteGuideVertxImplBase() {
@Override
public void getFeature(Point request, Promise<Feature> response) {
response.complete(checkFeature(request));
}
@Override
public void listFeatures(Rectangle request, GrpcWriteStream<Feature> response) {
int left = Math.min(request.getLo().getLongitude(), request.getHi().getLongitude());
int right = Math.max(request.getLo().getLongitude(), request.getHi().getLongitude());
int top = Math.max(request.getLo().getLatitude(), request.getHi().getLatitude());
int bottom = Math.min(request.getLo().getLatitude(), request.getHi().getLatitude());
for (Feature feature : features) {
if (!Util.exists(feature)) {
continue;
}
int lat = feature.getLocation().getLatitude();
int lon = feature.getLocation().getLongitude();
if (lon >= left && lon <= right && lat >= bottom && lat <= top) {
response.write(feature);
}
}
response.end();
}
@Override
public void recordRoute(GrpcReadStream<Point> request, Future<RouteSummary> response) {
request.exceptionHandler(err -> {
System.out.println("recordRoute cancelled");
});
RouteRecorder recorder = new RouteRecorder();
request.handler(recorder::append);
request.endHandler(v -> {
response.complete(recorder.build());
});
}
@Override
public void routeChat(GrpcBidiExchange<RouteNote, RouteNote> exchange) {
exchange.handler(note -> {
List<RouteNote> notes = getOrCreateNotes(note.getLocation());
// Respond with all previous notes at this location.
for (RouteNote prevNote : notes.toArray(new RouteNote[0])) {
exchange.write(prevNote);
}
// Now add the new note to the list
notes.add(note);
});
exchange.exceptionHandler(err -> {
System.out.println("routeChat cancelled");
});
exchange.endHandler(v -> exchange.end());
}
}).build();
server.start(ar -> {
if (ar.succeeded()) {
System.out.println("gRPC service started");
} else {
System.out.println("Could not start server " + ar.cause().getMessage());
}
});
}
class RouteRecorder {
int pointCount;
int featureCount;
int distance;
Point previous;
final long startTime = System.nanoTime();
void append(Point point) {
pointCount++;
if (Util.exists(checkFeature(point))) {
featureCount++;
}
// For each point after the first, add the incremental distance from the previous point to
// the total distance value.
if (previous != null) {
distance += calcDistance(previous, point);
}
previous = point;
}
RouteSummary build() {
long seconds = NANOSECONDS.toSeconds(System.nanoTime() - startTime);
return RouteSummary.newBuilder().setPointCount(pointCount)
.setFeatureCount(featureCount).setDistance(distance)
.setElapsedTime((int) seconds).build();
}
}
/**
* Get the notes list for the given location. If missing, create it.
*/
private List<RouteNote> getOrCreateNotes(Point location) {
List<RouteNote> notes = Collections.synchronizedList(new ArrayList<RouteNote>());
List<RouteNote> prevNotes = routeNotes.putIfAbsent(location, notes);
return prevNotes != null ? prevNotes : notes;
}
/**
* Gets the feature at the given point.
*
* @param location the location to check.
* @return The feature object at the point. Note that an empty name indicates no feature.
*/
private Feature checkFeature(Point location) {
for (Feature feature : features) {
if (feature.getLocation().getLatitude() == location.getLatitude()
&& feature.getLocation().getLongitude() == location.getLongitude()) {
return feature;
}
}
// No feature was found, return an unnamed feature.
return Feature.newBuilder().setName("").setLocation(location).build();
}
/**
* Calculate the distance between two points using the "haversine" formula.
* This code was taken from http://www.movable-type.co.uk/scripts/latlong.html.
*
* @param start The starting point
* @param end The end point
* @return The distance between the points in meters
*/
private static int calcDistance(Point start, Point end) {
double lat1 = Util.getLatitude(start);
double lat2 = Util.getLatitude(end);
double lon1 = Util.getLongitude(start);
double lon2 = Util.getLongitude(end);
int r = 6371000; // meters
double phi1 = Math.toRadians(lat1);
double phi2 = Math.toRadians(lat2);
double deltaPhi = Math.toRadians(lat2 - lat1);
double deltaLambda = Math.toRadians(lon2 - lon1);
double a = Math.sin(deltaPhi / 2) * Math.sin(deltaPhi / 2)
+ Math.cos(phi1) * Math.cos(phi2) * Math.sin(deltaLambda / 2) * Math.sin(deltaLambda / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return (int) (r * c);
}
}