| /* |
| * |
| * Copyright 2015 gRPC authors. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| |
| // 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 routeguide/route_guide.proto. |
| package main |
| |
| import ( |
| "context" |
| "flag" |
| "io" |
| "log" |
| "math/rand" |
| "time" |
| |
| "google.golang.org/grpc" |
| "google.golang.org/grpc/credentials" |
| "google.golang.org/grpc/examples/data" |
| pb "google.golang.org/grpc/examples/route_guide/routeguide" |
| ) |
| |
| var ( |
| tls = flag.Bool("tls", false, "Connection uses TLS if true, else plain TCP") |
| caFile = flag.String("ca_file", "", "The file containing the CA root cert file") |
| serverAddr = flag.String("server_addr", "localhost:10000", "The server address in the format of host:port") |
| serverHostOverride = flag.String("server_host_override", "x.test.youtube.com", "The server name used to verify the hostname returned by the TLS handshake") |
| ) |
| |
| // printFeature gets the feature for the given point. |
| func printFeature(client pb.RouteGuideClient, point *pb.Point) { |
| log.Printf("Getting feature for point (%d, %d)", point.Latitude, point.Longitude) |
| ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) |
| defer cancel() |
| feature, err := client.GetFeature(ctx, point) |
| if err != nil { |
| log.Fatalf("%v.GetFeatures(_) = _, %v: ", client, err) |
| } |
| log.Println(feature) |
| } |
| |
| // printFeatures lists all the features within the given bounding Rectangle. |
| func printFeatures(client pb.RouteGuideClient, rect *pb.Rectangle) { |
| log.Printf("Looking for features within %v", rect) |
| ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) |
| defer cancel() |
| stream, err := client.ListFeatures(ctx, rect) |
| if err != nil { |
| log.Fatalf("%v.ListFeatures(_) = _, %v", client, err) |
| } |
| for { |
| feature, err := stream.Recv() |
| if err == io.EOF { |
| break |
| } |
| if err != nil { |
| log.Fatalf("%v.ListFeatures(_) = _, %v", client, err) |
| } |
| log.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)) |
| } |
| log.Printf("Traversing %d points.", len(points)) |
| ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) |
| defer cancel() |
| stream, err := client.RecordRoute(ctx) |
| if err != nil { |
| log.Fatalf("%v.RecordRoute(_) = _, %v", client, err) |
| } |
| for _, point := range points { |
| if err := stream.Send(point); err != nil { |
| log.Fatalf("%v.Send(%v) = %v", stream, point, err) |
| } |
| } |
| reply, err := stream.CloseAndRecv() |
| if err != nil { |
| log.Fatalf("%v.CloseAndRecv() got error %v, want %v", stream, err, nil) |
| } |
| log.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{ |
| {Location: &pb.Point{Latitude: 0, Longitude: 1}, Message: "First message"}, |
| {Location: &pb.Point{Latitude: 0, Longitude: 2}, Message: "Second message"}, |
| {Location: &pb.Point{Latitude: 0, Longitude: 3}, Message: "Third message"}, |
| {Location: &pb.Point{Latitude: 0, Longitude: 1}, Message: "Fourth message"}, |
| {Location: &pb.Point{Latitude: 0, Longitude: 2}, Message: "Fifth message"}, |
| {Location: &pb.Point{Latitude: 0, Longitude: 3}, Message: "Sixth message"}, |
| } |
| ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) |
| defer cancel() |
| stream, err := client.RouteChat(ctx) |
| if err != nil { |
| log.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 { |
| log.Fatalf("Failed to receive a note : %v", err) |
| } |
| log.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 { |
| log.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{Latitude: lat, Longitude: long} |
| } |
| |
| func main() { |
| flag.Parse() |
| var opts []grpc.DialOption |
| if *tls { |
| if *caFile == "" { |
| *caFile = data.Path("x509/ca_cert.pem") |
| } |
| creds, err := credentials.NewClientTLSFromFile(*caFile, *serverHostOverride) |
| if err != nil { |
| log.Fatalf("Failed to create TLS credentials %v", err) |
| } |
| opts = append(opts, grpc.WithTransportCredentials(creds)) |
| } else { |
| opts = append(opts, grpc.WithInsecure()) |
| } |
| |
| opts = append(opts, grpc.WithBlock()) |
| conn, err := grpc.Dial(*serverAddr, opts...) |
| if err != nil { |
| log.Fatalf("fail to dial: %v", err) |
| } |
| defer conn.Close() |
| client := pb.NewRouteGuideClient(conn) |
| |
| // Looking for a valid feature |
| printFeature(client, &pb.Point{Latitude: 409146138, Longitude: -746188906}) |
| |
| // Feature missing. |
| printFeature(client, &pb.Point{Latitude: 0, Longitude: 0}) |
| |
| // Looking for features between 40, -75 and 42, -73. |
| printFeatures(client, &pb.Rectangle{ |
| Lo: &pb.Point{Latitude: 400000000, Longitude: -750000000}, |
| Hi: &pb.Point{Latitude: 420000000, Longitude: -730000000}, |
| }) |
| |
| // RecordRoute |
| runRecordRoute(client) |
| |
| // RouteChat |
| runRouteChat(client) |
| } |