重构代码结构与认证体系,集成异步任务消费者
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package globals
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"platform/pkg/env"
|
||||
|
||||
"github.com/smartwalle/alipay/v3"
|
||||
@@ -8,25 +9,26 @@ import (
|
||||
|
||||
var Alipay *alipay.Client
|
||||
|
||||
func initAlipay() {
|
||||
func initAlipay() error {
|
||||
var client, err = alipay.New(
|
||||
env.AlipayAppId,
|
||||
env.AlipayAppPrivateKey,
|
||||
env.AlipayProduction,
|
||||
)
|
||||
if err != nil {
|
||||
panic("初始化支付宝客户端失败: " + err.Error())
|
||||
return fmt.Errorf("初始化支付宝客户端失败: %w", err)
|
||||
}
|
||||
|
||||
err = client.LoadAliPayPublicKey(env.AlipayPublicKey)
|
||||
if err != nil {
|
||||
panic("加载支付宝公钥失败: " + err.Error())
|
||||
return fmt.Errorf("加载支付宝公钥失败: %w", err)
|
||||
}
|
||||
|
||||
err = client.SetEncryptKey(env.AlipayApiCert)
|
||||
if err != nil {
|
||||
panic("设置支付宝加密密钥失败: " + err.Error())
|
||||
return fmt.Errorf("设置支付宝加密证书失败: %w", err)
|
||||
}
|
||||
|
||||
Alipay = client
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package globals
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"platform/pkg/env"
|
||||
"platform/pkg/u"
|
||||
|
||||
@@ -14,17 +15,18 @@ type aliyunClient struct {
|
||||
Sms *sms.Client
|
||||
}
|
||||
|
||||
func initAliyun() {
|
||||
func initAliyun() error {
|
||||
client, err := sms.NewClient(&openapi.Config{
|
||||
AccessKeyId: &env.AliyunAccessKey,
|
||||
AccessKeySecret: &env.AliyunAccessKeySecret,
|
||||
Endpoint: u.P("dysmsapi.aliyuncs.com"),
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return fmt.Errorf("初始化阿里云客户端失败: %w", err)
|
||||
}
|
||||
|
||||
Aliyun = &aliyunClient{
|
||||
Sms: client,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -35,10 +35,11 @@ type cloud struct {
|
||||
|
||||
var Cloud CloudClient
|
||||
|
||||
func initBaiyin() {
|
||||
func initBaiyin() error {
|
||||
Cloud = &cloud{
|
||||
url: env.BaiyinAddr,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type AutoConfig struct {
|
||||
|
||||
@@ -1,14 +1,38 @@
|
||||
package globals
|
||||
|
||||
func Init() {
|
||||
initBaiyin()
|
||||
initAlipay()
|
||||
initWechatPay()
|
||||
initAliyun()
|
||||
initValidator()
|
||||
initRedis()
|
||||
initOrm()
|
||||
initProxy()
|
||||
initAsynq()
|
||||
initSft()
|
||||
import (
|
||||
"context"
|
||||
"platform/pkg/u"
|
||||
)
|
||||
|
||||
func Init(ctx context.Context) error {
|
||||
errs := make([]error, 0)
|
||||
|
||||
errs = append(errs, initBaiyin())
|
||||
errs = append(errs, initAlipay())
|
||||
errs = append(errs, initWechatPay())
|
||||
errs = append(errs, initAliyun())
|
||||
errs = append(errs, initValidator())
|
||||
errs = append(errs, initRedis())
|
||||
errs = append(errs, initOrm())
|
||||
errs = append(errs, initProxy())
|
||||
errs = append(errs, initSft())
|
||||
|
||||
return u.CombineErrors(errs)
|
||||
}
|
||||
|
||||
func Stop() error {
|
||||
var errs = make([]error, 0)
|
||||
|
||||
err := stopRedis()
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
err = stopOrm()
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
return u.CombineErrors(errs)
|
||||
}
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
package globals
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"platform/pkg/env"
|
||||
"platform/web/queries"
|
||||
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/schema"
|
||||
"log/slog"
|
||||
"platform/pkg/env"
|
||||
)
|
||||
|
||||
var DB *gorm.DB
|
||||
var Conn *sql.DB
|
||||
|
||||
func initOrm() {
|
||||
func initOrm() error {
|
||||
|
||||
// 连接数据库
|
||||
dsn := fmt.Sprintf(
|
||||
@@ -25,27 +28,29 @@ func initOrm() {
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
slog.Error("gorm 初始化数据库失败:", slog.Any("err", err))
|
||||
panic(err)
|
||||
return fmt.Errorf("连接数据库失败: %w", err)
|
||||
}
|
||||
|
||||
// 连接池
|
||||
conn, err := db.DB()
|
||||
if err != nil {
|
||||
slog.Error("gorm 初始化数据库失败:", slog.Any("err", err))
|
||||
panic(err)
|
||||
return fmt.Errorf("配置连接池失败: %w", err)
|
||||
}
|
||||
conn.SetMaxIdleConns(10)
|
||||
conn.SetMaxOpenConns(100)
|
||||
|
||||
queries.SetDefault(db)
|
||||
DB = db
|
||||
Conn = conn
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ExitOrm() error {
|
||||
func stopOrm() error {
|
||||
if DB != nil {
|
||||
conn, err := DB.DB()
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("关闭数据库连接失败: %w", err)
|
||||
}
|
||||
return conn.Close()
|
||||
}
|
||||
|
||||
@@ -23,8 +23,9 @@ var Proxy *ProxyClient
|
||||
type ProxyClient struct {
|
||||
}
|
||||
|
||||
func initProxy() {
|
||||
func initProxy() error {
|
||||
Proxy = &ProxyClient{}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ProxyPermitConfig struct {
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package globals
|
||||
|
||||
import (
|
||||
"github.com/go-redsync/redsync/v4/redis/goredis/v9"
|
||||
"log/slog"
|
||||
"net"
|
||||
"platform/pkg/env"
|
||||
"platform/web/core"
|
||||
|
||||
"github.com/go-redsync/redsync/v4/redis/goredis/v9"
|
||||
|
||||
"github.com/go-redsync/redsync/v4"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
@@ -18,11 +19,10 @@ type ExtendRedSync struct {
|
||||
*redsync.Redsync
|
||||
}
|
||||
|
||||
func initRedis() {
|
||||
func initRedis() error {
|
||||
client := redis.NewClient(&redis.Options{
|
||||
Addr: net.JoinHostPort(env.RedisHost, env.RedisPort),
|
||||
DB: env.RedisDb,
|
||||
Password: env.RedisPass,
|
||||
Password: env.RedisPassword,
|
||||
})
|
||||
|
||||
pool := goredis.NewPool(client)
|
||||
@@ -30,9 +30,11 @@ func initRedis() {
|
||||
|
||||
Redis = client
|
||||
Redsync = &ExtendRedSync{sync}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ExitRedis() error {
|
||||
func stopRedis() error {
|
||||
if Redis != nil {
|
||||
return Redis.Close()
|
||||
}
|
||||
|
||||
@@ -28,9 +28,9 @@ type SftClient struct {
|
||||
publicKey *rsa.PublicKey
|
||||
}
|
||||
|
||||
func initSft() {
|
||||
func initSft() error {
|
||||
if !env.SftPayEnable {
|
||||
panic("商福通支付未启用,请检查环境变量 SFTPAY_ENABLE")
|
||||
return fmt.Errorf("商福通支付未启用,请检查环境变量 SFTPAY_ENABLE")
|
||||
}
|
||||
|
||||
SFTPay = SftClient{
|
||||
@@ -41,7 +41,7 @@ func initSft() {
|
||||
// 加载私钥
|
||||
private, err := base64.StdEncoding.DecodeString(env.SftPayAppPrivateKey)
|
||||
if err != nil {
|
||||
panic("解析商福通私钥失败: " + err.Error())
|
||||
return fmt.Errorf("解析商福通私钥失败: %w", err)
|
||||
}
|
||||
|
||||
var privateKey *rsa.PrivateKey
|
||||
@@ -49,13 +49,13 @@ func initSft() {
|
||||
if err != nil {
|
||||
pkcs8, err := x509.ParsePKCS8PrivateKey(private)
|
||||
if err != nil {
|
||||
panic("解析商福通私钥失败: " + err.Error())
|
||||
return fmt.Errorf("解析商福通私钥失败: %w", err)
|
||||
}
|
||||
|
||||
var ok bool
|
||||
privateKey, ok = pkcs8.(*rsa.PrivateKey)
|
||||
if !ok {
|
||||
panic("解析商福通私钥失败")
|
||||
return fmt.Errorf("解析商福通私钥失败")
|
||||
}
|
||||
}
|
||||
SFTPay.privateKey = privateKey
|
||||
@@ -63,35 +63,36 @@ func initSft() {
|
||||
// 加载公钥
|
||||
public, err := base64.StdEncoding.DecodeString(env.SftPayPublicKey)
|
||||
if err != nil {
|
||||
panic("解析商福通公钥失败: " + err.Error())
|
||||
return fmt.Errorf("解析商福通公钥失败: %w", err)
|
||||
}
|
||||
|
||||
var publicKey *rsa.PublicKey
|
||||
pkix, err := x509.ParsePKIXPublicKey(public)
|
||||
if err != nil {
|
||||
panic("解析商福通公钥失败: " + err.Error())
|
||||
return fmt.Errorf("解析商福通公钥失败: %w", err)
|
||||
}
|
||||
|
||||
var ok bool
|
||||
publicKey, ok = pkix.(*rsa.PublicKey)
|
||||
if !ok {
|
||||
panic("解析商福通公钥失败")
|
||||
return fmt.Errorf("解析商福通公钥失败")
|
||||
}
|
||||
SFTPay.publicKey = publicKey
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SftClient) PaymentScanPay(req *PaymentScanPayReq) (*PaymentScanPayResp, error) {
|
||||
const url = "https://pay.rscygroup.com/api/open/payment/scanpay"
|
||||
req.ReturnUrl = env.SftReturnUrl
|
||||
req.NotifyUrl = env.SftNotifyUrl
|
||||
req.ReturnUrl = u.X(env.SftReturnUrl)
|
||||
req.NotifyUrl = u.X(env.SftNotifyUrl)
|
||||
req.RouteNo = u.P(s.routeId)
|
||||
return call[PaymentScanPayResp](s, url, req)
|
||||
}
|
||||
|
||||
func (s *SftClient) PaymentH5Pay(req *PaymentH5PayReq) (*PaymentH5PayResp, error) {
|
||||
const url = "https://pay.rscygroup.com/api/open/payment/h5pay"
|
||||
req.ReturnUrl = env.SftReturnUrl
|
||||
req.NotifyUrl = env.SftNotifyUrl
|
||||
req.ReturnUrl = u.X(env.SftReturnUrl)
|
||||
req.NotifyUrl = u.X(env.SftNotifyUrl)
|
||||
req.RouteNo = u.P(s.routeId)
|
||||
return call[PaymentH5PayResp](s, url, req)
|
||||
}
|
||||
@@ -256,7 +257,7 @@ func call[T any](s *SftClient, url string, req any) (*T, error) {
|
||||
|
||||
encode, err := s.sign(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("加密请求内容失败:%w", err)
|
||||
return nil, fmt.Errorf("加密请求内容失败: %w", err)
|
||||
}
|
||||
|
||||
bytes, err := json.Marshal(encode)
|
||||
@@ -266,33 +267,33 @@ func call[T any](s *SftClient, url string, req any) (*T, error) {
|
||||
|
||||
request, err := http.NewRequest("POST", url, strings.NewReader(string(bytes)))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("创建请求失败:%w", err)
|
||||
return nil, fmt.Errorf("创建请求失败: %w", err)
|
||||
}
|
||||
request.Header.Set("Content-Type", "application/json")
|
||||
|
||||
if env.DebugHttpDump == true {
|
||||
reqDump, err := httputil.DumpRequest(request, true)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("请求内容转储失败:%w", err)
|
||||
return nil, fmt.Errorf("请求内容转储失败: %w", err)
|
||||
}
|
||||
println(string(reqDump) + "\n\n")
|
||||
}
|
||||
|
||||
response, err := http.DefaultClient.Do(request)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("请求失败:%w", err)
|
||||
return nil, fmt.Errorf("请求失败: %w", err)
|
||||
}
|
||||
|
||||
if env.DebugHttpDump == true {
|
||||
respDump, err := httputil.DumpResponse(response, true)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("响应内容转储失败:%w", err)
|
||||
return nil, fmt.Errorf("响应内容转储失败: %w", err)
|
||||
}
|
||||
println(string(respDump) + "\n\n")
|
||||
}
|
||||
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("请求响应失败:%d", response.StatusCode)
|
||||
return nil, fmt.Errorf("请求响应失败: %d", response.StatusCode)
|
||||
}
|
||||
defer func(body io.ReadCloser) {
|
||||
_ = body.Close()
|
||||
@@ -300,18 +301,18 @@ func call[T any](s *SftClient, url string, req any) (*T, error) {
|
||||
|
||||
body, err := io.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("读取响应内容失败:%w", err)
|
||||
return nil, fmt.Errorf("读取响应内容失败: %w", err)
|
||||
}
|
||||
|
||||
decode, err := s.verify(body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("解密响应内容失败:%w", err)
|
||||
return nil, fmt.Errorf("解密响应内容失败: %w", err)
|
||||
}
|
||||
|
||||
var resp = new(T)
|
||||
err = json.Unmarshal([]byte(decode), resp)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("响应正文解析失败:%w", err)
|
||||
return nil, fmt.Errorf("响应正文解析失败: %w", err)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
@@ -321,7 +322,7 @@ func (s *SftClient) sign(msg any) (*request, error) {
|
||||
|
||||
bytes, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("格式化加密正文失败:%w", err)
|
||||
return nil, fmt.Errorf("格式化加密正文失败: %w", err)
|
||||
}
|
||||
|
||||
if env.DebugHttpDump {
|
||||
@@ -341,7 +342,7 @@ func (s *SftClient) sign(msg any) (*request, error) {
|
||||
hashed := sha256.Sum256([]byte(body.String()))
|
||||
signature, err := rsa.SignPKCS1v15(nil, s.privateKey, crypto.SHA256, hashed[:])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("签名失败:%w", err)
|
||||
return nil, fmt.Errorf("签名失败: %w", err)
|
||||
}
|
||||
|
||||
body.Sign = base64.StdEncoding.EncodeToString(signature)
|
||||
@@ -353,11 +354,11 @@ func (s *SftClient) verify(str []byte) (string, error) {
|
||||
var resp = new(response)
|
||||
err := json.Unmarshal(str, resp)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("解析响应正文失败:%w", err)
|
||||
return "", fmt.Errorf("解析响应正文失败: %w", err)
|
||||
}
|
||||
|
||||
if resp.Code != "000000" {
|
||||
return "", fmt.Errorf("请求业务响应失败:%s", u.Z(resp.Msg))
|
||||
return "", fmt.Errorf("请求业务响应失败: %s", u.Z(resp.Msg))
|
||||
}
|
||||
|
||||
if resp.Sign == nil {
|
||||
@@ -371,13 +372,13 @@ func (s *SftClient) verify(str []byte) (string, error) {
|
||||
|
||||
ser, err := resp.String()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("格式化响应内容失败:%w", err)
|
||||
return "", fmt.Errorf("格式化响应内容失败: %w", err)
|
||||
}
|
||||
|
||||
hashed := sha256.Sum256([]byte(ser))
|
||||
err = rsa.VerifyPKCS1v15(s.publicKey, crypto.SHA256, hashed[:], sign)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("验签失败:%w", err)
|
||||
return "", fmt.Errorf("验签失败: %w", err)
|
||||
}
|
||||
|
||||
return *resp.BizData, nil
|
||||
@@ -412,7 +413,7 @@ type response struct {
|
||||
func (r response) String() (string, error) {
|
||||
if r.BizData == nil || r.Msg == nil || r.SignType == nil {
|
||||
return "", core.NewServErr(fmt.Sprintf(
|
||||
"上游数据返回有空值:BizData %v,Msg %v, SignType %v",
|
||||
"上游数据返回有空值: BizData %v,Msg %v, SignType %v",
|
||||
r.BizData == nil, r.Msg == nil, r.SignType == nil,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -2,12 +2,14 @@ package globals
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/go-playground/locales/zh"
|
||||
ut "github.com/go-playground/universal-translator"
|
||||
"github.com/go-playground/validator/v10"
|
||||
zhtrans "github.com/go-playground/validator/v10/translations/zh"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var Validator *ValidatorClient
|
||||
@@ -38,17 +40,18 @@ func (v *ValidatorClient) Validate(c *fiber.Ctx, data any) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func initValidator() {
|
||||
func initValidator() error {
|
||||
var validate = validator.New(validator.WithRequiredStructEnabled())
|
||||
|
||||
var translator = ut.New(zh.New()).GetFallback()
|
||||
err := zhtrans.RegisterDefaultTranslations(validate, translator)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return fmt.Errorf("初始化验证器失败: %w", err)
|
||||
}
|
||||
|
||||
Validator = &ValidatorClient{
|
||||
validator: validate,
|
||||
translator: translator,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package globals
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"platform/pkg/env"
|
||||
|
||||
"github.com/wechatpay-apiv3/wechatpay-go/core"
|
||||
@@ -20,28 +21,28 @@ type WechatPayClient struct {
|
||||
Notify *notify.Handler
|
||||
}
|
||||
|
||||
func initWechatPay() {
|
||||
func initWechatPay() error {
|
||||
|
||||
// 加载商户私钥
|
||||
private, err := base64.StdEncoding.DecodeString(env.WechatPayMchPrivateKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return fmt.Errorf("加载微信支付商户私钥失败: %w", err)
|
||||
}
|
||||
|
||||
appPrivateKey, err := utils.LoadPrivateKey(string(private))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return fmt.Errorf("解析微信支付商户私钥失败: %w", err)
|
||||
}
|
||||
|
||||
// 加载微信支付公钥
|
||||
public, err := base64.StdEncoding.DecodeString(env.WechatPayPublicKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return fmt.Errorf("加载微信支付公钥失败: %w", err)
|
||||
}
|
||||
|
||||
wechatPublicKey, err := utils.LoadPublicKey(string(public))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return fmt.Errorf("解析微信支付公钥失败: %w", err)
|
||||
}
|
||||
|
||||
// 创建 WechatPay 客户端
|
||||
@@ -55,7 +56,7 @@ func initWechatPay() {
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return fmt.Errorf("创建微信支付客户端失败: %w", err)
|
||||
}
|
||||
|
||||
// 创建 WechatPay 通知处理器
|
||||
@@ -64,7 +65,7 @@ func initWechatPay() {
|
||||
*wechatPublicKey,
|
||||
))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return fmt.Errorf("创建微信支付通知处理器失败: %w", err)
|
||||
}
|
||||
|
||||
// 创建 WechatPay 服务
|
||||
@@ -72,4 +73,5 @@ func initWechatPay() {
|
||||
Native: &native.NativeApiService{Client: client},
|
||||
Notify: handler,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user