267 lines
6.5 KiB
Go
267 lines
6.5 KiB
Go
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
|
|
}
|