|
|
|
|
package base
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
"mime/multipart"
|
|
|
|
|
"net/http"
|
|
|
|
|
"net/url"
|
|
|
|
|
"reflect"
|
|
|
|
|
"server/modules/pay/values"
|
|
|
|
|
"server/pb"
|
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
|
"github.com/gogo/protobuf/proto"
|
|
|
|
|
"github.com/liangdas/mqant/log"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type HttpType int
|
|
|
|
|
type OPTType int
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
HttpTypeInvalid HttpType = iota
|
|
|
|
|
HttpTypeJson
|
|
|
|
|
HttpTypeForm
|
|
|
|
|
HttpTypeMultiPartForm
|
|
|
|
|
HttpTypeGet // get请求
|
|
|
|
|
HttpTypeAll
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
OPTPay OPTType = iota + 1
|
|
|
|
|
OPTWithdraw
|
|
|
|
|
OPTPayCB
|
|
|
|
|
OPTWithdrawCB
|
|
|
|
|
OPTQueryWithdraw
|
|
|
|
|
OPTQueryPay
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
QueryStatusFail = iota + 1 // 查询到订单失败了或者提交失败
|
|
|
|
|
QueryStatusSuccess // 查询到订单提交成功
|
|
|
|
|
QueryStatusUnknown // 查询失败,状态未知,需要重新查询
|
|
|
|
|
QueryStatusOrderSuccess // 查询到订单支付成功
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type QueryReq struct {
|
|
|
|
|
Channel int
|
|
|
|
|
OrderID string
|
|
|
|
|
APIOrderID string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Base struct {
|
|
|
|
|
Channel values.PayWay
|
|
|
|
|
PayReq *pb.InnerRechargeReq
|
|
|
|
|
WithdrawReq *pb.InnerWithdrawReq
|
|
|
|
|
SignKey string
|
|
|
|
|
ShouldSignUpper bool
|
|
|
|
|
HttpType HttpType
|
|
|
|
|
ReqURL string
|
|
|
|
|
Opt OPTType // 1支付 2退出 3支付回调 4退出回调 5退出查询 6支付查询
|
|
|
|
|
Status int // 返回的状态
|
|
|
|
|
GetResp url.Values
|
|
|
|
|
Resp interface{}
|
|
|
|
|
CallbackReq interface{}
|
|
|
|
|
CallbackResp CallbackResp
|
|
|
|
|
QueryWithdrawResp QueryResp
|
|
|
|
|
QueryPayResp QueryResp
|
|
|
|
|
Sub
|
|
|
|
|
SubReq func() ([]byte, error) // 特殊处理一些非常规请求
|
|
|
|
|
SubCallbackDecode func([]byte) (string, error) // 特殊处理回调解析的方法
|
|
|
|
|
SignPassStr []string // 不参与签名的字段
|
|
|
|
|
KeyName string // 有时候有些渠道签名字段不一样
|
|
|
|
|
C *gin.Context
|
|
|
|
|
ReqData interface{}
|
|
|
|
|
|
|
|
|
|
QueryWithdrawReq *QueryReq
|
|
|
|
|
QueryPayReq *QueryReq
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type CallbackResp struct {
|
|
|
|
|
Msg string
|
|
|
|
|
OrderID string
|
|
|
|
|
APIOrderID string
|
|
|
|
|
FailMessage string
|
|
|
|
|
Success bool
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type QueryResp struct {
|
|
|
|
|
Msg string
|
|
|
|
|
OrderID string
|
|
|
|
|
APIOrderID string
|
|
|
|
|
Status int // 1成功 2失败 3处理中
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Sub interface {
|
|
|
|
|
PackHeader(header http.Header) // 生成请求头
|
|
|
|
|
PackReq() interface{} // 生成支付请求体
|
|
|
|
|
GetResp() (proto.Message, error) // 获取返回
|
|
|
|
|
CheckSign(str string) bool // 验签同时给callbackresp赋值
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewRechargeBase(req *pb.InnerRechargeReq) *Base {
|
|
|
|
|
values.PackPay(req)
|
|
|
|
|
base := &Base{
|
|
|
|
|
Channel: values.PayWay(req.Channel),
|
|
|
|
|
PayReq: req,
|
|
|
|
|
Opt: OPTPay,
|
|
|
|
|
SignPassStr: []string{"sign"},
|
|
|
|
|
}
|
|
|
|
|
return base
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewWithdrawBase(req *pb.InnerWithdrawReq) *Base {
|
|
|
|
|
values.PackWithdraw(req)
|
|
|
|
|
base := &Base{
|
|
|
|
|
Channel: values.PayWay(req.Channel),
|
|
|
|
|
WithdrawReq: req,
|
|
|
|
|
Opt: OPTWithdraw,
|
|
|
|
|
}
|
|
|
|
|
return base
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewQueryWithdrawBase(req *pb.InnerWithdrawReq) *Base {
|
|
|
|
|
base := &Base{
|
|
|
|
|
Channel: values.PayWay(req.Channel),
|
|
|
|
|
WithdrawReq: req,
|
|
|
|
|
Opt: OPTQueryWithdraw,
|
|
|
|
|
}
|
|
|
|
|
return base
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewQueryPayBase(req *pb.InnerWithdrawReq) *Base {
|
|
|
|
|
base := &Base{
|
|
|
|
|
Channel: values.PayWay(req.Channel),
|
|
|
|
|
WithdrawReq: req,
|
|
|
|
|
Opt: OPTQueryPay,
|
|
|
|
|
}
|
|
|
|
|
return base
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewCallbackBase(opt OPTType) *Base {
|
|
|
|
|
base := &Base{
|
|
|
|
|
Opt: opt,
|
|
|
|
|
}
|
|
|
|
|
return base
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (b *Base) PackHeader(header http.Header) {
|
|
|
|
|
switch b.HttpType {
|
|
|
|
|
case HttpTypeJson:
|
|
|
|
|
header.Set("Content-Type", "application/json")
|
|
|
|
|
case HttpTypeForm:
|
|
|
|
|
header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
|
|
|
}
|
|
|
|
|
b.Sub.PackHeader(header)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (b *Base) Req() ([]byte, error) {
|
|
|
|
|
if b.SubReq != nil {
|
|
|
|
|
return b.SubReq()
|
|
|
|
|
}
|
|
|
|
|
send := b.Sub.PackReq()
|
|
|
|
|
if send == nil {
|
|
|
|
|
return nil, errors.New("pay fail")
|
|
|
|
|
}
|
|
|
|
|
var req *http.Request
|
|
|
|
|
var err error
|
|
|
|
|
if b.HttpType == HttpTypeGet {
|
|
|
|
|
req, _ = http.NewRequest("GET", b.ReqURL, nil)
|
|
|
|
|
} else {
|
|
|
|
|
reqData := b.PackReq(send)
|
|
|
|
|
req, err = http.NewRequest("POST", b.ReqURL, reqData)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Error("err:%v", err)
|
|
|
|
|
return nil, errors.New("pay fail")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
b.PackHeader(req.Header)
|
|
|
|
|
b.Status = Request(req, b.Resp)
|
|
|
|
|
ret, err := b.Sub.GetResp()
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Error("err:%v", err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
data, _ := proto.Marshal(ret)
|
|
|
|
|
return data, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (b *Base) PackReq(send interface{}) io.Reader {
|
|
|
|
|
ref := reflect.ValueOf(send)
|
|
|
|
|
reft := reflect.TypeOf(send)
|
|
|
|
|
if ref.Kind() == reflect.Ptr {
|
|
|
|
|
ref = ref.Elem()
|
|
|
|
|
reft = reft.Elem()
|
|
|
|
|
}
|
|
|
|
|
switch b.HttpType {
|
|
|
|
|
case HttpTypeJson:
|
|
|
|
|
reqData, _ := json.Marshal(send)
|
|
|
|
|
log.Debug("post to:%v,req:%v", b.ReqURL, string(reqData))
|
|
|
|
|
return bytes.NewBuffer(reqData)
|
|
|
|
|
case HttpTypeForm:
|
|
|
|
|
data := url.Values{}
|
|
|
|
|
for i := 0; i < ref.NumField(); i++ {
|
|
|
|
|
if ref.Field(i).IsZero() {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
data.Set(reft.Field(i).Tag.Get("json"), fmt.Sprintf("%v", ref.Field(i).Interface()))
|
|
|
|
|
}
|
|
|
|
|
str := data.Encode()
|
|
|
|
|
log.Debug("post to:%v,req:%v", b.ReqURL, str)
|
|
|
|
|
return strings.NewReader(str)
|
|
|
|
|
case HttpTypeMultiPartForm:
|
|
|
|
|
data := &bytes.Buffer{}
|
|
|
|
|
writer := multipart.NewWriter(data)
|
|
|
|
|
for i := 0; i < ref.NumField(); i++ {
|
|
|
|
|
if ref.Field(i).IsZero() {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
writer.WriteField(reft.Field(i).Tag.Get("json"), fmt.Sprintf("%v", ref.Field(i).Interface()))
|
|
|
|
|
}
|
|
|
|
|
log.Debug("post to:%v,req:%v", b.ReqURL, data.String())
|
|
|
|
|
return data
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (b *Base) GetPayCallbackURL() string {
|
|
|
|
|
return values.GetPayCallback(b.Channel)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (b *Base) GetWithdrawCallbackURL() string {
|
|
|
|
|
return values.GetWithdrawCallback(b.Channel)
|
|
|
|
|
}
|