telegraf/plugins/inputs/minecraft/rcon.go

113 lines
2.6 KiB
Go

package minecraft
import (
"strconv"
"strings"
"github.com/influxdata/telegraf/plugins/inputs/minecraft/internal/rcon"
)
const (
// NoMatches is a sentinel value returned when there are no statistics defined on the
//minecraft server
NoMatches = `All matches failed`
// ScoreboardPlayerList is the command to see all player statistics
ScoreboardPlayerList = `scoreboard players list *`
)
// RCONClient is a representation of RCON command authorizaiton and exectution
type RCONClient interface {
Authorize(password string) (*rcon.Packet, error)
Execute(command string) (*rcon.Packet, error)
}
// RCON represents a RCON server connection
type RCON struct {
Server string
Port string
Password string
client RCONClient
}
// RCONClientProducer is an interface which defines how a new client will be
// produced in the event of a network disconnect. It exists mainly for
// testing purposes
type RCONClientProducer interface {
newClient() (RCONClient, error)
}
type defaultClientProducer struct {
Server string
Port string
}
func (d defaultClientProducer) newClient() (RCONClient, error) {
return newClient(d.Server, d.Port)
}
// NewRCON creates a new RCON
func NewRCON(server, port, password string) (*RCON, error) {
client, err := newClient(server, port)
if err != nil {
return nil, err
}
return &RCON{
Server: server,
Port: port,
Password: password,
client: client,
}, nil
}
func newClient(server, port string) (*rcon.Client, error) {
p, err := strconv.Atoi(port)
if err != nil {
return nil, err
}
client, err := rcon.NewClient(server, p)
// If we've encountered any error, the contents of `client` could be corrupted,
// so we must return nil, err
if err != nil {
return nil, err
}
return client, nil
}
// Gather receives all player scoreboard information and returns it per player.
func (r *RCON) Gather(producer RCONClientProducer) ([]string, error) {
if r.client == nil {
var err error
r.client, err = producer.newClient()
if err != nil {
return nil, err
}
}
if _, err := r.client.Authorize(r.Password); err != nil {
// Potentially a network problem where the client will need to be
// re-initialized
r.client = nil
return nil, err
}
packet, err := r.client.Execute(ScoreboardPlayerList)
if err != nil {
// Potentially a network problem where the client will need to be
// re-initialized
r.client = nil
return nil, err
}
if !strings.Contains(packet.Body, NoMatches) {
players := strings.Split(packet.Body, "Showing")
if len(players) > 1 {
return players[1:], nil
}
}
return []string{}, nil
}