...
This commit is contained in:
		
							
								
								
									
										75
									
								
								_pkg2_dont_use/heroscript/cmd/fakehandler_start/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								_pkg2_dont_use/heroscript/cmd/fakehandler_start/main.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"os/signal" | ||||
| 	"syscall" | ||||
|  | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/handlerfactory/herohandler" | ||||
| ) | ||||
|  | ||||
| func main() { | ||||
| 	// Parse command line flags | ||||
| 	socketPath := flag.String("socket", "/tmp/hero.sock", "Unix socket path") | ||||
| 	tcpAddress := flag.String("tcp", "localhost:8023", "TCP address") | ||||
| 	useUnixSocket := flag.Bool("unix", true, "Use Unix socket") | ||||
| 	useTCP := flag.Bool("tcp-enable", false, "Use TCP") | ||||
| 	flag.Parse() | ||||
|  | ||||
| 	// Initialize the hero handler | ||||
| 	err := herohandler.Init() | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Failed to initialize hero handler: %v\n", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
|  | ||||
| 	// Get the default instance | ||||
| 	handler := herohandler.DefaultInstance | ||||
|  | ||||
| 	// The fake handler is already registered in the Init() function | ||||
| 	fmt.Println("Using pre-registered fake handler") | ||||
|  | ||||
| 	// Start the server | ||||
| 	if *useUnixSocket || *useTCP { | ||||
| 		fmt.Printf("Starting telnet server\n") | ||||
| 		var socketPathStr, tcpAddressStr string | ||||
| 		if *useUnixSocket { | ||||
| 			socketPathStr = *socketPath | ||||
| 			fmt.Printf("Unix socket: %s\n", socketPathStr) | ||||
| 		} | ||||
| 		if *useTCP { | ||||
| 			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) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Print available commands | ||||
| 	factory := handler.GetFactory() | ||||
| 	actions := factory.GetSupportedActions() | ||||
| 	fmt.Println("\nAvailable commands:") | ||||
| 	for actor, commands := range actions { | ||||
| 		fmt.Printf("Actor: %s\n", actor) | ||||
| 		for _, command := range commands { | ||||
| 			fmt.Printf("  !!%s.%s\n", actor, command) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	fmt.Println("\nServer is running. Press Ctrl+C to stop.") | ||||
|  | ||||
| 	// Wait for interrupt signal | ||||
| 	sigCh := make(chan os.Signal, 1) | ||||
| 	signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM) | ||||
| 	<-sigCh | ||||
|  | ||||
| 	fmt.Println("\nShutting down...") | ||||
| 	handler.StopTelnet() | ||||
| 	fmt.Println("Server stopped") | ||||
| } | ||||
							
								
								
									
										1
									
								
								_pkg2_dont_use/heroscript/cmd/heroexecute/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								_pkg2_dont_use/heroscript/cmd/heroexecute/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| heroexecute | ||||
							
								
								
									
										165
									
								
								_pkg2_dont_use/heroscript/cmd/heroexecute/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								_pkg2_dont_use/heroscript/cmd/heroexecute/main.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,165 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"strings" | ||||
|  | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/heroscript/playbook" | ||||
| ) | ||||
|  | ||||
| func main() { | ||||
| 	// Define command line flags | ||||
| 	parseCmd := flag.NewFlagSet("parse", flag.ExitOnError) | ||||
| 	parseFile := parseCmd.String("file", "", "Path to heroscript file to parse") | ||||
| 	parseText := parseCmd.String("text", "", "Heroscript text to parse") | ||||
| 	parsePriority := parseCmd.Int("priority", 10, "Default priority for actions") | ||||
|  | ||||
| 	executeCmd := flag.NewFlagSet("execute", flag.ExitOnError) | ||||
| 	executeFile := executeCmd.String("file", "", "Path to heroscript file to execute") | ||||
| 	executeText := executeCmd.String("text", "", "Heroscript text to execute") | ||||
| 	executePriority := executeCmd.Int("priority", 10, "Default priority for actions") | ||||
| 	executeActor := executeCmd.String("actor", "", "Only execute actions for this actor") | ||||
| 	executeAction := executeCmd.String("action", "", "Only execute actions with this name") | ||||
|  | ||||
| 	// Check if a subcommand is provided | ||||
| 	if len(os.Args) < 2 { | ||||
| 		fmt.Println("Expected 'parse' or 'execute' subcommand") | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
|  | ||||
| 	// Parse the subcommand | ||||
| 	switch os.Args[1] { | ||||
| 	case "parse": | ||||
| 		parseCmd.Parse(os.Args[2:]) | ||||
| 		handleParseCommand(*parseFile, *parseText, *parsePriority) | ||||
| 	case "execute": | ||||
| 		executeCmd.Parse(os.Args[2:]) | ||||
| 		handleExecuteCommand(*executeFile, *executeText, *executePriority, *executeActor, *executeAction) | ||||
| 	default: | ||||
| 		fmt.Println("Expected 'parse' or 'execute' subcommand") | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func handleParseCommand(file, text string, priority int) { | ||||
| 	var pb *playbook.PlayBook | ||||
| 	var err error | ||||
|  | ||||
| 	// Parse from file or text | ||||
| 	if file != "" { | ||||
| 		content, err := ioutil.ReadFile(file) | ||||
| 		if err != nil { | ||||
| 			log.Fatalf("Failed to read file: %v", err) | ||||
| 		} | ||||
| 		pb, err = playbook.NewFromText(string(content)) | ||||
| 	} else if text != "" { | ||||
| 		pb, err = playbook.NewFromText(text) | ||||
| 	} else { | ||||
| 		log.Fatalf("Either -file or -text must be provided") | ||||
| 	} | ||||
|  | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("Failed to parse heroscript: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	// Print the parsed playbook | ||||
| 	fmt.Printf("Parsed %d actions:\n\n", len(pb.Actions)) | ||||
| 	for i, action := range pb.Actions { | ||||
| 		fmt.Printf("Action %d: %s.%s (Priority: %d)\n", i+1, action.Actor, action.Name, action.Priority) | ||||
| 		if action.Comments != "" { | ||||
| 			fmt.Printf("  Comments: %s\n", action.Comments) | ||||
| 		} | ||||
| 		fmt.Printf("  Parameters:\n") | ||||
| 		for key, value := range action.Params.GetAll() { | ||||
| 			// Format multiline values | ||||
| 			if strings.Contains(value, "\n") { | ||||
| 				fmt.Printf("    %s: |\n", key) | ||||
| 				lines := strings.Split(value, "\n") | ||||
| 				for _, line := range lines { | ||||
| 					fmt.Printf("      %s\n", line) | ||||
| 				} | ||||
| 			} else { | ||||
| 				fmt.Printf("    %s: %s\n", key, value) | ||||
| 			} | ||||
| 		} | ||||
| 		fmt.Println() | ||||
| 	} | ||||
|  | ||||
| 	// Print the generated heroscript | ||||
| 	fmt.Println("Generated HeroScript:") | ||||
| 	fmt.Println("---------------------") | ||||
| 	fmt.Println(pb.HeroScript(true)) | ||||
| 	fmt.Println("---------------------") | ||||
| } | ||||
|  | ||||
| func handleExecuteCommand(file, text string, priority int, actor, action string) { | ||||
| 	var pb *playbook.PlayBook | ||||
| 	var err error | ||||
|  | ||||
| 	// Parse from file or text | ||||
| 	if file != "" { | ||||
| 		content, err := ioutil.ReadFile(file) | ||||
| 		if err != nil { | ||||
| 			log.Fatalf("Failed to read file: %v", err) | ||||
| 		} | ||||
| 		pb, err = playbook.NewFromText(string(content)) | ||||
| 	} else if text != "" { | ||||
| 		pb, err = playbook.NewFromText(text) | ||||
| 	} else { | ||||
| 		log.Fatalf("Either -file or -text must be provided") | ||||
| 	} | ||||
|  | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("Failed to parse heroscript: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	// Find actions to execute | ||||
| 	var actionsToExecute []*playbook.Action | ||||
| 	if actor != "" || action != "" { | ||||
| 		// Find specific actions | ||||
| 		actionsToExecute, err = pb.FindActions(0, actor, action, playbook.ActionTypeUnknown) | ||||
| 		if err != nil { | ||||
| 			log.Fatalf("Failed to find actions: %v", err) | ||||
| 		} | ||||
| 	} else { | ||||
| 		// Execute all actions in priority order | ||||
| 		actionsToExecute, err = pb.ActionsSorted(false) | ||||
| 		if err != nil { | ||||
| 			log.Fatalf("Failed to sort actions: %v", err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Execute the actions | ||||
| 	fmt.Printf("Executing %d actions:\n\n", len(actionsToExecute)) | ||||
| 	for i, action := range actionsToExecute { | ||||
| 		fmt.Printf("Executing action %d: %s.%s\n", i+1, action.Actor, action.Name) | ||||
|  | ||||
| 		// In a real implementation, you would have handlers for different actors and actions | ||||
| 		// For this example, we'll just simulate execution | ||||
| 		fmt.Printf("  Parameters:\n") | ||||
| 		for key, value := range action.Params.GetAll() { | ||||
| 			fmt.Printf("    %s: %s\n", key, value) | ||||
| 		} | ||||
|  | ||||
| 		// Mark the action as done | ||||
| 		action.Done = true | ||||
|  | ||||
| 		// Set some result data | ||||
| 		action.Result.Set("status", "success") | ||||
| 		action.Result.Set("execution_time", "0.5s") | ||||
|  | ||||
| 		fmt.Printf("  Result: success\n\n") | ||||
| 	} | ||||
|  | ||||
| 	// Check if all actions are done | ||||
| 	err = pb.EmptyCheck() | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Warning: %v\n", err) | ||||
| 	} else { | ||||
| 		fmt.Println("All actions executed successfully!") | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										2
									
								
								_pkg2_dont_use/heroscript/cmd/herohandler/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								_pkg2_dont_use/heroscript/cmd/herohandler/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| herohandler | ||||
| example | ||||
							
								
								
									
										106
									
								
								_pkg2_dont_use/heroscript/cmd/herohandler/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								_pkg2_dont_use/heroscript/cmd/herohandler/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,106 @@ | ||||
| # HeroHandler Example | ||||
|  | ||||
| This package demonstrates how to implement and use a handler for HeroScript in the HeroLauncher project. | ||||
|  | ||||
| ## Overview | ||||
|  | ||||
| The HeroHandler example provides a simple key-value store implementation that showcases how to: | ||||
|  | ||||
| 1. Create a custom handler that extends the base handler functionality | ||||
| 2. Implement action methods that can be called via HeroScript | ||||
| 3. Parse parameters from HeroScript actions | ||||
| 4. Process and execute HeroScript commands | ||||
|  | ||||
| ## Project Structure | ||||
|  | ||||
| ``` | ||||
| ./herohandler/ | ||||
| ├── README.md           # This documentation file | ||||
| ├── main.go             # Main executable that uses the example handler | ||||
| └── internal/           # Internal package for the example handler implementation | ||||
|     └── example_handler.go  # Example handler implementation | ||||
| ``` | ||||
|  | ||||
| ## Handler Actions | ||||
|  | ||||
| The example handler supports the following actions: | ||||
|  | ||||
| - `example.set`: Store a key-value pair | ||||
|   - Parameters: `key`, `value` | ||||
| - `example.get`: Retrieve a value by key | ||||
|   - Parameters: `key` | ||||
| - `example.list`: List all stored key-value pairs | ||||
|   - No parameters | ||||
| - `example.delete`: Remove a key-value pair | ||||
|   - Parameters: `key` | ||||
|  | ||||
| ## Usage | ||||
|  | ||||
| You can run the example handler using the provided `main.go`: | ||||
|  | ||||
| ```bash | ||||
| # Build the binary | ||||
| cd pkg/heroscript/cmd/herohandler | ||||
| go build -o herohandler | ||||
|  | ||||
| # Set a key-value pair | ||||
| ./herohandler "example.set key:mykey value:myvalue" | ||||
|  | ||||
| # Get a value by key | ||||
| ./herohandler "example.get key:mykey" | ||||
|  | ||||
| # List all stored key-value pairs | ||||
| ./herohandler "example.list" | ||||
|  | ||||
| # Delete a key-value pair | ||||
| ./herohandler "example.delete key:mykey" | ||||
| ``` | ||||
|  | ||||
| ### Important Note on State Persistence | ||||
|  | ||||
| The example handler maintains its key-value store in memory only for the duration of a single command execution. Each time you run the `herohandler` command, a new instance of the handler is created with an empty data store. This is by design to keep the example simple. | ||||
|  | ||||
| In a real-world application, you would typically implement persistence using a database, file storage, or other mechanisms to maintain state between command executions. | ||||
|  | ||||
| ### Multi-Command Example | ||||
|  | ||||
| To execute multiple commands in a single script, you can create a HeroScript file and pass it to the handler. For example: | ||||
|  | ||||
| ```bash | ||||
| # Create a script file | ||||
| cat > example.hero << EOF | ||||
| !!example.set key:user value:john | ||||
| !!example.set key:role value:admin | ||||
| !!example.list | ||||
| EOF | ||||
|  | ||||
| # Run the script | ||||
| cat example.hero | ./herohandler | ||||
| ``` | ||||
|  | ||||
| This would process all commands in a single execution, allowing the in-memory state to be shared between commands. | ||||
|  | ||||
| ## Implementation Details | ||||
|  | ||||
| The example handler demonstrates several important concepts: | ||||
|  | ||||
| 1. **Handler Structure**: The `ExampleHandler` extends the `handlers.BaseHandler` which provides common functionality for all handlers. | ||||
|  | ||||
| 2. **Action Methods**: Each action is implemented as a method on the handler struct (e.g., `Set`, `Get`, `List`, `Delete`). | ||||
|  | ||||
| 3. **Parameter Parsing**: The `ParseParams` method from `BaseHandler` is used to extract parameters from HeroScript. | ||||
|  | ||||
| 4. **Action Execution**: The `Play` method from `BaseHandler` uses reflection to find and call the appropriate method based on the action name. | ||||
|  | ||||
| 5. **In-Memory Storage**: The example handler maintains a simple in-memory key-value store using a map. | ||||
|  | ||||
| ## Extending the Example | ||||
|  | ||||
| To create your own handler: | ||||
|  | ||||
| 1. Create a new struct that embeds the `handlers.BaseHandler` | ||||
| 2. Implement methods for each action your handler will support | ||||
| 3. Create a constructor function that initializes your handler with the appropriate actor name | ||||
| 4. Use the `Play` method to process HeroScript commands | ||||
|  | ||||
| For more complex handlers, you might need to add additional fields to store state or configuration. | ||||
							
								
								
									
										7
									
								
								_pkg2_dont_use/heroscript/cmd/herohandler/example.hero
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								_pkg2_dont_use/heroscript/cmd/herohandler/example.hero
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| !!example.set key:username value:johndoe | ||||
| !!example.set key:email value:john@example.com | ||||
| !!example.set key:role value:admin | ||||
| !!example.list | ||||
| !!example.get key:username | ||||
| !!example.delete key:email | ||||
| !!example.list | ||||
| @@ -0,0 +1,102 @@ | ||||
| package internal | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
|  | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/handlerfactory" | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/heroscript/handlers" | ||||
| ) | ||||
|  | ||||
| // ExampleHandler handles example actions | ||||
| type ExampleHandler struct { | ||||
| 	handlers.BaseHandler | ||||
| 	data map[string]string | ||||
| } | ||||
|  | ||||
| // NewExampleHandler creates a new example handler | ||||
| func NewExampleHandler() *ExampleHandler { | ||||
| 	return &ExampleHandler{ | ||||
| 		BaseHandler: handlers.BaseHandler{ | ||||
| 			BaseHandler: handlerfactory.BaseHandler{ | ||||
| 				ActorName: "example", | ||||
| 			}, | ||||
| 		}, | ||||
| 		data: make(map[string]string), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Set handles the example.set action | ||||
| func (h *ExampleHandler) Set(script string) string { | ||||
| 	params, err := h.BaseHandler.ParseParams(script) | ||||
| 	if err != nil { | ||||
| 		return fmt.Sprintf("Error parsing parameters: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	key := params.Get("key") | ||||
| 	if key == "" { | ||||
| 		return "Error: key is required" | ||||
| 	} | ||||
|  | ||||
| 	value := params.Get("value") | ||||
| 	if value == "" { | ||||
| 		return "Error: value is required" | ||||
| 	} | ||||
|  | ||||
| 	h.data[key] = value | ||||
| 	return fmt.Sprintf("Set %s = %s", key, value) | ||||
| } | ||||
|  | ||||
| // Get handles the example.get action | ||||
| func (h *ExampleHandler) Get(script string) string { | ||||
| 	params, err := h.BaseHandler.ParseParams(script) | ||||
| 	if err != nil { | ||||
| 		return fmt.Sprintf("Error parsing parameters: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	key := params.Get("key") | ||||
| 	if key == "" { | ||||
| 		return "Error: key is required" | ||||
| 	} | ||||
|  | ||||
| 	value, exists := h.data[key] | ||||
| 	if !exists { | ||||
| 		return fmt.Sprintf("Key '%s' not found", key) | ||||
| 	} | ||||
|  | ||||
| 	return fmt.Sprintf("%s = %s", key, value) | ||||
| } | ||||
|  | ||||
| // List handles the example.list action | ||||
| func (h *ExampleHandler) List(script string) string { | ||||
| 	if len(h.data) == 0 { | ||||
| 		return "No data stored" | ||||
| 	} | ||||
|  | ||||
| 	var result string | ||||
| 	for key, value := range h.data { | ||||
| 		result += fmt.Sprintf("%s = %s\n", key, value) | ||||
| 	} | ||||
|  | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // Delete handles the example.delete action | ||||
| func (h *ExampleHandler) Delete(script string) string { | ||||
| 	params, err := h.BaseHandler.ParseParams(script) | ||||
| 	if err != nil { | ||||
| 		return fmt.Sprintf("Error parsing parameters: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	key := params.Get("key") | ||||
| 	if key == "" { | ||||
| 		return "Error: key is required" | ||||
| 	} | ||||
|  | ||||
| 	_, exists := h.data[key] | ||||
| 	if !exists { | ||||
| 		return fmt.Sprintf("Key '%s' not found", key) | ||||
| 	} | ||||
|  | ||||
| 	delete(h.data, key) | ||||
| 	return fmt.Sprintf("Deleted key '%s'", key) | ||||
| } | ||||
							
								
								
									
										101
									
								
								_pkg2_dont_use/heroscript/cmd/herohandler/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								_pkg2_dont_use/heroscript/cmd/herohandler/main.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"strings" | ||||
|  | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/heroscript/cmd/herohandler/internal" | ||||
| ) | ||||
|  | ||||
| func main() { | ||||
| 	// Create a new example handler | ||||
| 	handler := internal.NewExampleHandler() | ||||
|  | ||||
| 	// Check if input is coming from stdin (piped input) | ||||
| 	stat, _ := os.Stdin.Stat() | ||||
| 	if (stat.Mode() & os.ModeCharDevice) == 0 { | ||||
| 		// Reading from stdin (pipe or redirect) | ||||
| 		processStdin(handler) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// Check if there are command-line arguments | ||||
| 	if len(os.Args) < 2 { | ||||
| 		printUsage() | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// 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, "!!") { | ||||
| 		script = "!!" + script | ||||
| 	} | ||||
|  | ||||
| 	// Process the script | ||||
| 	result, err := handler.Play(script, handler) | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Error: %v\n", err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// Print the result | ||||
| 	fmt.Println(result) | ||||
| } | ||||
|  | ||||
| func printUsage() { | ||||
| 	fmt.Println("Usage: herohandler <action>") | ||||
| 	fmt.Println("       cat script.hero | herohandler") | ||||
| 	fmt.Println("\nExample commands:") | ||||
| 	fmt.Println("  example.set key:mykey value:myvalue") | ||||
| 	fmt.Println("  example.get key:mykey") | ||||
| 	fmt.Println("  example.list") | ||||
| 	fmt.Println("  example.delete key:mykey") | ||||
| 	fmt.Println("\nNote: The command will be automatically formatted as HeroScript with !! prefix.") | ||||
| 	fmt.Println("      You can also pipe a multi-line HeroScript file to process multiple commands.") | ||||
| } | ||||
|  | ||||
| // processStdin reads and processes HeroScript from stdin | ||||
| func processStdin(handler *internal.ExampleHandler) { | ||||
| 	reader := bufio.NewReader(os.Stdin) | ||||
| 	var scriptBuilder strings.Builder | ||||
|  | ||||
| 	// Read all lines from stdin | ||||
| 	for { | ||||
| 		line, err := reader.ReadString('\n') | ||||
| 		if err != nil && err != io.EOF { | ||||
| 			fmt.Printf("Error reading from stdin: %v\n", err) | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		// Add the line to our script | ||||
| 		scriptBuilder.WriteString(line) | ||||
|  | ||||
| 		// If we've reached EOF, break | ||||
| 		if err == io.EOF { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Process the complete script | ||||
| 	script := scriptBuilder.String() | ||||
| 	if script == "" { | ||||
| 		fmt.Println("Error: Empty script") | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// Process the script | ||||
| 	result, err := handler.Play(script, handler) | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Error: %v\n", err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// Print the result | ||||
| 	fmt.Println(result) | ||||
| } | ||||
							
								
								
									
										208
									
								
								_pkg2_dont_use/heroscript/cmd/herohandler_start/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										208
									
								
								_pkg2_dont_use/heroscript/cmd/herohandler_start/main.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,208 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| 	"net" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| 	"syscall" | ||||
| 	"time" | ||||
|  | ||||
| 	"git.ourworld.tf/herocode/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) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										1
									
								
								_pkg2_dont_use/heroscript/cmd/heroscriptexample/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								_pkg2_dont_use/heroscript/cmd/heroscriptexample/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| heroscriptexample | ||||
							
								
								
									
										75
									
								
								_pkg2_dont_use/heroscript/cmd/heroscriptexample/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								_pkg2_dont_use/heroscript/cmd/heroscriptexample/main.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"log" | ||||
|  | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/heroscript/playbook" | ||||
| ) | ||||
|  | ||||
| const exampleScript = ` | ||||
| //This is a mail client configuration | ||||
| !!mailclient.configure | ||||
| 	name: 'mymail' | ||||
| 	host: 'smtp.example.com' | ||||
| 	port: 25 | ||||
| 	secure: 1 | ||||
| 	reset: 1  | ||||
| 	description: ' | ||||
| 		This is a multiline description | ||||
| 		for my mail client configuration. | ||||
|  | ||||
| 		It supports multiple paragraphs. | ||||
| 		' | ||||
|  | ||||
| //System update action | ||||
| !!system.update | ||||
| 	force: 1 | ||||
| 	packages: 'git,curl,wget' | ||||
| ` | ||||
|  | ||||
| func main() { | ||||
| 	// Parse heroscript | ||||
| 	pb, err := playbook.NewFromText(exampleScript) | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("Failed to parse heroscript: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	// Print the playbook | ||||
| 	fmt.Println("Playbook contains:") | ||||
| 	fmt.Printf("- %d actions\n", len(pb.Actions)) | ||||
| 	fmt.Println("- Hash: " + pb.HashKey()) | ||||
| 	fmt.Println() | ||||
|  | ||||
| 	// Print each action | ||||
| 	for i, action := range pb.Actions { | ||||
| 		fmt.Printf("Action %d: %s.%s\n", i+1, action.Actor, action.Name) | ||||
| 		fmt.Printf("  Comments: %s\n", action.Comments) | ||||
| 		fmt.Printf("  Parameters:\n") | ||||
|  | ||||
| 		for key, value := range action.Params.GetAll() { | ||||
| 			fmt.Printf("    %s: %s\n", key, value) | ||||
| 		} | ||||
| 		fmt.Println() | ||||
| 	} | ||||
|  | ||||
| 	// Generate heroscript | ||||
| 	fmt.Println("Generated HeroScript:") | ||||
| 	fmt.Println("---------------------") | ||||
| 	fmt.Println(pb.HeroScript(true)) | ||||
| 	fmt.Println("---------------------") | ||||
|  | ||||
| 	// Demonstrate finding actions | ||||
| 	mailActions, err := pb.FindActions(0, "mailclient", "", playbook.ActionTypeUnknown) | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("Error finding actions: %v", err) | ||||
| 	} | ||||
| 	fmt.Printf("\nFound %d mail client actions\n", len(mailActions)) | ||||
|  | ||||
| 	// Mark an action as done | ||||
| 	if len(pb.Actions) > 0 { | ||||
| 		pb.Actions[0].Done = true | ||||
| 		fmt.Println("\nAfter marking first action as done:") | ||||
| 		fmt.Println(pb.HeroScript(false)) // Don't show done actions | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										19
									
								
								_pkg2_dont_use/heroscript/cmd/vmhandler/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								_pkg2_dont_use/heroscript/cmd/vmhandler/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| # Binaries for programs and plugins | ||||
| *.exe | ||||
| *.exe~ | ||||
| *.dll | ||||
| *.so | ||||
| *.dylib | ||||
| vmhandler | ||||
|  | ||||
| # Test binary, built with `go test -c` | ||||
| *.test | ||||
|  | ||||
| # Output of the go coverage tool, specifically when used with LiteIDE | ||||
| *.out | ||||
|  | ||||
| # Dependency directories (remove the comment below to include it) | ||||
| # vendor/ | ||||
|  | ||||
| # Go workspace file | ||||
| go.work | ||||
							
								
								
									
										134
									
								
								_pkg2_dont_use/heroscript/cmd/vmhandler/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								_pkg2_dont_use/heroscript/cmd/vmhandler/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,134 @@ | ||||
| # VM Handler Example | ||||
|  | ||||
| This example demonstrates how to use the HandlerFactory with a VM handler to process heroscript commands. | ||||
|  | ||||
| ## Overview | ||||
|  | ||||
| The VM handler example shows how to: | ||||
|  | ||||
| 1. Create a handler that processes VM-related actions | ||||
| 2. Register the handler with the HandlerFactory | ||||
| 3. Start a telnet server that uses the HandlerFactory to process commands | ||||
| 4. Connect to the telnet server and send heroscript commands | ||||
|  | ||||
| ## Running the Example | ||||
|  | ||||
| To run the example: | ||||
|  | ||||
| ```bash | ||||
| cd ~/code/github/freeflowuniverse/herocode/heroagent/pkg/handlerfactory/cmd/vmhandler | ||||
| go run . tutorial | ||||
| #to run just the server do | ||||
| go run .  | ||||
| #you can then go to other terminal and play with telnet / nc | ||||
| ``` | ||||
|  | ||||
| This will start a telnet server on: | ||||
| - Unix socket: `/tmp/vmhandler.sock` | ||||
| - TCP: `localhost:8024` | ||||
|  | ||||
| ## Connecting to the Server | ||||
|  | ||||
| ### Using Unix Socket | ||||
|  | ||||
| ```bash | ||||
| nc -U /tmp/vmhandler.sock | ||||
| ``` | ||||
|  | ||||
| ### Using TCP | ||||
|  | ||||
| ```bash | ||||
| telnet localhost 8024 | ||||
| ``` | ||||
|  | ||||
| ## Authentication | ||||
|  | ||||
| When you connect, you'll need to authenticate with the secret: | ||||
|  | ||||
| ``` | ||||
| !!auth secret:1234 | ||||
| ``` | ||||
|  | ||||
| ## Available Commands | ||||
|  | ||||
| Once authenticated, you can use the following commands: | ||||
|  | ||||
| ``` | ||||
| !!vm.define name:'test_vm' cpu:4 memory:'8GB' storage:'100GB' | ||||
| !!vm.start name:'test_vm' | ||||
| !!vm.stop name:'test_vm' | ||||
| !!vm.disk_add name:'test_vm' size:'50GB' type:'SSD' | ||||
| !!vm.list | ||||
| !!vm.status name:'test_vm' | ||||
| !!vm.delete name:'test_vm' force:true | ||||
| ``` | ||||
|  | ||||
| ## Example Session | ||||
|  | ||||
| Here's an example session: | ||||
|  | ||||
| ``` | ||||
| $ telnet localhost 8024 | ||||
| Connected to localhost. | ||||
| Escape character is '^]'. | ||||
|  ** Welcome: you are not authenticated, provide secret. | ||||
| !!auth secret:1234 | ||||
|  | ||||
|  ** Welcome: you are authenticated. | ||||
| !!vm.define name:'test_vm' cpu:4 memory:'8GB' storage:'100GB' | ||||
| VM 'test_vm' defined successfully with 4 CPU, 8GB memory, and 100GB storage | ||||
|  | ||||
| !!vm.start name:'test_vm' | ||||
| VM 'test_vm' started successfully | ||||
|  | ||||
| !!vm.disk_add name:'test_vm' size:'50GB' type:'SSD' | ||||
| Added 50GB SSD disk to VM 'test_vm' | ||||
|  | ||||
| !!vm.status name:'test_vm' | ||||
| VM 'test_vm' status: | ||||
| - Status: running | ||||
| - CPU: 4 | ||||
| - Memory: 8GB | ||||
| - Storage: 100GB | ||||
| - Attached disks: | ||||
|   1. 50GB SSD | ||||
|  | ||||
| !!vm.list | ||||
| Defined VMs: | ||||
| - test_vm (running): 4 CPU, 8GB memory, 100GB storage | ||||
|   Attached disks: | ||||
|   1. 50GB SSD | ||||
|  | ||||
| !!vm.stop name:'test_vm' | ||||
| VM 'test_vm' stopped successfully | ||||
|  | ||||
| !!vm.delete name:'test_vm' | ||||
| VM 'test_vm' deleted successfully | ||||
|  | ||||
| !!quit | ||||
| Goodbye! | ||||
| Connection closed by foreign host. | ||||
| ``` | ||||
|  | ||||
| ## Other Commands | ||||
|  | ||||
| - `!!help`, `h`, or `?` - Show help | ||||
| - `!!interactive` or `!!i` - Toggle interactive mode (with colors) | ||||
| - `!!quit`, `!!exit`, or `q` - Disconnect from server | ||||
|  | ||||
| ## How It Works | ||||
|  | ||||
| 1. The `main.go` file creates a HandlerFactory and registers the VM handler | ||||
| 2. It starts a telnet server that uses the HandlerFactory to process commands | ||||
| 3. When a client connects and sends a heroscript command, the server: | ||||
|    - Parses the command to determine the actor and action | ||||
|    - Calls the appropriate method on the VM handler | ||||
|    - Returns the result to the client | ||||
|  | ||||
| ## Extending the Example | ||||
|  | ||||
| You can extend this example by: | ||||
|  | ||||
| 1. Adding more methods to the VM handler | ||||
| 2. Creating new handlers for different actors | ||||
| 3. Registering multiple handlers with the HandlerFactory | ||||
							
								
								
									
										276
									
								
								_pkg2_dont_use/heroscript/cmd/vmhandler/tutorial.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										276
									
								
								_pkg2_dont_use/heroscript/cmd/vmhandler/tutorial.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,276 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"time" | ||||
|  | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/handlerfactory" | ||||
| ) | ||||
|  | ||||
| // runTutorial runs an interactive tutorial demonstrating the VM handler | ||||
| func runTutorial() { | ||||
| 	fmt.Println("=== VM Handler Tutorial ===") | ||||
| 	fmt.Println("This tutorial will demonstrate how to use the VM handler with heroscript commands.") | ||||
| 	fmt.Println("Press Enter to continue through each step...") | ||||
| 	waitForEnter() | ||||
|  | ||||
| 	// Create a new handler factory | ||||
| 	fmt.Println("\nStep 1: Create a new HandlerFactory") | ||||
| 	fmt.Println("factory := handlerfactory.NewHandlerFactory()") | ||||
| 	factory := handlerfactory.NewHandlerFactory() | ||||
| 	waitForEnter() | ||||
|  | ||||
| 	// Create a VM handler | ||||
| 	fmt.Println("\nStep 2: Create a VM handler") | ||||
| 	fmt.Println("vmHandler := NewVMHandler()") | ||||
| 	vmHandler := NewVMHandler() | ||||
| 	waitForEnter() | ||||
|  | ||||
| 	// Register the VM handler with the factory | ||||
| 	fmt.Println("\nStep 3: Register the VM handler with the factory") | ||||
| 	fmt.Println("factory.RegisterHandler(vmHandler)") | ||||
| 	err := factory.RegisterHandler(vmHandler) | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Error: %v\n", err) | ||||
| 		return | ||||
| 	} | ||||
| 	fmt.Println("Handler registered successfully!") | ||||
| 	waitForEnter() | ||||
|  | ||||
| 	// Show available actions | ||||
| 	fmt.Println("\nStep 4: List available actions for the VM handler") | ||||
| 	actions := factory.GetSupportedActions() | ||||
| 	fmt.Println("Supported actions for 'vm' actor:") | ||||
| 	for _, action := range actions["vm"] { | ||||
| 		fmt.Printf("- %s\n", action) | ||||
| 	} | ||||
| 	waitForEnter() | ||||
|  | ||||
| 	// 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'` | ||||
| 	fmt.Println("\nCommand:") | ||||
| 	fmt.Println(defineScript) | ||||
| 	fmt.Println("\nProcessing...") | ||||
| 	time.Sleep(1 * time.Second) | ||||
| 	result, err := factory.ProcessHeroscript(defineScript) | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Error: %v\n", err) | ||||
| 	} else { | ||||
| 		fmt.Printf("Result: %s\n", result) | ||||
| 	} | ||||
| 	waitForEnter() | ||||
|  | ||||
| 	// Start the VM | ||||
| 	startScript := `!!vm.start name:'tutorial_vm'` | ||||
| 	fmt.Println("\nCommand:") | ||||
| 	fmt.Println(startScript) | ||||
| 	fmt.Println("\nProcessing...") | ||||
| 	time.Sleep(1 * time.Second) | ||||
| 	result, err = factory.ProcessHeroscript(startScript) | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Error: %v\n", err) | ||||
| 	} else { | ||||
| 		fmt.Printf("Result: %s\n", result) | ||||
| 	} | ||||
| 	waitForEnter() | ||||
|  | ||||
| 	// Add a disk | ||||
| 	diskAddScript := `!!vm.disk_add name:'tutorial_vm' size:'20GB' type:'SSD'` | ||||
| 	fmt.Println("\nCommand:") | ||||
| 	fmt.Println(diskAddScript) | ||||
| 	fmt.Println("\nProcessing...") | ||||
| 	time.Sleep(1 * time.Second) | ||||
| 	result, err = factory.ProcessHeroscript(diskAddScript) | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Error: %v\n", err) | ||||
| 	} else { | ||||
| 		fmt.Printf("Result: %s\n", result) | ||||
| 	} | ||||
| 	waitForEnter() | ||||
|  | ||||
| 	// Check VM status | ||||
| 	statusScript := `!!vm.status name:'tutorial_vm'` | ||||
| 	fmt.Println("\nCommand:") | ||||
| 	fmt.Println(statusScript) | ||||
| 	fmt.Println("\nProcessing...") | ||||
| 	time.Sleep(1 * time.Second) | ||||
| 	result, err = factory.ProcessHeroscript(statusScript) | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Error: %v\n", err) | ||||
| 	} else { | ||||
| 		fmt.Printf("Result: %s\n", result) | ||||
| 	} | ||||
| 	waitForEnter() | ||||
|  | ||||
| 	// List all VMs | ||||
| 	listScript := `!!vm.list` | ||||
| 	fmt.Println("\nCommand:") | ||||
| 	fmt.Println(listScript) | ||||
| 	fmt.Println("\nProcessing...") | ||||
| 	time.Sleep(1 * time.Second) | ||||
| 	result, err = factory.ProcessHeroscript(listScript) | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Error: %v\n", err) | ||||
| 	} else { | ||||
| 		fmt.Printf("Result: %s\n", result) | ||||
| 	} | ||||
| 	waitForEnter() | ||||
|  | ||||
| 	// Stop the VM | ||||
| 	stopScript := `!!vm.stop name:'tutorial_vm'` | ||||
| 	fmt.Println("\nCommand:") | ||||
| 	fmt.Println(stopScript) | ||||
| 	fmt.Println("\nProcessing...") | ||||
| 	time.Sleep(1 * time.Second) | ||||
| 	result, err = factory.ProcessHeroscript(stopScript) | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Error: %v\n", err) | ||||
| 	} else { | ||||
| 		fmt.Printf("Result: %s\n", result) | ||||
| 	} | ||||
| 	waitForEnter() | ||||
|  | ||||
| 	// Delete the VM | ||||
| 	deleteScript := `!!vm.delete name:'tutorial_vm'` | ||||
| 	fmt.Println("\nCommand:") | ||||
| 	fmt.Println(deleteScript) | ||||
| 	fmt.Println("\nProcessing...") | ||||
| 	time.Sleep(1 * time.Second) | ||||
| 	result, err = factory.ProcessHeroscript(deleteScript) | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Error: %v\n", err) | ||||
| 	} else { | ||||
| 		fmt.Printf("Result: %s\n", result) | ||||
| 	} | ||||
| 	waitForEnter() | ||||
|  | ||||
| 	// Try an invalid command | ||||
| 	invalidScript := `!!vm.invalid name:'tutorial_vm'` | ||||
| 	fmt.Println("\nInvalid Command:") | ||||
| 	fmt.Println(invalidScript) | ||||
| 	fmt.Println("\nProcessing...") | ||||
| 	time.Sleep(1 * time.Second) | ||||
| 	result, err = factory.ProcessHeroscript(invalidScript) | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Error: %v\n", err) | ||||
| 	} else { | ||||
| 		fmt.Printf("Result: %s\n", result) | ||||
| 	} | ||||
| 	waitForEnter() | ||||
|  | ||||
| 	// Conclusion | ||||
| 	fmt.Println("\nTutorial Complete!") | ||||
| 	fmt.Println("You've seen how to:") | ||||
| 	fmt.Println("1. Create a HandlerFactory") | ||||
| 	fmt.Println("2. Register a VM handler") | ||||
| 	fmt.Println("3. Process various heroscript commands") | ||||
| 	fmt.Println("\nTo run the full telnet server example, execute:") | ||||
| 	fmt.Println("go run main.go vm_handler.go") | ||||
| 	fmt.Println("\nPress Enter to exit the tutorial...") | ||||
| 	waitForEnter() | ||||
| } | ||||
|  | ||||
| // waitForEnter waits for the user to press Enter | ||||
| func waitForEnter() { | ||||
| 	reader := bufio.NewReader(os.Stdin) | ||||
| 	reader.ReadString('\n') | ||||
| } | ||||
|  | ||||
| // VMTutorial contains the tutorial text for the VM handler | ||||
| const VMTutorial = ` | ||||
| VM Handler Tutorial | ||||
| ================== | ||||
|  | ||||
| The VM handler provides a set of commands to manage virtual machines through heroscript commands. | ||||
|  | ||||
| Available VM commands: | ||||
|   !!vm.define name:test_vm cpu:4 memory:8GB storage:100GB | ||||
|   !!vm.start name:test_vm | ||||
|   !!vm.stop name:test_vm | ||||
|   !!vm.disk_add name:test_vm size:50GB type:SSD | ||||
|   !!vm.list | ||||
|   !!vm.status name:test_vm | ||||
|   !!vm.delete name:test_vm force:true | ||||
|  | ||||
| Authentication secret: 1234 | ||||
|  | ||||
| Command Details: | ||||
| -------------- | ||||
| 1. define - Create a new VM with specified resources | ||||
|    Parameters: | ||||
|    - name: (required) Name of the VM | ||||
|    - cpu: (optional) Number of CPUs, default: 1 | ||||
|    - memory: (optional) Memory size, default: 1GB | ||||
|    - storage: (optional) Storage size, default: 10GB | ||||
|    - description: (optional) Description of the VM | ||||
|  | ||||
| 2. start - Start a VM | ||||
|    Parameters: | ||||
|    - name: (required) Name of the VM to start | ||||
|  | ||||
| 3. stop - Stop a running VM | ||||
|    Parameters: | ||||
|    - name: (required) Name of the VM to stop | ||||
|  | ||||
| 4. disk_add - Add a disk to a VM | ||||
|    Parameters: | ||||
|    - name: (required) Name of the VM | ||||
|    - size: (optional) Size of the disk, default: 10GB | ||||
|    - type: (optional) Type of disk (SSD, HDD), default: HDD | ||||
|  | ||||
| 5. list - List all VMs | ||||
|  | ||||
| 6. status - Show status of a VM | ||||
|    Parameters: | ||||
|    - name: (required) Name of the VM | ||||
|  | ||||
| 7. delete - Delete a VM | ||||
|    Parameters: | ||||
|    - name: (required) Name of the VM | ||||
|    - force: (optional) Force deletion even if VM is running, default: false | ||||
|  | ||||
| 8. help - Show this help message | ||||
|  | ||||
| Examples: | ||||
| -------- | ||||
| 1. Create a new VM: | ||||
|    !!vm.define name:webserver cpu:2 memory:4GB storage:50GB description:'Web server VM' | ||||
|  | ||||
| 2. Start the VM: | ||||
|    !!vm.start name:webserver | ||||
|  | ||||
| 3. Add an SSD disk: | ||||
|    !!vm.disk_add name:webserver size:100GB type:SSD | ||||
|  | ||||
| 4. Check VM status: | ||||
|    !!vm.status name:webserver | ||||
|  | ||||
| 5. List all VMs: | ||||
|    !!vm.list | ||||
|  | ||||
| 6. Stop the VM: | ||||
|    !!vm.stop name:webserver | ||||
|  | ||||
| 7. Delete the VM: | ||||
|    !!vm.delete name:webserver force:true | ||||
| ` | ||||
|  | ||||
| // addTutorialCommand adds the tutorial command to the main function | ||||
| func addTutorialCommand() { | ||||
| 	// Check command line arguments | ||||
| 	if len(os.Args) > 1 && os.Args[1] == "tutorial" { | ||||
| 		runTutorial() | ||||
| 		os.Exit(0) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // GetVMTutorial returns the VM handler tutorial text | ||||
| func GetVMTutorial() string { | ||||
| 	return VMTutorial | ||||
| } | ||||
							
								
								
									
										285
									
								
								_pkg2_dont_use/heroscript/cmd/vmhandler/vm_handler.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										285
									
								
								_pkg2_dont_use/heroscript/cmd/vmhandler/vm_handler.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,285 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
|  | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/handlerfactory" | ||||
| ) | ||||
|  | ||||
| // VMHandler handles VM-related actions | ||||
| type VMHandler struct { | ||||
| 	handlerfactory.BaseHandler | ||||
| 	vms map[string]*VM | ||||
| } | ||||
|  | ||||
| // VM represents a virtual machine | ||||
| type VM struct { | ||||
| 	Name        string | ||||
| 	CPU         int | ||||
| 	Memory      string | ||||
| 	Storage     string | ||||
| 	Description string | ||||
| 	Running     bool | ||||
| 	Disks       []Disk | ||||
| } | ||||
|  | ||||
| // Disk represents a disk attached to a VM | ||||
| type Disk struct { | ||||
| 	Size string | ||||
| 	Type string | ||||
| } | ||||
|  | ||||
| // NewVMHandler creates a new VM handler | ||||
| func NewVMHandler() *VMHandler { | ||||
| 	return &VMHandler{ | ||||
| 		BaseHandler: handlerfactory.BaseHandler{ | ||||
| 			ActorName: "vm", | ||||
| 		}, | ||||
| 		vms: make(map[string]*VM), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Define handles the vm.define action | ||||
| func (h *VMHandler) Define(script string) string { | ||||
| 	params, err := h.ParseParams(script) | ||||
| 	if err != nil { | ||||
| 		return fmt.Sprintf("Error parsing parameters: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	name := params.Get("name") | ||||
| 	if name == "" { | ||||
| 		return "Error: VM name is required" | ||||
| 	} | ||||
|  | ||||
| 	// Check if VM already exists | ||||
| 	if _, exists := h.vms[name]; exists { | ||||
| 		return fmt.Sprintf("Error: VM '%s' already exists", name) | ||||
| 	} | ||||
|  | ||||
| 	// Create new VM | ||||
| 	cpu := params.GetIntDefault("cpu", 1) | ||||
| 	memory := params.Get("memory") | ||||
| 	if memory == "" { | ||||
| 		memory = "1GB" | ||||
| 	} | ||||
| 	storage := params.Get("storage") | ||||
| 	if storage == "" { | ||||
| 		storage = "10GB" | ||||
| 	} | ||||
| 	description := params.Get("description") | ||||
|  | ||||
| 	vm := &VM{ | ||||
| 		Name:        name, | ||||
| 		CPU:         cpu, | ||||
| 		Memory:      memory, | ||||
| 		Storage:     storage, | ||||
| 		Description: description, | ||||
| 		Running:     false, | ||||
| 		Disks:       []Disk{}, | ||||
| 	} | ||||
|  | ||||
| 	// Add VM to map | ||||
| 	h.vms[name] = vm | ||||
|  | ||||
| 	return fmt.Sprintf("VM '%s' defined successfully with %d CPU, %s memory, and %s storage", | ||||
| 		name, cpu, memory, storage) | ||||
| } | ||||
|  | ||||
| // Start handles the vm.start action | ||||
| func (h *VMHandler) Start(script string) string { | ||||
| 	params, err := h.ParseParams(script) | ||||
| 	if err != nil { | ||||
| 		return fmt.Sprintf("Error parsing parameters: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	name := params.Get("name") | ||||
| 	if name == "" { | ||||
| 		return "Error: VM name is required" | ||||
| 	} | ||||
|  | ||||
| 	// Find VM | ||||
| 	vm, exists := h.vms[name] | ||||
| 	if !exists { | ||||
| 		return fmt.Sprintf("Error: VM '%s' not found", name) | ||||
| 	} | ||||
|  | ||||
| 	// Start VM | ||||
| 	if vm.Running { | ||||
| 		return fmt.Sprintf("VM '%s' is already running", name) | ||||
| 	} | ||||
|  | ||||
| 	vm.Running = true | ||||
| 	return fmt.Sprintf("VM '%s' started successfully", name) | ||||
| } | ||||
|  | ||||
| // Stop handles the vm.stop action | ||||
| func (h *VMHandler) Stop(script string) string { | ||||
| 	params, err := h.ParseParams(script) | ||||
| 	if err != nil { | ||||
| 		return fmt.Sprintf("Error parsing parameters: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	name := params.Get("name") | ||||
| 	if name == "" { | ||||
| 		return "Error: VM name is required" | ||||
| 	} | ||||
|  | ||||
| 	// Find VM | ||||
| 	vm, exists := h.vms[name] | ||||
| 	if !exists { | ||||
| 		return fmt.Sprintf("Error: VM '%s' not found", name) | ||||
| 	} | ||||
|  | ||||
| 	// Stop VM | ||||
| 	if !vm.Running { | ||||
| 		return fmt.Sprintf("VM '%s' is already stopped", name) | ||||
| 	} | ||||
|  | ||||
| 	vm.Running = false | ||||
| 	return fmt.Sprintf("VM '%s' stopped successfully", name) | ||||
| } | ||||
|  | ||||
| // DiskAdd handles the vm.disk_add action | ||||
| func (h *VMHandler) DiskAdd(script string) string { | ||||
| 	params, err := h.ParseParams(script) | ||||
| 	if err != nil { | ||||
| 		return fmt.Sprintf("Error parsing parameters: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	name := params.Get("name") | ||||
| 	if name == "" { | ||||
| 		return "Error: VM name is required" | ||||
| 	} | ||||
|  | ||||
| 	// Find VM | ||||
| 	vm, exists := h.vms[name] | ||||
| 	if !exists { | ||||
| 		return fmt.Sprintf("Error: VM '%s' not found", name) | ||||
| 	} | ||||
|  | ||||
| 	// Add disk | ||||
| 	size := params.Get("size") | ||||
| 	if size == "" { | ||||
| 		size = "10GB" | ||||
| 	} | ||||
| 	diskType := params.Get("type") | ||||
| 	if diskType == "" { | ||||
| 		diskType = "HDD" | ||||
| 	} | ||||
|  | ||||
| 	disk := Disk{ | ||||
| 		Size: size, | ||||
| 		Type: diskType, | ||||
| 	} | ||||
|  | ||||
| 	vm.Disks = append(vm.Disks, disk) | ||||
| 	return fmt.Sprintf("Added %s %s disk to VM '%s'", size, diskType, name) | ||||
| } | ||||
|  | ||||
| // Delete handles the vm.delete action | ||||
| func (h *VMHandler) Delete(script string) string { | ||||
| 	params, err := h.ParseParams(script) | ||||
| 	if err != nil { | ||||
| 		return fmt.Sprintf("Error parsing parameters: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	name := params.Get("name") | ||||
| 	if name == "" { | ||||
| 		return "Error: VM name is required" | ||||
| 	} | ||||
|  | ||||
| 	// Find VM | ||||
| 	vm, exists := h.vms[name] | ||||
| 	if !exists { | ||||
| 		return fmt.Sprintf("Error: VM '%s' not found", name) | ||||
| 	} | ||||
|  | ||||
| 	// Check if VM is running and force flag is not set | ||||
| 	if vm.Running && !params.GetBool("force") { | ||||
| 		return fmt.Sprintf("Error: VM '%s' is running. Use force:true to delete anyway", name) | ||||
| 	} | ||||
|  | ||||
| 	// Delete VM | ||||
| 	delete(h.vms, name) | ||||
| 	return fmt.Sprintf("VM '%s' deleted successfully", name) | ||||
| } | ||||
|  | ||||
| // List handles the vm.list action | ||||
| func (h *VMHandler) List(script string) string { | ||||
| 	if len(h.vms) == 0 { | ||||
| 		return "No VMs defined" | ||||
| 	} | ||||
|  | ||||
| 	var result strings.Builder | ||||
| 	result.WriteString("Defined VMs:\n") | ||||
|  | ||||
| 	for _, vm := range h.vms { | ||||
| 		status := "stopped" | ||||
| 		if vm.Running { | ||||
| 			status = "running" | ||||
| 		} | ||||
|  | ||||
| 		result.WriteString(fmt.Sprintf("- %s (%s): %d CPU, %s memory, %s storage\n", | ||||
| 			vm.Name, status, vm.CPU, vm.Memory, vm.Storage)) | ||||
|  | ||||
| 		if len(vm.Disks) > 0 { | ||||
| 			result.WriteString("  Attached disks:\n") | ||||
| 			for i, disk := range vm.Disks { | ||||
| 				result.WriteString(fmt.Sprintf("  %d. %s %s\n", i+1, disk.Size, disk.Type)) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return result.String() | ||||
| } | ||||
|  | ||||
| // Help handles the vm.help action | ||||
| func (h *VMHandler) Help(script string) string { | ||||
| 	return GetVMTutorial() | ||||
| } | ||||
|  | ||||
| // Status handles the vm.status action | ||||
| func (h *VMHandler) Status(script string) string { | ||||
| 	params, err := h.ParseParams(script) | ||||
| 	if err != nil { | ||||
| 		return fmt.Sprintf("Error parsing parameters: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	name := params.Get("name") | ||||
| 	if name == "" { | ||||
| 		return "Error: VM name is required" | ||||
| 	} | ||||
|  | ||||
| 	// Find VM | ||||
| 	vm, exists := h.vms[name] | ||||
| 	if !exists { | ||||
| 		return fmt.Sprintf("Error: VM '%s' not found", name) | ||||
| 	} | ||||
|  | ||||
| 	// Return VM status | ||||
| 	status := "stopped" | ||||
| 	if vm.Running { | ||||
| 		status = "running" | ||||
| 	} | ||||
|  | ||||
| 	var result strings.Builder | ||||
| 	result.WriteString(fmt.Sprintf("VM '%s' status:\n", name)) | ||||
| 	result.WriteString(fmt.Sprintf("- Status: %s\n", status)) | ||||
| 	result.WriteString(fmt.Sprintf("- CPU: %d\n", vm.CPU)) | ||||
| 	result.WriteString(fmt.Sprintf("- Memory: %s\n", vm.Memory)) | ||||
| 	result.WriteString(fmt.Sprintf("- Storage: %s\n", vm.Storage)) | ||||
|  | ||||
| 	if vm.Description != "" { | ||||
| 		result.WriteString(fmt.Sprintf("- Description: %s\n", vm.Description)) | ||||
| 	} | ||||
|  | ||||
| 	if len(vm.Disks) > 0 { | ||||
| 		result.WriteString("- Attached disks:\n") | ||||
| 		for i, disk := range vm.Disks { | ||||
| 			result.WriteString(fmt.Sprintf("  %d. %s %s\n", i+1, disk.Size, disk.Type)) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return result.String() | ||||
| } | ||||
							
								
								
									
										75
									
								
								_pkg2_dont_use/heroscript/cmd/vmhandler/vm_handler_server.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								_pkg2_dont_use/heroscript/cmd/vmhandler/vm_handler_server.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"os/signal" | ||||
| 	"path/filepath" | ||||
| 	"syscall" | ||||
|  | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/handlerfactory" | ||||
| ) | ||||
|  | ||||
| // The tutorial functions are defined in tutorial.go | ||||
|  | ||||
| func main() { | ||||
| 	// Check if tutorial mode is requested | ||||
| 	addTutorialCommand() | ||||
|  | ||||
| 	fmt.Println("Starting VM Handler Example") | ||||
|  | ||||
| 	// Create a new handler factory | ||||
| 	factory := handlerfactory.NewHandlerFactory() | ||||
|  | ||||
| 	// Create and register the VM handler | ||||
| 	vmHandler := NewVMHandler() | ||||
| 	err := factory.RegisterHandler(vmHandler) | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("Failed to register VM handler: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	// Create a telnet server with the handler factory | ||||
| 	server := handlerfactory.NewTelnetServer(factory, "1234") | ||||
|  | ||||
| 	// Create socket directory if it doesn't exist | ||||
| 	socketDir := "/tmp" | ||||
| 	err = os.MkdirAll(socketDir, 0755) | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("Failed to create socket directory: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	// Start the telnet server on a Unix socket | ||||
| 	socketPath := filepath.Join(socketDir, "vmhandler.sock") | ||||
| 	err = server.Start(socketPath) | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("Failed to start telnet server: %v", err) | ||||
| 	} | ||||
| 	fmt.Printf("Telnet server started on socket: %s\n", socketPath) | ||||
| 	fmt.Printf("Connect with: nc -U %s\n", socketPath) | ||||
|  | ||||
| 	// Also start on TCP port for easier access | ||||
| 	err = server.StartTCP("localhost:8024") | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("Failed to start TCP telnet server: %v", err) | ||||
| 	} | ||||
| 	fmt.Println("Telnet server started on TCP: localhost:8024") | ||||
| 	fmt.Println("Connect with: telnet localhost 8024") | ||||
|  | ||||
| 	// Print available commands | ||||
| 	fmt.Println("\nVM Handler started. Type '!!vm.help' to see available commands.") | ||||
| 	fmt.Println("Authentication secret: 1234") | ||||
|  | ||||
| 	// Wait for interrupt signal | ||||
| 	sigChan := make(chan os.Signal, 1) | ||||
| 	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) | ||||
| 	<-sigChan | ||||
|  | ||||
| 	// Stop the server | ||||
| 	fmt.Println("Stopping server...") | ||||
| 	err = server.Stop() | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("Failed to stop telnet server: %v", err) | ||||
| 	} | ||||
| 	fmt.Println("Telnet server stopped") | ||||
| } | ||||
		Reference in New Issue
	
	Block a user