This commit is contained in:
2025-04-23 04:18:28 +02:00
parent 10a7d9bb6b
commit a16ac8f627
276 changed files with 85166 additions and 1 deletions

View File

@@ -0,0 +1,242 @@
package openrpc
import (
"encoding/json"
"fmt"
"github.com/freeflowuniverse/heroagent/pkg/openrpcmanager/client"
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces"
)
// Client provides a client for interacting with process manager operations via RPC
type Client struct {
client.BaseClient
secret string
}
// NewClient creates a new client for the process manager API
func NewClient(socketPath, secret string) *Client {
return &Client{
BaseClient: *client.NewClient(socketPath, secret),
}
}
// StartProcess starts a new process with the given name and command
func (c *Client) StartProcess(name, command string, logEnabled bool, deadline int, cron, jobID string) (interfaces.ProcessStartResult, error) {
params := map[string]interface{}{
"name": name,
"command": command,
"log_enabled": logEnabled,
"deadline": deadline,
"cron": cron,
"job_id": jobID,
}
paramsJSON, err := json.Marshal(params)
if err != nil {
return interfaces.ProcessStartResult{}, fmt.Errorf("failed to marshal parameters: %w", err)
}
result, err := c.Request("process.start", paramsJSON, "")
if err != nil {
return interfaces.ProcessStartResult{}, fmt.Errorf("failed to start process: %w", err)
}
// Convert result to ProcessStartResult
resultJSON, err := json.Marshal(result)
if err != nil {
return interfaces.ProcessStartResult{}, fmt.Errorf("failed to marshal result: %w", err)
}
var startResult interfaces.ProcessStartResult
if err := json.Unmarshal(resultJSON, &startResult); err != nil {
return interfaces.ProcessStartResult{}, fmt.Errorf("failed to unmarshal process start result: %w", err)
}
return startResult, nil
}
// StopProcess stops a running process
func (c *Client) StopProcess(name string) (interfaces.ProcessStopResult, error) {
params := map[string]string{
"name": name,
}
paramsJSON, err := json.Marshal(params)
if err != nil {
return interfaces.ProcessStopResult{}, fmt.Errorf("failed to marshal parameters: %w", err)
}
result, err := c.Request("process.stop", paramsJSON, "")
if err != nil {
return interfaces.ProcessStopResult{}, fmt.Errorf("failed to stop process: %w", err)
}
// Convert result to ProcessStopResult
resultJSON, err := json.Marshal(result)
if err != nil {
return interfaces.ProcessStopResult{}, fmt.Errorf("failed to marshal result: %w", err)
}
var stopResult interfaces.ProcessStopResult
if err := json.Unmarshal(resultJSON, &stopResult); err != nil {
return interfaces.ProcessStopResult{}, fmt.Errorf("failed to unmarshal process stop result: %w", err)
}
return stopResult, nil
}
// RestartProcess restarts a process
func (c *Client) RestartProcess(name string) (interfaces.ProcessRestartResult, error) {
params := map[string]string{
"name": name,
}
paramsJSON, err := json.Marshal(params)
if err != nil {
return interfaces.ProcessRestartResult{}, fmt.Errorf("failed to marshal parameters: %w", err)
}
result, err := c.Request("process.restart", paramsJSON, "")
if err != nil {
return interfaces.ProcessRestartResult{}, fmt.Errorf("failed to restart process: %w", err)
}
// Convert result to ProcessRestartResult
resultJSON, err := json.Marshal(result)
if err != nil {
return interfaces.ProcessRestartResult{}, fmt.Errorf("failed to marshal result: %w", err)
}
var restartResult interfaces.ProcessRestartResult
if err := json.Unmarshal(resultJSON, &restartResult); err != nil {
return interfaces.ProcessRestartResult{}, fmt.Errorf("failed to unmarshal process restart result: %w", err)
}
return restartResult, nil
}
// DeleteProcess deletes a process from the manager
func (c *Client) DeleteProcess(name string) (interfaces.ProcessDeleteResult, error) {
params := map[string]string{
"name": name,
}
paramsJSON, err := json.Marshal(params)
if err != nil {
return interfaces.ProcessDeleteResult{}, fmt.Errorf("failed to marshal parameters: %w", err)
}
result, err := c.Request("process.delete", paramsJSON, "")
if err != nil {
return interfaces.ProcessDeleteResult{}, fmt.Errorf("failed to delete process: %w", err)
}
// Convert result to ProcessDeleteResult
resultJSON, err := json.Marshal(result)
if err != nil {
return interfaces.ProcessDeleteResult{}, fmt.Errorf("failed to marshal result: %w", err)
}
var deleteResult interfaces.ProcessDeleteResult
if err := json.Unmarshal(resultJSON, &deleteResult); err != nil {
return interfaces.ProcessDeleteResult{}, fmt.Errorf("failed to unmarshal process delete result: %w", err)
}
return deleteResult, nil
}
// GetProcessStatus gets the status of a process
func (c *Client) GetProcessStatus(name string, format string) (interface{}, error) {
params := map[string]string{
"name": name,
"format": format,
}
paramsJSON, err := json.Marshal(params)
if err != nil {
return nil, fmt.Errorf("failed to marshal parameters: %w", err)
}
result, err := c.Request("process.status", paramsJSON, "")
if err != nil {
return nil, fmt.Errorf("failed to get process status: %w", err)
}
if format == "text" {
// For text format, return the raw result
return result, nil
}
// For JSON format, convert to ProcessStatus
resultJSON, err := json.Marshal(result)
if err != nil {
return nil, fmt.Errorf("failed to marshal result: %w", err)
}
var statusResult interfaces.ProcessStatus
if err := json.Unmarshal(resultJSON, &statusResult); err != nil {
return nil, fmt.Errorf("failed to unmarshal process status result: %w", err)
}
return statusResult, nil
}
// ListProcesses lists all processes
func (c *Client) ListProcesses(format string) (interface{}, error) {
params := map[string]string{
"format": format,
}
paramsJSON, err := json.Marshal(params)
if err != nil {
return nil, fmt.Errorf("failed to marshal parameters: %w", err)
}
result, err := c.Request("process.list", paramsJSON, "")
if err != nil {
return nil, fmt.Errorf("failed to list processes: %w", err)
}
if format == "text" {
// For text format, return the raw result
return result, nil
}
// For JSON format, convert to []ProcessStatus
resultJSON, err := json.Marshal(result)
if err != nil {
return nil, fmt.Errorf("failed to marshal result: %w", err)
}
var listResult []interfaces.ProcessStatus
if err := json.Unmarshal(resultJSON, &listResult); err != nil {
return nil, fmt.Errorf("failed to unmarshal process list result: %w", err)
}
return listResult, nil
}
// GetProcessLogs gets logs for a process
func (c *Client) GetProcessLogs(name string, lines int) (interfaces.ProcessLogResult, error) {
params := map[string]interface{}{
"name": name,
"lines": lines,
}
paramsJSON, err := json.Marshal(params)
if err != nil {
return interfaces.ProcessLogResult{}, fmt.Errorf("failed to marshal parameters: %w", err)
}
result, err := c.Request("process.log", paramsJSON, "")
if err != nil {
return interfaces.ProcessLogResult{}, fmt.Errorf("failed to get process logs: %w", err)
}
// Convert result to ProcessLogResult
resultJSON, err := json.Marshal(result)
if err != nil {
return interfaces.ProcessLogResult{}, fmt.Errorf("failed to marshal result: %w", err)
}
var logResult interfaces.ProcessLogResult
if err := json.Unmarshal(resultJSON, &logResult); err != nil {
return interfaces.ProcessLogResult{}, fmt.Errorf("failed to unmarshal process log result: %w", err)
}
return logResult, nil
}

