| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- package config
- import (
- "crypto/md5"
- "encoding/hex"
- "fmt"
- "github.com/spf13/viper"
- )
- type AppConfig struct {
- AppEnv string
- AppPort string
- LogLevel string
- RedisAddr string
- MySQLDSN string
- PostgresDSN string
- MongoDSN string
- MinIoEndpoint string
- MinioAccessKey string
- MinioSecretKey string
- MinioBucketName string
- AsynqmonPort string
- TotpViewPassword string
- TotpViewHost string
- TotpViewPort string
- }
- type FwhApiConfig struct {
- FwhEnergy string
- FwhOss string
- FwhUser string
- FwhPassword string
- FwhTotpSecret string
- FwhTotpField string
- }
- type FwhMqttConfig struct {
- FwhMqttBroker string
- FwhMqttCaUrl string
- FwhMqttCertUrl string
- FwhMqttKeyUrl string
- }
- // FwhEsConfig Elasticsearch(iotcore-stat) 连接配置
- type FwhEsConfig struct {
- // EsHost 形如 "alb-prod.franklinwh.click:5603"(不含 scheme)
- EsHost string
- // EsUser / EsPassword basic auth 凭证
- EsUser string
- EsPassword string
- // EsIndexPrefix 索引前缀,形如 "iotcore-stat",
- // 实际索引名会拼接日期,如 "iotcore-stat-2026.09.07"
- EsIndexPrefix string
- // EsInsecureSkipVerify 是否跳过 TLS 证书校验(对应 curl -k)
- EsInsecureSkipVerify bool
- }
- type PlaneApiConfig struct {
- Host string
- ApiKey string
- WorkspaceSlug string
- ProjectId string
- LabelBugId string
- LabelFeatureId string
- }
- type PlaneWebApiConfig struct {
- Host string
- Email string
- Password string
- WorkspaceSlug string
- ProjectId string
- LabelBugId string
- LabelFeatureId string
- LabelFeedbackId string
- }
- type KiroConfig struct {
- // RunAsUser 指定拉起 kiro-cli 子进程时降权到的系统用户名。
- // 为空时表示不降权,沿用后台服务自身的运行用户。
- RunAsUser string
- // Home 指定拉起 kiro-cli 子进程时使用的 HOME 目录(即 $HOME 环境变量)。
- // kiro-cli 依赖 HOME 定位其配置与凭证。为空时回退到降权用户的家目录,
- // 若也无法推导则使用默认值。
- Home string
- // DebugLog 为调试日志总开关(宏开关)。
- // 开启后,拉起 kiro-cli 子进程时注入 KIRO_LOG_LEVEL=debug,
- // 让 kiro-cli 输出 debug 级日志,便于问题排查。
- // 由环境变量 KIRO_DEBUG_LOG 控制(true/1/on 开启,默认关闭)。
- DebugLog bool
- }
- type Config struct {
- App AppConfig
- FwhApi FwhApiConfig
- FwhTestApi FwhApiConfig
- FwhMqtt FwhMqttConfig
- FwhTestMqtt FwhMqttConfig
- FwhEs FwhEsConfig
- PlaneApi PlaneApiConfig
- PlaneWebApi PlaneWebApiConfig
- Kiro KiroConfig
- }
- // 需先执行LoadConfig后才能读取ENV
- // var APP_ENV string = "dev"
- // var FWH_ENERGY string = "energy.franklinwh.com"
- // var FWH_OSS string = "oss.franklinwh.com"
- // var FWH_USER string = ""
- // var FWH_PASSWORD string = "" // MD5 - PASSWORD
- // LoadConfig 读取配置文件和环境变量。
- // 可选参数 configPaths 指定候选配置文件路径(按顺序尝试,命中第一个存在的即停)。
- // 不传时使用默认路径 ["./.env", "./config.env"](后端主服务用)。
- // MCP 等独立进程可传入自己的配置文件,例如 LoadConfig("./config.mcp.env")。
- func LoadConfig(configPaths ...string) (*Config, error) {
- v := viper.New()
- // 默认值(避免缺省时崩溃)
- // APP
- v.SetDefault("APP_ENV", "dev")
- v.SetDefault("APP_PORT", "8080")
- v.SetDefault("REDIS_ADDR", "localhost:6379")
- v.SetDefault("MYSQL_DSN", "")
- v.SetDefault("POSTGRES_DSN", "host=localhost user=fwh_toolbox password=fwh_toolbox dbname=fwh_toolbox_db port=5432 sslmode=disable")
- v.SetDefault("MONGO_DSN", "mongodb://localhost:27017/FwhToolboxDbDev")
- v.SetDefault("MINIO_ENDPOINT", "localhost:9198")
- v.SetDefault("MINIO_ACCESS_KEY", "fwh-toolbox")
- v.SetDefault("MINIO_SECRET_KEY", "fwh-toolbox")
- v.SetDefault("MINIO_BUCKET_NAME", "fwh-toolbox")
- v.SetDefault("ASYNQMON_PORT", "8081")
- v.SetDefault("FWH_TOTP_VIEW_PORT", "8303")
- v.SetDefault("FWH_TOTP_VIEW_HOST", "127.0.0.1")
- // FWH API
- v.SetDefault("FWH_ENERGY", "energy.franklinwh.com")
- v.SetDefault("FWH_OSS", "oss.franklinwh.com")
- // FWH MQTT
- // FWH ES(iotcore-stat)
- v.SetDefault("FWH_ES_INDEX_PREFIX", "iotcore-stat")
- v.SetDefault("FWH_ES_INSECURE_SKIP_VERIFY", true)
- // 多文件路径支持:优先使用调用方传入的路径,否则回退默认
- paths := configPaths
- if len(paths) == 0 {
- paths = []string{"./.env", "./config.env"}
- }
- var readErr error
- for _, path := range paths {
- v.SetConfigFile(path)
- if err := v.ReadInConfig(); err == nil {
- fmt.Printf("✅ Using config file: %s\n", path)
- readErr = nil
- break
- } else {
- readErr = err
- }
- }
- // 环境变量覆盖文件配置
- v.AutomaticEnv()
- // 如果两个文件都没读到,也没关系,直接用默认值
- if readErr != nil {
- fmt.Println("⚠️ No config file found, using default values & environment variables")
- }
- // APP_ENV = v.GetString("APP_ENV")
- // FWH_ENERGY = v.GetString("FWH_ENERGY")
- // FWH_OSS = v.GetString("FWH_OSS")
- // FWH_USER = v.GetString("FWH_USER")
- // FWH_PASSWORD = v.GetString("FWH_PASSWORD")
- h := md5.New()
- h.Write([]byte(v.GetString("FWH_PASSWORD")))
- fwhApiPassword := hex.EncodeToString(h.Sum(nil))
- h = md5.New()
- h.Write([]byte(v.GetString("FWH_TEST_PASSWORD")))
- fwhTestApiPassword := hex.EncodeToString(h.Sum(nil))
- return &Config{
- App: AppConfig{
- AppEnv: v.GetString("APP_ENV"),
- AppPort: v.GetString("APP_PORT"),
- LogLevel: v.GetString("LOG_LEVEL"),
- RedisAddr: v.GetString("REDIS_ADDR"),
- MySQLDSN: v.GetString("MYSQL_DSN"),
- PostgresDSN: v.GetString("POSTGRES_DSN"),
- MongoDSN: v.GetString("MONGO_DSN"),
- MinIoEndpoint: v.GetString("MINIO_ENDPOINT"),
- MinioAccessKey: v.GetString("MINIO_ACCESS_KEY"),
- MinioSecretKey: v.GetString("MINIO_SECRET_KEY"),
- MinioBucketName: v.GetString("MINIO_BUCKET_NAME"),
- AsynqmonPort: v.GetString("ASYNQMON_PORT"),
- TotpViewPassword: v.GetString("FWH_TOTP_VIEW_PASSWORD"),
- TotpViewHost: v.GetString("FWH_TOTP_VIEW_HOST"),
- TotpViewPort: v.GetString("FWH_TOTP_VIEW_PORT"),
- },
- FwhApi: FwhApiConfig{
- FwhEnergy: v.GetString("FWH_ENERGY"),
- FwhOss: v.GetString("FWH_OSS"),
- FwhUser: v.GetString("FWH_USER"),
- FwhPassword: fwhApiPassword,
- FwhTotpSecret: v.GetString("FWH_TOTP_SECRET"),
- FwhTotpField: v.GetString("FWH_TOTP_FIELD"),
- },
- FwhTestApi: FwhApiConfig{
- FwhEnergy: v.GetString("FWH_TEST_ENERGY"),
- FwhOss: v.GetString("FWH_TEST_OSS"),
- FwhUser: v.GetString("FWH_TEST_USER"),
- FwhPassword: fwhTestApiPassword,
- },
- FwhMqtt: FwhMqttConfig{
- FwhMqttBroker: v.GetString("FWH_MQTT_BROKER"),
- FwhMqttCaUrl: v.GetString("FWH_MQTT_CA"),
- FwhMqttCertUrl: v.GetString("FWH_MQTT_CERT"),
- FwhMqttKeyUrl: v.GetString("FWH_MQTT_KEY"),
- },
- FwhTestMqtt: FwhMqttConfig{
- FwhMqttBroker: v.GetString("FWH_TEST_MQTT_BROKER"),
- FwhMqttCaUrl: v.GetString("FWH_TEST_MQTT_CA"),
- FwhMqttCertUrl: v.GetString("FWH_TEST_MQTT_CERT"),
- FwhMqttKeyUrl: v.GetString("FWH_TEST_MQTT_KEY"),
- },
- FwhEs: FwhEsConfig{
- EsHost: v.GetString("FWH_ES_HOST"),
- EsUser: v.GetString("FWH_ES_USER"),
- EsPassword: v.GetString("FWH_ES_PASSWORD"),
- EsIndexPrefix: v.GetString("FWH_ES_INDEX_PREFIX"),
- EsInsecureSkipVerify: v.GetBool("FWH_ES_INSECURE_SKIP_VERIFY"),
- },
- PlaneApi: PlaneApiConfig{
- Host: v.GetString("PLANE_HOST"),
- ApiKey: v.GetString("PLANE_API_KEY"),
- WorkspaceSlug: v.GetString("PLANE_WORKSPACE_SLUG"),
- ProjectId: v.GetString("PLANE_PROJECT_ID"),
- LabelBugId: v.GetString("PLANE_LABEL_BUG"),
- LabelFeatureId: v.GetString("PLANE_LABEL_FEATURE"),
- },
- PlaneWebApi: PlaneWebApiConfig{
- Host: v.GetString("PLANE_WEB_HOST"),
- Email: v.GetString("PLANE_WEB_EMAIL"),
- Password: v.GetString("PLANE_WEB_PASSWORD"),
- WorkspaceSlug: v.GetString("PLANE_WEB_WORKSPACE_SLUG"),
- ProjectId: v.GetString("PLANE_WEB_PROJECT_ID"),
- LabelBugId: v.GetString("PLANE_WEB_LABEL_BUG"),
- LabelFeatureId: v.GetString("PLANE_WEB_LABEL_FEATURE"),
- LabelFeedbackId: v.GetString("PLANE_WEB_LABEL_FEEDBACK"),
- },
- Kiro: KiroConfig{
- RunAsUser: v.GetString("KIRO_RUN_AS_USER"),
- Home: v.GetString("KIRO_HOME"),
- DebugLog: v.GetBool("KIRO_DEBUG_LOG"),
- },
- }, nil
- }
|