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