Files
2026-08-25 17:59:42 +08:00

79 lines
2.0 KiB
Go

package service
import (
"context"
"log/slog"
"net/http"
"sync"
"time"
"juhe-factory/api/internal/provider/apimart"
"github.com/google/uuid"
)
type balanceChannel struct {
ID uuid.UUID
Name string
BaseURL string
APIKeyCiphertext string
}
func (s *AdminData) triggerChannelBalanceSync() {
if !s.balanceSyncing.CompareAndSwap(false, true) {
return
}
go func() {
defer s.balanceSyncing.Store(false)
s.syncChannelBalances(context.Background())
}()
}
func (s *AdminData) syncChannelBalances(ctx context.Context) {
if s.Encryptor == nil {
return
}
var channels []balanceChannel
if err := s.DB.Table("channels").Select("id,name,base_url,api_key_ciphertext").
Where("deleted_at IS NULL AND api_key_ciphertext IS NOT NULL AND api_key_ciphertext<>''").
Find(&channels).Error; err != nil {
slog.Warn("读取待同步渠道余额失败", "error", err)
return
}
syncCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
client := s.HTTPClient
if client == nil {
client = http.DefaultClient
}
var wait sync.WaitGroup
for _, channel := range channels {
channel := channel
wait.Add(1)
go func() {
defer wait.Done()
apiKey, err := s.Encryptor.Decrypt(channel.APIKeyCiphertext)
if err != nil {
slog.Warn("解密渠道 API Key 失败", "channel", channel.Name, "error", err)
return
}
balance, err := apimart.NewClient(client).Balance(syncCtx, channel.BaseURL, apiKey)
if err != nil {
slog.Warn("同步渠道余额失败", "channel", channel.Name, "error", err)
return
}
remainBalance := balance.RemainBalance
if balance.UnlimitedQuota {
remainBalance = -1
}
if err := s.DB.Exec(`INSERT INTO channel_balance_snapshots(channel_id,balance,currency,synced_at)
VALUES(?,?,?,?)`, channel.ID, remainBalance, "USD", time.Now()).Error; err != nil {
slog.Warn("保存渠道余额快照失败", "channel", channel.Name, "error", err)
}
}()
}
wait.Wait()
}