package main import ( "fmt" "io" "net" "net/http" "os" "path/filepath" "strings" "time" "git.asio.asia/nixevol/NixMsg/internal/config" ) // healthcheck 请求本机 /healthz,成功退出 0。给 Docker HEALTHCHECK 用。 func cmdHealthcheck(_ []string) error { cfgPath := config.PathFromEnv() cfg, err := config.Load(cfgPath) if err != nil { // 无配置时仍尝试 data_dir 默认值下的 listen.addr cfg = config.Default() } addr, err := resolveHealthAddr(cfg.DataDir, cfg.Listen) if err != nil { return err } url := "http://" + addr + "/healthz" client := &http.Client{Timeout: 3 * time.Second} resp, err := client.Get(url) if err != nil { return fmt.Errorf("healthcheck %s: %w", url, err) } defer func() { _ = resp.Body.Close() }() _, _ = io.Copy(io.Discard, resp.Body) if resp.StatusCode != http.StatusOK { return fmt.Errorf("healthcheck %s: status %d", url, resp.StatusCode) } return nil } func resolveHealthAddr(dataDir, listen string) (string, error) { path := filepath.Join(dataDir, "listen.addr") if b, err := os.ReadFile(path); err == nil { addr := strings.TrimSpace(string(b)) if addr != "" { return rewriteLoopback(addr), nil } } if listen == "" { return "", fmt.Errorf("no listen.addr and empty listen") } host, port, err := net.SplitHostPort(listen) if err != nil { // listen 可能是 ":7443" if strings.HasPrefix(listen, ":") { return "127.0.0.1" + listen, nil } return "", fmt.Errorf("parse listen %q: %w", listen, err) } if host == "" || host == "0.0.0.0" || host == "::" { host = "127.0.0.1" } return net.JoinHostPort(host, port), nil } func rewriteLoopback(addr string) string { host, port, err := net.SplitHostPort(addr) if err != nil { return addr } if host == "" || host == "0.0.0.0" || host == "::" { host = "127.0.0.1" } return net.JoinHostPort(host, port) }