22 Commits

Author SHA1 Message Date
51e8ac85be use fs.GetArgs() 2026-02-17 16:41:42 +00:00
79d53f34da reword 2026-02-17 16:37:25 +00:00
7c5a3523bf fix install command 2026-02-17 16:34:09 +00:00
44a528e31d add v0.5.0 to CHANGELOG 2026-02-17 16:30:14 +00:00
48b23321e5 fix help usage 2026-02-17 16:26:31 +00:00
d05ed91473 fix NAME desc in help output 2026-02-17 16:13:50 +00:00
5c28c4e8b7 upd date 2026-02-17 16:10:57 +00:00
53f30981fd bump version in CHANGELOG
add note about CLI env vars
2026-02-17 16:10:09 +00:00
fce6fa43fc Reimplement the CLI with flags first package.
CLI configuration may now be managed with env vars.

improved CLI help output
2026-02-17 16:09:53 +00:00
0b9546ee0e update README 2026-02-17 16:06:58 +00:00
a55de6fe50 upd host shortflag to -H
upd readme
2026-02-17 10:25:16 +00:00
e4f3366a67 rewrite versionFromBuild() 2026-02-16 01:26:12 +00:00
0fe373d1d1 replace logrus with charmbracelet/log 2026-02-16 01:13:05 +00:00
e0668d11d9 upd go version in go.mod 2026-02-16 01:11:48 +00:00
f3853f6a4d rename taskfile version var 2026-02-16 01:04:08 +00:00
c4e2dacee9 add --version flag
ensure version is injected at build time in makefile/taskfile
2026-02-16 00:55:17 +00:00
3be7ddb36b ensure we return closer from run() 2026-02-16 00:11:50 +00:00
c22b07808f upd imgs 2026-02-15 19:37:41 +00:00
c015770c2c add v0.4.0 to CHANGELOG 2026-02-15 18:35:52 +00:00
cd15e89837 add macos target to goreleaser config 2026-02-15 18:31:25 +00:00
c3e8013c4f make the example implementation a little more useful with a timeouts map. 2026-02-15 18:29:14 +00:00
89dd2d2eb1 replace exitOnError with deferred exit function.
this ensures the closer() cleanup function is always called
2026-02-15 18:24:59 +00:00
12 changed files with 305 additions and 92 deletions

1
.gitignore vendored
View File

@@ -24,6 +24,7 @@ go.work.sum
# env file # env file
.env .env
.envrc
# Added by goreleaser init: # Added by goreleaser init:
dist/ dist/

View File

@@ -22,6 +22,7 @@ builds:
goos: goos:
- linux - linux
- windows - windows
- darwin
goarch: goarch:
- amd64 - amd64

View File

