/* * * Copyright 2017 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 grpc import ( "strings" "google.golang.org/grpc/grpclog" "google.golang.org/grpc/resolver" ) // ccResolverWrapper is a wrapper on top of cc for resolvers. // It implements resolver.ClientConnection interface. type ccResolverWrapper struct { cc *ClientConn resolver resolver.Resolver addrCh chan []resolver.Address scCh chan string done chan struct{} } // newCCResolverWrapper parses cc.target for scheme and gets the resolver // builder for this scheme. It then builds the resolver and starts the // monitoring goroutine for it. // // This function could return nil, nil, in tests for old behaviors. // TODO(bar) never return nil, nil when DNS becomes the default resolver. func newCCResolverWrapper(cc *ClientConn) (*ccResolverWrapper, error) { var scheme string targetSplitted := strings.Split(cc.target, "://") if len(targetSplitted) >= 2 { scheme = targetSplitted[0] } grpclog.Infof("dialing to target with scheme: %q", scheme) rb := resolver.Get(scheme) if rb == nil { // TODO(bar) return error when DNS becomes the default (implemented and // registered by DNS package). grpclog.Infof("could not get resolver for scheme: %q", scheme) return nil, nil } ccr := &ccResolverWrapper{ cc: cc, addrCh: make(chan []resolver.Address, 1), scCh: make(chan string, 1), done: make(chan struct{}), } var err error ccr.resolver, err = rb.Build(cc.target, ccr, resolver.BuildOption{}) if err != nil { return nil, err } go ccr.watcher() return ccr, nil } // watcher processes address updates and service config updates sequencially. // Otherwise, we need to resolve possible races between address and service // config (e.g. they specify different balancer types). func (ccr *ccResolverWrapper) watcher() { for { select { case <-ccr.done: return default: } select { case addrs := <-ccr.addrCh: grpclog.Infof("ccResolverWrapper: sending new addresses to balancer wrapper: %v", addrs) // TODO(bar switching) this should never be nil. Pickfirst should be default. if ccr.cc.balancerWrapper != nil { // TODO(bar switching) create balancer if it's nil? ccr.cc.balancerWrapper.handleResolvedAddrs(addrs, nil) } case sc := <-ccr.scCh: grpclog.Infof("ccResolverWrapper: got new service config: %v", sc) case <-ccr.done: return } } } func (ccr *ccResolverWrapper) close() { ccr.resolver.Close() close(ccr.done) } // NewAddress is called by the resolver implemenetion to send addresses to gRPC. func (ccr *ccResolverWrapper) NewAddress(addrs []resolver.Address) { select { case <-ccr.addrCh: default: } ccr.addrCh <- addrs } // NewServiceConfig is called by the resolver implemenetion to send service // configs to gPRC. func (ccr *ccResolverWrapper) NewServiceConfig(sc string) { select { case <-ccr.scCh: default: } ccr.scCh <- sc }