| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 |
- package main
- import (
- "context"
- "fmt"
- "log"
- "time"
- "spider/internal/config"
- "spider/internal/handler"
- "spider/internal/llm"
- "spider/internal/model"
- "spider/internal/search"
- "spider/internal/service"
- "spider/internal/telegram"
- "spider/internal/worker"
- "github.com/redis/go-redis/v9"
- "gorm.io/driver/mysql"
- "gorm.io/gorm"
- )
- func main() {
- // 1. 加载配置
- cfg, err := config.Load("configs/config.yaml")
- if err != nil {
- log.Fatalf("load config: %v", err)
- }
- // 2. 连接 MySQL
- dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
- cfg.MySQL.User, cfg.MySQL.Password, cfg.MySQL.Host, cfg.MySQL.Port, cfg.MySQL.Database)
- db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
- if err != nil {
- log.Fatalf("connect mysql: %v", err)
- }
- // 3. AutoMigrate 所有表
- err = db.AutoMigrate(
- &model.ManagedSeed{},
- &model.ManagedKeyword{},
- &model.ManagedSetting{},
- &model.Channel{},
- &model.NavSite{},
- &model.MerchantRaw{},
- &model.MerchantClean{},
- &model.Task{},
- &model.ConfigRevision{},
- )
- if err != nil {
- log.Fatalf("automigrate: %v", err)
- }
- log.Println("MySQL tables migrated")
- // 3a. 初始化 managed_settings 默认值(幂等,已有记录不覆盖)
- seedSettings(db)
- // 4. 连接 Redis
- rdb := redis.NewClient(&redis.Options{
- Addr: fmt.Sprintf("%s:%d", cfg.Redis.Host, cfg.Redis.Port),
- Password: cfg.Redis.Password,
- DB: cfg.Redis.DB,
- })
- log.Println("Redis connected")
- // 5. 初始化 TaskService
- taskSvc := service.NewTaskService(db, rdb)
- // 5a. 初始化 SettingsService 并加载到 Redis 缓存
- settings := service.NewSettingsService(db, rdb)
- if err := settings.Load(context.Background()); err != nil {
- log.Printf("load settings into cache: %v", err)
- }
- // 5b. 初始化 AccountManager(账号从配置读取,为空时运行时从 DB 动态加载)
- tgAccounts := make([]telegram.Account, 0, len(cfg.Telegram.Accounts))
- for _, a := range cfg.Telegram.Accounts {
- tgAccounts = append(tgAccounts, telegram.Account{
- Phone: a.Phone,
- SessionFile: a.SessionFile,
- AppID: cfg.Telegram.AppID,
- AppHash: cfg.Telegram.AppHash,
- })
- }
- tgManager := telegram.NewAccountManager(tgAccounts, rdb)
- // 5c. 初始化 LLM Client(配置缺失时为 nil,phase 会安全跳过)
- var llmClient *llm.Client
- if cfg.LLM.APIKey != "" {
- llmClient = llm.New(cfg.LLM.BaseURL, cfg.LLM.APIKey, cfg.LLM.Model, 30*time.Second)
- }
- // 5d. 初始化 Serper Client(配置缺失时为 nil)
- var serperClient *search.SerperClient
- if cfg.Serper.APIKey != "" {
- serperClient = search.NewSerperClient(cfg.Serper.APIKey, cfg.Serper.ResultsPerPage, cfg.Serper.MaxPages)
- }
- // 6. 初始化并启动 asynq Worker
- redisAddr := fmt.Sprintf("%s:%d", cfg.Redis.Host, cfg.Redis.Port)
- w := worker.New(redisAddr, cfg.Redis.Password, cfg.Redis.DB, db, rdb, tgManager, llmClient, settings, serperClient, cfg.GitHub.Token)
- go func() {
- log.Println("asynq worker starting...")
- if err := w.Start(); err != nil {
- log.Fatalf("asynq worker error: %v", err)
- }
- }()
- // 7. 初始化 Gin router
- r := handler.SetupRouter(db, rdb, taskSvc)
- addr := handler.ServerAddr(cfg.Server.Port)
- log.Printf("Server starting on %s", addr)
- if err := r.Run(addr); err != nil {
- log.Fatalf("gin run: %v", err)
- }
- }
|