@@ -11,6 +11,30 @@ Before any major/minor/patch bump all unit tests will be run to verify they pass
- [x] - [x]
# [0.5.0] - 2026-02-17
### Added
- CLI configuration can be managed through env vars, see [Environment Variables](https://github.com/onyx-and-iris/q3rcon?tab=readme-ov-file#environment-variables) under Configuration in README.
### Changed
- The CLI now supports `--long` and `-short` style flags. Several examples in README.
- `--help` output has been improved.
# [0.4.1] - 2026-02-15
### Added
- macos build to releases
### Changed
- exitOnError() removed in favour of a [deferred exit function](https://github.com/onyx-and-iris/q3rcon/blob/cd15e8983726177d6edd985a8bf3d7f4e0d7f346/cmd/q3rcon/main.go#L21), this ensures the closer() cleanup function is always called.
- the included CLI now uses a [timeouts map](https://github.com/onyx-and-iris/q3rcon/blob/cd15e8983726177d6edd985a8bf3d7f4e0d7f346/cmd/q3rcon/main.go#L109).
- even though this is only an example implementation it should still be basically usable.
# [0.3.0] - 2025-04-05 # [0.3.0] - 2025-04-05
### Changed ### Changed

View File

@@ -17,9 +17,15 @@ Quake3 Rcon works by firing UDP packets to the game server port, responses may b
Rcon itself is insecure and each packet includes the password so I don't suggest using it remotely. If you have direct access to the server then SSH in first, then use this tool locally. Rcon itself is insecure and each packet includes the password so I don't suggest using it remotely. If you have direct access to the server then SSH in first, then use this tool locally.
## Use ---
`go get github.com/onyx-and-iris/q3rcon` ## Package
#### Use
```console
go get github.com/onyx-and-iris/q3rcon
```
```go ```go
package main package main
@@ -91,12 +97,24 @@ rcon, err := q3rcon.New(
q3rcon.WithTimeouts(timeouts)) q3rcon.WithTimeouts(timeouts))
``` ```
---
## Command line ## Command line
Pass `host`, `port` and `rconpass` as flags, for example: ### Install
```console
go install github.com/onyx-and-iris/q3rcon/cmd/q3rcon@latest
``` ```
q3rcon -h=localhost -p=30000 -r="rconpassword" "mapname"
### Configuration
#### Flags
Pass `--host`, `--port` and `--rconpass` as flags, for example:
```console
q3rcon --host=localhost --port=30000 --rconpass="rconpassword" "mapname"
``` ```
- `host` defaults to "localhost" - `host` defaults to "localhost"
@@ -105,25 +123,41 @@ q3rcon -h=localhost -p=30000 -r="rconpassword" "mapname"
Arguments following the flags will be sent as rcon commands. You may send multiple arguments. Arguments following the flags will be sent as rcon commands. You may send multiple arguments.
#### Interactive mode #### Environment Variables
example .envrc:
```bash
#!/usr/bin/env bash
export Q3RCON_HOST="localhost"
export Q3RCON_PORT=28960
export Q3RCON_RCONPASS="rconpassword"
```
### Interactive mode
Pass `interactive (-i shorthand)` flag to enable interactive mode, for example: Pass `interactive (-i shorthand)` flag to enable interactive mode, for example:
```bash ```console
q3rcon -h=localhost -p=30000 -r="rconpassword" -i q3rcon -H=localhost -p=30000 -r="rconpassword" -i
``` ```
If interactive mode is enabled, any arguments sent on the command line will be ignored. If interactive mode is enabled, any arguments sent on the command line will be ignored.
---
## Your own implementation ## Your own implementation
The included CLI is a generic implementation, while it can be used out of the box you may find that some requests result in fragmented responses. The solution is to implement your own version, adjusting the timings with the functional options as detailed above. I could have increased the default timeouts but that would add unnecessary delay for most requests, so I decided to leave those details to the users of the package. The included CLI is a generic implementation, while it can be used out of the box you may find that some requests result in fragmented responses. The solution is to implement your own version, adjusting the timings with the functional options as detailed above.
Since you can include the q3rcon package into your own package you can easily make your own modifications, for example, I added [colour to the terminal][status] and [reformatted some of the responses][mapname]. Since you can include the q3rcon package into your own CLI/package you can easily make your own modifications, for example, I added [colour to the terminal][status] and [tabulated some of the responses][mapname].
---
## Logging ## Logging
The `-loglevel` flag allows you to control the verbosity of the application's logging output. The `--loglevel` flag allows you to control the verbosity of the application's logging output.
Acceptable values for this flag are: Acceptable values for this flag are:
@@ -137,8 +171,8 @@ Acceptable values for this flag are:
For example, to set the log level to `debug`, you can use: For example, to set the log level to `debug`, you can use:
```bash ```console
q3rcon -p=28960 -r="rconpassword" -loglevel=debug -i q3rcon -H=localhost -p=28960 -r="rconpassword" -l=debug -i
``` ```
The default log level is `warn` if the flag is not specified. The default log level is `warn` if the flag is not specified.

View File

@@ -8,8 +8,8 @@ vars:
WINDOWS: '{{.BIN_DIR}}/{{.PROGRAM}}_windows_amd64.exe' WINDOWS: '{{.BIN_DIR}}/{{.PROGRAM}}_windows_amd64.exe'
LINUX: '{{.BIN_DIR}}/{{.PROGRAM}}_linux_amd64' LINUX: '{{.BIN_DIR}}/{{.PROGRAM}}_linux_amd64'
MACOS: '{{.BIN_DIR}}/{{.PROGRAM}}_darwin_amd64' MACOS: '{{.BIN_DIR}}/{{.PROGRAM}}_darwin_amd64'
GIT_COMMIT: VERSION:
sh: git log -n 1 --format=%h sh: 'git describe --tags $(git rev-list --tags --max-count=1)'
tasks: tasks:
default: default:
@@ -39,19 +39,19 @@ tasks:
build-windows: build-windows:
desc: Build the q3rcon project for Windows desc: Build the q3rcon project for Windows
cmds: cmds:
- GOOS=windows GOARCH=amd64 go build -o {{.WINDOWS}} -ldflags="-X main.Version={{.GIT_COMMIT}}" ./cmd/{{.PROGRAM}}/ - GOOS=windows GOARCH=amd64 go build -o {{.WINDOWS}} -ldflags="-X main.version={{.VERSION}}" ./cmd/{{.PROGRAM}}/
internal: true internal: true
build-linux: build-linux:
desc: Build the q3rcon project for Linux desc: Build the q3rcon project for Linux
cmds: cmds:
- GOOS=linux GOARCH=amd64 go build -o {{.LINUX}} -ldflags="-X main.Version={{.GIT_COMMIT}}" ./cmd/{{.PROGRAM}}/ - GOOS=linux GOARCH=amd64 go build -o {{.LINUX}} -ldflags="-X main.version={{.VERSION}}" ./cmd/{{.PROGRAM}}/
internal: true internal: true
build-macos: build-macos:
desc: Build the q3rcon project for macOS desc: Build the q3rcon project for macOS
cmds: cmds:
- GOOS=darwin GOARCH=amd64 go build -o {{.MACOS}} -ldflags="-X main.Version={{.GIT_COMMIT}}" ./cmd/{{.PROGRAM}}/ - GOOS=darwin GOARCH=amd64 go build -o {{.MACOS}} -ldflags="-X main.version={{.VERSION}}" ./cmd/{{.PROGRAM}}/
internal: true internal: true
test: test:

View File

@@ -2,95 +2,188 @@ package main
import ( import (
"bufio" "bufio"
"flag" "errors"
"fmt" "fmt"
"io" "io"
"os" "os"
"runtime/debug"
"strings" "strings"
"time"
"github.com/charmbracelet/log"
"github.com/peterbourgon/ff/v4"
"github.com/peterbourgon/ff/v4/ffhelp"
"github.com/onyx-and-iris/q3rcon" "github.com/onyx-and-iris/q3rcon"
log "github.com/sirupsen/logrus"
) )
func exitOnError(err error) { var version string // Version will be set at build time
_, _ = fmt.Fprintf(os.Stderr, "Error: %s\n", err)
os.Exit(1) type Flags struct {
Host string
Port int
Rconpass string
Interactive bool
LogLevel string
Version bool
}
func (f Flags) Validate() error {
if f.Port < 1024 || f.Port > 65535 {
return fmt.Errorf(
"invalid port value, got: (%d) expected: in range 1024-65535",
f.Port,
)
}
if len(f.Rconpass) < 8 {
return fmt.Errorf(
"invalid rcon password, got: (%s) expected: at least 8 characters",
f.Rconpass,
)
}
return nil
} }
func main() { func main() {
var ( var exitCode int
host string
port int
rconpass string
interactive bool
loglevel string
)
flag.StringVar(&host, "host", "localhost", "hostname of the gameserver") // Defer exit with the final exit code
flag.StringVar(&host, "h", "localhost", "hostname of the gameserver (shorthand)") defer func() {
flag.IntVar(&port, "port", 28960, "port on which the gameserver resides, default is 28960") if exitCode != 0 {
flag.IntVar(&port, "p", 28960, "port on which the gameserver resides, default is 28960 (shorthand)") os.Exit(exitCode)
flag.StringVar(&rconpass, "rconpass", os.Getenv("RCON_PASS"), "rcon password of the gameserver") }
flag.StringVar(&rconpass, "r", os.Getenv("RCON_PASS"), "rcon password of the gameserver (shorthand)") }()
flag.BoolVar(&interactive, "interactive", false, "run in interactive mode") closer, err := run()
flag.BoolVar(&interactive, "i", false, "run in interactive mode") if closer != nil {
defer closer()
flag.StringVar(&loglevel, "loglevel", "warn", "log level") }
flag.StringVar(&loglevel, "l", "warn", "log level (shorthand)")
flag.Parse()
level, err := log.ParseLevel(loglevel)
if err != nil { if err != nil {
exitOnError(fmt.Errorf("invalid log level: %s", loglevel)) log.Error(err)
} exitCode = 1
log.SetLevel(level)
if port < 1024 || port > 65535 {
exitOnError(fmt.Errorf("invalid port value, got: (%d) expected: in range 1024-65535", port))
}
if len(rconpass) < 8 {
exitOnError(fmt.Errorf("invalid rcon password, got: (%s) expected: at least 8 characters", rconpass))
}
rcon, err := connectRcon(host, port, rconpass)
if err != nil {
exitOnError(err)
}
defer rcon.Close()
if !interactive {
runCommands(flag.Args(), rcon)
return
}
fmt.Printf("Enter 'Q' to exit.\n>> ")
err = interactiveMode(rcon, os.Stdin)
if err != nil {
exitOnError(err)
} }
} }
func connectRcon(host string, port int, password string) (*q3rcon.Rcon, error) { // run executes the main logic of the application and returns a cleanup function and an error if any.
rcon, err := q3rcon.New(host, port, password) func run() (func(), error) {
if err != nil { var flags Flags
fs := ff.NewFlagSet("q3rcon - A command-line RCON client for Q3 Rcon compatible game servers")
fs.StringVar(&flags.Host, 'H', "host", "localhost", "hostname of the gameserver")
fs.IntVar(
&flags.Port,
'p',
"port",
28960,
"port on which the gameserver resides, default is 28960",
)
fs.StringVar(
&flags.Rconpass,
'r',
"rconpass",
"",
"rcon password of the gameserver",
)
fs.BoolVar(&flags.Interactive, 'i', "interactive", "run in interactive mode")
fs.StringVar(
&flags.LogLevel,
'l',
"loglevel",
"info",
"Log level (debug, info, warn, error, fatal, panic)",
)
fs.BoolVar(&flags.Version, 'v', "version", "print version information and exit")
err := ff.Parse(fs, os.Args[1:],
ff.WithEnvVarPrefix("Q3RCON"),
)
switch {
case errors.Is(err, ff.ErrHelp):
fmt.Fprintf(os.Stderr, "%s\n", ffhelp.Flags(fs, "q3rcon [flags] <rcon commands>"))
return nil, nil
case err != nil:
return nil, fmt.Errorf("failed to parse flags: %w", err)
}
if flags.Version {
fmt.Printf("q3rcon version: %s\n", versionFromBuild())
return nil, nil
}
if err := flags.Validate(); err != nil {
return nil, err return nil, err
} }
return rcon, nil
level, err := log.ParseLevel(flags.LogLevel)
if err != nil {
return nil, fmt.Errorf("invalid log level: %s", flags.LogLevel)
}
log.SetLevel(level)
client, closer, err := connectRcon(flags.Host, flags.Port, flags.Rconpass)
if err != nil {
return nil, fmt.Errorf("failed to connect to rcon: %w", err)
}
if flags.Interactive {
fmt.Printf("Enter 'Q' to exit.\n>> ")
err := interactiveMode(client, os.Stdin)
if err != nil {
return closer, fmt.Errorf("interactive mode error: %w", err)
}
return closer, nil
}
commands := fs.GetArgs()
if len(commands) == 0 {
log.Debug("no commands provided, defaulting to 'status'")
commands = append(commands, "status")
}
runCommands(client, commands)
return closer, nil
}
// versionFromBuild retrieves the version information from the build metadata.
func versionFromBuild() string {
if version != "" {
return version
}
info, ok := debug.ReadBuildInfo()
if !ok {
return "(unable to read version)"
}
return strings.Split(info.Main.Version, "-")[0]
}
func connectRcon(host string, port int, password string) (*q3rcon.Rcon, func(), error) {
client, err := q3rcon.New(host, port, password, q3rcon.WithTimeouts(map[string]time.Duration{
"map": time.Second,
"map_rotate": time.Second,
"map_restart": time.Second,
}))
if err != nil {
return nil, nil, err
}
closer := func() {
if err := client.Close(); err != nil {
log.Error(err)
}
}
return client, closer, nil
} }
// runCommands runs the commands given in the flag.Args slice. // runCommands runs the commands given in the flag.Args slice.
// If no commands are given, it defaults to running the "status" command. // If no commands are given, it defaults to running the "status" command.
func runCommands(commands []string, rcon *q3rcon.Rcon) { func runCommands(client *q3rcon.Rcon, commands []string) {
if len(commands) == 0 {
commands = append(commands, "status")
}
for _, cmd := range commands { for _, cmd := range commands {
resp, err := rcon.Send(cmd) resp, err := client.Send(cmd)
if err != nil { if err != nil {
log.Error(err) log.Error(err)
continue continue
@@ -100,7 +193,7 @@ func runCommands(commands []string, rcon *q3rcon.Rcon) {
} }
// interactiveMode continuously reads from input until a quit signal is given. // interactiveMode continuously reads from input until a quit signal is given.
func interactiveMode(rcon *q3rcon.Rcon, input io.Reader) error { func interactiveMode(client *q3rcon.Rcon, input io.Reader) error {
scanner := bufio.NewScanner(input) scanner := bufio.NewScanner(input)
for scanner.Scan() { for scanner.Scan() {
cmd := scanner.Text() cmd := scanner.Text()
@@ -108,7 +201,7 @@ func interactiveMode(rcon *q3rcon.Rcon, input io.Reader) error {
return nil return nil
} }
resp, err := rcon.Send(cmd) resp, err := client.Send(cmd)
if err != nil { if err != nil {
log.Error(err) log.Error(err)
continue continue

26
go.mod
View File

@@ -1,7 +1,27 @@
module github.com/onyx-and-iris/q3rcon module github.com/onyx-and-iris/q3rcon
go 1.23.0 go 1.25.0
require github.com/sirupsen/logrus v1.9.3 require (
github.com/charmbracelet/log v0.4.2
github.com/peterbourgon/ff/v4 v4.0.0-beta.1
github.com/sirupsen/logrus v1.9.3
)
require golang.org/x/sys v0.34.0 // indirect require (
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
github.com/charmbracelet/lipgloss v1.1.0 // indirect
github.com/charmbracelet/x/ansi v0.8.0 // indirect
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
github.com/charmbracelet/x/term v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/muesli/termenv v0.16.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
golang.org/x/sys v0.34.0 // indirect
)

44
go.sum
View File

@@ -1,16 +1,56 @@
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs=
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk=
github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
github.com/charmbracelet/log v0.4.2 h1:hYt8Qj6a8yLnvR+h7MwsJv/XvmBJXiueUcI3cIxsyig=
github.com/charmbracelet/log v0.4.2/go.mod h1:qifHGX/tc7eluv2R6pWIpyHDDrrb/AG71Pf2ysQu5nw=
github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE=
github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q=
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8=
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0=
github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/peterbourgon/ff/v4 v4.0.0-beta.1 h1:hV8qRu3V7YfiSMsBSfPfdcznAvPQd3jI5zDddSrDoUc=
github.com/peterbourgon/ff/v4 v4.0.0-beta.1/go.mod h1:onQJUKipvCyFmZ1rIYwFAh1BhPOvftb1uhvSI7krNLc=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -6,7 +6,7 @@ BIN_DIR := bin
WINDOWS=$(BIN_DIR)/$(PROGRAM)_windows_amd64.exe WINDOWS=$(BIN_DIR)/$(PROGRAM)_windows_amd64.exe
LINUX=$(BIN_DIR)/$(PROGRAM)_linux_amd64 LINUX=$(BIN_DIR)/$(PROGRAM)_linux_amd64
MACOS=$(BIN_DIR)/$(PROGRAM)_darwin_amd64 MACOS=$(BIN_DIR)/$(PROGRAM)_darwin_amd64
VERSION=$(shell git log -n 1 --format=%h) VERSION=$(shell git describe --tags $(shell git rev-list --tags --max-count=1))
.DEFAULT_GOAL := build .DEFAULT_GOAL := build

View File

@@ -140,6 +140,6 @@ func (r Rcon) listen(timeout time.Duration, respChan chan<- string, errChan chan
} }
} }
func (r Rcon) Close() { func (r Rcon) Close() error {
r.conn.Close() return r.conn.Close()
} }