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