Files
eightbf-analysis-go/internal/config/config.go
T
gozerosandCursor 0c45b86d67 chore: 初始化 eightbf-analysis-go(对齐 Java 会商作业服务)
Go 实现 /api/v1/analysis 契约、Demo/Live Worker、DeerFlow SSE;含设计文档与冒烟脚本。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-11-03 00:13:46 +08:00

145 lines
3.8 KiB
Go

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
}