diff --git a/README.md b/README.md deleted file mode 100644 index 65e82b2..0000000 --- a/README.md +++ /dev/null @@ -1,122 +0,0 @@ -# 智能网络监控脚本 - 系统部署版 - -## 📁 文件结构 - -``` -smart_shutdown/ -├── smart_shutdown.ps1 # 原始监控脚本(用户模式) -├── deploy_system.ps1 # 系统级部署脚本 -├── uninstall_system.ps1 # 系统级卸载脚本 -├── TEST_REPORT.md # 测试报告 -├── README.md # 本文件 -└── logs/ # 本地测试日志目录 - └── network_monitor_20250606.log -``` - -## 🚀 快速部署 - -### 系统级部署(推荐) -```powershell -# 以管理员身份运行 -.\deploy_system.ps1 -``` - -**部署效果:** -- 程序部署到:`C:\Program Files\SmartNetworkMonitor\` -- 配置和日志:`C:\ProgramData\SmartNetworkMonitor\` -- 开机自启动,无需用户登录 -- 以 SYSTEM 权限运行 - -### 用户级运行 -```powershell -# 以管理员身份运行(需要用户登录) -.\smart_shutdown.ps1 -``` - -## 🎯 系统部署后的文件位置 - -### 程序文件位置 -``` -C:\Program Files\SmartNetworkMonitor\ -├── smart_shutdown_system.ps1 # 系统优化版监控脚本 -└── manage.ps1 # 管理工具脚本 -``` - -### 数据文件位置 -``` -C:\ProgramData\SmartNetworkMonitor\ -├── config.json # 配置文件 -└── logs\ # 系统日志目录 - └── network_monitor_YYYYMMDD.log -``` - -## 🔧 管理命令 - -### 查看任务状态 -```powershell -Get-ScheduledTask -TaskName "Smart Network Shutdown Monitor" -``` - -### 启动/停止监控 -```powershell -Start-ScheduledTask -TaskName "Smart Network Shutdown Monitor" -Stop-ScheduledTask -TaskName "Smart Network Shutdown Monitor" -``` - -### 查看日志 -```powershell -# 查看今天的日志 -Get-Content "C:\ProgramData\SmartNetworkMonitor\logs\network_monitor_$(Get-Date -Format 'yyyyMMdd').log" - -# 实时监控日志 -Get-Content "C:\ProgramData\SmartNetworkMonitor\logs\network_monitor_$(Get-Date -Format 'yyyyMMdd').log" -Wait -``` - -### 查看系统事件日志 -```powershell -Get-EventLog -LogName Application -Source SmartNetworkMonitor -Newest 20 -``` - -## ⚙️ 配置说明 - -系统部署后,配置文件位于:`C:\ProgramData\SmartNetworkMonitor\config.json` - -默认配置: -```json -{ - "TargetIP": "192.168.3.3", - "MonitorWindowSeconds": 180, - "ShutdownCountdown": 60, - "NormalPingInterval": 15 -} -``` - -修改配置文件后,重启监控任务使配置生效: -```powershell -Stop-ScheduledTask -TaskName "Smart Network Shutdown Monitor" -Start-ScheduledTask -TaskName "Smart Network Shutdown Monitor" -``` - -## 🗑️ 卸载 - -```powershell -# 以管理员身份运行 -.\uninstall_system.ps1 -``` - -## 📊 特性 - -- ✅ 开机自启动,无需用户登录 -- ✅ 系统级权限运行 -- ✅ 智能日志管理 -- ✅ 配置文件支持 -- ✅ 事件日志备份 -- ✅ 自动日志清理(30天) -- ✅ 网络恢复自动取消关机 -- ✅ 完整的错误处理 - -## 🔐 安全说明 - -- 脚本以 SYSTEM 权限运行,具有执行关机的完整权限 -- 所有操作都会记录在日志和系统事件日志中 -- 支持通过任务计划程序进行管理和监控 diff --git a/README_Ubuntu.md b/README_Ubuntu.md deleted file mode 100644 index 9db9a3c..0000000 --- a/README_Ubuntu.md +++ /dev/null @@ -1,290 +0,0 @@ -# 智能网络监控脚本 - Ubuntu版本 - -## 📁 项目结构 - -``` -smart-shutdown/ -├── smart_shutdown.sh # 主监控脚本(用户模式) -├── deploy_system.sh # 系统级部署脚本 -├── uninstall_system.sh # 系统级卸载脚本 -├── manage.sh # 管理工具脚本 -├── README.md # 本文件 -└── logs/ # 本地运行时的日志目录 - └── network_monitor_YYYYMMDD.log -``` - -## 🚀 快速开始 - -### 系统级部署(推荐) - -```bash -# 1. 克隆或下载项目到本地 -cd /path/to/smart-shutdown/ - -# 2. 以root权限运行部署脚本 -sudo ./deploy_system.sh -``` - -**部署效果:** -- 程序文件:`/opt/smart-network-monitor/` -- 配置文件:`/etc/smart-network-monitor/config.json` -- 日志文件:`/var/log/smart-network-monitor/` -- systemd服务:`smart-network-monitor.service` -- 开机自启动,无需用户登录 - -### 用户级运行 - -```bash -# 以root权限直接运行(需要用户登录) -sudo ./smart_shutdown.sh -``` - -## 🎯 系统部署后的文件位置 - -### 程序文件位置 -``` -/opt/smart-network-monitor/ -├── smart_shutdown_system.sh # 系统优化版监控脚本 -└── manage.sh # 管理工具脚本 -``` - -### 配置文件位置 -``` -/etc/smart-network-monitor/ -└── config.json # 配置文件 -``` - -### 日志文件位置 -``` -/var/log/smart-network-monitor/ -└── network_monitor_YYYYMMDD.log # 日志文件 -``` - -## 🔧 管理命令 - -### 使用管理工具(推荐) -```bash -# 使用快捷命令(系统安装后可用) -smart-monitor - -# 或者直接运行管理脚本 -sudo /opt/smart-network-monitor/manage.sh -``` - -### 直接使用systemctl命令 - -#### 查看服务状态 -```bash -systemctl status smart-network-monitor -``` - -#### 启动/停止/重启服务 -```bash -sudo systemctl start smart-network-monitor -sudo systemctl stop smart-network-monitor -sudo systemctl restart smart-network-monitor -``` - -#### 启用/禁用开机自启动 -```bash -sudo systemctl enable smart-network-monitor -sudo systemctl disable smart-network-monitor -``` - -### 查看日志 - -#### 查看今天的应用日志 -```bash -cat /var/log/smart-network-monitor/network_monitor_$(date '+%Y%m%d').log -``` - -#### 实时监控应用日志 -```bash -tail -f /var/log/smart-network-monitor/network_monitor_$(date '+%Y%m%d').log -``` - -#### 查看系统日志 -```bash -# 查看最近的系统日志 -journalctl -u smart-network-monitor -n 50 - -# 实时监控系统日志 -journalctl -u smart-network-monitor -f -``` - -## ⚙️ 配置说明 - -系统部署后,配置文件位于:`/etc/smart-network-monitor/config.json` - -### 默认配置 -```json -{ - "TargetIP": "192.168.3.3", - "MonitorWindowSeconds": 180, - "ShutdownCountdown": 60, - "NormalPingInterval": 15 -} -``` - -### 配置参数说明 -- `TargetIP`: 监控的目标IP地址 -- `MonitorWindowSeconds`: 监控窗口时长(秒),网络持续中断超过此时间将触发关机 -- `ShutdownCountdown`: 关机倒计时时长(秒) -- `NormalPingInterval`: 正常监控时的ping间隔(秒) - -### 修改配置 -```bash -# 使用管理工具编辑(推荐) -smart-monitor - -# 或直接编辑配置文件 -sudo nano /etc/smart-network-monitor/config.json - -# 修改配置后重启服务使配置生效 -sudo systemctl restart smart-network-monitor -``` - -## 🗑️ 卸载 - -```bash -# 运行卸载脚本 -sudo ./uninstall_system.sh -``` - -卸载脚本会询问是否删除配置文件和日志文件,您可以选择保留或删除。 - -## 📊 功能特性 - -- ✅ 开机自启动,无需用户登录 -- ✅ 系统级权限运行 -- ✅ 智能日志管理(应用日志 + 系统日志) -- ✅ JSON配置文件支持 -- ✅ 自动日志清理(30天) -- ✅ 网络恢复自动取消关机 -- ✅ 完整的错误处理和信号处理 -- ✅ 彩色终端输出 -- ✅ 交互式管理工具 - -## 🔧 系统要求 - -### 必需软件包 -- `ping` (通常已预装) -- `systemctl` (systemd) -- `journalctl` (systemd) - -### 推荐软件包 -```bash -# 安装jq以获得更好的JSON配置支持 -sudo apt-get update -sudo apt-get install jq -``` - -### 支持的系统 -- Ubuntu 16.04+ (带systemd) -- Debian 8+ (带systemd) -- 其他使用systemd的Linux发行版 - -## 🔐 安全说明 - -- 脚本需要root权限以执行关机操作 -- systemd服务以root权限运行 -- 所有操作都会记录在应用日志和系统日志中 -- 支持通过systemd进行完整的服务管理和监控 - -## 📝 使用示例 - -### 1. 基本使用流程 - -```bash -# 1. 部署系统级服务 -sudo ./deploy_system.sh - -# 2. 检查服务状态 -systemctl status smart-network-monitor - -# 3. 查看实时日志 -journalctl -u smart-network-monitor -f - -# 4. 使用管理工具 -smart-monitor -``` - -### 2. 自定义配置示例 - -```bash -# 编辑配置文件 -sudo nano /etc/smart-network-monitor/config.json - -# 修改为监控路由器 -{ - "TargetIP": "192.168.1.1", - "MonitorWindowSeconds": 300, - "ShutdownCountdown": 120, - "NormalPingInterval": 30 -} - -# 重启服务应用配置 -sudo systemctl restart smart-network-monitor -``` - -### 3. 故障排除 - -```bash -# 查看服务详细状态 -systemctl status smart-network-monitor -l - -# 查看最近的错误日志 -journalctl -u smart-network-monitor --since "1 hour ago" - -# 测试网络连接 -ping -c 4 192.168.3.3 - -# 手动运行脚本进行调试 -sudo /opt/smart-network-monitor/smart_shutdown_system.sh -``` - -## 🚨 注意事项 - -1. **关机权限**:脚本需要root权限才能执行关机操作 -2. **网络依赖**:确保目标IP地址可达且稳定响应ping -3. **测试模式**:默认脚本在关机时会输出模拟信息,取消注释 `shutdown -h now` 行以启用实际关机 -4. **备份重要数据**:在启用实际关机功能前,请确保重要数据已备份 -5. **防火墙设置**:确保ICMP ping包不被防火墙阻挡 - -## 🔗 相关命令速查 - -```bash -# 服务管理 -sudo systemctl start smart-network-monitor # 启动 -sudo systemctl stop smart-network-monitor # 停止 -sudo systemctl restart smart-network-monitor # 重启 -sudo systemctl status smart-network-monitor # 状态 -sudo systemctl enable smart-network-monitor # 开机启动 -sudo systemctl disable smart-network-monitor # 禁用启动 - -# 日志查看 -journalctl -u smart-network-monitor # 所有日志 -journalctl -u smart-network-monitor -f # 实时日志 -journalctl -u smart-network-monitor -n 50 # 最近50行 -tail -f /var/log/smart-network-monitor/network_monitor_$(date '+%Y%m%d').log # 应用日志 - -# 配置管理 -sudo nano /etc/smart-network-monitor/config.json # 编辑配置 -cat /etc/smart-network-monitor/config.json # 查看配置 - -# 管理工具 -smart-monitor # 交互式管理 -``` - -## 📞 技术支持 - -如果您在使用过程中遇到问题,请: - -1. 检查系统日志:`journalctl -u smart-network-monitor -n 100` -2. 验证网络连接:`ping 目标IP` -3. 检查配置文件格式:`jq . /etc/smart-network-monitor/config.json` -4. 查看服务状态:`systemctl status smart-network-monitor -l` - ---- - -**享受智能网络监控带来的便利!** 🎉 \ No newline at end of file diff --git a/TEST_REPORT.md b/TEST_REPORT.md deleted file mode 100644 index 00b5dde..0000000 --- a/TEST_REPORT.md +++ /dev/null @@ -1,113 +0,0 @@ -# 智能网络监控脚本测试报告 - -## 测试日期 -2025年6月6日 - -## 脚本概述 -这是一个PowerShell智能网络监控脚本,用于监控指定IP的网络连通性,当网络持续中断超过设定时间后自动关闭计算机。 - -## 主要功能 -1. **网络连通性监控** - 定期ping目标IP地址 -2. **智能故障检测** - 区分临时网络波动和持续故障 -3. **可配置监控窗口** - 防止因短暂网络中断导致误关机 -4. **关机倒计时机制** - 提供最后的取消机会 -5. **完整日志记录** - 记录所有操作和状态变化 -6. **手动取消功能** - 用户可以随时按键取消关机 - -## 配置参数(原版) -- **目标IP**: 192.168.3.3 -- **正常监控间隔**: 15秒 -- **监控窗口**: 180秒(3分钟) -- **关机倒计时**: 60秒 -- **倒计时ping间隔**: 3秒 -- **Ping超时**: 3秒 - -## 测试配置(测试版) -- **目标IP**: 192.168.3.99(不存在的IP,模拟网络故障) -- **正常监控间隔**: 3秒 -- **监控窗口**: 15秒 -- **关机倒计时**: 10秒 -- **倒计时ping间隔**: 2秒 - -## 修复的问题 -1. **兼容性问题**: 修复了`Test-Connection`命令在旧版PowerShell中不支持`-TimeoutSeconds`参数的问题 -2. **编码问题**: 将特殊Unicode字符(✓ ✗ ℹ)替换为ASCII字符,避免控制台显示乱码 - -## 测试结果 - -### ✅ 功能测试全部通过 - -#### 1. 脚本启动功能 -- ✅ 正常启动和初始化 -- ✅ 日志系统正常工作 -- ✅ 配置参数正确加载 -- ✅ 本地IP获取功能正常 - -#### 2. 网络监控功能 -- ✅ 正常IP连通性检测(如8.8.8.8) -- ✅ 故障IP检测(如192.168.3.99) -- ✅ 网络异常处理机制 -- ✅ Ping命令兼容性修复 - -#### 3. 监控窗口机制 -- ✅ 首次网络中断检测 -- ✅ 监控窗口计时功能 -- ✅ 剩余时间计算和显示 -- ✅ 监控窗口超时触发 - -#### 4. 关机倒计时功能 -- ✅ 倒计时启动机制 -- ✅ 倒计时期间网络快速检测 -- ✅ 按键手动取消功能 -- ✅ 模拟关机操作 - -#### 5. 日志记录功能 -- ✅ 日志目录自动创建 -- ✅ 按日期分类的日志文件 -- ✅ 完整的操作记录 -- ✅ 不同级别的日志分类(INFO、WARN、CRITICAL、FAIL、SUCCESS) - -#### 6. 用户界面和显示 -- ✅ 彩色控制台输出 -- ✅ 清晰的状态提示 -- ✅ 编码问题修复 -- ✅ 用户友好的信息显示 - -## 实际测试执行记录 - -### 测试1(13:02:43开始) -- 监控窗口:15秒 -- 实际触发时间:18秒后进入关机倒计时 -- 关机倒计时:10秒 -- 结果:正常完成模拟关机,重置状态继续监控 - -### 测试2(13:08:30开始) -- 同样配置重复测试 -- 确认功能稳定性和一致性 -- 编码问题已完全修复 - -## 实际使用建议 - -### 安全配置 -1. **取消注释关机命令**:在`smart_shutdown.ps1`第217行,将`# Stop-Computer -Force`的注释去掉 -2. **以管理员身份运行**:脚本需要管理员权限执行关机命令 -3. **测试配置**:建议先用较短时间参数测试,确认无误后再使用正式配置 - -### 最佳实践 -1. **监控窗口设置**:建议设置为3-5分钟,避免网络短暂波动造成误关机 -2. **目标IP选择**:建议使用网关IP或重要服务器IP -3. **日志监控**:定期检查日志文件,了解网络状况 -4. **备用方案**:考虑配置多个目标IP进行冗余检测 - -## 结论 -**脚本功能完整,测试全部通过,可以安全投入使用。** - -经过全面测试,智能网络监控脚本各项功能均正常工作: -- 网络监控准确可靠 -- 故障检测机制有效 -- 用户交互友好 -- 日志记录完整 -- 编码问题已解决 -- 兼容性问题已修复 - -脚本已准备好在生产环境中使用,能够有效监控网络连接并在必要时自动关闭计算机。 diff --git a/cmd/smart-monitor/main.go b/cmd/smart-monitor/main.go new file mode 100644 index 0000000..dbdd341 --- /dev/null +++ b/cmd/smart-monitor/main.go @@ -0,0 +1,123 @@ +package main + +import ( + "fmt" + "os" + + "github.com/kardianos/service" + "github.com/spf13/cobra" + "smart-shutdown/pkg/config" + "smart-shutdown/pkg/daemon" + "smart-shutdown/pkg/logger" +) + +func main() { + // 初始化全局系统日志 + if err := logger.InitLogger(); err != nil { + fmt.Printf("无法初始化日志系统: %v\n", err) + os.Exit(1) + } + + // 初始化配置加载 + cfg, err := config.LoadConfig() + if err != nil { + logger.Crit("读取配置失败: %v", err) + os.Exit(1) + } + + // 注册为跨平台系统服务 + svc, err := daemon.GetService(cfg) + if err != nil { + logger.Crit("构建服务对象失败: %v", err) + os.Exit(1) + } + + // 定义根命令,无后续子命令会直接触发 + var rootCommand = &cobra.Command{ + Use: "smart-monitor", + Short: "智能网络监控自动关机", + Run: func(cmd *cobra.Command, args []string) { + // 如果没有输入子命令,尝试作为服务直接前台或者后台跑起来 + // 这个分支也是系统启动服务(systemd/services.msc)自动拉起进程时的必然入口 + err := svc.Run() + if err != nil { + logger.Fail("运行抛出异常: %v", err) + } + }, + } + + // 系统服务管理一键控制逻辑,使用 kardianos/service 提供的内置 Control方法 + cmds := []*cobra.Command{ + { + Use: "install", + Short: "将本程序装载并注册为系统常驻服务 (例如 systemd / windows registry)", + Run: func(cmd *cobra.Command, args []string) { + handleServiceControl(svc, "install") + }, + }, + { + Use: "uninstall", + Short: "从系统中彻底卸载此后台监控服务", + Run: func(cmd *cobra.Command, args []string) { + handleServiceControl(svc, "uninstall") + }, + }, + { + Use: "start", + Short: "令已注册的系统服务开始运行", + Run: func(cmd *cobra.Command, args []string) { + handleServiceControl(svc, "start") + }, + }, + { + Use: "stop", + Short: "停止系统服务", + Run: func(cmd *cobra.Command, args []string) { + handleServiceControl(svc, "stop") + }, + }, + { + Use: "restart", + Short: "重启系统服务", + Run: func(cmd *cobra.Command, args []string) { + handleServiceControl(svc, "restart") + }, + }, + { + Use: "status", + Short: "查询服务存活进程状态", + Run: func(cmd *cobra.Command, args []string) { + status, err := svc.Status() + if err != nil { + fmt.Printf("❌ 获取服务状态失败: %v\n", err) + return + } + switch status { + case service.StatusRunning: + fmt.Println("✅ 服务存活 [运行中]") + case service.StatusStopped: + fmt.Println("💤 服务处于 [已停止] 状态") + default: + fmt.Println("❓ 服务尚未在本机注册或者状态未知。请确认你是否执行过 smart-monitor install") + } + }, + }, + } + + for _, c := range cmds { + rootCommand.AddCommand(c) + } + + if err := rootCommand.Execute(); err != nil { + os.Exit(1) + } +} + +func handleServiceControl(s service.Service, action string) { + err := service.Control(s, action) + if err != nil { + logger.Crit("执行动作 [%s] 遭到拒绝或失败: %v", action, err) + return + } + logger.Succ("成功对系统后台服务执行 [%s] 指令!", action) +} diff --git a/deploy_system.ps1 b/deploy_system.ps1 deleted file mode 100644 index 00d8e6d..0000000 --- a/deploy_system.ps1 +++ /dev/null @@ -1,519 +0,0 @@ -<# -.SYNOPSIS - 智能网络监控脚本 - 系统级部署脚本 - -.DESCRIPTION - 将脚本部署到系统级目录,配置为开机自启动,无需用户登录 - - 部署位置: - - 程序文件: C:\Program Files\SmartNetworkMonitor\ - - 配置文件: C:\ProgramData\SmartNetworkMonitor\ - - 日志文件: C:\ProgramData\SmartNetworkMonitor\logs\ -#> - -# 定义系统级路径 -$ProgramPath = "C:\Program Files\SmartNetworkMonitor" -$DataPath = "C:\ProgramData\SmartNetworkMonitor" -$LogPath = "$DataPath\logs" - -Write-Host "==========================================" -ForegroundColor Cyan -Write-Host "智能网络监控脚本 - 系统级部署" -ForegroundColor Cyan -Write-Host "==========================================" -ForegroundColor Cyan -Write-Host "" - -Write-Host "部署计划:" -ForegroundColor Yellow -Write-Host "- 程序目录: $ProgramPath" -ForegroundColor White -Write-Host "- 数据目录: $DataPath" -ForegroundColor White -Write-Host "- 日志目录: $LogPath" -ForegroundColor White -Write-Host "" - -# 检查源文件 -$SourcePath = $PSScriptRoot -$RequiredFiles = @( - "smart_shutdown.ps1" -) - -foreach ($file in $RequiredFiles) { - if (-not (Test-Path -Path (Join-Path $SourcePath $file))) { - Write-Error "找不到必需文件: $file" - exit 1 - } -} - -Write-Host "[OK] 源文件检查完成" -ForegroundColor Green - -# 创建目录结构 -Write-Host "正在创建目录结构..." -ForegroundColor Yellow - -try { - # 创建程序目录 - if (-not (Test-Path -Path $ProgramPath)) { - New-Item -Path $ProgramPath -ItemType Directory -Force | Out-Null - Write-Host "[OK] 创建程序目录: $ProgramPath" -ForegroundColor Green - } - - # 创建数据目录 - if (-not (Test-Path -Path $DataPath)) { - New-Item -Path $DataPath -ItemType Directory -Force | Out-Null - Write-Host "[OK] 创建数据目录: $DataPath" -ForegroundColor Green - } - - # 创建日志目录 - if (-not (Test-Path -Path $LogPath)) { - New-Item -Path $LogPath -ItemType Directory -Force | Out-Null - Write-Host "[OK] 创建日志目录: $LogPath" -ForegroundColor Green - } -} -catch { - Write-Error "创建目录失败: $($_.Exception.Message)" - exit 1 -} - -# 创建系统优化版的主脚本 -Write-Host "正在创建系统版本的脚本..." -ForegroundColor Yellow - -$SystemScriptContent = @" -#Requires -Version 5.1 - -<# -.SYNOPSIS - 智能网络监控脚本 - 系统服务版本 - -.DESCRIPTION - 系统级网络监控脚本,在网络持续中断时自动关机 - - 特点: - - 开机自启动,无需用户登录 - - 日志存储在系统数据目录 - - 优化的错误处理和权限管理 -#> - -# ==================== 系统级配置参数 ==================== - -# 监控的目标IP地址 -[string]`$TargetIP = "192.168.3.3" - -# 正常监控时的ping间隔(秒) -[int]`$NormalPingInterval = 15 - -# 监控窗口时长(秒) - 在此期间持续失败则触发关机 -[int]`$MonitorWindowSeconds = 180 - -# 关机倒计时时长(秒) -[int]`$ShutdownCountdown = 60 - -# 关机倒计时阶段的ping间隔(秒) -[int]`$CountdownPingInterval = 3 - -# 系统级日志配置 -[string]`$LogDirectory = "$LogPath" -[string]`$LogFile = Join-Path -Path `$LogDirectory -ChildPath "network_monitor_`$(Get-Date -Format 'yyyyMMdd').log" -[string]`$ConfigFile = "$DataPath\config.json" -[int]`$MaxLogDays = 30 - -# 正常连接时的日志记录间隔计数器 -[int]`$normalLogInterval = 24 # 每24次循环记录一次状态 (约6分钟) -[int]`$normalLogCounter = 0 - -# ================================================= - -# --- 函数定义 --- - -# 加载配置文件 -function Load-Configuration { - if (Test-Path -Path `$ConfigFile) { - try { - `$config = Get-Content -Path `$ConfigFile | ConvertFrom-Json - if (`$config.TargetIP) { `$script:TargetIP = `$config.TargetIP } - if (`$config.MonitorWindowSeconds) { `$script:MonitorWindowSeconds = `$config.MonitorWindowSeconds } - if (`$config.ShutdownCountdown) { `$script:ShutdownCountdown = `$config.ShutdownCountdown } - if (`$config.NormalPingInterval) { `$script:NormalPingInterval = `$config.NormalPingInterval } - Write-Log -Level "INFO" -Message "配置文件加载成功" - } - catch { - Write-Log -Level "WARN" -Message "配置文件格式错误,使用默认配置" - } - } else { - # 创建默认配置文件 - `$defaultConfig = @{ - TargetIP = `$TargetIP - MonitorWindowSeconds = `$MonitorWindowSeconds - ShutdownCountdown = `$ShutdownCountdown - NormalPingInterval = `$NormalPingInterval - } - try { - `$defaultConfig | ConvertTo-Json | Set-Content -Path `$ConfigFile - Write-Log -Level "INFO" -Message "创建默认配置文件: `$ConfigFile" - } - catch { - Write-Log -Level "WARN" -Message "无法创建配置文件,使用内置默认值" - } - } -} - -# 日志写入函数 -function Write-Log { - param( - [Parameter(Mandatory=`$true)] - [ValidateSet("INFO", "SUCCESS", "FAIL", "WARN", "CRITICAL", "DEBUG")] - [string]`$Level, - - [Parameter(Mandatory=`$true)] - [string]`$Message - ) - - `$logTimestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" - `$logEntry = "[`$logTimestamp] [`$Level] `$Message" - - # 尝试写入日志文件 - try { - if (-not (Test-Path -Path `$LogDirectory)) { - New-Item -Path `$LogDirectory -ItemType Directory -ErrorAction Stop | Out-Null - } - Add-Content -Path `$LogFile -Value `$logEntry -ErrorAction Stop - } - catch { - # 如果写入失败,尝试输出到事件日志 - try { - if (-not [System.Diagnostics.EventLog]::SourceExists("SmartNetworkMonitor")) { - New-EventLog -LogName "Application" -Source "SmartNetworkMonitor" - } - Write-EventLog -LogName "Application" -Source "SmartNetworkMonitor" -EventId 1001 -EntryType Information -Message `$logEntry - } - catch { - # 最后尝试输出到控制台(虽然在服务模式下不可见) - Write-Host "[`$logTimestamp] [CRITICAL] 日志写入失败!`$Message" - } - } - - # 在服务模式下,也输出到事件日志作为备份 - try { - if (`$Level -eq "CRITICAL" -or `$Level -eq "FAIL") { - Write-EventLog -LogName "Application" -Source "SmartNetworkMonitor" -EventId 1002 -EntryType Warning -Message `$logEntry -ErrorAction SilentlyContinue - } - } - catch { - # 忽略事件日志写入错误 - } -} - -# 清理旧日志文件 -function Remove-OldLogs { - try { - `$cutoffDate = (Get-Date).AddDays(-`$MaxLogDays) - `$oldLogs = Get-ChildItem -Path `$LogDirectory -Filter "network_monitor_*.log" | Where-Object { `$_.LastWriteTime -lt `$cutoffDate } - foreach (`$oldLog in `$oldLogs) { - Remove-Item -Path `$oldLog.FullName -Force - Write-Log -Level "INFO" -Message "删除旧日志文件: `$(`$oldLog.Name)" - } - } - catch { - Write-Log -Level "WARN" -Message "清理旧日志文件时出错: `$(`$_.Exception.Message)" - } -} - -# ================================================= - -# --- 主程序开始 --- - -# 初始化 -Load-Configuration -Remove-OldLogs - -# 获取系统信息 -try { - `$runningAs = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name - `$localIP = (Get-NetIPAddress -AddressFamily IPv4 | Where-Object { `$_.InterfaceAlias -notmatch "Loopback" } | Select-Object -First 1).IPAddress -} -catch { - `$runningAs = "Unknown" - `$localIP = "Unknown" -} - -Write-Log -Level "INFO" -Message "========== 系统级网络监控脚本启动 ==========" -Write-Log -Level "INFO" -Message "运行账户: `$runningAs" -Write-Log -Level "INFO" -Message "本机IP: `$localIP" -Write-Log -Level "INFO" -Message "监控目标: `$TargetIP" -Write-Log -Level "INFO" -Message "监控窗口: `${MonitorWindowSeconds}秒" -Write-Log -Level "INFO" -Message "关机倒计时: `${ShutdownCountdown}秒" -Write-Log -Level "INFO" -Message "日志目录: `$LogDirectory" -Write-Log -Level "INFO" -Message "配置文件: `$ConfigFile" - -# 主循环 -`$failureStartTime = `$null - -while (`$true) { - # 测试网络连接 - try { - `$pingResult = Test-Connection -ComputerName `$TargetIP -Count 1 -Quiet -ErrorAction SilentlyContinue - `$isOnline = `$pingResult - } - catch { - Write-Log -Level "FAIL" -Message "网络测试出现异常: `$(`$_.Exception.Message)" - `$isOnline = `$false - } - - if (`$isOnline) { - if (`$failureStartTime) { - Write-Log -Level "SUCCESS" -Message "网络连接已恢复。" - `$failureStartTime = `$null - } else { - # 减少正常连接时的日志频率 - `$normalLogCounter++ - if (`$normalLogCounter -ge `$normalLogInterval) { - Write-Log -Level "INFO" -Message "网络连接正常 (定期状态报告)" - `$normalLogCounter = 0 - } - } - - Start-Sleep -Seconds `$NormalPingInterval - - } else { - # 网络不通时的处理逻辑 - Write-Log -Level "FAIL" -Message "Ping失败 - 目标: `$TargetIP" - - if (-not `$failureStartTime) { - `$failureStartTime = Get-Date - Write-Log -Level "WARN" -Message "网络首次中断,开始进入监控窗口计时。" - } - - `$failureDuration = (New-TimeSpan -Start `$failureStartTime -End (Get-Date)).TotalSeconds - Write-Log -Level "INFO" -Message "网络已持续中断 `$([math]::Round(`$failureDuration)) / `${MonitorWindowSeconds} 秒。" - - if (`$failureDuration -ge `$MonitorWindowSeconds) { - Write-Log -Level "CRITICAL" -Message "网络持续中断已超过 `${MonitorWindowSeconds} 秒,开始关机流程。" - - `$shutdownCancelled = `$false - `$countdownEndTime = (Get-Date).AddSeconds(`$ShutdownCountdown) - - while ((Get-Date) -lt `$countdownEndTime -and -not `$shutdownCancelled) { - `$remainingSeconds = [math]::Ceiling((`$countdownEndTime - (Get-Date)).TotalSeconds) - if (`$remainingSeconds -le 0) { break } - - Write-Log -Level "WARN" -Message "距离关机还有 `$remainingSeconds 秒... 正在快速检测网络。" - - # 在倒计时中再次检测网络 - try { - if (Test-Connection -ComputerName `$TargetIP -Count 1 -Quiet -ErrorAction SilentlyContinue) { - Write-Log -Level "SUCCESS" -Message "网络在倒计时期间恢复!取消关机。" - `$failureStartTime = `$null - `$shutdownCancelled = `$true - break - } - } - catch { - Write-Log -Level "WARN" -Message "倒计时期间网络测试出现异常: `$(`$_.Exception.Message)" - } - - Start-Sleep -Seconds `$CountdownPingInterval - } - - if (-not `$shutdownCancelled) { - Write-Log -Level "CRITICAL" -Message "关机倒计时完成,执行系统关机命令。" - try { - # 执行实际关机命令 - Stop-Computer -Force - Write-Log -Level "CRITICAL" -Message "关机命令已执行。" - } - catch { - Write-Log -Level "CRITICAL" -Message "关机命令执行失败: `$(`$_.Exception.Message)" - } - exit - } - } else { - Start-Sleep -Seconds `$NormalPingInterval - } - } -} -"@ - -# 写入系统版本脚本 -$SystemScriptPath = Join-Path $ProgramPath "smart_shutdown_system.ps1" -try { - $SystemScriptContent | Set-Content -Path $SystemScriptPath -Encoding UTF8 - Write-Host "[OK] 创建系统脚本: $SystemScriptPath" -ForegroundColor Green -} -catch { - Write-Error "创建系统脚本失败: $($_.Exception.Message)" - exit 1 -} - -# 创建默认配置文件 -Write-Host "正在创建配置文件..." -ForegroundColor Yellow - -$DefaultConfig = @{ - TargetIP = "192.168.3.3" - MonitorWindowSeconds = 180 - ShutdownCountdown = 60 - NormalPingInterval = 15 -} - -$ConfigPath = Join-Path $DataPath "config.json" -try { - $DefaultConfig | ConvertTo-Json -Depth 10 | Set-Content -Path $ConfigPath -Encoding UTF8 - Write-Host "[OK] 创建配置文件: $ConfigPath" -ForegroundColor Green -} -catch { - Write-Error "创建配置文件失败: $($_.Exception.Message)" - exit 1 -} - -# 配置任务计划程序 -Write-Host "正在配置任务计划程序..." -ForegroundColor Yellow - -try { - # 删除已存在的任务(如果有) - try { - Unregister-ScheduledTask -TaskName "Smart Network Shutdown Monitor" -Confirm:$false -ErrorAction SilentlyContinue - } - catch { - # 忽略错误,任务可能不存在 - } - - # 创建触发器(系统启动时) - $Trigger = New-ScheduledTaskTrigger -AtStartup - - # 创建操作 - $Action = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument "-WindowStyle Hidden -ExecutionPolicy Bypass -File `"$SystemScriptPath`"" - - # 创建设置 - $Settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -DontStopOnIdleEnd -ExecutionTimeLimit (New-TimeSpan -Days 365) - - # 创建主体(以SYSTEM身份运行) - $Principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest - - # 注册任务 - Register-ScheduledTask -TaskName "Smart Network Shutdown Monitor" -Trigger $Trigger -Action $Action -Settings $Settings -Principal $Principal -Description "智能网络监控脚本 - 系统级运行" - - Write-Host "[OK] 任务计划程序配置完成" -ForegroundColor Green -} -catch { - Write-Error "配置任务计划程序失败: $($_.Exception.Message)" - exit 1 -} - -# 创建管理脚本 -Write-Host "正在创建管理工具..." -ForegroundColor Yellow - -$ManagementScript = @" -# 智能网络监控脚本 - 管理工具 - -Write-Host "智能网络监控脚本 - 管理工具" -ForegroundColor Cyan -Write-Host "==============================" -ForegroundColor Cyan -Write-Host "" - -Write-Host "可用操作:" -ForegroundColor Yellow -Write-Host "1. 查看任务状态" -Write-Host "2. 启动监控任务" -Write-Host "3. 停止监控任务" -Write-Host "4. 查看今天的日志" -Write-Host "5. 查看实时日志" -Write-Host "6. 查看配置文件" -Write-Host "7. 编辑配置文件" -Write-Host "" - -`$choice = Read-Host "请选择操作 (1-7)" - -switch (`$choice) { - "1" { - Get-ScheduledTask -TaskName "Smart Network Shutdown Monitor" | Format-Table - } - "2" { - Start-ScheduledTask -TaskName "Smart Network Shutdown Monitor" - Write-Host "任务已启动" -ForegroundColor Green - } - "3" { - Stop-ScheduledTask -TaskName "Smart Network Shutdown Monitor" - Write-Host "任务已停止" -ForegroundColor Green - } - "4" { - `$logFile = "$LogPath\network_monitor_`$(Get-Date -Format 'yyyyMMdd').log" - if (Test-Path `$logFile) { - Get-Content `$logFile - } else { - Write-Host "今天的日志文件不存在" -ForegroundColor Red - } - } - "5" { - `$logFile = "$LogPath\network_monitor_`$(Get-Date -Format 'yyyyMMdd').log" - if (Test-Path `$logFile) { - Get-Content `$logFile -Wait - } else { - Write-Host "今天的日志文件不存在" -ForegroundColor Red - } - } - "6" { - Get-Content "$DataPath\config.json" - } - "7" { - notepad "$DataPath\config.json" - } - default { - Write-Host "无效选择" -ForegroundColor Red - } -} - -Write-Host "" -Write-Host "常用命令:" -ForegroundColor Yellow -Write-Host "1. 查看任务状态:" -Write-Host " Get-ScheduledTask -TaskName 'Smart Network Shutdown Monitor'" -Write-Host "" -Write-Host "2. 启动任务:" -Write-Host " Start-ScheduledTask -TaskName 'Smart Network Shutdown Monitor'" -Write-Host "" -Write-Host "3. 停止任务:" -Write-Host " Stop-ScheduledTask -TaskName 'Smart Network Shutdown Monitor'" -Write-Host "" -Write-Host "4. 查看今天日志:" -Write-Host " Get-Content '$LogPath\network_monitor_`$(Get-Date -Format 'yyyyMMdd').log'" -Write-Host "" -Write-Host "5. 实时查看日志:" -Write-Host " Get-Content '$LogPath\network_monitor_`$(Get-Date -Format 'yyyyMMdd').log' -Wait" -Write-Host "" -Write-Host "6. 查看配置:" -Write-Host " Get-Content '$DataPath\config.json'" -Write-Host "" -Write-Host "7. 编辑配置文件:" -Write-Host " notepad '$DataPath\config.json'" -Write-Host "" -"@ - -$ManagementScriptPath = Join-Path $ProgramPath "manage.ps1" -try { - $ManagementScript | Set-Content -Path $ManagementScriptPath -Encoding UTF8 - Write-Host "[OK] 创建管理脚本: $ManagementScriptPath" -ForegroundColor Green -} -catch { - Write-Error "创建管理脚本失败: $($_.Exception.Message)" - exit 1 -} - -Write-Host "" -Write-Host "[INFO] 系统级部署完成!" -ForegroundColor Green -Write-Host "" -Write-Host "部署摘要:" -ForegroundColor Cyan -Write-Host "[OK] 程序文件已部署到: $ProgramPath" -ForegroundColor White -Write-Host "[OK] 数据目录已创建: $DataPath" -ForegroundColor White -Write-Host "[OK] 日志目录已创建: $LogPath" -ForegroundColor White -Write-Host "[OK] 任务计划程序已配置(系统启动时运行)" -ForegroundColor White -Write-Host "[OK] SYSTEM 权限配置完成" -ForegroundColor White -Write-Host "" -Write-Host "管理工具:" -ForegroundColor Yellow -Write-Host "- 管理脚本: $ManagementScriptPath" -ForegroundColor White -Write-Host "- 配置文件: $DataPath\config.json" -ForegroundColor White -Write-Host "- 今天日志: $LogPath\network_monitor_$(Get-Date -Format 'yyyyMMdd').log" -ForegroundColor White -Write-Host "" -Write-Host "下次重启后,脚本将自动运行!" -ForegroundColor Green -Write-Host "" - -# 询问是否立即启动 -$response = Read-Host "是否立即启动监控任务?(Y/N)" -if ($response -eq 'Y' -or $response -eq 'y' -or $response -eq '') { - try { - Start-ScheduledTask -TaskName "Smart Network Shutdown Monitor" - Write-Host "[OK] 监控任务已启动" -ForegroundColor Green - } - catch { - Write-Host "[X] 启动任务失败: $($_.Exception.Message)" -ForegroundColor Red - } -} diff --git a/deploy_system.sh b/deploy_system.sh deleted file mode 100755 index 94ba8d4..0000000 --- a/deploy_system.sh +++ /dev/null @@ -1,528 +0,0 @@ -#!/bin/bash - -# -# 智能网络监控脚本 - Ubuntu系统级部署脚本 -# -# 功能描述: -# 将脚本部署到系统级目录,配置为systemd服务,开机自启动 -# -# 部署位置: -# - 程序文件: /opt/smart-network-monitor/ -# - 配置文件: /etc/smart-network-monitor/ -# - 日志文件: /var/log/smart-network-monitor/ -# - 服务文件: /etc/systemd/system/smart-network-monitor.service -# -# 使用方法: -# sudo ./deploy_system.sh -# - -# 设置颜色输出 -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -CYAN='\033[0;36m' -NC='\033[0m' # No Color - -# 定义系统级路径 -PROGRAM_PATH="/opt/smart-network-monitor" -CONFIG_PATH="/etc/smart-network-monitor" -LOG_PATH="/var/log/smart-network-monitor" -SERVICE_FILE="/etc/systemd/system/smart-network-monitor.service" -SERVICE_NAME="smart-network-monitor" - -# 当前脚本目录 -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - -echo -e "${CYAN}==========================================${NC}" -echo -e "${CYAN}智能网络监控脚本 - Ubuntu系统级部署${NC}" -echo -e "${CYAN}==========================================${NC}" -echo "" - -echo -e "${YELLOW}部署计划:${NC}" -echo -e "- 程序目录: ${PROGRAM_PATH}" -echo -e "- 配置目录: ${CONFIG_PATH}" -echo -e "- 日志目录: ${LOG_PATH}" -echo -e "- 服务文件: ${SERVICE_FILE}" -echo "" - -# 检查root权限 -if [[ $EUID -ne 0 ]]; then - echo -e "${RED}错误:此脚本需要root权限执行${NC}" - echo -e "${YELLOW}请使用: sudo $0${NC}" - exit 1 -fi - -# 检查源文件 -REQUIRED_FILES=( - "smart_shutdown.sh" -) - -for file in "${REQUIRED_FILES[@]}"; do - if [[ ! -f "$SCRIPT_DIR/$file" ]]; then - echo -e "${RED}错误:找不到必需文件: $file${NC}" - exit 1 - fi -done - -echo -e "${GREEN}[OK] 源文件检查完成${NC}" - -# 停止已存在的服务 -if systemctl is-active --quiet "$SERVICE_NAME"; then - echo -e "${YELLOW}正在停止现有服务...${NC}" - systemctl stop "$SERVICE_NAME" - echo -e "${GREEN}[OK] 服务已停止${NC}" -fi - -# 创建目录结构 -echo -e "${YELLOW}正在创建目录结构...${NC}" - -# 创建程序目录 -if [[ ! -d "$PROGRAM_PATH" ]]; then - mkdir -p "$PROGRAM_PATH" - echo -e "${GREEN}[OK] 创建程序目录: $PROGRAM_PATH${NC}" -fi - -# 创建配置目录 -if [[ ! -d "$CONFIG_PATH" ]]; then - mkdir -p "$CONFIG_PATH" - echo -e "${GREEN}[OK] 创建配置目录: $CONFIG_PATH${NC}" -fi - -# 创建日志目录 -if [[ ! -d "$LOG_PATH" ]]; then - mkdir -p "$LOG_PATH" - # 设置适当的权限,允许服务用户写入 - chmod 755 "$LOG_PATH" - echo -e "${GREEN}[OK] 创建日志目录: $LOG_PATH${NC}" -fi - -# 创建系统优化版的主脚本 -echo -e "${YELLOW}正在创建系统版本的脚本...${NC}" - -cat > "$PROGRAM_PATH/smart_shutdown_system.sh" << 'EOF' -#!/bin/bash - -# -# 智能网络监控脚本 - 系统服务版本 -# -# 功能描述: -# 系统级网络监控脚本,在网络持续中断时自动关机 -# -# 特点: -# - 开机自启动,作为systemd服务运行 -# - 日志存储在系统日志目录 -# - 优化的错误处理和权限管理 -# - -# ==================== 系统级配置参数 ==================== - -# 默认配置参数 -TARGET_IP="192.168.3.3" -NORMAL_PING_INTERVAL=15 -MONITOR_WINDOW_SECONDS=180 -SHUTDOWN_COUNTDOWN=60 -COUNTDOWN_PING_INTERVAL=3 -PING_TIMEOUT=3 - -# 系统级路径配置 -CONFIG_FILE="/etc/smart-network-monitor/config.json" -LOG_DIRECTORY="/var/log/smart-network-monitor" -MAX_LOG_DAYS=30 - -# 正常连接时的日志记录间隔计数器 -NORMAL_LOG_INTERVAL=24 # 每24次循环记录一次状态 (约6分钟) -NORMAL_LOG_COUNTER=0 - -# ==================== 函数定义 ==================== - -# 日志写入函数 -write_log() { - local level="$1" - local message="$2" - local timestamp=$(date '+%Y-%m-%d %H:%M:%S') - local log_file="$LOG_DIRECTORY/network_monitor_$(date '+%Y%m%d').log" - local log_entry="[$timestamp] [$level] $message" - - # 确保日志目录存在 - mkdir -p "$LOG_DIRECTORY" - - # 写入日志文件 - echo "$log_entry" >> "$log_file" 2>/dev/null - - # 同时写入系统日志 - logger -t "smart-network-monitor" "$log_entry" - - # 对于关键信息,输出到标准输出(systemd会捕获) - if [[ "$level" == "CRITICAL" || "$level" == "SUCCESS" || "$level" == "WARN" ]]; then - echo "$log_entry" - fi -} - -# 加载配置文件 -load_configuration() { - if [[ -f "$CONFIG_FILE" ]]; then - write_log "INFO" "加载配置文件: $CONFIG_FILE" - - # 使用jq解析JSON配置文件(如果可用) - if command -v jq >/dev/null 2>&1; then - local target_ip=$(jq -r '.TargetIP // empty' "$CONFIG_FILE" 2>/dev/null) - local monitor_window=$(jq -r '.MonitorWindowSeconds // empty' "$CONFIG_FILE" 2>/dev/null) - local shutdown_countdown=$(jq -r '.ShutdownCountdown // empty' "$CONFIG_FILE" 2>/dev/null) - local ping_interval=$(jq -r '.NormalPingInterval // empty' "$CONFIG_FILE" 2>/dev/null) - - [[ -n "$target_ip" ]] && TARGET_IP="$target_ip" - [[ -n "$monitor_window" ]] && MONITOR_WINDOW_SECONDS="$monitor_window" - [[ -n "$shutdown_countdown" ]] && SHUTDOWN_COUNTDOWN="$shutdown_countdown" - [[ -n "$ping_interval" ]] && NORMAL_PING_INTERVAL="$ping_interval" - - write_log "SUCCESS" "配置文件加载成功" - else - write_log "WARN" "jq未安装,无法解析JSON配置文件,使用默认配置" - fi - else - write_log "WARN" "配置文件不存在,使用默认配置" - fi -} - -# 测试网络连接 -test_network_connection() { - local target_ip="$1" - ping -c 1 -W "$PING_TIMEOUT" "$target_ip" >/dev/null 2>&1 - return $? -} - -# 清理旧日志文件 -cleanup_old_logs() { - if [[ -d "$LOG_DIRECTORY" ]]; then - find "$LOG_DIRECTORY" -name "network_monitor_*.log" -type f -mtime +$MAX_LOG_DAYS -exec rm -f {} \; 2>/dev/null - fi -} - -# 信号处理函数 -cleanup_and_exit() { - write_log "INFO" "接收到退出信号,正在清理..." - write_log "INFO" "========== 服务退出 ==========" - exit 0 -} - -# ==================== 主程序开始 ==================== - -# 设置信号处理 -trap cleanup_and_exit SIGINT SIGTERM - -# 清理旧日志 -cleanup_old_logs - -# 加载配置 -load_configuration - -# 获取系统信息 -running_user=$(whoami) -local_ip=$(ip route get 8.8.8.8 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="src") print $(i+1)}' | head -1) -[[ -z "$local_ip" ]] && local_ip="未知" - -write_log "INFO" "========== 系统级网络监控服务启动 ==========" -write_log "INFO" "运行用户: $running_user" -write_log "INFO" "本机IP: $local_ip" -write_log "INFO" "监控目标: $TARGET_IP" -write_log "INFO" "监控窗口: ${MONITOR_WINDOW_SECONDS}秒" -write_log "INFO" "关机倒计时: ${SHUTDOWN_COUNTDOWN}秒" -write_log "INFO" "日志目录: $LOG_DIRECTORY" -write_log "INFO" "配置文件: $CONFIG_FILE" - -# 主循环 -failure_start_time="" - -while true; do - # 测试网络连接 - if test_network_connection "$TARGET_IP"; then - # 网络连接正常 - if [[ -n "$failure_start_time" ]]; then - write_log "SUCCESS" "网络连接已恢复" - failure_start_time="" - NORMAL_LOG_COUNTER=0 - else - # 减少正常连接时的日志频率 - ((NORMAL_LOG_COUNTER++)) - if [[ $NORMAL_LOG_COUNTER -ge $NORMAL_LOG_INTERVAL ]]; then - write_log "INFO" "网络连接正常(定期状态报告)" - NORMAL_LOG_COUNTER=0 - fi - fi - - sleep "$NORMAL_PING_INTERVAL" - - else - # 网络连接失败 - write_log "FAIL" "Ping失败 - 目标: $TARGET_IP" - - if [[ -z "$failure_start_time" ]]; then - failure_start_time=$(date +%s) - write_log "WARN" "网络首次中断,开始进入监控窗口计时" - fi - - current_time=$(date +%s) - failure_duration=$((current_time - failure_start_time)) - write_log "INFO" "网络已持续中断 $failure_duration / ${MONITOR_WINDOW_SECONDS} 秒" - - if [[ $failure_duration -ge $MONITOR_WINDOW_SECONDS ]]; then - write_log "CRITICAL" "网络持续中断已超过 ${MONITOR_WINDOW_SECONDS} 秒,开始关机流程" - - shutdown_cancelled=false - countdown_end_time=$((current_time + SHUTDOWN_COUNTDOWN)) - - while [[ $(date +%s) -lt $countdown_end_time && "$shutdown_cancelled" == "false" ]]; do - current_time=$(date +%s) - remaining_seconds=$((countdown_end_time - current_time)) - - if [[ $remaining_seconds -le 0 ]]; then - break - fi - - write_log "WARN" "距离关机还有 $remaining_seconds 秒... 正在快速检测网络" - - # 在倒计时中再次检测网络 - if test_network_connection "$TARGET_IP"; then - write_log "SUCCESS" "网络在倒计时期间恢复!取消关机" - failure_start_time="" - shutdown_cancelled=true - break - fi - - sleep "$COUNTDOWN_PING_INTERVAL" - done - - if [[ "$shutdown_cancelled" == "false" ]]; then - write_log "CRITICAL" "关机倒计时完成,执行系统关机命令" - - # 执行实际关机命令 - shutdown -h now - write_log "CRITICAL" "关机命令已执行" - - exit 0 - fi - else - sleep "$NORMAL_PING_INTERVAL" - fi - fi -done -EOF - -# 设置脚本权限 -chmod +x "$PROGRAM_PATH/smart_shutdown_system.sh" -echo -e "${GREEN}[OK] 创建系统脚本: $PROGRAM_PATH/smart_shutdown_system.sh${NC}" - -# 创建默认配置文件 -echo -e "${YELLOW}正在创建配置文件...${NC}" - -cat > "$CONFIG_PATH/config.json" << EOF -{ - "TargetIP": "192.168.3.3", - "MonitorWindowSeconds": 180, - "ShutdownCountdown": 60, - "NormalPingInterval": 15 -} -EOF - -echo -e "${GREEN}[OK] 创建配置文件: $CONFIG_PATH/config.json${NC}" - -# 创建systemd服务文件 -echo -e "${YELLOW}正在配置systemd服务...${NC}" - -cat > "$SERVICE_FILE" << EOF -[Unit] -Description=Smart Network Monitor Service -Documentation=https://github.com/example/smart-network-monitor -After=network-online.target -Wants=network-online.target - -[Service] -Type=simple -User=root -Group=root -ExecStart=$PROGRAM_PATH/smart_shutdown_system.sh -Restart=always -RestartSec=10 -StandardOutput=journal -StandardError=journal - -# 安全设置 -NoNewPrivileges=false -PrivateTmp=true -ProtectHome=true -ProtectSystem=strict -ReadWritePaths=$LOG_PATH - -# 环境变量 -Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin - -[Install] -WantedBy=multi-user.target -EOF - -echo -e "${GREEN}[OK] 创建systemd服务文件: $SERVICE_FILE${NC}" - -# 重新加载systemd配置 -echo -e "${YELLOW}正在重新加载systemd配置...${NC}" -systemctl daemon-reload -echo -e "${GREEN}[OK] systemd配置已重新加载${NC}" - -# 启用服务 -echo -e "${YELLOW}正在启用服务开机自启动...${NC}" -systemctl enable "$SERVICE_NAME" -echo -e "${GREEN}[OK] 服务已设置为开机自启动${NC}" - -# 创建管理脚本 -echo -e "${YELLOW}正在创建管理工具...${NC}" - -cat > "$PROGRAM_PATH/manage.sh" << 'EOF' -#!/bin/bash - -# -# 智能网络监控脚本 - 管理工具 -# - -# 颜色定义 -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -CYAN='\033[0;36m' -NC='\033[0m' - -SERVICE_NAME="smart-network-monitor" -CONFIG_FILE="/etc/smart-network-monitor/config.json" -LOG_PATH="/var/log/smart-network-monitor" - -echo -e "${CYAN}智能网络监控脚本 - 管理工具${NC}" -echo -e "${CYAN}==============================${NC}" -echo "" - -echo -e "${YELLOW}可用操作:${NC}" -echo "1. 查看服务状态" -echo "2. 启动服务" -echo "3. 停止服务" -echo "4. 重启服务" -echo "5. 查看今天的日志" -echo "6. 查看实时日志" -echo "7. 查看配置文件" -echo "8. 编辑配置文件" -echo "9. 查看系统日志" -echo "" - -read -p "请选择操作 (1-9): " choice - -case "$choice" in - "1") - systemctl status "$SERVICE_NAME" - ;; - "2") - sudo systemctl start "$SERVICE_NAME" - echo -e "${GREEN}服务已启动${NC}" - ;; - "3") - sudo systemctl stop "$SERVICE_NAME" - echo -e "${GREEN}服务已停止${NC}" - ;; - "4") - sudo systemctl restart "$SERVICE_NAME" - echo -e "${GREEN}服务已重启${NC}" - ;; - "5") - log_file="$LOG_PATH/network_monitor_$(date '+%Y%m%d').log" - if [[ -f "$log_file" ]]; then - cat "$log_file" - else - echo -e "${RED}今天的日志文件不存在${NC}" - fi - ;; - "6") - log_file="$LOG_PATH/network_monitor_$(date '+%Y%m%d').log" - if [[ -f "$log_file" ]]; then - tail -f "$log_file" - else - echo -e "${RED}今天的日志文件不存在,显示systemd日志:${NC}" - journalctl -u "$SERVICE_NAME" -f - fi - ;; - "7") - if [[ -f "$CONFIG_FILE" ]]; then - cat "$CONFIG_FILE" - else - echo -e "${RED}配置文件不存在${NC}" - fi - ;; - "8") - if [[ -f "$CONFIG_FILE" ]]; then - sudo nano "$CONFIG_FILE" - echo -e "${YELLOW}配置已修改,重启服务使配置生效:${NC}" - echo "sudo systemctl restart $SERVICE_NAME" - else - echo -e "${RED}配置文件不存在${NC}" - fi - ;; - "9") - journalctl -u "$SERVICE_NAME" -n 50 - ;; - *) - echo -e "${RED}无效选择${NC}" - ;; -esac - -echo "" -echo -e "${YELLOW}常用命令:${NC}" -echo -e "${BLUE}查看服务状态:${NC} systemctl status $SERVICE_NAME" -echo -e "${BLUE}启动服务:${NC} sudo systemctl start $SERVICE_NAME" -echo -e "${BLUE}停止服务:${NC} sudo systemctl stop $SERVICE_NAME" -echo -e "${BLUE}重启服务:${NC} sudo systemctl restart $SERVICE_NAME" -echo -e "${BLUE}查看今天日志:${NC} cat $LOG_PATH/network_monitor_\$(date '+%Y%m%d').log" -echo -e "${BLUE}实时查看日志:${NC} tail -f $LOG_PATH/network_monitor_\$(date '+%Y%m%d').log" -echo -e "${BLUE}查看系统日志:${NC} journalctl -u $SERVICE_NAME -f" -echo -e "${BLUE}编辑配置:${NC} sudo nano $CONFIG_FILE" -echo "" -EOF - -chmod +x "$PROGRAM_PATH/manage.sh" -echo -e "${GREEN}[OK] 创建管理脚本: $PROGRAM_PATH/manage.sh${NC}" - -# 创建符号链接到系统PATH -if [[ ! -L "/usr/local/bin/smart-monitor" ]]; then - ln -s "$PROGRAM_PATH/manage.sh" "/usr/local/bin/smart-monitor" - echo -e "${GREEN}[OK] 创建管理工具快捷命令: smart-monitor${NC}" -fi - -echo "" -echo -e "${GREEN}[INFO] 系统级部署完成!${NC}" -echo "" -echo -e "${CYAN}部署摘要:${NC}" -echo -e "${GREEN}[OK]${NC} 程序文件已部署到: $PROGRAM_PATH" -echo -e "${GREEN}[OK]${NC} 配置目录已创建: $CONFIG_PATH" -echo -e "${GREEN}[OK]${NC} 日志目录已创建: $LOG_PATH" -echo -e "${GREEN}[OK]${NC} systemd服务已配置: $SERVICE_NAME" -echo -e "${GREEN}[OK]${NC} 开机自启动已启用" -echo "" -echo -e "${YELLOW}管理工具:${NC}" -echo -e "- 管理脚本: $PROGRAM_PATH/manage.sh" -echo -e "- 快捷命令: ${CYAN}smart-monitor${NC}" -echo -e "- 配置文件: $CONFIG_PATH/config.json" -echo -e "- 今天日志: $LOG_PATH/network_monitor_$(date '+%Y%m%d').log" -echo "" -echo -e "${GREEN}下次重启后,服务将自动运行!${NC}" -echo "" - -# 询问是否立即启动 -read -p "是否立即启动监控服务?(Y/n): " response -if [[ "$response" == "Y" || "$response" == "y" || "$response" == "" ]]; then - if systemctl start "$SERVICE_NAME"; then - echo -e "${GREEN}[OK] 监控服务已启动${NC}" - echo -e "${CYAN}使用以下命令查看服务状态:${NC}" - echo -e "${BLUE}systemctl status $SERVICE_NAME${NC}" - echo -e "${BLUE}journalctl -u $SERVICE_NAME -f${NC}" - else - echo -e "${RED}[X] 启动服务失败${NC}" - fi -fi - -echo "" -echo -e "${CYAN}使用 'smart-monitor' 命令来管理服务${NC}" \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..8d776f0 --- /dev/null +++ b/go.mod @@ -0,0 +1,22 @@ +module smart-shutdown + +go 1.25.0 + +require ( + github.com/fatih/color v1.19.0 + github.com/kardianos/service v1.2.4 + github.com/prometheus-community/pro-bing v0.8.0 + github.com/spf13/cobra v1.10.2 + gopkg.in/natefinch/lumberjack.v2 v2.2.1 +) + +require ( + github.com/google/uuid v1.6.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/spf13/pflag v1.0.9 // indirect + golang.org/x/net v0.49.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.42.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..c66391a --- /dev/null +++ b/go.sum @@ -0,0 +1,31 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w= +github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/kardianos/service v1.2.4 h1:XNlGtZOYNx2u91urOdg/Kfmc+gfmuIo1Dd3rEi2OgBk= +github.com/kardianos/service v1.2.4/go.mod h1:E4V9ufUuY82F7Ztlu1eN9VXWIQxg8NoLQlmFe0MtrXc= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/prometheus-community/pro-bing v0.8.0 h1:CEY/g1/AgERRDjxw5P32ikcOgmrSuXs7xon7ovx6mNc= +github.com/prometheus-community/pro-bing v0.8.0/go.mod h1:Idyxz8raDO6TgkUN6ByiEGvWJNyQd40kN9ZUeho3lN0= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= +github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= +github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= +github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= +golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= diff --git a/manage.sh b/manage.sh deleted file mode 100755 index 05b4b3d..0000000 --- a/manage.sh +++ /dev/null @@ -1,574 +0,0 @@ -#!/bin/bash - -# -# 智能网络监控脚本 - 管理工具 -# -# 功能描述: -# 提供智能网络监控脚本的管理界面 -# 包括服务控制、日志查看、配置管理等功能 -# -# 使用方法: -# ./manage.sh -# 或者(如果已安装到系统):smart-monitor -# - -# 颜色定义 -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -CYAN='\033[0;36m' -PURPLE='\033[0;35m' -NC='\033[0m' # No Color - -# 系统路径配置 -SERVICE_NAME="smart-network-monitor" -SYSTEM_CONFIG_FILE="/etc/smart-network-monitor/config.json" -SYSTEM_LOG_PATH="/var/log/smart-network-monitor" -LOCAL_CONFIG_FILE="./config.json" -LOCAL_LOG_PATH="./logs" - -# 检测是否为系统级安装 -if [[ -f "$SYSTEM_CONFIG_FILE" ]]; then - CONFIG_FILE="$SYSTEM_CONFIG_FILE" - LOG_PATH="$SYSTEM_LOG_PATH" - IS_SYSTEM_INSTALL=true -else - CONFIG_FILE="$LOCAL_CONFIG_FILE" - LOG_PATH="$LOCAL_LOG_PATH" - IS_SYSTEM_INSTALL=false -fi - -# 显示标题 -show_header() { - clear - echo -e "${CYAN}==========================================${NC}" - echo -e "${CYAN}智能网络监控脚本 - 管理工具${NC}" - echo -e "${CYAN}==========================================${NC}" - echo "" - - if [[ "$IS_SYSTEM_INSTALL" == "true" ]]; then - echo -e "${GREEN}检测到系统级安装${NC}" - echo -e "服务名称: ${BLUE}$SERVICE_NAME${NC}" - else - echo -e "${YELLOW}使用本地模式${NC}" - echo -e "配置文件: ${BLUE}$CONFIG_FILE${NC}" - fi - echo -e "日志路径: ${BLUE}$LOG_PATH${NC}" - echo "" -} - -# 显示菜单 -show_menu() { - echo -e "${YELLOW}可用操作:${NC}" - - if [[ "$IS_SYSTEM_INSTALL" == "true" ]]; then - echo "1. 查看服务状态" - echo "2. 启动服务" - echo "3. 停止服务" - echo "4. 重启服务" - echo "5. 启用开机自启动" - echo "6. 禁用开机自启动" - echo "7. 查看今天的日志" - echo "8. 查看实时日志" - echo "9. 查看系统日志" - echo "10. 查看配置文件" - echo "11. 编辑配置文件" - echo "12. 测试网络连接" - echo "13. 显示服务信息" - echo "0. 退出" - else - echo "1. 查看配置文件" - echo "2. 编辑配置文件" - echo "3. 查看今天的日志" - echo "4. 查看实时日志" - echo "5. 测试网络连接" - echo "6. 启动本地脚本(前台运行)" - echo "7. 清理旧日志" - echo "0. 退出" - fi - echo "" -} - -# 检查服务状态 -check_service_status() { - if systemctl is-active --quiet "$SERVICE_NAME"; then - echo -e "${GREEN}✓ 服务正在运行${NC}" - return 0 - else - echo -e "${RED}✗ 服务未运行${NC}" - return 1 - fi -} - -# 显示服务状态 -show_service_status() { - echo -e "${CYAN}=== 服务状态 ===${NC}" - systemctl status "$SERVICE_NAME" --no-pager -l - echo "" - - echo -e "${CYAN}=== 服务是否启用 ===${NC}" - if systemctl is-enabled --quiet "$SERVICE_NAME" 2>/dev/null; then - echo -e "${GREEN}✓ 开机自启动已启用${NC}" - else - echo -e "${YELLOW}✗ 开机自启动未启用${NC}" - fi - echo "" -} - -# 启动服务 -start_service() { - echo -e "${YELLOW}正在启动服务...${NC}" - if sudo systemctl start "$SERVICE_NAME"; then - echo -e "${GREEN}[OK] 服务已启动${NC}" - else - echo -e "${RED}[ERROR] 启动服务失败${NC}" - fi -} - -# 停止服务 -stop_service() { - echo -e "${YELLOW}正在停止服务...${NC}" - if sudo systemctl stop "$SERVICE_NAME"; then - echo -e "${GREEN}[OK] 服务已停止${NC}" - else - echo -e "${RED}[ERROR] 停止服务失败${NC}" - fi -} - -# 重启服务 -restart_service() { - echo -e "${YELLOW}正在重启服务...${NC}" - if sudo systemctl restart "$SERVICE_NAME"; then - echo -e "${GREEN}[OK] 服务已重启${NC}" - else - echo -e "${RED}[ERROR] 重启服务失败${NC}" - fi -} - -# 启用开机自启动 -enable_service() { - echo -e "${YELLOW}正在启用开机自启动...${NC}" - if sudo systemctl enable "$SERVICE_NAME"; then - echo -e "${GREEN}[OK] 开机自启动已启用${NC}" - else - echo -e "${RED}[ERROR] 启用开机自启动失败${NC}" - fi -} - -# 禁用开机自启动 -disable_service() { - echo -e "${YELLOW}正在禁用开机自启动...${NC}" - if sudo systemctl disable "$SERVICE_NAME"; then - echo -e "${GREEN}[OK] 开机自启动已禁用${NC}" - else - echo -e "${RED}[ERROR] 禁用开机自启动失败${NC}" - fi -} - -# 查看今天的日志 -show_today_log() { - local log_file="$LOG_PATH/network_monitor_$(date '+%Y%m%d').log" - - echo -e "${CYAN}=== 今天的日志 ($log_file) ===${NC}" - if [[ -f "$log_file" ]]; then - echo -e "${BLUE}文件大小: $(du -h "$log_file" | cut -f1)${NC}" - echo -e "${BLUE}最后修改: $(stat -c %y "$log_file")${NC}" - echo "" - echo -e "${YELLOW}最近20行:${NC}" - tail -n 20 "$log_file" - echo "" - echo -e "${CYAN}按任意键查看所有内容,或按 Ctrl+C 返回菜单${NC}" - read -n 1 -s - less "$log_file" - else - echo -e "${RED}今天的日志文件不存在${NC}" - echo -e "${BLUE}日志文件路径: $log_file${NC}" - fi -} - -# 查看实时日志 -show_live_log() { - local log_file="$LOG_PATH/network_monitor_$(date '+%Y%m%d').log" - - echo -e "${CYAN}=== 实时日志监控 ===${NC}" - echo -e "${YELLOW}按 Ctrl+C 退出实时监控${NC}" - echo "" - - if [[ -f "$log_file" ]]; then - tail -f "$log_file" - else - echo -e "${RED}今天的日志文件不存在,监控系统日志...${NC}" - if [[ "$IS_SYSTEM_INSTALL" == "true" ]]; then - journalctl -u "$SERVICE_NAME" -f - else - echo -e "${RED}无可用日志${NC}" - fi - fi -} - -# 查看系统日志 -show_system_log() { - echo -e "${CYAN}=== 系统日志 ===${NC}" - echo -e "${YELLOW}最近100条系统日志:${NC}" - journalctl -u "$SERVICE_NAME" -n 100 --no-pager - echo "" - echo -e "${CYAN}按任意键查看实时系统日志,或按 Ctrl+C 返回菜单${NC}" - read -n 1 -s - journalctl -u "$SERVICE_NAME" -f -} - -# 查看配置文件 -show_config() { - echo -e "${CYAN}=== 配置文件 ($CONFIG_FILE) ===${NC}" - if [[ -f "$CONFIG_FILE" ]]; then - echo -e "${BLUE}文件路径: $CONFIG_FILE${NC}" - echo -e "${BLUE}最后修改: $(stat -c %y "$CONFIG_FILE")${NC}" - echo "" - echo -e "${YELLOW}当前配置:${NC}" - cat "$CONFIG_FILE" - echo "" - - # 如果有jq,则格式化显示 - if command -v jq >/dev/null 2>&1; then - echo -e "${YELLOW}格式化显示:${NC}" - jq . "$CONFIG_FILE" 2>/dev/null || echo -e "${RED}JSON格式错误${NC}" - fi - else - echo -e "${RED}配置文件不存在: $CONFIG_FILE${NC}" - echo -e "${YELLOW}是否创建默认配置文件? (y/N): ${NC}" - read -n 1 response - echo "" - - if [[ "$response" == "y" || "$response" == "Y" ]]; then - create_default_config - fi - fi -} - -# 创建默认配置文件 -create_default_config() { - local config_dir=$(dirname "$CONFIG_FILE") - - # 确保配置目录存在 - if [[ ! -d "$config_dir" ]]; then - if [[ "$IS_SYSTEM_INSTALL" == "true" ]]; then - sudo mkdir -p "$config_dir" - else - mkdir -p "$config_dir" - fi - fi - - local default_config='{ - "TargetIP": "192.168.3.3", - "MonitorWindowSeconds": 180, - "ShutdownCountdown": 60, - "NormalPingInterval": 15 -}' - - if [[ "$IS_SYSTEM_INSTALL" == "true" ]]; then - echo "$default_config" | sudo tee "$CONFIG_FILE" > /dev/null - else - echo "$default_config" > "$CONFIG_FILE" - fi - - echo -e "${GREEN}[OK] 默认配置文件已创建: $CONFIG_FILE${NC}" -} - -# 编辑配置文件 -edit_config() { - if [[ ! -f "$CONFIG_FILE" ]]; then - echo -e "${YELLOW}配置文件不存在,是否创建默认配置? (y/N): ${NC}" - read -n 1 response - echo "" - - if [[ "$response" == "y" || "$response" == "Y" ]]; then - create_default_config - else - return - fi - fi - - echo -e "${CYAN}=== 编辑配置文件 ===${NC}" - echo -e "${YELLOW}使用编辑器编辑配置文件...${NC}" - - # 选择编辑器 - local editor="" - if command -v nano >/dev/null 2>&1; then - editor="nano" - elif command -v vi >/dev/null 2>&1; then - editor="vi" - else - echo -e "${RED}未找到可用的编辑器${NC}" - return - fi - - echo -e "${BLUE}使用编辑器: $editor${NC}" - echo -e "${YELLOW}编辑完成后,如果是系统安装,需要重启服务使配置生效${NC}" - echo "" - - if [[ "$IS_SYSTEM_INSTALL" == "true" ]]; then - sudo "$editor" "$CONFIG_FILE" - echo "" - echo -e "${YELLOW}配置已修改,是否重启服务使配置生效? (y/N): ${NC}" - read -n 1 response - echo "" - - if [[ "$response" == "y" || "$response" == "Y" ]]; then - restart_service - fi - else - "$editor" "$CONFIG_FILE" - fi -} - -# 测试网络连接 -test_network() { - local target_ip="192.168.3.3" - - # 尝试从配置文件读取目标IP - if [[ -f "$CONFIG_FILE" ]] && command -v jq >/dev/null 2>&1; then - local config_ip=$(jq -r '.TargetIP // empty' "$CONFIG_FILE" 2>/dev/null) - [[ -n "$config_ip" ]] && target_ip="$config_ip" - fi - - echo -e "${CYAN}=== 网络连接测试 ===${NC}" - echo -e "${BLUE}目标IP: $target_ip${NC}" - echo "" - - echo -e "${YELLOW}正在测试网络连接...${NC}" - - for i in {1..5}; do - echo -n "测试 $i/5: " - if ping -c 1 -W 3 "$target_ip" >/dev/null 2>&1; then - echo -e "${GREEN}✓ 连接成功${NC}" - else - echo -e "${RED}✗ 连接失败${NC}" - fi - [[ $i -lt 5 ]] && sleep 1 - done - - echo "" - echo -e "${CYAN}详细ping测试:${NC}" - ping -c 4 "$target_ip" -} - -# 启动本地脚本 -start_local_script() { - local script_path="./smart_shutdown.sh" - - echo -e "${CYAN}=== 启动本地脚本 ===${NC}" - - if [[ ! -f "$script_path" ]]; then - echo -e "${RED}本地脚本不存在: $script_path${NC}" - return - fi - - if [[ ! -x "$script_path" ]]; then - echo -e "${YELLOW}脚本没有执行权限,正在添加...${NC}" - chmod +x "$script_path" - fi - - echo -e "${YELLOW}即将启动本地脚本(前台运行)${NC}" - echo -e "${YELLOW}按 Ctrl+C 可以停止脚本${NC}" - echo -e "${BLUE}3秒后开始...${NC}" - - for i in {3..1}; do - echo -n "$i " - sleep 1 - done - echo "" - echo "" - - sudo "$script_path" -} - -# 清理旧日志 -cleanup_old_logs() { - echo -e "${CYAN}=== 清理旧日志 ===${NC}" - - if [[ ! -d "$LOG_PATH" ]]; then - echo -e "${RED}日志目录不存在: $LOG_PATH${NC}" - return - fi - - echo -e "${BLUE}日志目录: $LOG_PATH${NC}" - echo -e "${YELLOW}查找30天前的日志文件...${NC}" - - local old_logs=$(find "$LOG_PATH" -name "network_monitor_*.log" -type f -mtime +30 2>/dev/null) - - if [[ -z "$old_logs" ]]; then - echo -e "${GREEN}没有找到需要清理的旧日志文件${NC}" - return - fi - - echo -e "${YELLOW}找到以下旧日志文件:${NC}" - echo "$old_logs" - echo "" - - echo -e "${YELLOW}确定要删除这些文件吗? (y/N): ${NC}" - read -n 1 response - echo "" - - if [[ "$response" == "y" || "$response" == "Y" ]]; then - echo "$old_logs" | xargs rm -f - echo -e "${GREEN}[OK] 旧日志文件已清理${NC}" - else - echo -e "${YELLOW}清理已取消${NC}" - fi -} - -# 显示服务信息 -show_service_info() { - echo -e "${CYAN}=== 服务详细信息 ===${NC}" - - echo -e "${YELLOW}基本信息:${NC}" - echo -e "服务名称: ${BLUE}$SERVICE_NAME${NC}" - echo -e "配置文件: ${BLUE}$CONFIG_FILE${NC}" - echo -e "日志目录: ${BLUE}$LOG_PATH${NC}" - echo "" - - echo -e "${YELLOW}服务状态:${NC}" - systemctl show "$SERVICE_NAME" --no-pager - echo "" - - echo -e "${YELLOW}最近的服务日志:${NC}" - journalctl -u "$SERVICE_NAME" -n 10 --no-pager -} - -# 等待用户按键 -wait_for_key() { - echo "" - echo -e "${CYAN}按任意键继续...${NC}" - read -n 1 -s -} - -# 主程序 -main() { - while true; do - show_header - show_menu - - read -p "请选择操作: " choice - echo "" - - case "$choice" in - "1") - if [[ "$IS_SYSTEM_INSTALL" == "true" ]]; then - show_service_status - else - show_config - fi - wait_for_key - ;; - "2") - if [[ "$IS_SYSTEM_INSTALL" == "true" ]]; then - start_service - else - edit_config - fi - wait_for_key - ;; - "3") - if [[ "$IS_SYSTEM_INSTALL" == "true" ]]; then - stop_service - else - show_today_log - fi - wait_for_key - ;; - "4") - if [[ "$IS_SYSTEM_INSTALL" == "true" ]]; then - restart_service - else - show_live_log - fi - ;; - "5") - if [[ "$IS_SYSTEM_INSTALL" == "true" ]]; then - enable_service - else - test_network - fi - wait_for_key - ;; - "6") - if [[ "$IS_SYSTEM_INSTALL" == "true" ]]; then - disable_service - else - start_local_script - fi - wait_for_key - ;; - "7") - if [[ "$IS_SYSTEM_INSTALL" == "true" ]]; then - show_today_log - else - cleanup_old_logs - fi - ;; - "8") - [[ "$IS_SYSTEM_INSTALL" == "true" ]] && show_live_log - ;; - "9") - [[ "$IS_SYSTEM_INSTALL" == "true" ]] && show_system_log - ;; - "10") - [[ "$IS_SYSTEM_INSTALL" == "true" ]] && show_config - wait_for_key - ;; - "11") - [[ "$IS_SYSTEM_INSTALL" == "true" ]] && edit_config - wait_for_key - ;; - "12") - [[ "$IS_SYSTEM_INSTALL" == "true" ]] && test_network - wait_for_key - ;; - "13") - [[ "$IS_SYSTEM_INSTALL" == "true" ]] && show_service_info - wait_for_key - ;; - "0") - echo -e "${GREEN}再见!${NC}" - exit 0 - ;; - *) - echo -e "${RED}无效选择,请重新输入${NC}" - wait_for_key - ;; - esac - done -} - -# 检查依赖 -check_dependencies() { - local missing_deps=() - - # 检查必要命令 - for cmd in ping systemctl journalctl; do - if ! command -v "$cmd" >/dev/null 2>&1; then - missing_deps+=("$cmd") - fi - done - - if [[ ${#missing_deps[@]} -gt 0 ]]; then - echo -e "${RED}缺少必要的命令:${NC}" - for dep in "${missing_deps[@]}"; do - echo -e "${RED} - $dep${NC}" - done - echo -e "${YELLOW}请安装缺少的软件包${NC}" - exit 1 - fi - - # 检查可选命令 - if ! command -v jq >/dev/null 2>&1; then - echo -e "${YELLOW}建议安装 jq 以获得更好的JSON配置文件支持${NC}" - echo -e "${BLUE}安装命令: sudo apt-get install jq${NC}" - echo "" - fi -} - -# 启动主程序 -check_dependencies -main \ No newline at end of file diff --git a/pkg/config/config.go b/pkg/config/config.go new file mode 100644 index 0000000..96084c8 --- /dev/null +++ b/pkg/config/config.go @@ -0,0 +1,67 @@ +package config + +import ( + "encoding/json" + "os" + "path/filepath" + "runtime" +) + +// 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 间隔 +} + +// DefaultConfig 提供一套开箱即用的默认配置 +func DefaultConfig() *Config { + return &Config{ + TargetIP: "192.168.3.3", + MonitorWindowSeconds: 180, + ShutdownCountdown: 60, + NormalPingInterval: 15, + } +} + +// GetConfigDir 根据当前操作系统返回标准的配置存放路径 +func GetConfigDir() string { + if runtime.GOOS == "windows" { + return `C:\ProgramData\SmartNetworkMonitor` + } + return `/etc/smart-network-monitor` +} + +// GetLogDir 根据当前操作系统返回标准的日志存放路径 +func GetLogDir() string { + if runtime.GOOS == "windows" { + return `C:\ProgramData\SmartNetworkMonitor\logs` + } + return `/var/log/smart-network-monitor` +} + +// LoadConfig 从系统标准路径读取 config.json 并反序列化。如果不存在,则返回默认配置。 +func LoadConfig() (*Config, error) { + configDir := GetConfigDir() + configPath := filepath.Join(configDir, "config.json") + + data, err := os.ReadFile(configPath) + if err != nil { + if os.IsNotExist(err) { + // 文件不存在时,静默采用默认配置 + return DefaultConfig(), nil + } + return nil, err + } + + if len(data) >= 3 && data[0] == 0xef && data[1] == 0xbb && data[2] == 0xbf { + data = data[3:] + } + + cfg := &Config{} + if err := json.Unmarshal(data, cfg); err != nil { + return nil, err + } + return cfg, nil +} diff --git a/pkg/daemon/service.go b/pkg/daemon/service.go new file mode 100644 index 0000000..277faea --- /dev/null +++ b/pkg/daemon/service.go @@ -0,0 +1,63 @@ +package daemon + +import ( + "context" + + "github.com/kardianos/service" + "smart-shutdown/pkg/config" + "smart-shutdown/pkg/logger" + "smart-shutdown/pkg/monitor" +) + +type program struct { + exit chan struct{} + cancel context.CancelFunc + cfg *config.Config +} + +func (p *program) Start(s service.Service) error { + // Start should not block. Do the actual work async. + logger.Info("准备在后台启动服务监控...") + + ctx, cancel := context.WithCancel(context.Background()) + p.cancel = cancel + p.exit = make(chan struct{}) + + go p.run(ctx) + return nil +} + +func (p *program) run(ctx context.Context) { + // 挂载执行核心循环逻辑 + monitor.Run(ctx, p.cfg) + close(p.exit) +} + +func (p *program) Stop(s service.Service) error { + // Stop should not block. Return within a few seconds. + logger.Info("正在平滑停止后台服务监控...") + if p.cancel != nil { + p.cancel() + } + <-p.exit + return nil +} + +// GetService 构建 service 实例供 CLI 控制(安装,启动,停止,卸载)和前台直接 Run。 +func GetService(cfg *config.Config) (service.Service, error) { + svcConfig := &service.Config{ + Name: "SmartNetworkMonitor", + DisplayName: "Smart Network Shutdown Monitor", + Description: "A daemon that pings target IP periodically and shuts down the computer if disconnected for too long.", + } + + prg := &program{ + cfg: cfg, + } + + s, err := service.New(prg, svcConfig) + if err != nil { + return nil, err + } + return s, nil +} diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go new file mode 100644 index 0000000..6a9eba3 --- /dev/null +++ b/pkg/logger/logger.go @@ -0,0 +1,70 @@ +package logger + +import ( + "io" + "log" + "os" + "path/filepath" + + "github.com/fatih/color" + "gopkg.in/natefinch/lumberjack.v2" + "smart-shutdown/pkg/config" +) + +var ( + infoLogger *log.Logger + succLogger *log.Logger + warnLogger *log.Logger + failLogger *log.Logger + critLogger *log.Logger +) + +// InitLogger 初始化全局日志系统,将日志同时输出到终端色彩日志和滚动文件 +func InitLogger() error { + logDir := config.GetLogDir() + if err := os.MkdirAll(logDir, 0755); err != nil { + // 降级为当前目录,适用于未具有系统写权限的 Local 执行 + logDir = "logs" + os.MkdirAll(logDir, 0755) + } + + logFile := filepath.Join(logDir, "network_monitor.log") + + // 使用 lumberjack 实现每天轮转和最大保留 30 天功能 + ljLogger := &lumberjack.Logger{ + Filename: logFile, + MaxSize: 10, // 每个切片最大兆字节 (MB) + MaxBackups: 30, // 保留最近 30 个切片 + MaxAge: 30, // 保留最近 30 天的文件 + Compress: false, // 是否压缩 + } + + // 各级别终端色彩 + cSucc := color.New(color.FgGreen).SprintFunc() + cFail := color.New(color.FgRed).SprintFunc() + cWarn := color.New(color.FgYellow).SprintFunc() + cCrit := color.New(color.FgHiRed, color.Bold).SprintFunc() + + // 构建复合输出写入器:终端标准输出 + 日志文件 + outGeneral := io.MultiWriter(os.Stdout, ljLogger) + outError := io.MultiWriter(os.Stderr, ljLogger) + + // 时间戳格式前缀 + flags := log.Ldate | log.Ltime + + // 实例化各个级别 Logger + infoLogger = log.New(outGeneral, "[INFO] ", flags) + succLogger = log.New(outGeneral, cSucc("[SUCCESS] "), flags) + warnLogger = log.New(outGeneral, cWarn("[WARN] "), flags) + failLogger = log.New(outError, cFail("[FAIL] "), flags) + critLogger = log.New(outError, cCrit("[CRITICAL] "), flags) + + return nil +} + +// 封装导出供业务调用的函数 +func Info(format string, v ...interface{}) { infoLogger.Printf(format, v...) } +func Succ(format string, v ...interface{}) { succLogger.Printf(format, v...) } +func Warn(format string, v ...interface{}) { warnLogger.Printf(format, v...) } +func Fail(format string, v ...interface{}) { failLogger.Printf(format, v...) } +func Crit(format string, v ...interface{}) { critLogger.Printf(format, v...) } diff --git a/pkg/monitor/statemachine.go b/pkg/monitor/statemachine.go new file mode 100644 index 0000000..44b9b6b --- /dev/null +++ b/pkg/monitor/statemachine.go @@ -0,0 +1,124 @@ +package monitor + +import ( + "context" + "time" + + "smart-shutdown/pkg/config" + "smart-shutdown/pkg/logger" + "smart-shutdown/pkg/pinger" + "smart-shutdown/pkg/system" +) + +// Run 开启核心状态机循环监控,接收 ctx 以便主程序或者服务管理器控制安全退出 +func Run(ctx context.Context, cfg *config.Config) { + logger.Info("========== 智能关机监控已启动 ==========") + logger.Info("监控目标: %s", cfg.TargetIP) + logger.Info("监控窗口: %d秒", cfg.MonitorWindowSeconds) + logger.Info("关机倒计时: %d秒", cfg.ShutdownCountdown) + + var failureStartTime time.Time + var inFailureWindow bool = false + + normalStatusCounter := 0 + // 每 24 次正常检测输出一次日志(约 6 分钟) + const normalStatusLogInterval = 24 + + for { + select { + case <-ctx.Done(): + logger.Info("========== 收到停止信号,退出监控 ==========") + return + default: + } + + isOnline := pinger.Ping(cfg.TargetIP, 3) // 3 秒超时探测一次 + + if isOnline { + if inFailureWindow { + logger.Succ("网络连接已恢复!重置断网计时器。") + inFailureWindow = false + normalStatusCounter = 0 + } else { + normalStatusCounter++ + if normalStatusCounter >= normalStatusLogInterval { + logger.Info("网络连接持续正常(已检测 %d 次)", normalStatusCounter) + normalStatusCounter = 0 + } + } + + // 正常状态下休眠等待下一次探测 + time.Sleep(time.Duration(cfg.NormalPingInterval) * time.Second) + + } else { + logger.Fail("Ping 测试失败 - 目标: %s", cfg.TargetIP) + + if !inFailureWindow { + // 首次断网 + failureStartTime = time.Now() + inFailureWindow = true + logger.Warn("网络首次中断,开始进入监控窗口计时。") + } + + // 计算当前断网累计时间 + failureDuration := time.Since(failureStartTime).Seconds() + + if int(failureDuration) >= cfg.MonitorWindowSeconds { + logger.Crit("网络持续中断已超过 %d 秒,触发关机流程!", cfg.MonitorWindowSeconds) + + // 进入倒计时阶段,倒计时期间高频检测(阻塞调用) + shutdownCancelled := startCountdown(ctx, cfg.TargetIP, cfg.ShutdownCountdown) + + if !shutdownCancelled { + logger.Crit("倒计时结束,执行最终关机!") + system.ExecuteShutdown() + // 关机指令发出,理论上系统即将终止进程,为了优雅,此处也退出 + return + } else { + // 倒计时中途网络恢复被取消了,重置状态重新进入监控环节 + inFailureWindow = false + } + } else { + // 还在容忍窗口期内,仅仅打印日志并休眠 + logger.Info("网络已持续中断 %.0f / %d 秒,继续监控...", failureDuration, cfg.MonitorWindowSeconds) + time.Sleep(time.Duration(cfg.NormalPingInterval) * time.Second) + } + } + } +} + +// startCountdown 执行关机前倒计时的轮询,如果中途恢复网络返回 true (代表取消关机)。 +// 返回 false 代表断网到底,坚决关机。 +func startCountdown(ctx context.Context, targetIP string, countdownSec int) bool { + logger.Warn("============================================") + logger.Warn("准备关机!倒计时 %d 秒期间将快速探测网络...", countdownSec) + logger.Warn("============================================") + + endTime := time.Now().Add(time.Duration(countdownSec) * time.Second) + // 倒计时期间提高探测频率:每 3 秒一次 + ticker := time.NewTicker(3 * time.Second) + defer ticker.Stop() + + for { + remaining := int(time.Until(endTime).Seconds()) + if remaining <= 0 { + return false // 时间到,确认无法恢复 + } + + logger.Warn("距离关机还有 %d 秒... 正在高频检测网络", remaining) + + select { + case <-ctx.Done(): + logger.Info("收到退出系统服务信号,中止倒计时关机!") + return true + case <-ticker.C: + // 高频重试检测网络 + if pinger.Ping(targetIP, 3) { + logger.Succ("============================================") + logger.Succ("网络在倒计时期间奇迹般地恢复了!立刻取消关机!") + logger.Succ("============================================") + return true + } + } + } +} diff --git a/pkg/pinger/pinger.go b/pkg/pinger/pinger.go new file mode 100644 index 0000000..5182d67 --- /dev/null +++ b/pkg/pinger/pinger.go @@ -0,0 +1,41 @@ +package pinger + +import ( + "time" + + probing "github.com/prometheus-community/pro-bing" + "smart-shutdown/pkg/logger" +) + +// Ping 连通性测试,向指定的 targetIP 发送 ICMP 请求。 +// 如果规定时间内可达返回 true,超时或者全部丢包返回 false。 +func Ping(targetIP string, timeoutSec int) bool { + pinger, err := probing.NewPinger(targetIP) + if err != nil { + logger.Warn("解析目标 IP 失败 [%s]: %v", targetIP, err) + return false + } + + // 大部分操作系统为了安全,普通程序发 ICMP 包会被拦截。开启 Privileged 会尝试使用 raw sockets 发行 + // 本程序由于本身作为系统服务(System 或 Root 权限)运行,故直接开启特权模式以保障发包成功率。 + pinger.SetPrivileged(true) + + // 只发送 1 个探测包 + pinger.Count = 1 + pinger.Timeout = time.Duration(timeoutSec) * time.Second + + err = pinger.Run() + if err != nil { + logger.Fail("Ping 测试运行时遇到异常: %v", err) + return false + } + + stats := pinger.Statistics() + // 只要成功收到至少 1 个回包,认为网络通畅 + if stats.PacketsRecv > 0 { + return true + } + + // 丢包或者无回音 + return false +} diff --git a/pkg/system/shutdown.go b/pkg/system/shutdown.go new file mode 100644 index 0000000..7bb0bab --- /dev/null +++ b/pkg/system/shutdown.go @@ -0,0 +1,28 @@ +package system + +import ( + "os/exec" + "runtime" + "smart-shutdown/pkg/logger" +) + +// ExecuteShutdown 跨平台执行立即无条件关机 +func ExecuteShutdown() error { + logger.Crit("执行系统关机操作!") + + // 注意:在实际正式环境使用前,如果想防误触可暂时注释掉下方的 `cmd.Run()` + var cmd *exec.Cmd + if runtime.GOOS == "windows" { + cmd = exec.Command("shutdown", "-s", "-f", "-t", "0") + } else { + cmd = exec.Command("shutdown", "-h", "now") + } + + err := cmd.Run() + if err != nil { + logger.Crit("系统关机指令执行失败: %v", err) + return err + } + + return nil +} diff --git a/run_deploy.ps1 b/run_deploy.ps1 deleted file mode 100644 index e69de29..0000000 diff --git a/smart-monitor.exe b/smart-monitor.exe new file mode 100644 index 0000000..bed89a1 Binary files /dev/null and b/smart-monitor.exe differ diff --git a/smart_shutdown.ps1 b/smart_shutdown.ps1 deleted file mode 100644 index de6d58a..0000000 --- a/smart_shutdown.ps1 +++ /dev/null @@ -1,239 +0,0 @@ -#Requires -Version 5.1 -#Requires -RunAsAdministrator - -<# -.SYNOPSIS - 一个智能网络监控脚本,当检测到与目标IP的网络持续中断后,会自动关闭计算机。 - -.DESCRIPTION - 该脚本会定期测试与指定目标IP的网络连通性。 - 如果在设定的“监控窗口”时间内连接持续失败,脚本将启动一个可取消的关机倒计时。 - 如果在倒计时期间网络恢复,关机将被中止。 - 所有操作都会被记录在日志文件中。 -#> - -# ==================== 配置参数 ==================== - -# 监控的目标IP地址 -[string]$TargetIP = "192.168.3.15" - -# 正常监控时的ping间隔(秒) -[int]$NormalPingInterval = 15 - -# 监控窗口时长(秒) - 在此期间持续失败则触发关机 -[int]$MonitorWindowSeconds = 60 - -# 关机倒计时时长(秒) -[int]$ShutdownCountdown = 60 - -# 关机倒计时阶段的ping间隔(秒) -[int]$CountdownPingInterval = 3 - -# ping超时时间(秒) -[int]$PingTimeout = 3 - -# 日志配置 -[string]$LogDirectory = Join-Path -Path $PSScriptRoot -ChildPath "logs" -#[string]$LogFile = Join-Path -Path $LogDirectory -ChildPath "network_monitor_$(Get-Date -Format 'yyyyMMdd').log" -[int]$MaxLogDays = 30 - -# ================================================= - -# --- 函数定义 --- - -# 日志写入函数 -function Write-Log { - param( - [Parameter(Mandatory=$true)] - [ValidateSet("INFO", "SUCCESS", "FAIL", "WARN", "CRITICAL", "DEBUG")] - [string]$Level, - - [Parameter(Mandatory=$true)] - [string]$Message - ) - - # ===================== V0.2update ===================== - # 每次写日志时,都重新根据当前日期确定日志文件名 - $LogFile = Join-Path -Path $LogDirectory -ChildPath "network_monitor_$(Get-Date -Format 'yyyyMMdd').log" - # ==================================================== - - $logTimestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" - $logEntry = "[$logTimestamp] [$Level] $Message" - - # 尝试写入日志文件 - try { - if (-not (Test-Path -Path $LogDirectory)) { - New-Item -Path $LogDirectory -ItemType Directory -ErrorAction Stop | Out-Null - } - Add-Content -Path $LogFile -Value $logEntry -ErrorAction Stop - } - catch { - Write-Host "[$logTimestamp] [CRITICAL] 日志文件写入失败!请检查权限或磁盘空间。" -ForegroundColor Red - } - - # 根据日志级别在控制台输出不同颜色的信息 - switch ($Level) { - "SUCCESS" { Write-Host $logEntry -ForegroundColor Green } - "FAIL" { Write-Host $logEntry -ForegroundColor Red } - "WARN" { Write-Host $logEntry -ForegroundColor Yellow } - "CRITICAL" { Write-Host $logEntry -ForegroundColor DarkRed } - default { Write-Host $logEntry } - } -} - -# 获取本机的最佳IP地址 -function Get-LocalIP { - param($TargetIP) - try { - # 尝试寻找与目标IP在同一个子网的本机IP地址 - $targetSubnet = ($TargetIP.Split('.')[0..2]) -join '.' - $ip = Get-NetIPAddress -AddressFamily IPv4 -AddressState Preferred | Where-Object { $_.IPAddress -like "$targetSubnet.*" } | Select-Object -First 1 -ExpandProperty IPAddress - - if ($ip) { return $ip } - - # 如果找不到,则返回任意一个非环回的私有IP地址 - $ip = Get-NetIPAddress -AddressFamily IPv4 -AddressState Preferred | Where-Object { $_.IPAddress -notlike "127.0.0.1" -and $_.InterfaceAlias -notlike "Loopback*" } | Select-Object -First 1 -ExpandProperty IPAddress - return $ip - } - catch { - return "未知" - } -} - - -# --- 脚本主逻辑 --- - -# 清理旧日志 -if (Test-Path -Path $LogDirectory) { - Get-ChildItem -Path $LogDirectory -Filter "*.log" | Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-$MaxLogDays) } | Remove-Item -} - -# 初始化 -Clear-Host -$localIP = Get-LocalIP -TargetIP $TargetIP -Write-Log -Level "INFO" -Message "========== 脚本启动 ==========" -Write-Log -Level "INFO" -Message "本机IP: $localIP" -Write-Log -Level "INFO" -Message "监控目标: $TargetIP" -Write-Log -Level "INFO" -Message "监控窗口: ${MonitorWindowSeconds}秒" -Write-Log -Level "INFO" -Message "关机倒计时: ${ShutdownCountdown}秒" -Write-Log -Level "INFO" -Message "日志文件: $LogFile" -Write-Log -Level "INFO" -Message "脚本已启动,按 Ctrl+C 退出..." -Write-Host "========================================" - -# 主循环 -$failureStartTime = $null -$normalStatusCounter = 0 # 正常状态计数器,用于定期记录正常运行日志 -$normalStatusLogInterval = 24 # 每24次正常检测记录一次日志(约6分钟) - -while ($true) {# 测试网络连接 - try { - # 使用兼容性更好的ping方法 - $pingResult = Test-Connection -ComputerName $TargetIP -Count 1 -Quiet -ErrorAction SilentlyContinue - $isOnline = $pingResult - } catch { - Write-Log -Level "FAIL" -Message "网络测试出现异常: $($_.Exception.Message)" - $isOnline = $false - } if ($isOnline) { - if ($failureStartTime) { - Write-Log -Level "SUCCESS" -Message "网络连接已恢复。" - Write-Host "[OK] 网络连接已恢复,重置监控窗口" -ForegroundColor Green - $failureStartTime = $null # 重置失败计时器 - $normalStatusCounter = 0 # 重置正常状态计数器 - } else { - Write-Host "[OK] 网络连接正常" -ForegroundColor Green - # 正常连接时减少日志频率,只定期记录 - $normalStatusCounter++ - if ($normalStatusCounter -ge $normalStatusLogInterval) { - Write-Log -Level "INFO" -Message "网络连接持续正常(已检测 $normalStatusCounter 次)" - $normalStatusCounter = 0 # 重置计数器 - } - } - # 只在控制台显示等待信息,不写入日志文件 - Write-Host "等待 ${NormalPingInterval}秒后继续监控..." -ForegroundColor Cyan - Start-Sleep -Seconds $NormalPingInterval - - } else { - # 如果网络不通 - Write-Log -Level "FAIL" -Message "Ping失败 - 目标: $TargetIP" - - if (-not $failureStartTime) { - # 记录首次失败的时间 - $failureStartTime = Get-Date - Write-Log -Level "WARN" -Message "网络首次中断,开始进入监控窗口计时。" - } # 计算网络已中断的时间 - $failureDuration = (New-TimeSpan -Start $failureStartTime -End (Get-Date)).TotalSeconds - Write-Log -Level "INFO" -Message "网络已持续中断 $([math]::Round($failureDuration)) / ${MonitorWindowSeconds} 秒。" - - # 显示详细状态 - $remainingTime = $MonitorWindowSeconds - [math]::Round($failureDuration) - Write-Host "监控状态 - 已中断: $([math]::Round($failureDuration))/${MonitorWindowSeconds}秒,剩余: ${remainingTime}秒" -ForegroundColor Yellow - - if ($failureDuration -ge $MonitorWindowSeconds) { - # 持续失败时间超过监控窗口,开始关机倒计时 - Write-Log -Level "CRITICAL" -Message "网络持续中断已超过 ${MonitorWindowSeconds} 秒,开始关机流程。" - Write-Host "========================================" -ForegroundColor Yellow - $shutdownCancelled = $false - $countdownEndTime = (Get-Date).AddSeconds($ShutdownCountdown) - while ((Get-Date) -lt $countdownEndTime -and -not $shutdownCancelled) { - $remainingSeconds = [math]::Ceiling(($countdownEndTime - (Get-Date)).TotalSeconds) - if ($remainingSeconds -le 0) { break } - - Write-Log -Level "WARN" -Message "距离关机还有 $remainingSeconds 秒... 正在快速检测网络。" - Write-Host "----------------------------------------" -ForegroundColor Yellow - Write-Host "距离关机还有 $remainingSeconds 秒..." -ForegroundColor Yellow - Write-Host "正在快速检测网络连接... 按任意键可手动取消关机" -ForegroundColor Yellow # 在倒计时中再次检测网络 - try { - if (Test-Connection -ComputerName $TargetIP -Count 1 -Quiet -ErrorAction SilentlyContinue) { - Write-Log -Level "SUCCESS" -Message "网络在倒计时期间恢复!取消关机。" - Write-Host "========================================" -ForegroundColor Green - Write-Host "[OK] 网络连接已恢复!取消关机操作" -ForegroundColor Green - Write-Host "========================================" -ForegroundColor Green - $failureStartTime = $null - $shutdownCancelled = $true - break - } else { - Write-Host "[X] 网络仍然中断" -ForegroundColor Red - } - } - catch { - Write-Log -Level "WARN" -Message "倒计时期间网络测试出现异常: $($_.Exception.Message)" - Write-Host "[X] 网络测试异常" -ForegroundColor Red - } - # 检查是否有按键输入(手动取消) - $timeout = $CountdownPingInterval - $startTime = Get-Date - while (((Get-Date) - $startTime).TotalSeconds -lt $timeout -and -not $shutdownCancelled) { - if ([Console]::KeyAvailable) { - $null = [Console]::ReadKey($true) # 读取按键但不使用 - Write-Log -Level "WARN" -Message "用户手动取消了关机操作" Write-Host "" - Write-Host "========================================" -ForegroundColor Cyan - Write-Host "[INFO] 用户已手动取消关机,返回监控模式" -ForegroundColor Cyan - Write-Host "========================================" -ForegroundColor Cyan - $failureStartTime = $null - $shutdownCancelled = $true - break } - Start-Sleep -Milliseconds 100 - } - } - - if (-not $shutdownCancelled) { - Write-Log -Level "CRITICAL" -Message "关机倒计时完成,执行系统关机命令。" - try { - # 取消注释下一行以启用实际关机 - # Stop-Computer -Force - Write-Host "模拟关机:Stop-Computer -Force (为防止意外,此行已注释)" -ForegroundColor Red - Write-Log -Level "CRITICAL" -Message "关机命令已执行(模拟模式)。" - } - catch { - Write-Log -Level "CRITICAL" -Message "关机命令执行失败: $($_.Exception.Message)" - } - # 脚本执行完关机命令后可以退出 - exit - } - } else { - # 在监控窗口期内,继续等待 - Write-Log -Level "INFO" -Message "等待 ${NormalPingInterval}秒后继续..." - Start-Sleep -Seconds $NormalPingInterval - } - } -} diff --git a/smart_shutdown.sh b/smart_shutdown.sh deleted file mode 100755 index 28b5a32..0000000 --- a/smart_shutdown.sh +++ /dev/null @@ -1,316 +0,0 @@ -#!/bin/bash - -# -# 智能网络监控脚本 - Ubuntu版本 -# -# 功能描述: -# 该脚本会定期测试与指定目标IP的网络连通性。 -# 如果在设定的"监控窗口"时间内连接持续失败,脚本将启动一个可取消的关机倒计时。 -# 如果在倒计时期间网络恢复,关机将被中止。 -# 所有操作都会被记录在日志文件中。 -# -# 使用方法: -# sudo ./smart_shutdown.sh -# -# 要求:需要root权限来执行关机命令 -# - -# ==================== 配置参数 ==================== - -# 监控的目标IP地址 -TARGET_IP="192.168.3.15" - -# 正常监控时的ping间隔(秒) -NORMAL_PING_INTERVAL=15 - -# 监控窗口时长(秒) - 在此期间持续失败则触发关机 -MONITOR_WINDOW_SECONDS=180 - -# 关机倒计时时长(秒) -SHUTDOWN_COUNTDOWN=60 - -# 关机倒计时阶段的ping间隔(秒) -COUNTDOWN_PING_INTERVAL=3 - -# ping超时时间(秒) -PING_TIMEOUT=3 - -# 日志配置 -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -LOG_DIRECTORY="$SCRIPT_DIR/logs" -MAX_LOG_DAYS=30 - -# 配置文件路径 -CONFIG_FILE="$SCRIPT_DIR/config.json" - -# ==================== 函数定义 ==================== - -# 颜色定义 -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -CYAN='\033[0;36m' -PURPLE='\033[0;35m' -NC='\033[0m' # No Color - -# 日志写入函数 -write_log() { - local level="$1" - local message="$2" - local timestamp=$(date '+%Y-%m-%d %H:%M:%S') - local log_file="$LOG_DIRECTORY/network_monitor_$(date '+%Y%m%d').log" - local log_entry="[$timestamp] [$level] $message" - - # 确保日志目录存在 - mkdir -p "$LOG_DIRECTORY" - - # 写入日志文件 - echo "$log_entry" >> "$log_file" - - # 根据日志级别在控制台输出不同颜色的信息 - case "$level" in - "SUCCESS") - echo -e "${GREEN}$log_entry${NC}" - ;; - "FAIL") - echo -e "${RED}$log_entry${NC}" - ;; - "WARN") - echo -e "${YELLOW}$log_entry${NC}" - ;; - "CRITICAL") - echo -e "${PURPLE}$log_entry${NC}" - ;; - "INFO") - echo -e "$log_entry" - ;; - *) - echo -e "$log_entry" - ;; - esac -} - -# 加载配置文件 -load_configuration() { - if [[ -f "$CONFIG_FILE" ]]; then - write_log "INFO" "加载配置文件: $CONFIG_FILE" - - # 使用jq解析JSON配置文件(如果可用) - if command -v jq >/dev/null 2>&1; then - local target_ip=$(jq -r '.TargetIP // empty' "$CONFIG_FILE" 2>/dev/null) - local monitor_window=$(jq -r '.MonitorWindowSeconds // empty' "$CONFIG_FILE" 2>/dev/null) - local shutdown_countdown=$(jq -r '.ShutdownCountdown // empty' "$CONFIG_FILE" 2>/dev/null) - local ping_interval=$(jq -r '.NormalPingInterval // empty' "$CONFIG_FILE" 2>/dev/null) - - [[ -n "$target_ip" ]] && TARGET_IP="$target_ip" - [[ -n "$monitor_window" ]] && MONITOR_WINDOW_SECONDS="$monitor_window" - [[ -n "$shutdown_countdown" ]] && SHUTDOWN_COUNTDOWN="$shutdown_countdown" - [[ -n "$ping_interval" ]] && NORMAL_PING_INTERVAL="$ping_interval" - - write_log "SUCCESS" "配置文件加载成功" - else - write_log "WARN" "jq未安装,无法解析JSON配置文件,使用默认配置" - fi - else - # 创建默认配置文件 - create_default_config - fi -} - -# 创建默认配置文件 -create_default_config() { - cat > "$CONFIG_FILE" << EOF -{ - "TargetIP": "$TARGET_IP", - "MonitorWindowSeconds": $MONITOR_WINDOW_SECONDS, - "ShutdownCountdown": $SHUTDOWN_COUNTDOWN, - "NormalPingInterval": $NORMAL_PING_INTERVAL -} -EOF - write_log "INFO" "创建默认配置文件: $CONFIG_FILE" -} - -# 获取本机IP地址 -get_local_ip() { - local local_ip - # 尝试获取默认路由接口的IP地址 - local_ip=$(ip route get 8.8.8.8 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="src") print $(i+1)}' | head -1) - - if [[ -z "$local_ip" ]]; then - # 备用方法:获取第一个非环回接口的IP - local_ip=$(ip addr show | grep -E 'inet [0-9]' | grep -v '127.0.0.1' | head -1 | awk '{print $2}' | cut -d'/' -f1) - fi - - [[ -n "$local_ip" ]] && echo "$local_ip" || echo "未知" -} - -# 测试网络连接 -test_network_connection() { - local target_ip="$1" - # 使用ping命令测试连接,发送1个包,超时时间为PING_TIMEOUT秒 - ping -c 1 -W "$PING_TIMEOUT" "$target_ip" >/dev/null 2>&1 - return $? -} - -# 清理旧日志文件 -cleanup_old_logs() { - if [[ -d "$LOG_DIRECTORY" ]]; then - # 删除超过MAX_LOG_DAYS天的日志文件 - find "$LOG_DIRECTORY" -name "network_monitor_*.log" -type f -mtime +$MAX_LOG_DAYS -exec rm -f {} \; 2>/dev/null - fi -} - -# 信号处理函数 -cleanup_and_exit() { - write_log "INFO" "接收到退出信号,正在清理..." - write_log "INFO" "========== 脚本退出 ==========" - exit 0 -} - -# 检查root权限 -check_root_permission() { - if [[ $EUID -ne 0 ]]; then - echo -e "${RED}错误:此脚本需要root权限才能执行关机操作${NC}" - echo -e "${YELLOW}请使用以下命令运行:${NC}" - echo -e "${CYAN}sudo $0${NC}" - exit 1 - fi -} - -# ==================== 主程序开始 ==================== - -# 设置信号处理 -trap cleanup_and_exit SIGINT SIGTERM - -# 检查权限 -check_root_permission - -# 清理旧日志 -cleanup_old_logs - -# 加载配置 -load_configuration - -# 初始化 -clear -local_ip=$(get_local_ip) -write_log "INFO" "========== 脚本启动 ==========" -write_log "INFO" "运行用户: $(whoami)" -write_log "INFO" "本机IP: $local_ip" -write_log "INFO" "监控目标: $TARGET_IP" -write_log "INFO" "监控窗口: ${MONITOR_WINDOW_SECONDS}秒" -write_log "INFO" "关机倒计时: ${SHUTDOWN_COUNTDOWN}秒" -write_log "INFO" "日志目录: $LOG_DIRECTORY" -write_log "INFO" "配置文件: $CONFIG_FILE" -write_log "INFO" "脚本已启动,按 Ctrl+C 退出..." - -echo "========================================" - -# 主循环变量 -failure_start_time="" -normal_status_counter=0 -normal_status_log_interval=24 # 每24次正常检测记录一次日志(约6分钟) - -# 主循环 -while true; do - # 测试网络连接 - if test_network_connection "$TARGET_IP"; then - # 网络连接正常 - if [[ -n "$failure_start_time" ]]; then - write_log "SUCCESS" "网络连接已恢复" - echo -e "${GREEN}[OK] 网络连接已恢复,重置监控窗口${NC}" - failure_start_time="" # 重置失败计时器 - normal_status_counter=0 # 重置正常状态计数器 - else - echo -e "${GREEN}[OK] 网络连接正常${NC}" - # 正常连接时减少日志频率,只定期记录 - ((normal_status_counter++)) - if [[ $normal_status_counter -ge $normal_status_log_interval ]]; then - write_log "INFO" "网络连接持续正常(已检测 $normal_status_counter 次)" - normal_status_counter=0 # 重置计数器 - fi - fi - - # 只在控制台显示等待信息,不写入日志文件 - echo -e "${CYAN}等待 ${NORMAL_PING_INTERVAL}秒后继续监控...${NC}" - sleep "$NORMAL_PING_INTERVAL" - - else - # 网络连接失败 - write_log "FAIL" "Ping失败 - 目标: $TARGET_IP" - - if [[ -z "$failure_start_time" ]]; then - # 记录首次失败的时间 - failure_start_time=$(date +%s) - write_log "WARN" "网络首次中断,开始进入监控窗口计时" - fi - - # 计算网络已中断的时间 - current_time=$(date +%s) - failure_duration=$((current_time - failure_start_time)) - write_log "INFO" "网络已持续中断 $failure_duration / ${MONITOR_WINDOW_SECONDS} 秒" - - # 显示详细状态 - remaining_time=$((MONITOR_WINDOW_SECONDS - failure_duration)) - echo -e "${YELLOW}监控状态 - 已中断: ${failure_duration}/${MONITOR_WINDOW_SECONDS}秒,剩余: ${remaining_time}秒${NC}" - - if [[ $failure_duration -ge $MONITOR_WINDOW_SECONDS ]]; then - # 持续失败时间超过监控窗口,开始关机倒计时 - write_log "CRITICAL" "网络持续中断已超过 ${MONITOR_WINDOW_SECONDS} 秒,开始关机流程" - echo "========================================" - - shutdown_cancelled=false - countdown_end_time=$((current_time + SHUTDOWN_COUNTDOWN)) - - while [[ $(date +%s) -lt $countdown_end_time && "$shutdown_cancelled" == "false" ]]; do - current_time=$(date +%s) - remaining_seconds=$((countdown_end_time - current_time)) - - if [[ $remaining_seconds -le 0 ]]; then - break - fi - - write_log "WARN" "距离关机还有 $remaining_seconds 秒... 正在快速检测网络" - echo "----------------------------------------" - echo -e "${YELLOW}距离关机还有 $remaining_seconds 秒...${NC}" - echo -e "${YELLOW}正在快速检测网络连接... 按 Ctrl+C 可取消关机${NC}" - - # 在倒计时中再次检测网络 - if test_network_connection "$TARGET_IP"; then - write_log "SUCCESS" "网络在倒计时期间恢复!取消关机" - echo "========================================" - echo -e "${GREEN}[OK] 网络连接已恢复!取消关机操作${NC}" - echo "========================================" - failure_start_time="" - shutdown_cancelled=true - break - else - echo -e "${RED}[X] 网络仍然中断${NC}" - fi - - # 等待下一次检测 - sleep "$COUNTDOWN_PING_INTERVAL" - done - - if [[ "$shutdown_cancelled" == "false" ]]; then - write_log "CRITICAL" "关机倒计时完成,执行系统关机命令" - - # 执行关机命令 - # 注意:为了安全起见,默认注释掉实际的关机命令 - # 如需启用,请取消下面一行的注释 - # shutdown -h now - - echo -e "${RED}模拟关机:shutdown -h now (为防止意外,此行已注释)${NC}" - write_log "CRITICAL" "关机命令已执行(模拟模式)" - - # 脚本执行完关机命令后可以退出 - exit 0 - fi - else - # 在监控窗口期内,继续等待 - write_log "INFO" "等待 ${NORMAL_PING_INTERVAL}秒后继续..." - sleep "$NORMAL_PING_INTERVAL" - fi - fi -done \ No newline at end of file diff --git a/uninstall_system.ps1 b/uninstall_system.ps1 deleted file mode 100644 index 285f938..0000000 --- a/uninstall_system.ps1 +++ /dev/null @@ -1,91 +0,0 @@ -#Requires -RunAsAdministrator - -<# -.SYNOPSIS - 智能网络监控脚本 - 系统卸载脚本 - -.DESCRIPTION - 完全卸载系统级部署的智能网络监控脚本 -#> - -$ProgramPath = "C:\Program Files\SmartNetworkMonitor" -$DataPath = "C:\ProgramData\SmartNetworkMonitor" - -Write-Host "==========================================" -ForegroundColor Red -Write-Host "智能网络监控脚本 - 系统卸载" -ForegroundColor Red -Write-Host "==========================================" -ForegroundColor Red -Write-Host "" - -Write-Host "将要删除:" -ForegroundColor Yellow -Write-Host "- 程序目录: $ProgramPath" -ForegroundColor White -Write-Host "- 数据目录: $DataPath (包含日志文件)" -ForegroundColor White -Write-Host "- 任务计划程序条目" -ForegroundColor White -Write-Host "- 事件日志源" -ForegroundColor White -Write-Host "" - -$confirmation = Read-Host "确定要继续吗?这将删除所有相关文件和配置 (y/N)" - -if ($confirmation -ne 'y' -and $confirmation -ne 'Y') { - Write-Host "卸载已取消" -ForegroundColor Green - exit 0 -} - -Write-Host "" -Write-Host "正在卸载..." -ForegroundColor Yellow - -# 停止并删除任务计划程序 -try { - $task = Get-ScheduledTask -TaskName "Smart Network Shutdown Monitor" -ErrorAction SilentlyContinue - if ($task) { - Stop-ScheduledTask -TaskName "Smart Network Shutdown Monitor" -ErrorAction SilentlyContinue - Unregister-ScheduledTask -TaskName "Smart Network Shutdown Monitor" -Confirm:$false - Write-Host "[OK] 任务计划程序已删除" -ForegroundColor Green - } -} -catch { - Write-Host "[X] 删除任务计划程序失败: $($_.Exception.Message)" -ForegroundColor Red -} - -# 删除事件日志源 -try { - if ([System.Diagnostics.EventLog]::SourceExists("SmartNetworkMonitor")) { - [System.Diagnostics.EventLog]::DeleteEventSource("SmartNetworkMonitor") - Write-Host "[OK] 事件日志源已删除" -ForegroundColor Green - } -} -catch { - Write-Host "[X] 删除事件日志源失败: $($_.Exception.Message)" -ForegroundColor Red -} - -# 删除程序目录 -try { - if (Test-Path $ProgramPath) { - Remove-Item -Path $ProgramPath -Recurse -Force - Write-Host "[OK] 程序目录已删除: $ProgramPath" -ForegroundColor Green - } -} -catch { - Write-Host "[X] 删除程序目录失败: $($_.Exception.Message)" -ForegroundColor Red -} - -# 询问是否删除数据目录(包含日志) -Write-Host "" -$deleteData = Read-Host "是否同时删除数据目录和所有日志文件?(y/N)" - -if ($deleteData -eq 'y' -or $deleteData -eq 'Y') { - try { - if (Test-Path $DataPath) { - Remove-Item -Path $DataPath -Recurse -Force - Write-Host "[OK] 数据目录已删除: $DataPath" -ForegroundColor Green - } - } - catch { - Write-Host "[X] 删除数据目录失败: $($_.Exception.Message)" -ForegroundColor Red - } -} else { - Write-Host "[INFO] 数据目录保留: $DataPath" -ForegroundColor Cyan -} - -Write-Host "" -Write-Host "[OK] 卸载完成!" -ForegroundColor Green -Read-Host "按任意键退出" diff --git a/uninstall_system.sh b/uninstall_system.sh deleted file mode 100755 index 2d2e35a..0000000 --- a/uninstall_system.sh +++ /dev/null @@ -1,223 +0,0 @@ -#!/bin/bash - -# -# 智能网络监控脚本 - Ubuntu系统级卸载脚本 -# -# 功能描述: -# 完全卸载系统级部署的智能网络监控脚本 -# 包括停止服务、删除文件、清理配置等 -# -# 使用方法: -# sudo ./uninstall_system.sh -# - -# 设置颜色输出 -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -CYAN='\033[0;36m' -NC='\033[0m' # No Color - -# 定义系统级路径 -PROGRAM_PATH="/opt/smart-network-monitor" -CONFIG_PATH="/etc/smart-network-monitor" -LOG_PATH="/var/log/smart-network-monitor" -SERVICE_FILE="/etc/systemd/system/smart-network-monitor.service" -SERVICE_NAME="smart-network-monitor" -SYMLINK_PATH="/usr/local/bin/smart-monitor" - -echo -e "${CYAN}==========================================${NC}" -echo -e "${CYAN}智能网络监控脚本 - Ubuntu系统级卸载${NC}" -echo -e "${CYAN}==========================================${NC}" -echo "" - -# 检查root权限 -if [[ $EUID -ne 0 ]]; then - echo -e "${RED}错误:此脚本需要root权限执行${NC}" - echo -e "${YELLOW}请使用: sudo $0${NC}" - exit 1 -fi - -echo -e "${YELLOW}将要删除的组件:${NC}" -echo -e "- 程序目录: ${PROGRAM_PATH}" -echo -e "- 配置目录: ${CONFIG_PATH}" -echo -e "- 日志目录: ${LOG_PATH}" -echo -e "- 服务文件: ${SERVICE_FILE}" -echo -e "- 符号链接: ${SYMLINK_PATH}" -echo "" - -# 询问用户确认 -read -p "确定要完全卸载智能网络监控脚本吗?这将删除所有相关文件和日志 (y/N): " confirm - -if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then - echo -e "${YELLOW}卸载已取消${NC}" - exit 0 -fi - -echo "" -echo -e "${YELLOW}开始卸载过程...${NC}" - -# 停止并禁用服务 -if systemctl is-active --quiet "$SERVICE_NAME"; then - echo -e "${YELLOW}正在停止服务...${NC}" - if systemctl stop "$SERVICE_NAME"; then - echo -e "${GREEN}[OK] 服务已停止${NC}" - else - echo -e "${RED}[WARNING] 停止服务失败${NC}" - fi -fi - -if systemctl is-enabled --quiet "$SERVICE_NAME" 2>/dev/null; then - echo -e "${YELLOW}正在禁用服务自启动...${NC}" - if systemctl disable "$SERVICE_NAME"; then - echo -e "${GREEN}[OK] 服务自启动已禁用${NC}" - else - echo -e "${RED}[WARNING] 禁用服务自启动失败${NC}" - fi -fi - -# 删除服务文件 -if [[ -f "$SERVICE_FILE" ]]; then - echo -e "${YELLOW}正在删除服务文件...${NC}" - if rm -f "$SERVICE_FILE"; then - echo -e "${GREEN}[OK] 服务文件已删除: $SERVICE_FILE${NC}" - else - echo -e "${RED}[ERROR] 删除服务文件失败${NC}" - fi -fi - -# 重新加载systemd配置 -echo -e "${YELLOW}正在重新加载systemd配置...${NC}" -if systemctl daemon-reload; then - echo -e "${GREEN}[OK] systemd配置已重新加载${NC}" -else - echo -e "${RED}[WARNING] 重新加载systemd配置失败${NC}" -fi - -# 删除符号链接 -if [[ -L "$SYMLINK_PATH" ]]; then - echo -e "${YELLOW}正在删除符号链接...${NC}" - if rm -f "$SYMLINK_PATH"; then - echo -e "${GREEN}[OK] 符号链接已删除: $SYMLINK_PATH${NC}" - else - echo -e "${RED}[ERROR] 删除符号链接失败${NC}" - fi -fi - -# 删除程序目录 -if [[ -d "$PROGRAM_PATH" ]]; then - echo -e "${YELLOW}正在删除程序目录...${NC}" - if rm -rf "$PROGRAM_PATH"; then - echo -e "${GREEN}[OK] 程序目录已删除: $PROGRAM_PATH${NC}" - else - echo -e "${RED}[ERROR] 删除程序目录失败${NC}" - fi -fi - -# 询问是否删除配置文件 -echo "" -read -p "是否删除配置文件?这将删除您的自定义配置 (y/N): " delete_config - -if [[ "$delete_config" == "y" || "$delete_config" == "Y" ]]; then - if [[ -d "$CONFIG_PATH" ]]; then - echo -e "${YELLOW}正在删除配置目录...${NC}" - if rm -rf "$CONFIG_PATH"; then - echo -e "${GREEN}[OK] 配置目录已删除: $CONFIG_PATH${NC}" - else - echo -e "${RED}[ERROR] 删除配置目录失败${NC}" - fi - fi -else - echo -e "${BLUE}[INFO] 保留配置文件: $CONFIG_PATH${NC}" -fi - -# 询问是否删除日志文件 -echo "" -read -p "是否删除日志文件?这将删除所有监控历史记录 (y/N): " delete_logs - -if [[ "$delete_logs" == "y" || "$delete_logs" == "Y" ]]; then - if [[ -d "$LOG_PATH" ]]; then - echo -e "${YELLOW}正在删除日志目录...${NC}" - if rm -rf "$LOG_PATH"; then - echo -e "${GREEN}[OK] 日志目录已删除: $LOG_PATH${NC}" - else - echo -e "${RED}[ERROR] 删除日志目录失败${NC}" - fi - fi -else - echo -e "${BLUE}[INFO] 保留日志文件: $LOG_PATH${NC}" -fi - -# 清理系统日志中的相关条目(可选) -echo "" -read -p "是否清理系统日志中的相关条目?(y/N): " clean_syslogs - -if [[ "$clean_syslogs" == "y" || "$clean_syslogs" == "Y" ]]; then - echo -e "${YELLOW}正在清理系统日志...${NC}" - if command -v journalctl >/dev/null 2>&1; then - # 注意:journalctl --vacuum-time 需要适当的权限 - journalctl --vacuum-time=1d 2>/dev/null || echo -e "${YELLOW}[WARNING] 清理系统日志需要额外权限${NC}" - echo -e "${GREEN}[OK] 系统日志清理完成${NC}" - else - echo -e "${YELLOW}[WARNING] journalctl命令不可用${NC}" - fi -fi - -echo "" -echo -e "${GREEN}==========================================${NC}" -echo -e "${GREEN}卸载完成!${NC}" -echo -e "${GREEN}==========================================${NC}" -echo "" - -# 显示卸载摘要 -echo -e "${CYAN}卸载摘要:${NC}" -echo -e "${GREEN}[OK]${NC} 服务已停止并禁用" -echo -e "${GREEN}[OK]${NC} 服务文件已删除" -echo -e "${GREEN}[OK]${NC} 程序文件已删除" -echo -e "${GREEN}[OK]${NC} 符号链接已删除" - -if [[ "$delete_config" == "y" || "$delete_config" == "Y" ]]; then - echo -e "${GREEN}[OK]${NC} 配置文件已删除" -else - echo -e "${BLUE}[INFO]${NC} 配置文件已保留" -fi - -if [[ "$delete_logs" == "y" || "$delete_logs" == "Y" ]]; then - echo -e "${GREEN}[OK]${NC} 日志文件已删除" -else - echo -e "${BLUE}[INFO]${NC} 日志文件已保留" -fi - -echo "" - -# 检查是否有残留文件 -echo -e "${YELLOW}检查残留文件...${NC}" -remaining_files=() - -[[ -f "$SERVICE_FILE" ]] && remaining_files+=("$SERVICE_FILE") -[[ -d "$PROGRAM_PATH" ]] && remaining_files+=("$PROGRAM_PATH") -[[ -L "$SYMLINK_PATH" ]] && remaining_files+=("$SYMLINK_PATH") - -if [[ ${#remaining_files[@]} -eq 0 ]]; then - echo -e "${GREEN}[OK] 没有发现残留文件${NC}" -else - echo -e "${YELLOW}[WARNING] 发现以下残留文件:${NC}" - for file in "${remaining_files[@]}"; do - echo -e "${RED} - $file${NC}" - done - echo -e "${YELLOW}您可能需要手动删除这些文件${NC}" -fi - -echo "" -echo -e "${CYAN}智能网络监控脚本已完全卸载!${NC}" - -# 如果保留了配置或日志文件,提供再次卸载的说明 -if [[ "$delete_config" != "y" && "$delete_config" != "Y" ]] || [[ "$delete_logs" != "y" && "$delete_logs" != "Y" ]]; then - echo "" - echo -e "${BLUE}如果您之后想删除保留的文件,可以手动删除:${NC}" - [[ "$delete_config" != "y" && "$delete_config" != "Y" ]] && echo -e "${BLUE} 配置文件: sudo rm -rf $CONFIG_PATH${NC}" - [[ "$delete_logs" != "y" && "$delete_logs" != "Y" ]] && echo -e "${BLUE} 日志文件: sudo rm -rf $LOG_PATH${NC}" -fi - -echo "" \ No newline at end of file