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  }