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 }