github.com/alibabacloud-go/tea@v1.3.10/dara/core.go (about) 1 package dara 2 3 import ( 4 "bytes" 5 "context" 6 "crypto/tls" 7 "crypto/x509" 8 "encoding/base64" 9 "encoding/hex" 10 "encoding/json" 11 "errors" 12 "fmt" 13 "io" 14 "math" 15 "math/rand" 16 "net" 17 "net/http" 18 "net/url" 19 "os" 20 "reflect" 21 "strconv" 22 "strings" 23 "sync" 24 "time" 25 26 "github.com/alibabacloud-go/debug/debug" 27 util "github.com/alibabacloud-go/tea-utils/v2/service" 28 "github.com/alibabacloud-go/tea/utils" 29 30 "golang.org/x/net/proxy" 31 ) 32 33 type RuntimeOptions = util.RuntimeOptions 34 type ExtendsParameters = util.ExtendsParameters 35 36 var debugLog = debug.Init("dara") 37 38 type HttpRequest interface { 39 } 40 41 type HttpResponse interface { 42 } 43 44 type HttpClient interface { 45 Call(request *http.Request, transport *http.Transport) (response *http.Response, err error) 46 } 47 48 type daraClient struct { 49 sync.Mutex 50 httpClient *http.Client 51 ifInit bool 52 } 53 54 func (client *daraClient) Call(request *http.Request, transport *http.Transport) (response *http.Response, err error) { 55 response, err = client.httpClient.Do(request) 56 return 57 } 58 59 var hookDo = func(fn func(req *http.Request, transport *http.Transport) (*http.Response, error)) func(req *http.Request, transport *http.Transport) (*http.Response, error) { 60 return fn 61 } 62 63 var basicTypes = []string{ 64 "int", "int16", "int64", "int32", "float32", "float64", "string", "bool", "uint64", "uint32", "uint16", 65 } 66 67 // Verify whether the parameters meet the requirements 68 var validateParams = []string{"require", "pattern", "maxLength", "minLength", "maximum", "minimum", "maxItems", "minItems"} 69 70 var clientPool = &sync.Map{} 71 72 // Request is used wrap http request 73 type Request struct { 74 Protocol *string 75 Port *int 76 Method *string 77 Pathname *string 78 Domain *string 79 Headers map[string]*string 80 Query map[string]*string 81 Body io.Reader 82 } 83 84 // Response is use d wrap http response 85 type Response struct { 86 Body io.ReadCloser 87 StatusCode *int 88 StatusMessage *string 89 Headers map[string]*string 90 } 91 92 // RuntimeObject is used for converting http configuration 93 type RuntimeObject struct { 94 IgnoreSSL *bool `json:"ignoreSSL" xml:"ignoreSSL"` 95 ReadTimeout *int `json:"readTimeout" xml:"readTimeout"` 96 ConnectTimeout *int `json:"connectTimeout" xml:"connectTimeout"` 97 LocalAddr *string `json:"localAddr" xml:"localAddr"` 98 HttpProxy *string `json:"httpProxy" xml:"httpProxy"` 99 HttpsProxy *string `json:"httpsProxy" xml:"httpsProxy"` 100 NoProxy *string `json:"noProxy" xml:"noProxy"` 101 MaxIdleConns *int `json:"maxIdleConns" xml:"maxIdleConns"` 102 Key *string `json:"key" xml:"key"` 103 Cert *string `json:"cert" xml:"cert"` 104 Ca *string `json:"ca" xml:"ca"` 105 Socks5Proxy *string `json:"socks5Proxy" xml:"socks5Proxy"` 106 Socks5NetWork *string `json:"socks5NetWork" xml:"socks5NetWork"` 107 Listener utils.ProgressListener `json:"listener" xml:"listener"` 108 Tracker *utils.ReaderTracker `json:"tracker" xml:"tracker"` 109 Logger *utils.Logger `json:"logger" xml:"logger"` 110 RetryOptions *RetryOptions `json:"retryOptions" xml:"retryOptions"` 111 ExtendsParameters *ExtendsParameters `json:"extendsParameters,omitempty" xml:"extendsParameters,omitempty"` 112 HttpClient 113 } 114 115 func (r *RuntimeObject) getClientTag(domain string) string { 116 return strconv.FormatBool(BoolValue(r.IgnoreSSL)) + strconv.Itoa(IntValue(r.ReadTimeout)) + 117 strconv.Itoa(IntValue(r.ConnectTimeout)) + StringValue(r.LocalAddr) + StringValue(r.HttpProxy) + 118 StringValue(r.HttpsProxy) + StringValue(r.NoProxy) + StringValue(r.Socks5Proxy) + StringValue(r.Socks5NetWork) + domain 119 } 120 121 // NewRuntimeObject is used for shortly create runtime object 122 func NewRuntimeObject(runtime map[string]interface{}) *RuntimeObject { 123 if runtime == nil { 124 return &RuntimeObject{} 125 } 126 127 runtimeObject := &RuntimeObject{ 128 IgnoreSSL: TransInterfaceToBool(runtime["ignoreSSL"]), 129 ReadTimeout: TransInterfaceToInt(runtime["readTimeout"]), 130 ConnectTimeout: TransInterfaceToInt(runtime["connectTimeout"]), 131 LocalAddr: TransInterfaceToString(runtime["localAddr"]), 132 HttpProxy: TransInterfaceToString(runtime["httpProxy"]), 133 HttpsProxy: TransInterfaceToString(runtime["httpsProxy"]), 134 NoProxy: TransInterfaceToString(runtime["noProxy"]), 135 MaxIdleConns: TransInterfaceToInt(runtime["maxIdleConns"]), 136 Socks5Proxy: TransInterfaceToString(runtime["socks5Proxy"]), 137 Socks5NetWork: TransInterfaceToString(runtime["socks5NetWork"]), 138 Key: TransInterfaceToString(runtime["key"]), 139 Cert: TransInterfaceToString(runtime["cert"]), 140 Ca: TransInterfaceToString(runtime["ca"]), 141 } 142 if runtime["listener"] != nil { 143 runtimeObject.Listener = runtime["listener"].(utils.ProgressListener) 144 } 145 if runtime["tracker"] != nil { 146 runtimeObject.Tracker = runtime["tracker"].(*utils.ReaderTracker) 147 } 148 if runtime["logger"] != nil { 149 runtimeObject.Logger = runtime["logger"].(*utils.Logger) 150 } 151 if runtime["httpClient"] != nil { 152 runtimeObject.HttpClient = runtime["httpClient"].(HttpClient) 153 } 154 if runtime["retryOptions"] != nil { 155 runtimeObject.RetryOptions = runtime["retryOptions"].(*RetryOptions) 156 } 157 return runtimeObject 158 } 159 160 // NewRequest is used shortly create Request 161 func NewRequest() (req *Request) { 162 return &Request{ 163 Headers: map[string]*string{}, 164 Query: map[string]*string{}, 165 } 166 } 167 168 // NewResponse is create response with http response 169 func NewResponse(httpResponse *http.Response) (res *Response) { 170 res = &Response{} 171 res.Body = httpResponse.Body 172 res.Headers = make(map[string]*string) 173 res.StatusCode = Int(httpResponse.StatusCode) 174 res.StatusMessage = String(httpResponse.Status) 175 return 176 } 177 178 // Convert is use convert map[string]interface object to struct 179 func Convert(in interface{}, out interface{}) error { 180 byt, _ := json.Marshal(in) 181 decoder := jsonParser.NewDecoder(bytes.NewReader(byt)) 182 decoder.UseNumber() 183 err := decoder.Decode(&out) 184 return err 185 } 186 187 // Recover is used to format error 188 func Recover(in interface{}) error { 189 if in == nil { 190 return nil 191 } 192 return errors.New(fmt.Sprint(in)) 193 } 194 195 // ReadBody is used read response body 196 func (response *Response) ReadBody() (body []byte, err error) { 197 var buffer [512]byte 198 defer response.Body.Close() 199 result := bytes.NewBuffer(nil) 200 201 for { 202 n, err := response.Body.Read(buffer[0:]) 203 result.Write(buffer[0:n]) 204 if err != nil && err == io.EOF { 205 break 206 } else if err != nil { 207 return nil, err 208 } 209 } 210 return result.Bytes(), nil 211 } 212 213 func getDaraClient(tag string) *daraClient { 214 client, ok := clientPool.Load(tag) 215 if client == nil && !ok { 216 client = &daraClient{ 217 httpClient: &http.Client{}, 218 ifInit: false, 219 } 220 clientPool.Store(tag, client) 221 } 222 return client.(*daraClient) 223 } 224 225 // DoRequest is used send request to server 226 func DoRequest(request *Request, runtimeObject *RuntimeObject) (response *Response, err error) { 227 if runtimeObject == nil { 228 runtimeObject = &RuntimeObject{} 229 } 230 fieldMap := make(map[string]string) 231 utils.InitLogMsg(fieldMap) 232 defer func() { 233 if runtimeObject.Logger != nil { 234 runtimeObject.Logger.PrintLog(fieldMap, err) 235 } 236 }() 237 if request.Method == nil { 238 request.Method = String("GET") 239 } 240 241 if request.Protocol == nil { 242 request.Protocol = String("http") 243 } else { 244 request.Protocol = String(strings.ToLower(StringValue(request.Protocol))) 245 } 246 247 requestURL := "" 248 request.Domain = request.Headers["host"] 249 if request.Port != nil { 250 request.Domain = String(fmt.Sprintf("%s:%d", StringValue(request.Domain), IntValue(request.Port))) 251 } 252 requestURL = fmt.Sprintf("%s://%s%s", StringValue(request.Protocol), StringValue(request.Domain), StringValue(request.Pathname)) 253 queryParams := request.Query 254 // sort QueryParams by key 255 q := url.Values{} 256 for key, value := range queryParams { 257 q.Add(key, StringValue(value)) 258 } 259 querystring := q.Encode() 260 if len(querystring) > 0 { 261 if strings.Contains(requestURL, "?") { 262 requestURL = fmt.Sprintf("%s&%s", requestURL, querystring) 263 } else { 264 requestURL = fmt.Sprintf("%s?%s", requestURL, querystring) 265 } 266 } 267 debugLog("> %s %s", StringValue(request.Method), requestURL) 268 269 httpRequest, err := http.NewRequest(StringValue(request.Method), requestURL, request.Body) 270 if err != nil { 271 return 272 } 273 httpRequest.Host = StringValue(request.Domain) 274 275 var client HttpClient 276 if runtimeObject.HttpClient == nil { 277 client = getDaraClient(runtimeObject.getClientTag(StringValue(request.Domain))) 278 } else { 279 client = runtimeObject.HttpClient 280 } 281 282 trans, err := getHttpTransport(request, runtimeObject) 283 if err != nil { 284 return 285 } 286 if defaultClient, ok := client.(*daraClient); ok { 287 defaultClient.Lock() 288 if !defaultClient.ifInit || defaultClient.httpClient.Transport == nil { 289 defaultClient.httpClient.Transport = trans 290 } 291 defaultClient.httpClient.Timeout = time.Duration(IntValue(runtimeObject.ReadTimeout)) * time.Millisecond 292 defaultClient.ifInit = true 293 defaultClient.Unlock() 294 } 295 296 for key, value := range request.Headers { 297 if value == nil || key == "content-length" { 298 continue 299 } else if key == "host" { 300 httpRequest.Header["Host"] = []string{*value} 301 delete(httpRequest.Header, "host") 302 } else if key == "user-agent" { 303 httpRequest.Header["User-Agent"] = []string{*value} 304 delete(httpRequest.Header, "user-agent") 305 } else { 306 httpRequest.Header[key] = []string{*value} 307 } 308 debugLog("> %s: %s", key, StringValue(value)) 309 } 310 contentlength, _ := strconv.Atoi(StringValue(request.Headers["content-length"])) 311 event := utils.NewProgressEvent(utils.TransferStartedEvent, 0, int64(contentlength), 0) 312 utils.PublishProgress(runtimeObject.Listener, event) 313 314 putMsgToMap(fieldMap, httpRequest) 315 startTime := time.Now() 316 fieldMap["{start_time}"] = startTime.Format("2006-01-02 15:04:05") 317 res, err := hookDo(client.Call)(httpRequest, trans) 318 fieldMap["{cost}"] = time.Since(startTime).String() 319 completedBytes := int64(0) 320 if runtimeObject.Tracker != nil { 321 completedBytes = runtimeObject.Tracker.CompletedBytes 322 } 323 if err != nil { 324 event = utils.NewProgressEvent(utils.TransferFailedEvent, completedBytes, int64(contentlength), 0) 325 utils.PublishProgress(runtimeObject.Listener, event) 326 return 327 } 328 329 event = utils.NewProgressEvent(utils.TransferCompletedEvent, completedBytes, int64(contentlength), 0) 330 utils.PublishProgress(runtimeObject.Listener, event) 331 332 response = NewResponse(res) 333 fieldMap["{code}"] = strconv.Itoa(res.StatusCode) 334 fieldMap["{res_headers}"] = Stringify(res.Header) 335 debugLog("< HTTP/1.1 %s", res.Status) 336 for key, value := range res.Header { 337 debugLog("< %s: %s", key, strings.Join(value, "")) 338 if len(value) != 0 { 339 response.Headers[strings.ToLower(key)] = String(value[0]) 340 } 341 } 342 return 343 } 344 345 func DoRequestWithCtx(ctx context.Context, request *Request, runtimeObject *RuntimeObject) (response *Response, err error) { 346 if runtimeObject == nil { 347 runtimeObject = &RuntimeObject{} 348 } 349 fieldMap := make(map[string]string) 350 utils.InitLogMsg(fieldMap) 351 defer func() { 352 if runtimeObject.Logger != nil { 353 runtimeObject.Logger.PrintLog(fieldMap, err) 354 } 355 }() 356 if request.Method == nil { 357 request.Method = String("GET") 358 } 359 360 if request.Protocol == nil { 361 request.Protocol = String("http") 362 } else { 363 request.Protocol = String(strings.ToLower(StringValue(request.Protocol))) 364 } 365 366 requestURL := "" 367 request.Domain = request.Headers["host"] 368 if request.Port != nil { 369 request.Domain = String(fmt.Sprintf("%s:%d", StringValue(request.Domain), IntValue(request.Port))) 370 } 371 requestURL = fmt.Sprintf("%s://%s%s", StringValue(request.Protocol), StringValue(request.Domain), StringValue(request.Pathname)) 372 queryParams := request.Query 373 // sort QueryParams by key 374 q := url.Values{} 375 for key, value := range queryParams { 376 q.Add(key, StringValue(value)) 377 } 378 querystring := q.Encode() 379 if len(querystring) > 0 { 380 if strings.Contains(requestURL, "?") { 381 requestURL = fmt.Sprintf("%s&%s", requestURL, querystring) 382 } else { 383 requestURL = fmt.Sprintf("%s?%s", requestURL, querystring) 384 } 385 } 386 debugLog("> %s %s", StringValue(request.Method), requestURL) 387 388 httpRequest, err := http.NewRequestWithContext(ctx, StringValue(request.Method), requestURL, request.Body) 389 if err != nil { 390 return 391 } 392 httpRequest.Host = StringValue(request.Domain) 393 394 var client HttpClient 395 if runtimeObject.HttpClient == nil { 396 client = getDaraClient(runtimeObject.getClientTag(StringValue(request.Domain))) 397 } else { 398 client = runtimeObject.HttpClient 399 } 400 401 trans, err := getHttpTransport(request, runtimeObject) 402 if err != nil { 403 return 404 } 405 if defaultClient, ok := client.(*daraClient); ok { 406 defaultClient.Lock() 407 if !defaultClient.ifInit || defaultClient.httpClient.Transport == nil { 408 defaultClient.httpClient.Transport = trans 409 } 410 defaultClient.httpClient.Timeout = time.Duration(IntValue(runtimeObject.ReadTimeout)) * time.Millisecond 411 defaultClient.ifInit = true 412 defaultClient.Unlock() 413 } 414 415 for key, value := range request.Headers { 416 if value == nil || key == "content-length" { 417 continue 418 } else if key == "host" { 419 httpRequest.Header["Host"] = []string{*value} 420 delete(httpRequest.Header, "host") 421 } else if key == "user-agent" { 422 httpRequest.Header["User-Agent"] = []string{*value} 423 delete(httpRequest.Header, "user-agent") 424 } else { 425 httpRequest.Header[key] = []string{*value} 426 } 427 debugLog("> %s: %s", key, StringValue(value)) 428 } 429 contentlength, _ := strconv.Atoi(StringValue(request.Headers["content-length"])) 430 event := utils.NewProgressEvent(utils.TransferStartedEvent, 0, int64(contentlength), 0) 431 utils.PublishProgress(runtimeObject.Listener, event) 432 433 putMsgToMap(fieldMap, httpRequest) 434 startTime := time.Now() 435 fieldMap["{start_time}"] = startTime.Format("2006-01-02 15:04:05") 436 res, err := hookDo(client.Call)(httpRequest, trans) 437 fieldMap["{cost}"] = time.Since(startTime).String() 438 completedBytes := int64(0) 439 if runtimeObject.Tracker != nil { 440 completedBytes = runtimeObject.Tracker.CompletedBytes 441 } 442 if err != nil { 443 select { 444 case <-ctx.Done(): 445 err = TeaSDKError(ctx.Err()) 446 default: 447 } 448 449 event = utils.NewProgressEvent(utils.TransferFailedEvent, completedBytes, int64(contentlength), 0) 450 utils.PublishProgress(runtimeObject.Listener, event) 451 return 452 } 453 454 event = utils.NewProgressEvent(utils.TransferCompletedEvent, completedBytes, int64(contentlength), 0) 455 utils.PublishProgress(runtimeObject.Listener, event) 456 457 response = NewResponse(res) 458 fieldMap["{code}"] = strconv.Itoa(res.StatusCode) 459 fieldMap["{res_headers}"] = Stringify(res.Header) 460 debugLog("< HTTP/1.1 %s", res.Status) 461 for key, value := range res.Header { 462 debugLog("< %s: %s", key, strings.Join(value, "")) 463 if len(value) != 0 { 464 response.Headers[strings.ToLower(key)] = String(value[0]) 465 } 466 } 467 return 468 } 469 470 func getHttpTransport(req *Request, runtime *RuntimeObject) (*http.Transport, error) { 471 trans := new(http.Transport) 472 httpProxy, err := getHttpProxy(StringValue(req.Protocol), StringValue(req.Domain), runtime) 473 if err != nil { 474 return nil, err 475 } 476 if strings.ToLower(*req.Protocol) == "https" { 477 if BoolValue(runtime.IgnoreSSL) != true { 478 trans.TLSClientConfig = &tls.Config{ 479 InsecureSkipVerify: false, 480 } 481 if runtime.Key != nil && runtime.Cert != nil && StringValue(runtime.Key) != "" && StringValue(runtime.Cert) != "" { 482 cert, err := tls.X509KeyPair([]byte(StringValue(runtime.Cert)), []byte(StringValue(runtime.Key))) 483 if err != nil { 484 return nil, err 485 } 486 trans.TLSClientConfig.Certificates = []tls.Certificate{cert} 487 } 488 if runtime.Ca != nil && StringValue(runtime.Ca) != "" { 489 clientCertPool := x509.NewCertPool() 490 ok := clientCertPool.AppendCertsFromPEM([]byte(StringValue(runtime.Ca))) 491 if !ok { 492 return nil, errors.New("Failed to parse root certificate") 493 } 494 trans.TLSClientConfig.RootCAs = clientCertPool 495 } 496 } else { 497 trans.TLSClientConfig = &tls.Config{ 498 InsecureSkipVerify: true, 499 } 500 } 501 } 502 if httpProxy != nil { 503 trans.Proxy = http.ProxyURL(httpProxy) 504 if httpProxy.User != nil { 505 password, _ := httpProxy.User.Password() 506 auth := httpProxy.User.Username() + ":" + password 507 basic := "Basic " + base64.StdEncoding.EncodeToString([]byte(auth)) 508 req.Headers["Proxy-Authorization"] = String(basic) 509 } 510 } 511 if runtime.Socks5Proxy != nil && StringValue(runtime.Socks5Proxy) != "" { 512 socks5Proxy, err := getSocks5Proxy(runtime) 513 if err != nil { 514 return nil, err 515 } 516 if socks5Proxy != nil { 517 var auth *proxy.Auth 518 if socks5Proxy.User != nil { 519 password, _ := socks5Proxy.User.Password() 520 auth = &proxy.Auth{ 521 User: socks5Proxy.User.Username(), 522 Password: password, 523 } 524 } 525 dialer, err := proxy.SOCKS5(strings.ToLower(StringValue(runtime.Socks5NetWork)), socks5Proxy.String(), auth, 526 &net.Dialer{ 527 Timeout: time.Duration(IntValue(runtime.ConnectTimeout)) * time.Millisecond, 528 DualStack: true, 529 LocalAddr: getLocalAddr(StringValue(runtime.LocalAddr)), 530 }) 531 if err != nil { 532 return nil, err 533 } 534 trans.Dial = dialer.Dial 535 } 536 } else { 537 trans.DialContext = setDialContext(runtime) 538 } 539 if runtime.MaxIdleConns != nil && *runtime.MaxIdleConns > 0 { 540 trans.MaxIdleConns = IntValue(runtime.MaxIdleConns) 541 trans.MaxIdleConnsPerHost = IntValue(runtime.MaxIdleConns) 542 } 543 return trans, nil 544 } 545 546 func putMsgToMap(fieldMap map[string]string, request *http.Request) { 547 fieldMap["{host}"] = request.Host 548 fieldMap["{method}"] = request.Method 549 fieldMap["{uri}"] = request.URL.RequestURI() 550 fieldMap["{pid}"] = strconv.Itoa(os.Getpid()) 551 fieldMap["{version}"] = strings.Split(request.Proto, "/")[1] 552 hostname, _ := os.Hostname() 553 fieldMap["{hostname}"] = hostname 554 fieldMap["{req_headers}"] = Stringify(request.Header) 555 fieldMap["{target}"] = request.URL.Path + request.URL.RawQuery 556 } 557 558 func getNoProxy(protocol string, runtime *RuntimeObject) []string { 559 var urls []string 560 if runtime.NoProxy != nil && StringValue(runtime.NoProxy) != "" { 561 urls = strings.Split(StringValue(runtime.NoProxy), ",") 562 } else if rawurl := os.Getenv("NO_PROXY"); rawurl != "" { 563 urls = strings.Split(rawurl, ",") 564 } else if rawurl := os.Getenv("no_proxy"); rawurl != "" { 565 urls = strings.Split(rawurl, ",") 566 } 567 568 return urls 569 } 570 571 func ToReader(obj interface{}) io.Reader { 572 switch obj.(type) { 573 case string: 574 tmp := obj.(string) 575 return strings.NewReader(tmp) 576 case *string: 577 tmp := obj.(*string) 578 return strings.NewReader(StringValue(tmp)) 579 case []byte: 580 return strings.NewReader(string(obj.([]byte))) 581 case io.Reader: 582 return obj.(io.Reader) 583 default: 584 panic("Invalid Body. Please set a valid Body.") 585 } 586 } 587 588 func ToWriter(obj interface{}) io.Writer { 589 switch obj.(type) { 590 case string: 591 var buf bytes.Buffer 592 buf.WriteString(obj.(string)) 593 return &buf 594 case *string: 595 var buf bytes.Buffer 596 tmp := obj.(*string) 597 buf.WriteString(*tmp) 598 return &buf 599 case []byte: 600 var buf bytes.Buffer 601 buf.Write(obj.([]byte)) 602 return &buf 603 case io.Writer: 604 return obj.(io.Writer) 605 case *bytes.Buffer: 606 return obj.(*bytes.Buffer) 607 case *os.File: 608 return obj.(*os.File) 609 default: 610 panic("Invalid Writer. Please provide a valid Writer.") 611 } 612 } 613 614 func ToString(val interface{}) string { 615 switch v := val.(type) { 616 case []byte: 617 return string(v) // 将 []byte 转换为字符串 618 default: 619 return fmt.Sprintf("%v", v) // 处理其他类型 620 } 621 } 622 623 func getHttpProxy(protocol, host string, runtime *RuntimeObject) (proxy *url.URL, err error) { 624 urls := getNoProxy(protocol, runtime) 625 for _, url := range urls { 626 if url == host { 627 return nil, nil 628 } 629 } 630 if protocol == "https" { 631 if runtime.HttpsProxy != nil && StringValue(runtime.HttpsProxy) != "" { 632 proxy, err = url.Parse(StringValue(runtime.HttpsProxy)) 633 } else if rawurl := os.Getenv("HTTPS_PROXY"); rawurl != "" { 634 proxy, err = url.Parse(rawurl) 635 } else if rawurl := os.Getenv("https_proxy"); rawurl != "" { 636 proxy, err = url.Parse(rawurl) 637 } 638 } else { 639 if runtime.HttpProxy != nil && StringValue(runtime.HttpProxy) != "" { 640 proxy, err = url.Parse(StringValue(runtime.HttpProxy)) 641 } else if rawurl := os.Getenv("HTTP_PROXY"); rawurl != "" { 642 proxy, err = url.Parse(rawurl) 643 } else if rawurl := os.Getenv("http_proxy"); rawurl != "" { 644 proxy, err = url.Parse(rawurl) 645 } 646 } 647 648 return proxy, err 649 } 650 651 func getSocks5Proxy(runtime *RuntimeObject) (proxy *url.URL, err error) { 652 if runtime.Socks5Proxy != nil && StringValue(runtime.Socks5Proxy) != "" { 653 proxy, err = url.Parse(StringValue(runtime.Socks5Proxy)) 654 } 655 return proxy, err 656 } 657 658 func getLocalAddr(localAddr string) (addr *net.TCPAddr) { 659 if localAddr != "" { 660 addr = &net.TCPAddr{ 661 IP: []byte(localAddr), 662 } 663 } 664 return addr 665 } 666 667 func setDialContext(runtime *RuntimeObject) func(cxt context.Context, net, addr string) (c net.Conn, err error) { 668 return func(ctx context.Context, network, address string) (net.Conn, error) { 669 if runtime.LocalAddr != nil && StringValue(runtime.LocalAddr) != "" { 670 netAddr := &net.TCPAddr{ 671 IP: []byte(StringValue(runtime.LocalAddr)), 672 } 673 return (&net.Dialer{ 674 Timeout: time.Duration(IntValue(runtime.ConnectTimeout)) * time.Second, 675 DualStack: true, 676 LocalAddr: netAddr, 677 }).DialContext(ctx, network, address) 678 } 679 return (&net.Dialer{ 680 Timeout: time.Duration(IntValue(runtime.ConnectTimeout)) * time.Second, 681 DualStack: true, 682 }).DialContext(ctx, network, address) 683 } 684 } 685 686 func ToObject(obj interface{}) map[string]interface{} { 687 result := make(map[string]interface{}) 688 byt, _ := json.Marshal(obj) 689 err := json.Unmarshal(byt, &result) 690 if err != nil { 691 return nil 692 } 693 return result 694 } 695 696 func AllowRetry(retry interface{}, retryTimes *int) *bool { 697 if IntValue(retryTimes) == 0 { 698 return Bool(true) 699 } 700 retryMap, ok := retry.(map[string]interface{}) 701 if !ok { 702 return Bool(false) 703 } 704 retryable, ok := retryMap["retryable"].(bool) 705 if !ok || !retryable { 706 return Bool(false) 707 } 708 709 maxAttempts, ok := retryMap["maxAttempts"].(int) 710 if !ok || maxAttempts < IntValue(retryTimes) { 711 return Bool(false) 712 } 713 return Bool(true) 714 } 715 716 func Merge(args ...interface{}) map[string]*string { 717 finalArg := make(map[string]*string) 718 for _, obj := range args { 719 switch obj.(type) { 720 case map[string]*string: 721 arg := obj.(map[string]*string) 722 for key, value := range arg { 723 if value != nil { 724 finalArg[key] = value 725 } 726 } 727 default: 728 byt, _ := json.Marshal(obj) 729 arg := make(map[string]string) 730 err := json.Unmarshal(byt, &arg) 731 if err != nil { 732 return finalArg 733 } 734 for key, value := range arg { 735 if value != "" { 736 finalArg[key] = String(value) 737 } 738 } 739 } 740 } 741 742 return finalArg 743 } 744 745 func IsNil(val interface{}) bool { 746 defer func() { 747 recover() 748 }() 749 if val == nil { 750 return true 751 } 752 753 v := reflect.ValueOf(val) 754 if v.Kind() == reflect.Ptr || v.Kind() == reflect.Slice || v.Kind() == reflect.Map { 755 return v.IsNil() 756 } 757 758 valType := reflect.TypeOf(val) 759 valZero := reflect.Zero(valType) 760 return valZero == v 761 } 762 763 func isNil(a interface{}) bool { 764 defer func() { 765 recover() 766 }() 767 vi := reflect.ValueOf(a) 768 return vi.IsNil() 769 } 770 771 func isNilOrZero(value interface{}) bool { 772 if value == nil { 773 return true 774 } 775 776 v := reflect.ValueOf(value) 777 switch v.Kind() { 778 case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Slice: 779 return v.IsNil() 780 default: 781 // Check for zero value 782 return reflect.DeepEqual(value, reflect.Zero(v.Type()).Interface()) 783 } 784 } 785 786 func Default(inputValue interface{}, defaultValue interface{}) (_result interface{}) { 787 if isNilOrZero(inputValue) { 788 _result = defaultValue 789 return _result 790 } 791 792 _result = inputValue 793 return _result 794 } 795 796 func ToMap(args ...interface{}) map[string]interface{} { 797 isNotNil := false 798 finalArg := make(map[string]interface{}) 799 for _, obj := range args { 800 if obj == nil { 801 continue 802 } 803 804 if isNil(obj) { 805 continue 806 } 807 isNotNil = true 808 809 switch obj.(type) { 810 case map[string]*string: 811 arg := obj.(map[string]*string) 812 for key, value := range arg { 813 if value != nil { 814 finalArg[key] = StringValue(value) 815 } 816 } 817 case map[string]interface{}: 818 arg := obj.(map[string]interface{}) 819 for key, value := range arg { 820 if value != nil { 821 finalArg[key] = value 822 } 823 } 824 case *string: 825 str := obj.(*string) 826 arg := make(map[string]interface{}) 827 err := json.Unmarshal([]byte(StringValue(str)), &arg) 828 if err == nil { 829 for key, value := range arg { 830 if value != nil { 831 finalArg[key] = value 832 } 833 } 834 } 835 tmp := make(map[string]string) 836 err = json.Unmarshal([]byte(StringValue(str)), &tmp) 837 if err == nil { 838 for key, value := range arg { 839 if value != "" { 840 finalArg[key] = value 841 } 842 } 843 } 844 case []byte: 845 byt := obj.([]byte) 846 arg := make(map[string]interface{}) 847 err := json.Unmarshal(byt, &arg) 848 if err == nil { 849 for key, value := range arg { 850 if value != nil { 851 finalArg[key] = value 852 } 853 } 854 break 855 } 856 default: 857 val := reflect.ValueOf(obj) 858 if val.Kind().String() == "map" { 859 tmp := val.MapKeys() 860 for _, key := range tmp { 861 finalArg[key.String()] = val.MapIndex(key).Interface() 862 } 863 } else { 864 res := structToMap(val) 865 for key, value := range res { 866 if value != nil { 867 finalArg[key] = value 868 } 869 } 870 } 871 } 872 } 873 874 if !isNotNil { 875 return nil 876 } 877 return finalArg 878 } 879 880 func structToMap(dataValue reflect.Value) map[string]interface{} { 881 out := make(map[string]interface{}) 882 if !dataValue.IsValid() { 883 return out 884 } 885 if dataValue.Kind().String() == "ptr" { 886 if dataValue.IsNil() { 887 return out 888 } 889 dataValue = dataValue.Elem() 890 } 891 if !dataValue.IsValid() { 892 return out 893 } 894 dataType := dataValue.Type() 895 if dataType.Kind().String() != "struct" { 896 return out 897 } 898 for i := 0; i < dataType.NumField(); i++ { 899 field := dataType.Field(i) 900 name, containsNameTag := field.Tag.Lookup("json") 901 if !containsNameTag { 902 name = field.Name 903 } else { 904 strs := strings.Split(name, ",") 905 name = strs[0] 906 } 907 fieldValue := dataValue.FieldByName(field.Name) 908 if !fieldValue.IsValid() || fieldValue.IsNil() { 909 continue 910 } 911 if field.Type.String() == "io.Reader" || field.Type.String() == "io.Writer" { 912 continue 913 } else if field.Type.Kind().String() == "struct" { 914 out[name] = structToMap(fieldValue) 915 } else if field.Type.Kind().String() == "ptr" && 916 field.Type.Elem().Kind().String() == "struct" { 917 if fieldValue.Elem().IsValid() { 918 out[name] = structToMap(fieldValue) 919 } 920 } else if field.Type.Kind().String() == "ptr" { 921 if fieldValue.IsValid() && !fieldValue.IsNil() { 922 out[name] = fieldValue.Elem().Interface() 923 } 924 } else if field.Type.Kind().String() == "slice" { 925 tmp := make([]interface{}, 0) 926 num := fieldValue.Len() 927 for i := 0; i < num; i++ { 928 value := fieldValue.Index(i) 929 if !value.IsValid() { 930 continue 931 } 932 if value.Type().Kind().String() == "ptr" && 933 value.Type().Elem().Kind().String() == "struct" { 934 if value.IsValid() && !value.IsNil() { 935 tmp = append(tmp, structToMap(value)) 936 } 937 } else if value.Type().Kind().String() == "struct" { 938 tmp = append(tmp, structToMap(value)) 939 } else if value.Type().Kind().String() == "ptr" { 940 if value.IsValid() && !value.IsNil() { 941 tmp = append(tmp, value.Elem().Interface()) 942 } 943 } else { 944 tmp = append(tmp, value.Interface()) 945 } 946 } 947 if len(tmp) > 0 { 948 out[name] = tmp 949 } 950 } else { 951 out[name] = fieldValue.Interface() 952 } 953 954 } 955 return out 956 } 957 958 func GetBackoffTime(backoff interface{}, retrytimes *int) *int { 959 backoffMap, ok := backoff.(map[string]interface{}) 960 if !ok { 961 return Int(0) 962 } 963 policy, ok := backoffMap["policy"].(string) 964 if !ok || policy == "no" { 965 return Int(0) 966 } 967 968 period, ok := backoffMap["period"].(int) 969 if !ok || period == 0 { 970 return Int(0) 971 } 972 973 maxTime := math.Pow(2.0, float64(IntValue(retrytimes))) 974 return Int(rand.Intn(int(maxTime-1)) * period) 975 } 976 977 func Sleep(backoffTime int) { 978 sleeptime := time.Duration(backoffTime) * time.Second 979 time.Sleep(sleeptime) 980 } 981 982 // Determines whether realType is in filterTypes 983 func isFilterType(realType string, filterTypes []string) bool { 984 for _, value := range filterTypes { 985 if value == realType { 986 return true 987 } 988 } 989 return false 990 } 991 992 func TransInterfaceToBool(val interface{}) *bool { 993 if val == nil { 994 return nil 995 } 996 997 return Bool(val.(bool)) 998 } 999 1000 func TransInterfaceToInt(val interface{}) *int { 1001 if val == nil { 1002 return nil 1003 } 1004 1005 return Int(val.(int)) 1006 } 1007 1008 func TransInterfaceToString(val interface{}) *string { 1009 if val == nil { 1010 return nil 1011 } 1012 1013 return String(val.(string)) 1014 } 1015 1016 func Prettify(i interface{}) string { 1017 resp, _ := json.MarshalIndent(i, "", " ") 1018 return string(resp) 1019 } 1020 1021 func ToInt(a *int32) *int { 1022 return Int(int(Int32Value(a))) 1023 } 1024 1025 func ToInt32(a *int) *int32 { 1026 return Int32(int32(IntValue(a))) 1027 } 1028 1029 func ToBytes(s, encodingType string) []byte { 1030 switch encodingType { 1031 case "utf8": 1032 return []byte(s) 1033 case "base64": 1034 data, err := base64.StdEncoding.DecodeString(s) 1035 if err != nil { 1036 return nil 1037 } 1038 return data 1039 case "hex": 1040 data, err := hex.DecodeString(s) 1041 if err != nil { 1042 return nil 1043 } 1044 return data 1045 default: 1046 return nil 1047 } 1048 } 1049 1050 func BytesFromString(str string, typeStr string) []byte { 1051 switch typeStr { 1052 case "utf8": 1053 return []byte(str) 1054 case "hex": 1055 bytes, err := hex.DecodeString(str) 1056 if err == nil { 1057 return bytes 1058 } 1059 case "base64": 1060 bytes, err := base64.StdEncoding.DecodeString(str) 1061 if err == nil { 1062 return bytes 1063 } 1064 } 1065 1066 // 对于不支持的类型或解码失败,返回 nil 1067 return nil 1068 } 1069 1070 func ForceInt(a interface{}) int { 1071 num, _ := a.(int) 1072 return num 1073 } 1074 1075 func ForceBoolean(a interface{}) bool { 1076 b, _ := a.(bool) 1077 return b 1078 } 1079 1080 func ForceInt64(a interface{}) int64 { 1081 b, _ := a.(int64) 1082 return b 1083 } 1084 1085 func ForceUint64(a interface{}) uint64 { 1086 b, _ := a.(uint64) 1087 return b 1088 } 1089 1090 // ForceInt32 attempts to assert that a is of type int32. 1091 func ForceInt32(a interface{}) int32 { 1092 b, _ := a.(int32) 1093 return b 1094 } 1095 1096 // ForceUInt32 attempts to assert that a is of type uint32. 1097 func ForceUInt32(a interface{}) uint32 { 1098 b, _ := a.(uint32) 1099 return b 1100 } 1101 1102 // ForceInt16 attempts to assert that a is of type int16. 1103 func ForceInt16(a interface{}) int16 { 1104 b, _ := a.(int16) 1105 return b 1106 } 1107 1108 // ForceUInt16 attempts to assert that a is of type uint16. 1109 func ForceUInt16(a interface{}) uint16 { 1110 b, _ := a.(uint16) 1111 return b 1112 } 1113 1114 // ForceInt8 attempts to assert that a is of type int8. 1115 func ForceInt8(a interface{}) int8 { 1116 b, _ := a.(int8) 1117 return b 1118 } 1119 1120 // ForceUInt8 attempts to assert that a is of type uint8. 1121 func ForceUInt8(a interface{}) uint8 { 1122 b, _ := a.(uint8) 1123 return b 1124 } 1125 1126 // ForceFloat32 attempts to assert that a is of type float32. 1127 func ForceFloat32(a interface{}) float32 { 1128 b, _ := a.(float32) 1129 return b 1130 } 1131 1132 // ForceFloat64 attempts to assert that a is of type float64. 1133 func ForceFloat64(a interface{}) float64 { 1134 b, _ := a.(float64) 1135 return b 1136 }