79 lines
2.0 KiB
Go
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()
|
|
}
|