2026-05-29 18:48:48 +08:00
|
|
|
//go:build llm_script && !scripts_pkg
|
2026-05-15 22:32:57 +08:00
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"database/sql"
|
|
|
|
|
"flag"
|
|
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
"net/http"
|
|
|
|
|
"os"
|
|
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type aliyunSubscriptionImportConfig struct {
|
|
|
|
|
TokenURL string
|
|
|
|
|
CodingURL string
|
|
|
|
|
TokenFixture string
|
|
|
|
|
CodingFixture string
|
|
|
|
|
DryRun bool
|
|
|
|
|
Timeout time.Duration
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
|
loadSubscriptionImportEnv()
|
|
|
|
|
|
|
|
|
|
var tokenURL string
|
|
|
|
|
var codingURL string
|
|
|
|
|
var tokenFixture string
|
|
|
|
|
var codingFixture string
|
|
|
|
|
var dryRun bool
|
|
|
|
|
var timeoutSeconds int
|
|
|
|
|
|
|
|
|
|
flag.StringVar(&tokenURL, "token-url", defaultAliyunTokenPlanURL, "阿里云 Token Plan 文档 URL")
|
|
|
|
|
flag.StringVar(&codingURL, "coding-url", defaultAliyunCodingPlanURL, "阿里云 Coding Plan 文档 URL")
|
|
|
|
|
flag.StringVar(&tokenFixture, "token-fixture", "", "阿里云 Token Plan 本地样例文件")
|
|
|
|
|
flag.StringVar(&codingFixture, "coding-fixture", "", "阿里云 Coding Plan 本地样例文件")
|
|
|
|
|
flag.BoolVar(&dryRun, "dry-run", false, "仅解析并打印摘要,不写入数据库")
|
|
|
|
|
flag.IntVar(&timeoutSeconds, "timeout", 20, "请求超时(秒)")
|
|
|
|
|
flag.Parse()
|
|
|
|
|
|
|
|
|
|
cfg := aliyunSubscriptionImportConfig{
|
|
|
|
|
TokenURL: tokenURL,
|
|
|
|
|
CodingURL: codingURL,
|
|
|
|
|
TokenFixture: tokenFixture,
|
|
|
|
|
CodingFixture: codingFixture,
|
|
|
|
|
DryRun: dryRun,
|
|
|
|
|
Timeout: time.Duration(timeoutSeconds) * time.Second,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var db *sql.DB
|
|
|
|
|
var err error
|
|
|
|
|
if !cfg.DryRun {
|
|
|
|
|
db, err = subscriptionImportDB()
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Fprintf(os.Stderr, "open db: %v\n", err)
|
|
|
|
|
os.Exit(1)
|
|
|
|
|
}
|
|
|
|
|
defer db.Close()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := runAliyunSubscriptionImport(cfg, db, os.Stdout); err != nil {
|
|
|
|
|
fmt.Fprintf(os.Stderr, "import_aliyun_subscription: %v\n", err)
|
|
|
|
|
os.Exit(1)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func runAliyunSubscriptionImport(cfg aliyunSubscriptionImportConfig, db *sql.DB, out io.Writer) error {
|
|
|
|
|
client := &http.Client{Timeout: cfg.Timeout}
|
|
|
|
|
tokenRaw, err := fetchSubscriptionPage(cfg.TokenURL, cfg.TokenFixture, client)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
codingRaw, err := fetchSubscriptionPage(cfg.CodingURL, cfg.CodingFixture, client)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
records, err := parseAliyunSubscriptionCatalog(tokenRaw, codingRaw)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if cfg.DryRun {
|
|
|
|
|
_, err = fmt.Fprintf(out, "source=aliyun-subscription-import plans=%d provider=%s operator=%s dry_run=true\n", len(records), records[0].ProviderName, records[0].OperatorName)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if db == nil {
|
|
|
|
|
return fmt.Errorf("db is required when dry-run=false")
|
|
|
|
|
}
|
|
|
|
|
if err := upsertSubscriptionImportRecords(db, records); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var tableRows int
|
|
|
|
|
if err := db.QueryRow(`SELECT COUNT(*) FROM subscription_plan`).Scan(&tableRows); err != nil {
|
|
|
|
|
return fmt.Errorf("count subscription_plan: %w", err)
|
|
|
|
|
}
|
|
|
|
|
_, err = fmt.Fprintf(out, "source=aliyun-subscription-import plans=%d provider=%s operator=%s table_rows=%d dry_run=false\n", len(records), records[0].ProviderName, records[0].OperatorName, tableRows)
|
|
|
|
|
return err
|
|
|
|
|
}
|