grcon/client/minecraft_client.go
Augusto Dwenger J. 7b8e1bbe41
Add a minecraft client
Minecraft (spigot) behaves differently. It does not support empty
requests. This is a deal breaker for the SimpleClient implementation.
The implementation is mutch simpler but in limits the exec support to
not support multi packet responses.
2022-03-04 21:52:24 +01:00

85 lines
2.4 KiB
Go

package client
import (
"github.com/hamburghammer/grcon"
"github.com/hamburghammer/grcon/util"
)
// NewMinecraftClient is a constructor for the MinecraftClient struct.
// The util.GenerateNewId can be used as idGenFunc.
func NewMinecraftClient(r util.RemoteConsole, idGenFunc func() grcon.PacketId) MinecraftClient {
return MinecraftClient{RemoteConsole: r, IdGenFunc: idGenFunc}
}
// MinecraftClient is a wrapper for a RemoteConsole that provides some utility functions.
// It simplifies the interaction with a remote console of a minecraft server.
type MinecraftClient struct {
// RemoteConsole is the console to use for the interactions.
util.RemoteConsole
// IdGenFunc is the function to use to generate ids.
IdGenFunc func() grcon.PacketId
}
// Auth should be used to authenticate the connection.
//
// It can return following errors:
// - InvalidResponseTypeError
// - ResponseIdMismatchError
// - AuthFailedError
func (sc MinecraftClient) Auth(password string) error {
reqID := sc.IdGenFunc()
err := sc.Write(grcon.Packet{Id: reqID, Type: grcon.SERVERDATA_AUTH, Body: []byte(password)})
if err != nil {
return err
}
packet, err := sc.Read()
if err != nil {
return err
}
if packet.Type != grcon.SERVERDATA_AUTH_RESPONSE {
return newInvalidResponseTypeError(grcon.SERVERDATA_AUTH_RESPONSE, packet.Type)
}
if packet.Id == -1 {
return newAuthFailedError()
}
if packet.Id != reqID {
return newResponseIdMismatchError(reqID, packet.Id)
}
return nil
}
// Exec executes the command on the given RemoteConsole implementation and
// waits till the response is read returns it.
//
// Errors:
// Returns all errors returned from the Write and Read methode from the RemoteConsole implementation.
// Can also return an InvalidResponseTypeError if the response is not of the type
// grcon.SERVERDATA_RESPONSE_VALUE.
func (sc MinecraftClient) Exec(cmd string) ([]byte, error) {
cmdPacket := grcon.Packet{
Id: sc.IdGenFunc(),
Type: grcon.SERVERDATA_EXECCOMMAND,
Body: []byte(cmd),
}
err := sc.Write(cmdPacket)
if err != nil {
return []byte{}, err
}
packet, err := sc.Read()
if err != nil {
return []byte{}, err
}
if packet.Type != grcon.SERVERDATA_RESPONSE_VALUE {
return []byte{}, newInvalidResponseTypeError(grcon.SERVERDATA_RESPONSE_VALUE, packet.Type)
}
if packet.Id != cmdPacket.Id {
return []byte{}, newResponseIdMismatchError(cmdPacket.Id, packet.Id)
}
return packet.Body, nil
}