feat: client config from yaml with interval/reconnect settings

This commit is contained in:
ngfchl
2026-06-19 16:46:41 +08:00
parent 22fb7e2c84
commit 742928a93d
2 changed files with 78 additions and 23 deletions
+13
View File
@@ -0,0 +1,13 @@
# Hardware Monitor Client 配置
#
# machine_name : 设备名称 (默认使用主机名)
# server : 服务端地址 (ip:port)
# interval : 采集间隔 (秒, 默认 3)
# reconnect_delay : 断线重连间隔 (秒, 默认 3)
#
# 删除此文件可重新配置
machine_name: my-pc
server: 192.168.1.100:8080
interval: 3
reconnect_delay: 3
+65 -23
View File
@@ -33,34 +33,56 @@ var (
// ═══════════════════════════════════════════════
type ClientConfig struct {
MachineName string `yaml:"machine_name"`
Server string `yaml:"server"`
MachineName string `yaml:"machine_name"`
Server string `yaml:"server"`
Interval int `yaml:"interval"`
ReconnectDelay int `yaml:"reconnect_delay"`
}
func defaultConfig() ClientConfig {
return ClientConfig{
Interval: 3,
ReconnectDelay: 3,
}
}
func configPath() string {
exe, err := os.Executable()
if err != nil {
return "client.yaml"
// 优先: 当前工作目录
if wd, err := os.Getwd(); err == nil {
p := filepath.Join(wd, "client.yaml")
if _, err := os.Stat(p); err == nil {
return p
}
}
return filepath.Join(filepath.Dir(exe), "client.yaml")
// 其次: 可执行文件目录
if exe, err := os.Executable(); err == nil {
return filepath.Join(filepath.Dir(exe), "client.yaml")
}
return "client.yaml"
}
func loadConfig() (ClientConfig, bool) {
p := configPath()
raw, err := os.ReadFile(p)
if err != nil {
return ClientConfig{}, false
return defaultConfig(), false
}
var c ClientConfig
if yaml.Unmarshal(raw, &c) != nil {
return ClientConfig{}, false
cfg := defaultConfig()
if yaml.Unmarshal(raw, &cfg) != nil {
return defaultConfig(), false
}
c.MachineName = strings.TrimSpace(c.MachineName)
c.Server = strings.TrimSpace(c.Server)
if c.MachineName == "" || c.Server == "" {
return ClientConfig{}, false
cfg.MachineName = strings.TrimSpace(cfg.MachineName)
cfg.Server = strings.TrimSpace(cfg.Server)
if cfg.MachineName == "" || cfg.Server == "" {
return defaultConfig(), false
}
return c, true
if cfg.Interval <= 0 {
cfg.Interval = 3
}
if cfg.ReconnectDelay <= 0 {
cfg.ReconnectDelay = 3
}
return cfg, true
}
func saveConfig(c ClientConfig) error {
@@ -68,7 +90,14 @@ func saveConfig(c ClientConfig) error {
if err != nil {
return err
}
hdr := "# Monitor Client 配置\n# 删除此文件可重新输入设备信息\n\n"
hdr := "# Hardware Monitor Client 配置\n"
hdr += "#\n"
hdr += "# machine_name : 设备名称 (默认使用主机名)\n"
hdr += "# server : 服务端地址 (ip:port)\n"
hdr += "# interval : 采集间隔 (秒, 默认 3)\n"
hdr += "# reconnect_delay : 断线重连间隔 (秒, 默认 3)\n"
hdr += "#\n"
hdr += "# 删除此文件可重新配置\n\n"
p := configPath()
os.MkdirAll(filepath.Dir(p), 0755)
return os.WriteFile(p, append([]byte(hdr), out...), 0644)
@@ -414,7 +443,10 @@ func (m model) handleEnter() (tea.Model, tea.Cmd) {
addr += ":8080"
}
m.cfg = ClientConfig{MachineName: name, Server: addr}
cfg := defaultConfig()
cfg.MachineName = name
cfg.Server = addr
m.cfg = cfg
saveConfig(m.cfg)
// 切换到监控阶段
@@ -869,6 +901,15 @@ func runCollector(done <-chan struct{}, cfg ClientConfig, dataCh chan<- MachineD
// 预热
cpu.Percent(500*time.Millisecond, true)
interval := time.Duration(cfg.Interval) * time.Second
if interval < time.Second {
interval = 3 * time.Second
}
reconnect := time.Duration(cfg.ReconnectDelay) * time.Second
if reconnect < time.Second {
reconnect = 3 * time.Second
}
for {
select {
case <-done:
@@ -877,7 +918,7 @@ func runCollector(done <-chan struct{}, cfg ClientConfig, dataCh chan<- MachineD
}
wsURL := "ws://" + cfg.Server + "/ws/agent"
err := collectLoop(done, wsURL, cfg.MachineName, dataCh, statCh)
err := collectLoop(done, wsURL, cfg.MachineName, interval, dataCh, statCh)
if err != nil {
select {
case statCh <- false:
@@ -889,12 +930,12 @@ func runCollector(done <-chan struct{}, cfg ClientConfig, dataCh chan<- MachineD
select {
case <-done:
return
case <-time.After(3 * time.Second):
case <-time.After(reconnect):
}
}
}
func collectLoop(done <-chan struct{}, wsURL, name string, dataCh chan<- MachineData, statCh chan<- bool) error {
func collectLoop(done <-chan struct{}, wsURL, name string, interval time.Duration, dataCh chan<- MachineData, statCh chan<- bool) error {
conn, _, err := websocket.DefaultDialer.Dial(wsURL, nil)
if err != nil {
return err
@@ -913,8 +954,8 @@ func collectLoop(done <-chan struct{}, wsURL, name string, dataCh chan<- Machine
default:
}
// 采集 CPU 使用率 (阻塞 ~3s)
perCore, _ := cpu.Percent(3*time.Second, true)
// 采集 CPU 使用率
perCore, _ := cpu.Percent(interval, true)
data := collectAll(name, perCore)
@@ -1130,9 +1171,10 @@ func main() {
cfg, loaded := loadConfig()
if loaded {
fmt.Printf(" [✓] 加载配置: %s\n", configPath())
fmt.Printf(" [✓] 配置文件: %s\n", configPath())
fmt.Printf(" [✓] 设备名称: %s\n", cfg.MachineName)
fmt.Printf(" [✓] 服务端 : %s\n", cfg.Server)
fmt.Printf(" [✓] 采集间隔: %ds\n", cfg.Interval)
fmt.Println()
}