Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4c5dd0c5f4 |
11
client.go
11
client.go
@@ -21,3 +21,14 @@ func NewAll(timeout time.Duration) *Client {
|
|||||||
Source: source.New(source.Options{Timeout: timeout}),
|
Source: source.New(source.Options{Timeout: timeout}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) SetSourceDebug(debug bool) {
|
||||||
|
if c == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
timeout := 2 * time.Second
|
||||||
|
if c.Source != nil {
|
||||||
|
timeout = c.Source.Timeout()
|
||||||
|
}
|
||||||
|
c.Source = source.New(source.Options{Timeout: timeout, Debug: debug})
|
||||||
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
client := gamestatus.NewAll(cfg.timeout)
|
client := gamestatus.NewAll(cfg.timeout)
|
||||||
|
client.SetSourceDebug(cfg.debug)
|
||||||
|
|
||||||
info, err := connect(client, cfg.edition, host, port, cfg.useQuery)
|
info, err := connect(client, cfg.edition, host, port, cfg.useQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -54,6 +55,7 @@ type cliConfig struct {
|
|||||||
useQuery bool
|
useQuery bool
|
||||||
pretty bool
|
pretty bool
|
||||||
motdRaw bool
|
motdRaw bool
|
||||||
|
debug bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseCLI(args []string) (cliConfig, string, error) {
|
func parseCLI(args []string) (cliConfig, string, error) {
|
||||||
@@ -70,6 +72,7 @@ func parseCLI(args []string) (cliConfig, string, error) {
|
|||||||
useQuery := fs.Bool("query", false, "use full query when supported")
|
useQuery := fs.Bool("query", false, "use full query when supported")
|
||||||
pretty := fs.Bool("pretty", false, "use compact human-friendly output")
|
pretty := fs.Bool("pretty", false, "use compact human-friendly output")
|
||||||
motdRaw := fs.Bool("motd-raw", false, "print raw MOTD without cleanup")
|
motdRaw := fs.Bool("motd-raw", false, "print raw MOTD without cleanup")
|
||||||
|
debug := fs.Bool("debug", false, "print protocol-specific diagnostics")
|
||||||
|
|
||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
switch strings.ToLower(strings.TrimSpace(args[0])) {
|
switch strings.ToLower(strings.TrimSpace(args[0])) {
|
||||||
@@ -96,6 +99,7 @@ func parseCLI(args []string) (cliConfig, string, error) {
|
|||||||
cfg.useQuery = *useQuery
|
cfg.useQuery = *useQuery
|
||||||
cfg.pretty = *pretty
|
cfg.pretty = *pretty
|
||||||
cfg.motdRaw = *motdRaw
|
cfg.motdRaw = *motdRaw
|
||||||
|
cfg.debug = *debug
|
||||||
|
|
||||||
if fs.NArg() != 1 {
|
if fs.NArg() != 1 {
|
||||||
return cfg, "", nil
|
return cfg, "", nil
|
||||||
@@ -126,6 +130,8 @@ func printUsage() {
|
|||||||
fmt.Fprintln(os.Stderr, " use compact human-friendly output")
|
fmt.Fprintln(os.Stderr, " use compact human-friendly output")
|
||||||
fmt.Fprintln(os.Stderr, " -motd-raw")
|
fmt.Fprintln(os.Stderr, " -motd-raw")
|
||||||
fmt.Fprintln(os.Stderr, " print raw MOTD without cleanup")
|
fmt.Fprintln(os.Stderr, " print raw MOTD without cleanup")
|
||||||
|
fmt.Fprintln(os.Stderr, " -debug")
|
||||||
|
fmt.Fprintln(os.Stderr, " print protocol-specific diagnostics")
|
||||||
}
|
}
|
||||||
|
|
||||||
func connect(client *gamestatus.Client, edition, host string, port int, useQuery bool) (*gamestatus.ServerInfo, error) {
|
func connect(client *gamestatus.Client, edition, host string, port int, useQuery bool) (*gamestatus.ServerInfo, error) {
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package source
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -14,6 +16,7 @@ import (
|
|||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
Timeout time.Duration
|
Timeout time.Duration
|
||||||
|
Debug bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
@@ -27,6 +30,13 @@ func New(opt Options) *Client {
|
|||||||
return &Client{opt: opt}
|
return &Client{opt: opt}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) Timeout() time.Duration {
|
||||||
|
if c == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return c.opt.Timeout
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client) Connect(address string, port int) (*info.ServerInfo, error) {
|
func (c *Client) Connect(address string, port int) (*info.ServerInfo, error) {
|
||||||
return c.query(address, port, false)
|
return c.query(address, port, false)
|
||||||
}
|
}
|
||||||
@@ -93,14 +103,14 @@ func (c *Client) query(address string, port int, full bool) (*info.ServerInfo, e
|
|||||||
addr := normalizeAddress(address, port)
|
addr := normalizeAddress(address, port)
|
||||||
client, err := a2s.NewClient(addr, a2s.TimeoutOption(c.opt.Timeout))
|
client, err := a2s.NewClient(addr, a2s.TimeoutOption(c.opt.Timeout))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, wrapQueryError(addr, "connect", err, c.opt.Debug)
|
||||||
}
|
}
|
||||||
defer client.Close()
|
defer client.Close()
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
infoResp, err := client.QueryInfo()
|
infoResp, err := client.QueryInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, wrapQueryError(addr, "info", err, c.opt.Debug)
|
||||||
}
|
}
|
||||||
|
|
||||||
out := &info.ServerInfo{
|
out := &info.ServerInfo{
|
||||||
@@ -133,10 +143,14 @@ func (c *Client) query(address string, port int, full bool) (*info.ServerInfo, e
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
out.Players = names
|
out.Players = names
|
||||||
|
} else if err != nil && c.opt.Debug {
|
||||||
|
return nil, wrapQueryError(addr, "players", err, true)
|
||||||
}
|
}
|
||||||
rulesResp, err := client.QueryRules()
|
rulesResp, err := client.QueryRules()
|
||||||
if err == nil && rulesResp != nil {
|
if err == nil && rulesResp != nil {
|
||||||
out.RawQuery = rulesResp.Rules
|
out.RawQuery = rulesResp.Rules
|
||||||
|
} else if err != nil && c.opt.Debug {
|
||||||
|
return nil, wrapQueryError(addr, "rules", err, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,6 +159,25 @@ func (c *Client) query(address string, port int, full bool) (*info.ServerInfo, e
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func wrapQueryError(addr, stage string, err error, debug bool) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
msg := fmt.Sprintf("no A2S response from %s", addr)
|
||||||
|
if debug && strings.TrimSpace(stage) != "" {
|
||||||
|
msg += fmt.Sprintf(" during %s", stage)
|
||||||
|
}
|
||||||
|
msg += " (server may have query disabled, blocked, or be using a different query port)"
|
||||||
|
return errors.New(msg)
|
||||||
|
}
|
||||||
|
if debug && strings.TrimSpace(stage) != "" {
|
||||||
|
return fmt.Errorf("source query %s failed for %s: %w", stage, addr, err)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func normalizeAddress(host string, port int) string {
|
func normalizeAddress(host string, port int) string {
|
||||||
if port == 0 {
|
if port == 0 {
|
||||||
port = a2s.DefaultPort
|
port = a2s.DefaultPort
|
||||||
|
|||||||
Reference in New Issue
Block a user