102 lines
2.3 KiB
Go
102 lines
2.3 KiB
Go
// Package cps provides the command processing system.
|
|
package cps
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
type Command struct {
|
|
Context context.Context
|
|
Raw string // The original command passed to the agent.
|
|
Command string // Which command was invoked?
|
|
Arg string // Input string sans the leading command.
|
|
Args []string // Tokenised list of arguments.
|
|
Meta map[string]string // Sometimes you need additional information.
|
|
}
|
|
|
|
func (cmd *Command) Handle() (*Response, error) {
|
|
return handle(cmd)
|
|
}
|
|
|
|
// Parse takes a command string from an input string and parent context.
|
|
func Parse(ctx context.Context, line string) (*Command, error) {
|
|
line = strings.TrimSpace(line)
|
|
args := strings.Fields(line)
|
|
if len(args) == 0 {
|
|
return nil, errors.New("cps: no command line provided")
|
|
}
|
|
|
|
cmd := &Command{
|
|
Context: ctx,
|
|
Raw: line,
|
|
Command: strings.ToLower(args[0]),
|
|
Args: args[1:],
|
|
Meta: map[string]string{},
|
|
}
|
|
cmd.Arg = strings.TrimSpace(strings.TrimPrefix(cmd.Raw, cmd.Command))
|
|
return cmd, nil
|
|
}
|
|
|
|
// ParseBackground calls Parse(context.Background, line).
|
|
func ParseBackground(line string) (*Command, error) {
|
|
return Parse(context.Background(), line)
|
|
}
|
|
|
|
type Response struct {
|
|
Message string
|
|
Error error
|
|
}
|
|
|
|
func (r *Response) String() string {
|
|
if r == nil {
|
|
return "carrier signal lost"
|
|
}
|
|
|
|
out := ""
|
|
if r.Message != "" {
|
|
out += r.Message
|
|
} else if r.Error != nil {
|
|
out = fmt.Sprintf("Error: %s", r.Error)
|
|
}
|
|
|
|
return out
|
|
}
|
|
|
|
var registry = map[string]func(*Command) (*Response, error){}
|
|
|
|
func Register(command string, handler func(*Command) (*Response, error)) {
|
|
if _, ok := registry[command]; ok {
|
|
panic("handler for " + command + " already registered!")
|
|
}
|
|
|
|
registry[command] = handler
|
|
}
|
|
|
|
func handle(cmd *Command) (*Response, error) {
|
|
handler, ok := registry[cmd.Command]
|
|
if !ok {
|
|
err := fmt.Errorf("cps: no handler for command '%s'", cmd.Command)
|
|
return &Response{
|
|
Message: fmt.Sprintf("%s is not a recognized command", cmd.Command),
|
|
Error: err,
|
|
}, err
|
|
}
|
|
|
|
return handler(cmd)
|
|
}
|
|
|
|
func Handle(ctx context.Context, line string) (*Response, error) {
|
|
cmd, err := Parse(ctx, line)
|
|
if err != nil {
|
|
return &Response{
|
|
Message: "Unable to process message",
|
|
Error: err,
|
|
}, err
|
|
}
|
|
|
|
return cmd.Handle()
|
|
}
|