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