| /* |
| * |
| * Copyright 2015, Google Inc. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following disclaimer |
| * in the documentation and/or other materials provided with the |
| * distribution. |
| * * Neither the name of Google Inc. nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| */ |
| |
| // Package main implements a simple gRPC client that demonstrates how to use gRPC-Go libraries |
| // to perform unary, client streaming, server streaming and full duplex RPCs. |
| // |
| // It interacts with the route guide service whose definition can be found in proto/route_guide.proto. |
| package main |
| |
| import ( |
| "flag" |
| "io" |
| "math/rand" |
| "time" |
| |
| "golang.org/x/net/context" |
| "google.golang.org/grpc" |
| "google.golang.org/grpc/credentials" |
| pb "google.golang.org/grpc/examples/route_guide/routeguide" |
| "google.golang.org/grpc/grpclog" |
| ) |
| |
| var ( |
| tls = flag.Bool("tls", false, "Connection uses TLS if true, else plain TCP") |
| caFile = flag.String("ca_file", "testdata/ca.pem", "The file containning the CA root cert file") |
| serverAddr = flag.String("server_addr", "127.0.0.1:10000", "The server address in the format of host:port") |
| serverHostOverride = flag.String("server_host_override", "x.test.youtube.com", "The server name use to verify the hostname returned by TLS handshake") |
| ) |
| |
| // printFeature gets the feature for the given point. |
| func printFeature(client pb.RouteGuideClient, point *pb.Point) { |
| grpclog.Printf("Getting feature for point (%d, %d)", point.Latitude, point.Longitude) |
| feature, err := client.GetFeature(context.Background(), point) |
| if err != nil { |
| grpclog.Fatalf("%v.GetFeatures(_) = _, %v: ", client, err) |
| } |
| grpclog.Println(feature) |
| } |
| |
| // printFeatures lists all the features within the given bounding Rectangle. |
| func printFeatures(client pb.RouteGuideClient, rect *pb.Rectangle) { |
| grpclog.Printf("Looking for features within %v", rect) |
| stream, err := client.ListFeatures(context.Background(), rect) |
| if err != nil { |
| grpclog.Fatalf("%v.ListFeatures(_) = _, %v", client, err) |
| } |
| for { |
| feature, err := stream.Recv() |
| if err == io.EOF { |
| break |
| } |
| if err != nil { |
| grpclog.Fatalf("%v.ListFeatures(_) = _, %v", client, err) |
| } |
| grpclog.Println(feature) |
| } |
| } |
| |
| // runRecordRoute sends a sequence of points to server and expects to get a RouteSummary from server. |
| func runRecordRoute(client pb.RouteGuideClient) { |
| // Create a random number of random points |
| r := rand.New(rand.NewSource(time.Now().UnixNano())) |
| pointCount := int(r.Int31n(100)) + 2 // Traverse at least two points |
| var points []*pb.Point |
| for i := 0; i < pointCount; i++ { |
| points = append(points, randomPoint(r)) |
| } |
| grpclog.Printf("Traversing %d points.", len(points)) |
| stream, err := client.RecordRoute(context.Background()) |
| if err != nil { |
| grpclog.Fatalf("%v.RecordRoute(_) = _, %v", client, err) |
| } |
| for _, point := range points { |
| if err := stream.Send(point); err != nil { |
| grpclog.Fatalf("%v.Send(%v) = %v", stream, point, err) |
| } |
| } |
| reply, err := stream.CloseAndRecv() |
| if err != nil { |
| grpclog.Fatalf("%v.CloseAndRecv() got error %v, want %v", stream, err, nil) |
| } |
| grpclog.Printf("Route summary: %v", reply) |
| } |
| |
| // runRouteChat receives a sequence of route notes, while sending notes for various locations. |
| func runRouteChat(client pb.RouteGuideClient) { |
| notes := []*pb.RouteNote{ |
| {&pb.Point{0, 1}, "First message"}, |
| {&pb.Point{0, 2}, "Second message"}, |
| {&pb.Point{0, 3}, "Third message"}, |
| {&pb.Point{0, 1}, "Fourth message"}, |
| {&pb.Point{0, 2}, "Fifth message"}, |
| {&pb.Point{0, 3}, "Sixth message"}, |
| } |
| stream, err := client.RouteChat(context.Background()) |
| if err != nil { |
| grpclog.Fatalf("%v.RouteChat(_) = _, %v", client, err) |
| } |
| waitc := make(chan struct{}) |
| go func() { |
| for { |
| in, err := stream.Recv() |
| if err == io.EOF { |
| // read done. |
| close(waitc) |
| return |
| } |
| if err != nil { |
| grpclog.Fatalf("Failed to receive a note : %v", err) |
| } |
| grpclog.Printf("Got message %s at point(%d, %d)", in.Message, in.Location.Latitude, in.Location.Longitude) |
| } |
| }() |
| for _, note := range notes { |
| if err := stream.Send(note); err != nil { |
| grpclog.Fatalf("Failed to send a note: %v", err) |
| } |
| } |
| stream.CloseSend() |
| <-waitc |
| } |
| |
| func randomPoint(r *rand.Rand) *pb.Point { |
| lat := (r.Int31n(180) - 90) * 1e7 |
| long := (r.Int31n(360) - 180) * 1e7 |
| return &pb.Point{lat, long} |
| } |
| |
| func main() { |
| flag.Parse() |
| var opts []grpc.DialOption |
| if *tls { |
| var sn string |
| if *serverHostOverride != "" { |
| sn = *serverHostOverride |
| } |
| var creds credentials.TransportAuthenticator |
| if *caFile != "" { |
| var err error |
| creds, err = credentials.NewClientTLSFromFile(*caFile, sn) |
| if err != nil { |
| grpclog.Fatalf("Failed to create TLS credentials %v", err) |
| } |
| } else { |
| creds = credentials.NewClientTLSFromCert(nil, sn) |
| } |
| opts = append(opts, grpc.WithTransportCredentials(creds)) |
| } else { |
| opts = append(opts, grpc.WithInsecure()) |
| } |
| conn, err := grpc.Dial(*serverAddr, opts...) |
| if err != nil { |
| grpclog.Fatalf("fail to dial: %v", err) |
| } |
| defer conn.Close() |
| client := pb.NewRouteGuideClient(conn) |
| |
| // Looking for a valid feature |
| printFeature(client, &pb.Point{409146138, -746188906}) |
| |
| // Feature missing. |
| printFeature(client, &pb.Point{0, 0}) |
| |
| // Looking for features between 40, -75 and 42, -73. |
| printFeatures(client, &pb.Rectangle{&pb.Point{400000000, -750000000}, &pb.Point{420000000, -730000000}}) |
| |
| // RecordRoute |
| runRecordRoute(client) |
| |
| // RouteChat |
| runRouteChat(client) |
| } |