release: v0.2.0
Some checks failed
Release / Build & Release (push) Has been cancelled

Comprehensive release containing structural, UX, and behavioral upgrades since v0.1.0:

1. Namespace Transition: Renamed core executable and project namespaces from 'smart-monitor' to 'smart-shutdown'.
2. Objective Vocabulary Refactoring: Normalized output strings and logging descriptors system-wide to a strict, professional tone.
3. Advanced Status Query: 'status' subcommand now retrieves the parsed configuration, log locations/sizes, and tails the last 10 lines of the local log file.
4. Runtime Configuration Setter: Introduced 'config set' subcommand to modify the configuration file with strict type validations.
5. Auto-System Deployment: Remapped 'install' to clone the executable into system domains and register global PATH variables.
6. Cleaner Removal: 'uninstall' purges binary clones and clears environmental variables, leaving zero traces.
7. Documentation Rewrite: Generated an objective README file featuring copy-paste ready Markdown blocks.
This commit is contained in:
2026-03-24 16:07:22 +08:00
parent 3525a59976
commit 3be3e19e49
10 changed files with 243 additions and 237 deletions

View File

@@ -2,20 +2,21 @@ package config
import (
"encoding/json"
"fmt"
"net"
"os"
"path/filepath"
"runtime"
"strconv"
)
// Config 存储程序的各类配置常量,支持通过读取 json 文件动态修改
type Config struct {
TargetIP string `json:"TargetIP"` // 检测目标 IP默认 192.168.3.3
MonitorWindowSeconds int `json:"MonitorWindowSeconds"` // 监控窗口期内持续失败才触发关机
ShutdownCountdown int `json:"ShutdownCountdown"` // 关机倒计时时间
NormalPingInterval int `json:"NormalPingInterval"` // 正常状态下的 ping 间隔
TargetIP string `json:"TargetIP"`
MonitorWindowSeconds int `json:"MonitorWindowSeconds"`
ShutdownCountdown int `json:"ShutdownCountdown"`
NormalPingInterval int `json:"NormalPingInterval"`
}
// DefaultConfig 提供一套开箱即用的默认配置
func DefaultConfig() *Config {
return &Config{
TargetIP: "192.168.3.3",
@@ -25,7 +26,6 @@ func DefaultConfig() *Config {
}
}
// GetConfigDir 根据当前操作系统返回标准的配置存放路径
func GetConfigDir() string {
if runtime.GOOS == "windows" {
return `C:\ProgramData\SmartNetworkMonitor`
@@ -33,7 +33,6 @@ func GetConfigDir() string {
return `/etc/smart-network-monitor`
}
// GetLogDir 根据当前操作系统返回标准的日志存放路径
func GetLogDir() string {
if runtime.GOOS == "windows" {
return `C:\ProgramData\SmartNetworkMonitor\logs`
@@ -41,7 +40,6 @@ func GetLogDir() string {
return `/var/log/smart-network-monitor`
}
// LoadConfig 从系统标准路径读取 config.json 并反序列化。如果不存在,则返回默认配置。
func LoadConfig() (*Config, error) {
configDir := GetConfigDir()
configPath := filepath.Join(configDir, "config.json")
@@ -49,7 +47,6 @@ func LoadConfig() (*Config, error) {
data, err := os.ReadFile(configPath)
if err != nil {
if os.IsNotExist(err) {
// 文件不存在时,静默采用默认配置
return DefaultConfig(), nil
}
return nil, err
@@ -65,3 +62,54 @@ func LoadConfig() (*Config, error) {
}
return cfg, nil
}
func SaveConfig(cfg *Config) error {
configDir := GetConfigDir()
if err := os.MkdirAll(configDir, 0755); err != nil {
return err
}
configPath := filepath.Join(configDir, "config.json")
data, err := json.MarshalIndent(cfg, "", " ")
if err != nil {
return err
}
return os.WriteFile(configPath, data, 0644)
}
func UpdateConfig(key string, value string) error {
cfg, err := LoadConfig()
if err != nil {
return fmt.Errorf("加载配置文件失败: %v", err)
}
switch key {
case "TargetIP":
if net.ParseIP(value) == nil {
return fmt.Errorf("非法 IP 地址: %s", value)
}
cfg.TargetIP = value
case "MonitorWindowSeconds":
val, err := strconv.Atoi(value)
if err != nil || val <= 0 {
return fmt.Errorf("非法输入: MonitorWindowSeconds 必须为正整数")
}
cfg.MonitorWindowSeconds = val
case "ShutdownCountdown":
val, err := strconv.Atoi(value)
if err != nil || val <= 0 {
return fmt.Errorf("非法输入: ShutdownCountdown 必须为正整数")
}
cfg.ShutdownCountdown = val
case "NormalPingInterval":
val, err := strconv.Atoi(value)
if err != nil || val <= 0 {
return fmt.Errorf("非法输入: NormalPingInterval 必须为正整数")
}
cfg.NormalPingInterval = val
default:
return fmt.Errorf("未知配置项: %s (开放编辑项: TargetIP, MonitorWindowSeconds, ShutdownCountdown, NormalPingInterval)", key)
}
return SaveConfig(cfg)
}