03a281d009
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
82 lines
2.9 KiB
Go
82 lines
2.9 KiB
Go
// Package rcon provides pluggable RCON adapters. Games speak different
|
|
// dialects — Source RCON (Counter-Strike, Minecraft with Mojang auth),
|
|
// telnet line protocol (7 Days to Die), HTTP admin APIs (some community
|
|
// implementations), stdin-pipe for headless servers without a network
|
|
// surface. The Agent picks an adapter based on the module manifest's
|
|
// `rcon.adapter` field.
|
|
package rcon
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"time"
|
|
)
|
|
|
|
// Client is a connected RCON session. Exec runs one command and returns its
|
|
// raw text response. Clients must be safe for concurrent Exec calls — the
|
|
// poll loop and a future ad-hoc-command path both need to call through the
|
|
// same session.
|
|
type Client interface {
|
|
Exec(ctx context.Context, cmd string) (string, error)
|
|
Close() error
|
|
}
|
|
|
|
// DialOptions configures one RCON connection attempt.
|
|
type DialOptions struct {
|
|
Host string
|
|
Port int
|
|
Password string
|
|
ConnectTimeout time.Duration
|
|
// ReadIdle is how long to wait with no new bytes before treating an Exec
|
|
// response as complete. Telnet has no packet framing, so this heuristic
|
|
// is needed; Source RCON overrides it to 0 (ignored).
|
|
ReadIdle time.Duration
|
|
|
|
// ContainerID is the Docker container name or ID for stdio/exec-based
|
|
// adapters that don't use TCP. Ignored by telnet/source_rcon.
|
|
ContainerID string
|
|
// Stdio is the backend that knows how to attach to a container's
|
|
// stdin/stdout. Provided by the Docker runtime when the adapter is
|
|
// "stdio". Nil for TCP adapters.
|
|
Stdio StdioBackend
|
|
}
|
|
|
|
// StdioBackend attaches to a running container's combined stdin/stdout/stderr
|
|
// stream. Needed by the stdio adapter for games whose only admin console is
|
|
// stdin (Valheim, Terraria, Barotrauma, Enshrouded, Sons Of The Forest).
|
|
//
|
|
// Returned ReadWriteCloser writes go to the container's stdin; reads are the
|
|
// demux-multiplexed stdout+stderr. Close shuts down the hijacked connection.
|
|
type StdioBackend interface {
|
|
AttachStdio(ctx context.Context, containerID string) (io.ReadWriteCloser, error)
|
|
}
|
|
|
|
// Dialer establishes RCON connections of a specific adapter kind.
|
|
type Dialer interface {
|
|
Dial(ctx context.Context, opts DialOptions) (Client, error)
|
|
Name() string
|
|
}
|
|
|
|
// DialerFor returns the dialer for the given adapter id, or an error if the
|
|
// adapter is unknown. Adapter ids come directly from the module manifest's
|
|
// `rcon.adapter` field.
|
|
func DialerFor(adapter string) (Dialer, error) {
|
|
switch adapter {
|
|
case "telnet":
|
|
return &TelnetDialer{}, nil
|
|
case "source_rcon":
|
|
return &SourceDialer{}, nil
|
|
case "stdio":
|
|
return &StdioDialer{}, nil
|
|
case "websocket_rcon":
|
|
return &WebSocketDialer{}, nil
|
|
case "docker_exec_rcon":
|
|
return &DockerExecDialer{}, nil
|
|
case "be_rcon":
|
|
return &BattlEyeDialer{}, nil
|
|
default:
|
|
return nil, fmt.Errorf("unknown rcon adapter %q (known: telnet, source_rcon, docker_exec_rcon, stdio, websocket_rcon, be_rcon)", adapter)
|
|
}
|
|
}
|