View File

@@ -0,0 +1,269 @@
package openrpc
import (
"encoding/json"
"fmt"
"github.com/freeflowuniverse/heroagent/pkg/openrpcmanager"
"github.com/freeflowuniverse/heroagent/pkg/processmanager"
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces"
)
// Handler implements the OpenRPC handlers for process manager operations
type Handler struct {
processManager interfaces.ProcessManagerInterface
}
// NewHandler creates a new RPC handler for process manager operations
func NewHandler(processManager interfaces.ProcessManagerInterface) *Handler {
return &Handler{
processManager: processManager,
}
}
// GetHandlers returns a map of RPC handlers for the OpenRPC manager
func (h *Handler) GetHandlers() map[string]openrpcmanager.RPCHandler {
return map[string]openrpcmanager.RPCHandler{
"process.start": h.handleProcessStart,
"process.stop": h.handleProcessStop,
"process.restart": h.handleProcessRestart,
"process.delete": h.handleProcessDelete,
"process.status": h.handleProcessStatus,
"process.list": h.handleProcessList,
"process.log": h.handleProcessLog,
}
}
// handleProcessStart handles the process.start method
func (h *Handler) handleProcessStart(params json.RawMessage) (interface{}, error) {
var request struct {
Name string `json:"name"`
Command string `json:"command"`
LogEnabled bool `json:"log_enabled"`
Deadline int `json:"deadline"`
Cron string `json:"cron"`
JobID string `json:"job_id"`
}
if err := json.Unmarshal(params, &request); err != nil {
return nil, fmt.Errorf("invalid parameters: %w", err)
}
err := h.processManager.StartProcess(
request.Name,
request.Command,
request.LogEnabled,
request.Deadline,
request.Cron,
request.JobID,
)
result := interfaces.ProcessStartResult{
Success: err == nil,
Message: "",
}
if err != nil {
result.Message = err.Error()
return result, nil
}
// Get the process info to return the PID
procInfo, err := h.processManager.GetProcessStatus(request.Name)
if err != nil {
result.Message = fmt.Sprintf("Process started but failed to get status: %v", err)
return result, nil
}
result.PID = procInfo.PID
result.Message = fmt.Sprintf("Process '%s' started successfully with PID %d", request.Name, procInfo.PID)
return result, nil
}
// handleProcessStop handles the process.stop method
func (h *Handler) handleProcessStop(params json.RawMessage) (interface{}, error) {
var request struct {
Name string `json:"name"`
}
if err := json.Unmarshal(params, &request); err != nil {
return nil, fmt.Errorf("invalid parameters: %w", err)
}
err := h.processManager.StopProcess(request.Name)
result := interfaces.ProcessStopResult{
Success: err == nil,
Message: "",
}
if err != nil {
result.Message = err.Error()
} else {
result.Message = fmt.Sprintf("Process '%s' stopped successfully", request.Name)
}
return result, nil
}
// handleProcessRestart handles the process.restart method
func (h *Handler) handleProcessRestart(params json.RawMessage) (interface{}, error) {
var request struct {
Name string `json:"name"`
}
if err := json.Unmarshal(params, &request); err != nil {
return nil, fmt.Errorf("invalid parameters: %w", err)
}
err := h.processManager.RestartProcess(request.Name)
result := interfaces.ProcessRestartResult{
Success: err == nil,
Message: "",
}
if err != nil {
result.Message = err.Error()
return result, nil
}
// Get the process info to return the PID
procInfo, err := h.processManager.GetProcessStatus(request.Name)
if err != nil {
result.Message = fmt.Sprintf("Process restarted but failed to get status: %v", err)
return result, nil
}
result.PID = procInfo.PID
result.Message = fmt.Sprintf("Process '%s' restarted successfully with PID %d", request.Name, procInfo.PID)
return result, nil
}
// handleProcessDelete handles the process.delete method
func (h *Handler) handleProcessDelete(params json.RawMessage) (interface{}, error) {
var request struct {
Name string `json:"name"`
}
if err := json.Unmarshal(params, &request); err != nil {
return nil, fmt.Errorf("invalid parameters: %w", err)
}
err := h.processManager.DeleteProcess(request.Name)
result := interfaces.ProcessDeleteResult{
Success: err == nil,
Message: "",
}
if err != nil {
result.Message = err.Error()
} else {
result.Message = fmt.Sprintf("Process '%s' deleted successfully", request.Name)
}
return result, nil
}
// handleProcessStatus handles the process.status method
func (h *Handler) handleProcessStatus(params json.RawMessage) (interface{}, error) {
var request struct {
Name string `json:"name"`
Format string `json:"format"`
}
if err := json.Unmarshal(params, &request); err != nil {
return nil, fmt.Errorf("invalid parameters: %w", err)
}
procInfo, err := h.processManager.GetProcessStatus(request.Name)
if err != nil {
return nil, fmt.Errorf("failed to get process status: %w", err)
}
if request.Format == "text" {
// Format as text using the processmanager's FormatProcessInfo function
textResult, err := processmanager.FormatProcessInfo(procInfo, "text")
if err != nil {
return nil, fmt.Errorf("failed to format process info: %w", err)
}
return map[string]interface{}{
"text": textResult,
}, nil
}
// Default to JSON format
return convertProcessInfoToStatus(procInfo), nil
}
// handleProcessList handles the process.list method
func (h *Handler) handleProcessList(params json.RawMessage) (interface{}, error) {
var request struct {
Format string `json:"format"`
}
if err := json.Unmarshal(params, &request); err != nil {
return nil, fmt.Errorf("invalid parameters: %w", err)
}
processes := h.processManager.ListProcesses()
if request.Format == "text" {
// Format as text using the processmanager's FormatProcessList function
textResult, err := processmanager.FormatProcessList(processes, "text")
if err != nil {
return nil, fmt.Errorf("failed to format process list: %w", err)
}
return map[string]interface{}{
"text": textResult,
}, nil
}
// Default to JSON format
result := make([]interfaces.ProcessStatus, 0, len(processes))
for _, proc := range processes {
result = append(result, convertProcessInfoToStatus(proc))
}
return result, nil
}
// handleProcessLog handles the process.log method
func (h *Handler) handleProcessLog(params json.RawMessage) (interface{}, error) {
var request struct {
Name string `json:"name"`
Lines int `json:"lines"`
}
if err := json.Unmarshal(params, &request); err != nil {
return nil, fmt.Errorf("invalid parameters: %w", err)
}
logs, err := h.processManager.GetProcessLogs(request.Name, request.Lines)
result := interfaces.ProcessLogResult{
Success: err == nil,
Message: "",
Logs: logs,
}
if err != nil {
result.Message = err.Error()
result.Logs = ""
} else {
result.Message = fmt.Sprintf("Retrieved %d lines of logs for process '%s'", request.Lines, request.Name)
}
return result, nil
}
// convertProcessInfoToStatus converts a ProcessInfo to a ProcessStatus
func convertProcessInfoToStatus(info *processmanager.ProcessInfo) interfaces.ProcessStatus {
return interfaces.ProcessStatus{
Name: info.Name,
Command: info.Command,
PID: info.PID,
Status: string(info.Status),
CPUPercent: info.CPUPercent,
MemoryMB: info.MemoryMB,
StartTime: info.StartTime,
LogEnabled: info.LogEnabled,
Cron: info.Cron,
JobID: info.JobID,
Deadline: info.Deadline,
Error: info.Error,
}
}

