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 ¬Node{} }, 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(¬); 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 }