package config import ( "os" "strconv" "strings" ) // Config 运行配置(环境变量优先,与 Java EBA_* / analysis.* 对齐)。 type Config struct { Port int // MySQL:优先 EBA_DB_DSN;否则用 HOST/PORT/NAME/USER/PASSWORD 拼,或解析 JDBC URL。 DBDSN string AnalysisMode string // live | demo AuthEnabled bool DemoEnabled bool LivePollMS int DemoTickMS int DeerFlowBaseURL string DeerFlowUser string DeerFlowPassword string DeerFlowCoordinator string DeerFlowStreamIdleTimeout int // 毫秒 } // Load 从环境变量加载;缺省贴近本机联调。 func Load() Config { c := Config{ Port: envInt("SERVER_PORT", 18097), AnalysisMode: env("ANALYSIS_MODE", "live"), AuthEnabled: envBool("ANALYSIS_AUTH_ENABLED", false), DemoEnabled: envBool("EBA_WORKER_DEMO_ENABLED", false), LivePollMS: envInt("EBA_WORKER_LIVE_POLL_MS", 1000), DemoTickMS: envInt("EBA_WORKER_TICK_MS", 400), DeerFlowBaseURL: strings.TrimRight(env("EBA_DF_BASE_URL", "http://127.0.0.1:8001"), "/"), DeerFlowUser: env("EBA_DF_USER", "admin"), DeerFlowPassword: env("EBA_DF_PASSWORD", "123ewq"), DeerFlowCoordinator: env("EBA_DF_COORDINATOR", "roundtable-coordinator"), DeerFlowStreamIdleTimeout: envInt("EBA_DF_STREAM_IDLE_TIMEOUT_MS", 180000), } c.DBDSN = resolveDSN() // live 默认关掉 demo;显式 ANALYSIS_MODE=demo 时打开假进度 if c.AnalysisMode == "demo" { c.DemoEnabled = true } if c.AnalysisMode == "live" && !envExplicit("EBA_WORKER_DEMO_ENABLED") { c.DemoEnabled = false } return c } func resolveDSN() string { if d := strings.TrimSpace(os.Getenv("EBA_DB_DSN")); d != "" { return ensureMultiStatements(d) } user := env("EBA_DB_USER", "eba") pass := env("EBA_DB_PASSWORD", "eba_local_dev") jdbc := strings.TrimSpace(os.Getenv("EBA_DB_URL")) if jdbc != "" { if dsn, ok := jdbcToDSN(jdbc, user, pass); ok { return dsn } } host := env("EBA_DB_HOST", "127.0.0.1") port := env("EBA_DB_PORT", "3306") name := env("EBA_DB_NAME", "eightbf_analysis") return user + ":" + pass + "@tcp(" + host + ":" + port + ")/" + name + "?parseTime=true&loc=Asia%2FShanghai&charset=utf8mb4&multiStatements=true" } // jdbcToDSN 把 Java 的 jdbc:mysql://host:port/db?... 转成 Go driver DSN。 func jdbcToDSN(jdbc, user, pass string) (string, bool) { s := strings.TrimPrefix(jdbc, "jdbc:mysql://") if s == jdbc { return "", false } hostPath := s query := "" if i := strings.Index(s, "?"); i >= 0 { hostPath = s[:i] query = s[i+1:] } host := hostPath db := "eightbf_analysis" if i := strings.Index(hostPath, "/"); i >= 0 { host = hostPath[:i] db = hostPath[i+1:] } params := "parseTime=true&loc=Asia%2FShanghai&charset=utf8mb4&multiStatements=true" _ = query // Java JDBC 专用参数不照搬 return user + ":" + pass + "@tcp(" + host + ")/" + db + "?" + params, true } func ensureMultiStatements(dsn string) string { if strings.Contains(dsn, "multiStatements=") { return dsn } if strings.Contains(dsn, "?") { return dsn + "&multiStatements=true" } return dsn + "?multiStatements=true" } func env(k, def string) string { if v := strings.TrimSpace(os.Getenv(k)); v != "" { return v } return def } func envExplicit(k string) bool { _, ok := os.LookupEnv(k) return ok } func envBool(k string, def bool) bool { v := strings.TrimSpace(os.Getenv(k)) if v == "" { return def } switch strings.ToLower(v) { case "1", "true", "yes", "on": return true case "0", "false", "no", "off": return false default: return def } } func envInt(k string, def int) int { v := strings.TrimSpace(os.Getenv(k)) if v == "" { return def } n, err := strconv.Atoi(v) if err != nil { return def } return n }