feat(migration): upgrade legacy ps1 scripts to single-binary Golang platform
This commit is contained in:
122
README.md
122
README.md
@@ -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 权限运行,具有执行关机的完整权限
|
|
||||||
- 所有操作都会记录在日志和系统事件日志中
|
|
||||||
- 支持通过任务计划程序进行管理和监控
|
|
||||||
290
README_Ubuntu.md
290
README_Ubuntu.md
@@ -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`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**享受智能网络监控带来的便利!** 🎉
|
|
||||||
113
TEST_REPORT.md
113
TEST_REPORT.md
@@ -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进行冗余检测
|
|
||||||
|
|
||||||
## 结论
|
|
||||||
**脚本功能完整,测试全部通过,可以安全投入使用。**
|
|
||||||
|
|
||||||
经过全面测试,智能网络监控脚本各项功能均正常工作:
|
|
||||||
- 网络监控准确可靠
|
|
||||||
- 故障检测机制有效
|
|
||||||
- 用户交互友好
|
|
||||||
- 日志记录完整
|
|
||||||
- 编码问题已解决
|
|
||||||
- 兼容性问题已修复
|
|
||||||
|
|
||||||
脚本已准备好在生产环境中使用,能够有效监控网络连接并在必要时自动关闭计算机。
|
|
||||||
123
cmd/smart-monitor/main.go
Normal file
123
cmd/smart-monitor/main.go
Normal file
@@ -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)
|
||||||
|
}
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
528
deploy_system.sh
528
deploy_system.sh
@@ -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}"
|
|
||||||
22
go.mod
Normal file
22
go.mod
Normal file
@@ -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
|
||||||
|
)
|
||||||
31
go.sum
Normal file
31
go.sum
Normal file
@@ -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=
|
||||||
574
manage.sh
574
manage.sh
@@ -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
|
|
||||||
67
pkg/config/config.go
Normal file
67
pkg/config/config.go
Normal file
@@ -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
|
||||||
|
}
|
||||||
63
pkg/daemon/service.go
Normal file
63
pkg/daemon/service.go
Normal file
@@ -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
|
||||||
|
}
|
||||||
70
pkg/logger/logger.go
Normal file
70
pkg/logger/logger.go
Normal file
@@ -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...) }
|
||||||
124
pkg/monitor/statemachine.go
Normal file
124
pkg/monitor/statemachine.go
Normal file
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
41
pkg/pinger/pinger.go
Normal file
41
pkg/pinger/pinger.go
Normal file
@@ -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
|
||||||
|
}
|
||||||
28
pkg/system/shutdown.go
Normal file
28
pkg/system/shutdown.go
Normal file
@@ -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
|
||||||
|
}
|
||||||
BIN
smart-monitor.exe
Normal file
BIN
smart-monitor.exe
Normal file
Binary file not shown.
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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 "按任意键退出"
|
|
||||||
@@ -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 ""
|
|
||||||
Reference in New Issue
Block a user