This repository has been archived on 2025-08-04. You can view files and clone it, but cannot push or open issues or pull requests.
heroagent_go_old/pkg/heroagent/handlers/process_handlers.go
2025-04-23 04:18:28 +02:00

206 lines
6.4 KiB
Go

package handlers
import (
"fmt"
"time"
"github.com/freeflowuniverse/heroagent/pkg/system/stats"
"github.com/gofiber/fiber/v2"
)
// ProcessHandler handles process-related routes
type ProcessHandler struct {
statsManager *stats.StatsManager
}
// NewProcessHandler creates a new ProcessHandler
func NewProcessHandler(statsManager *stats.StatsManager) *ProcessHandler {
return &ProcessHandler{
statsManager: statsManager,
}
}
// GetProcessStatsJSON returns process stats in JSON format for API consumption
func (h *ProcessHandler) GetProcessStatsJSON(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)
}
// GetProcesses renders the processes page with initial process data
func (h *ProcessHandler) GetProcesses(c *fiber.Ctx) error {
// Check if StatsManager is properly initialized
if h.statsManager == nil {
return c.Render("admin/system/processes", fiber.Map{
"processes": []fiber.Map{},
"error": "System error: Stats manager not initialized",
"warning": "The process manager is not properly initialized.",
})
}
// Force cache refresh for process stats
h.statsManager.ForceUpdate("process")
// Get process data from the StatsManager
processData, err := h.statsManager.GetProcessStatsFresh(0) // Get all processes with fresh data
if err != nil {
// Try getting cached data as fallback
processData, err = h.statsManager.GetProcessStats(0)
if err != nil {
// If there's an error, still render the page but with empty data
return c.Render("admin/system/processes", fiber.Map{
"processes": []fiber.Map{},
"error": "Failed to load process data: " + err.Error(),
"warning": "System attempted both fresh and cached data retrieval but failed.",
})
}
}
// Convert to []fiber.Map for template rendering
processStats := make([]fiber.Map, len(processData.Processes))
for i, proc := range processData.Processes {
processStats[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,
"cpu_percent_str": fmt.Sprintf("%.1f%%", proc.CPUPercent),
"memory_mb_str": fmt.Sprintf("%.1f MB", proc.MemoryMB),
}
}
// Render the full page with initial process data
return c.Render("admin/system/processes", fiber.Map{
"processes": processStats,
})
}
// GetProcessesData returns the HTML fragment for processes data
func (h *ProcessHandler) GetProcessesData(c *fiber.Ctx) error {
// Check if this is a manual refresh request (with X-Requested-With header set)
isManualRefresh := c.Get("X-Requested-With") == "XMLHttpRequest"
// Check if StatsManager is properly initialized
if h.statsManager == nil {
return c.Render("admin/system/processes_data", fiber.Map{
"error": "System error: Stats manager not initialized",
"layout": "",
})
}
// For manual refresh, always get fresh data by forcing cache invalidation
var processData *stats.ProcessStats
var err error
// Force cache refresh for process stats on manual refresh
if isManualRefresh {
h.statsManager.ForceUpdate("process")
}
if isManualRefresh {
// Force bypass cache for manual refresh by using fresh data
processData, err = h.statsManager.GetProcessStatsFresh(0)
} else {
// Use cached data for auto-polling
processData, err = h.statsManager.GetProcessStats(0)
}
if err != nil {
// Try alternative method if the primary method fails
if isManualRefresh {
processData, err = h.statsManager.GetProcessStats(0)
} else {
processData, err = h.statsManager.GetProcessStatsFresh(0)
}
if err != nil {
// Handle AJAX requests differently from regular requests
isAjax := c.Get("X-Requested-With") == "XMLHttpRequest"
if isAjax {
return c.Status(fiber.StatusInternalServerError).SendString("Failed to get process data: " + err.Error())
}
// For regular requests, render the error within the fragment
return c.Render("admin/system/processes_data", fiber.Map{
"error": "Failed to get process data: " + err.Error(),
"layout": "",
})
}
}
// Convert to []fiber.Map for template rendering
processStats := make([]fiber.Map, len(processData.Processes))
for i, proc := range processData.Processes {
processStats[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,
"cpu_percent_str": fmt.Sprintf("%.1f%%", proc.CPUPercent),
"memory_mb_str": fmt.Sprintf("%.1f MB", proc.MemoryMB),
}
}
// Create a boolean to indicate if we have processes
hasProcesses := len(processStats) > 0
// Create template data with fiber.Map
templateData := fiber.Map{
"hasProcesses": hasProcesses,
"processCount": len(processStats),
"processStats": processStats,
"layout": "", // Disable layout for partial template
}
// Return only the table HTML content directly to be injected into the processes-table-content div
return c.Render("admin/system/processes_data", templateData)
}