Add vote route
This commit is contained in:
@@ -6,9 +6,11 @@ import (
|
|||||||
"main/src/assets"
|
"main/src/assets"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
"github.com/mcstatus-io/mcutil"
|
"github.com/mcstatus-io/mcutil"
|
||||||
|
"github.com/mcstatus-io/mcutil/options"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -18,6 +20,7 @@ func init() {
|
|||||||
app.Get("/status/bedrock/:address", BedrockStatusHandler)
|
app.Get("/status/bedrock/:address", BedrockStatusHandler)
|
||||||
app.Get("/icon", DefaultIconHandler)
|
app.Get("/icon", DefaultIconHandler)
|
||||||
app.Get("/icon/:address", IconHandler)
|
app.Get("/icon/:address", IconHandler)
|
||||||
|
app.Post("/vote", SendVoteHandler)
|
||||||
app.Get("/debug/java/:address", DebugJavaStatusHandler)
|
app.Get("/debug/java/:address", DebugJavaStatusHandler)
|
||||||
app.Get("/debug/legacy/:address", DebugLegacyStatusHandler)
|
app.Get("/debug/legacy/:address", DebugLegacyStatusHandler)
|
||||||
app.Get("/debug/bedrock/:address", DebugBedrockStatusHandler)
|
app.Get("/debug/bedrock/:address", DebugBedrockStatusHandler)
|
||||||
@@ -113,6 +116,35 @@ func IconHandler(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Type("png").Send(icon)
|
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.
|
// DefaultIconHandler returns the default server icon.
|
||||||
func DefaultIconHandler(ctx *fiber.Ctx) error {
|
func DefaultIconHandler(ctx *fiber.Ctx) error {
|
||||||
return ctx.Type("png").Send(assets.DefaultIcon)
|
return ctx.Type("png").Send(assets.DefaultIcon)
|
||||||
|
|||||||
97
src/util.go
97
src/util.go
@@ -4,6 +4,7 @@ import (
|
|||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
_ "embed"
|
_ "embed"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
@@ -14,6 +15,9 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -22,6 +26,18 @@ var (
|
|||||||
ipAddressRegEx *regexp.Regexp = regexp.MustCompile(`^\d{1,3}(\.\d{1,3}){3}$`)
|
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.
|
// MutexArray is a thread-safe array for storing and retrieving values.
|
||||||
type MutexArray[T comparable] struct {
|
type MutexArray[T comparable] struct {
|
||||||
List []T
|
List []T
|
||||||
@@ -122,6 +138,87 @@ func ParseAddress(address string, defaultPort uint16) (string, uint16, error) {
|
|||||||
return host, uint16(port), nil
|
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.
|
// GetInstanceID returns the INSTANCE_ID environment variable parsed as an unsigned 16-bit integer.
|
||||||
func GetInstanceID() (uint16, error) {
|
func GetInstanceID() (uint16, error) {
|
||||||
if instanceID := os.Getenv("INSTANCE_ID"); len(instanceID) > 0 {
|
if instanceID := os.Getenv("INSTANCE_ID"); len(instanceID) > 0 {
|
||||||
|
|||||||
Reference in New Issue
Block a user