package service import ( "bufio" "bytes" "crypto/md5" "encoding/hex" "encoding/json" "errors" "fmt" "io" "io/ioutil" "math/rand" "net/http" "net/url" "reflect" "runtime" "strconv" "strings" "sync/atomic" "time" "github.com/alibabacloud-go/tea/tea" ) var defaultUserAgent = fmt.Sprintf("AlibabaCloud (%s; %s) Golang/%s Core/%s TeaDSL/1", runtime.GOOS, runtime.GOARCH, strings.Trim(runtime.Version(), "go"), "0.01") type ExtendsParameters struct { Headers map[string]*string `json:"headers,omitempty" xml:"headers,omitempty"` Queries map[string]*string `json:"queries,omitempty" xml:"queries,omitempty"` } func (s ExtendsParameters) String() string { return tea.Prettify(s) } func (s ExtendsParameters) GoString() string { return s.String() } func (s *ExtendsParameters) SetHeaders(v map[string]*string) *ExtendsParameters { s.Headers = v return s } func (s *ExtendsParameters) SetQueries(v map[string]*string) *ExtendsParameters { s.Queries = v return s } type RuntimeOptions struct { Autoretry *bool `json:"autoretry" xml:"autoretry"` IgnoreSSL *bool `json:"ignoreSSL" xml:"ignoreSSL"` Key *string `json:"key,omitempty" xml:"key,omitempty"` Cert *string `json:"cert,omitempty" xml:"cert,omitempty"` Ca *string `json:"ca,omitempty" xml:"ca,omitempty"` MaxAttempts *int `json:"maxAttempts" xml:"maxAttempts"` BackoffPolicy *string `json:"backoffPolicy" xml:"backoffPolicy"` BackoffPeriod *int `json:"backoffPeriod" xml:"backoffPeriod"` ReadTimeout *int `json:"readTimeout" xml:"readTimeout"` ConnectTimeout *int `json:"connectTimeout" xml:"connectTimeout"` LocalAddr *string `json:"localAddr" xml:"localAddr"` HttpProxy *string `json:"httpProxy" xml:"httpProxy"` HttpsProxy *string `json:"httpsProxy" xml:"httpsProxy"` NoProxy *string `json:"noProxy" xml:"noProxy"` MaxIdleConns *int `json:"maxIdleConns" xml:"maxIdleConns"` Socks5Proxy *string `json:"socks5Proxy" xml:"socks5Proxy"` Socks5NetWork *string `json:"socks5NetWork" xml:"socks5NetWork"` KeepAlive *bool `json:"keepAlive" xml:"keepAlive"` ExtendsParameters *ExtendsParameters `json:"extendsParameters,omitempty" xml:"extendsParameters,omitempty"` } var processStartTime int64 = time.Now().UnixNano() / 1e6 var seqId int64 = 0 type SSEEvent struct { ID *string Event *string Data *string Retry *int } func parseEvent(eventLines []string) (SSEEvent, error) { var event SSEEvent for _, line := range eventLines { if strings.HasPrefix(line, "data:") { event.Data = tea.String(tea.StringValue(event.Data) + strings.TrimPrefix(line, "data:") + "\n") } else if strings.HasPrefix(line, "id:") { id := strings.TrimPrefix(line, "id:") event.ID = tea.String(strings.Trim(id, " ")) } else if strings.HasPrefix(line, "event:") { eventName := strings.TrimPrefix(line, "event:") event.Event = tea.String(strings.Trim(eventName, " ")) } else if strings.HasPrefix(line, "retry:") { trimmedLine := strings.TrimPrefix(line, "retry:") trimmedLine = strings.Trim(trimmedLine, " ") retryValue, _err := strconv.Atoi(trimmedLine) if _err != nil { return event, fmt.Errorf("retry %v is not a int", trimmedLine) } event.Retry = tea.Int(retryValue) } } data := strings.TrimRight(tea.StringValue(event.Data), "\n") event.Data = tea.String(strings.Trim(data, " ")) return event, nil } func getGID() uint64 { // https://blog.sgmansfield.com/2015/12/goroutine-ids/ b := make([]byte, 64) b = b[:runtime.Stack(b, false)] b = bytes.TrimPrefix(b, []byte("goroutine ")) b = b[:bytes.IndexByte(b, ' ')] n, _ := strconv.ParseUint(string(b), 10, 64) return n } func (s RuntimeOptions) String() string { return tea.Prettify(s) } func (s RuntimeOptions) GoString() string { return s.String() } func (s *RuntimeOptions) SetAutoretry(v bool) *RuntimeOptions { s.Autoretry = &v return s } func (s *RuntimeOptions) SetIgnoreSSL(v bool) *RuntimeOptions { s.IgnoreSSL = &v return s } func (s *RuntimeOptions) SetKey(v string) *RuntimeOptions { s.Key = &v return s } func (s *RuntimeOptions) SetCert(v string) *RuntimeOptions { s.Cert = &v return s } func (s *RuntimeOptions) SetCa(v string) *RuntimeOptions { s.Ca = &v return s } func (s *RuntimeOptions) SetMaxAttempts(v int) *RuntimeOptions { s.MaxAttempts = &v return s } func (s *RuntimeOptions) SetBackoffPolicy(v string) *RuntimeOptions { s.BackoffPolicy = &v return s } func (s *RuntimeOptions) SetBackoffPeriod(v int) *RuntimeOptions { s.BackoffPeriod = &v return s } func (s *RuntimeOptions) SetReadTimeout(v int) *RuntimeOptions { s.ReadTimeout = &v return s } func (s *RuntimeOptions) SetConnectTimeout(v int) *RuntimeOptions { s.ConnectTimeout = &v return s } func (s *RuntimeOptions) SetHttpProxy(v string) *RuntimeOptions { s.HttpProxy = &v return s } func (s *RuntimeOptions) SetHttpsProxy(v string) *RuntimeOptions { s.HttpsProxy = &v return s } func (s *RuntimeOptions) SetNoProxy(v string) *RuntimeOptions { s.NoProxy = &v return s } func (s *RuntimeOptions) SetMaxIdleConns(v int) *RuntimeOptions { s.MaxIdleConns = &v return s } func (s *RuntimeOptions) SetLocalAddr(v string) *RuntimeOptions { s.LocalAddr = &v return s } func (s *RuntimeOptions) SetSocks5Proxy(v string) *RuntimeOptions { s.Socks5Proxy = &v return s } func (s *RuntimeOptions) SetSocks5NetWork(v string) *RuntimeOptions { s.Socks5NetWork = &v return s } func (s *RuntimeOptions) SetKeepAlive(v bool) *RuntimeOptions { s.KeepAlive = &v return s } func (s *RuntimeOptions) SetExtendsParameters(v *ExtendsParameters) *RuntimeOptions { s.ExtendsParameters = v return s } func ReadAsString(body io.Reader) (*string, error) { byt, err := ioutil.ReadAll(body) if err != nil { return tea.String(""), err } r, ok := body.(io.ReadCloser) if ok { r.Close() } return tea.String(string(byt)), nil } func StringifyMapValue(a map[string]interface{}) map[string]*string { res := make(map[string]*string) for key, value := range a { if value != nil { res[key] = ToJSONString(value) } } return res } func AnyifyMapValue(a map[string]*string) map[string]interface{} { res := make(map[string]interface{}) for key, value := range a { res[key] = tea.StringValue(value) } return res } func ReadAsBytes(body io.Reader) ([]byte, error) { byt, err := ioutil.ReadAll(body) if err != nil { return nil, err } r, ok := body.(io.ReadCloser) if ok { r.Close() } return byt, nil } func DefaultString(reaStr, defaultStr *string) *string { if reaStr == nil { return defaultStr } return reaStr } func ToJSONString(a interface{}) *string { switch v := a.(type) { case *string: return v case string: return tea.String(v) case []byte: return tea.String(string(v)) case io.Reader: byt, err := ioutil.ReadAll(v) if err != nil { return nil } return tea.String(string(byt)) } byt := bytes.NewBuffer([]byte{}) jsonEncoder := json.NewEncoder(byt) jsonEncoder.SetEscapeHTML(false) if err := jsonEncoder.Encode(a); err != nil { return nil } return tea.String(string(bytes.TrimSpace(byt.Bytes()))) } func DefaultNumber(reaNum, defaultNum *int) *int { if reaNum == nil { return defaultNum } return reaNum } func ReadAsJSON(body io.Reader) (result interface{}, err error) { byt, err := ioutil.ReadAll(body) if err != nil { return } if string(byt) == "" { return } r, ok := body.(io.ReadCloser) if ok { r.Close() } d := json.NewDecoder(bytes.NewReader(byt)) d.UseNumber() err = d.Decode(&result) return } func GetNonce() *string { routineId := getGID() currentTime := time.Now().UnixNano() / 1e6 seq := atomic.AddInt64(&seqId, 1) randNum := rand.Int63() msg := fmt.Sprintf("%d-%d-%d-%d-%d", processStartTime, routineId, currentTime, seq, randNum) h := md5.New() h.Write([]byte(msg)) ret := hex.EncodeToString(h.Sum(nil)) return &ret } func Empty(val *string) *bool { return tea.Bool(val == nil || tea.StringValue(val) == "") } func ValidateModel(a interface{}) error { if a == nil { return nil } err := tea.Validate(a) return err } func EqualString(val1, val2 *string) *bool { return tea.Bool(tea.StringValue(val1) == tea.StringValue(val2)) } func EqualNumber(val1, val2 *int) *bool { return tea.Bool(tea.IntValue(val1) == tea.IntValue(val2)) } func IsUnset(val interface{}) *bool { if val == nil { return tea.Bool(true) } v := reflect.ValueOf(val) if v.Kind() == reflect.Ptr || v.Kind() == reflect.Slice || v.Kind() == reflect.Map { return tea.Bool(v.IsNil()) } valType := reflect.TypeOf(val) valZero := reflect.Zero(valType) return tea.Bool(valZero == v) } func ToBytes(a *string) []byte { return []byte(tea.StringValue(a)) } func AssertAsMap(a interface{}) (_result map[string]interface{}, _err error) { r := reflect.ValueOf(a) if r.Kind().String() != "map" { return nil, errors.New(fmt.Sprintf("%v is not a map[string]interface{}", a)) } res := make(map[string]interface{}) tmp := r.MapKeys() for _, key := range tmp { res[key.String()] = r.MapIndex(key).Interface() } return res, nil } func AssertAsNumber(a interface{}) (_result *int, _err error) { res := 0 switch a.(type) { case int: tmp := a.(int) res = tmp case *int: tmp := a.(*int) res = tea.IntValue(tmp) default: return nil, errors.New(fmt.Sprintf("%v is not a int", a)) } return tea.Int(res), nil } /** * Assert a value, if it is a integer, return it, otherwise throws * @return the integer value */ func AssertAsInteger(value interface{}) (_result *int, _err error) { res := 0 switch value.(type) { case int: tmp := value.(int) res = tmp case *int: tmp := value.(*int) res = tea.IntValue(tmp) default: return nil, errors.New(fmt.Sprintf("%v is not a int", value)) } return tea.Int(res), nil } func AssertAsBoolean(a interface{}) (_result *bool, _err error) { res := false switch a.(type) { case bool: tmp := a.(bool) res = tmp case *bool: tmp := a.(*bool) res = tea.BoolValue(tmp) default: return nil, errors.New(fmt.Sprintf("%v is not a bool", a)) } return tea.Bool(res), nil } func AssertAsString(a interface{}) (_result *string, _err error) { res := "" switch a.(type) { case string: tmp := a.(string) res = tmp case *string: tmp := a.(*string) res = tea.StringValue(tmp) default: return nil, errors.New(fmt.Sprintf("%v is not a string", a)) } return tea.String(res), nil } func AssertAsBytes(a interface{}) (_result []byte, _err error) { res, ok := a.([]byte) if !ok { return nil, errors.New(fmt.Sprintf("%v is not a []byte", a)) } return res, nil } func AssertAsReadable(a interface{}) (_result io.Reader, _err error) { res, ok := a.(io.Reader) if !ok { return nil, errors.New(fmt.Sprintf("%v is not a reader", a)) } return res, nil } func AssertAsArray(a interface{}) (_result []interface{}, _err error) { r := reflect.ValueOf(a) if r.Kind().String() != "array" && r.Kind().String() != "slice" { return nil, errors.New(fmt.Sprintf("%v is not a []interface{}", a)) } aLen := r.Len() res := make([]interface{}, 0) for i := 0; i < aLen; i++ { res = append(res, r.Index(i).Interface()) } return res, nil } func ParseJSON(a *string) interface{} { mapTmp := make(map[string]interface{}) d := json.NewDecoder(bytes.NewReader([]byte(tea.StringValue(a)))) d.UseNumber() err := d.Decode(&mapTmp) if err == nil { return mapTmp } sliceTmp := make([]interface{}, 0) d = json.NewDecoder(bytes.NewReader([]byte(tea.StringValue(a)))) d.UseNumber() err = d.Decode(&sliceTmp) if err == nil { return sliceTmp } if num, err := strconv.Atoi(tea.StringValue(a)); err == nil { return num } if ok, err := strconv.ParseBool(tea.StringValue(a)); err == nil { return ok } if floa64tVal, err := strconv.ParseFloat(tea.StringValue(a), 64); err == nil { return floa64tVal } return nil } func ToString(a []byte) *string { return tea.String(string(a)) } func ToMap(in interface{}) map[string]interface{} { if in == nil { return nil } res := tea.ToMap(in) return res } func ToFormString(a map[string]interface{}) *string { if a == nil { return tea.String("") } res := "" urlEncoder := url.Values{} for key, value := range a { v := fmt.Sprintf("%v", value) urlEncoder.Add(key, v) } res = urlEncoder.Encode() return tea.String(res) } func GetDateUTCString() *string { return tea.String(time.Now().UTC().Format(http.TimeFormat)) } func GetUserAgent(userAgent *string) *string { if userAgent != nil && tea.StringValue(userAgent) != "" { return tea.String(defaultUserAgent + " " + tea.StringValue(userAgent)) } return tea.String(defaultUserAgent) } func Is2xx(code *int) *bool { tmp := tea.IntValue(code) return tea.Bool(tmp >= 200 && tmp < 300) } func Is3xx(code *int) *bool { tmp := tea.IntValue(code) return tea.Bool(tmp >= 300 && tmp < 400) } func Is4xx(code *int) *bool { tmp := tea.IntValue(code) return tea.Bool(tmp >= 400 && tmp < 500) } func Is5xx(code *int) *bool { tmp := tea.IntValue(code) return tea.Bool(tmp >= 500 && tmp < 600) } func Sleep(millisecond *int) error { ms := tea.IntValue(millisecond) time.Sleep(time.Duration(ms) * time.Millisecond) return nil } func ToArray(in interface{}) []map[string]interface{} { if tea.BoolValue(IsUnset(in)) { return nil } tmp := make([]map[string]interface{}, 0) byt, _ := json.Marshal(in) d := json.NewDecoder(bytes.NewReader(byt)) d.UseNumber() err := d.Decode(&tmp) if err != nil { return nil } return tmp } func ReadAsSSE(body io.ReadCloser) (<-chan SSEEvent, <-chan error) { eventChannel := make(chan SSEEvent) errorChannel := make(chan error) go func() { defer body.Close() defer close(eventChannel) reader := bufio.NewReader(body) var eventLines []string for { line, err := reader.ReadString('\n') if err == io.EOF { break } if err != nil { errorChannel <- err } line = strings.TrimRight(line, "\n") if line == "" { if len(eventLines) > 0 { event, err := parseEvent(eventLines) if err != nil { errorChannel <- err } eventChannel <- event eventLines = []string{} } continue } eventLines = append(eventLines, line) } }() return eventChannel, errorChannel }