|
|
|
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:]
|
|
|
|
}
|