8 Commits

Author SHA1 Message Date
430e9be1f7 reorder tasks 2025-02-03 18:18:10 +00:00
a27809643a add taskfile 2025-02-03 18:16:38 +00:00
485978956c send 'status' if not in interactive and no commands passed
remove interactive global var.
2025-02-03 17:26:42 +00:00
c51dba5ead add link to q3rcon-proxy 2024-11-29 04:25:56 +00:00
0bc19a718b add section 0.1.0 to CHANGELOG 2024-11-29 01:09:30 +00:00
adebc61b98 change -P flag to -r for setting rcon password
update README
2024-11-29 01:07:05 +00:00
51ff562ac4 use EqualFold 2024-11-25 19:08:02 +00:00
313d96fffa Create LICENSE 2024-11-25 03:43:02 +00:00
8 changed files with 144 additions and 64 deletions

View File

@@ -11,6 +11,12 @@ Before any major/minor/patch bump all unit tests will be run to verify they pass
- [x]
# [0.1.0] - 2024-11-29
### Changed
- `-P` flag changed to `-r` for setting rcon password. This is to disambiguate it from the port (-p) flag.
# [0.0.3] - 2024-11-24
### Changed

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 Onyx and Iris
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -93,15 +93,15 @@ rcon, err := q3rcon.New(
## Command line
Pass `host`, `port` and `password` as flags, for example:
Pass `host`, `port` and `rconpass` as flags, for example:
```
q3rcon -h=localhost -p=30000 -P="rconpassword" "mapname"
q3rcon -h=localhost -p=30000 -r="rconpassword" "mapname"
```
- `host` defaults to "localhost"
- `port` defaults to 28960
- `password` defaults to ""
- `rconpass` defaults to ""
Arguments following the flags will be sent as rcon commands. You may send multiple arguments.
@@ -110,7 +110,7 @@ Arguments following the flags will be sent as rcon commands. You may send multip
Pass `interactive (-i shorthand)` flag to enable interactive mode, for example:
```
q3rcon -h=localhost -p=30000 -P="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.
@@ -129,3 +129,10 @@ Log level may be set by passing the `-l` flag with a number from 0 up to 6 where
[status]: ./img/status.png
[mapname]: ./img/mapname.png
## Further Notes
This rcon client is fully compatible with the [Q3 Rcon Proxy][q3rcon-proxy] package.
[q3rcon-proxy]: https://github.com/onyx-and-iris/q3rcon-proxy/tree/dev

51
Taskfile.yml Normal file
View File

@@ -0,0 +1,51 @@
version: '3'
vars:
PROGRAM: q3rcon
SHELL: '{{if eq .OS "Windows_NT"}}powershell{{end}}'
BIN_DIR: bin
WINDOWS: '{{.BIN_DIR}}/{{.PROGRAM}}_windows_amd64.exe'
LINUX: '{{.BIN_DIR}}/{{.PROGRAM}}_linux_amd64'
GIT_COMMIT:
sh: git log -n 1 --format=%h
tasks:
default:
desc: "Build the q3rcon project"
deps: [build]
build:
desc: "Build the q3rcon project"
deps: [vet, build-windows, build-linux]
vet:
desc: "Vet the code"
deps: [fmt]
cmds:
- go vet ./...
fmt:
desc: "Fmt the code"
cmds:
- go fmt ./...
build-windows:
desc: "Build the q3rcon project for Windows"
cmds:
- GOOS=windows GOARCH=amd64 go build -o {{.WINDOWS}} -ldflags="-X main.Version={{.GIT_COMMIT}}" ./cmd/{{.PROGRAM}}/
build-linux:
desc: "Build the q3rcon project for Linux"
cmds:
- GOOS=linux GOARCH=amd64 go build -o {{.LINUX}} -ldflags="-X main.Version={{.GIT_COMMIT}}" ./cmd/{{.PROGRAM}}/
test:
desc: "Run tests"
cmds:
- go test ./...
clean:
desc: "Clean the build artifacts"
cmds:
- '{{.SHELL}} rm -r {{.BIN_DIR}}'

View File

@@ -2,7 +2,6 @@ package main
import (
"bufio"
"errors"
"flag"
"fmt"
"io"
@@ -15,28 +14,26 @@ import (
log "github.com/sirupsen/logrus"
)
var interactive bool
func exit(err error) {
func exitOnError(err error) {
_, _ = fmt.Fprintf(os.Stderr, "Error: %s\n", err)
flag.Usage()
os.Exit(1)
}
func main() {
var (
host string
port int
password string
loglevel int
host string
port int
rconpass string
interactive bool
loglevel int
)
flag.StringVar(&host, "host", "localhost", "hostname of the server")
flag.StringVar(&host, "h", "localhost", "hostname of the server (shorthand)")
flag.IntVar(&port, "port", 28960, "port of the server")
flag.IntVar(&port, "p", 28960, "port of the server (shorthand)")
flag.StringVar(&password, "password", "", "rcon password")
flag.StringVar(&password, "P", "", "rcon password (shorthand)")
flag.StringVar(&host, "host", "localhost", "hostname of the gameserver")
flag.StringVar(&host, "h", "localhost", "hostname of the gameserver (shorthand)")
flag.IntVar(&port, "port", 28960, "port on which the gameserver resides, default is 28960")
flag.IntVar(&port, "p", 28960, "port on which the gameserver resides, default is 28960 (shorthand)")
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")
flag.BoolVar(&interactive, "i", false, "run in interactive mode")
@@ -49,33 +46,29 @@ func main() {
log.SetLevel(log.Level(loglevel))
}
rcon, err := connectRcon(host, port, password)
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 {
log.Fatal(err)
exitOnError(err)
}
defer rcon.Close()
if interactive {
fmt.Printf("Enter 'Q' to exit.\n>> ")
err := interactiveMode(rcon, os.Stdin)
if err != nil {
log.Fatal(err)
}
if !interactive {
runCommands(flag.Args(), rcon)
return
}
if len(flag.Args()) == 0 {
err = errors.New("no rcon commands passed")
exit(err)
}
for _, arg := range flag.Args() {
resp, err := rcon.Send(arg)
if err != nil {
log.Error(err)
continue
}
fmt.Print(resp)
fmt.Printf("Enter 'Q' to exit.\n>> ")
err = interactiveMode(rcon, os.Stdin)
if err != nil {
exitOnError(err)
}
}
@@ -87,12 +80,29 @@ func connectRcon(host string, port int, password string) (*q3rcon.Rcon, error) {
return rcon, nil
}
// runCommands runs the commands given in the flag.Args slice.
// If no commands are given, it defaults to running the "status" command.
func runCommands(commands []string, rcon *q3rcon.Rcon) {
if len(commands) == 0 {
commands = append(commands, "status")
}
for _, cmd := range commands {
resp, err := rcon.Send(cmd)
if err != nil {
log.Error(err)
continue
}
fmt.Print(resp)
}
}
// interactiveMode continuously reads from input until a quit signal is given.
func interactiveMode(rcon *q3rcon.Rcon, input io.Reader) error {
scanner := bufio.NewScanner(input)
for scanner.Scan() {
cmd := scanner.Text()
if strings.ToUpper(cmd) == "Q" {
if strings.EqualFold(cmd, "Q") {
return nil
}
@@ -103,6 +113,7 @@ func interactiveMode(rcon *q3rcon.Rcon, input io.Reader) error {
}
fmt.Printf("%s>> ", resp)
}
if scanner.Err() != nil {
return scanner.Err()
}

11
go.mod
View File

@@ -2,13 +2,6 @@ module github.com/onyx-and-iris/q3rcon
go 1.23.0
require (
github.com/fatih/color v1.18.0
github.com/sirupsen/logrus v1.9.3
)
require github.com/sirupsen/logrus v1.9.3
require (
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
golang.org/x/sys v0.25.0 // indirect
)
require golang.org/x/sys v0.25.0 // indirect

9
go.sum
View File

@@ -1,13 +1,6 @@
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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
@@ -16,8 +9,6 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@@ -1,11 +1,11 @@
program = q3rcon
PROGRAM = q3rcon
GO = @go
BIN_DIR := bin
WINDOWS=$(BIN_DIR)/$(program)_windows_amd64.exe
LINUX=$(BIN_DIR)/$(program)_linux_amd64
VERSION=$(shell git describe --tags --always --long --dirty)
WINDOWS=$(BIN_DIR)/$(PROGRAM)_windows_amd64.exe
LINUX=$(BIN_DIR)/$(PROGRAM)_linux_amd64
VERSION=$(shell git log -n 1 --format=%h)
.DEFAULT_GOAL := build
@@ -25,10 +25,10 @@ linux: $(LINUX)
$(WINDOWS):
env GOOS=windows GOARCH=amd64 go build -v -o $(WINDOWS) -ldflags="-s -w -X main.version=$(VERSION)" ./cmd/q3rcon/
env GOOS=windows GOARCH=amd64 go build -v -o $(WINDOWS) -ldflags="-s -w -X main.version=$(VERSION)" ./cmd/$(PROGRAM)/
$(LINUX):
env GOOS=linux GOARCH=amd64 go build -v -o $(LINUX) -ldflags="-s -w -X main.version=$(VERSION)" ./cmd/q3rcon/
env GOOS=linux GOARCH=amd64 go build -v -o $(LINUX) -ldflags="-s -w -X main.version=$(VERSION)" ./cmd/$(PROGRAM)/
test:
$(GO) test ./...