dubbo.apache.org/dubbo-go/v3@v3.1.1/protocol/grpc/client.go (about)

     1  /*
     2   * Licensed to the Apache Software Foundation (ASF) under one or more
     3   * contributor license agreements.  See the NOTICE file distributed with
     4   * this work for additional information regarding copyright ownership.
     5   * The ASF licenses this file to You under the Apache License, Version 2.0
     6   * (the "License"); you may not use this file except in compliance with
     7   * the License.  You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  
    18  package grpc
    19  
    20  import (
    21  	"reflect"
    22  	"sync"
    23  	"time"
    24  )
    25  
    26  import (
    27  	"github.com/dubbogo/gost/log/logger"
    28  
    29  	"github.com/dustin/go-humanize"
    30  
    31  	"github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc"
    32  
    33  	"github.com/opentracing/opentracing-go"
    34  
    35  	"google.golang.org/grpc"
    36  	"google.golang.org/grpc/credentials"
    37  	"google.golang.org/grpc/credentials/insecure"
    38  
    39  	"gopkg.in/yaml.v2"
    40  )
    41  
    42  import (
    43  	"dubbo.apache.org/dubbo-go/v3/common"
    44  	"dubbo.apache.org/dubbo-go/v3/common/constant"
    45  	"dubbo.apache.org/dubbo-go/v3/config"
    46  )
    47  
    48  var clientConf *ClientConfig
    49  var clientConfInitOnce sync.Once
    50  
    51  // Client is gRPC client include client connection and invoker
    52  type Client struct {
    53  	*grpc.ClientConn
    54  	invoker reflect.Value
    55  }
    56  
    57  // NewClient creates a new gRPC client.
    58  func NewClient(url *common.URL) (*Client, error) {
    59  	clientConfInitOnce.Do(clientInit)
    60  
    61  	// If global trace instance was set, it means trace function enabled.
    62  	// If not, will return NoopTracer.
    63  	tracer := opentracing.GlobalTracer()
    64  	dialOpts := make([]grpc.DialOption, 0, 4)
    65  
    66  	// set max send and recv msg size
    67  	maxCallRecvMsgSize := constant.DefaultMaxCallRecvMsgSize
    68  	if recvMsgSize, err := humanize.ParseBytes(url.GetParam(constant.MaxCallRecvMsgSize, "")); err == nil && recvMsgSize > 0 {
    69  		maxCallRecvMsgSize = int(recvMsgSize)
    70  	}
    71  	maxCallSendMsgSize := constant.DefaultMaxCallSendMsgSize
    72  	if sendMsgSize, err := humanize.ParseBytes(url.GetParam(constant.MaxCallSendMsgSize, "")); err == nil && sendMsgSize > 0 {
    73  		maxCallSendMsgSize = int(sendMsgSize)
    74  	}
    75  
    76  	// consumer config client connectTimeout
    77  	//connectTimeout := config.GetConsumerConfig().ConnectTimeout
    78  
    79  	dialOpts = append(dialOpts,
    80  		grpc.WithBlock(),
    81  		// todo config network timeout
    82  		grpc.WithTimeout(time.Second*3),
    83  		grpc.WithUnaryInterceptor(otgrpc.OpenTracingClientInterceptor(tracer, otgrpc.LogPayloads())),
    84  		grpc.WithStreamInterceptor(otgrpc.OpenTracingStreamClientInterceptor(tracer, otgrpc.LogPayloads())),
    85  		grpc.WithDefaultCallOptions(
    86  			grpc.CallContentSubtype(clientConf.ContentSubType),
    87  			grpc.MaxCallRecvMsgSize(maxCallRecvMsgSize),
    88  			grpc.MaxCallSendMsgSize(maxCallSendMsgSize),
    89  		),
    90  	)
    91  	tlsConfig := config.GetRootConfig().TLSConfig
    92  
    93  	if tlsConfig != nil {
    94  		cfg, err := config.GetClientTlsConfig(&config.TLSConfig{
    95  			CACertFile:    tlsConfig.CACertFile,
    96  			TLSCertFile:   tlsConfig.TLSCertFile,
    97  			TLSKeyFile:    tlsConfig.TLSKeyFile,
    98  			TLSServerName: tlsConfig.TLSServerName,
    99  		})
   100  		logger.Infof("Grpc Client initialized the TLSConfig configuration")
   101  		if err != nil {
   102  			return nil, err
   103  		}
   104  		dialOpts = append(dialOpts, grpc.WithTransportCredentials(credentials.NewTLS(cfg)))
   105  	} else {
   106  		dialOpts = append(dialOpts, grpc.WithTransportCredentials(insecure.NewCredentials()))
   107  	}
   108  
   109  	conn, err := grpc.Dial(url.Location, dialOpts...)
   110  	if err != nil {
   111  		logger.Errorf("grpc dial error: %v", err)
   112  		return nil, err
   113  	}
   114  
   115  	key := url.GetParam(constant.InterfaceKey, "")
   116  	impl := config.GetConsumerServiceByInterfaceName(key)
   117  	invoker := getInvoker(impl, conn)
   118  
   119  	return &Client{
   120  		ClientConn: conn,
   121  		invoker:    reflect.ValueOf(invoker),
   122  	}, nil
   123  }
   124  
   125  func clientInit() {
   126  	// load rootConfig from runtime
   127  	rootConfig := config.GetRootConfig()
   128  
   129  	clientConfig := GetClientConfig()
   130  	clientConf = &clientConfig
   131  
   132  	// check client config and decide whether to use the default config
   133  	defer func() {
   134  		if clientConf == nil || len(clientConf.ContentSubType) == 0 {
   135  			defaultClientConfig := GetDefaultClientConfig()
   136  			clientConf = &defaultClientConfig
   137  		}
   138  		if err := clientConf.Validate(); err != nil {
   139  			panic(err)
   140  		}
   141  	}()
   142  
   143  	if rootConfig.Application == nil {
   144  		return
   145  	}
   146  	protocolConf := config.GetRootConfig().Protocols
   147  
   148  	if protocolConf == nil {
   149  		logger.Info("protocol_conf default use dubbo config")
   150  	} else {
   151  		grpcConf := protocolConf[GRPC]
   152  		if grpcConf == nil {
   153  			logger.Warnf("grpcConf is nil")
   154  			return
   155  		}
   156  		grpcConfByte, err := yaml.Marshal(grpcConf)
   157  		if err != nil {
   158  			panic(err)
   159  		}
   160  		err = yaml.Unmarshal(grpcConfByte, clientConf)
   161  		if err != nil {
   162  			panic(err)
   163  		}
   164  	}
   165  }
   166  
   167  func getInvoker(impl interface{}, conn *grpc.ClientConn) interface{} {
   168  	var in []reflect.Value
   169  	in = append(in, reflect.ValueOf(conn))
   170  	method := reflect.ValueOf(impl).MethodByName("GetDubboStub")
   171  	res := method.Call(in)
   172  	return res[0].Interface()
   173  }