低空智控平台 后端go
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.
 
 

101 lines
2.9 KiB

package handler
import (
"bytes"
"encoding/json"
"fmt"
"io"
"mime"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"laic-backend/common"
"laic-backend/logger"
"laic-backend/model"
"laic-backend/service"
"laic-backend/vo"
)
const maxAGPayCallbackBodyBytes = 64 * 1024
func CreateWechatPayment(c *gin.Context) {
var req vo.PaymentCreateReq
if err := c.ShouldBindJSON(&req); err != nil {
common.FailWithBindError(c, common.ErrParam, err)
return
}
data, e := service.DefaultPaymentService.CreateWechatPayment(common.GetUserId(c), &req)
if e != nil {
common.FailWithBusiError(c, e)
return
}
common.OKWithData(c, data)
}
func GetPaymentTransaction(c *gin.Context) {
id, e := parseID(c)
if e != nil {
common.FailWithBusiError(c, e)
return
}
data, e := service.DefaultPaymentService.GetTransaction(common.GetUserId(c), id)
if e != nil {
common.FailWithBusiError(c, e)
return
}
common.OKWithData(c, data)
}
func AGPayCallback(c *gin.Context) {
c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, maxAGPayCallbackBodyBytes)
body, err := c.GetRawData()
if err != nil {
logger.WARN("拒绝 AGPay 支付回调", "stage", "read_body", "error", err)
c.Status(http.StatusBadRequest)
return
}
callback, err := parseAGPayCallback(c.GetHeader("Content-Type"), body)
if err != nil {
logger.WARN("拒绝 AGPay 支付回调", "stage", "parse", "contentType", c.GetHeader("Content-Type"), "bodyBytes", len(body), "error", err)
c.Status(http.StatusBadRequest)
return
}
if err := service.DefaultPaymentService.ConfirmAGPayCallback(callback.TradeNo, body); err != nil {
logger.WARN("拒绝 AGPay 支付回调", "stage", "confirm", "tradeNo", callback.TradeNo, "code", err.Code, "error", err)
if err == common.ErrInternal {
c.Status(http.StatusInternalServerError)
return
}
c.Status(http.StatusBadRequest)
return
}
c.JSON(http.StatusOK, gin.H{"code": "SUCCESS"})
}
func parseAGPayCallback(contentType string, body []byte) (model.AGPayCallback, error) {
var callback model.AGPayCallback
mediaType, _, err := mime.ParseMediaType(contentType)
if err != nil || (mediaType != "application/json" && !strings.HasSuffix(mediaType, "+json")) {
return callback, fmt.Errorf("unsupported content type %q", contentType)
}
decoder := json.NewDecoder(bytes.NewReader(body))
// Gateways commonly add payment amount, provider transaction ID, and
// signature fields. Only the merchant trade number is needed here; reject
// malformed payloads, but do not reject otherwise valid gateway metadata.
if err := decoder.Decode(&callback); err != nil {
return callback, err
}
if err := decoder.Decode(&struct{}{}); err != io.EOF {
if err == nil {
return callback, fmt.Errorf("multiple JSON values")
}
return callback, err
}
callback.TradeNo = strings.TrimSpace(callback.TradeNo)
if callback.TradeNo == "" || len(callback.TradeNo) > 128 {
return callback, fmt.Errorf("invalid tradeNo")
}
return callback, nil
}