feat: sync lijiaoqiao implementation and staging validation artifacts

This commit is contained in:
Your Name
2026-03-31 13:40:00 +08:00
parent 0e5ecd930e
commit e9338dec28
686 changed files with 29213 additions and 168 deletions

View File

@@ -0,0 +1,319 @@
package storage
import (
"context"
"errors"
"sync"
"time"
"lijiaoqiao/supply-api/internal/domain"
)
// 错误定义
var ErrNotFound = errors.New("resource not found")
// 内存账号存储
type InMemoryAccountStore struct {
mu sync.RWMutex
accounts map[int64]*domain.Account
nextID int64
}
func NewInMemoryAccountStore() *InMemoryAccountStore {
return &InMemoryAccountStore{
accounts: make(map[int64]*domain.Account),
nextID: 1,
}
}
func (s *InMemoryAccountStore) Create(ctx context.Context, account *domain.Account) error {
s.mu.Lock()
defer s.mu.Unlock()
account.ID = s.nextID
s.nextID++
account.CreatedAt = time.Now()
account.UpdatedAt = time.Now()
s.accounts[account.ID] = account
return nil
}
func (s *InMemoryAccountStore) GetByID(ctx context.Context, supplierID, id int64) (*domain.Account, error) {
s.mu.RLock()
defer s.mu.RUnlock()
account, ok := s.accounts[id]
if !ok || account.SupplierID != supplierID {
return nil, ErrNotFound
}
return account, nil
}
func (s *InMemoryAccountStore) Update(ctx context.Context, account *domain.Account) error {
s.mu.Lock()
defer s.mu.Unlock()
existing, ok := s.accounts[account.ID]
if !ok || existing.SupplierID != account.SupplierID {
return ErrNotFound
}
account.UpdatedAt = time.Now()
s.accounts[account.ID] = account
return nil
}
func (s *InMemoryAccountStore) List(ctx context.Context, supplierID int64) ([]*domain.Account, error) {
s.mu.RLock()
defer s.mu.RUnlock()
var result []*domain.Account
for _, account := range s.accounts {
if account.SupplierID == supplierID {
result = append(result, account)
}
}
return result, nil
}
// 内存套餐存储
type InMemoryPackageStore struct {
mu sync.RWMutex
packages map[int64]*domain.Package
nextID int64
}
func NewInMemoryPackageStore() *InMemoryPackageStore {
return &InMemoryPackageStore{
packages: make(map[int64]*domain.Package),
nextID: 1,
}
}
func (s *InMemoryPackageStore) Create(ctx context.Context, pkg *domain.Package) error {
s.mu.Lock()
defer s.mu.Unlock()
pkg.ID = s.nextID
s.nextID++
pkg.CreatedAt = time.Now()
pkg.UpdatedAt = time.Now()
s.packages[pkg.ID] = pkg
return nil
}
func (s *InMemoryPackageStore) GetByID(ctx context.Context, supplierID, id int64) (*domain.Package, error) {
s.mu.RLock()
defer s.mu.RUnlock()
pkg, ok := s.packages[id]
if !ok || pkg.SupplierID != supplierID {
return nil, ErrNotFound
}
return pkg, nil
}
func (s *InMemoryPackageStore) Update(ctx context.Context, pkg *domain.Package) error {
s.mu.Lock()
defer s.mu.Unlock()
existing, ok := s.packages[pkg.ID]
if !ok || existing.SupplierID != pkg.SupplierID {
return ErrNotFound
}
pkg.UpdatedAt = time.Now()
s.packages[pkg.ID] = pkg
return nil
}
func (s *InMemoryPackageStore) List(ctx context.Context, supplierID int64) ([]*domain.Package, error) {
s.mu.RLock()
defer s.mu.RUnlock()
var result []*domain.Package
for _, pkg := range s.packages {
if pkg.SupplierID == supplierID {
result = append(result, pkg)
}
}
return result, nil
}
// 内存结算存储
type InMemorySettlementStore struct {
mu sync.RWMutex
settlements map[int64]*domain.Settlement
nextID int64
}
func NewInMemorySettlementStore() *InMemorySettlementStore {
return &InMemorySettlementStore{
settlements: make(map[int64]*domain.Settlement),
nextID: 1,
}
}
func (s *InMemorySettlementStore) Create(ctx context.Context, settlement *domain.Settlement) error {
s.mu.Lock()
defer s.mu.Unlock()
settlement.ID = s.nextID
s.nextID++
settlement.CreatedAt = time.Now()
settlement.UpdatedAt = time.Now()
s.settlements[settlement.ID] = settlement
return nil
}
func (s *InMemorySettlementStore) GetByID(ctx context.Context, supplierID, id int64) (*domain.Settlement, error) {
s.mu.RLock()
defer s.mu.RUnlock()
settlement, ok := s.settlements[id]
if !ok || settlement.SupplierID != supplierID {
return nil, ErrNotFound
}
return settlement, nil
}
func (s *InMemorySettlementStore) Update(ctx context.Context, settlement *domain.Settlement) error {
s.mu.Lock()
defer s.mu.Unlock()
existing, ok := s.settlements[settlement.ID]
if !ok || existing.SupplierID != settlement.SupplierID {
return ErrNotFound
}
settlement.UpdatedAt = time.Now()
s.settlements[settlement.ID] = settlement
return nil
}
func (s *InMemorySettlementStore) List(ctx context.Context, supplierID int64) ([]*domain.Settlement, error) {
s.mu.RLock()
defer s.mu.RUnlock()
var result []*domain.Settlement
for _, settlement := range s.settlements {
if settlement.SupplierID == supplierID {
result = append(result, settlement)
}
}
return result, nil
}
func (s *InMemorySettlementStore) GetWithdrawableBalance(ctx context.Context, supplierID int64) (float64, error) {
return 10000.0, nil
}
// 内存收益存储
type InMemoryEarningStore struct {
mu sync.RWMutex
records map[int64]*domain.EarningRecord
nextID int64
}
func NewInMemoryEarningStore() *InMemoryEarningStore {
return &InMemoryEarningStore{
records: make(map[int64]*domain.EarningRecord),
nextID: 1,
}
}
func (s *InMemoryEarningStore) ListRecords(ctx context.Context, supplierID int64, startDate, endDate string, page, pageSize int) ([]*domain.EarningRecord, int, error) {
s.mu.RLock()
defer s.mu.RUnlock()
var result []*domain.EarningRecord
for _, record := range s.records {
if record.SupplierID == supplierID {
result = append(result, record)
}
}
total := len(result)
start := (page - 1) * pageSize
end := start + pageSize
if start >= total {
return []*domain.EarningRecord{}, total, nil
}
if end > total {
end = total
}
return result[start:end], total, nil
}
func (s *InMemoryEarningStore) GetBillingSummary(ctx context.Context, supplierID int64, startDate, endDate string) (*domain.BillingSummary, error) {
return &domain.BillingSummary{
Period: domain.BillingPeriod{
Start: startDate,
End: endDate,
},
Summary: domain.BillingTotal{
TotalRevenue: 10000.0,
TotalOrders: 100,
TotalUsage: 1000000,
TotalRequests: 50000,
AvgSuccessRate: 99.5,
PlatformFee: 100.0,
NetEarnings: 9900.0,
},
}, nil
}
// 内存幂等存储
type InMemoryIdempotencyStore struct {
mu sync.RWMutex
records map[string]*IdempotencyRecord
}
type IdempotencyRecord struct {
Key string
Status string // processing, succeeded, failed
Response interface{}
CreatedAt time.Time
ExpiresAt time.Time
}
func NewInMemoryIdempotencyStore() *InMemoryIdempotencyStore {
return &InMemoryIdempotencyStore{
records: make(map[string]*IdempotencyRecord),
}
}
func (s *InMemoryIdempotencyStore) Get(key string) (*IdempotencyRecord, bool) {
s.mu.RLock()
defer s.mu.RUnlock()
record, ok := s.records[key]
if ok && record.ExpiresAt.After(time.Now()) {
return record, true
}
return nil, false
}
func (s *InMemoryIdempotencyStore) SetProcessing(key string, ttl time.Duration) {
s.mu.Lock()
defer s.mu.Unlock()
s.records[key] = &IdempotencyRecord{
Key: key,
Status: "processing",
CreatedAt: time.Now(),
ExpiresAt: time.Now().Add(ttl),
}
}
func (s *InMemoryIdempotencyStore) SetSuccess(key string, response interface{}, ttl time.Duration) {
s.mu.Lock()
defer s.mu.Unlock()
s.records[key] = &IdempotencyRecord{
Key: key,
Status: "succeeded",
Response: response,
CreatedAt: time.Now(),
ExpiresAt: time.Now().Add(ttl),
}
}