...
This commit is contained in:
375
pkg/heroagent/handlers/system_handlers.go
Normal file
375
pkg/heroagent/handlers/system_handlers.go
Normal file
@@ -0,0 +1,375 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/system/stats"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/shirou/gopsutil/v3/host"
|
||||
)
|
||||
|
||||
// UptimeProvider defines an interface for getting system uptime
|
||||
type UptimeProvider interface {
|
||||
GetUptime() string
|
||||
}
|
||||
|
||||
// SystemHandler handles system-related page routes
|
||||
type SystemHandler struct {
|
||||
uptimeProvider UptimeProvider
|
||||
statsManager *stats.StatsManager
|
||||
}
|
||||
|
||||
// NewSystemHandler creates a new SystemHandler
|
||||
func NewSystemHandler(uptimeProvider UptimeProvider, statsManager *stats.StatsManager) *SystemHandler {
|
||||
// If statsManager is nil, create a new one with default settings
|
||||
if statsManager == nil {
|
||||
var err error
|
||||
statsManager, err = stats.NewStatsManagerWithDefaults()
|
||||
if err != nil {
|
||||
// Log the error but continue with nil statsManager
|
||||
fmt.Printf("Error creating StatsManager: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
return &SystemHandler{
|
||||
uptimeProvider: uptimeProvider,
|
||||
statsManager: statsManager,
|
||||
}
|
||||
}
|
||||
|
||||
// GetSystemInfo renders the system info page
|
||||
func (h *SystemHandler) GetSystemInfo(c *fiber.Ctx) error {
|
||||
// Initialize default values
|
||||
cpuInfo := "Unknown"
|
||||
memoryInfo := "Unknown"
|
||||
diskInfo := "Unknown"
|
||||
networkInfo := "Unknown"
|
||||
osInfo := "Unknown"
|
||||
uptimeInfo := "Unknown"
|
||||
|
||||
// Get hardware stats from the StatsManager
|
||||
var hardwareStats map[string]interface{}
|
||||
if h.statsManager != nil {
|
||||
hardwareStats = h.statsManager.GetHardwareStats()
|
||||
} else {
|
||||
// Fallback to direct function call if StatsManager is not available
|
||||
hardwareStats = stats.GetHardwareStats()
|
||||
}
|
||||
|
||||
// Extract the formatted strings - safely handle different return types
|
||||
if cpuVal, ok := hardwareStats["cpu"]; ok {
|
||||
switch v := cpuVal.(type) {
|
||||
case string:
|
||||
cpuInfo = v
|
||||
case map[string]interface{}:
|
||||
// Format the map into a string
|
||||
if model, ok := v["model"].(string); ok {
|
||||
usage := 0.0
|
||||
if usagePercent, ok := v["usage_percent"].(float64); ok {
|
||||
usage = usagePercent
|
||||
}
|
||||
cpuInfo = fmt.Sprintf("%s (Usage: %.1f%%)", model, usage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if memVal, ok := hardwareStats["memory"]; ok {
|
||||
switch v := memVal.(type) {
|
||||
case string:
|
||||
memoryInfo = v
|
||||
case map[string]interface{}:
|
||||
// Format the map into a string
|
||||
total, used := 0.0, 0.0
|
||||
if totalGB, ok := v["total_gb"].(float64); ok {
|
||||
total = totalGB
|
||||
}
|
||||
if usedGB, ok := v["used_gb"].(float64); ok {
|
||||
used = usedGB
|
||||
}
|
||||
usedPercent := 0.0
|
||||
if percent, ok := v["used_percent"].(float64); ok {
|
||||
usedPercent = percent
|
||||
}
|
||||
memoryInfo = fmt.Sprintf("%.1f GB / %.1f GB (%.1f%% used)", used, total, usedPercent)
|
||||
}
|
||||
}
|
||||
|
||||
if diskVal, ok := hardwareStats["disk"]; ok {
|
||||
switch v := diskVal.(type) {
|
||||
case string:
|
||||
diskInfo = v
|
||||
case map[string]interface{}:
|
||||
// Format the map into a string
|
||||
total, used := 0.0, 0.0
|
||||
if totalGB, ok := v["total_gb"].(float64); ok {
|
||||
total = totalGB
|
||||
}
|
||||
if usedGB, ok := v["used_gb"].(float64); ok {
|
||||
used = usedGB
|
||||
}
|
||||
usedPercent := 0.0
|
||||
if percent, ok := v["used_percent"].(float64); ok {
|
||||
usedPercent = percent
|
||||
}
|
||||
diskInfo = fmt.Sprintf("%.1f GB / %.1f GB (%.1f%% used)", used, total, usedPercent)
|
||||
}
|
||||
}
|
||||
|
||||
if netVal, ok := hardwareStats["network"]; ok {
|
||||
switch v := netVal.(type) {
|
||||
case string:
|
||||
networkInfo = v
|
||||
case map[string]interface{}:
|
||||
// Format the map into a string
|
||||
var interfaces []string
|
||||
if ifaces, ok := v["interfaces"].([]interface{}); ok {
|
||||
for _, iface := range ifaces {
|
||||
if ifaceMap, ok := iface.(map[string]interface{}); ok {
|
||||
name := ifaceMap["name"].(string)
|
||||
ip := ifaceMap["ip"].(string)
|
||||
interfaces = append(interfaces, fmt.Sprintf("%s: %s", name, ip))
|
||||
}
|
||||
}
|
||||
networkInfo = strings.Join(interfaces, ", ")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get OS info
|
||||
hostInfo, err := host.Info()
|
||||
if err == nil {
|
||||
osInfo = fmt.Sprintf("%s %s (%s)", hostInfo.Platform, hostInfo.PlatformVersion, hostInfo.KernelVersion)
|
||||
}
|
||||
|
||||
// Get uptime
|
||||
if h.uptimeProvider != nil {
|
||||
uptimeInfo = h.uptimeProvider.GetUptime()
|
||||
}
|
||||
|
||||
// Render the template with the system info
|
||||
return c.Render("admin/system/info", fiber.Map{
|
||||
"title": "System Information",
|
||||
"cpuInfo": cpuInfo,
|
||||
"memoryInfo": memoryInfo,
|
||||
"diskInfo": diskInfo,
|
||||
"networkInfo": networkInfo,
|
||||
"osInfo": osInfo,
|
||||
"uptimeInfo": uptimeInfo,
|
||||
})
|
||||
}
|
||||
|
||||
// GetHardwareStats returns only the hardware stats for Unpoly polling
|
||||
func (h *SystemHandler) GetHardwareStats(c *fiber.Ctx) error {
|
||||
// Initialize default values
|
||||
cpuInfo := "Unknown"
|
||||
memoryInfo := "Unknown"
|
||||
diskInfo := "Unknown"
|
||||
networkInfo := "Unknown"
|
||||
|
||||
// Get hardware stats from the StatsManager
|
||||
var hardwareStats map[string]interface{}
|
||||
if h.statsManager != nil {
|
||||
hardwareStats = h.statsManager.GetHardwareStats()
|
||||
} else {
|
||||
// Fallback to direct function call if StatsManager is not available
|
||||
hardwareStats = stats.GetHardwareStats()
|
||||
}
|
||||
|
||||
// Extract the formatted strings - safely handle different return types
|
||||
if cpuVal, ok := hardwareStats["cpu"]; ok {
|
||||
switch v := cpuVal.(type) {
|
||||
case string:
|
||||
cpuInfo = v
|
||||
case map[string]interface{}:
|
||||
// Format the map into a string
|
||||
if model, ok := v["model"].(string); ok {
|
||||
cpuInfo = model
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if memVal, ok := hardwareStats["memory"]; ok {
|
||||
switch v := memVal.(type) {
|
||||
case string:
|
||||
memoryInfo = v
|
||||
case map[string]interface{}:
|
||||
// Format the map into a string
|
||||
total, used := 0.0, 0.0
|
||||
if totalGB, ok := v["total_gb"].(float64); ok {
|
||||
total = totalGB
|
||||
}
|
||||
if usedGB, ok := v["used_gb"].(float64); ok {
|
||||
used = usedGB
|
||||
}
|
||||
memoryInfo = fmt.Sprintf("%.1f GB / %.1f GB", used, total)
|
||||
}
|
||||
}
|
||||
|
||||
if diskVal, ok := hardwareStats["disk"]; ok {
|
||||
switch v := diskVal.(type) {
|
||||
case string:
|
||||
diskInfo = v
|
||||
case map[string]interface{}:
|
||||
// Format the map into a string
|
||||
total, used := 0.0, 0.0
|
||||
if totalGB, ok := v["total_gb"].(float64); ok {
|
||||
total = totalGB
|
||||
}
|
||||
if usedGB, ok := v["used_gb"].(float64); ok {
|
||||
used = usedGB
|
||||
}
|
||||
diskInfo = fmt.Sprintf("%.1f GB / %.1f GB", used, total)
|
||||
}
|
||||
}
|
||||
|
||||
if netVal, ok := hardwareStats["network"]; ok {
|
||||
switch v := netVal.(type) {
|
||||
case string:
|
||||
networkInfo = v
|
||||
case map[string]interface{}:
|
||||
// Format the map into a string
|
||||
var interfaces []string
|
||||
if ifaces, ok := v["interfaces"].([]interface{}); ok {
|
||||
for _, iface := range ifaces {
|
||||
if ifaceMap, ok := iface.(map[string]interface{}); ok {
|
||||
name := ifaceMap["name"].(string)
|
||||
ip := ifaceMap["ip"].(string)
|
||||
interfaces = append(interfaces, fmt.Sprintf("%s: %s", name, ip))
|
||||
}
|
||||
}
|
||||
networkInfo = strings.Join(interfaces, ", ")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Format for display
|
||||
cpuUsage := "0.0%"
|
||||
memUsage := "0.0%"
|
||||
diskUsage := "0.0%"
|
||||
|
||||
// Safely extract usage percentages
|
||||
if cpuVal, ok := hardwareStats["cpu"].(map[string]interface{}); ok {
|
||||
if usagePercent, ok := cpuVal["usage_percent"].(float64); ok {
|
||||
cpuUsage = fmt.Sprintf("%.1f%%", usagePercent)
|
||||
}
|
||||
}
|
||||
|
||||
if memVal, ok := hardwareStats["memory"].(map[string]interface{}); ok {
|
||||
if usedPercent, ok := memVal["used_percent"].(float64); ok {
|
||||
memUsage = fmt.Sprintf("%.1f%%", usedPercent)
|
||||
}
|
||||
}
|
||||
|
||||
if diskVal, ok := hardwareStats["disk"].(map[string]interface{}); ok {
|
||||
if usedPercent, ok := diskVal["used_percent"].(float64); ok {
|
||||
diskUsage = fmt.Sprintf("%.1f%%", usedPercent)
|
||||
}
|
||||
}
|
||||
|
||||
// Render only the hardware stats fragment
|
||||
return c.Render("admin/system/hardware_stats_fragment", fiber.Map{
|
||||
"cpuInfo": cpuInfo,
|
||||
"memoryInfo": memoryInfo,
|
||||
"diskInfo": diskInfo,
|
||||
"networkInfo": networkInfo,
|
||||
"cpuUsage": cpuUsage,
|
||||
"memUsage": memUsage,
|
||||
"diskUsage": diskUsage,
|
||||
})
|
||||
}
|
||||
|
||||
// GetHardwareStatsAPI returns hardware stats in JSON format
|
||||
func (h *SystemHandler) GetHardwareStatsAPI(c *fiber.Ctx) error {
|
||||
// Get hardware stats from the StatsManager
|
||||
var hardwareStats map[string]interface{}
|
||||
if h.statsManager != nil {
|
||||
hardwareStats = h.statsManager.GetHardwareStats()
|
||||
} else {
|
||||
// Fallback to direct function call if StatsManager is not available
|
||||
hardwareStats = stats.GetHardwareStats()
|
||||
}
|
||||
|
||||
return c.JSON(hardwareStats)
|
||||
}
|
||||
|
||||
// GetProcessStatsAPI returns process stats in JSON format for API consumption
|
||||
func (h *SystemHandler) GetProcessStatsAPI(c *fiber.Ctx) error {
|
||||
// Check if StatsManager is properly initialized
|
||||
if h.statsManager == nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"error": "System error: Stats manager not initialized",
|
||||
})
|
||||
}
|
||||
|
||||
// Get process data from the StatsManager
|
||||
processData, err := h.statsManager.GetProcessStatsFresh(100) // Limit to 100 processes
|
||||
if err != nil {
|
||||
// Try getting cached data as fallback
|
||||
processData, err = h.statsManager.GetProcessStats(100)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"error": "Failed to get process data: " + err.Error(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Convert to fiber.Map for JSON response
|
||||
response := fiber.Map{
|
||||
"total": processData.Total,
|
||||
"filtered": processData.Filtered,
|
||||
"timestamp": time.Now().Unix(),
|
||||
}
|
||||
|
||||
// Convert processes to a slice of maps
|
||||
processes := make([]fiber.Map, len(processData.Processes))
|
||||
for i, proc := range processData.Processes {
|
||||
processes[i] = fiber.Map{
|
||||
"pid": proc.PID,
|
||||
"name": proc.Name,
|
||||
"status": proc.Status,
|
||||
"cpu_percent": proc.CPUPercent,
|
||||
"memory_mb": proc.MemoryMB,
|
||||
"create_time_str": proc.CreateTime,
|
||||
"is_current": proc.IsCurrent,
|
||||
}
|
||||
}
|
||||
|
||||
response["processes"] = processes
|
||||
|
||||
// Return JSON response
|
||||
return c.JSON(response)
|
||||
}
|
||||
|
||||
// GetSystemLogs renders the system logs page
|
||||
func (h *SystemHandler) GetSystemLogs(c *fiber.Ctx) error {
|
||||
return c.Render("admin/system/logs", fiber.Map{
|
||||
"title": "System Logs",
|
||||
})
|
||||
}
|
||||
|
||||
// GetSystemLogsTest renders the test logs page
|
||||
func (h *SystemHandler) GetSystemLogsTest(c *fiber.Ctx) error {
|
||||
return c.Render("admin/system/logs_test", fiber.Map{
|
||||
"title": "Test Logs",
|
||||
})
|
||||
}
|
||||
|
||||
// GetSystemSettings renders the system settings page
|
||||
func (h *SystemHandler) GetSystemSettings(c *fiber.Ctx) error {
|
||||
// Get the current time
|
||||
currentTime := time.Now().Format("2006-01-02 15:04:05")
|
||||
|
||||
// Render the template with the system settings
|
||||
return c.Render("admin/system/settings", fiber.Map{
|
||||
"title": "System Settings",
|
||||
"currentTime": currentTime,
|
||||
"settings": map[string]interface{}{
|
||||
"autoUpdate": true,
|
||||
"logLevel": "info",
|
||||
"maxLogSize": "100MB",
|
||||
"backupFrequency": "Daily",
|
||||
},
|
||||
})
|
||||
}
|
Reference in New Issue
Block a user