优化结构
This commit is contained in:
@@ -82,7 +82,7 @@ func (a *alipayAdapter) Create(ctx context.Context, req *bizpayment.PaymentReque
|
||||
case "10003":
|
||||
status = "pending"
|
||||
default:
|
||||
return nil, fmt.Errorf("支付宝付款码支付失败: %s", firstNonEmptyAlipay(response.SubMsg, response.Msg, response.SubCode, response.Code))
|
||||
return nil, fmt.Errorf("支付宝付款码支付失败: %s", firstNonEmpty(response.SubMsg, response.Msg, response.SubCode, response.Code))
|
||||
}
|
||||
if strings.TrimSpace(response.OutTradeNo) == "" {
|
||||
return nil, errors.New("支付宝付款码支付响应缺少 out_trade_no")
|
||||
@@ -125,7 +125,7 @@ func (a *alipayAdapter) Create(ctx context.Context, req *bizpayment.PaymentReque
|
||||
}
|
||||
return &bizpayment.PaymentResult{
|
||||
Provider: bizpayment.PaymentAlipay, Status: "created", TradeNo: req.TradeNo,
|
||||
Payload: mustMarshalAlipayPayload(map[string]string{"order_string": orderString}),
|
||||
Payload: mustJSON(map[string]string{"order_string": orderString}),
|
||||
}, nil
|
||||
case "alipay.trade.page.pay":
|
||||
payURL, callErr := sdk.client.TradePagePay(ctx, bm)
|
||||
@@ -141,7 +141,7 @@ func (a *alipayAdapter) Create(ctx context.Context, req *bizpayment.PaymentReque
|
||||
}
|
||||
return &bizpayment.PaymentResult{
|
||||
Provider: bizpayment.PaymentAlipay, Status: "created", TradeNo: req.TradeNo,
|
||||
Payload: mustMarshalAlipayPayload(map[string]string{"pay_url": payURL}),
|
||||
Payload: mustJSON(map[string]string{"pay_url": payURL}),
|
||||
}, nil
|
||||
case "alipay.trade.wap.pay":
|
||||
payURL, callErr := sdk.client.TradeWapPay(ctx, bm)
|
||||
@@ -157,7 +157,7 @@ func (a *alipayAdapter) Create(ctx context.Context, req *bizpayment.PaymentReque
|
||||
}
|
||||
return &bizpayment.PaymentResult{
|
||||
Provider: bizpayment.PaymentAlipay, Status: "created", TradeNo: req.TradeNo,
|
||||
Payload: mustMarshalAlipayPayload(map[string]string{"pay_url": payURL}),
|
||||
Payload: mustJSON(map[string]string{"pay_url": payURL}),
|
||||
}, nil
|
||||
default:
|
||||
rsp, callErr := sdk.client.TradeCreate(ctx, bm)
|
||||
@@ -214,7 +214,7 @@ func (a *alipayAdapter) Query(ctx context.Context, tradeNo string, c map[string]
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("解析支付宝订单金额: %w", err)
|
||||
}
|
||||
result.Currency = strings.ToUpper(firstNonEmptyAlipay(response.TransCurrency, response.PayCurrency))
|
||||
result.Currency = strings.ToUpper(firstNonEmpty(response.TransCurrency, response.PayCurrency))
|
||||
if result.Currency == "" {
|
||||
result.Currency = "CNY"
|
||||
}
|
||||
@@ -383,7 +383,7 @@ func (c *alipayClient) payload(fallback any) []byte {
|
||||
if c.response.Len() > 0 {
|
||||
return append([]byte(nil), c.response.Bytes()...)
|
||||
}
|
||||
return mustMarshalAlipayPayload(fallback)
|
||||
return mustJSON(fallback)
|
||||
}
|
||||
|
||||
func (c *alipayClient) rewriteGeneratedURL(value string) (string, error) {
|
||||
@@ -466,20 +466,6 @@ func alipayResponseValues(value any) (map[string]any, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func mustMarshalAlipayPayload(value any) []byte {
|
||||
raw, _ := json.Marshal(value)
|
||||
return raw
|
||||
}
|
||||
|
||||
func firstNonEmptyAlipay(values ...string) string {
|
||||
for _, value := range values {
|
||||
if value = strings.TrimSpace(value); value != "" {
|
||||
return value
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func populateAlipayBreakdown(result *bizpayment.PaymentResult, response map[string]any) error {
|
||||
if result == nil || result.Status != "success" {
|
||||
return nil
|
||||
|
||||
@@ -688,15 +688,6 @@ func paypalNestedMapString(values map[string]any, keys ...string) string {
|
||||
return strings.TrimSpace(fmt.Sprint(current))
|
||||
}
|
||||
|
||||
func firstNonEmpty(values ...string) string {
|
||||
for _, value := range values {
|
||||
if value = strings.TrimSpace(value); value != "" && value != "<nil>" {
|
||||
return value
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func paypalResponseError(operation string, code int, detail string) error {
|
||||
detail = strings.TrimSpace(detail)
|
||||
if detail == "" {
|
||||
|
||||
@@ -103,7 +103,7 @@ func (a *qqAdapter) Create(ctx context.Context, req *bizpayment.PaymentRequest,
|
||||
if status == "pending" && strings.EqualFold(rsp.ResultCode, "SUCCESS") && strings.TrimSpace(rsp.TransactionId) != "" {
|
||||
status = "success"
|
||||
}
|
||||
return &bizpayment.PaymentResult{Provider: bizpayment.PaymentQQ, Status: status, TradeNo: firstNonEmptyQQ(rsp.OutTradeNo, req.TradeNo), ProviderTradeNo: strings.TrimSpace(rsp.TransactionId), Payload: mustJSON(rsp)}, nil
|
||||
return &bizpayment.PaymentResult{Provider: bizpayment.PaymentQQ, Status: status, TradeNo: firstNonEmpty(rsp.OutTradeNo, req.TradeNo), ProviderTradeNo: strings.TrimSpace(rsp.TransactionId), Payload: mustJSON(rsp)}, nil
|
||||
}
|
||||
bm.Set("trade_type", tradeType)
|
||||
mergeGoPayExtras(bm, req.Extra, "nonce_str", "body", "out_trade_no", "total_fee", "spbill_create_ip", "notify_url", "trade_type", "mch_id", "sign_type")
|
||||
@@ -143,15 +143,6 @@ func qqCreateMethod(extra, config map[string]any) (string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func firstNonEmptyQQ(values ...string) string {
|
||||
for _, value := range values {
|
||||
if strings.TrimSpace(value) != "" {
|
||||
return strings.TrimSpace(value)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (a *qqAdapter) Query(ctx context.Context, tradeNo string, c map[string]any) (*bizpayment.PaymentResult, error) {
|
||||
tradeNo = strings.TrimSpace(tradeNo)
|
||||
if tradeNo == "" {
|
||||
|
||||
@@ -1,55 +1,29 @@
|
||||
package payment
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
bizpayment "kra/internal/biz/payment"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"kra/internal/paymentkit"
|
||||
)
|
||||
|
||||
func callbackFields(callback *bizpayment.PaymentCallback) map[string]string {
|
||||
fields := map[string]string{}
|
||||
if callback == nil {
|
||||
return fields
|
||||
return map[string]string{}
|
||||
}
|
||||
for key, value := range callback.Query {
|
||||
fields[key] = value
|
||||
}
|
||||
contentType := ""
|
||||
for key, value := range callback.Headers {
|
||||
if strings.EqualFold(key, "Content-Type") {
|
||||
contentType = strings.ToLower(value)
|
||||
break
|
||||
}
|
||||
}
|
||||
if strings.Contains(contentType, "application/x-www-form-urlencoded") {
|
||||
if values, err := url.ParseQuery(string(callback.Body)); err == nil {
|
||||
for key, value := range values {
|
||||
if len(value) > 0 {
|
||||
fields[key] = value[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var object map[string]any
|
||||
if json.Unmarshal(callback.Body, &object) == nil {
|
||||
for key, value := range object {
|
||||
if stringValue, ok := value.(string); ok {
|
||||
fields[key] = stringValue
|
||||
}
|
||||
}
|
||||
}
|
||||
return fields
|
||||
return paymentkit.CallbackFields(callback.Query, callback.Headers, callback.Body)
|
||||
}
|
||||
|
||||
func first(values map[string]string, keys ...string) string {
|
||||
for _, key := range keys {
|
||||
if values[key] != "" {
|
||||
return values[key]
|
||||
return paymentkit.FirstString(values, keys...)
|
||||
}
|
||||
|
||||
func firstNonEmpty(values ...string) string {
|
||||
for _, value := range values {
|
||||
if value = strings.TrimSpace(value); value != "" && value != "<nil>" {
|
||||
return value
|
||||
}
|
||||
}
|
||||
return ""
|
||||
@@ -69,6 +43,10 @@ func normalizePaymentStatus(value, fallback string) string {
|
||||
return paymentkit.NormalizeStatus(value, fallback)
|
||||
}
|
||||
|
||||
func normalizeRefundStatus(value, fallback string) string {
|
||||
return paymentkit.NormalizeRefundStatus(value, fallback)
|
||||
}
|
||||
|
||||
func parseIntegerAmount(value string) (int64, error) {
|
||||
return paymentkit.ParseIntegerAmount(value)
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ func (a *vendorPaymentAdapter) call(ctx context.Context, endpointKey string, pay
|
||||
result.Status = "created"
|
||||
default:
|
||||
if operation == "refund" {
|
||||
normalized := normalizePaymentStatus(state, "")
|
||||
normalized := normalizeRefundStatus(state, "")
|
||||
switch normalized {
|
||||
case "success", "pending", "failed":
|
||||
result.Status = normalized
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
mqintegration "kra/internal/integration/mq"
|
||||
paymentintegration "kra/internal/integration/payment"
|
||||
"kra/internal/integration/storage"
|
||||
"kra/internal/integration/systeminfo"
|
||||
websocketintegration "kra/internal/integration/websocket"
|
||||
"kra/pkg/mq"
|
||||
platformws "kra/pkg/websocket"
|
||||
@@ -25,6 +26,8 @@ var ProviderSet = wire.NewSet(
|
||||
paymentintegration.NewFactory,
|
||||
wire.Bind(new(bizpayment.PaymentAdapterFactory), new(*paymentintegration.Factory)),
|
||||
storage.NewFileStorage,
|
||||
systeminfo.NewProvider,
|
||||
wire.Bind(new(system.SystemInfoProvider), new(*systeminfo.Provider)),
|
||||
NewConnectivityTester,
|
||||
wire.Bind(new(integrationbiz.IntegrationConnectionTester), new(*ConnectivityTester)),
|
||||
mqintegration.New,
|
||||
|
||||
@@ -69,29 +69,7 @@ func (s *aliyunStorage) Compose(ctx context.Context, names []string, destination
|
||||
return composeFiles(ctx, s, names, destination)
|
||||
}
|
||||
func (s *aliyunStorage) DeletePrefix(ctx context.Context, prefix string) error {
|
||||
prefix, err := normalizeDeletePrefix(prefix)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cursor := ""
|
||||
for {
|
||||
items, next, more, err := s.List(ctx, prefix+"/", cursor, 1000)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, item := range items {
|
||||
if err = s.Delete(ctx, item.Path); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if !more {
|
||||
return nil
|
||||
}
|
||||
cursor, err = advanceDeletePrefixCursor(cursor, next, more)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return deletePrefixViaList(ctx, prefix, s.List, s.Delete)
|
||||
}
|
||||
func (s *aliyunStorage) List(_ context.Context, prefix, cursor string, limit int) ([]*system.StoredFile, string, bool, error) {
|
||||
if limit <= 0 {
|
||||
|
||||
@@ -106,29 +106,7 @@ func (s *awsStorage) Compose(ctx context.Context, names []string, destination st
|
||||
return composeFiles(ctx, s, names, destination)
|
||||
}
|
||||
func (s *awsStorage) DeletePrefix(ctx context.Context, prefix string) error {
|
||||
prefix, err := normalizeDeletePrefix(prefix)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cursor := ""
|
||||
for {
|
||||
items, next, more, err := s.List(ctx, prefix+"/", cursor, 1000)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, item := range items {
|
||||
if err = s.Delete(ctx, item.Path); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if !more {
|
||||
return nil
|
||||
}
|
||||
cursor, err = advanceDeletePrefixCursor(cursor, next, more)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return deletePrefixViaList(ctx, prefix, s.List, s.Delete)
|
||||
}
|
||||
func (s *awsStorage) List(ctx context.Context, prefix, cursor string, limit int) ([]*system.StoredFile, string, bool, error) {
|
||||
if limit <= 0 {
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"io"
|
||||
"kra/internal/biz/system"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -117,3 +118,38 @@ func TestAdvanceDeletePrefixCursor(t *testing.T) {
|
||||
t.Fatalf("advance cursor = %q, %v", next, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeletePrefixViaListDeletesAllPages(t *testing.T) {
|
||||
pages := map[string][]*system.StoredFile{
|
||||
"": {{Path: "uploads/a"}, {Path: "uploads/b"}},
|
||||
"next": {{Path: "uploads/c"}},
|
||||
}
|
||||
removed := []string{}
|
||||
if err := deletePrefixViaList(context.Background(), "uploads", func(_ context.Context, prefix, cursor string, limit int) ([]*system.StoredFile, string, bool, error) {
|
||||
if prefix != "uploads/" || limit != 1000 {
|
||||
t.Fatalf("list arguments = %q, %q, %d", prefix, cursor, limit)
|
||||
}
|
||||
items := pages[cursor]
|
||||
if cursor == "" {
|
||||
return items, "next", true, nil
|
||||
}
|
||||
return items, "", false, nil
|
||||
}, func(_ context.Context, path string) error {
|
||||
removed = append(removed, path)
|
||||
return nil
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(removed) != 3 || removed[2] != "uploads/c" {
|
||||
t.Fatalf("removed paths = %#v", removed)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeletePrefixViaListRejectsStalledCursor(t *testing.T) {
|
||||
err := deletePrefixViaList(context.Background(), "uploads", func(_ context.Context, _, _ string, _ int) ([]*system.StoredFile, string, bool, error) {
|
||||
return nil, "", true, nil
|
||||
}, func(context.Context, string) error { return nil })
|
||||
if err == nil || !strings.Contains(err.Error(), "no progress") {
|
||||
t.Fatalf("stalled pagination error = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,29 +68,7 @@ func (s *huaweiStorage) Compose(ctx context.Context, names []string, destination
|
||||
return composeFiles(ctx, s, names, destination)
|
||||
}
|
||||
func (s *huaweiStorage) DeletePrefix(ctx context.Context, prefix string) error {
|
||||
prefix, err := normalizeDeletePrefix(prefix)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cursor := ""
|
||||
for {
|
||||
items, next, more, err := s.List(ctx, prefix+"/", cursor, 1000)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, item := range items {
|
||||
if err = s.Delete(ctx, item.Path); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if !more {
|
||||
return nil
|
||||
}
|
||||
cursor, err = advanceDeletePrefixCursor(cursor, next, more)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return deletePrefixViaList(ctx, prefix, s.List, s.Delete)
|
||||
}
|
||||
func (s *huaweiStorage) List(_ context.Context, prefix, cursor string, limit int) ([]*system.StoredFile, string, bool, error) {
|
||||
if limit <= 0 {
|
||||
|
||||
@@ -1,11 +1,39 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"kra/internal/biz/system"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func deletePrefixViaList(ctx context.Context, prefix string, list func(context.Context, string, string, int) ([]*system.StoredFile, string, bool, error), remove func(context.Context, string) error) error {
|
||||
prefix, err := normalizeDeletePrefix(prefix)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cursor := ""
|
||||
for {
|
||||
items, next, more, err := list(ctx, prefix+"/", cursor, 1000)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, item := range items {
|
||||
if err := remove(ctx, item.Path); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if !more {
|
||||
return nil
|
||||
}
|
||||
cursor, err = advanceDeletePrefixCursor(cursor, next, more)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// normalizeDeletePrefix rejects requests that could accidentally target the
|
||||
// storage root and returns the canonical key form used by all backends.
|
||||
func normalizeDeletePrefix(prefix string) (string, error) {
|
||||
|
||||
@@ -99,29 +99,7 @@ func (s *qiniuStorage) Compose(ctx context.Context, names []string, destination
|
||||
return composeFiles(ctx, s, names, destination)
|
||||
}
|
||||
func (s *qiniuStorage) DeletePrefix(ctx context.Context, prefix string) error {
|
||||
prefix, err := normalizeDeletePrefix(prefix)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cursor := ""
|
||||
for {
|
||||
items, next, more, err := s.List(ctx, prefix+"/", cursor, 1000)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, item := range items {
|
||||
if err = s.Delete(ctx, item.Path); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if !more {
|
||||
return nil
|
||||
}
|
||||
cursor, err = advanceDeletePrefixCursor(cursor, next, more)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return deletePrefixViaList(ctx, prefix, s.List, s.Delete)
|
||||
}
|
||||
func (s *qiniuStorage) List(ctx context.Context, prefix, cursor string, limit int) ([]*system.StoredFile, string, bool, error) {
|
||||
if limit <= 0 {
|
||||
|
||||
@@ -82,29 +82,7 @@ func (s *tencentStorage) Compose(ctx context.Context, names []string, destinatio
|
||||
return composeFiles(ctx, s, names, destination)
|
||||
}
|
||||
func (s *tencentStorage) DeletePrefix(ctx context.Context, prefix string) error {
|
||||
prefix, err := normalizeDeletePrefix(prefix)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cursor := ""
|
||||
for {
|
||||
items, next, more, err := s.List(ctx, prefix+"/", cursor, 1000)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, item := range items {
|
||||
if err = s.Delete(ctx, item.Path); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if !more {
|
||||
return nil
|
||||
}
|
||||
cursor, err = advanceDeletePrefixCursor(cursor, next, more)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return deletePrefixViaList(ctx, prefix, s.List, s.Delete)
|
||||
}
|
||||
func (s *tencentStorage) List(ctx context.Context, prefix, cursor string, limit int) ([]*system.StoredFile, string, bool, error) {
|
||||
if limit <= 0 {
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package systeminfo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"kra/internal/biz/system"
|
||||
|
||||
"github.com/shirou/gopsutil/v4/cpu"
|
||||
"github.com/shirou/gopsutil/v4/disk"
|
||||
"github.com/shirou/gopsutil/v4/mem"
|
||||
)
|
||||
|
||||
type Provider struct{}
|
||||
|
||||
func NewProvider() *Provider { return &Provider{} }
|
||||
|
||||
func (*Provider) Collect(ctx context.Context, mountPoints []string) (*system.ServerInfo, error) {
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
}
|
||||
if err := ctx.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
physicalCores, err := cpu.Counts(false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cpuPercent, err := cpu.PercentWithContext(ctx, 200*time.Millisecond, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
memory, err := mem.VirtualMemoryWithContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
diskInfo := make([]system.ServerDiskInfo, 0, len(mountPoints))
|
||||
for _, mountPoint := range mountPoints {
|
||||
if err = ctx.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
usage, usageErr := disk.UsageWithContext(ctx, mountPoint)
|
||||
if usageErr != nil {
|
||||
return nil, usageErr
|
||||
}
|
||||
diskInfo = append(diskInfo, system.ServerDiskInfo{MountPoint: mountPoint, UsedMB: usage.Used / 1024 / 1024, UsedGB: usage.Used / 1024 / 1024 / 1024, TotalMB: usage.Total / 1024 / 1024, TotalGB: usage.Total / 1024 / 1024 / 1024, UsedPercent: int(usage.UsedPercent)})
|
||||
}
|
||||
return &system.ServerInfo{GOOS: runtime.GOOS, NumCPU: runtime.NumCPU(), Compiler: runtime.Compiler, GoVersion: runtime.Version(), NumGoroutine: runtime.NumGoroutine(), CPUs: cpuPercent, Cores: physicalCores, UsedMB: memory.Used / 1024 / 1024, TotalMB: memory.Total / 1024 / 1024, UsedPercent: int(memory.UsedPercent), Disk: diskInfo}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user