config.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. package config
  2. import (
  3. "crypto/md5"
  4. "encoding/hex"
  5. "fmt"
  6. "github.com/spf13/viper"
  7. )
  8. type AppConfig struct {
  9. AppEnv string
  10. AppPort string
  11. LogLevel string
  12. RedisAddr string
  13. MySQLDSN string
  14. PostgresDSN string
  15. MongoDSN string
  16. MinIoEndpoint string
  17. MinioAccessKey string
  18. MinioSecretKey string
  19. MinioBucketName string
  20. AsynqmonPort string
  21. TotpViewPassword string
  22. TotpViewHost string
  23. TotpViewPort string
  24. }
  25. type FwhApiConfig struct {
  26. FwhEnergy string
  27. FwhOss string
  28. FwhUser string
  29. FwhPassword string
  30. FwhTotpSecret string
  31. FwhTotpField string
  32. }
  33. type FwhMqttConfig struct {
  34. FwhMqttBroker string
  35. FwhMqttCaUrl string
  36. FwhMqttCertUrl string
  37. FwhMqttKeyUrl string
  38. }
  39. // FwhEsConfig Elasticsearch(iotcore-stat) 连接配置
  40. type FwhEsConfig struct {
  41. // EsHost 形如 "alb-prod.franklinwh.click:5603"(不含 scheme)
  42. EsHost string
  43. // EsUser / EsPassword basic auth 凭证
  44. EsUser string
  45. EsPassword string
  46. // EsIndexPrefix 索引前缀,形如 "iotcore-stat",
  47. // 实际索引名会拼接日期,如 "iotcore-stat-2026.09.07"
  48. EsIndexPrefix string
  49. // EsInsecureSkipVerify 是否跳过 TLS 证书校验(对应 curl -k)
  50. EsInsecureSkipVerify bool
  51. }
  52. type PlaneApiConfig struct {
  53. Host string
  54. ApiKey string
  55. WorkspaceSlug string
  56. ProjectId string
  57. LabelBugId string
  58. LabelFeatureId string
  59. }
  60. type PlaneWebApiConfig struct {
  61. Host string
  62. Email string
  63. Password string
  64. WorkspaceSlug string
  65. ProjectId string
  66. LabelBugId string
  67. LabelFeatureId string
  68. LabelFeedbackId string
  69. }
  70. type KiroConfig struct {
  71. // RunAsUser 指定拉起 kiro-cli 子进程时降权到的系统用户名。
  72. // 为空时表示不降权,沿用后台服务自身的运行用户。
  73. RunAsUser string
  74. // Home 指定拉起 kiro-cli 子进程时使用的 HOME 目录(即 $HOME 环境变量)。
  75. // kiro-cli 依赖 HOME 定位其配置与凭证。为空时回退到降权用户的家目录,
  76. // 若也无法推导则使用默认值。
  77. Home string
  78. // DebugLog 为调试日志总开关(宏开关)。
  79. // 开启后,拉起 kiro-cli 子进程时注入 KIRO_LOG_LEVEL=debug,
  80. // 让 kiro-cli 输出 debug 级日志,便于问题排查。
  81. // 由环境变量 KIRO_DEBUG_LOG 控制(true/1/on 开启,默认关闭)。
  82. DebugLog bool
  83. }
  84. type Config struct {
  85. App AppConfig
  86. FwhApi FwhApiConfig
  87. FwhTestApi FwhApiConfig
  88. FwhMqtt FwhMqttConfig
  89. FwhTestMqtt FwhMqttConfig
  90. FwhEs FwhEsConfig
  91. PlaneApi PlaneApiConfig
  92. PlaneWebApi PlaneWebApiConfig
  93. Kiro KiroConfig
  94. }
  95. // 需先执行LoadConfig后才能读取ENV
  96. // var APP_ENV string = "dev"
  97. // var FWH_ENERGY string = "energy.franklinwh.com"
  98. // var FWH_OSS string = "oss.franklinwh.com"
  99. // var FWH_USER string = ""
  100. // var FWH_PASSWORD string = "" // MD5 - PASSWORD
  101. // LoadConfig 读取配置文件和环境变量。
  102. // 可选参数 configPaths 指定候选配置文件路径(按顺序尝试,命中第一个存在的即停)。
  103. // 不传时使用默认路径 ["./.env", "./config.env"](后端主服务用)。
  104. // MCP 等独立进程可传入自己的配置文件,例如 LoadConfig("./config.mcp.env")。
  105. func LoadConfig(configPaths ...string) (*Config, error) {
  106. v := viper.New()
  107. // 默认值(避免缺省时崩溃)
  108. // APP
  109. v.SetDefault("APP_ENV", "dev")
  110. v.SetDefault("APP_PORT", "8080")
  111. v.SetDefault("REDIS_ADDR", "localhost:6379")
  112. v.SetDefault("MYSQL_DSN", "")
  113. v.SetDefault("POSTGRES_DSN", "host=localhost user=fwh_toolbox password=fwh_toolbox dbname=fwh_toolbox_db port=5432 sslmode=disable")
  114. v.SetDefault("MONGO_DSN", "mongodb://localhost:27017/FwhToolboxDbDev")
  115. v.SetDefault("MINIO_ENDPOINT", "localhost:9198")
  116. v.SetDefault("MINIO_ACCESS_KEY", "fwh-toolbox")
  117. v.SetDefault("MINIO_SECRET_KEY", "fwh-toolbox")
  118. v.SetDefault("MINIO_BUCKET_NAME", "fwh-toolbox")
  119. v.SetDefault("ASYNQMON_PORT", "8081")
  120. v.SetDefault("FWH_TOTP_VIEW_PORT", "8303")
  121. v.SetDefault("FWH_TOTP_VIEW_HOST", "127.0.0.1")
  122. // FWH API
  123. v.SetDefault("FWH_ENERGY", "energy.franklinwh.com")
  124. v.SetDefault("FWH_OSS", "oss.franklinwh.com")
  125. // FWH MQTT
  126. // FWH ES(iotcore-stat)
  127. v.SetDefault("FWH_ES_INDEX_PREFIX", "iotcore-stat")
  128. v.SetDefault("FWH_ES_INSECURE_SKIP_VERIFY", true)
  129. // 多文件路径支持:优先使用调用方传入的路径,否则回退默认
  130. paths := configPaths
  131. if len(paths) == 0 {
  132. paths = []string{"./.env", "./config.env"}
  133. }
  134. var readErr error
  135. for _, path := range paths {
  136. v.SetConfigFile(path)
  137. if err := v.ReadInConfig(); err == nil {
  138. fmt.Printf("✅ Using config file: %s\n", path)
  139. readErr = nil
  140. break
  141. } else {
  142. readErr = err
  143. }
  144. }
  145. // 环境变量覆盖文件配置
  146. v.AutomaticEnv()
  147. // 如果两个文件都没读到,也没关系,直接用默认值
  148. if readErr != nil {
  149. fmt.Println("⚠️ No config file found, using default values & environment variables")
  150. }
  151. // APP_ENV = v.GetString("APP_ENV")
  152. // FWH_ENERGY = v.GetString("FWH_ENERGY")
  153. // FWH_OSS = v.GetString("FWH_OSS")
  154. // FWH_USER = v.GetString("FWH_USER")
  155. // FWH_PASSWORD = v.GetString("FWH_PASSWORD")
  156. h := md5.New()
  157. h.Write([]byte(v.GetString("FWH_PASSWORD")))
  158. fwhApiPassword := hex.EncodeToString(h.Sum(nil))
  159. h = md5.New()
  160. h.Write([]byte(v.GetString("FWH_TEST_PASSWORD")))
  161. fwhTestApiPassword := hex.EncodeToString(h.Sum(nil))
  162. return &Config{
  163. App: AppConfig{
  164. AppEnv: v.GetString("APP_ENV"),
  165. AppPort: v.GetString("APP_PORT"),
  166. LogLevel: v.GetString("LOG_LEVEL"),
  167. RedisAddr: v.GetString("REDIS_ADDR"),
  168. MySQLDSN: v.GetString("MYSQL_DSN"),
  169. PostgresDSN: v.GetString("POSTGRES_DSN"),
  170. MongoDSN: v.GetString("MONGO_DSN"),
  171. MinIoEndpoint: v.GetString("MINIO_ENDPOINT"),
  172. MinioAccessKey: v.GetString("MINIO_ACCESS_KEY"),
  173. MinioSecretKey: v.GetString("MINIO_SECRET_KEY"),
  174. MinioBucketName: v.GetString("MINIO_BUCKET_NAME"),
  175. AsynqmonPort: v.GetString("ASYNQMON_PORT"),
  176. TotpViewPassword: v.GetString("FWH_TOTP_VIEW_PASSWORD"),
  177. TotpViewHost: v.GetString("FWH_TOTP_VIEW_HOST"),
  178. TotpViewPort: v.GetString("FWH_TOTP_VIEW_PORT"),
  179. },
  180. FwhApi: FwhApiConfig{
  181. FwhEnergy: v.GetString("FWH_ENERGY"),
  182. FwhOss: v.GetString("FWH_OSS"),
  183. FwhUser: v.GetString("FWH_USER"),
  184. FwhPassword: fwhApiPassword,
  185. FwhTotpSecret: v.GetString("FWH_TOTP_SECRET"),
  186. FwhTotpField: v.GetString("FWH_TOTP_FIELD"),
  187. },
  188. FwhTestApi: FwhApiConfig{
  189. FwhEnergy: v.GetString("FWH_TEST_ENERGY"),
  190. FwhOss: v.GetString("FWH_TEST_OSS"),
  191. FwhUser: v.GetString("FWH_TEST_USER"),
  192. FwhPassword: fwhTestApiPassword,
  193. },
  194. FwhMqtt: FwhMqttConfig{
  195. FwhMqttBroker: v.GetString("FWH_MQTT_BROKER"),
  196. FwhMqttCaUrl: v.GetString("FWH_MQTT_CA"),
  197. FwhMqttCertUrl: v.GetString("FWH_MQTT_CERT"),
  198. FwhMqttKeyUrl: v.GetString("FWH_MQTT_KEY"),
  199. },
  200. FwhTestMqtt: FwhMqttConfig{
  201. FwhMqttBroker: v.GetString("FWH_TEST_MQTT_BROKER"),
  202. FwhMqttCaUrl: v.GetString("FWH_TEST_MQTT_CA"),
  203. FwhMqttCertUrl: v.GetString("FWH_TEST_MQTT_CERT"),
  204. FwhMqttKeyUrl: v.GetString("FWH_TEST_MQTT_KEY"),
  205. },
  206. FwhEs: FwhEsConfig{
  207. EsHost: v.GetString("FWH_ES_HOST"),
  208. EsUser: v.GetString("FWH_ES_USER"),
  209. EsPassword: v.GetString("FWH_ES_PASSWORD"),
  210. EsIndexPrefix: v.GetString("FWH_ES_INDEX_PREFIX"),
  211. EsInsecureSkipVerify: v.GetBool("FWH_ES_INSECURE_SKIP_VERIFY"),
  212. },
  213. PlaneApi: PlaneApiConfig{
  214. Host: v.GetString("PLANE_HOST"),
  215. ApiKey: v.GetString("PLANE_API_KEY"),
  216. WorkspaceSlug: v.GetString("PLANE_WORKSPACE_SLUG"),
  217. ProjectId: v.GetString("PLANE_PROJECT_ID"),
  218. LabelBugId: v.GetString("PLANE_LABEL_BUG"),
  219. LabelFeatureId: v.GetString("PLANE_LABEL_FEATURE"),
  220. },
  221. PlaneWebApi: PlaneWebApiConfig{
  222. Host: v.GetString("PLANE_WEB_HOST"),
  223. Email: v.GetString("PLANE_WEB_EMAIL"),
  224. Password: v.GetString("PLANE_WEB_PASSWORD"),
  225. WorkspaceSlug: v.GetString("PLANE_WEB_WORKSPACE_SLUG"),
  226. ProjectId: v.GetString("PLANE_WEB_PROJECT_ID"),
  227. LabelBugId: v.GetString("PLANE_WEB_LABEL_BUG"),
  228. LabelFeatureId: v.GetString("PLANE_WEB_LABEL_FEATURE"),
  229. LabelFeedbackId: v.GetString("PLANE_WEB_LABEL_FEEDBACK"),
  230. },
  231. Kiro: KiroConfig{
  232. RunAsUser: v.GetString("KIRO_RUN_AS_USER"),
  233. Home: v.GetString("KIRO_HOME"),
  234. DebugLog: v.GetBool("KIRO_DEBUG_LOG"),
  235. },
  236. }, nil
  237. }