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