From 276ab47fb5e2d9eef80f89734018b9004cb2944d Mon Sep 17 00:00:00 2001 From: Jeremy Brown Date: Fri, 3 Nov 2023 15:30:09 -0400 Subject: [PATCH] cleanups and test stubs --- README.md | 22 ++++++++--------- cmd/cli/main.go | 6 ++++- lib/svrquery/client.go | 25 +++++++++---------- lib/svrquery/protocol/prom/query_test.go | 10 ++++++++ lib/svrquery/protocol/prom/types.go | 2 +- lib/svrsample/protocol/prom/metrics.go | 2 +- lib/svrsample/protocol/prom/prom_test.go | 9 +++++++ lib/svrsample/protocol/prom/server_info.go | 28 ---------------------- lib/svrsample/query.go | 3 +-- lib/svrsample/{net.go => transport.go} | 13 +++++++--- lib/svrsample/transport_test.go | 13 ++++++++++ 11 files changed, 74 insertions(+), 59 deletions(-) create mode 100644 lib/svrquery/protocol/prom/query_test.go create mode 100644 lib/svrsample/protocol/prom/prom_test.go delete mode 100644 lib/svrsample/protocol/prom/server_info.go rename lib/svrsample/{net.go => transport.go} (83%) create mode 100644 lib/svrsample/transport_test.go diff --git a/README.md b/README.md index 94d8e89..3461f78 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ go-svrquery is a [Go](http://golang.org/) client for talking to game servers using various query protocols. - Features +Features -------- * Support for various game server query protocol's including: ** SQP, TF2E, Prometheus @@ -50,18 +50,18 @@ endpoint. For example: client, err := svrquery.NewClient("prom", "http://127.0.0.1:9100/metrics") ``` -The library will read the following metrics: +The library expects the following metrics to be available: ```text -# HELP gameserver_current_players Number of players currently connected to the server. -# TYPE gameserver_current_players gauge -gameserver_current_players 1 -# HELP gameserver_max_players Maximum number of players that can connect to the server. -# TYPE gameserver_max_players gauge -gameserver_max_players 2 -# HELP gameserver_server_info Server status info. -# TYPE gameserver_server_info gauge -gameserver_server_info{game_type="Game Type",map_name="Map",port="1000",server_name="Name"} 1 +# HELP current_players Number of players currently connected to the server. +# TYPE current_players gauge +current_players 1 +# HELP max_players Maximum number of players that can connect to the server. +# TYPE max_players gauge +max_players 2 +# HELP server_info Server status info. +# TYPE server_info gauge +server_info{game_type="Game Type",map_name="Map",port="1000",server_name="Name"} 1 ``` CLI diff --git a/cmd/cli/main.go b/cmd/cli/main.go index f563e7e..91baab9 100644 --- a/cmd/cli/main.go +++ b/cmd/cli/main.go @@ -1,6 +1,7 @@ package main import ( + "context" "encoding/json" "flag" "fmt" @@ -110,8 +111,11 @@ func server(l *log.Logger, proto, address string) error { return fmt.Errorf("create responder: %w", err) } + // TODO: implement cancellable context + ctx, _ := context.WithCancel(context.Background()) + // this function will block until the transport is closed - err = transport.Start(responder) + err = transport.Start(ctx, responder) if err != nil { return fmt.Errorf("transport error") } diff --git a/lib/svrquery/client.go b/lib/svrquery/client.go index 5e2ebb1..26bf45d 100644 --- a/lib/svrquery/client.go +++ b/lib/svrquery/client.go @@ -3,6 +3,7 @@ package svrquery import ( "errors" "fmt" + "io" "net" "net/http" "time" @@ -36,15 +37,6 @@ type Client struct { transport } -type transport interface { - Setup() error - Address() string - Read(b []byte) (int, error) - Write(b []byte) (int, error) - Close() error - SetTimeout(time.Duration) -} - // WithKey sets the key used for request by for the client. func WithKey(key string) Option { return func(c *Client) error { @@ -61,7 +53,7 @@ func WithTimeout(t time.Duration) Option { } } -// NewClient creates a new client that talks to address. +// NewClient creates a new client that talks to addr using proto. func NewClient(proto, addr string, options ...Option) (*Client, error) { f, err := protocol.Get(proto) if err != nil { @@ -98,8 +90,17 @@ func (c *Client) Query() (protocol.Responser, error) { return c.Queryer.Query() } -var _ transport = (*udpTransport)(nil) -var _ transport = (*httpTransport)(nil) +var ( + _ transport = (*udpTransport)(nil) + _ transport = (*httpTransport)(nil) +) + +type transport interface { + Setup() error + Address() string + SetTimeout(time.Duration) + io.ReadWriteCloser +} type udpTransport struct { address string diff --git a/lib/svrquery/protocol/prom/query_test.go b/lib/svrquery/protocol/prom/query_test.go new file mode 100644 index 0000000..203136b --- /dev/null +++ b/lib/svrquery/protocol/prom/query_test.go @@ -0,0 +1,10 @@ +package prom + +import ( + "testing" +) + +func TestQuery(t *testing.T) { + // use httptest.NewServer() + t.Fatal("unimplemented") +} diff --git a/lib/svrquery/protocol/prom/types.go b/lib/svrquery/protocol/prom/types.go index 5421543..69b2cf7 100644 --- a/lib/svrquery/protocol/prom/types.go +++ b/lib/svrquery/protocol/prom/types.go @@ -1,7 +1,7 @@ package prom const ( - metricNamespace = "gameserver_" + metricNamespace = "" // adjust this if we want to enforce a namespace/prefix for metrics currentPlayersMetricName = metricNamespace + "current_players" maxPlayersMetricName = metricNamespace + "max_players" serverInfoMetricName = metricNamespace + "server_info" diff --git a/lib/svrsample/protocol/prom/metrics.go b/lib/svrsample/protocol/prom/metrics.go index e681ec2..215334c 100644 --- a/lib/svrsample/protocol/prom/metrics.go +++ b/lib/svrsample/protocol/prom/metrics.go @@ -9,7 +9,7 @@ import ( var _ prometheus.Collector = (*metrics)(nil) const ( - metricNamespace = "gameserver" + metricNamespace = "" ) // metrics holds the current prometheus metrics data for the server diff --git a/lib/svrsample/protocol/prom/prom_test.go b/lib/svrsample/protocol/prom/prom_test.go new file mode 100644 index 0000000..9372c0d --- /dev/null +++ b/lib/svrsample/protocol/prom/prom_test.go @@ -0,0 +1,9 @@ +package prom + +import ( + "testing" +) + +func TestPrometheusServer(t *testing.T) { + t.Fatal("unimplemented") +} diff --git a/lib/svrsample/protocol/prom/server_info.go b/lib/svrsample/protocol/prom/server_info.go deleted file mode 100644 index 33189f1..0000000 --- a/lib/svrsample/protocol/prom/server_info.go +++ /dev/null @@ -1,28 +0,0 @@ -package prom - -import ( - "github.com/multiplay/go-svrquery/lib/svrsample/common" -) - -// ServerInfo holds the ServerInfo chunk data. -type ServerInfo struct { - CurrentPlayers uint16 - MaxPlayers uint16 - ServerName string - GameType string - BuildID string - GameMap string - Port uint16 -} - -// ServerInfoFromQueryState converts server info data in common.QueryState to ServerInfo. -func ServerInfoFromQueryState(qs common.QueryState) *ServerInfo { - return &ServerInfo{ - CurrentPlayers: uint16(qs.CurrentPlayers), - MaxPlayers: uint16(qs.MaxPlayers), - ServerName: qs.ServerName, - GameType: qs.GameType, - GameMap: qs.Map, - Port: qs.Port, - } -} diff --git a/lib/svrsample/query.go b/lib/svrsample/query.go index 8376c95..838b631 100644 --- a/lib/svrsample/query.go +++ b/lib/svrsample/query.go @@ -3,10 +3,9 @@ package svrsample import ( "errors" "fmt" - "github.com/multiplay/go-svrquery/lib/svrsample/protocol/prom" "github.com/multiplay/go-svrquery/lib/svrsample/common" - + "github.com/multiplay/go-svrquery/lib/svrsample/protocol/prom" "github.com/multiplay/go-svrquery/lib/svrsample/protocol/sqp" ) diff --git a/lib/svrsample/net.go b/lib/svrsample/transport.go similarity index 83% rename from lib/svrsample/net.go rename to lib/svrsample/transport.go index 4465ede..322f46d 100644 --- a/lib/svrsample/net.go +++ b/lib/svrsample/transport.go @@ -1,6 +1,7 @@ package svrsample import ( + "context" "errors" "fmt" "github.com/multiplay/go-svrquery/lib/svrsample/common" @@ -16,8 +17,10 @@ var ( _ Transport = (*HTTPTransport)(nil) ) +// Transport is an abstraction of the metrics transport (UDP, HTTP, etc.) type Transport interface { - Start(responder common.QueryResponder) error + // Start starts the transport and blocks until it is stopped + Start(context.Context, common.QueryResponder) error } type UDPTransport struct { @@ -30,7 +33,9 @@ func NewUDPTransport(address string) UDPTransport { return UDPTransport{address: address} } -func (u UDPTransport) Start(responder common.QueryResponder) error { +func (u UDPTransport) Start(ctx context.Context, responder common.QueryResponder) error { + // TODO: do something with context + addr, err := net.ResolveUDPAddr("udp4", u.address) if err != nil { return fmt.Errorf("resolved udp: %w", err) @@ -91,12 +96,14 @@ func NewHTTPTransport(address string) HTTPTransport { return HTTPTransport{address: address} } -func (h HTTPTransport) Start(responder common.QueryResponder) error { +func (h HTTPTransport) Start(ctx context.Context, responder common.QueryResponder) error { promResponder, ok := responder.(*prom.QueryResponder) if !ok { return errors.New(fmt.Sprintf("bad responder type, expected prom.QueryResponder but got %T", responder)) } + // TODO: do something with context + listener, err := net.Listen("tcp", h.address) if err != nil { return fmt.Errorf("listen tcp: %w", err) diff --git a/lib/svrsample/transport_test.go b/lib/svrsample/transport_test.go new file mode 100644 index 0000000..922f791 --- /dev/null +++ b/lib/svrsample/transport_test.go @@ -0,0 +1,13 @@ +package svrsample + +import ( + "testing" +) + +func TestUDPTransport(t *testing.T) { + t.Fatal("unimplemented") +} + +func TestHTTPTransport(t *testing.T) { + t.Fatal("unimplemented") +}