View File

@@ -0,0 +1,130 @@
package openrpc
import (
"os"
"path/filepath"
"testing"
"time"
"github.com/freeflowuniverse/heroagent/pkg/processmanager"
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestProcessManagerRPC(t *testing.T) {
// Create a temporary directory for the socket
tempDir, err := os.MkdirTemp("", "processmanager-rpc-test")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
// Create a socket path
socketPath := filepath.Join(tempDir, "process-manager.sock")
// Create a process manager
pm := processmanager.NewProcessManager()
pm.SetLogsBasePath(filepath.Join(tempDir, "logs"))
// Create and start the server
server, err := NewServer(pm, socketPath)
require.NoError(t, err)
// Start the server in a goroutine
go func() {
err := server.Start()
if err != nil {
t.Logf("Error starting server: %v", err)
}
}()
// Wait for the server to start
time.Sleep(100 * time.Millisecond)
// Create a client
client := NewClient(socketPath, "")
// Test process start
t.Run("StartProcess", func(t *testing.T) {
result, err := client.StartProcess("test-process", "echo 'Hello, World!'", true, 0, "", "")
require.NoError(t, err)
assert.True(t, result.Success)
assert.NotEmpty(t, result.Message)
assert.NotZero(t, result.PID)
})
// Test process status
t.Run("GetProcessStatus", func(t *testing.T) {
status, err := client.GetProcessStatus("test-process", "json")
require.NoError(t, err)
processStatus, ok := status.(interfaces.ProcessStatus)
require.True(t, ok)
assert.Equal(t, "test-process", processStatus.Name)
assert.Equal(t, "echo 'Hello, World!'", processStatus.Command)
})
// Test process list
t.Run("ListProcesses", func(t *testing.T) {
processList, err := client.ListProcesses("json")
require.NoError(t, err)
processes, ok := processList.([]interfaces.ProcessStatus)
require.True(t, ok)
assert.NotEmpty(t, processes)
// Find our test process
found := false
for _, proc := range processes {
if proc.Name == "test-process" {
found = true
break
}
}
assert.True(t, found)
})
// Test process logs
t.Run("GetProcessLogs", func(t *testing.T) {
// Wait a bit for logs to be generated
time.Sleep(100 * time.Millisecond)
logs, err := client.GetProcessLogs("test-process", 10)
require.NoError(t, err)
assert.True(t, logs.Success)
})
// Test process restart
t.Run("RestartProcess", func(t *testing.T) {
result, err := client.RestartProcess("test-process")
require.NoError(t, err)
assert.True(t, result.Success)
assert.NotEmpty(t, result.Message)
})
// Test process stop
t.Run("StopProcess", func(t *testing.T) {
result, err := client.StopProcess("test-process")
require.NoError(t, err)
assert.True(t, result.Success)
assert.NotEmpty(t, result.Message)
})
// Test process delete
t.Run("DeleteProcess", func(t *testing.T) {
result, err := client.DeleteProcess("test-process")
require.NoError(t, err)
assert.True(t, result.Success)
assert.NotEmpty(t, result.Message)
})
// Stop the server
err = server.Stop()
require.NoError(t, err)
}
// TestProcessManagerRPCWithMock tests the RPC interface with a mock process manager
func TestProcessManagerRPCWithMock(t *testing.T) {
// This test would use a mock implementation of the ProcessManagerInterface
// to test the RPC layer without actually starting real processes
t.Skip("Mock implementation test to be added")
}

View File

@@ -0,0 +1,32 @@
package openrpc
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"runtime"
"github.com/freeflowuniverse/heroagent/pkg/openrpcmanager"
)
// LoadSchema loads the OpenRPC schema from the embedded JSON file
func LoadSchema() (openrpcmanager.OpenRPCSchema, error) {
// Get the absolute path to the schema.json file
_, filename, _, _ := runtime.Caller(0)
schemaPath := filepath.Join(filepath.Dir(filename), "schema.json")
// Read the schema file
schemaBytes, err := os.ReadFile(schemaPath)
if err != nil {
return openrpcmanager.OpenRPCSchema{}, fmt.Errorf("failed to read schema file: %w", err)
}
// Unmarshal the schema
var schema openrpcmanager.OpenRPCSchema
if err := json.Unmarshal(schemaBytes, &schema); err != nil {
return openrpcmanager.OpenRPCSchema{}, fmt.Errorf("failed to unmarshal schema: %w", err)
}
return schema, nil
}

