package request import ( "crypto/hmac" "crypto/md5" "crypto/sha1" "encoding/base64" "encoding/hex" "encoding/json" "errors" "fmt" "git.oa00.com/go/jdsdk/config" "github.com/mitchellh/mapstructure" "log" "net/url" "reflect" "sort" "strings" "time" ) type ctpProtocol struct { AppKey string `json:"appKey"` ChannelId uint `json:"channelId"` CustomerId uint `json:"customerId"` OpName string `json:"opName"` TraceId string `json:"traceId"` } type resp struct { Code string `json:"code"` Result struct { ErrMsg string `json:"errMsg"` Data interface{} `json:"data"` StockStateList interface{} `json:"StockStateList"` Success bool `json:"success"` ErrCode int `json:"errCode"` } `json:"result"` } type RespErr struct { ErrorResponse struct { Code string `json:"code"` ZhDesc string `json:"zh_desc"` EnDesc string `json:"en_desc"` } `json:"error_response"` } // @Title 调用接口 func exec(action string, data string, result interface{}) error { t := time.Now().Format("2006-01-02 15:04:05") params := url.Values{ "app_key": {config.SdkConfig.AppKey}, "method": {action}, "access_token": {config.SdkConfig.AccessToken}, "v": {"2.0"}, "format": {"json"}, "timestamp": {t}, "360buy_param_json": {data}, } params.Add("sign", Sign(params)) bytes, err := request("GET", fmt.Sprintf("%s?%s", config.SdkConfig.Url, params.Encode()), "") if err != nil { return err } log.Println(string(bytes)) respErr := RespErr{} json.Unmarshal(bytes, &respErr) if respErr.ErrorResponse.Code != "" { //if respErr.ErrorResponse.Code == "19" && config.SdkConfig.RefreshTokenCallback != nil { // token, err := RefreshToken() // if err != nil { // return err // } // config.SdkConfig.RefreshTokenCallback(token) //} return errors.New(respErr.ErrorResponse.ZhDesc) } mResp := map[string]resp{} json.Unmarshal(bytes, &mResp) for _, val := range mResp { if val.Result.ErrCode != 200 { return errors.New(val.Result.ErrMsg) } if val.Result.Data != nil { err = mapstructure.Decode(val.Result.Data, &result) } if val.Result.StockStateList != nil { err = mapstructure.Decode(val.Result.StockStateList, &result) } return nil } return errors.New("接口请求错误") } // ExecProtocol @Title 调用接口 func ExecProtocol(action string, data interface{}, result interface{}) error { requestData := map[string]interface{}{ "protocol": ctpProtocol{ AppKey: config.SdkConfig.AppKey, ChannelId: config.SdkConfig.ChannelId, CustomerId: config.SdkConfig.CustomerId, OpName: config.SdkConfig.OpName, TraceId: "", }, getStructName(data): data, } jsonData, _ := json.Marshal(&requestData) return exec(action, string(jsonData), result) } // ExecCtlProtocol @Title 调用接口 func ExecCtlProtocol(action string, data interface{}, result interface{}) error { requestData := map[string]interface{}{ "ctpProtocol": ctpProtocol{ AppKey: config.SdkConfig.AppKey, ChannelId: config.SdkConfig.ChannelId, CustomerId: config.SdkConfig.CustomerId, OpName: config.SdkConfig.OpName, TraceId: "", }, getStructName(data): data, } jsonData, _ := json.Marshal(&requestData) return exec(action, string(jsonData), result) } // ExecParam @Title 调用接口 func ExecParam(action string, data map[string]interface{}, result interface{}) error { requestData := map[string]interface{}{ "appKey": config.SdkConfig.AppKey, "channelId": config.SdkConfig.ChannelId, "customerId": config.SdkConfig.CustomerId, "traceId": "", "pin": config.SdkConfig.Pin, "clientIp": "127.0.0.1", } for key, item := range data { requestData[key] = item } jsonData, _ := json.Marshal(&requestData) return exec(action, string(jsonData), result) } type mqResult struct { RequestId string `json:"requestId"` Result Message `json:"result"` Error resError `json:"error"` } type Message struct { TopicName string `json:"topicName"` AckIndex string `json:"ackIndex"` Messages []MessageItem `json:"messages"` Action string `json:"action"` } type MessageItem struct { MessageId string `json:"messageId"` MessageBody string `json:"messageBody"` } type resError struct { Code int `json:"code"` Message string `json:"message"` Status string `json:"status"` } const ( AckActionSuccess = "SUCCESS" // 消费成功 AckActionFailed = "CONSUME_FAILED" // 消费失败,服务端会进行重新推送 AckActionResend = "RESEND" // 立即重发 AckActionDiscard = "DISCARD" // 丢弃消息,服务端不会进行重试 ) // Success @Title 消费成功 func (m *Message) Success() error { return m.ack(AckActionSuccess) } // Failed @Title 消费失败,服务端会进行重新推送 func (m *Message) Failed() error { return m.ack(AckActionFailed) } // Resend @Title 立即重发 func (m *Message) Resend() error { return m.ack(AckActionResend) } // Discard @Title 丢弃消息,服务端不会进行重试 func (m *Message) Discard() error { return m.ack(AckActionDiscard) } // Ack @Title 确认消息 func (m *Message) ack(ackAction string) error { dateTime := time.Now().UTC().Format("2006-01-02T15:04:05Z") data := map[string]string{ "topic": m.TopicName, "consumerGroupId": fmt.Sprintf("open_message_%d", config.SdkConfig.AccountId), "ackAction": ackAction, "ackIndex": m.AckIndex, "accessKey": config.SdkConfig.AccessKey, "dateTime": dateTime, } sign := MqSign(data) jsonData, _ := json.Marshal(&data) bytes, err := request(post, config.SdkConfig.MqUrl+"/ack", string(jsonData), map[string]string{ "accessKey": config.SdkConfig.AccessKey, "dateTime": dateTime, "signature": sign, "Content-Type": "application/json", }) if err != nil { return err } res := mqResult{} if err := json.Unmarshal(bytes, &res); err != nil { return err } if res.Error.Code > 0 { return errors.New(res.Error.Message) } return nil } // ExecMq @Title 调用mq func ExecMq(action string) (Message, error) { data := map[string]string{ "topic": fmt.Sprintf("%sopen_message_ct_%s_%s", config.SdkConfig.TopicPrefix, action, config.SdkConfig.AppKey), "consumerGroupId": fmt.Sprintf("open_message_%d", config.SdkConfig.AccountId), } value := url.Values{} for k, v := range data { value.Set(k, v) } dateTime := time.Now().UTC().Format("2006-01-02T15:04:05Z") data["accessKey"] = config.SdkConfig.AccessKey data["dateTime"] = dateTime sign := MqSign(data) bytes, err := request(get, config.SdkConfig.MqUrl+"/messages?"+value.Encode(), "", map[string]string{ "accessKey": config.SdkConfig.AccessKey, "dateTime": dateTime, "signature": sign, }) if err != nil { return Message{}, err } res := mqResult{} if err := json.Unmarshal(bytes, &res); err != nil { return Message{}, err } res.Result.Action = action if res.Error.Code > 0 { return res.Result, errors.New(res.Error.Message) } return res.Result, err } func map2str(data map[string]string, sep string) string { var temp []string for key, _ := range data { temp = append(temp, key) } sort.Strings(temp) var tt []string for _, v := range temp { tt = append(tt, fmt.Sprintf("%s=%s", v, data[v])) } return strings.Join(tt, sep) } // MqSign @Title mq签名 func MqSign(data map[string]string) string { h := hmac.New(sha1.New, []byte(config.SdkConfig.SecretKey)) str := map2str(data, "&") h.Write([]byte(str)) return base64.StdEncoding.EncodeToString(h.Sum(nil)) } // RefreshToken @Title 刷新token func RefreshToken() (*config.Bearer, error) { value := url.Values{} value.Set("app_key", config.SdkConfig.AppKey) value.Set("app_secret", config.SdkConfig.AppSecret) value.Set("refresh_token", config.SdkConfig.RefreshToken) value.Set("grant_type", "refresh_token") data, err := request(get, fmt.Sprintf("%s?%s", config.SdkConfig.TokenUrl, value.Encode()), "") if err != nil { return nil, err } log.Println(string(data)) var b config.Bearer if err = json.Unmarshal(data, &b); err != nil { return nil, err } return &b, nil } // Sign @Title 签名 func Sign(params url.Values) string { h := md5.New() var order []string for key, _ := range params { order = append(order, key) } sort.Strings(order) h.Write([]byte(config.SdkConfig.AppSecret)) for _, value := range order { h.Write([]byte(fmt.Sprintf("%s%s", value, params.Get(value)))) } h.Write([]byte(config.SdkConfig.AppSecret)) return strings.ToUpper(hex.EncodeToString(h.Sum(nil))) } // 字符串首字母小写 func getStructName(obj interface{}) string { s := reflect.TypeOf(obj).Name() if s == "" { return "" } return strings.ToLower(s[:1]) + s[1:] }