rcon-cli/main.go
Augusto Dwenger J. 3e532d98c5
Switch from SimpleClient to MinecraftClient
Minecrafts server implementation doesn't behave like valves and the
SimpleClient followes strictly the documentation from valve.

Switching the implementation I also refactored the code so that future
implementation changes won't change mutch due to the usage of an
interface.
2022-03-05 15:54:32 +01:00

162 lines
3.3 KiB
Go

package main
import (
"bufio"
"fmt"
"net"
"os"
"strings"
"github.com/hamburghammer/grcon"
"github.com/hamburghammer/grcon/client"
"github.com/hamburghammer/grcon/util"
flags "github.com/spf13/pflag"
)
const (
defaultHost = "localhost"
defaultPort = "25575"
defaultPassword = ""
envVarPrefix = "RCON_CLI_"
)
// vars holding the parsed configuration
var (
host string
port string
password string
help bool
)
func main() {
commands, _ := parseArgs(os.Args[1:])
loadEnvIfNotSet()
if help {
printHelp()
os.Exit(0)
return
}
err := run(strings.Join(commands, " "))
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
}
func parseArgs(args []string) ([]string, error) {
flags.StringVar(&host, "host", defaultHost, "RCON server's hostname.")
flags.StringVar(&port, "port", defaultPort, "RCON server's port.")
flags.StringVar(&password, "password", defaultPassword, "RCON server's password.")
flags.BoolVarP(&help, "help", "h", false, "Prints this help message and exits.")
err := flags.CommandLine.Parse(args)
if err != nil {
return []string{}, err
}
command := flags.Args()
return command, nil
}
func loadEnvIfNotSet() {
envHost := os.Getenv(fmt.Sprintf("%sHOST", envVarPrefix))
if envHost != "" && host == defaultHost {
host = envHost
}
envPort := os.Getenv(fmt.Sprintf("%sPORT", envVarPrefix))
if envPort != "" && port == defaultPort {
port = envPort
}
envPassword := os.Getenv(fmt.Sprintf("%sPASSWORD", envVarPrefix))
if envPassword != "" && password == defaultPassword {
password = envPassword
}
}
func run(cmd string) error {
hostPort := net.JoinHostPort(host, port)
conn, err := net.Dial("tcp", hostPort)
if err != nil {
return err
}
defer conn.Close()
remoteConsole := grcon.NewRemoteConsole(conn)
rconClient := client.NewMinecraftClient(remoteConsole, util.GenerateRequestId)
err = rconClient.Auth(password)
if err != nil {
return fmt.Errorf("failed to authenticate: %w", err)
}
if len(cmd) == 0 {
err = executeInteractive(rconClient)
} else {
resp, err := execute(cmd, rconClient)
if err != nil {
return err
}
fmt.Println(resp)
}
return err
}
func printHelp() {
fmt.Println(`rcon-cli is a CLI to interact with a RCON server.
It can be run in an interactive mode or to execute a single command.
USAGE:
rcon-cli [FLAGS] [RCON command ...]
FLAGS:`)
flags.PrintDefaults()
fmt.Printf(`
ENVIRONMENT VARIABLE:
All flags can be set through the flag name in capslock with the %s prefix (see examples).
Flags have allways priority over env vars!
EXAMPLES:
rcon-cli --host 127.0.0.1 --port 25575
rcon-cli --password admin123 stop
%sPORT=25575 rcon-cli stop
`, envVarPrefix, envVarPrefix)
}
func executeInteractive(remoteConsole client.Client) error {
scanner := bufio.NewScanner(os.Stdin)
fmt.Println("To quit the session type 'exit'.")
for scanner.Scan() {
fmt.Print("> ")
cmd := scanner.Text()
if cmd == "exit" {
return nil
}
resp, err := execute(cmd, remoteConsole)
if err != nil {
return err
}
fmt.Println(resp)
}
if err := scanner.Err(); err != nil {
return fmt.Errorf("reading standard input: %w", err)
}
return nil
}
func execute(cmd string, client client.Client) (string, error) {
response, err := client.Exec(cmd)
if err != nil {
return "", fmt.Errorf("failed to execute command: %w", err)
}
return string(response), nil
}