feat: init pc-monitor project
- Client: Go-based Windows hardware monitoring (CPU, GPU, memory, disk, network, power) - Server: Go + Gin + SQLite backend with REST API - Frontend: Vue 3 + Element Plus dashboard - Docker deployment support - Windows service installation script
This commit is contained in:
99
server/service/alert.go
Normal file
99
server/service/alert.go
Normal file
@@ -0,0 +1,99 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"pc-monitor-server/model"
|
||||
"pc-monitor-server/repository"
|
||||
"time"
|
||||
)
|
||||
|
||||
type AlertService struct {
|
||||
alertRepo *repository.AlertRepository
|
||||
metricsRepo *repository.MetricsRepository
|
||||
}
|
||||
|
||||
func NewAlertService(alertRepo *repository.AlertRepository, metricsRepo *repository.MetricsRepository) *AlertService {
|
||||
return &AlertService{alertRepo: alertRepo, metricsRepo: metricsRepo}
|
||||
}
|
||||
|
||||
func (s *AlertService) CreateRule(rule *model.AlertRule) error {
|
||||
rule.CreatedAt = time.Now()
|
||||
return s.alertRepo.CreateRule(rule)
|
||||
}
|
||||
|
||||
func (s *AlertService) GetRulesByDevice(deviceID string) ([]model.AlertRule, error) {
|
||||
return s.alertRepo.GetRulesByDevice(deviceID)
|
||||
}
|
||||
|
||||
func (s *AlertService) DeleteRule(id string) error {
|
||||
return s.alertRepo.DeleteRule(id)
|
||||
}
|
||||
|
||||
func (s *AlertService) GetActiveAlerts() ([]model.Alert, error) {
|
||||
return s.alertRepo.GetActiveAlerts()
|
||||
}
|
||||
|
||||
func (s *AlertService) ResolveAlert(id string) error {
|
||||
return s.alertRepo.ResolveAlert(id)
|
||||
}
|
||||
|
||||
func (s *AlertService) CheckAlerts(deviceID string, metrics *model.Metrics) error {
|
||||
rules, err := s.alertRepo.GetRulesByDevice(deviceID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, rule := range rules {
|
||||
value := getMetricValue(metrics, rule.Metric)
|
||||
if checkThreshold(value, rule.Operator, rule.Threshold) {
|
||||
alert := &model.Alert{
|
||||
ID: fmt.Sprintf("%s-%s-%d", deviceID, rule.ID, time.Now().Unix()),
|
||||
DeviceID: deviceID,
|
||||
RuleID: rule.ID,
|
||||
Metric: rule.Metric,
|
||||
Value: value,
|
||||
Message: fmt.Sprintf("%s %s %.2f (threshold: %.2f)", rule.Metric, rule.Operator, value, rule.Threshold),
|
||||
Status: "active",
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
s.alertRepo.CreateAlert(alert)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getMetricValue(m *model.Metrics, metric string) float64 {
|
||||
switch metric {
|
||||
case "cpu_usage":
|
||||
return m.CPUUsage
|
||||
case "cpu_temperature":
|
||||
return m.CPUTemperature
|
||||
case "memory_usage":
|
||||
return m.MemoryUsage
|
||||
case "gpu_usage":
|
||||
return m.GPUUsage
|
||||
case "gpu_temperature":
|
||||
return m.GPUTemperature
|
||||
case "battery_level":
|
||||
return float64(m.BatteryLevel)
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func checkThreshold(value float64, operator string, threshold float64) bool {
|
||||
switch operator {
|
||||
case ">":
|
||||
return value > threshold
|
||||
case ">=":
|
||||
return value >= threshold
|
||||
case "<":
|
||||
return value < threshold
|
||||
case "<=":
|
||||
return value <= threshold
|
||||
case "==":
|
||||
return value == threshold
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
73
server/service/device.go
Normal file
73
server/service/device.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"pc-monitor-server/model"
|
||||
"pc-monitor-server/repository"
|
||||
"time"
|
||||
)
|
||||
|
||||
type DeviceService struct {
|
||||
repo *repository.DeviceRepository
|
||||
}
|
||||
|
||||
func NewDeviceService(repo *repository.DeviceRepository) *DeviceService {
|
||||
return &DeviceService{repo: repo}
|
||||
}
|
||||
|
||||
func (s *DeviceService) Register(hostname, osName, ip string) (*model.Device, error) {
|
||||
id := generateDeviceID(hostname, ip)
|
||||
device, err := s.repo.GetByID(id)
|
||||
if err == nil {
|
||||
device.LastReportAt = time.Now()
|
||||
device.Status = "online"
|
||||
s.repo.Update(device)
|
||||
return device, nil
|
||||
}
|
||||
|
||||
device = &model.Device{
|
||||
ID: id,
|
||||
Hostname: hostname,
|
||||
OS: osName,
|
||||
IP: ip,
|
||||
RegisteredAt: time.Now(),
|
||||
LastReportAt: time.Now(),
|
||||
Status: "online",
|
||||
}
|
||||
if err := s.repo.Create(device); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return device, nil
|
||||
}
|
||||
|
||||
func (s *DeviceService) GetAll() ([]model.Device, error) {
|
||||
return s.repo.GetAll()
|
||||
}
|
||||
|
||||
func (s *DeviceService) GetByID(id string) (*model.Device, error) {
|
||||
return s.repo.GetByID(id)
|
||||
}
|
||||
|
||||
func (s *DeviceService) Delete(id string) error {
|
||||
return s.repo.Delete(id)
|
||||
}
|
||||
|
||||
func (s *DeviceService) Heartbeat(id string) error {
|
||||
device, err := s.repo.GetByID(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
device.LastReportAt = time.Now()
|
||||
device.Status = "online"
|
||||
return s.repo.Update(device)
|
||||
}
|
||||
|
||||
func (s *DeviceService) CheckOffline() {
|
||||
s.repo.MarkOffline(2 * time.Minute)
|
||||
}
|
||||
|
||||
func generateDeviceID(hostname, ip string) string {
|
||||
hash := sha256.Sum256([]byte(fmt.Sprintf("%s-%s", hostname, ip)))
|
||||
return fmt.Sprintf("%x", hash[:8])
|
||||
}
|
||||
35
server/service/metrics.go
Normal file
35
server/service/metrics.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"pc-monitor-server/model"
|
||||
"pc-monitor-server/repository"
|
||||
"time"
|
||||
)
|
||||
|
||||
type MetricsService struct {
|
||||
repo *repository.MetricsRepository
|
||||
}
|
||||
|
||||
func NewMetricsService(repo *repository.MetricsRepository) *MetricsService {
|
||||
return &MetricsService{repo: repo}
|
||||
}
|
||||
|
||||
func (s *MetricsService) Save(m *model.Metrics) error {
|
||||
return s.repo.Save(m)
|
||||
}
|
||||
|
||||
func (s *MetricsService) GetLatest(deviceID string) (*model.Metrics, error) {
|
||||
return s.repo.GetLatest(deviceID)
|
||||
}
|
||||
|
||||
func (s *MetricsService) GetHistory(deviceID string, start, end time.Time, limit int) ([]model.Metrics, error) {
|
||||
if limit <= 0 {
|
||||
limit = 1000
|
||||
}
|
||||
return s.repo.GetHistory(deviceID, start, end, limit)
|
||||
}
|
||||
|
||||
func (s *MetricsService) Cleanup(retentionDays int) error {
|
||||
before := time.Now().AddDate(0, 0, -retentionDays)
|
||||
return s.repo.Cleanup(before)
|
||||
}
|
||||
Reference in New Issue
Block a user