...
This commit is contained in:
266
pkg/heroagent/handlers/service_handlers.go
Normal file
266
pkg/heroagent/handlers/service_handlers.go
Normal file
@@ -0,0 +1,266 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces/openrpc"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
// ServiceHandler handles service-related routes
|
||||
type ServiceHandler struct {
|
||||
client *openrpc.Client
|
||||
}
|
||||
|
||||
// NewServiceHandler creates a new ServiceHandler
|
||||
func NewServiceHandler(socketPath, secret string) *ServiceHandler {
|
||||
fmt.Printf("DEBUG: Creating new ServiceHandler with socket path: %s and secret: %s\n", socketPath, secret)
|
||||
return &ServiceHandler{
|
||||
client: openrpc.NewClient(socketPath, secret),
|
||||
}
|
||||
}
|
||||
|
||||
// GetServices renders the services page
|
||||
func (h *ServiceHandler) GetServices(c *fiber.Ctx) error {
|
||||
return c.Render("admin/services", fiber.Map{
|
||||
"title": "Services",
|
||||
"error": c.Query("error", ""),
|
||||
"warning": c.Query("warning", ""),
|
||||
})
|
||||
}
|
||||
|
||||
// GetServicesFragment returns the services table fragment for Unpoly updates
|
||||
func (h *ServiceHandler) GetServicesFragment(c *fiber.Ctx) error {
|
||||
processes, err := h.getProcessList()
|
||||
if err != nil {
|
||||
return c.Render("admin/services_fragment", fiber.Map{
|
||||
"error": fmt.Sprintf("Failed to fetch services: %v", err),
|
||||
})
|
||||
}
|
||||
|
||||
return c.Render("admin/services_fragment", fiber.Map{
|
||||
"processes": processes,
|
||||
})
|
||||
}
|
||||
|
||||
// StartService handles the request to start a new service
|
||||
func (h *ServiceHandler) StartService(c *fiber.Ctx) error {
|
||||
name := c.FormValue("name")
|
||||
command := c.FormValue("command")
|
||||
|
||||
if name == "" || command == "" {
|
||||
return c.JSON(fiber.Map{
|
||||
"error": "Service name and command are required",
|
||||
})
|
||||
}
|
||||
|
||||
// Default to enabling logs
|
||||
logEnabled := true
|
||||
|
||||
// Start the process with no deadline, no cron, and no job ID
|
||||
fmt.Printf("DEBUG: StartService called for '%s' using client: %p\n", name, h.client)
|
||||
result, err := h.client.StartProcess(name, command, logEnabled, 0, "", "")
|
||||
if err != nil {
|
||||
return c.JSON(fiber.Map{
|
||||
"error": fmt.Sprintf("Failed to start service: %v", err),
|
||||
})
|
||||
}
|
||||
|
||||
if !result.Success {
|
||||
return c.JSON(fiber.Map{
|
||||
"error": result.Message,
|
||||
})
|
||||
}
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
"success": true,
|
||||
"message": result.Message,
|
||||
"pid": result.PID,
|
||||
})
|
||||
}
|
||||
|
||||
// StopService handles the request to stop a service
|
||||
func (h *ServiceHandler) StopService(c *fiber.Ctx) error {
|
||||
name := c.FormValue("name")
|
||||
|
||||
if name == "" {
|
||||
return c.JSON(fiber.Map{
|
||||
"error": "Service name is required",
|
||||
})
|
||||
}
|
||||
|
||||
result, err := h.client.StopProcess(name)
|
||||
if err != nil {
|
||||
return c.JSON(fiber.Map{
|
||||
"error": fmt.Sprintf("Failed to stop service: %v", err),
|
||||
})
|
||||
}
|
||||
|
||||
if !result.Success {
|
||||
return c.JSON(fiber.Map{
|
||||
"error": result.Message,
|
||||
})
|
||||
}
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
"success": true,
|
||||
"message": result.Message,
|
||||
})
|
||||
}
|
||||
|
||||
// RestartService handles the request to restart a service
|
||||
func (h *ServiceHandler) RestartService(c *fiber.Ctx) error {
|
||||
name := c.FormValue("name")
|
||||
|
||||
if name == "" {
|
||||
return c.JSON(fiber.Map{
|
||||
"error": "Service name is required",
|
||||
})
|
||||
}
|
||||
|
||||
result, err := h.client.RestartProcess(name)
|
||||
if err != nil {
|
||||
return c.JSON(fiber.Map{
|
||||
"error": fmt.Sprintf("Failed to restart service: %v", err),
|
||||
})
|
||||
}
|
||||
|
||||
if !result.Success {
|
||||
return c.JSON(fiber.Map{
|
||||
"error": result.Message,
|
||||
})
|
||||
}
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
"success": true,
|
||||
"message": result.Message,
|
||||
"pid": result.PID,
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteService handles the request to delete a service
|
||||
func (h *ServiceHandler) DeleteService(c *fiber.Ctx) error {
|
||||
name := c.FormValue("name")
|
||||
|
||||
if name == "" {
|
||||
return c.JSON(fiber.Map{
|
||||
"error": "Service name is required",
|
||||
})
|
||||
}
|
||||
|
||||
result, err := h.client.DeleteProcess(name)
|
||||
if err != nil {
|
||||
return c.JSON(fiber.Map{
|
||||
"error": fmt.Sprintf("Failed to delete service: %v", err),
|
||||
})
|
||||
}
|
||||
|
||||
if !result.Success {
|
||||
return c.JSON(fiber.Map{
|
||||
"error": result.Message,
|
||||
})
|
||||
}
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
"success": true,
|
||||
"message": result.Message,
|
||||
})
|
||||
}
|
||||
|
||||
// GetServiceLogs handles the request to get logs for a service
|
||||
func (h *ServiceHandler) GetServiceLogs(c *fiber.Ctx) error {
|
||||
name := c.Query("name")
|
||||
lines := c.QueryInt("lines", 100)
|
||||
|
||||
fmt.Printf("DEBUG: GetServiceLogs called for service '%s' using client: %p\n", name, h.client)
|
||||
|
||||
if name == "" {
|
||||
return c.JSON(fiber.Map{
|
||||
"error": "Service name is required",
|
||||
})
|
||||
}
|
||||
|
||||
// Debug: List all processes before getting logs
|
||||
processes, listErr := h.getProcessList()
|
||||
if listErr == nil {
|
||||
fmt.Println("DEBUG: Current processes in service handler:")
|
||||
for _, proc := range processes {
|
||||
fmt.Printf("DEBUG: - '%v' (PID: %v, Status: %v)\n", proc["Name"], proc["ID"], proc["Status"])
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("DEBUG: Error listing processes: %v\n", listErr)
|
||||
}
|
||||
|
||||
result, err := h.client.GetProcessLogs(name, lines)
|
||||
if err != nil {
|
||||
return c.JSON(fiber.Map{
|
||||
"error": fmt.Sprintf("Failed to get service logs: %v", err),
|
||||
})
|
||||
}
|
||||
|
||||
if !result.Success {
|
||||
return c.JSON(fiber.Map{
|
||||
"error": result.Message,
|
||||
})
|
||||
}
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
"success": true,
|
||||
"logs": result.Logs,
|
||||
})
|
||||
}
|
||||
|
||||
// Helper function to get the list of processes and format them for the UI
|
||||
func (h *ServiceHandler) getProcessList() ([]fiber.Map, error) {
|
||||
// Get the list of processes
|
||||
result, err := h.client.ListProcesses("json")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list processes: %v", err)
|
||||
}
|
||||
|
||||
// Convert the result to a slice of ProcessStatus
|
||||
processList, ok := result.([]interfaces.ProcessStatus)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected result type from ListProcesses")
|
||||
}
|
||||
|
||||
// Format the processes for the UI
|
||||
formattedProcesses := make([]fiber.Map, 0, len(processList))
|
||||
for _, proc := range processList {
|
||||
// Calculate uptime
|
||||
uptime := "N/A"
|
||||
if proc.Status == "running" {
|
||||
duration := time.Since(proc.StartTime)
|
||||
if duration.Hours() >= 24 {
|
||||
days := int(duration.Hours() / 24)
|
||||
hours := int(duration.Hours()) % 24
|
||||
uptime = fmt.Sprintf("%dd %dh", days, hours)
|
||||
} else if duration.Hours() >= 1 {
|
||||
hours := int(duration.Hours())
|
||||
minutes := int(duration.Minutes()) % 60
|
||||
uptime = fmt.Sprintf("%dh %dm", hours, minutes)
|
||||
} else {
|
||||
minutes := int(duration.Minutes())
|
||||
seconds := int(duration.Seconds()) % 60
|
||||
uptime = fmt.Sprintf("%dm %ds", minutes, seconds)
|
||||
}
|
||||
}
|
||||
|
||||
// Format CPU and memory usage
|
||||
cpuUsage := fmt.Sprintf("%.1f%%", proc.CPUPercent)
|
||||
memoryUsage := fmt.Sprintf("%.1f MB", proc.MemoryMB)
|
||||
|
||||
formattedProcesses = append(formattedProcesses, fiber.Map{
|
||||
"Name": proc.Name,
|
||||
"Status": string(proc.Status),
|
||||
"ID": proc.PID,
|
||||
"CPU": cpuUsage,
|
||||
"Memory": memoryUsage,
|
||||
"Uptime": uptime,
|
||||
})
|
||||
}
|
||||
|
||||
return formattedProcesses, nil
|
||||
}
|
Reference in New Issue
Block a user