Add vote route

This commit is contained in:
Jacob Gunther
2023-07-28 19:14:05 -05:00
parent 1192c4236a
commit 5eed28681e
2 changed files with 129 additions and 0 deletions

View File

@@ -6,9 +6,11 @@ import (
"main/src/assets"
"net/http"
"strconv"
"time"
"github.com/gofiber/fiber/v2"
"github.com/mcstatus-io/mcutil"
"github.com/mcstatus-io/mcutil/options"
)
func init() {
@@ -18,6 +20,7 @@ func init() {
app.Get("/status/bedrock/:address", BedrockStatusHandler)
app.Get("/icon", DefaultIconHandler)
app.Get("/icon/:address", IconHandler)
app.Post("/vote", SendVoteHandler)
app.Get("/debug/java/:address", DebugJavaStatusHandler)
app.Get("/debug/legacy/:address", DebugLegacyStatusHandler)
app.Get("/debug/bedrock/:address", DebugBedrockStatusHandler)
@@ -113,6 +116,35 @@ func IconHandler(ctx *fiber.Ctx) error {
return ctx.Type("png").Send(icon)
}
// SendVoteHandler allows sending of Votifier votes to the specified server.
func SendVoteHandler(ctx *fiber.Ctx) error {
opts, err := ParseVoteOptions(ctx)
if err != nil {
return ctx.Status(http.StatusBadRequest).SendString(err.Error())
}
switch opts.Version {
case 1:
return ctx.Status(http.StatusNotImplemented).SendString("Votifier version 1 is currently not supported")
case 2:
{
if err = mcutil.SendVote(opts.Host, opts.Port, options.Vote{
ServiceName: opts.ServiceName,
Username: opts.Username,
Token: opts.Token,
UUID: opts.UUID,
Timestamp: opts.Timestamp,
Timeout: time.Second * 5,
}); err != nil {
return ctx.Status(http.StatusBadRequest).SendString(err.Error())
}
}
}
return ctx.Status(http.StatusOK).SendString("The vote was successfully sent to the server")
}
// DefaultIconHandler returns the default server icon.
func DefaultIconHandler(ctx *fiber.Ctx) error {
return ctx.Type("png").Send(assets.DefaultIcon)

View File

@@ -4,6 +4,7 @@ import (
"crypto/sha1"
_ "embed"
"encoding/hex"
"errors"
"fmt"
"io"
"log"
@@ -14,6 +15,9 @@ import (
"strconv"
"strings"
"sync"
"time"
"github.com/gofiber/fiber/v2"
)
var (
@@ -22,6 +26,18 @@ var (
ipAddressRegEx *regexp.Regexp = regexp.MustCompile(`^\d{1,3}(\.\d{1,3}){3}$`)
)
// VoteOptions is the options provided as query parameters to the vote route.
type VoteOptions struct {
Version int
Host string
Port uint16
ServiceName string
Username string
UUID string
Token string
Timestamp time.Time
}
// MutexArray is a thread-safe array for storing and retrieving values.
type MutexArray[T comparable] struct {
List []T
@@ -122,6 +138,87 @@ func ParseAddress(address string, defaultPort uint16) (string, uint16, error) {
return host, uint16(port), nil
}
// ParseVoteOptions parses the vote options from the provided query parameters.
func ParseVoteOptions(ctx *fiber.Ctx) (*VoteOptions, error) {
result := VoteOptions{}
// Version
{
result.Version = ctx.QueryInt("version", 2)
if result.Version < 0 || result.Version > 2 {
return nil, fmt.Errorf("invalid 'version' query parameter: %d", result.Version)
}
}
// Host
{
result.Host = ctx.Query("host")
if len(result.Host) < 1 {
return nil, errors.New("missing 'host' query parameter")
}
}
// Port
{
result.Port = uint16(ctx.QueryInt("host", 8192))
}
// Service Name
{
result.ServiceName = ctx.Query("serviceName", "mcstatus.io")
if len(result.ServiceName) < 1 {
return nil, fmt.Errorf("invalid 'serviceName' query parameter: %s", result.ServiceName)
}
}
// Username
{
result.Username = ctx.Query("username")
if len(result.Username) < 1 || len(result.Username) > 16 {
return nil, fmt.Errorf("invalid 'username' query parameter: %s", result.Username)
}
}
// UUID
{
result.UUID = ctx.Query("uuid")
// TODO check for properly formatted UUID
}
// Token
{
result.Token = ctx.Query("token")
if len(result.Token) < 1 {
return nil, fmt.Errorf("invalid 'token' query parameter: %s", result.Token)
}
}
// Timestamp
{
value := ctx.Query("timestamp")
if len(value) > 0 {
parsedTime, err := time.Parse(time.RFC3339, value)
if err != nil {
return nil, fmt.Errorf("invalid 'timestamp' query parameter: %s", result.Token)
}
result.Timestamp = parsedTime
} else {
result.Timestamp = time.Now()
}
}
return &result, nil
}
// GetInstanceID returns the INSTANCE_ID environment variable parsed as an unsigned 16-bit integer.
func GetInstanceID() (uint16, error) {
if instanceID := os.Getenv("INSTANCE_ID"); len(instanceID) > 0 {