296 lines
9.2 KiB
Go
296 lines
9.2 KiB
Go
package udunhelper
|
|
|
|
import (
|
|
"crypto/md5"
|
|
"crypto/tls"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
log "github.com/go-admin-team/go-admin-core/logger"
|
|
ext "go-admin/config"
|
|
"go-admin/pkg/jsonhelper"
|
|
"go-admin/pkg/utility/seqs"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
const (
|
|
createAddressUrl = "/mch/address/create"
|
|
withdrawUrl = "/mch/withdraw"
|
|
checkAddressUrl = "/mch/check/address"
|
|
supportCoinsUrl = "/mch/support-coins"
|
|
existAddressUrl = "/mch/exist/address"
|
|
|
|
Notify = "/api/v1/line/notify"
|
|
)
|
|
|
|
var (
|
|
clientUDun *http.Client
|
|
)
|
|
|
|
func init() {
|
|
t := http.DefaultTransport.(*http.Transport).Clone()
|
|
t.MaxIdleConns = 100
|
|
t.MaxConnsPerHost = 10000
|
|
t.MaxIdleConnsPerHost = 100
|
|
t.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
|
|
|
//u盾client
|
|
clientUDun = &http.Client{
|
|
Timeout: 50 * time.Second, //time.Duration(timeout) * time.Second,
|
|
Transport: t,
|
|
}
|
|
//UdKey = config.AppGlobalConfig.UDunKey // "d333ae13beb3a96c0225847098267cf3"
|
|
//UdMerchantId = config.AppGlobalConfig.UDunMerchantID // "311129"
|
|
//CallUrl = config.AppGlobalConfig.CurrServerIp + "/api/recharge/notify" // "https://8.218.110.85/api/recharge/notify" // 回调地址
|
|
//baseUrl = config.AppGlobalConfig.UDunUrl //"https://sig10.udun.io"
|
|
}
|
|
|
|
/* 回调例子
|
|
"timestamp": 1535005047,
|
|
"nonce": 100000,
|
|
"sign": "e1bee3a417b9c606ba6cedda26db761a",
|
|
"body": "{\"address\":\"DJY781Z8qbuJeuA7C3McYivbX8kmAUXPsW\",\"amount\":\"12345678\",\"blockHigh\":\"102419\",\"coinType\":\"206\",\"decimals\":\"8\",\"fee\":\"452000\",
|
|
\"mainCoinType\":\"206\",\"status\":3,\"tradeId\":\"20181024175416907\",\"tradeType\":1,\"txId\":\"31689c332536b56a2246347e206fbed2d04d461a3d668c4c1de32a75a8d436f0\"}"
|
|
*/
|
|
|
|
// GetSupportCoinsByMerchant 获取商家支持币种
|
|
func GetSupportCoinsByMerchant(baseReq BaseRequest, showBalance bool) BaseCoinsMerchant {
|
|
mp := make(map[string]interface{}, 0)
|
|
//mp["merchantId"] = config.AppGlobalConfig.UDunMerchantID
|
|
mp["merchantId"] = ext.ExtConfig.UDunConfig.UDunMerchantID
|
|
mp["showBalance"] = showBalance
|
|
reqBody, _ := json.Marshal(mp)
|
|
sign := Signature(baseReq.Nonce, baseReq.Timestamp, string(reqBody))
|
|
url := fmt.Sprintf("%v%v", ext.ExtConfig.UDunConfig.UDunUrl, supportCoinsUrl)
|
|
re, err := sendRequestUDun(url, baseReq.Nonce, baseReq.Timestamp, string(reqBody), sign)
|
|
if err != nil {
|
|
log.Error("GetSupportCoinsByMerchant", zap.Error(err))
|
|
return BaseCoinsMerchant{}
|
|
}
|
|
|
|
var res BaseCoinsMerchant
|
|
err = jsonhelper.Unmarshal(re, &res)
|
|
if err != nil {
|
|
return BaseCoinsMerchant{}
|
|
}
|
|
return res
|
|
}
|
|
|
|
// CreateAddress 创建地址
|
|
func CreateAddress(baseReq BaseRequest, callback []*CallbackRequest) BaseCoinAddress {
|
|
for _, c := range callback {
|
|
c.MerchantId = ext.ExtConfig.UDunConfig.UDunMerchantID
|
|
c.CallUrl = ext.ExtConfig.UDunConfig.CurrServerIp + Notify // "/api/recharge/notify"
|
|
}
|
|
reqBody, _ := json.Marshal(callback)
|
|
sign := Signature(baseReq.Nonce, baseReq.Timestamp, string(reqBody))
|
|
url := fmt.Sprintf("%v%v", ext.ExtConfig.UDunConfig.UDunUrl, createAddressUrl)
|
|
re, err := sendRequestUDun(url, baseReq.Nonce, baseReq.Timestamp, string(reqBody), sign)
|
|
if err != nil {
|
|
log.Error("CreateAddress", zap.Error(err), zap.String("url", url))
|
|
return BaseCoinAddress{}
|
|
}
|
|
var res BaseCoinAddress
|
|
err = jsonhelper.Unmarshal(re, &res)
|
|
if err != nil {
|
|
log.Error("CreateAddress Unmarshal", zap.Error(err))
|
|
return BaseCoinAddress{}
|
|
}
|
|
return res
|
|
}
|
|
|
|
// Withdraw 提现
|
|
func Withdraw(withdraw []*WithdrawRequest) (code int, msg string) {
|
|
timeStamp := time.Now().Unix()
|
|
nonce := seqs.Rand().RandInt(600000)
|
|
// 序列化
|
|
reqBody, _ := json.Marshal(withdraw)
|
|
// 签名
|
|
sign := Signature(nonce, timeStamp, string(reqBody))
|
|
url := fmt.Sprintf("%v%v", ext.ExtConfig.UDunConfig.UDunUrl, withdrawUrl)
|
|
// 提交
|
|
re, err := sendRequestUDun(url, nonce, timeStamp, string(reqBody), sign)
|
|
if err != nil {
|
|
log.Error("Withdraw", zap.Error(err))
|
|
return 0, "调用失败"
|
|
}
|
|
// 反序列化
|
|
var res BaseRes
|
|
if err := jsonhelper.Unmarshal(re, &res); err != nil {
|
|
return 0, "Withdraw jsonhelper.Unmarshal失败"
|
|
}
|
|
return res.Code, getWithDrawMsg(res.Code) //res.Message
|
|
}
|
|
|
|
// CheckAddress 检查地址是否正确
|
|
func CheckAddress(baseReq BaseRequest, verify []*VerifyRequest) (code int, msg string) {
|
|
reqBody, _ := json.Marshal(verify)
|
|
sign := Signature(baseReq.Nonce, baseReq.Timestamp, string(reqBody))
|
|
url := fmt.Sprintf("%v%v", ext.ExtConfig.UDunConfig.UDunUrl, checkAddressUrl)
|
|
re, err := sendRequestUDun(url, baseReq.Nonce, baseReq.Timestamp, string(reqBody), sign)
|
|
if err != nil {
|
|
log.Error("CheckAddress", zap.Error(err))
|
|
return 0, "调用失败"
|
|
}
|
|
var res BaseRes
|
|
err = jsonhelper.Unmarshal(re, &res)
|
|
if err != nil {
|
|
return 0, "jsonhelper.Unmarshal失败"
|
|
}
|
|
return res.Code, res.Message
|
|
}
|
|
|
|
// ExistAddress 检查地址是否在udun存在
|
|
func ExistAddress(baseReq BaseRequest, verify []*VerifyRequest) (code int, msg string) {
|
|
reqBody, _ := json.Marshal(verify)
|
|
sign := Signature(baseReq.Nonce, baseReq.Timestamp, string(reqBody))
|
|
url := fmt.Sprintf("%v%v", ext.ExtConfig.UDunConfig.UDunUrl, existAddressUrl)
|
|
re, err := sendRequestUDun(url, baseReq.Nonce, baseReq.Timestamp, string(reqBody), sign)
|
|
if err != nil {
|
|
log.Error("ExistAddress", zap.Error(err))
|
|
return 0, "调用失败"
|
|
}
|
|
var res BaseRes
|
|
err = jsonhelper.Unmarshal(re, &res)
|
|
if err != nil {
|
|
return 0, "jsonhelper.Unmarshal失败"
|
|
}
|
|
return res.Code, res.Message
|
|
}
|
|
|
|
func Signature(nonce int, timestamp int64, body string) string {
|
|
msg := fmt.Sprintf("%v%v%v%v", body, ext.ExtConfig.UDunConfig.UDunKey, nonce, timestamp)
|
|
h := md5.New()
|
|
h.Write([]byte(msg))
|
|
return hex.EncodeToString(h.Sum(nil))
|
|
}
|
|
|
|
func CheckCallBackSign(timestamp string, nonce string, body string) string {
|
|
raw := body + ext.ExtConfig.UDunConfig.UDunKey + nonce + timestamp
|
|
h := md5.New()
|
|
h.Write([]byte(raw))
|
|
return hex.EncodeToString(h.Sum(nil))
|
|
}
|
|
|
|
func sendRequestUDun(url string, nonce int, timestamp int64, reqBody string, sign string) ([]byte, error) {
|
|
q := HttpRequest{Nonce: nonce, Timestamp: timestamp, Sign: sign, Body: reqBody}
|
|
body, _ := json.Marshal(q)
|
|
headers := map[string]string{}
|
|
headers["Content-Type"] = "application/json"
|
|
resp, err := newHttpRequest(url, string(body), headers)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
func newHttpRequest(reqUrl, postData string, reqHeaders map[string]string) ([]byte, error) {
|
|
req, _ := http.NewRequest("POST", reqUrl, strings.NewReader(postData))
|
|
if req.Header.Get("User-Agent") == "" {
|
|
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36")
|
|
}
|
|
if reqHeaders != nil {
|
|
for k, v := range reqHeaders {
|
|
req.Header.Add(k, v)
|
|
}
|
|
}
|
|
|
|
resp, err := clientUDun.Do(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
bodyData, err := io.ReadAll(resp.Body) // ioutil.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
arr := make([]byte, len(bodyData))
|
|
copy(arr, bodyData)
|
|
|
|
if resp.StatusCode != 200 {
|
|
return nil, errors.New(string(arr))
|
|
}
|
|
|
|
return arr, nil
|
|
}
|
|
|
|
/*
|
|
createAddressUrl 创建地址 接口返回code说明
|
|
-1 生成地址失敗
|
|
200 生成地址成功
|
|
4001 商户不存在
|
|
4005 非法參數
|
|
4045 幣種信息錯誤
|
|
4162 簽名異常
|
|
4163 簽名錯誤
|
|
4166 商戶沒有配置套餐
|
|
4168 商戶地址達到上限
|
|
4169 商戶已禁用
|
|
4175 錢包編號錯誤
|
|
4017 商戶沒有創建錢包
|
|
4176 錢包未添加支持該幣種
|
|
4188 暫不支持
|
|
4226 商戶普通賬戶被禁用
|
|
4261 商戶管理員賬戶被禁用
|
|
4262 賬戶不存在
|
|
|
|
withdrawUrl 提币 接口返回code说明
|
|
200 提幣成功
|
|
523 參數為空
|
|
581 無效的提幣金額
|
|
4005 非法參數
|
|
4014 幣種為空
|
|
4034 未找到該幣種信息
|
|
4162 簽名異常
|
|
4163 簽名錯誤
|
|
4169 商戶已被禁用
|
|
4183 到賬地址異常
|
|
4193 EOS金額小數點後超過4位長度
|
|
4214 暫無可用的幣種
|
|
4226 商戶普通賬戶被禁用
|
|
4261 商戶管理員賬戶被禁用
|
|
4284 商户不存在
|
|
4288 業務編號(BusinessId)重復,請勿重復申請
|
|
4598 傳入body中的list對象中的所有merchantId必須保持一致
|
|
4001 商户不存在
|
|
*/
|
|
|
|
//分充值回調和提幣回調, 其中提幣最多會進行兩次回調( 審核回調 + 交易結果回調)
|
|
|
|
//func SendRequest(url string, nonce int, timestamp int64, reqBody string, sign string) (code int64, msg string, extra string) {
|
|
// q := HttpRequest{Nonce: nonce, Timestamp: timestamp, Sign: sign, Body: reqBody}
|
|
// body, _ := json.Marshal(q)
|
|
// resp, err := clientUDun.Post(url, "application/json", bytes.NewBuffer(body))
|
|
// if err != nil {
|
|
// return http.StatusBadRequest, err.Error(), ""
|
|
// }
|
|
// defer resp.Body.Close()
|
|
// r, err := ioutil.ReadAll(resp.Body)
|
|
// if err != nil {
|
|
// return http.StatusBadGateway, err.Error(), ""
|
|
// }
|
|
//
|
|
// js := gjson.ParseBytes(r)
|
|
// code = js.Get("code").Int()
|
|
// msg = js.Get("message").String()
|
|
// if js.Get("data").Exists() {
|
|
// extra = js.Get("data").String()
|
|
// }
|
|
// return
|
|
//}
|
|
|
|
// CallBackFun 網關收到交易處理結果,調用商戶提供的回調接口,通知商戶具體變化信息。該接口網關發送給您指定的回調地址的內容,處理您的業務信息。
|
|
// 分充值回調和提幣回調, 其中提幣最多會進行兩次回調( 審核回調 + 交易結果回調)
|
|
func CallBackFun(res CallBackBase) {
|
|
|
|
}
|