View File

@@ -0,0 +1,333 @@
{
"openrpc": "1.2.6",
"info": {
"title": "Process Manager API",
"version": "1.0.0",
"description": "API for managing and monitoring processes"
},
"methods": [
{
"name": "process.start",
"description": "Start a new process with the given name and command",
"params": [
{
"name": "name",
"description": "Name of the process",
"schema": {
"type": "string"
}
},
{
"name": "command",
"description": "Command to execute",
"schema": {
"type": "string"
}
},
{
"name": "log_enabled",
"description": "Whether to enable logging for the process",
"schema": {
"type": "boolean"
}
},
{
"name": "deadline",
"description": "Deadline in seconds after which the process will be automatically stopped (0 for no deadline)",
"schema": {
"type": "integer"
}
},
{
"name": "cron",
"description": "Cron expression for scheduled execution",
"schema": {
"type": "string"
}
},
{
"name": "job_id",
"description": "Optional job ID for tracking",
"schema": {
"type": "string"
}
}
],
"result": {
"name": "result",
"description": "Process start result",
"schema": {
"type": "object",
"properties": {
"success": {
"type": "boolean"
},
"message": {
"type": "string"
},
"pid": {
"type": "integer"
}
}
}
}
},
{
"name": "process.stop",
"description": "Stop a running process",
"params": [
{
"name": "name",
"description": "Name of the process to stop",
"schema": {
"type": "string"
}
}
],
"result": {
"name": "result",
"description": "Process stop result",
"schema": {
"type": "object",
"properties": {
"success": {
"type": "boolean"
},
"message": {
"type": "string"
}
}
}
}
},
{
"name": "process.restart",
"description": "Restart a process",
"params": [
{
"name": "name",
"description": "Name of the process to restart",
"schema": {
"type": "string"
}
}
],
"result": {
"name": "result",
"description": "Process restart result",
"schema": {
"type": "object",
"properties": {
"success": {
"type": "boolean"
},
"message": {
"type": "string"
},
"pid": {
"type": "integer"
}
}
}
}
},
{
"name": "process.delete",
"description": "Delete a process from the manager",
"params": [
{
"name": "name",
"description": "Name of the process to delete",
"schema": {
"type": "string"
}
}
],
"result": {
"name": "result",
"description": "Process delete result",
"schema": {
"type": "object",
"properties": {
"success": {
"type": "boolean"
},
"message": {
"type": "string"
}
}
}
}
},
{
"name": "process.status",
"description": "Get the status of a process",
"params": [
{
"name": "name",
"description": "Name of the process",
"schema": {
"type": "string"
}
},
{
"name": "format",
"description": "Output format (json or text)",
"schema": {
"type": "string",
"enum": ["json", "text"]
}
}
],
"result": {
"name": "result",
"description": "Process status information",
"schema": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"command": {
"type": "string"
},
"pid": {
"type": "integer"
},
"status": {
"type": "string",
"enum": ["running", "stopped", "failed", "completed"]
},
"cpu_percent": {
"type": "number"
},
"memory_mb": {
"type": "number"
},
"start_time": {
"type": "string",
"format": "date-time"
},
"log_enabled": {
"type": "boolean"
},
"cron": {
"type": "string"
},
"job_id": {
"type": "string"
},
"deadline": {
"type": "integer"
},
"error": {
"type": "string"
}
}
}
}
},
{
"name": "process.list",
"description": "List all processes",
"params": [
{
"name": "format",
"description": "Output format (json or text)",
"schema": {
"type": "string",
"enum": ["json", "text"]
}
}
],
"result": {
"name": "result",
"description": "List of processes",
"schema": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"command": {
"type": "string"
},
"pid": {
"type": "integer"
},
"status": {
"type": "string",
"enum": ["running", "stopped", "failed", "completed"]
},
"cpu_percent": {
"type": "number"
},
"memory_mb": {
"type": "number"
},
"start_time": {
"type": "string",
"format": "date-time"
},
"log_enabled": {
"type": "boolean"
},
"cron": {
"type": "string"
},
"job_id": {
"type": "string"
},
"deadline": {
"type": "integer"
},
"error": {
"type": "string"
}
}
}
}
}
},
{
"name": "process.log",
"description": "Get logs for a process",
"params": [
{
"name": "name",
"description": "Name of the process",
"schema": {
"type": "string"
}
},
{
"name": "lines",
"description": "Number of log lines to retrieve",
"schema": {
"type": "integer"
}
}
],
"result": {
"name": "result",
"description": "Process logs",
"schema": {
"type": "object",
"properties": {
"success": {
"type": "boolean"
},
"message": {
"type": "string"
},
"logs": {
"type": "string"
}
}
}
}
}
]
}

