github.com/volts-dev/volts@v0.0.0-20240120094013-5e9c65924106/client/config.go (about)

     1  package client
     2  
     3  import (
     4  	"context"
     5  	"crypto/tls"
     6  	"net"
     7  	"net/http"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/volts-dev/volts/codec"
    12  	"github.com/volts-dev/volts/config"
    13  	"github.com/volts-dev/volts/logger"
    14  	"github.com/volts-dev/volts/registry"
    15  	"github.com/volts-dev/volts/selector"
    16  	"github.com/volts-dev/volts/transport"
    17  )
    18  
    19  var (
    20  	log = logger.New("Client")
    21  
    22  	// Default Client
    23  	defaultClient IClient
    24  	// DefaultRetry is the default check-for-retry function for retries
    25  	DefaultRetry = RetryOnError
    26  	// DefaultRetries is the default number of times a request is tried
    27  	DefaultRetries = 1
    28  	// DefaultRequestTimeout is the default request timeout
    29  	DefaultRequestTimeout = time.Second * 20
    30  	// DefaultPoolSize sets the connection pool size
    31  	DefaultPoolSize = 100
    32  	// DefaultPoolTTL sets the connection pool ttl
    33  	DefaultPoolTTL = time.Minute
    34  )
    35  
    36  type (
    37  	RequestOptions struct {
    38  		ContentType   string
    39  		Stream        bool
    40  		Codec         codec.ICodec
    41  		Encoded       bool // 传入的数据已经是编码器过的
    42  		SerializeType codec.SerializeType
    43  
    44  		Service string // 为该请求指定微服务名称
    45  		// Other options for implementations of the interface
    46  		// can be stored in a context
    47  		Context context.Context
    48  	}
    49  
    50  	HttpOption func(*Config)
    51  	// Option contains all options for creating clients.
    52  	Option func(*Config)
    53  	// CallOption used by Call or Stream
    54  	CallOption func(*CallOptions)
    55  
    56  	CallOptions struct {
    57  		SelectOptions []selector.SelectOption
    58  
    59  		// Address of remote hosts
    60  		Address []string
    61  		// Backoff func
    62  		//Backoff BackoffFunc
    63  		// Check if retriable func
    64  		Retry RetryFunc
    65  		// Transport Dial Timeout
    66  		DialTimeout time.Duration
    67  		// Number of Call attempts
    68  		Retries int
    69  		// Request/Response timeout
    70  		RequestTimeout time.Duration
    71  		// Stream timeout for the stream
    72  		StreamTimeout time.Duration
    73  		// Use the services own auth token
    74  		ServiceToken bool
    75  		// Duration to cache the response for
    76  		CacheExpiry time.Duration
    77  
    78  		// Middleware for low level call func
    79  		//CallWrappers []CallWrapper
    80  
    81  		// Other options for implementations of the interface
    82  		// can be stored in a context
    83  		Context context.Context
    84  	}
    85  
    86  	Config struct {
    87  		config.Config `field:"-"`
    88  		Name          string `field:"-"` // config name/path in config file
    89  		PrefixName    string `field:"-"` // config prefix name
    90  		// Other options for implementations of the interface
    91  		// can be stored in a context
    92  		Logger      logger.ILogger         `field:"-"` // 保留:提供给扩展使用
    93  		Context     context.Context        `field:"-"`
    94  		Client      IClient                `field:"-"`
    95  		Transport   transport.ITransport   `field:"-"`
    96  		Registry    registry.IRegistry     `field:"-"`
    97  		Selector    selector.ISelector     `field:"-"`
    98  		TlsConfig   *tls.Config            `field:"-"` // TLSConfig for tcp and quic
    99  		CallOptions CallOptions            `field:"-"` // Default Call Options
   100  		DialOptions []transport.DialOption `field:"-"` // TODO 		// 提供实时变化sturct
   101  		// Breaker is used to config CircuitBreaker
   102  		///Breaker Breaker
   103  
   104  		// Connection Pool
   105  		PoolSize int
   106  		PoolTtl  time.Duration
   107  		Retries  int // Retries retries to send
   108  
   109  		// Used to select codec
   110  		ContentType string
   111  		_conn       net.Conn
   112  		_protocol   string
   113  
   114  		// Group is used to select the services in the same group. Services set group info in their meta.
   115  		// If it is empty, clients will ignore group.
   116  		Group string
   117  
   118  		// kcp.BlockCrypt
   119  		_Block interface{}
   120  		// RPCPath for http connection
   121  		_RPCPath string
   122  
   123  		// BackupLatency is used for Failbackup mode. rpc will sends another request if the first response doesn't return in BackupLatency time.
   124  		BackupLatency time.Duration
   125  
   126  		// 传输序列类型
   127  		Serialize     codec.SerializeType `field:"-"`
   128  		SerializeType string              //codec.SerializeType
   129  		CompressType  transport.CompressType
   130  
   131  		Heartbeat         bool
   132  		HeartbeatInterval time.Duration
   133  
   134  		Ja3      transport.Ja3 `field:"-"`
   135  		ProxyUrl string
   136  		// http options
   137  		UserAgent     string
   138  		AllowRedirect bool
   139  
   140  		// Debug mode
   141  		PrintRequest    bool
   142  		PrintRequestAll bool
   143  
   144  		// Registry
   145  		RegistryType string
   146  		RegistryHost string
   147  
   148  		// Selector
   149  		SelectorStrategy string
   150  	}
   151  
   152  	// RequestOption used by NewRequest
   153  	RequestOption func(*RequestOptions)
   154  )
   155  
   156  func newConfig(tr transport.ITransport, opts ...Option) *Config {
   157  	cfg := &Config{
   158  		Name: "client",
   159  		//Config:    config.Default(),
   160  		Logger:    log,
   161  		Transport: tr,
   162  		Retries:   3,
   163  		//RPCPath:        share.DefaultRPCPath,
   164  		//SerializeType:  codec.MsgPack,
   165  		CompressType:  transport.None,
   166  		BackupLatency: 10 * time.Millisecond,
   167  
   168  		CallOptions: CallOptions{
   169  			//Backoff:        DefaultBackoff,
   170  			Retry:          DefaultRetry,
   171  			Retries:        DefaultRetries,
   172  			RequestTimeout: DefaultRequestTimeout,
   173  			DialTimeout:    transport.DefaultTimeout,
   174  		},
   175  		PoolSize: DefaultPoolSize,
   176  		PoolTtl:  DefaultPoolTTL,
   177  		//Broker:    broker.DefaultBroker,
   178  		//Selector: selector.Default(),
   179  		//Registry: registry.Default(),
   180  		SelectorStrategy: "random",
   181  	}
   182  
   183  	//if cfg.Name == "" {
   184  	//	cfg.Name = "client"
   185  	//}
   186  	cfg.Init(opts...)
   187  
   188  	config.Register(cfg)
   189  	/*
   190  		// 保存/加载
   191  		if !config.Default().InConfig(cfg.String()) {
   192  			// 保存到内存
   193  			if err := cfg.Save(false); err != nil {
   194  				log.Fatalf("save %v config failed!", cfg.String())
   195  			}
   196  			// 保存到配置文件
   197  			config.Default().Save()
   198  		} else if err := cfg.Load(); err != nil {
   199  			log.Fatalf("load %v config failed!", cfg.String())
   200  		}
   201  	*/
   202  	// 初始化序列
   203  	if st := codec.Use(cfg.SerializeType); st != 0 {
   204  		cfg.Serialize = st
   205  		cfg.SerializeType = st.String()
   206  	}
   207  
   208  	// 初始化 transport
   209  	cfg.Transport.Init(transport.WithConfigPrefixName(cfg.String()))
   210  
   211  	// 初始化 registry
   212  	if reg := registry.Use(cfg.RegistryType,
   213  		registry.WithConfigPrefixName(cfg.String()), registry.Addrs(cfg.RegistryHost)); reg != nil {
   214  		cfg.Registry = reg
   215  		cfg.Selector = selector.New(
   216  			selector.WithConfigPrefixName(cfg.String()), // 配置路径
   217  			selector.Registry(cfg.Registry),
   218  			selector.WithStrategy(cfg.SelectorStrategy),
   219  		)
   220  	}
   221  	return cfg
   222  }
   223  
   224  func (self *Config) String() string {
   225  	if len(self.PrefixName) > 0 {
   226  		return strings.Join([]string{"client", self.PrefixName}, ".")
   227  	}
   228  	return self.Name
   229  }
   230  
   231  // init options
   232  func (self *Config) Init(opts ...Option) {
   233  	for _, opt := range opts {
   234  		if opt != nil {
   235  			opt(self)
   236  		}
   237  	}
   238  }
   239  
   240  func (self *Config) Load() error {
   241  	return self.LoadToModel(self)
   242  }
   243  
   244  func (self *Config) Save(immed ...bool) error {
   245  	return self.SaveFromModel(self, immed...)
   246  }
   247  
   248  // 增加超时到60s
   249  func Debug() Option {
   250  	return func(cfg *Config) {
   251  		cfg.Debug = true
   252  		cfg.CallOptions.RequestTimeout = 180 * time.Second
   253  		cfg.CallOptions.DialTimeout = 180 * time.Second
   254  		cfg.Transport.Init(
   255  			transport.DialTimeout(cfg.CallOptions.DialTimeout),
   256  			transport.ReadTimeout(cfg.CallOptions.DialTimeout),
   257  			transport.WriteTimeout(cfg.CallOptions.DialTimeout),
   258  		)
   259  	}
   260  }
   261  
   262  func Logger() logger.ILogger {
   263  	return log
   264  }
   265  
   266  func WithCodec(c codec.SerializeType) RequestOption {
   267  	return func(cfg *RequestOptions) {
   268  		cfg.SerializeType = c
   269  		cfg.Codec = codec.IdentifyCodec(c)
   270  	}
   271  }
   272  
   273  func Encoded(on bool) RequestOption {
   274  	return func(cfg *RequestOptions) {
   275  		cfg.Encoded = on
   276  	}
   277  }
   278  
   279  func WithServiceName(name string) RequestOption {
   280  	return func(cfg *RequestOptions) {
   281  		cfg.Service = name
   282  	}
   283  }
   284  
   285  // WithRequestTimeout is a CallOption which overrides that which
   286  // set in Options.CallOptions
   287  func WithRequestTimeout(d time.Duration) CallOption {
   288  	return func(o *CallOptions) {
   289  		o.RequestTimeout = d
   290  	}
   291  }
   292  
   293  // WithAddress sets the remote addresses to use rather than using service discovery
   294  func WithAddress(a ...string) CallOption {
   295  	return func(o *CallOptions) {
   296  		o.Address = a
   297  	}
   298  }
   299  
   300  func WithContext(ctx context.Context) CallOption {
   301  	return func(o *CallOptions) {
   302  		o.Context = ctx
   303  	}
   304  }
   305  
   306  func WithCookiejar(jar http.CookieJar) HttpOption {
   307  	return func(cfg *Config) {
   308  		if cli, ok := cfg.Client.(*HttpClient); ok {
   309  			cli.client.Jar = jar
   310  		}
   311  	}
   312  }
   313  
   314  func WithUserAgent(userAgent string) HttpOption {
   315  	return func(cfg *Config) {
   316  		cfg.UserAgent = userAgent
   317  		cfg.Ja3.UserAgent = userAgent
   318  	}
   319  }
   320  
   321  func AllowRedirect() HttpOption {
   322  	return func(cfg *Config) {
   323  		cfg.AllowRedirect = true
   324  	}
   325  }
   326  
   327  // Codec to be used to encode/decode requests for a given content type
   328  func WithSerializeType(st codec.SerializeType) Option {
   329  	return func(cfg *Config) {
   330  		cfg.Serialize = st
   331  		cfg.SerializeType = st.String()
   332  	}
   333  }
   334  
   335  // Registry to find nodes for a given service
   336  func WithRegistry(r registry.IRegistry) Option {
   337  	return func(cfg *Config) {
   338  		cfg.Registry = r
   339  		// set in the selector
   340  		if cfg.Selector != nil {
   341  			cfg.Selector.Init(selector.Registry(r))
   342  		}
   343  	}
   344  }
   345  
   346  func WithRegistries(typ string, Host string) Option {
   347  	return func(cfg *Config) {
   348  		cfg.RegistryType = typ
   349  		cfg.RegistryHost = Host
   350  	}
   351  }
   352  
   353  // Transport to use for communication e.g http, rabbitmq, etc
   354  func WithTransport(t transport.ITransport) Option {
   355  	return func(cfg *Config) {
   356  		cfg.Transport = t
   357  	}
   358  }
   359  
   360  func WithJa3(ja3, userAgent string) Option {
   361  	return func(cfg *Config) {
   362  		cfg.Ja3.Ja3 = ja3
   363  		cfg.Ja3.UserAgent = userAgent
   364  		cfg.UserAgent = userAgent
   365  		//	cfg.DialOptions = append(cfg.DialOptions, transport.WithJa3(cfg.Ja3.Ja3, cfg.Ja3.UserAgent))
   366  	}
   367  }
   368  
   369  func WithProxyURL(proxyURL string) Option {
   370  	return func(cfg *Config) {
   371  		cfg.ProxyUrl = proxyURL
   372  		//cfg.DialOptions = append(cfg.DialOptions, transport.WithProxyURL(cfg.ProxyURL))
   373  	}
   374  }
   375  
   376  // init transport
   377  func WithTransportOptions(opts ...transport.Option) Option {
   378  	return func(cfg *Config) {
   379  		cfg.Transport.Init(opts...)
   380  	}
   381  }
   382  
   383  func WithHttpOptions(opts ...HttpOption) Option {
   384  	return func(cfg *Config) {
   385  		for _, opt := range opts {
   386  			if opt != nil {
   387  				opt(cfg)
   388  			}
   389  		}
   390  	}
   391  }
   392  
   393  // 打印请求信息
   394  func WithPrintRequest(all ...bool) Option {
   395  	return func(cfg *Config) {
   396  		cfg.PrintRequest = true
   397  		if len(all) > 0 {
   398  			cfg.PrintRequestAll = all[0]
   399  		}
   400  	}
   401  }
   402  
   403  // 固定服务器列表
   404  func WithHost(adr ...string) Option {
   405  	return func(cfg *Config) {
   406  		cfg.CallOptions.Address = append(cfg.CallOptions.Address, adr...)
   407  	}
   408  }
   409  
   410  // 修改Config.json的路径
   411  func WithConfigPrefixName(prefixName string) Option {
   412  	return func(cfg *Config) {
   413  		cfg.Unregister(cfg)
   414  		cfg.PrefixName = prefixName
   415  		cfg.Register(cfg)
   416  	}
   417  }