209 lines
5.0 KiB
Go
209 lines
5.0 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"log"
|
|
"net"
|
|
"os"
|
|
"strings"
|
|
"syscall"
|
|
"time"
|
|
|
|
"github.com/freeflowuniverse/heroagent/pkg/handlerfactory/herohandler"
|
|
)
|
|
|
|
func main() {
|
|
// Start the herohandler in a goroutine
|
|
go startHeroHandler()
|
|
|
|
// Run a simple telnet test
|
|
time.Sleep(1 * time.Second) // Give the server time to start
|
|
fmt.Println("\n=== Testing HeroHandler Telnet Server ===")
|
|
fmt.Println("The herohandler is running with a process manager handler registered.")
|
|
fmt.Println("You can connect to the telnet server at:")
|
|
fmt.Println("- Unix socket: /tmp/hero.sock")
|
|
fmt.Println("- TCP address: localhost:8023")
|
|
fmt.Println("\nYou can use the following command to connect:")
|
|
fmt.Println(" telnet localhost 8023")
|
|
fmt.Println(" nc -U /tmp/hero.sock")
|
|
|
|
// Start interactive shell
|
|
fmt.Println("\n=== Interactive Shell ===")
|
|
fmt.Println("Type 'help' to see available commands")
|
|
fmt.Println("Type 'exit' to quit")
|
|
|
|
startInteractiveShell()
|
|
}
|
|
|
|
func startInteractiveShell() {
|
|
reader := bufio.NewReader(os.Stdin)
|
|
|
|
for {
|
|
fmt.Print("> ")
|
|
input, err := reader.ReadString('\n')
|
|
if err != nil {
|
|
fmt.Println("Error reading input:", err)
|
|
continue
|
|
}
|
|
|
|
input = strings.TrimSpace(input)
|
|
|
|
switch input {
|
|
case "exit", "quit":
|
|
fmt.Println("Exiting...")
|
|
// Send termination signal to the herohandler goroutine
|
|
syscall.Kill(syscall.Getpid(), syscall.SIGINT)
|
|
return
|
|
|
|
case "help":
|
|
showHelp()
|
|
|
|
case "status":
|
|
fmt.Println("HeroHandler is running")
|
|
fmt.Println("Telnet server is active at:")
|
|
fmt.Println("- Unix socket: /tmp/hero.sock")
|
|
fmt.Println("- TCP address: localhost:8023")
|
|
|
|
case "actions":
|
|
showSupportedActions()
|
|
|
|
case "test":
|
|
runTestScript()
|
|
|
|
default:
|
|
if input != "" {
|
|
fmt.Println("Unknown command. Type 'help' to see available commands.")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func showHelp() {
|
|
fmt.Println("Available commands:")
|
|
fmt.Println(" help - Show this help message")
|
|
fmt.Println(" status - Show herohandler status")
|
|
fmt.Println(" actions - Show supported actions for registered handlers")
|
|
fmt.Println(" test - Run a test heroscript")
|
|
fmt.Println(" exit - Exit the program")
|
|
}
|
|
|
|
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 {
|
|
fmt.Printf("TCP connection failed, trying Unix socket: %v\n", err)
|
|
result, err = Send(script, "/tmp/hero.sock", true)
|
|
if err != nil {
|
|
fmt.Printf("Error getting supported actions: %v\n", err)
|
|
return
|
|
}
|
|
}
|
|
|
|
fmt.Println("Supported actions by actor:")
|
|
fmt.Println(result)
|
|
}
|
|
|
|
// Send connects to the telnet server and sends a command, returning the response
|
|
func Send(command string, address string, isUnixSocket bool) (string, error) {
|
|
var conn net.Conn
|
|
var err error
|
|
|
|
// Connect to the server based on the address type
|
|
if isUnixSocket {
|
|
conn, err = net.Dial("unix", address)
|
|
} else {
|
|
conn, err = net.Dial("tcp", address)
|
|
}
|
|
|
|
if err != nil {
|
|
return "", fmt.Errorf("error connecting to server: %v", err)
|
|
}
|
|
defer conn.Close()
|
|
|
|
// Create a reader for the connection
|
|
reader := bufio.NewReader(conn)
|
|
|
|
// Read the welcome message
|
|
_, err = reader.ReadString('\n')
|
|
if err != nil {
|
|
return "", fmt.Errorf("error reading welcome message: %v", err)
|
|
}
|
|
|
|
// Send the command
|
|
fmt.Fprintf(conn, "%s\n", command)
|
|
|
|
// Read the response with a timeout
|
|
result := ""
|
|
ch := make(chan string)
|
|
errCh := make(chan error)
|
|
|
|
go func() {
|
|
var response strings.Builder
|
|
for {
|
|
line, err := reader.ReadString('\n')
|
|
if err != nil {
|
|
errCh <- fmt.Errorf("error reading response: %v", err)
|
|
return
|
|
}
|
|
response.WriteString(line)
|
|
|
|
// If we've received a complete response, break
|
|
if strings.Contains(line, "\n") && strings.TrimSpace(line) == "" {
|
|
break
|
|
}
|
|
}
|
|
ch <- response.String()
|
|
}()
|
|
|
|
select {
|
|
case result = <-ch:
|
|
return result, nil
|
|
case err = <-errCh:
|
|
return "", err
|
|
case <-time.After(5 * time.Second):
|
|
return "", fmt.Errorf("timeout waiting for response")
|
|
}
|
|
}
|
|
|
|
func runTestScript() {
|
|
// Simple test script for the process manager
|
|
script := `
|
|
!!process.list format:json
|
|
`
|
|
|
|
fmt.Println("Running test script:")
|
|
fmt.Println(script)
|
|
|
|
// Send the script to the telnet server
|
|
// Try TCP first, then Unix socket if TCP fails
|
|
result, err := Send(script, "localhost:8023", false)
|
|
if err != nil {
|
|
fmt.Printf("TCP connection failed, trying Unix socket: %v\n", err)
|
|
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
|
|
}
|
|
}
|
|
|
|
fmt.Println("Result:")
|
|
fmt.Println(result)
|
|
}
|
|
|
|
func startHeroHandler() {
|
|
if err := herohandler.Init(); err != nil {
|
|
log.Fatalf("Failed to start telnet server: %v", err)
|
|
}
|
|
if err := herohandler.StartTelnet(); err != nil {
|
|
log.Fatalf("Failed to start telnet server: %v", err)
|
|
}
|
|
}
|