trpc.group/trpc-go/trpc-go@v1.0.3/config.go (about)

     1  //
     2  //
     3  // Tencent is pleased to support the open source community by making tRPC available.
     4  //
     5  // Copyright (C) 2023 THL A29 Limited, a Tencent company.
     6  // All rights reserved.
     7  //
     8  // If you have downloaded a copy of the tRPC source code from Tencent,
     9  // please note that tRPC source code is licensed under the  Apache 2.0 License,
    10  // A copy of the Apache 2.0 License is included in this file.
    11  //
    12  //
    13  
    14  package trpc
    15  
    16  import (
    17  	"errors"
    18  	"flag"
    19  	"fmt"
    20  	"net"
    21  	"os"
    22  	"strconv"
    23  	"strings"
    24  	"sync/atomic"
    25  	"time"
    26  
    27  	yaml "gopkg.in/yaml.v3"
    28  	"trpc.group/trpc-go/trpc-go/internal/expandenv"
    29  	trpcpb "trpc.group/trpc/trpc-protocol/pb/go/trpc"
    30  
    31  	"trpc.group/trpc-go/trpc-go/client"
    32  	"trpc.group/trpc-go/trpc-go/codec"
    33  	"trpc.group/trpc-go/trpc-go/errs"
    34  	"trpc.group/trpc-go/trpc-go/internal/rand"
    35  	"trpc.group/trpc-go/trpc-go/plugin"
    36  	"trpc.group/trpc-go/trpc-go/rpcz"
    37  )
    38  
    39  // ServerConfigPath is the file path of trpc server config file.
    40  // By default, it's ./trpc_go.yaml. It can be set by the flag -conf.
    41  var ServerConfigPath = defaultConfigPath
    42  
    43  const (
    44  	defaultConfigPath  = "./trpc_go.yaml"
    45  	defaultIdleTimeout = 60000 // in ms
    46  )
    47  
    48  // serverConfigPath returns the file path of trpc server config file.
    49  // With the highest priority: modifying value of ServerConfigPath.
    50  // With second-highest priority: setting by flag --conf or -conf.
    51  // With third-highest priority: using ./trpc_go.yaml as default path.
    52  func serverConfigPath() string {
    53  	if ServerConfigPath == defaultConfigPath && !flag.Parsed() {
    54  		flag.StringVar(&ServerConfigPath, "conf", defaultConfigPath, "server config path")
    55  		flag.Parse()
    56  	}
    57  	return ServerConfigPath
    58  }
    59  
    60  // Config is the configuration for trpc, which can be divided into 4 parts:
    61  // 1. Global config.
    62  // 2. Server config.
    63  // 3. Client config.
    64  // 4. Plugins config.
    65  type Config struct {
    66  	Global struct {
    67  		Namespace     string `yaml:"namespace"`      // Namespace for the configuration.
    68  		EnvName       string `yaml:"env_name"`       // Environment name.
    69  		ContainerName string `yaml:"container_name"` // Container name.
    70  		LocalIP       string `yaml:"local_ip"`       // Local IP address.
    71  		EnableSet     string `yaml:"enable_set"`     // Y/N. Whether to enable Set. Default is N.
    72  		// Full set name with the format: [set name].[set region].[set group name].
    73  		FullSetName string `yaml:"full_set_name"`
    74  		// Size of the read buffer in bytes. <=0 means read buffer disabled. Default value will be used if not set.
    75  		ReadBufferSize *int `yaml:"read_buffer_size,omitempty"`
    76  	}
    77  	Server struct {
    78  		App      string `yaml:"app"`       // Application name.
    79  		Server   string `yaml:"server"`    // Server name.
    80  		BinPath  string `yaml:"bin_path"`  // Binary file path.
    81  		DataPath string `yaml:"data_path"` // Data file path.
    82  		ConfPath string `yaml:"conf_path"` // Configuration file path.
    83  		Admin    struct {
    84  			IP           string      `yaml:"ip"`            // NIC IP to bind, e.g., 127.0.0.1.
    85  			Nic          string      `yaml:"nic"`           // NIC to bind.
    86  			Port         uint16      `yaml:"port"`          // Port to bind, e.g., 80. Default is 9028.
    87  			ReadTimeout  int         `yaml:"read_timeout"`  // Read timeout in milliseconds for admin HTTP server.
    88  			WriteTimeout int         `yaml:"write_timeout"` // Write timeout in milliseconds for admin HTTP server.
    89  			EnableTLS    bool        `yaml:"enable_tls"`    // Whether to enable TLS.
    90  			RPCZ         *RPCZConfig `yaml:"rpcz"`          // RPCZ configuration.
    91  		}
    92  		Transport    string           `yaml:"transport"`     // Transport type.
    93  		Network      string           `yaml:"network"`       // Network type for all services. Default is tcp.
    94  		Protocol     string           `yaml:"protocol"`      // Protocol type for all services. Default is trpc.
    95  		Filter       []string         `yaml:"filter"`        // Filters for all services.
    96  		StreamFilter []string         `yaml:"stream_filter"` // Stream filters for all services.
    97  		Service      []*ServiceConfig `yaml:"service"`       // Configuration for each individual service.
    98  		// Minimum waiting time in milliseconds when closing the server to wait for deregister finish.
    99  		CloseWaitTime int `yaml:"close_wait_time"`
   100  		// Maximum waiting time in milliseconds when closing the server to wait for requests to finish.
   101  		MaxCloseWaitTime int `yaml:"max_close_wait_time"`
   102  		Timeout          int `yaml:"timeout"` // Timeout in milliseconds.
   103  	}
   104  	Client  ClientConfig  `yaml:"client"`  // Client configuration.
   105  	Plugins plugin.Config `yaml:"plugins"` // Plugins configuration.
   106  }
   107  
   108  // RPCZConfig is the config for rpcz.GlobalRPCZ, and is a field of Config.Admin.
   109  type RPCZConfig struct {
   110  	Fraction   float64           `yaml:"fraction"`
   111  	Capacity   uint32            `yaml:"capacity"`
   112  	RecordWhen *RecordWhenConfig `yaml:"record_when"`
   113  }
   114  
   115  func (c *RPCZConfig) generate() *rpcz.Config {
   116  	if c.Capacity == 0 {
   117  		const defaultCapacity uint32 = 10000
   118  		c.Capacity = defaultCapacity
   119  	}
   120  
   121  	config := &rpcz.Config{
   122  		Fraction: c.Fraction,
   123  		Capacity: c.Capacity,
   124  	}
   125  	if c.RecordWhen != nil {
   126  		config.ShouldRecord = c.RecordWhen.shouldRecord()
   127  	}
   128  	return config
   129  }
   130  
   131  type node interface {
   132  	yaml.Unmarshaler
   133  	shouldRecorder
   134  }
   135  
   136  type nodeKind string
   137  
   138  const (
   139  	kindAND              nodeKind = "AND"
   140  	kindOR               nodeKind = "OR"
   141  	kindNOT              nodeKind = "NOT"
   142  	kindMinDuration      nodeKind = "__min_duration"
   143  	kindMinRequestSize   nodeKind = "__min_request_size"
   144  	kindMinResponseSize  nodeKind = "__min_response_size"
   145  	kindRPCName          nodeKind = "__rpc_name"
   146  	kindErrorCodes       nodeKind = "__error_code"
   147  	kindErrorMessages    nodeKind = "__error_message"
   148  	kindSamplingFraction nodeKind = "__sampling_fraction"
   149  	kindHasAttributes    nodeKind = "__has_attribute"
   150  )
   151  
   152  var kindToNode = map[nodeKind]func() node{
   153  	kindAND:              func() node { return &andNode{} },
   154  	kindOR:               func() node { return &orNode{} },
   155  	kindNOT:              func() node { return &notNode{} },
   156  	kindMinDuration:      func() node { return &minMinDurationNode{} },
   157  	kindMinRequestSize:   func() node { return &minRequestSizeNode{} },
   158  	kindMinResponseSize:  func() node { return &minResponseSizeNode{} },
   159  	kindRPCName:          func() node { return &rpcNameNode{} },
   160  	kindErrorCodes:       func() node { return &errorCodeNode{} },
   161  	kindErrorMessages:    func() node { return &errorMessageNode{} },
   162  	kindSamplingFraction: func() node { return &samplingFractionNode{} },
   163  	kindHasAttributes:    func() node { return &hasAttributeNode{} },
   164  }
   165  
   166  var kinds = func() []nodeKind {
   167  	ks := make([]nodeKind, 0, len(kindToNode))
   168  	for k := range kindToNode {
   169  		ks = append(ks, k)
   170  	}
   171  	return ks
   172  }()
   173  
   174  func generate(k nodeKind) (node, error) {
   175  	if fn, ok := kindToNode[k]; ok {
   176  		return fn(), nil
   177  	}
   178  	return nil, fmt.Errorf("unknown node: %s, valid node must be one of %v", k, kinds)
   179  }
   180  
   181  type shouldRecorder interface {
   182  	shouldRecord() rpcz.ShouldRecord
   183  }
   184  
   185  type recorder struct {
   186  	rpcz.ShouldRecord
   187  }
   188  
   189  func (n *recorder) shouldRecord() rpcz.ShouldRecord {
   190  	return n.ShouldRecord
   191  }
   192  
   193  // RecordWhenConfig stores the RecordWhenConfig field of Config.
   194  type RecordWhenConfig struct {
   195  	andNode
   196  }
   197  
   198  // UnmarshalYAML customizes RecordWhenConfig's behavior when being unmarshalled from a YAML document.
   199  func (c *RecordWhenConfig) UnmarshalYAML(node *yaml.Node) error {
   200  	if err := node.Decode(&c.andNode); err != nil {
   201  		return fmt.Errorf("decoding RecordWhenConfig's andNode: %w", err)
   202  	}
   203  	return nil
   204  }
   205  
   206  type nodeList struct {
   207  	shouldRecords []rpcz.ShouldRecord
   208  }
   209  
   210  func (nl *nodeList) UnmarshalYAML(node *yaml.Node) error {
   211  	var nodes []map[nodeKind]yaml.Node
   212  	if err := node.Decode(&nodes); err != nil {
   213  		return fmt.Errorf("decoding []map[nodeKind]yaml.Node: %w", err)
   214  	}
   215  	nl.shouldRecords = make([]rpcz.ShouldRecord, 0, len(nodes))
   216  	for _, n := range nodes {
   217  		if size := len(n); size != 1 {
   218  			return fmt.Errorf("%v node has %d element currently, "+
   219  				"but the valid number of elements can only be 1", n, size)
   220  		}
   221  		for nodeKind, value := range n {
   222  			if valueEmpty(value) {
   223  				return fmt.Errorf("decoding %s node: value is empty", nodeKind)
   224  			}
   225  			node, err := generate(nodeKind)
   226  			if err != nil {
   227  				return fmt.Errorf("generating %s node: %w", nodeKind, err)
   228  			}
   229  			if err := value.Decode(node); err != nil {
   230  				return fmt.Errorf("decoding %s node: %w", nodeKind, err)
   231  			}
   232  			nl.shouldRecords = append(nl.shouldRecords, node.shouldRecord())
   233  		}
   234  	}
   235  	return nil
   236  }
   237  
   238  func valueEmpty(node yaml.Node) bool {
   239  	return len(node.Content) == 0 && len(node.Value) == 0
   240  }
   241  
   242  type andNode struct {
   243  	recorder
   244  }
   245  
   246  func (n *andNode) UnmarshalYAML(node *yaml.Node) error {
   247  	nl := &nodeList{}
   248  	if err := node.Decode(nl); err != nil {
   249  		return fmt.Errorf("decoding andNode: %w", err)
   250  	}
   251  	n.ShouldRecord = func(s rpcz.Span) bool {
   252  		if len(nl.shouldRecords) == 0 {
   253  			return false
   254  		}
   255  		for _, r := range nl.shouldRecords {
   256  			if !r(s) {
   257  				return false
   258  			}
   259  		}
   260  		return true
   261  	}
   262  	return nil
   263  }
   264  
   265  type orNode struct {
   266  	recorder
   267  }
   268  
   269  func (n *orNode) UnmarshalYAML(node *yaml.Node) error {
   270  	nl := &nodeList{}
   271  	if err := node.Decode(nl); err != nil {
   272  		return fmt.Errorf("decoding orNode: %w", err)
   273  	}
   274  	n.ShouldRecord = func(s rpcz.Span) bool {
   275  		for _, r := range nl.shouldRecords {
   276  			if r(s) {
   277  				return true
   278  			}
   279  		}
   280  		return false
   281  	}
   282  	return nil
   283  }
   284  
   285  type notNode struct {
   286  	recorder
   287  }
   288  
   289  func (n *notNode) UnmarshalYAML(node *yaml.Node) error {
   290  	var not map[nodeKind]yaml.Node
   291  	if err := node.Decode(&not); err != nil {
   292  		return fmt.Errorf("decoding notNode: %w", err)
   293  	}
   294  	const numInvalidChildren = 1
   295  	if n := len(not); n != numInvalidChildren {
   296  		return fmt.Errorf("NOT node has %d child node currently, "+
   297  			"but the valid number of child node can only be %d", n, numInvalidChildren)
   298  	}
   299  	for nodeKind, value := range not {
   300  		node, err := generate(nodeKind)
   301  		if err != nil {
   302  			return fmt.Errorf("generating %s node: %w", nodeKind, err)
   303  		}
   304  		if err := value.Decode(node); err != nil {
   305  			return fmt.Errorf("decoding %s node: %w", nodeKind, err)
   306  		}
   307  		n.ShouldRecord = func(s rpcz.Span) bool {
   308  			return !node.shouldRecord()(s)
   309  		}
   310  	}
   311  	return nil
   312  }
   313  
   314  type hasAttributeNode struct {
   315  	recorder
   316  }
   317  
   318  func (n *hasAttributeNode) UnmarshalYAML(node *yaml.Node) error {
   319  	var attribute string
   320  	if err := node.Decode(&attribute); err != nil {
   321  		return fmt.Errorf("decoding hasAttributeNode: %w", err)
   322  	}
   323  
   324  	key, value, err := parse(attribute)
   325  	if err != nil {
   326  		return fmt.Errorf("parsing attribute %s : %w", attribute, err)
   327  	}
   328  
   329  	n.ShouldRecord = func(s rpcz.Span) bool {
   330  		v, ok := s.Attribute(key)
   331  		return ok && strings.Contains(fmt.Sprintf("%s", v), value)
   332  	}
   333  	return nil
   334  }
   335  
   336  var errInvalidAttribute = errors.New("invalid attribute form [ valid attribute form: (key, value), " +
   337  	"only one space character after comma character, and key can't contain comma(',') character ]")
   338  
   339  func parse(attribute string) (key string, value string, err error) {
   340  	if len(attribute) == 0 || attribute[0] != '(' {
   341  		return "", "", errInvalidAttribute
   342  	}
   343  	attribute = attribute[1:]
   344  
   345  	if n := len(attribute); n == 0 || attribute[n-1] != ')' {
   346  		return "", "", errInvalidAttribute
   347  	}
   348  	attribute = attribute[:len(attribute)-1]
   349  
   350  	const delimiter = ", "
   351  	i := strings.Index(attribute, delimiter)
   352  	if i == -1 {
   353  		return "", "", errInvalidAttribute
   354  	}
   355  	return attribute[:i], attribute[i+len(delimiter):], nil
   356  }
   357  
   358  type minRequestSizeNode struct {
   359  	recorder
   360  }
   361  
   362  func (n *minRequestSizeNode) UnmarshalYAML(node *yaml.Node) error {
   363  	var minRequestSize int
   364  	if err := node.Decode(&minRequestSize); err != nil {
   365  		return fmt.Errorf("decoding minRequestSizeNode: %w", err)
   366  	}
   367  	n.ShouldRecord = func(s rpcz.Span) bool {
   368  		size, ok := s.Attribute(rpcz.TRPCAttributeRequestSize)
   369  		if !ok {
   370  			return false
   371  		}
   372  		if size, ok := size.(int); !ok || size < minRequestSize {
   373  			return false
   374  		}
   375  		return true
   376  	}
   377  	return nil
   378  }
   379  
   380  type minResponseSizeNode struct {
   381  	recorder
   382  }
   383  
   384  func (n *minResponseSizeNode) UnmarshalYAML(node *yaml.Node) error {
   385  	var minResponseSize int
   386  	if err := node.Decode(&minResponseSize); err != nil {
   387  		return fmt.Errorf("decoding minResponseSizeNode: %w", err)
   388  	}
   389  	n.ShouldRecord = func(s rpcz.Span) bool {
   390  		responseSize, ok := s.Attribute(rpcz.TRPCAttributeResponseSize)
   391  		if !ok {
   392  			return false
   393  		}
   394  		if size, ok := responseSize.(int); !ok || size < minResponseSize {
   395  			return false
   396  		}
   397  		return true
   398  	}
   399  	return nil
   400  }
   401  
   402  type minMinDurationNode struct {
   403  	recorder
   404  }
   405  
   406  func (n *minMinDurationNode) UnmarshalYAML(node *yaml.Node) error {
   407  	var dur time.Duration
   408  	if err := node.Decode(&dur); err != nil {
   409  		return fmt.Errorf("decoding minMinDurationNode: %w", err)
   410  	}
   411  	n.ShouldRecord = func(s rpcz.Span) bool {
   412  		if dur == 0 {
   413  			return true
   414  		}
   415  		et := s.EndTime()
   416  		return et.IsZero() || et.Sub(s.StartTime()) >= dur
   417  	}
   418  	return nil
   419  }
   420  
   421  type rpcNameNode struct {
   422  	recorder
   423  }
   424  
   425  func (n *rpcNameNode) UnmarshalYAML(node *yaml.Node) error {
   426  	var rpcName string
   427  	if err := node.Decode(&rpcName); err != nil {
   428  		return fmt.Errorf("decoding rpcNameNode: %w", err)
   429  	}
   430  	n.ShouldRecord = func(s rpcz.Span) bool {
   431  		name, ok := s.Attribute(rpcz.TRPCAttributeRPCName)
   432  		if !ok {
   433  			return false
   434  		}
   435  		if name, ok := name.(string); !ok || !strings.Contains(name, rpcName) {
   436  			return false
   437  		}
   438  		return true
   439  	}
   440  	return nil
   441  }
   442  
   443  type samplingFractionNode struct {
   444  	recorder
   445  }
   446  
   447  var safeRand = rand.NewSafeRand(time.Now().UnixNano())
   448  
   449  func (n *samplingFractionNode) UnmarshalYAML(node *yaml.Node) error {
   450  	var f float64
   451  	if err := node.Decode(&f); err != nil {
   452  		return fmt.Errorf("decoding samplingFractionNode: %w", err)
   453  	}
   454  	n.ShouldRecord = func(s rpcz.Span) bool {
   455  		return f > safeRand.Float64()
   456  	}
   457  	return nil
   458  }
   459  
   460  type errorCodeNode struct {
   461  	recorder
   462  }
   463  
   464  func (n *errorCodeNode) UnmarshalYAML(node *yaml.Node) error {
   465  	var code trpcpb.TrpcRetCode
   466  	if err := node.Decode(&code); err != nil {
   467  		return fmt.Errorf("decoding errorCodeNode: %w", err)
   468  	}
   469  	n.ShouldRecord = func(s rpcz.Span) bool {
   470  		err, ok := extractError(s)
   471  		if !ok {
   472  			return false
   473  		}
   474  		c := errs.Code(err)
   475  		return c == code
   476  	}
   477  	return nil
   478  }
   479  
   480  type errorMessageNode struct {
   481  	recorder
   482  }
   483  
   484  func (n *errorMessageNode) UnmarshalYAML(node *yaml.Node) error {
   485  	var message string
   486  	if err := node.Decode(&message); err != nil {
   487  		return fmt.Errorf("decoding errorMessageNode: %w", err)
   488  	}
   489  	n.ShouldRecord = func(s rpcz.Span) bool {
   490  		err, ok := extractError(s)
   491  		if !ok {
   492  			return false
   493  		}
   494  		return strings.Contains(message, errs.Msg(err))
   495  	}
   496  	return nil
   497  }
   498  
   499  func extractError(span rpcz.Span) (error, bool) {
   500  	err, ok := span.Attribute(rpcz.TRPCAttributeError)
   501  	if !ok {
   502  		return nil, false
   503  	}
   504  
   505  	e, ok := err.(error)
   506  	return e, ok
   507  }
   508  
   509  // ServiceConfig is a configuration for a single service. A server process might have multiple services.
   510  type ServiceConfig struct {
   511  	// Disable request timeout inherited from upstream service.
   512  	DisableRequestTimeout bool   `yaml:"disable_request_timeout"`
   513  	IP                    string `yaml:"ip"` // IP address to listen to.
   514  	// Service name in the format: trpc.app.server.service. Used for naming the service.
   515  	Name string `yaml:"name"`
   516  	Nic  string `yaml:"nic"`  // Network Interface Card (NIC) to listen to. No need to configure.
   517  	Port uint16 `yaml:"port"` // Port to listen to.
   518  	// Address to listen to. If set, ipport will be ignored. Otherwise, ipport will be used.
   519  	Address  string `yaml:"address"`
   520  	Network  string `yaml:"network"`  // Network type like tcp/udp.
   521  	Protocol string `yaml:"protocol"` // Protocol type like trpc.
   522  	// Longest time in milliseconds for a handler to handle a request.
   523  	Timeout int `yaml:"timeout"`
   524  	// Maximum idle time in milliseconds for a server connection. Default is 1 minute.
   525  	Idletime          int      `yaml:"idletime"`
   526  	DisableKeepAlives bool     `yaml:"disable_keep_alives"`    // Disables keep-alives.
   527  	Registry          string   `yaml:"registry"`               // Registry to use, e.g., polaris.
   528  	Filter            []string `yaml:"filter"`                 // Filters for the service.
   529  	StreamFilter      []string `yaml:"stream_filter"`          // Stream filters for the service.
   530  	TLSKey            string   `yaml:"tls_key"`                // Server TLS key.
   531  	TLSCert           string   `yaml:"tls_cert"`               // Server TLS certificate.
   532  	CACert            string   `yaml:"ca_cert"`                // CA certificate to validate client certificate.
   533  	ServerAsync       *bool    `yaml:"server_async,omitempty"` // Whether to enable server asynchronous mode.
   534  	// MaxRoutines is the maximum number of goroutines for server asynchronous mode.
   535  	// Requests exceeding MaxRoutines will be queued. Prolonged overages may lead to OOM!
   536  	// MaxRoutines is not the solution to alleviate server overloading.
   537  	MaxRoutines int    `yaml:"max_routines"`
   538  	Writev      *bool  `yaml:"writev,omitempty"` // Whether to enable writev.
   539  	Transport   string `yaml:"transport"`        // Transport type.
   540  }
   541  
   542  // ClientConfig is the configuration for the client to request backends.
   543  type ClientConfig struct {
   544  	Network        string                  `yaml:"network"`        // Network for all backends. Default is tcp.
   545  	Protocol       string                  `yaml:"protocol"`       // Protocol for all backends. Default is trpc.
   546  	Filter         []string                `yaml:"filter"`         // Filters for all backends.
   547  	StreamFilter   []string                `yaml:"stream_filter"`  // Stream filters for all backends.
   548  	Namespace      string                  `yaml:"namespace"`      // Namespace for all backends.
   549  	Transport      string                  `yaml:"transport"`      // Transport type.
   550  	Timeout        int                     `yaml:"timeout"`        // Timeout in milliseconds.
   551  	Discovery      string                  `yaml:"discovery"`      // Discovery mechanism.
   552  	ServiceRouter  string                  `yaml:"servicerouter"`  // Service router.
   553  	Loadbalance    string                  `yaml:"loadbalance"`    // Load balancing algorithm.
   554  	Circuitbreaker string                  `yaml:"circuitbreaker"` // Circuit breaker configuration.
   555  	Service        []*client.BackendConfig `yaml:"service"`        // Configuration for each individual backend.
   556  }
   557  
   558  // trpc server config, set after the framework setup and the yaml config file is parsed.
   559  var globalConfig atomic.Value
   560  
   561  func init() {
   562  	globalConfig.Store(defaultConfig())
   563  }
   564  
   565  func defaultConfig() *Config {
   566  	cfg := &Config{}
   567  	cfg.Global.EnableSet = "N"
   568  	cfg.Server.Network = "tcp"
   569  	cfg.Server.Protocol = "trpc"
   570  	cfg.Client.Network = "tcp"
   571  	cfg.Client.Protocol = "trpc"
   572  	return cfg
   573  }
   574  
   575  // GlobalConfig returns the global Config.
   576  func GlobalConfig() *Config {
   577  	return globalConfig.Load().(*Config)
   578  }
   579  
   580  // SetGlobalConfig set the global Config.
   581  func SetGlobalConfig(cfg *Config) {
   582  	globalConfig.Store(cfg)
   583  }
   584  
   585  // LoadGlobalConfig loads a Config from the config file path and sets it as the global Config.
   586  func LoadGlobalConfig(configPath string) error {
   587  	cfg, err := LoadConfig(configPath)
   588  	if err != nil {
   589  		return err
   590  	}
   591  	SetGlobalConfig(cfg)
   592  	return nil
   593  }
   594  
   595  // LoadConfig loads a Config from the config file path.
   596  func LoadConfig(configPath string) (*Config, error) {
   597  	cfg, err := parseConfigFromFile(configPath)
   598  	if err != nil {
   599  		return nil, err
   600  	}
   601  	if err := RepairConfig(cfg); err != nil {
   602  		return nil, err
   603  	}
   604  	return cfg, nil
   605  }
   606  
   607  func parseConfigFromFile(configPath string) (*Config, error) {
   608  	buf, err := os.ReadFile(configPath)
   609  	if err != nil {
   610  		return nil, err
   611  	}
   612  	cfg := defaultConfig()
   613  	if err := yaml.Unmarshal(expandenv.ExpandEnv(buf), cfg); err != nil {
   614  		return nil, err
   615  	}
   616  	return cfg, nil
   617  }
   618  
   619  // Setup registers client config and setups plugins according to the Config.
   620  func Setup(cfg *Config) error {
   621  	if _, err := SetupPlugins(cfg.Plugins); err != nil {
   622  		return err
   623  	}
   624  	if err := SetupClients(&cfg.Client); err != nil {
   625  		return err
   626  	}
   627  	return nil
   628  }
   629  
   630  // SetupPlugins sets up all plugins and returns a function to close them.
   631  func SetupPlugins(cfg plugin.Config) (func() error, error) {
   632  	if cfg == nil {
   633  		return func() error { return nil }, nil
   634  	}
   635  	return cfg.SetupClosables()
   636  }
   637  
   638  // SetupClients sets up all backends and the wildcard.
   639  func SetupClients(cfg *ClientConfig) error {
   640  	for _, backendCfg := range cfg.Service {
   641  		if err := client.RegisterClientConfig(backendCfg.Callee, backendCfg); err != nil {
   642  			return err
   643  		}
   644  	}
   645  	// * represents general config for all backends
   646  	if _, ok := client.DefaultClientConfig()["*"]; !ok { // should not be covered if already registered by some plugins
   647  		if err := client.RegisterClientConfig("*", &client.BackendConfig{
   648  			Network:        cfg.Network,
   649  			Protocol:       cfg.Protocol,
   650  			Namespace:      cfg.Namespace,
   651  			Transport:      cfg.Transport,
   652  			Timeout:        cfg.Timeout,
   653  			Filter:         cfg.Filter,
   654  			StreamFilter:   cfg.StreamFilter,
   655  			Discovery:      cfg.Discovery,
   656  			ServiceRouter:  cfg.ServiceRouter,
   657  			Loadbalance:    cfg.Loadbalance,
   658  			Circuitbreaker: cfg.Circuitbreaker,
   659  		}); err != nil {
   660  			return err
   661  		}
   662  	}
   663  	return nil
   664  }
   665  
   666  // RepairConfig repairs the Config by filling in some fields with default values.
   667  func RepairConfig(cfg *Config) error {
   668  	// nic -> ip
   669  	if err := repairServiceIPWithNic(cfg); err != nil {
   670  		return err
   671  	}
   672  	// set default read buffer size
   673  	if cfg.Global.ReadBufferSize == nil {
   674  		readerSize := codec.DefaultReaderSize
   675  		cfg.Global.ReadBufferSize = &readerSize
   676  	}
   677  	codec.SetReaderSize(*cfg.Global.ReadBufferSize)
   678  
   679  	// nic -> ip
   680  	if err := repairServiceIPWithNic(cfg); err != nil {
   681  		return err
   682  	}
   683  
   684  	// Set empty ip to "0.0.0.0" to prevent malformed key matching
   685  	// for passed listeners during hot restart.
   686  	const defaultIP = "0.0.0.0"
   687  	setDefault(&cfg.Global.LocalIP, defaultIP)
   688  	setDefault(&cfg.Server.Admin.IP, cfg.Global.LocalIP)
   689  
   690  	// protocol network ip empty
   691  	for _, serviceCfg := range cfg.Server.Service {
   692  		setDefault(&serviceCfg.Protocol, cfg.Server.Protocol)
   693  		setDefault(&serviceCfg.Network, cfg.Server.Network)
   694  		setDefault(&serviceCfg.IP, cfg.Global.LocalIP)
   695  		setDefault(&serviceCfg.Transport, cfg.Server.Transport)
   696  		setDefault(&serviceCfg.Address, net.JoinHostPort(serviceCfg.IP, strconv.Itoa(int(serviceCfg.Port))))
   697  
   698  		// server async mode by default
   699  		if serviceCfg.ServerAsync == nil {
   700  			enableServerAsync := true
   701  			serviceCfg.ServerAsync = &enableServerAsync
   702  		}
   703  		// writev disabled by default
   704  		if serviceCfg.Writev == nil {
   705  			enableWritev := false
   706  			serviceCfg.Writev = &enableWritev
   707  		}
   708  		if serviceCfg.Timeout == 0 {
   709  			serviceCfg.Timeout = cfg.Server.Timeout
   710  		}
   711  		if serviceCfg.Idletime == 0 {
   712  			serviceCfg.Idletime = defaultIdleTimeout
   713  			if serviceCfg.Timeout > defaultIdleTimeout {
   714  				serviceCfg.Idletime = serviceCfg.Timeout
   715  			}
   716  		}
   717  	}
   718  
   719  	setDefault(&cfg.Client.Namespace, cfg.Global.Namespace)
   720  	for _, backendCfg := range cfg.Client.Service {
   721  		repairClientConfig(backendCfg, &cfg.Client)
   722  	}
   723  	return nil
   724  }
   725  
   726  // repairServiceIPWithNic repairs the Config when service ip is empty according to the nic.
   727  func repairServiceIPWithNic(cfg *Config) error {
   728  	for index, item := range cfg.Server.Service {
   729  		if item.IP == "" {
   730  			ip := getIP(item.Nic)
   731  			if ip == "" && item.Nic != "" {
   732  				return fmt.Errorf("can't find service IP by the NIC: %s", item.Nic)
   733  			}
   734  			cfg.Server.Service[index].IP = ip
   735  		}
   736  		setDefault(&cfg.Global.LocalIP, item.IP)
   737  	}
   738  
   739  	if cfg.Server.Admin.IP == "" {
   740  		ip := getIP(cfg.Server.Admin.Nic)
   741  		if ip == "" && cfg.Server.Admin.Nic != "" {
   742  			return fmt.Errorf("can't find admin IP by the NIC: %s", cfg.Server.Admin.Nic)
   743  		}
   744  		cfg.Server.Admin.IP = ip
   745  	}
   746  	return nil
   747  }
   748  
   749  func repairClientConfig(backendCfg *client.BackendConfig, clientCfg *ClientConfig) {
   750  	// service name in proto file will be used as key for backend config by default
   751  	// generally, service name in proto file is the same as the backend service name.
   752  	// therefore, no need to config backend service name
   753  	setDefault(&backendCfg.Callee, backendCfg.ServiceName)
   754  	setDefault(&backendCfg.ServiceName, backendCfg.Callee)
   755  	setDefault(&backendCfg.Namespace, clientCfg.Namespace)
   756  	setDefault(&backendCfg.Network, clientCfg.Network)
   757  	setDefault(&backendCfg.Protocol, clientCfg.Protocol)
   758  	setDefault(&backendCfg.Transport, clientCfg.Transport)
   759  	if backendCfg.Target == "" {
   760  		setDefault(&backendCfg.Discovery, clientCfg.Discovery)
   761  		setDefault(&backendCfg.ServiceRouter, clientCfg.ServiceRouter)
   762  		setDefault(&backendCfg.Loadbalance, clientCfg.Loadbalance)
   763  		setDefault(&backendCfg.Circuitbreaker, clientCfg.Circuitbreaker)
   764  	}
   765  	if backendCfg.Timeout == 0 {
   766  		backendCfg.Timeout = clientCfg.Timeout
   767  	}
   768  	// Global filter is at front and is deduplicated.
   769  	backendCfg.Filter = deduplicate(clientCfg.Filter, backendCfg.Filter)
   770  	backendCfg.StreamFilter = deduplicate(clientCfg.StreamFilter, backendCfg.StreamFilter)
   771  }
   772  
   773  // getMillisecond returns time.Duration by the input value in milliseconds.
   774  func getMillisecond(sec int) time.Duration {
   775  	return time.Millisecond * time.Duration(sec)
   776  }
   777  
   778  // setDefault points dst to def if dst is not nil and points to empty string.
   779  func setDefault(dst *string, def string) {
   780  	if dst != nil && *dst == "" {
   781  		*dst = def
   782  	}
   783  }