feat: add interactive config setup on first start, install scripts, and uninstall cleanup
This commit is contained in:
@@ -19,7 +19,7 @@ type Config struct {
|
||||
|
||||
func DefaultConfig() *Config {
|
||||
return &Config{
|
||||
TargetIP: "192.168.3.3",
|
||||
TargetIP: "192.168.3.1",
|
||||
MonitorWindowSeconds: 180,
|
||||
ShutdownCountdown: 60,
|
||||
NormalPingInterval: 15,
|
||||
|
||||
124
pkg/config/interactive.go
Normal file
124
pkg/config/interactive.go
Normal file
@@ -0,0 +1,124 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ConfigFileExists checks if the config.json file exists at the expected location.
|
||||
func ConfigFileExists() bool {
|
||||
configPath := filepath.Join(GetConfigDir(), "config.json")
|
||||
_, err := os.Stat(configPath)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// isTerminal checks if stdin is connected to a terminal (not a pipe).
|
||||
func isTerminal() bool {
|
||||
fi, err := os.Stdin.Stat()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return fi.Mode()&os.ModeCharDevice != 0
|
||||
}
|
||||
|
||||
// InteractiveSetup prompts the user to configure each parameter interactively.
|
||||
// If stdin is not a terminal (pipe mode), it silently saves and returns defaults.
|
||||
func InteractiveSetup() (*Config, error) {
|
||||
cfg := DefaultConfig()
|
||||
|
||||
if !isTerminal() {
|
||||
if err := SaveConfig(cfg); err != nil {
|
||||
return nil, fmt.Errorf("写入默认配置失败: %v", err)
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
fmt.Println("\n========== 首次配置 ==========")
|
||||
fmt.Println("未检测到配置文件,将引导您完成初始设置。直接按回车使用 [默认值]。")
|
||||
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
|
||||
cfg.TargetIP = promptString(scanner, "目标监控 IP 地址", cfg.TargetIP, func(s string) error {
|
||||
if net.ParseIP(s) == nil {
|
||||
return fmt.Errorf("非法 IP 地址: %s", s)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
cfg.MonitorWindowSeconds = promptInt(scanner, "断网容忍超时时长 (秒)", cfg.MonitorWindowSeconds)
|
||||
cfg.ShutdownCountdown = promptInt(scanner, "关机倒计时缓冲 (秒)", cfg.ShutdownCountdown)
|
||||
cfg.NormalPingInterval = promptInt(scanner, "探测发包间隔 (秒)", cfg.NormalPingInterval)
|
||||
|
||||
if err := SaveConfig(cfg); err != nil {
|
||||
return nil, fmt.Errorf("写入配置文件失败: %v", err)
|
||||
}
|
||||
|
||||
configPath := filepath.Join(GetConfigDir(), "config.json")
|
||||
fmt.Printf("\n配置已保存至: %s\n", configPath)
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// ConfirmConfigCleanup prompts the user to confirm deletion of config and log files.
|
||||
// Returns true if the user confirms. Non-terminal stdin defaults to no.
|
||||
func ConfirmConfigCleanup() bool {
|
||||
if !isTerminal() {
|
||||
return false
|
||||
}
|
||||
|
||||
configDir := GetConfigDir()
|
||||
configPath := filepath.Join(configDir, "config.json")
|
||||
if _, err := os.Stat(configPath); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
fmt.Printf("检测到配置文件: %s\n是否一并清除配置文件与日志?[y/N]: ", configDir)
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
if scanner.Scan() {
|
||||
return strings.EqualFold(strings.TrimSpace(scanner.Text()), "y")
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func promptString(scanner *bufio.Scanner, label, defaultVal string, validate func(string) error) string {
|
||||
for {
|
||||
fmt.Printf("\n%s [%s]: ", label, defaultVal)
|
||||
if !scanner.Scan() {
|
||||
return defaultVal
|
||||
}
|
||||
input := strings.TrimSpace(scanner.Text())
|
||||
if input == "" {
|
||||
return defaultVal
|
||||
}
|
||||
if validate != nil {
|
||||
if err := validate(input); err != nil {
|
||||
fmt.Printf(" 输入无效: %v,请重新输入。\n", err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
return input
|
||||
}
|
||||
}
|
||||
|
||||
func promptInt(scanner *bufio.Scanner, label string, defaultVal int) int {
|
||||
for {
|
||||
fmt.Printf("%s [%d]: ", label, defaultVal)
|
||||
if !scanner.Scan() {
|
||||
return defaultVal
|
||||
}
|
||||
input := strings.TrimSpace(scanner.Text())
|
||||
if input == "" {
|
||||
return defaultVal
|
||||
}
|
||||
val, err := strconv.Atoi(input)
|
||||
if err != nil || val <= 0 {
|
||||
fmt.Println(" 输入无效: 必须为正整数,请重新输入。")
|
||||
continue
|
||||
}
|
||||
return val
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user