Better timeout support
This commit is contained in:
2
go.mod
2
go.mod
@@ -5,7 +5,7 @@ go 1.19
|
|||||||
require (
|
require (
|
||||||
github.com/go-redsync/redsync/v4 v4.8.1
|
github.com/go-redsync/redsync/v4 v4.8.1
|
||||||
github.com/gofiber/fiber/v2 v2.48.0
|
github.com/gofiber/fiber/v2 v2.48.0
|
||||||
github.com/mcstatus-io/mcutil v1.4.0
|
github.com/mcstatus-io/mcutil/v2 v2.0.1
|
||||||
github.com/redis/go-redis/v9 v9.1.0
|
github.com/redis/go-redis/v9 v9.1.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|||||||
4
go.sum
4
go.sum
@@ -64,8 +64,8 @@ github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APP
|
|||||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
github.com/mcstatus-io/mcutil v1.4.0 h1:UpEaOm/PGIDcPFQqAXY14uhsgaclM3ZsEf6ojuAXZGE=
|
github.com/mcstatus-io/mcutil/v2 v2.0.1 h1:tIyOBYoa+DygzCkGIhU7/STA2gOIcWqS45/p4U58xmE=
|
||||||
github.com/mcstatus-io/mcutil v1.4.0/go.mod h1:VPWRCaYXfQheaTt4XJGYOGFzrp2E+B8g393SQiYO5mA=
|
github.com/mcstatus-io/mcutil/v2 v2.0.1/go.mod h1:GmQmohJjxYHkCI9qyK7rvfrZDqwwyKomnMbvXAz/US4=
|
||||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"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/gofiber/fiber/v2/middleware/cors"
|
"github.com/gofiber/fiber/v2/middleware/cors"
|
||||||
"github.com/gofiber/fiber/v2/middleware/logger"
|
"github.com/gofiber/fiber/v2/middleware/logger"
|
||||||
"github.com/gofiber/fiber/v2/middleware/recover"
|
"github.com/gofiber/fiber/v2/middleware/recover"
|
||||||
"github.com/mcstatus-io/mcutil"
|
"github.com/mcstatus-io/mcutil/v2"
|
||||||
"github.com/mcstatus-io/mcutil/options"
|
"github.com/mcstatus-io/mcutil/v2/options"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -54,6 +54,12 @@ func FaviconHandler(ctx *fiber.Ctx) error {
|
|||||||
|
|
||||||
// JavaStatusHandler returns the status of the Java edition Minecraft server specified in the address parameter.
|
// JavaStatusHandler returns the status of the Java edition Minecraft server specified in the address parameter.
|
||||||
func JavaStatusHandler(ctx *fiber.Ctx) error {
|
func JavaStatusHandler(ctx *fiber.Ctx) error {
|
||||||
|
opts, err := GetStatusOptions(ctx)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
host, port, err := ParseAddress(ctx.Params("address"), 25565)
|
host, port, err := ParseAddress(ctx.Params("address"), 25565)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -64,7 +70,7 @@ func JavaStatusHandler(ctx *fiber.Ctx) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
response, expiresAt, err := GetJavaStatus(host, port, ctx.QueryBool("query", true))
|
response, expiresAt, err := GetJavaStatus(host, port, opts)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -81,6 +87,12 @@ func JavaStatusHandler(ctx *fiber.Ctx) error {
|
|||||||
|
|
||||||
// BedrockStatusHandler returns the status of the Bedrock edition Minecraft server specified in the address parameter.
|
// BedrockStatusHandler returns the status of the Bedrock edition Minecraft server specified in the address parameter.
|
||||||
func BedrockStatusHandler(ctx *fiber.Ctx) error {
|
func BedrockStatusHandler(ctx *fiber.Ctx) error {
|
||||||
|
opts, err := GetStatusOptions(ctx)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
host, port, err := ParseAddress(ctx.Params("address"), 19132)
|
host, port, err := ParseAddress(ctx.Params("address"), 19132)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -91,7 +103,7 @@ func BedrockStatusHandler(ctx *fiber.Ctx) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
response, expiresAt, err := GetBedrockStatus(host, port)
|
response, expiresAt, err := GetBedrockStatus(host, port, opts)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -108,13 +120,19 @@ func BedrockStatusHandler(ctx *fiber.Ctx) error {
|
|||||||
|
|
||||||
// IconHandler returns the server icon for the specified Java edition Minecraft server.
|
// IconHandler returns the server icon for the specified Java edition Minecraft server.
|
||||||
func IconHandler(ctx *fiber.Ctx) error {
|
func IconHandler(ctx *fiber.Ctx) error {
|
||||||
|
opts, err := GetStatusOptions(ctx)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
host, port, err := ParseAddress(ctx.Params("address"), 25565)
|
host, port, err := ParseAddress(ctx.Params("address"), 25565)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(http.StatusBadRequest).SendString("Invalid address value")
|
return ctx.Status(http.StatusBadRequest).SendString("Invalid address value")
|
||||||
}
|
}
|
||||||
|
|
||||||
icon, expiresAt, err := GetServerIcon(host, port)
|
icon, expiresAt, err := GetServerIcon(host, port, opts)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -131,7 +149,7 @@ func IconHandler(ctx *fiber.Ctx) error {
|
|||||||
|
|
||||||
// SendVoteHandler allows sending of Votifier votes to the specified server.
|
// SendVoteHandler allows sending of Votifier votes to the specified server.
|
||||||
func SendVoteHandler(ctx *fiber.Ctx) error {
|
func SendVoteHandler(ctx *fiber.Ctx) error {
|
||||||
opts, err := ParseVoteOptions(ctx)
|
opts, err := GetVoteOptions(ctx)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(http.StatusBadRequest).SendString(err.Error())
|
return ctx.Status(http.StatusBadRequest).SendString(err.Error())
|
||||||
@@ -140,26 +158,34 @@ func SendVoteHandler(ctx *fiber.Ctx) error {
|
|||||||
switch opts.Version {
|
switch opts.Version {
|
||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
if err = mcutil.SendLegacyVote(opts.Host, opts.Port, options.LegacyVote{
|
c, cancel := context.WithTimeout(context.Background(), opts.Timeout)
|
||||||
|
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if err = mcutil.SendLegacyVote(c, opts.Host, opts.Port, options.LegacyVote{
|
||||||
PublicKey: opts.PublicKey,
|
PublicKey: opts.PublicKey,
|
||||||
ServiceName: opts.ServiceName,
|
ServiceName: opts.ServiceName,
|
||||||
Username: opts.Username,
|
Username: opts.Username,
|
||||||
IPAddress: opts.IPAddress,
|
IPAddress: opts.IPAddress,
|
||||||
Timestamp: opts.Timestamp,
|
Timestamp: opts.Timestamp,
|
||||||
Timeout: time.Second * 5,
|
Timeout: opts.Timeout,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return ctx.Status(http.StatusBadRequest).SendString(err.Error())
|
return ctx.Status(http.StatusBadRequest).SendString(err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 2:
|
case 2:
|
||||||
{
|
{
|
||||||
if err = mcutil.SendVote(opts.Host, opts.Port, options.Vote{
|
c, cancel := context.WithTimeout(context.Background(), opts.Timeout)
|
||||||
|
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if err = mcutil.SendVote(c, opts.Host, opts.Port, options.Vote{
|
||||||
ServiceName: opts.ServiceName,
|
ServiceName: opts.ServiceName,
|
||||||
Username: opts.Username,
|
Username: opts.Username,
|
||||||
Token: opts.Token,
|
Token: opts.Token,
|
||||||
UUID: opts.UUID,
|
UUID: opts.UUID,
|
||||||
Timestamp: opts.Timestamp,
|
Timestamp: opts.Timestamp,
|
||||||
Timeout: time.Second * 5,
|
Timeout: opts.Timeout,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return ctx.Status(http.StatusBadRequest).SendString(err.Error())
|
return ctx.Status(http.StatusBadRequest).SendString(err.Error())
|
||||||
}
|
}
|
||||||
|
|||||||
217
src/status.go
217
src/status.go
@@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -10,10 +11,10 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/mcstatus-io/mcutil"
|
"github.com/mcstatus-io/mcutil/v2"
|
||||||
"github.com/mcstatus-io/mcutil/description"
|
"github.com/mcstatus-io/mcutil/v2/formatting"
|
||||||
"github.com/mcstatus-io/mcutil/options"
|
"github.com/mcstatus-io/mcutil/v2/options"
|
||||||
"github.com/mcstatus-io/mcutil/response"
|
"github.com/mcstatus-io/mcutil/v2/response"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BaseStatus is the base response properties for returning any status response from the API.
|
// BaseStatus is the base response properties for returning any status response from the API.
|
||||||
@@ -114,8 +115,8 @@ type Plugin struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetJavaStatus returns the status response of a Java Edition server, either using cache or fetching a fresh status.
|
// GetJavaStatus returns the status response of a Java Edition server, either using cache or fetching a fresh status.
|
||||||
func GetJavaStatus(host string, port uint16, query bool) (*JavaStatusResponse, time.Duration, error) {
|
func GetJavaStatus(host string, port uint16, opts *StatusOptions) (*JavaStatusResponse, time.Duration, error) {
|
||||||
cacheKey := GetCacheKey(host, port, query)
|
cacheKey := GetCacheKey(host, port, opts)
|
||||||
|
|
||||||
// Wait for any other processes to finish fetching the status of this server
|
// Wait for any other processes to finish fetching the status of this server
|
||||||
if conf.Cache.EnableLocks {
|
if conf.Cache.EnableLocks {
|
||||||
@@ -144,7 +145,7 @@ func GetJavaStatus(host string, port uint16, query bool) (*JavaStatusResponse, t
|
|||||||
|
|
||||||
// Fetch a fresh status from the server itself
|
// Fetch a fresh status from the server itself
|
||||||
{
|
{
|
||||||
response := FetchJavaStatus(host, port, query)
|
response := FetchJavaStatus(host, port, opts)
|
||||||
|
|
||||||
data, err := json.Marshal(response)
|
data, err := json.Marshal(response)
|
||||||
|
|
||||||
@@ -161,8 +162,8 @@ func GetJavaStatus(host string, port uint16, query bool) (*JavaStatusResponse, t
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetBedrockStatus returns the status response of a Bedrock Edition server, either using cache or fetching a fresh status.
|
// GetBedrockStatus returns the status response of a Bedrock Edition server, either using cache or fetching a fresh status.
|
||||||
func GetBedrockStatus(host string, port uint16) (*BedrockStatusResponse, time.Duration, error) {
|
func GetBedrockStatus(host string, port uint16, opts *StatusOptions) (*BedrockStatusResponse, time.Duration, error) {
|
||||||
cacheKey := GetCacheKey(host, port, false)
|
cacheKey := GetCacheKey(host, port, nil)
|
||||||
|
|
||||||
// Wait for any other processes to finish fetching the status of this server
|
// Wait for any other processes to finish fetching the status of this server
|
||||||
if conf.Cache.EnableLocks {
|
if conf.Cache.EnableLocks {
|
||||||
@@ -191,7 +192,7 @@ func GetBedrockStatus(host string, port uint16) (*BedrockStatusResponse, time.Du
|
|||||||
|
|
||||||
// Fetch a fresh status from the server itself
|
// Fetch a fresh status from the server itself
|
||||||
{
|
{
|
||||||
response := FetchBedrockStatus(host, port)
|
response := FetchBedrockStatus(host, port, opts)
|
||||||
|
|
||||||
data, err := json.Marshal(response)
|
data, err := json.Marshal(response)
|
||||||
|
|
||||||
@@ -208,8 +209,8 @@ func GetBedrockStatus(host string, port uint16) (*BedrockStatusResponse, time.Du
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetServerIcon returns the icon image of a Java Edition server, either using cache or fetching a fresh image.
|
// GetServerIcon returns the icon image of a Java Edition server, either using cache or fetching a fresh image.
|
||||||
func GetServerIcon(host string, port uint16) ([]byte, time.Duration, error) {
|
func GetServerIcon(host string, port uint16, opts *StatusOptions) ([]byte, time.Duration, error) {
|
||||||
cacheKey := GetCacheKey(host, port, false)
|
cacheKey := GetCacheKey(host, port, nil)
|
||||||
|
|
||||||
// Fetch the cached icon if it exists
|
// Fetch the cached icon if it exists
|
||||||
{
|
{
|
||||||
@@ -230,7 +231,11 @@ func GetServerIcon(host string, port uint16) ([]byte, time.Duration, error) {
|
|||||||
|
|
||||||
// Fetch the icon from the server itself
|
// Fetch the icon from the server itself
|
||||||
{
|
{
|
||||||
status, err := mcutil.Status(host, port)
|
ctx, cancel := context.WithTimeout(context.Background(), opts.Timeout)
|
||||||
|
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
status, err := mcutil.Status(ctx, host, port)
|
||||||
|
|
||||||
if err == nil && status.Favicon != nil && strings.HasPrefix(*status.Favicon, "data:image/png;base64,") {
|
if err == nil && status.Favicon != nil && strings.HasPrefix(*status.Favicon, "data:image/png;base64,") {
|
||||||
data, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(*status.Favicon, "data:image/png;base64,"))
|
data, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(*status.Favicon, "data:image/png;base64,"))
|
||||||
@@ -254,38 +259,74 @@ func GetServerIcon(host string, port uint16) ([]byte, time.Duration, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FetchJavaStatus fetches fresh information about a Java Edition Minecraft server.
|
// FetchJavaStatus fetches fresh information about a Java Edition Minecraft server.
|
||||||
func FetchJavaStatus(host string, port uint16, enableQuery bool) JavaStatusResponse {
|
func FetchJavaStatus(host string, port uint16, opts *StatusOptions) JavaStatusResponse {
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
wg.Add(1)
|
wg.Add(2)
|
||||||
|
|
||||||
if enableQuery {
|
if opts.Query {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
statusContext, statusCancel := context.WithTimeout(context.Background(), opts.Timeout)
|
||||||
|
legacyContext, legacyCancel := context.WithTimeout(context.Background(), opts.Timeout)
|
||||||
|
queryContext, queryCancel := context.WithTimeout(context.Background(), opts.Timeout)
|
||||||
|
|
||||||
|
defer statusCancel()
|
||||||
|
defer legacyCancel()
|
||||||
|
defer queryCancel()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
statusResult interface{} = nil
|
statusResult *response.JavaStatus = nil
|
||||||
|
legacyStatusResult *response.JavaStatusLegacy = nil
|
||||||
queryResult *response.FullQuery = nil
|
queryResult *response.FullQuery = nil
|
||||||
)
|
)
|
||||||
|
|
||||||
// Status
|
// Status
|
||||||
{
|
{
|
||||||
go func() {
|
go func() {
|
||||||
if result, _ := mcutil.Status(host, port); result != nil {
|
if result, _ := mcutil.Status(statusContext, host, port, options.JavaStatus{
|
||||||
statusResult = result
|
Timeout: opts.Timeout - time.Millisecond*100,
|
||||||
} else if result, _ := mcutil.StatusLegacy(host, port); result != nil {
|
}); result != nil {
|
||||||
statusResult = result
|
statusResult = result
|
||||||
}
|
}
|
||||||
|
|
||||||
wg.Done()
|
wg.Done()
|
||||||
|
|
||||||
|
legacyCancel()
|
||||||
|
|
||||||
|
time.Sleep(time.Millisecond * 250)
|
||||||
|
|
||||||
|
if queryResult == nil {
|
||||||
|
queryCancel()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Legacy Status
|
||||||
|
{
|
||||||
|
go func() {
|
||||||
|
if result, _ := mcutil.StatusLegacy(legacyContext, host, port, options.JavaStatusLegacy{
|
||||||
|
Timeout: opts.Timeout - time.Millisecond*100,
|
||||||
|
}); result != nil {
|
||||||
|
legacyStatusResult = result
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Done()
|
||||||
|
|
||||||
|
time.Sleep(time.Millisecond * 250)
|
||||||
|
|
||||||
|
if queryResult == nil {
|
||||||
|
queryCancel()
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query
|
// Query
|
||||||
if enableQuery {
|
if opts.Query {
|
||||||
go func() {
|
go func() {
|
||||||
queryResult, _ = mcutil.FullQuery(host, port, options.Query{
|
queryResult, _ = mcutil.FullQuery(queryContext, host, port, options.Query{
|
||||||
Timeout: time.Second,
|
Timeout: opts.Timeout - time.Millisecond*100,
|
||||||
})
|
})
|
||||||
|
|
||||||
wg.Done()
|
wg.Done()
|
||||||
@@ -294,18 +335,22 @@ func FetchJavaStatus(host string, port uint16, enableQuery bool) JavaStatusRespo
|
|||||||
|
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
||||||
return BuildJavaResponse(host, port, statusResult, queryResult)
|
return BuildJavaResponse(host, port, statusResult, legacyStatusResult, queryResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FetchBedrockStatus fetches a fresh status of a Bedrock Edition server.
|
// FetchBedrockStatus fetches a fresh status of a Bedrock Edition server.
|
||||||
func FetchBedrockStatus(host string, port uint16) BedrockStatusResponse {
|
func FetchBedrockStatus(host string, port uint16, opts *StatusOptions) BedrockStatusResponse {
|
||||||
status, _ := mcutil.StatusBedrock(host, port)
|
ctx, cancel := context.WithTimeout(context.Background(), opts.Timeout)
|
||||||
|
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
status, _ := mcutil.StatusBedrock(ctx, host, port)
|
||||||
|
|
||||||
return BuildBedrockResponse(host, port, status)
|
return BuildBedrockResponse(host, port, status)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildJavaResponse builds the response data from the status and query information.
|
// BuildJavaResponse builds the response data from the status and query information.
|
||||||
func BuildJavaResponse(host string, port uint16, status interface{}, query *response.FullQuery) (result JavaStatusResponse) {
|
func BuildJavaResponse(host string, port uint16, status *response.JavaStatus, legacyStatus *response.JavaStatusLegacy, query *response.FullQuery) (result JavaStatusResponse) {
|
||||||
result = JavaStatusResponse{
|
result = JavaStatusResponse{
|
||||||
BaseStatus: BaseStatus{
|
BaseStatus: BaseStatus{
|
||||||
Online: false,
|
Online: false,
|
||||||
@@ -319,39 +364,33 @@ func BuildJavaResponse(host string, port uint16, status interface{}, query *resp
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Status
|
// Status
|
||||||
switch s := status.(type) {
|
if status != nil {
|
||||||
case *response.JavaStatus:
|
|
||||||
{
|
|
||||||
if s == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
result.Online = true
|
result.Online = true
|
||||||
|
|
||||||
result.JavaStatus = &JavaStatus{
|
result.JavaStatus = &JavaStatus{
|
||||||
Version: &JavaVersion{
|
Version: &JavaVersion{
|
||||||
NameRaw: s.Version.NameRaw,
|
NameRaw: status.Version.NameRaw,
|
||||||
NameClean: s.Version.NameClean,
|
NameClean: status.Version.NameClean,
|
||||||
NameHTML: s.Version.NameHTML,
|
NameHTML: status.Version.NameHTML,
|
||||||
Protocol: s.Version.Protocol,
|
Protocol: status.Version.Protocol,
|
||||||
},
|
},
|
||||||
Players: JavaPlayers{
|
Players: JavaPlayers{
|
||||||
Online: s.Players.Online,
|
Online: status.Players.Online,
|
||||||
Max: s.Players.Max,
|
Max: status.Players.Max,
|
||||||
List: make([]Player, 0),
|
List: make([]Player, 0),
|
||||||
},
|
},
|
||||||
MOTD: MOTD{
|
MOTD: MOTD{
|
||||||
Raw: s.MOTD.Raw,
|
Raw: status.MOTD.Raw,
|
||||||
Clean: s.MOTD.Clean,
|
Clean: status.MOTD.Clean,
|
||||||
HTML: s.MOTD.HTML,
|
HTML: status.MOTD.HTML,
|
||||||
},
|
},
|
||||||
Icon: s.Favicon,
|
Icon: status.Favicon,
|
||||||
Mods: make([]Mod, 0),
|
Mods: make([]Mod, 0),
|
||||||
Plugins: make([]Plugin, 0),
|
Plugins: make([]Plugin, 0),
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Players.Sample != nil {
|
if status.Players.Sample != nil {
|
||||||
for _, player := range s.Players.Sample {
|
for _, player := range status.Players.Sample {
|
||||||
result.Players.List = append(result.Players.List, Player{
|
result.Players.List = append(result.Players.List, Player{
|
||||||
UUID: player.ID,
|
UUID: player.ID,
|
||||||
NameRaw: player.NameRaw,
|
NameRaw: player.NameRaw,
|
||||||
@@ -361,53 +400,42 @@ func BuildJavaResponse(host string, port uint16, status interface{}, query *resp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.ModInfo != nil {
|
if status.ModInfo != nil {
|
||||||
for _, mod := range s.ModInfo.Mods {
|
for _, mod := range status.ModInfo.Mods {
|
||||||
result.Mods = append(result.Mods, Mod{
|
result.Mods = append(result.Mods, Mod{
|
||||||
Name: mod.ID,
|
Name: mod.ID,
|
||||||
Version: mod.Version,
|
Version: mod.Version,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if legacyStatus != nil {
|
||||||
break
|
|
||||||
}
|
|
||||||
case *response.JavaStatusLegacy:
|
|
||||||
{
|
|
||||||
if s == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
result.Online = true
|
result.Online = true
|
||||||
|
|
||||||
result.JavaStatus = &JavaStatus{
|
result.JavaStatus = &JavaStatus{
|
||||||
Version: nil,
|
Version: nil,
|
||||||
Players: JavaPlayers{
|
Players: JavaPlayers{
|
||||||
Online: &s.Players.Online,
|
Online: &legacyStatus.Players.Online,
|
||||||
Max: &s.Players.Max,
|
Max: &legacyStatus.Players.Max,
|
||||||
List: make([]Player, 0),
|
List: make([]Player, 0),
|
||||||
},
|
},
|
||||||
MOTD: MOTD{
|
MOTD: MOTD{
|
||||||
Raw: s.MOTD.Raw,
|
Raw: legacyStatus.MOTD.Raw,
|
||||||
Clean: s.MOTD.Clean,
|
Clean: legacyStatus.MOTD.Clean,
|
||||||
HTML: s.MOTD.HTML,
|
HTML: legacyStatus.MOTD.HTML,
|
||||||
},
|
},
|
||||||
Icon: nil,
|
Icon: nil,
|
||||||
Mods: make([]Mod, 0),
|
Mods: make([]Mod, 0),
|
||||||
Plugins: make([]Plugin, 0),
|
Plugins: make([]Plugin, 0),
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Version != nil {
|
if legacyStatus.Version != nil {
|
||||||
result.Version = &JavaVersion{
|
result.Version = &JavaVersion{
|
||||||
NameRaw: s.Version.NameRaw,
|
NameRaw: legacyStatus.Version.NameRaw,
|
||||||
NameClean: s.Version.NameClean,
|
NameClean: legacyStatus.Version.NameClean,
|
||||||
NameHTML: s.Version.NameHTML,
|
NameHTML: legacyStatus.Version.NameHTML,
|
||||||
Protocol: s.Version.Protocol,
|
Protocol: legacyStatus.Version.Protocol,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query
|
// Query
|
||||||
@@ -424,7 +452,7 @@ func BuildJavaResponse(host string, port uint16, status interface{}, query *resp
|
|||||||
}
|
}
|
||||||
|
|
||||||
if motd, ok := query.Data["hostname"]; ok {
|
if motd, ok := query.Data["hostname"]; ok {
|
||||||
if parsedMOTD, err := description.ParseFormatting(motd); err == nil {
|
if parsedMOTD, err := formatting.Parse(motd); err == nil {
|
||||||
result.MOTD = MOTD{
|
result.MOTD = MOTD{
|
||||||
Raw: parsedMOTD.Raw,
|
Raw: parsedMOTD.Raw,
|
||||||
Clean: parsedMOTD.Clean,
|
Clean: parsedMOTD.Clean,
|
||||||
@@ -450,7 +478,7 @@ func BuildJavaResponse(host string, port uint16, status interface{}, query *resp
|
|||||||
}
|
}
|
||||||
|
|
||||||
if version, ok := query.Data["version"]; ok {
|
if version, ok := query.Data["version"]; ok {
|
||||||
parsedValue, err := description.ParseFormatting(version)
|
parsedValue, err := formatting.Parse(version)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
result.Version = &JavaVersion{
|
result.Version = &JavaVersion{
|
||||||
@@ -490,7 +518,7 @@ func BuildJavaResponse(host string, port uint16, status interface{}, query *resp
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
parsedName, err := description.ParseFormatting(username)
|
parsedName, err := formatting.Parse(username)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
result.Players.List = append(result.Players.List, Player{
|
result.Players.List = append(result.Players.List, Player{
|
||||||
@@ -507,7 +535,7 @@ func BuildJavaResponse(host string, port uint16, status interface{}, query *resp
|
|||||||
}
|
}
|
||||||
|
|
||||||
// BuildBedrockResponse builds the response data from the status information.
|
// BuildBedrockResponse builds the response data from the status information.
|
||||||
func BuildBedrockResponse(host string, port uint16, status interface{}) (result BedrockStatusResponse) {
|
func BuildBedrockResponse(host string, port uint16, status *response.BedrockStatus) (result BedrockStatusResponse) {
|
||||||
result = BedrockStatusResponse{
|
result = BedrockStatusResponse{
|
||||||
BaseStatus: BaseStatus{
|
BaseStatus: BaseStatus{
|
||||||
Online: false,
|
Online: false,
|
||||||
@@ -520,25 +548,19 @@ func BuildBedrockResponse(host string, port uint16, status interface{}) (result
|
|||||||
BedrockStatus: nil,
|
BedrockStatus: nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
switch s := status.(type) {
|
if status != nil {
|
||||||
case *response.BedrockStatus:
|
|
||||||
{
|
|
||||||
if s == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
result.Online = true
|
result.Online = true
|
||||||
|
|
||||||
result.BedrockStatus = &BedrockStatus{
|
result.BedrockStatus = &BedrockStatus{
|
||||||
Version: nil,
|
Version: nil,
|
||||||
Players: nil,
|
Players: nil,
|
||||||
MOTD: nil,
|
MOTD: nil,
|
||||||
Gamemode: s.Gamemode,
|
Gamemode: status.Gamemode,
|
||||||
ServerID: s.ServerID,
|
ServerID: status.ServerID,
|
||||||
Edition: s.Edition,
|
Edition: status.Edition,
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Version != nil {
|
if status.Version != nil {
|
||||||
if result.Version == nil {
|
if result.Version == nil {
|
||||||
result.Version = &BedrockVersion{
|
result.Version = &BedrockVersion{
|
||||||
Name: nil,
|
Name: nil,
|
||||||
@@ -546,10 +568,10 @@ func BuildBedrockResponse(host string, port uint16, status interface{}) (result
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result.Version.Name = s.Version
|
result.Version.Name = status.Version
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.ProtocolVersion != nil {
|
if status.ProtocolVersion != nil {
|
||||||
if result.Version == nil {
|
if result.Version == nil {
|
||||||
result.Version = &BedrockVersion{
|
result.Version = &BedrockVersion{
|
||||||
Name: nil,
|
Name: nil,
|
||||||
@@ -557,10 +579,10 @@ func BuildBedrockResponse(host string, port uint16, status interface{}) (result
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result.Version.Protocol = s.ProtocolVersion
|
result.Version.Protocol = status.ProtocolVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.OnlinePlayers != nil {
|
if status.OnlinePlayers != nil {
|
||||||
if result.Players == nil {
|
if result.Players == nil {
|
||||||
result.Players = &BedrockPlayers{
|
result.Players = &BedrockPlayers{
|
||||||
Online: nil,
|
Online: nil,
|
||||||
@@ -568,10 +590,10 @@ func BuildBedrockResponse(host string, port uint16, status interface{}) (result
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result.Players.Online = s.OnlinePlayers
|
result.Players.Online = status.OnlinePlayers
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.MaxPlayers != nil {
|
if status.MaxPlayers != nil {
|
||||||
if result.Players == nil {
|
if result.Players == nil {
|
||||||
result.Players = &BedrockPlayers{
|
result.Players = &BedrockPlayers{
|
||||||
Online: nil,
|
Online: nil,
|
||||||
@@ -579,19 +601,16 @@ func BuildBedrockResponse(host string, port uint16, status interface{}) (result
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result.Players.Max = s.MaxPlayers
|
result.Players.Max = status.MaxPlayers
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.MOTD != nil {
|
if status.MOTD != nil {
|
||||||
result.MOTD = &MOTD{
|
result.MOTD = &MOTD{
|
||||||
Raw: s.MOTD.Raw,
|
Raw: status.MOTD.Raw,
|
||||||
Clean: s.MOTD.Clean,
|
Clean: status.MOTD.Clean,
|
||||||
HTML: s.MOTD.HTML,
|
HTML: status.MOTD.HTML,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|||||||
40
src/util.go
40
src/util.go
@@ -8,6 +8,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
"math"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
@@ -38,6 +39,13 @@ type VoteOptions struct {
|
|||||||
Token string
|
Token string
|
||||||
PublicKey string
|
PublicKey string
|
||||||
Timestamp time.Time
|
Timestamp time.Time
|
||||||
|
Timeout time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// StatusOptions is the options provided as query parameters to the status route.
|
||||||
|
type StatusOptions struct {
|
||||||
|
Query bool
|
||||||
|
Timeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// MutexArray is a thread-safe array for storing and retrieving values.
|
// MutexArray is a thread-safe array for storing and retrieving values.
|
||||||
@@ -140,8 +148,8 @@ 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.
|
// GetVoteOptions parses the vote options from the provided query parameters.
|
||||||
func ParseVoteOptions(ctx *fiber.Ctx) (*VoteOptions, error) {
|
func GetVoteOptions(ctx *fiber.Ctx) (*VoteOptions, error) {
|
||||||
result := VoteOptions{}
|
result := VoteOptions{}
|
||||||
|
|
||||||
// Version
|
// Version
|
||||||
@@ -232,9 +240,30 @@ func ParseVoteOptions(ctx *fiber.Ctx) (*VoteOptions, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Timeout
|
||||||
|
{
|
||||||
|
result.Timeout = time.Duration(math.Max(float64(time.Second)*ctx.QueryFloat("timeout", 5.0), float64(time.Millisecond*250)))
|
||||||
|
}
|
||||||
|
|
||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetStatusOptions(ctx *fiber.Ctx) (*StatusOptions, error) {
|
||||||
|
result := &StatusOptions{}
|
||||||
|
|
||||||
|
// Query
|
||||||
|
{
|
||||||
|
result.Query = ctx.QueryBool("query", true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timeout
|
||||||
|
{
|
||||||
|
result.Timeout = time.Duration(math.Max(float64(time.Second)*ctx.QueryFloat("timeout", 5.0), float64(time.Millisecond*500)))
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
@@ -251,11 +280,14 @@ func GetInstanceID() (uint16, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetCacheKey generates a unique key used for caching status results in Redis.
|
// GetCacheKey generates a unique key used for caching status results in Redis.
|
||||||
func GetCacheKey(host string, port uint16, query bool) string {
|
func GetCacheKey(host string, port uint16, opts *StatusOptions) string {
|
||||||
values := &url.Values{}
|
values := &url.Values{}
|
||||||
values.Set("host", host)
|
values.Set("host", host)
|
||||||
values.Set("port", strconv.FormatUint(uint64(port), 10))
|
values.Set("port", strconv.FormatUint(uint64(port), 10))
|
||||||
values.Set("query", strconv.FormatBool(query))
|
|
||||||
|
if opts != nil {
|
||||||
|
values.Set("query", strconv.FormatBool(opts.Query))
|
||||||
|
}
|
||||||
|
|
||||||
return SHA256(values.Encode())
|
return SHA256(values.Encode())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user