...
This commit is contained in:
@@ -11,7 +11,7 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/mycelium_client"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/mycelium_client"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
|
@@ -8,7 +8,7 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/mycelium_client"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/mycelium_client"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@@ -14,7 +14,7 @@ Dedupestor is a Go package that provides a key-value store with deduplication ba
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/freeflowuniverse/heroagent/pkg/dedupestor"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/dedupestor"
|
||||
)
|
||||
|
||||
// Create a new dedupe store
|
||||
|
@@ -7,8 +7,8 @@ import (
|
||||
"errors"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/data/ourdb"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/data/radixtree"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/data/ourdb"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/data/radixtree"
|
||||
)
|
||||
|
||||
// MaxValueSize is the maximum allowed size for values (1MB)
|
||||
|
@@ -18,7 +18,7 @@ The DocTree package provides functionality for managing collections of markdown
|
||||
### Creating a DocTree
|
||||
|
||||
```go
|
||||
import "github.com/freeflowuniverse/heroagent/pkg/doctree"
|
||||
import "git.ourworld.tf/herocode/heroagent/pkg/doctree"
|
||||
|
||||
// Create a new DocTree with a path and name
|
||||
dt, err := doctree.New("/path/to/collection", "My Collection")
|
||||
|
@@ -7,7 +7,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/tools"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/tools"
|
||||
)
|
||||
|
||||
// Collection represents a collection of markdown pages and files
|
||||
|
@@ -5,7 +5,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/tools"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/tools"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"github.com/yuin/goldmark"
|
||||
"github.com/yuin/goldmark/extension"
|
||||
|
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/tools"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/tools"
|
||||
)
|
||||
|
||||
// Global variable to track the current DocTree instance
|
||||
|
@@ -34,7 +34,7 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/ourdb"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/ourdb"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -78,7 +78,7 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/ourdb"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/ourdb"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@@ -4,7 +4,7 @@ package radixtree
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/data/ourdb"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/data/ourdb"
|
||||
)
|
||||
|
||||
// Node represents a node in the radix tree
|
||||
|
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/system/stats"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/system/stats"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
@@ -77,7 +77,7 @@ func (h *AdminHandler) getProcessStatsJSON(c *fiber.Ctx) error {
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"success": false,
|
||||
"error": "Failed to get process stats: " + err.Error(),
|
||||
"error": "Failed to get process stats: " + err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@@ -3,7 +3,7 @@ package api
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/sal/executor"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/sal/executor"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
@@ -7,9 +7,9 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces/openrpc"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/processmanager"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces/openrpc"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
@@ -102,26 +102,26 @@ func (h *ServiceHandler) getProcessList() ([]ProcessDisplayInfo, error) {
|
||||
if !ok {
|
||||
// Try to handle the result as a map or other structure
|
||||
h.logger.Printf("Warning: unexpected result type from ListProcesses, trying alternative parsing")
|
||||
|
||||
|
||||
// Try to convert the result to JSON and then parse it
|
||||
resultJSON, err := json.Marshal(result)
|
||||
if err != nil {
|
||||
h.logger.Printf("Error marshaling result to JSON: %v", err)
|
||||
return nil, fmt.Errorf("failed to marshal result: %w", err)
|
||||
}
|
||||
|
||||
|
||||
var processStatuses []interfaces.ProcessStatus
|
||||
if err := json.Unmarshal(resultJSON, &processStatuses); err != nil {
|
||||
h.logger.Printf("Error unmarshaling result to ProcessStatus: %v", err)
|
||||
return nil, fmt.Errorf("failed to unmarshal process list result: %w", err)
|
||||
}
|
||||
|
||||
|
||||
// Convert to display info format
|
||||
displayInfoList := make([]ProcessDisplayInfo, 0, len(processStatuses))
|
||||
for _, proc := range processStatuses {
|
||||
// Calculate uptime based on start time
|
||||
uptime := formatUptime(time.Since(proc.StartTime))
|
||||
|
||||
|
||||
displayInfo := ProcessDisplayInfo{
|
||||
ID: fmt.Sprintf("%d", proc.PID),
|
||||
Name: proc.Name,
|
||||
@@ -133,7 +133,7 @@ func (h *ServiceHandler) getProcessList() ([]ProcessDisplayInfo, error) {
|
||||
}
|
||||
displayInfoList = append(displayInfoList, displayInfo)
|
||||
}
|
||||
|
||||
|
||||
// Debug: Log the number of processes
|
||||
h.logger.Printf("Found %d processes", len(displayInfoList))
|
||||
return displayInfoList, nil
|
||||
@@ -144,7 +144,7 @@ func (h *ServiceHandler) getProcessList() ([]ProcessDisplayInfo, error) {
|
||||
for _, proc := range processStatuses {
|
||||
// Calculate uptime based on start time
|
||||
uptime := formatUptime(time.Since(proc.StartTime))
|
||||
|
||||
|
||||
displayInfo := ProcessDisplayInfo{
|
||||
ID: fmt.Sprintf("%d", proc.PID),
|
||||
Name: proc.Name,
|
||||
@@ -276,7 +276,7 @@ func (h *ServiceHandler) stopService(c *fiber.Ctx) error {
|
||||
"error": fmt.Sprintf("Failed to stop service: %v", err),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// Check if the result indicates success
|
||||
if !result.Success {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
@@ -331,7 +331,7 @@ func (h *ServiceHandler) restartService(c *fiber.Ctx) error {
|
||||
"error": fmt.Sprintf("Failed to restart service: %v", err),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// Check if the result indicates success
|
||||
if !result.Success {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
@@ -382,7 +382,7 @@ func (h *ServiceHandler) deleteService(c *fiber.Ctx) error {
|
||||
"error": fmt.Sprintf("Failed to delete service: %v", err),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// Check if the result indicates success
|
||||
if !result.Success {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
|
@@ -12,16 +12,16 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroagent/api"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroagent/handlers"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroagent/pages"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/sal/executor"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/servers/redisserver"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/system/stats"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroagent/api"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroagent/handlers"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroagent/pages"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/processmanager"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/sal/executor"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/servers/redisserver"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/system/stats"
|
||||
|
||||
// "github.com/freeflowuniverse/heroagent/pkg/vfs/interfaces"
|
||||
// "github.com/freeflowuniverse/heroagent/pkg/vfs/interfaces/mock"
|
||||
// "git.ourworld.tf/herocode/heroagent/pkg/vfs/interfaces"
|
||||
// "git.ourworld.tf/herocode/heroagent/pkg/vfs/interfaces/mock"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/cors"
|
||||
"github.com/gofiber/fiber/v2/middleware/logger"
|
||||
@@ -239,7 +239,7 @@ func (hl *HeroLauncher) GetUptime() string {
|
||||
func (hl *HeroLauncher) startProcessManager() error {
|
||||
_, filename, _, _ := runtime.Caller(0)
|
||||
projectRoot := filepath.Join(filepath.Dir(filename), "../..")
|
||||
processManagerPath := filepath.Join(projectRoot, "cmd/processmanager/main.go")
|
||||
processManagerPath := filepath.Join(projectRoot, "pkg/processmanager/examples/openrpc/main.go")
|
||||
|
||||
log.Printf("Starting process manager from: %s", processManagerPath)
|
||||
|
||||
|
@@ -5,7 +5,7 @@ import (
|
||||
"log"
|
||||
"strconv" // Added strconv for JobID parsing
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/herojobs"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/herojobs"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
|
@@ -10,7 +10,7 @@ import (
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/herojobs"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/herojobs"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
|
@@ -7,7 +7,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/logger"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/logger"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
@@ -65,40 +65,40 @@ func NewLogHandler(logPath string) (*LogHandler, error) {
|
||||
type LogType string
|
||||
|
||||
const (
|
||||
LogTypeSystem LogType = "system"
|
||||
LogTypeService LogType = "service"
|
||||
LogTypeJob LogType = "job"
|
||||
LogTypeProcess LogType = "process"
|
||||
LogTypeAll LogType = "all" // Special type to retrieve logs from all sources
|
||||
LogTypeSystem LogType = "system"
|
||||
LogTypeService LogType = "service"
|
||||
LogTypeJob LogType = "job"
|
||||
LogTypeProcess LogType = "process"
|
||||
LogTypeAll LogType = "all" // Special type to retrieve logs from all sources
|
||||
)
|
||||
|
||||
// GetLogs renders the logs page with logs content
|
||||
func (h *LogHandler) GetLogs(c *fiber.Ctx) error {
|
||||
// Check which logger to use based on the log type parameter
|
||||
logTypeParam := c.Query("log_type", string(LogTypeSystem))
|
||||
|
||||
|
||||
// Parse query parameters
|
||||
category := c.Query("category", "")
|
||||
logItemType := parseLogType(c.Query("type", ""))
|
||||
maxItems := c.QueryInt("max_items", 100)
|
||||
page := c.QueryInt("page", 1)
|
||||
itemsPerPage := 20 // Default items per page
|
||||
|
||||
|
||||
// Parse time range
|
||||
fromTime := parseTimeParam(c.Query("from", ""))
|
||||
toTime := parseTimeParam(c.Query("to", ""))
|
||||
|
||||
|
||||
// Create search arguments
|
||||
searchArgs := logger.SearchArgs{
|
||||
Category: category,
|
||||
LogType: logItemType,
|
||||
MaxItems: maxItems,
|
||||
Category: category,
|
||||
LogType: logItemType,
|
||||
MaxItems: maxItems,
|
||||
}
|
||||
|
||||
|
||||
if !fromTime.IsZero() {
|
||||
searchArgs.TimestampFrom = &fromTime
|
||||
}
|
||||
|
||||
|
||||
if !toTime.IsZero() {
|
||||
searchArgs.TimestampTo = &toTime
|
||||
}
|
||||
@@ -107,7 +107,7 @@ func (h *LogHandler) GetLogs(c *fiber.Ctx) error {
|
||||
var logs []logger.LogItem
|
||||
var err error
|
||||
var logTypeTitle string
|
||||
|
||||
|
||||
// Check if we want to merge logs from all sources
|
||||
if LogType(logTypeParam) == LogTypeAll {
|
||||
// Get merged logs from all loggers
|
||||
@@ -116,7 +116,7 @@ func (h *LogHandler) GetLogs(c *fiber.Ctx) error {
|
||||
} else {
|
||||
// Select the appropriate logger based on the log type
|
||||
var selectedLogger *logger.Logger
|
||||
|
||||
|
||||
switch LogType(logTypeParam) {
|
||||
case LogTypeService:
|
||||
selectedLogger = h.serviceLogger
|
||||
@@ -131,13 +131,13 @@ func (h *LogHandler) GetLogs(c *fiber.Ctx) error {
|
||||
selectedLogger = h.systemLogger
|
||||
logTypeTitle = "System Logs"
|
||||
}
|
||||
|
||||
|
||||
// Check if the selected logger is properly initialized
|
||||
if selectedLogger == nil {
|
||||
return c.Render("admin/system/logs", fiber.Map{
|
||||
"title": logTypeTitle,
|
||||
"error": "Logger not initialized",
|
||||
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
|
||||
"title": logTypeTitle,
|
||||
"error": "Logger not initialized",
|
||||
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
|
||||
"selectedLogType": logTypeParam,
|
||||
})
|
||||
}
|
||||
@@ -149,25 +149,24 @@ func (h *LogHandler) GetLogs(c *fiber.Ctx) error {
|
||||
// Handle search error
|
||||
if err != nil {
|
||||
return c.Render("admin/system/logs", fiber.Map{
|
||||
"title": logTypeTitle,
|
||||
"error": err.Error(),
|
||||
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
|
||||
"title": logTypeTitle,
|
||||
"error": err.Error(),
|
||||
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
|
||||
"selectedLogType": logTypeParam,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Calculate total pages
|
||||
totalLogs := len(logs)
|
||||
totalPages := (totalLogs + itemsPerPage - 1) / itemsPerPage
|
||||
|
||||
|
||||
// Apply pagination
|
||||
startIndex := (page - 1) * itemsPerPage
|
||||
endIndex := startIndex + itemsPerPage
|
||||
if endIndex > totalLogs {
|
||||
endIndex = totalLogs
|
||||
}
|
||||
|
||||
|
||||
// Slice logs for current page
|
||||
pagedLogs := logs
|
||||
if startIndex < totalLogs {
|
||||
@@ -175,7 +174,7 @@ func (h *LogHandler) GetLogs(c *fiber.Ctx) error {
|
||||
} else {
|
||||
pagedLogs = []logger.LogItem{}
|
||||
}
|
||||
|
||||
|
||||
// Convert logs to a format suitable for the UI
|
||||
formattedLogs := make([]fiber.Map, 0, len(pagedLogs))
|
||||
for _, log := range pagedLogs {
|
||||
@@ -185,7 +184,7 @@ func (h *LogHandler) GetLogs(c *fiber.Ctx) error {
|
||||
logTypeStr = "ERROR"
|
||||
logTypeClass = "log-error"
|
||||
}
|
||||
|
||||
|
||||
formattedLogs = append(formattedLogs, fiber.Map{
|
||||
"timestamp": log.Timestamp.Format("2006-01-02T15:04:05"),
|
||||
"category": log.Category,
|
||||
@@ -194,20 +193,20 @@ func (h *LogHandler) GetLogs(c *fiber.Ctx) error {
|
||||
"typeClass": logTypeClass,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
return c.Render("admin/system/logs", fiber.Map{
|
||||
"title": logTypeTitle,
|
||||
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
|
||||
"title": logTypeTitle,
|
||||
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
|
||||
"selectedLogType": logTypeParam,
|
||||
"logs": formattedLogs,
|
||||
"total": totalLogs,
|
||||
"showing": len(formattedLogs),
|
||||
"page": page,
|
||||
"totalPages": totalPages,
|
||||
"categoryParam": category,
|
||||
"typeParam": c.Query("type", ""),
|
||||
"fromParam": c.Query("from", ""),
|
||||
"toParam": c.Query("to", ""),
|
||||
"logs": formattedLogs,
|
||||
"total": totalLogs,
|
||||
"showing": len(formattedLogs),
|
||||
"page": page,
|
||||
"totalPages": totalPages,
|
||||
"categoryParam": category,
|
||||
"typeParam": c.Query("type", ""),
|
||||
"fromParam": c.Query("from", ""),
|
||||
"toParam": c.Query("to", ""),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -215,27 +214,27 @@ func (h *LogHandler) GetLogs(c *fiber.Ctx) error {
|
||||
func (h *LogHandler) GetLogsAPI(c *fiber.Ctx) error {
|
||||
// Check which logger to use based on the log type parameter
|
||||
logTypeParam := c.Query("log_type", string(LogTypeSystem))
|
||||
|
||||
|
||||
// Parse query parameters
|
||||
category := c.Query("category", "")
|
||||
logItemType := parseLogType(c.Query("type", ""))
|
||||
maxItems := c.QueryInt("max_items", 100)
|
||||
|
||||
|
||||
// Parse time range
|
||||
fromTime := parseTimeParam(c.Query("from", ""))
|
||||
toTime := parseTimeParam(c.Query("to", ""))
|
||||
|
||||
|
||||
// Create search arguments
|
||||
searchArgs := logger.SearchArgs{
|
||||
Category: category,
|
||||
LogType: logItemType,
|
||||
MaxItems: maxItems,
|
||||
Category: category,
|
||||
LogType: logItemType,
|
||||
MaxItems: maxItems,
|
||||
}
|
||||
|
||||
|
||||
if !fromTime.IsZero() {
|
||||
searchArgs.TimestampFrom = &fromTime
|
||||
}
|
||||
|
||||
|
||||
if !toTime.IsZero() {
|
||||
searchArgs.TimestampTo = &toTime
|
||||
}
|
||||
@@ -243,7 +242,7 @@ func (h *LogHandler) GetLogsAPI(c *fiber.Ctx) error {
|
||||
// Variables for logs and error
|
||||
var logs []logger.LogItem
|
||||
var err error
|
||||
|
||||
|
||||
// Check if we want to merge logs from all sources
|
||||
if LogType(logTypeParam) == LogTypeAll {
|
||||
// Get merged logs from all loggers
|
||||
@@ -251,7 +250,7 @@ func (h *LogHandler) GetLogsAPI(c *fiber.Ctx) error {
|
||||
} else {
|
||||
// Select the appropriate logger based on the log type
|
||||
var selectedLogger *logger.Logger
|
||||
|
||||
|
||||
switch LogType(logTypeParam) {
|
||||
case LogTypeService:
|
||||
selectedLogger = h.serviceLogger
|
||||
@@ -262,7 +261,7 @@ func (h *LogHandler) GetLogsAPI(c *fiber.Ctx) error {
|
||||
default:
|
||||
selectedLogger = h.systemLogger
|
||||
}
|
||||
|
||||
|
||||
// Check if the selected logger is properly initialized
|
||||
if selectedLogger == nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
@@ -280,7 +279,7 @@ func (h *LogHandler) GetLogsAPI(c *fiber.Ctx) error {
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// Convert logs to a format suitable for the UI
|
||||
response := make([]fiber.Map, 0, len(logs))
|
||||
for _, log := range logs {
|
||||
@@ -288,7 +287,7 @@ func (h *LogHandler) GetLogsAPI(c *fiber.Ctx) error {
|
||||
if log.LogType == logger.LogTypeError {
|
||||
logTypeStr = "ERROR"
|
||||
}
|
||||
|
||||
|
||||
response = append(response, fiber.Map{
|
||||
"timestamp": log.Timestamp.Format(time.RFC3339),
|
||||
"category": log.Category,
|
||||
@@ -296,9 +295,9 @@ func (h *LogHandler) GetLogsAPI(c *fiber.Ctx) error {
|
||||
"type": logTypeStr,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
"logs": response,
|
||||
"logs": response,
|
||||
"total": len(logs),
|
||||
})
|
||||
}
|
||||
@@ -309,29 +308,29 @@ func (h *LogHandler) GetLogsFragment(c *fiber.Ctx) error {
|
||||
|
||||
// Check which logger to use based on the log type parameter
|
||||
logTypeParam := c.Query("log_type", string(LogTypeSystem))
|
||||
|
||||
|
||||
// Parse query parameters
|
||||
category := c.Query("category", "")
|
||||
logItemType := parseLogType(c.Query("type", ""))
|
||||
maxItems := c.QueryInt("max_items", 100)
|
||||
page := c.QueryInt("page", 1)
|
||||
itemsPerPage := 20 // Default items per page
|
||||
|
||||
|
||||
// Parse time range
|
||||
fromTime := parseTimeParam(c.Query("from", ""))
|
||||
toTime := parseTimeParam(c.Query("to", ""))
|
||||
|
||||
|
||||
// Create search arguments
|
||||
searchArgs := logger.SearchArgs{
|
||||
Category: category,
|
||||
LogType: logItemType,
|
||||
MaxItems: maxItems,
|
||||
Category: category,
|
||||
LogType: logItemType,
|
||||
MaxItems: maxItems,
|
||||
}
|
||||
|
||||
|
||||
if !fromTime.IsZero() {
|
||||
searchArgs.TimestampFrom = &fromTime
|
||||
}
|
||||
|
||||
|
||||
if !toTime.IsZero() {
|
||||
searchArgs.TimestampTo = &toTime
|
||||
}
|
||||
@@ -340,7 +339,7 @@ func (h *LogHandler) GetLogsFragment(c *fiber.Ctx) error {
|
||||
var logs []logger.LogItem
|
||||
var err error
|
||||
var logTypeTitle string
|
||||
|
||||
|
||||
// Check if we want to merge logs from all sources
|
||||
if LogType(logTypeParam) == LogTypeAll {
|
||||
// Get merged logs from all loggers
|
||||
@@ -349,7 +348,7 @@ func (h *LogHandler) GetLogsFragment(c *fiber.Ctx) error {
|
||||
} else {
|
||||
// Select the appropriate logger based on the log type
|
||||
var selectedLogger *logger.Logger
|
||||
|
||||
|
||||
switch LogType(logTypeParam) {
|
||||
case LogTypeService:
|
||||
selectedLogger = h.serviceLogger
|
||||
@@ -364,13 +363,13 @@ func (h *LogHandler) GetLogsFragment(c *fiber.Ctx) error {
|
||||
selectedLogger = h.systemLogger
|
||||
logTypeTitle = "System Logs"
|
||||
}
|
||||
|
||||
|
||||
// Check if the selected logger is properly initialized
|
||||
if selectedLogger == nil {
|
||||
return c.Render("admin/system/logs_fragment", fiber.Map{
|
||||
"title": logTypeTitle,
|
||||
"error": "Logger not initialized",
|
||||
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
|
||||
"title": logTypeTitle,
|
||||
"error": "Logger not initialized",
|
||||
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
|
||||
"selectedLogType": logTypeParam,
|
||||
})
|
||||
}
|
||||
@@ -382,24 +381,24 @@ func (h *LogHandler) GetLogsFragment(c *fiber.Ctx) error {
|
||||
// Handle search error
|
||||
if err != nil {
|
||||
return c.Render("admin/system/logs_fragment", fiber.Map{
|
||||
"title": logTypeTitle,
|
||||
"error": err.Error(),
|
||||
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
|
||||
"title": logTypeTitle,
|
||||
"error": err.Error(),
|
||||
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
|
||||
"selectedLogType": logTypeParam,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// Calculate total pages
|
||||
totalLogs := len(logs)
|
||||
totalPages := (totalLogs + itemsPerPage - 1) / itemsPerPage
|
||||
|
||||
|
||||
// Apply pagination
|
||||
startIndex := (page - 1) * itemsPerPage
|
||||
endIndex := startIndex + itemsPerPage
|
||||
if endIndex > totalLogs {
|
||||
endIndex = totalLogs
|
||||
}
|
||||
|
||||
|
||||
// Slice logs for current page
|
||||
pagedLogs := logs
|
||||
if startIndex < totalLogs {
|
||||
@@ -407,7 +406,7 @@ func (h *LogHandler) GetLogsFragment(c *fiber.Ctx) error {
|
||||
} else {
|
||||
pagedLogs = []logger.LogItem{}
|
||||
}
|
||||
|
||||
|
||||
// Convert logs to a format suitable for the UI
|
||||
formattedLogs := make([]fiber.Map, 0, len(pagedLogs))
|
||||
for _, log := range pagedLogs {
|
||||
@@ -417,7 +416,7 @@ func (h *LogHandler) GetLogsFragment(c *fiber.Ctx) error {
|
||||
logTypeStr = "ERROR"
|
||||
logTypeClass = "log-error"
|
||||
}
|
||||
|
||||
|
||||
formattedLogs = append(formattedLogs, fiber.Map{
|
||||
"timestamp": log.Timestamp.Format("2006-01-02T15:04:05"),
|
||||
"category": log.Category,
|
||||
@@ -426,18 +425,18 @@ func (h *LogHandler) GetLogsFragment(c *fiber.Ctx) error {
|
||||
"typeClass": logTypeClass,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// Set layout to empty to disable the layout for fragment responses
|
||||
return c.Render("admin/system/logs_fragment", fiber.Map{
|
||||
"title": logTypeTitle,
|
||||
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
|
||||
"title": logTypeTitle,
|
||||
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
|
||||
"selectedLogType": logTypeParam,
|
||||
"logs": formattedLogs,
|
||||
"total": totalLogs,
|
||||
"showing": len(formattedLogs),
|
||||
"page": page,
|
||||
"totalPages": totalPages,
|
||||
"layout": "", // Disable layout for partial template
|
||||
"logs": formattedLogs,
|
||||
"total": totalLogs,
|
||||
"showing": len(formattedLogs),
|
||||
"page": page,
|
||||
"totalPages": totalPages,
|
||||
"layout": "", // Disable layout for partial template
|
||||
})
|
||||
}
|
||||
|
||||
@@ -458,12 +457,12 @@ func parseTimeParam(timeStr string) time.Time {
|
||||
if timeStr == "" {
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
|
||||
t, err := time.Parse(time.RFC3339, timeStr)
|
||||
if err != nil {
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
@@ -471,10 +470,10 @@ func parseTimeParam(timeStr string) time.Time {
|
||||
func (h *LogHandler) getMergedLogs(args logger.SearchArgs) ([]logger.LogItem, error) {
|
||||
// Create a slice to hold all logs
|
||||
allLogs := make([]logger.LogItem, 0)
|
||||
|
||||
|
||||
// Create a map to track errors
|
||||
errors := make(map[string]error)
|
||||
|
||||
|
||||
// Get logs from system logger if available
|
||||
if h.systemLogger != nil {
|
||||
systemLogs, err := h.systemLogger.Search(args)
|
||||
@@ -488,7 +487,7 @@ func (h *LogHandler) getMergedLogs(args logger.SearchArgs) ([]logger.LogItem, er
|
||||
allLogs = append(allLogs, systemLogs...)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Get logs from service logger if available
|
||||
if h.serviceLogger != nil {
|
||||
serviceLogs, err := h.serviceLogger.Search(args)
|
||||
@@ -502,7 +501,7 @@ func (h *LogHandler) getMergedLogs(args logger.SearchArgs) ([]logger.LogItem, er
|
||||
allLogs = append(allLogs, serviceLogs...)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Get logs from job logger if available
|
||||
if h.jobLogger != nil {
|
||||
jobLogs, err := h.jobLogger.Search(args)
|
||||
@@ -516,7 +515,7 @@ func (h *LogHandler) getMergedLogs(args logger.SearchArgs) ([]logger.LogItem, er
|
||||
allLogs = append(allLogs, jobLogs...)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Get logs from process logger if available
|
||||
if h.processLogger != nil {
|
||||
processLogs, err := h.processLogger.Search(args)
|
||||
@@ -530,7 +529,7 @@ func (h *LogHandler) getMergedLogs(args logger.SearchArgs) ([]logger.LogItem, er
|
||||
allLogs = append(allLogs, processLogs...)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check if we have any logs
|
||||
if len(allLogs) == 0 && len(errors) > 0 {
|
||||
// Combine error messages
|
||||
@@ -540,16 +539,16 @@ func (h *LogHandler) getMergedLogs(args logger.SearchArgs) ([]logger.LogItem, er
|
||||
}
|
||||
return nil, fmt.Errorf("failed to retrieve logs: %s", strings.Join(errorMsgs, "; "))
|
||||
}
|
||||
|
||||
|
||||
// Sort logs by timestamp (newest first)
|
||||
sort.Slice(allLogs, func(i, j int) bool {
|
||||
return allLogs[i].Timestamp.After(allLogs[j].Timestamp)
|
||||
})
|
||||
|
||||
|
||||
// Apply max items limit if specified
|
||||
if args.MaxItems > 0 && len(allLogs) > args.MaxItems {
|
||||
allLogs = allLogs[:args.MaxItems]
|
||||
}
|
||||
|
||||
|
||||
return allLogs, nil
|
||||
}
|
||||
|
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/system/stats"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/system/stats"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
@@ -43,8 +43,8 @@ func (h *ProcessHandler) GetProcessStatsJSON(c *fiber.Ctx) error {
|
||||
|
||||
// Convert to fiber.Map for JSON response
|
||||
response := fiber.Map{
|
||||
"total": processData.Total,
|
||||
"filtered": processData.Filtered,
|
||||
"total": processData.Total,
|
||||
"filtered": processData.Filtered,
|
||||
"timestamp": time.Now().Unix(),
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ func (h *ProcessHandler) GetProcessStatsJSON(c *fiber.Ctx) error {
|
||||
"is_current": proc.IsCurrent,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
response["processes"] = processes
|
||||
|
||||
// Return JSON response
|
||||
@@ -127,8 +127,8 @@ func (h *ProcessHandler) GetProcessesData(c *fiber.Ctx) error {
|
||||
// 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": "",
|
||||
"error": "System error: Stats manager not initialized",
|
||||
"layout": "",
|
||||
})
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ func (h *ProcessHandler) GetProcessesData(c *fiber.Ctx) error {
|
||||
} else {
|
||||
processData, err = h.statsManager.GetProcessStatsFresh(0)
|
||||
}
|
||||
|
||||
|
||||
if err != nil {
|
||||
// Handle AJAX requests differently from regular requests
|
||||
isAjax := c.Get("X-Requested-With") == "XMLHttpRequest"
|
||||
@@ -165,8 +165,8 @@ func (h *ProcessHandler) GetProcessesData(c *fiber.Ctx) 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": "",
|
||||
"error": "Failed to get process data: " + err.Error(),
|
||||
"layout": "",
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -197,9 +197,7 @@ func (h *ProcessHandler) GetProcessesData(c *fiber.Ctx) error {
|
||||
"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)
|
||||
}
|
||||
|
||||
|
||||
|
@@ -4,8 +4,8 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces/openrpc"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces/openrpc"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
|
@@ -5,7 +5,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/system/stats"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/system/stats"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/shirou/gopsutil/v3/host"
|
||||
)
|
||||
@@ -335,7 +335,7 @@ func (h *SystemHandler) GetProcessStatsAPI(c *fiber.Ctx) error {
|
||||
"is_current": proc.IsCurrent,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
response["processes"] = processes
|
||||
|
||||
// Return JSON response
|
||||
|
@@ -7,8 +7,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroagent/handlers"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/system/stats"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroagent/handlers"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/system/stats"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/shirou/gopsutil/v3/host"
|
||||
)
|
||||
@@ -68,12 +68,12 @@ func (h *AdminHandler) RegisterRoutes(app *fiber.App) {
|
||||
// System routes
|
||||
admin.Get("/system/info", h.getSystemInfo)
|
||||
admin.Get("/system/hardware-stats", h.getHardwareStats)
|
||||
|
||||
|
||||
// Create process handler
|
||||
processHandler := handlers.NewProcessHandler(h.statsManager)
|
||||
admin.Get("/system/processes", processHandler.GetProcesses)
|
||||
admin.Get("/system/processes-data", processHandler.GetProcessesData)
|
||||
|
||||
|
||||
// Create log handler
|
||||
// Ensure log directory exists
|
||||
// Using the same shared logs path as process manager
|
||||
@@ -81,7 +81,7 @@ func (h *AdminHandler) RegisterRoutes(app *fiber.App) {
|
||||
if err := os.MkdirAll(logDir, 0755); err != nil {
|
||||
fmt.Printf("Error creating log directory: %v\n", err)
|
||||
}
|
||||
|
||||
|
||||
logHandler, err := handlers.NewLogHandler(logDir)
|
||||
if err != nil {
|
||||
fmt.Printf("Error creating log handler: %v\n", err)
|
||||
@@ -96,11 +96,11 @@ func (h *AdminHandler) RegisterRoutes(app *fiber.App) {
|
||||
// but it now just redirects to the main logs endpoint
|
||||
admin.Get("/system/logs-fragment", logHandler.GetLogsFragment)
|
||||
admin.Get("/system/logs-test", h.getSystemLogsTest) // Keep the test logs route
|
||||
|
||||
|
||||
// Log API endpoints
|
||||
app.Get("/api/logs", logHandler.GetLogsAPI)
|
||||
}
|
||||
|
||||
|
||||
admin.Get("/system/settings", h.getSystemSettings)
|
||||
|
||||
// OpenRPC routes
|
||||
|
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/herojobs"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/herojobs"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
|
@@ -4,14 +4,14 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces/openrpc"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces/openrpc"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
// ServiceHandler handles service-related page routes
|
||||
type ServiceHandler struct {
|
||||
client *openrpc.Client
|
||||
logger *log.Logger
|
||||
client *openrpc.Client
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
// NewServiceHandler creates a new service handler with the provided socket path and secret
|
||||
@@ -90,7 +90,7 @@ func (h *ServiceHandler) getProcessList() ([]ProcessDisplayInfo, error) {
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
// Create a ProcessDisplayInfo from the map
|
||||
displayInfo := ProcessDisplayInfo{
|
||||
ID: fmt.Sprintf("%v", procMap["pid"]),
|
||||
|
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/processmanager"
|
||||
)
|
||||
|
||||
// ProcessDisplayInfo represents information about a process for display purposes
|
||||
@@ -22,7 +22,7 @@ type ProcessDisplayInfo struct {
|
||||
func ConvertToDisplayInfo(info *processmanager.ProcessInfo) ProcessDisplayInfo {
|
||||
// Calculate uptime from start time
|
||||
uptime := formatUptime(time.Since(info.StartTime))
|
||||
|
||||
|
||||
return ProcessDisplayInfo{
|
||||
ID: fmt.Sprintf("%d", info.PID),
|
||||
Name: info.Name,
|
||||
|
@@ -7,8 +7,8 @@ import (
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/data/ourdb"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/tools"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/data/ourdb"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/tools"
|
||||
)
|
||||
|
||||
// JobStatus represents the status of a job
|
||||
|
@@ -6,7 +6,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/tools"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/tools"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
|
@@ -35,7 +35,7 @@ Key features:
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/playbook"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/playbook"
|
||||
)
|
||||
|
||||
// Create a new playbook from HeroScript text
|
||||
|
@@ -7,7 +7,7 @@ import (
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/handlerfactory/herohandler"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/handlerfactory/herohandler"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -24,7 +24,7 @@ func main() {
|
||||
fmt.Printf("Failed to initialize hero handler: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
|
||||
// Get the default instance
|
||||
handler := herohandler.DefaultInstance
|
||||
|
||||
@@ -43,7 +43,7 @@ func main() {
|
||||
tcpAddressStr = *tcpAddress
|
||||
fmt.Printf("TCP address: %s\n", tcpAddressStr)
|
||||
}
|
||||
|
||||
|
||||
err = handler.StartTelnet(socketPathStr, tcpAddressStr)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to start telnet server: %v\n", err)
|
||||
|
@@ -8,7 +8,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/playbook"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/playbook"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@@ -3,8 +3,8 @@ package internal
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/handlerfactory"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/handlers"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/handlerfactory"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/handlers"
|
||||
)
|
||||
|
||||
// ExampleHandler handles example actions
|
||||
|
@@ -7,7 +7,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/cmd/herohandler/internal"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/cmd/herohandler/internal"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -30,7 +30,7 @@ func main() {
|
||||
|
||||
// Get the command from arguments
|
||||
command := strings.Join(os.Args[1:], " ")
|
||||
|
||||
|
||||
// Format as proper HeroScript with !! prefix if not already prefixed
|
||||
script := command
|
||||
if !strings.HasPrefix(script, "!!") {
|
||||
|
@@ -10,7 +10,7 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/handlerfactory/herohandler"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/handlerfactory/herohandler"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -92,7 +92,7 @@ func showSupportedActions() {
|
||||
// We need to implement this function to get supported actions
|
||||
// Since we can't directly access the factory field, we'll use the telnet interface
|
||||
script := "!!core.actions"
|
||||
|
||||
|
||||
// Try TCP first, then Unix socket if TCP fails
|
||||
result, err := Send(script, "localhost:8023", false)
|
||||
if err != nil {
|
||||
@@ -103,7 +103,7 @@ func showSupportedActions() {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fmt.Println("Supported actions by actor:")
|
||||
fmt.Println(result)
|
||||
}
|
||||
@@ -151,7 +151,7 @@ func Send(command string, address string, isUnixSocket bool) (string, error) {
|
||||
return
|
||||
}
|
||||
response.WriteString(line)
|
||||
|
||||
|
||||
// If we've received a complete response, break
|
||||
if strings.Contains(line, "\n") && strings.TrimSpace(line) == "" {
|
||||
break
|
||||
@@ -187,7 +187,7 @@ func runTestScript() {
|
||||
result, err = Send(script, "/tmp/hero.sock", true)
|
||||
if err != nil {
|
||||
fmt.Printf("Unix socket connection failed: %v\n", err)
|
||||
|
||||
|
||||
// We can't directly access the factory field, so we'll just report the error
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
return
|
||||
|
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/playbook"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/playbook"
|
||||
)
|
||||
|
||||
const exampleScript = `
|
||||
|
@@ -16,7 +16,7 @@ The VM handler example shows how to:
|
||||
To run the example:
|
||||
|
||||
```bash
|
||||
cd ~/code/github/freeflowuniverse/heroagent/pkg/handlerfactory/cmd/vmhandler
|
||||
cd ~/code/github/freeflowuniverse/herocode/heroagent/pkg/handlerfactory/cmd/vmhandler
|
||||
go run . tutorial
|
||||
#to run just the server do
|
||||
go run .
|
||||
|
@@ -6,7 +6,7 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/handlerfactory"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/handlerfactory"
|
||||
)
|
||||
|
||||
// runTutorial runs an interactive tutorial demonstrating the VM handler
|
||||
@@ -50,7 +50,7 @@ func runTutorial() {
|
||||
|
||||
// Process heroscript commands
|
||||
fmt.Println("\nStep 5: Process heroscript commands")
|
||||
|
||||
|
||||
// Define a VM
|
||||
defineScript := `!!vm.define name:'tutorial_vm' cpu:2 memory:'4GB' storage:'50GB'
|
||||
description: 'A tutorial VM for demonstration purposes'`
|
||||
|
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/handlerfactory"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/handlerfactory"
|
||||
)
|
||||
|
||||
// VMHandler handles VM-related actions
|
||||
|
@@ -8,7 +8,7 @@ import (
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/handlerfactory"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/handlerfactory"
|
||||
)
|
||||
|
||||
// The tutorial functions are defined in tutorial.go
|
||||
|
@@ -30,7 +30,7 @@ The Handler Factory exposes two interfaces for communication:
|
||||
to get started
|
||||
|
||||
```bash
|
||||
cd /root/code/github/freeflowuniverse/heroagent/pkg/handlerfactory/herohandler/cmd
|
||||
cd /root/code/github/freeflowuniverse/herocode/heroagent/pkg/handlerfactory/herohandler/cmd
|
||||
go run .
|
||||
```
|
||||
|
||||
|
@@ -5,8 +5,8 @@ import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/paramsparser"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/playbook"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/paramsparser"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/playbook"
|
||||
)
|
||||
|
||||
// Handler interface defines methods that all handlers must implement
|
||||
|
@@ -5,7 +5,7 @@ import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/playbook"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/playbook"
|
||||
)
|
||||
|
||||
// HandlerFactory manages a collection of handlers
|
||||
|
@@ -12,7 +12,7 @@ import (
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/playbook"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/playbook"
|
||||
)
|
||||
|
||||
// ANSI color codes for terminal output
|
||||
@@ -43,23 +43,23 @@ type TelnetServer struct {
|
||||
sigCh chan os.Signal
|
||||
onShutdown func()
|
||||
// Map to store client preferences (like json formatting)
|
||||
clientPrefs map[net.Conn]map[string]bool
|
||||
prefsMutex sync.RWMutex
|
||||
clientPrefs map[net.Conn]map[string]bool
|
||||
prefsMutex sync.RWMutex
|
||||
}
|
||||
|
||||
// NewTelnetServer creates a new telnet server
|
||||
func NewTelnetServer(factory *HandlerFactory, secrets ...string) *TelnetServer {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
return &TelnetServer{
|
||||
factory: factory,
|
||||
secrets: secrets,
|
||||
clients: make(map[net.Conn]bool),
|
||||
factory: factory,
|
||||
secrets: secrets,
|
||||
clients: make(map[net.Conn]bool),
|
||||
clientPrefs: make(map[net.Conn]map[string]bool),
|
||||
running: false,
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
sigCh: make(chan os.Signal, 1),
|
||||
onShutdown: func() {},
|
||||
running: false,
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
sigCh: make(chan os.Signal, 1),
|
||||
onShutdown: func() {},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +205,7 @@ func (ts *TelnetServer) handleConnection(conn net.Conn) {
|
||||
ts.clientsMutex.Lock()
|
||||
ts.clients[conn] = false
|
||||
ts.clientsMutex.Unlock()
|
||||
|
||||
|
||||
// Initialize client preferences
|
||||
ts.prefsMutex.Lock()
|
||||
ts.clientPrefs[conn] = make(map[string]bool)
|
||||
@@ -284,7 +284,7 @@ func (ts *TelnetServer) handleConnection(conn net.Conn) {
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
// Handle JSON format toggle
|
||||
if line == "!!json" {
|
||||
ts.prefsMutex.Lock()
|
||||
@@ -293,12 +293,12 @@ func (ts *TelnetServer) handleConnection(conn net.Conn) {
|
||||
prefs = make(map[string]bool)
|
||||
ts.clientPrefs[conn] = prefs
|
||||
}
|
||||
|
||||
|
||||
// Toggle JSON format preference
|
||||
currentSetting := prefs["json"]
|
||||
prefs["json"] = !currentSetting
|
||||
ts.prefsMutex.Unlock()
|
||||
|
||||
|
||||
if prefs["json"] {
|
||||
conn.Write([]byte("JSON format will be automatically added to all heroscripts.\n"))
|
||||
} else {
|
||||
@@ -416,7 +416,7 @@ func (ts *TelnetServer) executeHeroscript(script string, conn net.Conn, interact
|
||||
ts.prefsMutex.RLock()
|
||||
prefs, exists := ts.clientPrefs[conn]
|
||||
ts.prefsMutex.RUnlock()
|
||||
|
||||
|
||||
if exists && prefs["json"] {
|
||||
// Add format:json if not already present
|
||||
if !strings.Contains(script, "format:json") {
|
||||
@@ -424,7 +424,7 @@ func (ts *TelnetServer) executeHeroscript(script string, conn net.Conn, interact
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if interactive {
|
||||
// Format the script with colors
|
||||
formattedScript := formatHeroscript(script)
|
||||
@@ -466,8 +466,6 @@ func (ts *TelnetServer) addJsonFormat(script string) string {
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
|
||||
|
||||
|
||||
// formatHeroscript formats heroscript with colors for console output only
|
||||
// This is not used for telnet responses, only for server-side logging
|
||||
func formatHeroscript(script string) string {
|
||||
@@ -611,12 +609,12 @@ func (ts *TelnetServer) generateHelpText(interactive bool) string {
|
||||
// Try to call the Help method on each handler using reflection
|
||||
handlerValue := reflect.ValueOf(handler)
|
||||
helpMethod := handlerValue.MethodByName("Help")
|
||||
|
||||
|
||||
if helpMethod.IsValid() {
|
||||
// Call the Help method
|
||||
args := []reflect.Value{reflect.ValueOf("")}
|
||||
result := helpMethod.Call(args)
|
||||
|
||||
|
||||
// Get the result
|
||||
if len(result) > 0 && result[0].Kind() == reflect.String {
|
||||
helpText := result[0].String()
|
||||
|
@@ -3,7 +3,7 @@ package handlers
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/handlerfactory/core"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/handlerfactory/core"
|
||||
)
|
||||
|
||||
// AuthHandler handles authentication actions
|
||||
|
@@ -5,9 +5,9 @@ import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/handlerfactory/core"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/paramsparser"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/playbook"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/handlerfactory/core"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/paramsparser"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/playbook"
|
||||
)
|
||||
|
||||
// BaseHandler provides common functionality for all handlers
|
||||
|
@@ -4,8 +4,8 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/handlerfactory/core"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/playbook"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/handlerfactory/core"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/playbook"
|
||||
)
|
||||
|
||||
// HandlerFactory manages a collection of handlers for processing HeroScript commands
|
||||
|
@@ -1,7 +1,7 @@
|
||||
package herohandler
|
||||
|
||||
import (
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/handlerfactory/core"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/handlerfactory/core"
|
||||
)
|
||||
|
||||
// GetFactory returns the handler factory
|
||||
|
@@ -4,7 +4,7 @@ import (
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/handlerfactory/herohandler"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/handlerfactory/herohandler"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@@ -4,10 +4,10 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/handlerfactory/core"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/handlerfactory/core"
|
||||
|
||||
// "github.com/freeflowuniverse/heroagent/pkg/handlerfactory/heroscript/handlerfactory/fakehandler"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/handlerfactory/processmanagerhandler"
|
||||
// "git.ourworld.tf/herocode/heroagent/pkg/handlerfactory/heroscript/handlerfactory/fakehandler"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/handlerfactory/processmanagerhandler"
|
||||
)
|
||||
|
||||
// HeroHandler is the main handler factory that manages all registered handlers
|
||||
|
@@ -3,7 +3,7 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/playbook"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/playbook"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@@ -3,8 +3,8 @@ package processmanagerhandler
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/handlerfactory/core"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/handlerfactory/core"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/processmanager"
|
||||
)
|
||||
|
||||
// ProcessManagerHandler handles process manager-related actions
|
||||
|
@@ -19,7 +19,7 @@ A Go package for parsing and manipulating parameters from text in a key-value fo
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/freeflowuniverse/heroagent/pkg/paramsparser"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/paramsparser"
|
||||
)
|
||||
|
||||
// Create a new parser
|
||||
|
@@ -4,7 +4,7 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/paramsparser"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/paramsparser"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@@ -9,7 +9,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/tools"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/tools"
|
||||
)
|
||||
|
||||
// ParamsParser represents a parameter parser that can handle various parameter sources
|
||||
@@ -32,12 +32,12 @@ func New() *ParamsParser {
|
||||
func (p *ParamsParser) Parse(input string) error {
|
||||
// Normalize line endings
|
||||
input = strings.ReplaceAll(input, "\r\n", "\n")
|
||||
|
||||
|
||||
// Track the current state
|
||||
var currentKey string
|
||||
var currentValue strings.Builder
|
||||
var inMultilineString bool
|
||||
|
||||
|
||||
// Process each line
|
||||
lines := strings.Split(input, "\n")
|
||||
for i := 0; i < len(lines); i++ {
|
||||
@@ -48,12 +48,12 @@ func (p *ParamsParser) Parse(input string) error {
|
||||
} else {
|
||||
line = lines[i]
|
||||
}
|
||||
|
||||
|
||||
// Skip empty lines unless we're in a multiline string
|
||||
if line == "" && !inMultilineString {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
// If we're in a multiline string
|
||||
if inMultilineString {
|
||||
// Check if this line ends the multiline string
|
||||
@@ -71,7 +71,7 @@ func (p *ParamsParser) Parse(input string) error {
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
// Process the line to extract key-value pairs
|
||||
var processedPos int
|
||||
for processedPos < len(line) {
|
||||
@@ -79,62 +79,62 @@ func (p *ParamsParser) Parse(input string) error {
|
||||
for processedPos < len(line) && (line[processedPos] == ' ' || line[processedPos] == '\t') {
|
||||
processedPos++
|
||||
}
|
||||
|
||||
|
||||
if processedPos >= len(line) {
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
// Find the next key by looking for a colon
|
||||
keyStart := processedPos
|
||||
colonPos := -1
|
||||
|
||||
|
||||
for j := processedPos; j < len(line); j++ {
|
||||
if line[j] == ':' {
|
||||
colonPos = j
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if colonPos == -1 {
|
||||
// No colon found, skip this part
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
// Extract key and use NameFix to standardize it
|
||||
rawKey := strings.TrimSpace(line[keyStart:colonPos])
|
||||
key := tools.NameFix(rawKey)
|
||||
|
||||
|
||||
if key == "" {
|
||||
// Invalid key, move past the colon and continue
|
||||
processedPos = colonPos + 1
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
// Move position past the colon
|
||||
processedPos = colonPos + 1
|
||||
|
||||
|
||||
if processedPos >= len(line) {
|
||||
// End of line reached, store empty value
|
||||
p.params[key] = ""
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
// Skip whitespace after the colon
|
||||
for processedPos < len(line) && (line[processedPos] == ' ' || line[processedPos] == '\t') {
|
||||
processedPos++
|
||||
}
|
||||
|
||||
|
||||
if processedPos >= len(line) {
|
||||
// End of line reached after whitespace, store empty value
|
||||
p.params[key] = ""
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
// Check if the value is quoted
|
||||
if line[processedPos] == '\'' {
|
||||
// This is a quoted string
|
||||
processedPos++ // Skip the opening quote
|
||||
|
||||
|
||||
// Look for the closing quote
|
||||
quoteEnd := -1
|
||||
for j := processedPos; j < len(line); j++ {
|
||||
@@ -144,7 +144,7 @@ func (p *ParamsParser) Parse(input string) error {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if quoteEnd != -1 {
|
||||
// Single-line quoted string
|
||||
value := line[processedPos:quoteEnd]
|
||||
@@ -167,12 +167,12 @@ func (p *ParamsParser) Parse(input string) error {
|
||||
// This is an unquoted value
|
||||
valueStart := processedPos
|
||||
valueEnd := valueStart
|
||||
|
||||
|
||||
// Find the end of the value (space or end of line)
|
||||
for valueEnd < len(line) && line[valueEnd] != ' ' && line[valueEnd] != '\t' {
|
||||
valueEnd++
|
||||
}
|
||||
|
||||
|
||||
value := line[valueStart:valueEnd]
|
||||
// For unquoted values, use NameFix to standardize them
|
||||
// This handles the 'without' keyword and other special cases
|
||||
@@ -181,12 +181,12 @@ func (p *ParamsParser) Parse(input string) error {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If we're still in a multiline string at the end, that's an error
|
||||
if inMultilineString {
|
||||
return errors.New("unterminated multiline string")
|
||||
}
|
||||
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -196,7 +196,7 @@ func (p *ParamsParser) Parse(input string) error {
|
||||
func (p *ParamsParser) ParseString(input string) error {
|
||||
// Trim the input
|
||||
input = strings.TrimSpace(input)
|
||||
|
||||
|
||||
// Process the input to extract key-value pairs
|
||||
var processedPos int
|
||||
for processedPos < len(input) {
|
||||
@@ -204,62 +204,62 @@ func (p *ParamsParser) ParseString(input string) error {
|
||||
for processedPos < len(input) && (input[processedPos] == ' ' || input[processedPos] == '\t') {
|
||||
processedPos++
|
||||
}
|
||||
|
||||
|
||||
if processedPos >= len(input) {
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
// Find the next key by looking for a colon
|
||||
keyStart := processedPos
|
||||
colonPos := -1
|
||||
|
||||
|
||||
for j := processedPos; j < len(input); j++ {
|
||||
if input[j] == ':' {
|
||||
colonPos = j
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if colonPos == -1 {
|
||||
// No colon found, skip this part
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
// Extract key and use NameFix to standardize it
|
||||
rawKey := strings.TrimSpace(input[keyStart:colonPos])
|
||||
key := tools.NameFix(rawKey)
|
||||
|
||||
|
||||
if key == "" {
|
||||
// Invalid key, move past the colon and continue
|
||||
processedPos = colonPos + 1
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
// Move position past the colon
|
||||
processedPos = colonPos + 1
|
||||
|
||||
|
||||
if processedPos >= len(input) {
|
||||
// End of input reached, store empty value
|
||||
p.params[key] = ""
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
// Skip whitespace after the colon
|
||||
for processedPos < len(input) && (input[processedPos] == ' ' || input[processedPos] == '\t') {
|
||||
processedPos++
|
||||
}
|
||||
|
||||
|
||||
if processedPos >= len(input) {
|
||||
// End of input reached after whitespace, store empty value
|
||||
p.params[key] = ""
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
// Check if the value is quoted
|
||||
if input[processedPos] == '\'' {
|
||||
// This is a quoted string
|
||||
processedPos++ // Skip the opening quote
|
||||
|
||||
|
||||
// Look for the closing quote
|
||||
quoteEnd := -1
|
||||
for j := processedPos; j < len(input); j++ {
|
||||
@@ -269,11 +269,11 @@ func (p *ParamsParser) ParseString(input string) error {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if quoteEnd == -1 {
|
||||
return errors.New("unterminated quoted string")
|
||||
}
|
||||
|
||||
|
||||
value := input[processedPos:quoteEnd]
|
||||
// For quoted values in ParseString, we can apply NameFix
|
||||
// since this method doesn't handle multiline strings
|
||||
@@ -286,12 +286,12 @@ func (p *ParamsParser) ParseString(input string) error {
|
||||
// This is an unquoted value
|
||||
valueStart := processedPos
|
||||
valueEnd := valueStart
|
||||
|
||||
|
||||
// Find the end of the value (space or end of input)
|
||||
for valueEnd < len(input) && input[valueEnd] != ' ' && input[valueEnd] != '\t' {
|
||||
valueEnd++
|
||||
}
|
||||
|
||||
|
||||
value := input[valueStart:valueEnd]
|
||||
// For unquoted values, use NameFix to standardize them
|
||||
// This handles the 'without' keyword and other special cases
|
||||
@@ -299,7 +299,7 @@ func (p *ParamsParser) ParseString(input string) error {
|
||||
processedPos = valueEnd
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -364,7 +364,7 @@ func (p *ParamsParser) GetBool(key string) bool {
|
||||
if value == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
// Check for common boolean string representations
|
||||
value = strings.ToLower(value)
|
||||
return value == "true" || value == "yes" || value == "1" || value == "on"
|
||||
@@ -405,17 +405,17 @@ func (p *ParamsParser) Has(key string) bool {
|
||||
// GetAll returns all parameters as a map
|
||||
func (p *ParamsParser) GetAll() map[string]string {
|
||||
result := make(map[string]string)
|
||||
|
||||
|
||||
// First add defaults
|
||||
for k, v := range p.defaultParams {
|
||||
result[k] = v
|
||||
}
|
||||
|
||||
|
||||
// Then override with actual params
|
||||
for k, v := range p.params {
|
||||
result[k] = v
|
||||
}
|
||||
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
|
@@ -3,8 +3,8 @@ package playbook
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/paramsparser"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/tools"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/paramsparser"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/tools"
|
||||
)
|
||||
|
||||
// State represents the parser state
|
||||
|
@@ -7,7 +7,7 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/paramsparser"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/paramsparser"
|
||||
)
|
||||
|
||||
// ActionType represents the type of action
|
||||
|
@@ -11,7 +11,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroservices/billing/models"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroservices/billing/models"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@@ -7,9 +7,9 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/data/ourdb"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/data/radixtree"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/tools"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/data/ourdb"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/data/radixtree"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/tools"
|
||||
)
|
||||
|
||||
// DBStore represents the central database store for all models
|
||||
|
@@ -9,8 +9,7 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
openaiproxy "github.com/freeflowuniverse/heroagent/pkg/heroservices/openaiproxy"
|
||||
"github.com/openai/openai-go"
|
||||
openaiproxy "git.ourworld.tf/herocode/heroagent/pkg/heroservices/openaiproxy"
|
||||
"github.com/openai/openai-go/option"
|
||||
)
|
||||
|
||||
|
@@ -10,7 +10,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/jobsmanager"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/jobsmanager"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/logger"
|
||||
)
|
||||
|
@@ -6,7 +6,7 @@ import (
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/logger"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/logger"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@@ -5,8 +5,8 @@ import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces/openrpc"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces/openrpc"
|
||||
)
|
||||
|
||||
// RunClientExample runs a complete example of using the process manager OpenRPC client
|
||||
@@ -39,10 +39,10 @@ func RunClientExample(socketPath, secret string) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list processes: %w", err)
|
||||
}
|
||||
|
||||
|
||||
// For simplicity in this example, just log that we got a response
|
||||
log.Printf("Got process list response: %T", processList)
|
||||
|
||||
|
||||
// Try to handle the response in a more robust way
|
||||
switch v := processList.(type) {
|
||||
case []interface{}:
|
||||
|
@@ -7,7 +7,7 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces/openrpc"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces/openrpc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@@ -6,8 +6,8 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/processmanager"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces"
|
||||
)
|
||||
|
||||
// MockProcessManager implements the interfaces.ProcessManagerInterface for testing purposes
|
||||
|
@@ -4,8 +4,8 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/openrpcmanager/client"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/openrpcmanager/client"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces"
|
||||
)
|
||||
|
||||
// Client provides a client for interacting with process manager operations via RPC
|
||||
|
@@ -4,9 +4,9 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/openrpcmanager"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/openrpcmanager"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/processmanager"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces"
|
||||
)
|
||||
|
||||
// Handler implements the OpenRPC handlers for process manager operations
|
||||
|
@@ -6,8 +6,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/processmanager"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
@@ -7,7 +7,7 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/openrpcmanager"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/openrpcmanager"
|
||||
)
|
||||
|
||||
// LoadSchema loads the OpenRPC schema from the embedded JSON file
|
||||
|
@@ -6,8 +6,8 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/openrpcmanager"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/openrpcmanager"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces"
|
||||
)
|
||||
|
||||
// Server represents the Process Manager OpenRPC server
|
||||
|
@@ -3,7 +3,7 @@ package interfaces
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/processmanager"
|
||||
)
|
||||
|
||||
// ProcessManagerInterface defines the interface for process management operations
|
||||
|
@@ -14,7 +14,7 @@ import (
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/logger"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/logger"
|
||||
"github.com/shirou/gopsutil/v3/process"
|
||||
)
|
||||
|
||||
|
@@ -24,7 +24,7 @@ The server implements the following Redis commands:
|
||||
### Basic Usage
|
||||
|
||||
```go
|
||||
import "github.com/freeflowuniverse/heroagent/pkg/redisserver"
|
||||
import "git.ourworld.tf/herocode/heroagent/pkg/redisserver"
|
||||
|
||||
// Create a new server with default configuration
|
||||
server := redisserver.NewServer(redisserver.ServerConfig{
|
||||
|
@@ -10,7 +10,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/servers/redisserver"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/servers/redisserver"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
|
@@ -10,7 +10,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/servers/redisserver"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/servers/redisserver"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
|
@@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/system/builders/hetznerinstall"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/system/builders/hetznerinstall"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@@ -6,10 +6,10 @@ import (
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/system/builders/postgresql/dependencies"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/system/builders/postgresql/gosp"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/system/builders/postgresql/postgres"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/system/builders/postgresql/verification"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/system/builders/postgresql/dependencies"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/system/builders/postgresql/gosp"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/system/builders/postgresql/postgres"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/system/builders/postgresql/verification"
|
||||
)
|
||||
|
||||
// Constants for PostgreSQL installation
|
||||
|
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/system/builders/postgresql"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/system/builders/postgresql"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@@ -6,7 +6,7 @@ import (
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/system/builders/postgresql/postgres"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/system/builders/postgresql/postgres"
|
||||
)
|
||||
|
||||
// Constants for Go stored procedure
|
||||
@@ -46,10 +46,10 @@ func (b *GoSPBuilder) run(cmd string, args ...string) error {
|
||||
fmt.Println("Running:", cmd, args)
|
||||
c := exec.Command(cmd, args...)
|
||||
// Set environment variables
|
||||
c.Env = append(os.Environ(),
|
||||
c.Env = append(os.Environ(),
|
||||
"GOROOT=/usr/local/go",
|
||||
"GOPATH=/root/go",
|
||||
"PATH=/usr/local/go/bin:" + os.Getenv("PATH"))
|
||||
"GOPATH=/root/go",
|
||||
"PATH=/usr/local/go/bin:"+os.Getenv("PATH"))
|
||||
c.Stdout = os.Stdout
|
||||
c.Stderr = os.Stderr
|
||||
return c.Run()
|
||||
@@ -58,7 +58,7 @@ func (b *GoSPBuilder) run(cmd string, args ...string) error {
|
||||
// Build builds a Go stored procedure
|
||||
func (b *GoSPBuilder) Build() error {
|
||||
fmt.Println("Building Go stored procedure...")
|
||||
|
||||
|
||||
// Use the explicitly provided Go path if available
|
||||
var goExePath string
|
||||
if b.GoPath != "" {
|
||||
@@ -74,7 +74,7 @@ func (b *GoSPBuilder) Build() error {
|
||||
}
|
||||
fmt.Printf("Using detected Go executable from: %s\n", goExePath)
|
||||
}
|
||||
|
||||
|
||||
if err := os.MkdirAll(b.GoSharedLibDir, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create directory: %w", err)
|
||||
}
|
||||
@@ -98,27 +98,27 @@ func main() {}
|
||||
|
||||
// Use the full path to Go rather than relying on PATH
|
||||
fmt.Println("Running Go build with full path:", goExePath)
|
||||
|
||||
|
||||
// Show debug information
|
||||
fmt.Println("Environment variables that will be set:")
|
||||
fmt.Println(" GOROOT=/usr/local/go")
|
||||
fmt.Println(" GOPATH=/root/go")
|
||||
fmt.Println(" PATH=/usr/local/go/bin:" + os.Getenv("PATH"))
|
||||
|
||||
|
||||
// Verify that the Go executable exists before using it
|
||||
if _, err := os.Stat(goExePath); err != nil {
|
||||
return fmt.Errorf("Go executable not found at %s: %w", goExePath, err)
|
||||
}
|
||||
|
||||
|
||||
// Create the output directory if it doesn't exist
|
||||
outputDir := filepath.Join(b.InstallPrefix, "lib")
|
||||
if err := os.MkdirAll(outputDir, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create output directory %s: %w", outputDir, err)
|
||||
}
|
||||
|
||||
|
||||
// Prepare output path
|
||||
outputPath := filepath.Join(outputDir, "libgosp.so")
|
||||
|
||||
|
||||
// Instead of relying on environment variables, create a wrapper shell script
|
||||
// that sets all required environment variables and then calls the Go executable
|
||||
tempDir, err := os.MkdirTemp("", "go-build-")
|
||||
@@ -126,7 +126,7 @@ func main() {}
|
||||
return fmt.Errorf("failed to create temp directory: %w", err)
|
||||
}
|
||||
defer os.RemoveAll(tempDir) // Clean up when done
|
||||
|
||||
|
||||
goRoot := filepath.Dir(filepath.Dir(goExePath)) // /usr/local/go
|
||||
wrapperScript := filepath.Join(tempDir, "go-wrapper.sh")
|
||||
wrapperContent := fmt.Sprintf(`#!/bin/sh
|
||||
@@ -143,25 +143,25 @@ echo "PATH=$PATH"
|
||||
echo "=== Running Go command ==="
|
||||
echo "%s $@"
|
||||
exec %s "$@"
|
||||
`,
|
||||
goRoot,
|
||||
`,
|
||||
goRoot,
|
||||
filepath.Dir(goExePath),
|
||||
goExePath,
|
||||
goExePath)
|
||||
|
||||
|
||||
// Write the wrapper script
|
||||
if err := os.WriteFile(wrapperScript, []byte(wrapperContent), 0755); err != nil {
|
||||
return fmt.Errorf("failed to write wrapper script: %w", err)
|
||||
}
|
||||
|
||||
|
||||
fmt.Printf("Created wrapper script at %s\n", wrapperScript)
|
||||
|
||||
|
||||
// Use the wrapper script to build the Go shared library
|
||||
cmd := exec.Command(wrapperScript, "build", "-buildmode=c-shared", "-o", outputPath, libPath)
|
||||
cmd.Dir = filepath.Dir(libPath) // Set working directory to where the source file is
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
|
||||
fmt.Printf("Executing Go build via wrapper script\n")
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("failed to build Go stored procedure: %w", err)
|
||||
|
@@ -8,7 +8,7 @@ import (
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/mholt/archiver/v3"
|
||||
"github.com/mholt/archiver/v4"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -51,14 +51,14 @@ func (g *GoInstaller) GetGoVersion() (string, error) {
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get Go version: %w", err)
|
||||
}
|
||||
|
||||
|
||||
// Parse go version output (format: "go version go1.x.x ...")
|
||||
version := strings.TrimSpace(string(output))
|
||||
parts := strings.Split(version, " ")
|
||||
if len(parts) < 3 {
|
||||
return "", fmt.Errorf("unexpected go version output format: %s", version)
|
||||
}
|
||||
|
||||
|
||||
// Return just the version number without the "go" prefix
|
||||
return strings.TrimPrefix(parts[2], "go"), nil
|
||||
}
|
||||
@@ -77,7 +77,7 @@ func (g *GoInstaller) InstallGo() (string, error) {
|
||||
// Default Go installation location
|
||||
var installDir string = "/usr/local"
|
||||
var goExePath string = filepath.Join(installDir, "go", "bin", "go")
|
||||
|
||||
|
||||
// Check if Go is already installed by checking the binary directly
|
||||
if _, err := os.Stat(goExePath); err == nil {
|
||||
version, err := g.GetGoVersion()
|
||||
@@ -86,7 +86,7 @@ func (g *GoInstaller) InstallGo() (string, error) {
|
||||
return goExePath, nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Also check if Go is available in PATH as a fallback
|
||||
if g.IsGoInstalled() {
|
||||
path, err := exec.LookPath("go")
|
||||
@@ -98,31 +98,31 @@ func (g *GoInstaller) InstallGo() (string, error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fmt.Printf("Installing Go version %s...\n", g.Version)
|
||||
|
||||
|
||||
// Determine architecture and OS
|
||||
goOS := runtime.GOOS
|
||||
goArch := runtime.GOARCH
|
||||
|
||||
|
||||
// Construct download URL
|
||||
downloadURL := fmt.Sprintf("https://golang.org/dl/go%s.%s-%s.tar.gz", g.Version, goOS, goArch)
|
||||
|
||||
|
||||
// Create a temporary directory for download
|
||||
tempDir, err := os.MkdirTemp("", "go-install-")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create temporary directory: %w", err)
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
|
||||
// Download Go tarball
|
||||
tarballPath := filepath.Join(tempDir, "go.tar.gz")
|
||||
if err := downloadFile(downloadURL, tarballPath); err != nil {
|
||||
return "", fmt.Errorf("failed to download Go: %w", err)
|
||||
}
|
||||
|
||||
|
||||
// Install directory - typically /usr/local for Linux/macOS
|
||||
|
||||
|
||||
// Check if existing Go installation exists and remove it
|
||||
existingGoDir := filepath.Join(installDir, "go")
|
||||
if _, err := os.Stat(existingGoDir); err == nil {
|
||||
@@ -131,34 +131,34 @@ func (g *GoInstaller) InstallGo() (string, error) {
|
||||
return "", fmt.Errorf("failed to remove existing Go installation: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Extract tarball to install directory
|
||||
fmt.Printf("Extracting Go to %s\n", installDir)
|
||||
err = extractTarGz(tarballPath, installDir)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to extract Go tarball: %w", err)
|
||||
}
|
||||
|
||||
|
||||
// Verify installation
|
||||
var goExePathVerify = filepath.Join(installDir, "go", "bin", "go") // Use = instead of := to avoid variable shadowing
|
||||
|
||||
|
||||
// Check if the Go binary exists
|
||||
var statErr error
|
||||
_, statErr = os.Stat(goExePathVerify)
|
||||
if statErr != nil {
|
||||
return "", fmt.Errorf("Go installation failed - go executable not found at %s", goExePathVerify)
|
||||
}
|
||||
|
||||
|
||||
// Set up environment variables
|
||||
fmt.Println("Setting up Go environment variables...")
|
||||
|
||||
|
||||
// Update PATH in /etc/profile
|
||||
profilePath := "/etc/profile"
|
||||
profileContent, err := os.ReadFile(profilePath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to read profile: %w", err)
|
||||
}
|
||||
|
||||
|
||||
// Add Go bin to PATH if not already there
|
||||
goBinPath := filepath.Join(installDir, "go", "bin")
|
||||
if !strings.Contains(string(profileContent), goBinPath) {
|
||||
@@ -167,7 +167,7 @@ func (g *GoInstaller) InstallGo() (string, error) {
|
||||
return "", fmt.Errorf("failed to update profile: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fmt.Printf("✅ Go %s installed successfully!\n", g.Version)
|
||||
return goExePath, nil
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/system/stats"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/system/stats"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -18,11 +18,11 @@ func main() {
|
||||
// Create a new stats manager with Redis connection
|
||||
// Create a custom configuration
|
||||
config := &stats.Config{
|
||||
RedisAddr: "localhost:6379",
|
||||
RedisPassword: "",
|
||||
RedisDB: 0,
|
||||
Debug: false,
|
||||
QueueSize: 100,
|
||||
RedisAddr: "localhost:6379",
|
||||
RedisPassword: "",
|
||||
RedisDB: 0,
|
||||
Debug: false,
|
||||
QueueSize: 100,
|
||||
DefaultTimeout: 5 * time.Second,
|
||||
ExpirationTimes: map[string]time.Duration{
|
||||
"system": 60 * time.Second, // System info expires after 60 seconds
|
||||
@@ -32,7 +32,7 @@ func main() {
|
||||
"hardware": 120 * time.Second, // Hardware stats expire after 2 minutes
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
manager, err := stats.NewStatsManager(config)
|
||||
if err != nil {
|
||||
fmt.Printf("Error creating stats manager: %v\n", err)
|
||||
@@ -61,12 +61,12 @@ func main() {
|
||||
fmt.Printf(" Cores: %d\n", sysInfo.CPU.Cores)
|
||||
fmt.Printf(" Model: %s\n", sysInfo.CPU.ModelName)
|
||||
fmt.Printf(" Usage: %.1f%%\n", sysInfo.CPU.UsagePercent)
|
||||
|
||||
|
||||
fmt.Println("\nMemory Information:")
|
||||
fmt.Printf(" Total: %.1f GB\n", sysInfo.Memory.Total)
|
||||
fmt.Printf(" Used: %.1f GB (%.1f%%)\n", sysInfo.Memory.Used, sysInfo.Memory.UsedPercent)
|
||||
fmt.Printf(" Free: %.1f GB\n", sysInfo.Memory.Free)
|
||||
|
||||
|
||||
fmt.Println("\nNetwork Information:")
|
||||
fmt.Printf(" Upload Speed: %s\n", sysInfo.Network.UploadSpeed)
|
||||
fmt.Printf(" Download Speed: %s\n", sysInfo.Network.DownloadSpeed)
|
||||
@@ -81,7 +81,7 @@ func main() {
|
||||
} else {
|
||||
fmt.Printf("Found %d disks:\n", len(diskStats.Disks))
|
||||
for _, disk := range diskStats.Disks {
|
||||
fmt.Printf(" %s: %.1f GB total, %.1f GB free (%.1f%% used)\n",
|
||||
fmt.Printf(" %s: %.1f GB total, %.1f GB free (%.1f%% used)\n",
|
||||
disk.Path, disk.Total, disk.Free, disk.UsedPercent)
|
||||
}
|
||||
}
|
||||
@@ -93,12 +93,12 @@ func main() {
|
||||
if err != nil {
|
||||
fmt.Printf("Error getting process stats: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf("Total processes: %d (showing top %d)\n",
|
||||
fmt.Printf("Total processes: %d (showing top %d)\n",
|
||||
processStats.Total, len(processStats.Processes))
|
||||
|
||||
|
||||
fmt.Println("\nTop Processes by CPU Usage:")
|
||||
for i, proc := range processStats.Processes {
|
||||
fmt.Printf(" %d. PID %d: %s (CPU: %.1f%%, Memory: %.1f MB)\n",
|
||||
fmt.Printf(" %d. PID %d: %s (CPU: %.1f%%, Memory: %.1f MB)\n",
|
||||
i+1, proc.PID, proc.Name, proc.CPUPercent, proc.MemoryMB)
|
||||
}
|
||||
}
|
||||
@@ -107,10 +107,10 @@ func main() {
|
||||
fmt.Println("\n4. CACHING DEMONSTRATION")
|
||||
fmt.Println("----------------------")
|
||||
fmt.Println("Getting network speed multiple times (should use cache):")
|
||||
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
netSpeed := manager.GetNetworkSpeedResult()
|
||||
fmt.Printf(" Request %d: Upload: %s, Download: %s\n",
|
||||
fmt.Printf(" Request %d: Upload: %s, Download: %s\n",
|
||||
i+1, netSpeed.UploadSpeed, netSpeed.DownloadSpeed)
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
@@ -127,17 +127,17 @@ func main() {
|
||||
fmt.Println("--------------------------")
|
||||
fmt.Println("Enabling debug mode (direct fetching without cache)...")
|
||||
manager.Debug = true
|
||||
|
||||
|
||||
fmt.Println("Getting system info in debug mode:")
|
||||
debugSysInfo, err := manager.GetSystemInfo()
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf(" CPU Usage: %.1f%%\n", debugSysInfo.CPU.UsagePercent)
|
||||
fmt.Printf(" Memory Used: %.1f GB (%.1f%%)\n",
|
||||
fmt.Printf(" Memory Used: %.1f GB (%.1f%%)\n",
|
||||
debugSysInfo.Memory.Used, debugSysInfo.Memory.UsedPercent)
|
||||
}
|
||||
|
||||
|
||||
// Reset debug mode
|
||||
manager.Debug = false
|
||||
|
||||
@@ -148,17 +148,17 @@ func main() {
|
||||
for statsType, duration := range manager.Expiration {
|
||||
fmt.Printf(" %s: %v\n", statsType, duration)
|
||||
}
|
||||
|
||||
|
||||
fmt.Println("\nChanging system stats expiration to 10 seconds...")
|
||||
manager.Expiration["system"] = 10 * time.Second
|
||||
|
||||
|
||||
fmt.Println("Updated expiration times:")
|
||||
for statsType, duration := range manager.Expiration {
|
||||
fmt.Printf(" %s: %v\n", statsType, duration)
|
||||
}
|
||||
|
||||
fmt.Println("\nDemo complete. Press Ctrl+C to exit.")
|
||||
|
||||
|
||||
// Keep the program running
|
||||
select {}
|
||||
}
|
||||
|
@@ -11,27 +11,27 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/system/stats"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/system/stats"
|
||||
"github.com/shirou/gopsutil/v3/cpu"
|
||||
"github.com/shirou/gopsutil/v3/process"
|
||||
)
|
||||
|
||||
// TestResult stores the results of a single test run
|
||||
type TestResult struct {
|
||||
StartTime time.Time
|
||||
EndTime time.Time
|
||||
SystemInfoTime time.Duration
|
||||
DiskStatsTime time.Duration
|
||||
ProcessTime time.Duration
|
||||
NetworkTime time.Duration
|
||||
HardwareTime time.Duration
|
||||
TotalTime time.Duration
|
||||
UserCPU float64
|
||||
SystemCPU float64
|
||||
TotalCPU float64
|
||||
OverallCPU float64
|
||||
MemoryUsageMB float32
|
||||
NumGoroutines int
|
||||
StartTime time.Time
|
||||
EndTime time.Time
|
||||
SystemInfoTime time.Duration
|
||||
DiskStatsTime time.Duration
|
||||
ProcessTime time.Duration
|
||||
NetworkTime time.Duration
|
||||
HardwareTime time.Duration
|
||||
TotalTime time.Duration
|
||||
UserCPU float64
|
||||
SystemCPU float64
|
||||
TotalCPU float64
|
||||
OverallCPU float64
|
||||
MemoryUsageMB float32
|
||||
NumGoroutines int
|
||||
}
|
||||
|
||||
func main() {
|
||||
@@ -66,11 +66,11 @@ func main() {
|
||||
|
||||
// Create a new stats manager with Redis connection
|
||||
config := &stats.Config{
|
||||
RedisAddr: "localhost:6379",
|
||||
RedisPassword: "",
|
||||
RedisDB: 0,
|
||||
Debug: false,
|
||||
QueueSize: 100,
|
||||
RedisAddr: "localhost:6379",
|
||||
RedisPassword: "",
|
||||
RedisDB: 0,
|
||||
Debug: false,
|
||||
QueueSize: 100,
|
||||
DefaultTimeout: 5 * time.Second,
|
||||
ExpirationTimes: map[string]time.Duration{
|
||||
"system": 60 * time.Second, // System info expires after 60 seconds
|
||||
@@ -80,7 +80,7 @@ func main() {
|
||||
"hardware": 120 * time.Second, // Hardware stats expire after 2 minutes
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
manager, err := stats.NewStatsManager(config)
|
||||
if err != nil {
|
||||
fmt.Printf("Error creating stats manager: %v\n", err)
|
||||
@@ -101,11 +101,11 @@ func main() {
|
||||
// Set up signal handling for graceful shutdown
|
||||
sigChan := make(chan os.Signal, 1)
|
||||
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
|
||||
// Create a ticker for running tests at the specified interval
|
||||
ticker := time.NewTicker(time.Duration(*intervalPtr) * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
|
||||
// Store the sleep duration between operations
|
||||
sleepDuration := time.Duration(*sleepPtr) * time.Millisecond
|
||||
|
||||
@@ -118,7 +118,7 @@ func main() {
|
||||
|
||||
// Store test results
|
||||
var results []TestResult
|
||||
|
||||
|
||||
// Print header
|
||||
fmt.Printf("%-20s %-20s %-12s %-12s %-12s %-12s %-12s %-12s %-12s %-12s %-12s %-12s %-12s\n",
|
||||
"Start Time", "End Time", "System(ms)", "Disk(ms)", "Process(ms)", "Network(ms)", "Hardware(ms)", "Total(ms)", "UserCPU(%)", "SysCPU(%)", "TotalCPU(%)", "Memory(MB)", "Goroutines")
|
||||
@@ -131,7 +131,7 @@ func main() {
|
||||
// Run a test and record the results
|
||||
result := runTest(manager, currentProcess, sleepDuration)
|
||||
results = append(results, result)
|
||||
|
||||
|
||||
// Print the result
|
||||
fmt.Printf("%-20s %-20s %-12.2f %-12.2f %-12.2f %-12.2f %-12.2f %-12.2f %-12.2f %-12.2f %-12.2f %-12.2f %-12d\n",
|
||||
result.StartTime.Format("15:04:05.000000"),
|
||||
@@ -147,16 +147,16 @@ func main() {
|
||||
result.TotalCPU,
|
||||
result.MemoryUsageMB,
|
||||
result.NumGoroutines)
|
||||
|
||||
|
||||
case <-sigChan:
|
||||
// Calculate and print summary statistics
|
||||
fmt.Println("\nTest Summary:")
|
||||
fmt.Println(strings.Repeat("-", 50))
|
||||
|
||||
|
||||
var totalSystemTime, totalDiskTime, totalProcessTime, totalNetworkTime, totalHardwareTime, totalTime time.Duration
|
||||
var totalUserCPU, totalSystemCPU, totalCombinedCPU, totalOverallCPU float64
|
||||
var totalMemory float32
|
||||
|
||||
|
||||
for _, r := range results {
|
||||
totalSystemTime += r.SystemInfoTime
|
||||
totalDiskTime += r.DiskStatsTime
|
||||
@@ -170,7 +170,7 @@ func main() {
|
||||
totalOverallCPU += r.OverallCPU
|
||||
totalMemory += r.MemoryUsageMB
|
||||
}
|
||||
|
||||
|
||||
count := float64(len(results))
|
||||
if count > 0 {
|
||||
fmt.Printf("Average System Info Time: %.2f ms\n", float64(totalSystemTime.Microseconds())/(count*1000))
|
||||
@@ -185,7 +185,7 @@ func main() {
|
||||
fmt.Printf("Average Overall CPU: %.2f%%\n", totalOverallCPU/count)
|
||||
fmt.Printf("Average Memory Usage: %.2f MB\n", float64(totalMemory)/count)
|
||||
}
|
||||
|
||||
|
||||
fmt.Println("\nTest completed. Exiting...")
|
||||
return
|
||||
}
|
||||
@@ -196,90 +196,90 @@ func main() {
|
||||
func runTest(manager *stats.StatsManager, proc *process.Process, sleepBetweenOps time.Duration) TestResult {
|
||||
// Get initial CPU times for the process
|
||||
initialTimes, _ := proc.Times()
|
||||
|
||||
|
||||
// Get initial overall CPU usage
|
||||
_, _ = cpu.Percent(0, false) // Discard initial reading, we'll only use the final reading
|
||||
|
||||
|
||||
result := TestResult{
|
||||
StartTime: time.Now(),
|
||||
}
|
||||
|
||||
|
||||
// Measure total time
|
||||
totalStart := time.Now()
|
||||
|
||||
|
||||
// Measure system info time
|
||||
start := time.Now()
|
||||
_, _ = manager.GetSystemInfo()
|
||||
result.SystemInfoTime = time.Since(start)
|
||||
|
||||
|
||||
// Sleep between operations if configured
|
||||
if sleepBetweenOps > 0 {
|
||||
time.Sleep(sleepBetweenOps)
|
||||
}
|
||||
|
||||
|
||||
// Measure disk stats time
|
||||
start = time.Now()
|
||||
_, _ = manager.GetDiskStats()
|
||||
result.DiskStatsTime = time.Since(start)
|
||||
|
||||
|
||||
// Sleep between operations if configured
|
||||
if sleepBetweenOps > 0 {
|
||||
time.Sleep(sleepBetweenOps)
|
||||
}
|
||||
|
||||
|
||||
// Measure process stats time
|
||||
start = time.Now()
|
||||
_, _ = manager.GetProcessStats(10)
|
||||
result.ProcessTime = time.Since(start)
|
||||
|
||||
|
||||
// Sleep between operations if configured
|
||||
if sleepBetweenOps > 0 {
|
||||
time.Sleep(sleepBetweenOps)
|
||||
}
|
||||
|
||||
|
||||
// Measure network speed time
|
||||
start = time.Now()
|
||||
_ = manager.GetNetworkSpeedResult()
|
||||
result.NetworkTime = time.Since(start)
|
||||
|
||||
|
||||
// Sleep between operations if configured
|
||||
if sleepBetweenOps > 0 {
|
||||
time.Sleep(sleepBetweenOps)
|
||||
}
|
||||
|
||||
|
||||
// Measure hardware stats time
|
||||
start = time.Now()
|
||||
_ = manager.GetHardwareStatsJSON()
|
||||
result.HardwareTime = time.Since(start)
|
||||
|
||||
|
||||
// Record total time
|
||||
result.TotalTime = time.Since(totalStart)
|
||||
result.EndTime = time.Now()
|
||||
|
||||
|
||||
// Get final CPU times for the process
|
||||
finalTimes, _ := proc.Times()
|
||||
|
||||
|
||||
// Calculate CPU usage for this specific operation
|
||||
if initialTimes != nil && finalTimes != nil {
|
||||
result.UserCPU = (finalTimes.User - initialTimes.User) * 100
|
||||
result.SystemCPU = (finalTimes.System - initialTimes.System) * 100
|
||||
result.TotalCPU = result.UserCPU + result.SystemCPU
|
||||
}
|
||||
|
||||
|
||||
// Get overall CPU usage
|
||||
finalOverallCPU, _ := cpu.Percent(0, false)
|
||||
if len(finalOverallCPU) > 0 {
|
||||
result.OverallCPU = finalOverallCPU[0]
|
||||
}
|
||||
|
||||
|
||||
// Measure memory usage
|
||||
memInfo, _ := proc.MemoryInfo()
|
||||
if memInfo != nil {
|
||||
result.MemoryUsageMB = float32(memInfo.RSS) / (1024 * 1024)
|
||||
}
|
||||
|
||||
|
||||
// Record number of goroutines
|
||||
result.NumGoroutines = runtime.NumGoroutine()
|
||||
|
||||
|
||||
return result
|
||||
}
|
||||
|
@@ -6,7 +6,7 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/system/stats"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/system/stats"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
|
@@ -6,7 +6,7 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/system/stats"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/system/stats"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -15,21 +15,21 @@ func main() {
|
||||
|
||||
// Create a new stats manager with Redis connection
|
||||
config := &stats.Config{
|
||||
RedisAddr: "localhost:6379",
|
||||
RedisPassword: "",
|
||||
RedisDB: 0,
|
||||
Debug: false,
|
||||
QueueSize: 100,
|
||||
RedisAddr: "localhost:6379",
|
||||
RedisPassword: "",
|
||||
RedisDB: 0,
|
||||
Debug: false,
|
||||
QueueSize: 100,
|
||||
DefaultTimeout: 5 * time.Second,
|
||||
ExpirationTimes: map[string]time.Duration{
|
||||
"system": 30 * time.Second, // System info expires after 30 seconds
|
||||
"disk": 60 * time.Second, // Disk info expires after 1 minute
|
||||
"process": 15 * time.Second, // Process info expires after 15 seconds
|
||||
"network": 20 * time.Second, // Network info expires after 20 seconds
|
||||
"hardware": 60 * time.Second, // Hardware stats expire after 1 minute
|
||||
"system": 30 * time.Second, // System info expires after 30 seconds
|
||||
"disk": 60 * time.Second, // Disk info expires after 1 minute
|
||||
"process": 15 * time.Second, // Process info expires after 15 seconds
|
||||
"network": 20 * time.Second, // Network info expires after 20 seconds
|
||||
"hardware": 60 * time.Second, // Hardware stats expire after 1 minute
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
manager, err := stats.NewStatsManager(config)
|
||||
if err != nil {
|
||||
fmt.Printf("Error creating stats manager: %v\n", err)
|
||||
@@ -40,7 +40,7 @@ func main() {
|
||||
// DISK INFORMATION
|
||||
fmt.Println("\n1. DISK INFORMATION")
|
||||
fmt.Println("------------------")
|
||||
|
||||
|
||||
// Get all disk stats using the manager
|
||||
diskStats, err := manager.GetDiskStats()
|
||||
if err != nil {
|
||||
@@ -48,7 +48,7 @@ func main() {
|
||||
} else {
|
||||
fmt.Printf("Found %d disks:\n", len(diskStats.Disks))
|
||||
for _, disk := range diskStats.Disks {
|
||||
fmt.Printf(" %s: %.1f GB total, %.1f GB free (%.1f%% used)\n",
|
||||
fmt.Printf(" %s: %.1f GB total, %.1f GB free (%.1f%% used)\n",
|
||||
disk.Path, disk.Total, disk.Free, disk.UsedPercent)
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,7 @@ func main() {
|
||||
if err != nil {
|
||||
fmt.Printf("Error getting root disk info: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf("\nRoot Disk: %.1f GB total, %.1f GB free (%.1f%% used)\n",
|
||||
fmt.Printf("\nRoot Disk: %.1f GB total, %.1f GB free (%.1f%% used)\n",
|
||||
rootDisk.Total, rootDisk.Free, rootDisk.UsedPercent)
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ func main() {
|
||||
// SYSTEM INFORMATION
|
||||
fmt.Println("\n2. SYSTEM INFORMATION")
|
||||
fmt.Println("--------------------")
|
||||
|
||||
|
||||
// Get system info using the manager
|
||||
sysInfo, err := manager.GetSystemInfo()
|
||||
if err != nil {
|
||||
@@ -78,12 +78,12 @@ func main() {
|
||||
fmt.Printf(" Cores: %d\n", sysInfo.CPU.Cores)
|
||||
fmt.Printf(" Model: %s\n", sysInfo.CPU.ModelName)
|
||||
fmt.Printf(" Usage: %.1f%%\n", sysInfo.CPU.UsagePercent)
|
||||
|
||||
|
||||
fmt.Println("\nMemory Information:")
|
||||
fmt.Printf(" Total: %.1f GB\n", sysInfo.Memory.Total)
|
||||
fmt.Printf(" Used: %.1f GB (%.1f%%)\n", sysInfo.Memory.Used, sysInfo.Memory.UsedPercent)
|
||||
fmt.Printf(" Free: %.1f GB\n", sysInfo.Memory.Free)
|
||||
|
||||
|
||||
fmt.Println("\nNetwork Information:")
|
||||
fmt.Printf(" Upload Speed: %s\n", sysInfo.Network.UploadSpeed)
|
||||
fmt.Printf(" Download Speed: %s\n", sysInfo.Network.DownloadSpeed)
|
||||
@@ -98,18 +98,18 @@ func main() {
|
||||
// PROCESS INFORMATION
|
||||
fmt.Println("\n3. PROCESS INFORMATION")
|
||||
fmt.Println("---------------------")
|
||||
|
||||
|
||||
// Get process stats using the manager
|
||||
processStats, err := manager.GetProcessStats(5) // Get top 5 processes
|
||||
if err != nil {
|
||||
fmt.Printf("Error getting process stats: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf("Total processes: %d (showing top %d)\n",
|
||||
fmt.Printf("Total processes: %d (showing top %d)\n",
|
||||
processStats.Total, len(processStats.Processes))
|
||||
|
||||
|
||||
fmt.Println("\nTop Processes by CPU Usage:")
|
||||
for i, proc := range processStats.Processes {
|
||||
fmt.Printf(" %d. PID %d: %s (CPU: %.1f%%, Memory: %.1f MB)\n",
|
||||
fmt.Printf(" %d. PID %d: %s (CPU: %.1f%%, Memory: %.1f MB)\n",
|
||||
i+1, proc.PID, proc.Name, proc.CPUPercent, proc.MemoryMB)
|
||||
}
|
||||
}
|
||||
@@ -128,7 +128,7 @@ func main() {
|
||||
// COMBINED STATS
|
||||
fmt.Println("\n4. COMBINED STATS FUNCTIONS")
|
||||
fmt.Println("--------------------------")
|
||||
|
||||
|
||||
// Hardware stats using the manager
|
||||
fmt.Println("\nHardware Stats:")
|
||||
hardwareStats := manager.GetHardwareStats()
|
||||
@@ -151,17 +151,17 @@ func main() {
|
||||
// Wait and measure network speed again
|
||||
fmt.Println("\nWaiting 2 seconds for another network speed measurement...")
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
|
||||
// Get updated network speed using the manager
|
||||
updatedNetSpeed := manager.GetNetworkSpeedResult()
|
||||
fmt.Println("\nUpdated Network Speed:")
|
||||
fmt.Printf(" Upload: %s\n", updatedNetSpeed.UploadSpeed)
|
||||
fmt.Printf(" Download: %s\n", updatedNetSpeed.DownloadSpeed)
|
||||
|
||||
|
||||
// CACHE MANAGEMENT
|
||||
fmt.Println("\n5. CACHE MANAGEMENT")
|
||||
fmt.Println("------------------")
|
||||
|
||||
|
||||
// Force update of system stats
|
||||
fmt.Println("\nForcing update of system stats...")
|
||||
err = manager.ForceUpdate("system")
|
||||
@@ -170,7 +170,7 @@ func main() {
|
||||
} else {
|
||||
fmt.Println("System stats updated successfully")
|
||||
}
|
||||
|
||||
|
||||
// Get updated system info
|
||||
updatedSysInfo, err := manager.GetSystemInfo()
|
||||
if err != nil {
|
||||
@@ -178,7 +178,7 @@ func main() {
|
||||
} else {
|
||||
fmt.Println("\nUpdated CPU Usage: " + fmt.Sprintf("%.1f%%", updatedSysInfo.CPU.UsagePercent))
|
||||
}
|
||||
|
||||
|
||||
// Clear cache for disk stats
|
||||
fmt.Println("\nClearing cache for disk stats...")
|
||||
err = manager.ClearCache("disk")
|
||||
@@ -187,7 +187,7 @@ func main() {
|
||||
} else {
|
||||
fmt.Println("Disk stats cache cleared successfully")
|
||||
}
|
||||
|
||||
|
||||
// Toggle debug mode
|
||||
fmt.Println("\nToggling debug mode (direct fetching without cache)...")
|
||||
manager.Debug = !manager.Debug
|
||||
|
Reference in New Issue
Block a user