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