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) {
 | 
						|
 | 
						|
}
 |