View File

@@ -0,0 +1,100 @@
package openrpc
import (
"fmt"
"log"
"os"
"path/filepath"
"github.com/freeflowuniverse/heroagent/pkg/openrpcmanager"
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces"
)
// Server represents the Process Manager OpenRPC server
type Server struct {
processManager interfaces.ProcessManagerInterface
socketPath string
openRPCMgr *openrpcmanager.OpenRPCManager
unixServer *openrpcmanager.UnixServer
isRunning bool
}
// NewServer creates a new Process Manager OpenRPC server
func NewServer(processManager interfaces.ProcessManagerInterface, socketPath string) (*Server, error) {
// Ensure the directory for the socket exists
socketDir := filepath.Dir(socketPath)
if err := os.MkdirAll(socketDir, 0755); err != nil {
return nil, fmt.Errorf("failed to create socket directory: %w", err)
}
// Load the OpenRPC schema
schema, err := LoadSchema()
if err != nil {
return nil, fmt.Errorf("failed to load OpenRPC schema: %w", err)
}
// Create a new handler - no authentication now
handler := NewHandler(processManager)
// Create a new OpenRPC manager - using empty string for auth (no authentication)
openRPCMgr, err := openrpcmanager.NewOpenRPCManager(schema, handler.GetHandlers(), "")
if err != nil {
return nil, fmt.Errorf("failed to create OpenRPC manager: %w", err)
}
// Create a new Unix server
unixServer, err := openrpcmanager.NewUnixServer(openRPCMgr, socketPath)
if err != nil {
return nil, fmt.Errorf("failed to create Unix server: %w", err)
}
return &Server{
processManager: processManager,
socketPath: socketPath,
openRPCMgr: openRPCMgr,
unixServer: unixServer,
isRunning: false,
}, nil
}
// Start starts the Process Manager OpenRPC server
func (s *Server) Start() error {
if s.isRunning {
return fmt.Errorf("server is already running")
}
// Start the Unix server
if err := s.unixServer.Start(); err != nil {
return fmt.Errorf("failed to start Unix server: %w", err)
}
s.isRunning = true
log.Printf("Process Manager OpenRPC server started on socket: %s", s.socketPath)
return nil
}
// Stop stops the Process Manager OpenRPC server
func (s *Server) Stop() error {
if !s.isRunning {
return fmt.Errorf("server is not running")
}
// Stop the Unix server
if err := s.unixServer.Stop(); err != nil {
return fmt.Errorf("failed to stop Unix server: %w", err)
}
s.isRunning = false
log.Printf("Process Manager OpenRPC server stopped")
return nil
}
// IsRunning returns whether the server is running
func (s *Server) IsRunning() bool {
return s.isRunning
}
// SocketPath returns the socket path
func (s *Server) SocketPath() string {
return s.socketPath
}

