| /* | |
| * | |
| * Copyright 2018 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. | |
| * | |
| */ | |
| // Binary client demonstrates how to use custom name resolvers to resolve | |
| // server backend addresses. | |
| package main | |
| import ( | |
| "context" | |
| "fmt" | |
| "log" | |
| "time" | |
| "google.golang.org/grpc" | |
| "google.golang.org/grpc/credentials/insecure" | |
| ecpb "google.golang.org/grpc/examples/features/proto/echo" | |
| "google.golang.org/grpc/resolver" | |
| ) | |
| const ( | |
| exampleScheme = "example" | |
| exampleServiceName = "resolver.example.grpc.io" | |
| backendAddr = "localhost:50051" | |
| ) | |
| func callUnaryEcho(c ecpb.EchoClient, message string) { | |
| ctx, cancel := context.WithTimeout(context.Background(), time.Second) | |
| defer cancel() | |
| r, err := c.UnaryEcho(ctx, &ecpb.EchoRequest{Message: message}) | |
| if err != nil { | |
| log.Fatalf("could not greet: %v", err) | |
| } | |
| fmt.Println(r.Message) | |
| } | |
| func makeRPCs(cc *grpc.ClientConn, n int) { | |
| hwc := ecpb.NewEchoClient(cc) | |
| for i := 0; i < n; i++ { | |
| callUnaryEcho(hwc, "this is examples/name_resolving") | |
| } | |
| } | |
| func main() { | |
| passthroughConn, err := grpc.NewClient( | |
| fmt.Sprintf("passthrough:///%s", backendAddr), // Dial to "passthrough:///localhost:50051" | |
| grpc.WithTransportCredentials(insecure.NewCredentials()), | |
| ) | |
| if err != nil { | |
| log.Fatalf("did not connect: %v", err) | |
| } | |
| defer passthroughConn.Close() | |
| fmt.Printf("--- calling helloworld.Greeter/SayHello to \"passthrough:///%s\"\n", backendAddr) | |
| makeRPCs(passthroughConn, 10) | |
| fmt.Println() | |
| exampleConn, err := grpc.NewClient( | |
| fmt.Sprintf("%s:///%s", exampleScheme, exampleServiceName), // Dial to "example:///resolver.example.grpc.io" | |
| grpc.WithTransportCredentials(insecure.NewCredentials()), | |
| ) | |
| if err != nil { | |
| log.Fatalf("did not connect: %v", err) | |
| } | |
| defer exampleConn.Close() | |
| fmt.Printf("--- calling helloworld.Greeter/SayHello to \"%s:///%s\"\n", exampleScheme, exampleServiceName) | |
| makeRPCs(exampleConn, 10) | |
| } | |
| // Following is an example name resolver. It includes a | |
| // ResolverBuilder(https://godoc.org/google.golang.org/grpc/resolver#Builder) | |
| // and a Resolver(https://godoc.org/google.golang.org/grpc/resolver#Resolver). | |
| // | |
| // A ResolverBuilder is registered for a scheme (in this example, "example" is | |
| // the scheme). When a ClientConn is created for this scheme, the | |
| // ResolverBuilder will be picked to build a Resolver. Note that a new Resolver | |
| // is built for each ClientConn. The Resolver will watch the updates for the | |
| // target, and send updates to the ClientConn. | |
| // exampleResolverBuilder is a | |
| // ResolverBuilder(https://godoc.org/google.golang.org/grpc/resolver#Builder). | |
| type exampleResolverBuilder struct{} | |
| func (*exampleResolverBuilder) Build(target resolver.Target, cc resolver.ClientConn, _ resolver.BuildOptions) (resolver.Resolver, error) { | |
| r := &exampleResolver{ | |
| target: target, | |
| cc: cc, | |
| addrsStore: map[string][]string{ | |
| exampleServiceName: {backendAddr}, | |
| }, | |
| } | |
| r.start() | |
| return r, nil | |
| } | |
| func (*exampleResolverBuilder) Scheme() string { return exampleScheme } | |
| // exampleResolver is a | |
| // Resolver(https://godoc.org/google.golang.org/grpc/resolver#Resolver). | |
| type exampleResolver struct { | |
| target resolver.Target | |
| cc resolver.ClientConn | |
| addrsStore map[string][]string | |
| } | |
| func (r *exampleResolver) start() { | |
| addrStrs := r.addrsStore[r.target.Endpoint()] | |
| addrs := make([]resolver.Address, len(addrStrs)) | |
| for i, s := range addrStrs { | |
| addrs[i] = resolver.Address{Addr: s} | |
| } | |
| r.cc.UpdateState(resolver.State{Addresses: addrs}) | |
| } | |
| func (*exampleResolver) ResolveNow(resolver.ResolveNowOptions) {} | |
| func (*exampleResolver) Close() {} | |
| func init() { | |
| // Register the example ResolverBuilder. This is usually done in a package's | |
| // init() function. | |
| resolver.Register(&exampleResolverBuilder{}) | |
| } |