You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
jdsdk/request/client.go

326 lines
8.6 KiB

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("open_message_ct_%s_%s", 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:]
}