View File

@@ -0,0 +1,80 @@
package interfaces
import (
"time"
"github.com/freeflowuniverse/heroagent/pkg/processmanager"
)
// ProcessManagerInterface defines the interface for process management operations
type ProcessManagerInterface interface {
// StartProcess starts a new process with the given name and command
StartProcess(name, command string, logEnabled bool, deadline int, cron, jobID string) error
// StopProcess stops a running process
StopProcess(name string) error
// RestartProcess restarts a process
RestartProcess(name string) error
// DeleteProcess removes a process from the manager
DeleteProcess(name string) error
// GetProcessStatus returns the status of a process
GetProcessStatus(name string) (*processmanager.ProcessInfo, error)
// ListProcesses returns a list of all processes
ListProcesses() []*processmanager.ProcessInfo
// GetProcessLogs returns the logs for a specific process
GetProcessLogs(name string, lines int) (string, error)
}
// ProcessStartResult represents the result of starting a process
type ProcessStartResult struct {
Success bool `json:"success"`
Message string `json:"message"`
PID int32 `json:"pid"`
}
// ProcessStopResult represents the result of stopping a process
type ProcessStopResult struct {
Success bool `json:"success"`
Message string `json:"message"`
}
// ProcessRestartResult represents the result of restarting a process
type ProcessRestartResult struct {
Success bool `json:"success"`
Message string `json:"message"`
PID int32 `json:"pid"`
}
// ProcessDeleteResult represents the result of deleting a process
type ProcessDeleteResult struct {
Success bool `json:"success"`
Message string `json:"message"`
}
// ProcessLogResult represents the result of getting process logs
type ProcessLogResult struct {
Success bool `json:"success"`
Message string `json:"message"`
Logs string `json:"logs"`
}
// ProcessStatus represents detailed information about a process
type ProcessStatus struct {
Name string `json:"name"`
Command string `json:"command"`
PID int32 `json:"pid"`
Status string `json:"status"`
CPUPercent float64 `json:"cpu_percent"`
MemoryMB float64 `json:"memory_mb"`
StartTime time.Time `json:"start_time"`
LogEnabled bool `json:"log_enabled"`
Cron string `json:"cron,omitempty"`
JobID string `json:"job_id,omitempty"`
Deadline int `json:"deadline,omitempty"`
Error string `json:"error,omitempty"`
}