package config import ( "encoding/json" "errors" "os" "strconv" "time" ) // Config 包含运行时、上报、采集与服务注册相关的全部配置项。 type Config struct { HostID string `json:"host_id"` HTTP HTTPConfig `json:"http"` Collect CollectConfig `json:"collect"` Report ReportConfig `json:"report"` Service ServiceConfig `json:"service"` } // HTTPConfig 控制本地 HTTP API 的监听地址。 type HTTPConfig struct { ListenAddress string `json:"listen_address"` } // CollectConfig 控制周期性主机状态采集。 type CollectConfig struct { Interval Duration `json:"interval"` Timeout Duration `json:"timeout"` } // ReportConfig 控制可选的周期性状态 POST 上报。 type ReportConfig struct { Enabled bool `json:"enabled"` Endpoint string `json:"endpoint"` Interval Duration `json:"interval"` Timeout Duration `json:"timeout"` } // ServiceConfig 控制操作系统服务注册时使用的元数据。 type ServiceConfig struct { Name string `json:"name"` DisplayName string `json:"display_name"` Description string `json:"description"` } // Duration 封装 time.Duration,使 JSON 配置可使用 Go 时长字符串(如 "30s")。 type Duration time.Duration // Duration 返回标准库的 time.Duration 值。 func (d Duration) Duration() time.Duration { return time.Duration(d) } // MarshalJSON 将时长序列化为 Go 时长字符串,例如 "30s"。 func (d Duration) MarshalJSON() ([]byte, error) { return json.Marshal(time.Duration(d).String()) } // UnmarshalJSON 从 JSON 解析 Go 时长字符串。 func (d *Duration) UnmarshalJSON(data []byte) error { var raw string if err := json.Unmarshal(data, &raw); err != nil { return err } parsed, err := time.ParseDuration(raw) if err != nil { return err } *d = Duration(parsed) return nil } // Default 返回适合本地运行的安全默认配置。 func Default() Config { return Config{ HTTP: HTTPConfig{ListenAddress: "127.0.0.1:8080"}, Collect: CollectConfig{ Interval: Duration(30 * time.Second), Timeout: Duration(10 * time.Second), }, Report: ReportConfig{ Enabled: false, Interval: Duration(60 * time.Second), Timeout: Duration(5 * time.Second), }, Service: ServiceConfig{ Name: "mfd-monitor-agent", DisplayName: "MFD Monitor Agent", Description: "Collects host status and exposes it over HTTP.", }, } } // Load 读取可选的 JSON 配置文件,应用环境变量覆盖,并校验必填项。 func Load(path string) (Config, error) { cfg := Default() if path != "" { data, err := os.ReadFile(path) if err != nil { return cfg, err } if err := json.Unmarshal(data, &cfg); err != nil { return cfg, err } } applyEnv(&cfg) if cfg.Report.Enabled && cfg.Report.Endpoint == "" { return cfg, errors.New("report endpoint is required when reporting is enabled") } return cfg, nil } // applyEnv 将支持的 MFD_AGENT_* 环境变量覆盖到 cfg 上。 func applyEnv(cfg *Config) { if value := os.Getenv("MFD_AGENT_HOST_ID"); value != "" { cfg.HostID = value } if value := os.Getenv("MFD_AGENT_LISTEN"); value != "" { cfg.HTTP.ListenAddress = value } if value := os.Getenv("MFD_AGENT_REPORT_ENABLED"); value != "" { if parsed, err := strconv.ParseBool(value); err == nil { cfg.Report.Enabled = parsed } } if value := os.Getenv("MFD_AGENT_REPORT_ENDPOINT"); value != "" { cfg.Report.Endpoint = value } if value := os.Getenv("MFD_AGENT_REPORT_INTERVAL"); value != "" { if parsed, err := time.ParseDuration(value); err == nil { cfg.Report.Interval = Duration(parsed) } } if value := os.Getenv("MFD_AGENT_REPORT_TIMEOUT"); value != "" { if parsed, err := time.ParseDuration(value); err == nil { cfg.Report.Timeout = Duration(parsed) } } if value := os.Getenv("MFD_AGENT_COLLECT_INTERVAL"); value != "" { if parsed, err := time.ParseDuration(value); err == nil { cfg.Collect.Interval = Duration(parsed) } } if value := os.Getenv("MFD_AGENT_COLLECT_TIMEOUT"); value != "" { if parsed, err := time.ParseDuration(value); err == nil { cfg.Collect.Timeout = Duration(parsed) } } }