Initial sanitized code sync

This commit is contained in:
zqq61
2026-03-15 20:48:19 +08:00
commit 17ee51ba04
126 changed files with 22546 additions and 0 deletions

134
pkg/provider/card/file.go Normal file
View File

@@ -0,0 +1,134 @@
package card
import (
"bufio"
"context"
"fmt"
"os"
"strings"
)
// FileProvider loads cards from a local TXT file (one card per line).
// Supported formats:
// 卡号|月|年|CVC
// 卡号|月|年|CVC|姓名|国家|货币
// 卡号|月|年|CVC|姓名|国家|货币|地址|城市|州|邮编
// 卡号,月,年,CVC
// 卡号,月,年,CVC,姓名,国家,货币,地址,城市,州,邮编
type FileProvider struct {
pool *CardPool
}
// NewFileProvider creates a FileProvider by reading cards from a text file.
func NewFileProvider(filePath string, defaultCountry, defaultCurrency string, poolCfg PoolConfig) (*FileProvider, error) {
cards, err := parseCardFile(filePath, defaultCountry, defaultCurrency)
if err != nil {
return nil, err
}
if len(cards) == 0 {
return nil, fmt.Errorf("no valid cards found in %s", filePath)
}
pool := NewCardPool(poolCfg)
pool.AddCards(cards)
return &FileProvider{pool: pool}, nil
}
// GetCard returns the next available card from the pool.
func (p *FileProvider) GetCard(ctx context.Context) (*CardInfo, error) {
return p.pool.GetCard()
}
// ReportResult reports the usage outcome.
func (p *FileProvider) ReportResult(ctx context.Context, card *CardInfo, success bool) error {
p.pool.ReportResult(card, success)
return nil
}
// parseCardFile reads and parses a card file.
func parseCardFile(filePath, defaultCountry, defaultCurrency string) ([]*CardInfo, error) {
f, err := os.Open(filePath)
if err != nil {
return nil, fmt.Errorf("open card file: %w", err)
}
defer f.Close()
var cards []*CardInfo
scanner := bufio.NewScanner(f)
lineNum := 0
for scanner.Scan() {
lineNum++
line := strings.TrimSpace(scanner.Text())
// Skip empty lines and comments
if line == "" || strings.HasPrefix(line, "#") || strings.HasPrefix(line, "//") {
continue
}
card, err := parseLine(line, defaultCountry, defaultCurrency)
if err != nil {
return nil, fmt.Errorf("line %d: %w", lineNum, err)
}
cards = append(cards, card)
}
if err := scanner.Err(); err != nil {
return nil, fmt.Errorf("read card file: %w", err)
}
return cards, nil
}
// parseLine parses a single card line. Supports | and , delimiters.
func parseLine(line, defaultCountry, defaultCurrency string) (*CardInfo, error) {
var parts []string
if strings.Contains(line, "|") {
parts = strings.Split(line, "|")
} else {
parts = strings.Split(line, ",")
}
// Trim all parts
for i := range parts {
parts[i] = strings.TrimSpace(parts[i])
}
if len(parts) < 4 {
return nil, fmt.Errorf("expected at least 4 fields (number|month|year|cvc), got %d", len(parts))
}
card := &CardInfo{
Number: parts[0],
ExpMonth: parts[1],
ExpYear: parts[2],
CVC: parts[3],
Country: defaultCountry,
Currency: defaultCurrency,
}
if len(parts) >= 5 && parts[4] != "" {
card.Name = parts[4]
}
if len(parts) >= 6 && parts[5] != "" {
card.Country = parts[5]
}
if len(parts) >= 7 && parts[6] != "" {
card.Currency = parts[6]
}
if len(parts) >= 8 && parts[7] != "" {
card.Address = parts[7]
}
if len(parts) >= 9 && parts[8] != "" {
card.City = parts[8]
}
if len(parts) >= 10 && parts[9] != "" {
card.State = parts[9]
}
if len(parts) >= 11 && parts[10] != "" {
card.PostalCode = parts[10]
}
return card, nil
}