package main import ( "database/sql" "log" "net/http" "os" "strconv" "time" _ "github.com/go-sql-driver/mysql" "git.gozeros.com/wsk/eightbf-analysis-go/internal/api" "git.gozeros.com/wsk/eightbf-analysis-go/internal/config" "git.gozeros.com/wsk/eightbf-analysis-go/internal/deerflow" "git.gozeros.com/wsk/eightbf-analysis-go/internal/repo" "git.gozeros.com/wsk/eightbf-analysis-go/internal/service" "git.gozeros.com/wsk/eightbf-analysis-go/internal/worker" ) func main() { cfg := config.Load() log.Printf("eightbf-analysis-go starting port=%d mode=%s auth=%v demo=%v", cfg.Port, cfg.AnalysisMode, cfg.AuthEnabled, cfg.DemoEnabled) db, err := sql.Open("mysql", cfg.DBDSN) if err != nil { log.Fatalf("open db: %v", err) } db.SetMaxOpenConns(20) db.SetMaxIdleConns(5) db.SetConnMaxLifetime(time.Hour) if err := db.Ping(); err != nil { log.Fatalf("ping db: %v(请检查 EBA_DB_DSN / EBA_DB_*)", err) } jobRepo := repo.NewJobRepo(db) if schema, err := os.ReadFile("schema.sql"); err != nil { log.Printf("未找到 schema.sql,跳过自动建表: %v", err) } else { jobRepo.ApplySchema(string(schema)) } access := &service.AccessService{AuthEnabled: cfg.AuthEnabled} jobs := &service.JobService{Repo: jobRepo, Access: access} h := &api.Handler{Jobs: jobs} mux := http.NewServeMux() h.Routes(mux) if cfg.AnalysisMode == "live" && !cfg.DemoEnabled { auth := deerflow.NewAuth(cfg) df := deerflow.NewClient(cfg, auth) runner := &worker.LiveChainRunner{DF: df, Repo: jobRepo, Coord: cfg.DeerFlowCoordinator} lw := &worker.LiveWorker{ Repo: jobRepo, Runner: runner, PollEvery: time.Duration(cfg.LivePollMS) * time.Millisecond, } lw.Start() log.Printf("LiveWorker 已启动 poll=%dms", cfg.LivePollMS) } else if cfg.DemoEnabled || cfg.AnalysisMode == "demo" { dw := &service.DemoWorker{ Repo: jobRepo, Every: time.Duration(cfg.DemoTickMS) * time.Millisecond, } dw.Start() log.Printf("DemoWorker 已启动 tick=%dms", cfg.DemoTickMS) } else { log.Printf("警告:未启动任何 Worker(mode=%s demo=%v)", cfg.AnalysisMode, cfg.DemoEnabled) } addr := ":" + strconv.Itoa(cfg.Port) log.Printf("监听 %s (健康检查 GET /api/v1/analysis/health)", addr) if err := http.ListenAndServe(addr, api.WithCORS(mux)); err != nil { log.Fatal(err) } }