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