package io.vertx.example.grpc.routeguide; import io.grpc.ManagedChannel; import io.grpc.Status; 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.grpc.stub.StreamObserver; import io.vertx.core.AbstractVerticle; import io.vertx.core.AsyncResult; import io.vertx.core.Handler; import io.vertx.example.grpc.util.Runner; import io.vertx.grpc.GrpcUniExchange; import io.vertx.grpc.VertxChannelBuilder; import java.util.ArrayList; import java.util.List; import java.util.Random; /** * @author <a href="mailto:julien@julienviet.com">Julien Viet</a> */ public class Client extends AbstractVerticle { public static void main(String[] args) { Runner.runExample(Client.class); } private Random random = new Random(); private RouteGuideGrpc.RouteGuideVertxStub stub; @Override public void start() throws Exception { ManagedChannel channel = VertxChannelBuilder .forAddress(vertx, "localhost", 8080) .usePlaintext(true) .build(); stub = RouteGuideGrpc.newVertxStub(channel); List<Feature> features = Util.parseFeatures(Util.getDefaultFeaturesFile()); // Looking for a valid feature getFeature(409146138, -746188906); // Feature missing. getFeature(0, 0); // Looking for features between 40, -75 and 42, -73. listFeatures(400000000, -750000000, 420000000, -730000000); // Record a few randomly selected points from the features file. recordRoute(features, 10); routeChat(); } /** * Blocking unary call example. Calls getFeature and prints the response. */ public void getFeature(int lat, int lon) { System.out.println("*** GetFeature: lat=" + lat + " lon=" + lon); Point request = Point.newBuilder().setLatitude(lat).setLongitude(lon).build(); stub.getFeature(request, ar -> { if (ar.succeeded()) { Feature feature = ar.result(); if (Util.exists(feature)) { System.out.println("Found feature called " + feature.getName() + " at " + Util.getLatitude(feature.getLocation()) + ", " + Util.getLongitude(feature.getLocation())); } else { System.out.println("Found no feature at " + Util.getLatitude(feature.getLocation()) + ", " + Util.getLongitude(feature.getLocation())); } } }); } /** * Blocking server-streaming example. Calls listFeatures with a rectangle of interest. Prints each * response feature as it arrives. */ public void listFeatures(int lowLat, int lowLon, int hiLat, int hiLon) { System.out.println("*** ListFeatures: lowLat=" + lowLat +" lowLon=" + lowLon + " hiLat=" + hiLat + " hiLon=" + hiLon); Rectangle request = Rectangle.newBuilder() .setLo(Point.newBuilder().setLatitude(lowLat).setLongitude(lowLon).build()) .setHi(Point.newBuilder().setLatitude(hiLat).setLongitude(hiLon).build()).build(); stub.listFeatures(request, response -> { List<Feature> features = new ArrayList<>(); response.handler(feature -> { System.out.println("Result #" + features.size() + ": " + feature); features.add(feature); }); // Neede for now as it triggers an NPE if not set response.endHandler(v -> { /* Feb 14, 2017 11:08:53 PM io.grpc.internal.SerializingExecutor$TaskRunner run SEVERE: Exception while executing runnable io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed@6668e779 java.lang.NullPointerException at io.vertx.grpc.impl.GrpcReadStreamImpl$1.onCompleted(GrpcReadStreamImpl.java:69) at io.grpc.stub.ClientCalls$StreamObserverToCallListenerAdapter.onClose(ClientCalls.java:390) at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:422) */ }); }); } class RouteSender { List<Feature> features; GrpcUniExchange<Point, RouteSummary> exchange; AsyncResult result; RouteSender(List<Feature> features, GrpcUniExchange<Point, RouteSummary> exchange) { this.features = features; this.exchange = exchange; } void send(int numPoints) { if (result != null) { // RPC completed or errored before we finished sending. // Sending further requests won't error, but they will just be thrown away. return; } int index = random.nextInt(features.size()); Point point = features.get(index).getLocation(); System.out.println("Visiting point " + Util.getLatitude(point) + ", " + Util.getLongitude(point)); exchange.write(point); if (numPoints > 0) { vertx.setTimer(random.nextInt(1000) + 500, id -> { send(numPoints - 1); }); } else { exchange.end(); } } } /** * Async client-streaming example. Sends {@code numPoints} randomly chosen points from {@code * features} with a variable delay in between. Prints the statistics when they are sent from the * server. */ public void recordRoute(List<Feature> features, int numPoints) throws InterruptedException { System.out.println("*** RecordRoute"); stub.recordRoute(exchange -> { RouteSender sender = new RouteSender(features, exchange); exchange.handler(ar -> { sender.result = ar; if (ar.succeeded()) { RouteSummary summary = ar.result(); System.out.println("Finished trip with " + summary.getPointCount() + " points. Passed " + summary.getFeatureCount() + " features.Travelled " + summary.getDistance() + " meters. It took " + summary.getElapsedTime() + " seconds."); System.out.println("Finished RecordRoute"); } else { System.out.println("RecordRoute Failed: " + Status.fromThrowable(ar.cause())); } }); // Send numPoints points randomly selected from the features list. sender.send(numPoints); }); } /** * Bi-directional example, which can only be asynchronous. Send some chat messages, and print any * chat messages that are sent from the server. */ public void routeChat() { System.out.println("*** RouteChat"); stub.routeChat(exchange -> { exchange.handler(note -> { System.out.println("Got message \"" + note.getMessage() + "\" at " + note.getLocation().getLatitude() + ", " + note.getLocation().getLongitude()); }); exchange.exceptionHandler(err -> { System.out.println("RouteChat Failed: " + Status.fromThrowable(err)); }); exchange.endHandler(v -> { System.out.println("Finished RouteChat"); }); RouteNote[] requests = {newNote("First message", 0, 0), newNote("Second message", 0, 1), newNote("Third message", 1, 0), newNote("Fourth message", 1, 1)}; for (RouteNote request : requests) { System.out.println("Sending message \"" + request.getMessage() + "\" at " + request.getLocation() .getLatitude() + ", " + request.getLocation().getLongitude()); exchange.write(request); } exchange.end(); }); } private RouteNote newNote(String message, int lat, int lon) { return RouteNote.newBuilder().setMessage(message) .setLocation(Point.newBuilder().setLatitude(lat).setLongitude(lon).build()).build(); } }