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.
237 lines
5.4 KiB
237 lines
5.4 KiB
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) |
|
}
|
|
|