feat(mqtt): 实现MQTT客户端,支持系统资源监控和关机控制
添加新的MQTT客户端实现,具有系统资源使用情况监测和远程关机功能。客户端通过MQTT协议与服务器交换信息,订阅特定主题以接收控制命令,并发布系统资源使用情况。此功能允许在远程系统上执行关机操作,并监测CPU及内存使用情况。 - 实现PCInfo结构体以存储系统资源使用信息。 - 实现Command结构体以解析接收到的控制命令。 - 编写onMessageReceived处理函数以响应接收到的消息。 - 实现executeShutdown函数以处理不同操作系统的关机逻辑。 - 主函数中初始化MQTT客户端,加载环境变量,订阅主题,并循环发布系统资源信息。
This commit is contained in:
commit
6274a2bac0
|
@ -0,0 +1,3 @@
|
||||||
|
MQTT_BROKER=tcp://127.0.0.1:1883
|
||||||
|
MQTT_CLIENT_ID=local
|
||||||
|
MQTT_TOPIC=pc/0
|
|
@ -0,0 +1,8 @@
|
||||||
|
# 默认忽略的文件
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# 基于编辑器的 HTTP 客户端请求
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectRootManager">
|
||||||
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/pc_mqtt.iml" filepath="$PROJECT_DIR$/pc_mqtt.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -0,0 +1,3 @@
|
||||||
|
MQTT_BROKER=tcp://127.0.0.1:1883
|
||||||
|
MQTT_CLIENT_ID=local
|
||||||
|
MQTT_TOPIC=pc/0
|
Binary file not shown.
|
@ -0,0 +1,33 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# 确保脚本以root权限运行
|
||||||
|
if [ "$(id -u)" -ne "0" ]; then
|
||||||
|
echo "This script must be run as root." 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 设置变量
|
||||||
|
SERVICE_FILE="/etc/systemd/system/mqtt-info-tool.service"
|
||||||
|
BINARY_FILE="/opt/app/pc_mqtt/client"
|
||||||
|
|
||||||
|
# 确保Go程序可执行
|
||||||
|
chmod +x $BINARY_FILE
|
||||||
|
|
||||||
|
# 安装systemd服务文件
|
||||||
|
echo "Copying systemd service file to /etc/systemd/system..."
|
||||||
|
cp ./mqtt-info-tool.service $SERVICE_FILE
|
||||||
|
|
||||||
|
# 重新加载systemd配置
|
||||||
|
echo "Reloading systemd daemon..."
|
||||||
|
systemctl daemon-reload
|
||||||
|
|
||||||
|
# 启动服务并设置为开机自启
|
||||||
|
echo "Starting MQTT Info Tool service..."
|
||||||
|
systemctl start mqtt-info-tool
|
||||||
|
systemctl enable mqtt-info-tool
|
||||||
|
|
||||||
|
# 打印服务状态
|
||||||
|
echo "Service status:"
|
||||||
|
systemctl status mqtt-info-tool
|
||||||
|
|
||||||
|
echo "Installation completed successfully."
|
|
@ -0,0 +1,16 @@
|
||||||
|
[Unit]
|
||||||
|
Description=MQTT PC Information Tool
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStart=/opt/app/pc_mqtt/client
|
||||||
|
WorkingDirectory=/opt/app/pc_mqtt
|
||||||
|
EnvironmentFile=/opt/app/pc_mqtt/.env
|
||||||
|
Restart=always
|
||||||
|
User=root
|
||||||
|
Group=root
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
|
|
@ -0,0 +1,132 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"runtime"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
mqtt "github.com/eclipse/paho.mqtt.golang"
|
||||||
|
"github.com/joho/godotenv"
|
||||||
|
"github.com/shirou/gopsutil/cpu"
|
||||||
|
"github.com/shirou/gopsutil/mem"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PCInfo 定义 PC 使用信息的结构。
|
||||||
|
type PCInfo struct {
|
||||||
|
CPUUsage float64 `json:"cpu_usage"` // CPU
|
||||||
|
MemUsage float64 `json:"mem_usage"` // Memory
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command 定义接收命令的结构。
|
||||||
|
type Command struct {
|
||||||
|
Action string `json:"action"` // Action 待执行
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadEnv 加载 .env 文件以读取环境变量。
|
||||||
|
func loadEnv() {
|
||||||
|
err := godotenv.Load(".env")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error loading .env file")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getPCInfo 检索当前 PC 使用信息。
|
||||||
|
func getPCInfo() (PCInfo, error) {
|
||||||
|
cpuPercentages, err := cpu.Percent(0, false)
|
||||||
|
if err != nil {
|
||||||
|
return PCInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
memInfo, err := mem.VirtualMemory()
|
||||||
|
if err != nil {
|
||||||
|
return PCInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保留2位小数
|
||||||
|
return PCInfo{
|
||||||
|
CPUUsage: float64(int(cpuPercentages[0]*100)) / 100,
|
||||||
|
MemUsage: float64(int(memInfo.UsedPercent*100)) / 100,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// onMessageReceived 处理从 MQTT 接收的消息。
|
||||||
|
func onMessageReceived(client mqtt.Client, msg mqtt.Message) {
|
||||||
|
var cmd Command
|
||||||
|
err := json.Unmarshal(msg.Payload(), &cmd)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error decoding JSON command:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if cmd.Action == "shutdown" {
|
||||||
|
fmt.Println("Shutdown command received. Shutting down...")
|
||||||
|
executeShutdown()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// executeShutdown 根据操作系统执行关机命令。
|
||||||
|
func executeShutdown() {
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "windows":
|
||||||
|
cmd = exec.Command("shutdown", "/s", "/t", "0")
|
||||||
|
case "linux", "darwin":
|
||||||
|
cmd = exec.Command("shutdown", "-h", "now")
|
||||||
|
default:
|
||||||
|
fmt.Println("Shutdown not supported on this OS")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Failed to execute shutdown:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
loadEnv()
|
||||||
|
|
||||||
|
broker := os.Getenv("MQTT_BROKER")
|
||||||
|
clientID := os.Getenv("MQTT_CLIENT_ID")
|
||||||
|
topic := os.Getenv("MQTT_TOPIC")
|
||||||
|
|
||||||
|
opts := mqtt.NewClientOptions()
|
||||||
|
opts.AddBroker(broker)
|
||||||
|
opts.SetClientID(clientID)
|
||||||
|
opts.SetDefaultPublishHandler(onMessageReceived)
|
||||||
|
|
||||||
|
client := mqtt.NewClient(opts)
|
||||||
|
if token := client.Connect(); token.Wait() && token.Error() != nil {
|
||||||
|
fmt.Println(token.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 订阅主题以接收命令
|
||||||
|
client.Subscribe(topic, 0, nil)
|
||||||
|
|
||||||
|
for {
|
||||||
|
pcInfo, err := getPCInfo()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error getting PC info:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
pcInfoJSON, err := json.Marshal(pcInfo)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error encoding PC info to JSON:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
token := client.Publish(topic, 0, false, pcInfoJSON)
|
||||||
|
token.Wait()
|
||||||
|
|
||||||
|
fmt.Println("Message published:", string(pcInfoJSON))
|
||||||
|
|
||||||
|
time.Sleep(10 * time.Second) // 控制发送频率,例如每10秒发送一次
|
||||||
|
}
|
||||||
|
|
||||||
|
// 完成后断开 MQTT 客户端连接
|
||||||
|
// client.Disconnect(250)
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
module pc_mqtt
|
||||||
|
|
||||||
|
go 1.23.0
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/eclipse/paho.mqtt.golang v1.5.0
|
||||||
|
github.com/joho/godotenv v1.5.1
|
||||||
|
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||||
|
github.com/gorilla/websocket v1.5.3 // indirect
|
||||||
|
github.com/stretchr/testify v1.9.0 // indirect
|
||||||
|
github.com/tklauser/go-sysconf v0.3.14 // indirect
|
||||||
|
github.com/tklauser/numcpus v0.8.0 // indirect
|
||||||
|
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||||
|
golang.org/x/net v0.27.0 // indirect
|
||||||
|
golang.org/x/sync v0.7.0 // indirect
|
||||||
|
golang.org/x/sys v0.22.0 // indirect
|
||||||
|
)
|
|
@ -0,0 +1,31 @@
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/eclipse/paho.mqtt.golang v1.5.0 h1:EH+bUVJNgttidWFkLLVKaQPGmkTUfQQqjOsyvMGvD6o=
|
||||||
|
github.com/eclipse/paho.mqtt.golang v1.5.0/go.mod h1:du/2qNQVqJf/Sqs4MEL77kR8QTqANF7XU7Fk0aOTAgk=
|
||||||
|
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||||
|
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||||
|
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||||
|
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||||
|
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
|
||||||
|
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||||
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=
|
||||||
|
github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY=
|
||||||
|
github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY=
|
||||||
|
github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE=
|
||||||
|
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||||
|
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||||
|
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
|
||||||
|
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
|
||||||
|
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||||
|
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||||
|
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="Go" enabled="true" />
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
Loading…
Reference in New Issue