Code improvements, move back from shared repo

This commit is contained in:
Jacob Gunther
2023-01-02 03:23:41 -06:00
parent 5104fa754f
commit 65676c1683
10 changed files with 697 additions and 70 deletions

417
src/status.go Normal file
View File

@@ -0,0 +1,417 @@
package main
import (
"encoding/base64"
"encoding/json"
"fmt"
"strings"
"time"
"github.com/mcstatus-io/mcutil"
)
type StatusResponse struct {
Online bool `json:"online"`
Host string `json:"host"`
Port uint16 `json:"port"`
EULABlocked bool `json:"eula_blocked"`
RetrievedAt int64 `json:"retrieved_at"`
ExpiresAt int64 `json:"expires_at"`
}
type JavaStatusResponse struct {
StatusResponse
*JavaStatus
}
type JavaStatus struct {
Version *JavaVersion `json:"version"`
Players JavaPlayers `json:"players"`
MOTD MOTD `json:"motd"`
Icon *string `json:"icon"`
Mods []Mod `json:"mods"`
}
type BedrockStatusResponse struct {
StatusResponse
*BedrockStatus
}
type BedrockStatus struct {
Version *BedrockVersion `json:"version"`
Players *BedrockPlayers `json:"players"`
MOTD *MOTD `json:"motd"`
Gamemode *string `json:"gamemode"`
ServerID *string `json:"server_id"`
Edition *string `json:"edition"`
}
type JavaVersion struct {
NameRaw string `json:"name_raw"`
NameClean string `json:"name_clean"`
NameHTML string `json:"name_html"`
Protocol int `json:"protocol"`
}
type BedrockVersion struct {
Name *string `json:"name"`
Protocol *int64 `json:"protocol"`
}
type JavaPlayers struct {
Online int `json:"online"`
Max int `json:"max"`
List []Player `json:"list"`
}
type BedrockPlayers struct {
Online *int64 `json:"online"`
Max *int64 `json:"max"`
}
type Player struct {
UUID string `json:"uuid"`
NameRaw string `json:"name_raw"`
NameClean string `json:"name_clean"`
NameHTML string `json:"name_html"`
}
type MOTD struct {
Raw string `json:"raw"`
Clean string `json:"clean"`
HTML string `json:"html"`
}
type Mod struct {
Name string `json:"name"`
Version string `json:"version"`
}
func GetJavaStatus(host string, port uint16) (*JavaStatusResponse, *time.Duration, error) {
cacheKey := fmt.Sprintf("java:%s-%d", host, port)
exists, err := r.Exists(cacheKey)
if err != nil {
return nil, nil, err
}
if exists {
data, err := r.GetBytes(cacheKey)
if err != nil {
return nil, nil, err
}
var response JavaStatusResponse
if err = json.Unmarshal(data, &response); err != nil {
return nil, nil, err
}
ttl, err := r.TTL(cacheKey)
return &response, &ttl, err
}
response := FetchJavaStatus(host, port, config.Cache.JavaCacheDuration)
data, err := json.Marshal(response)
if err != nil {
return nil, nil, err
}
if err := r.Set(cacheKey, data, config.Cache.JavaCacheDuration); err != nil {
return nil, nil, err
}
return response, nil, nil
}
func GetBedrockStatus(host string, port uint16) (*BedrockStatusResponse, *time.Duration, error) {
cacheKey := fmt.Sprintf("bedrock:%s-%d", host, port)
exists, err := r.Exists(cacheKey)
if err != nil {
return nil, nil, err
}
if exists {
data, err := r.GetBytes(cacheKey)
if err != nil {
return nil, nil, err
}
var response BedrockStatusResponse
if err = json.Unmarshal(data, &response); err != nil {
return nil, nil, err
}
ttl, err := r.TTL(cacheKey)
return &response, &ttl, err
}
response := FetchBedrockStatus(host, port, config.Cache.BedrockCacheDuration)
data, err := json.Marshal(response)
if err != nil {
return nil, nil, err
}
if err := r.Set(cacheKey, data, config.Cache.BedrockCacheDuration); err != nil {
return nil, nil, err
}
return response, nil, nil
}
func GetServerIcon(host string, port uint16) ([]byte, *time.Duration, error) {
cacheKey := fmt.Sprintf("icon:%s-%d", host, port)
exists, err := r.Exists(cacheKey)
if err != nil {
return nil, nil, err
}
if exists {
data, err := r.GetBytes(cacheKey)
if err != nil {
return nil, nil, err
}
ttl, err := r.TTL(cacheKey)
return data, &ttl, err
}
icon := defaultIconBytes
status, err := mcutil.Status(host, port)
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,"))
if err != nil {
return nil, nil, err
}
icon = data
}
if err := r.Set(cacheKey, icon, config.Cache.IconCacheDuration); err != nil {
return nil, nil, err
}
return icon, nil, nil
}
func FetchJavaStatus(host string, port uint16, ttl time.Duration) *JavaStatusResponse {
status, err := mcutil.Status(host, port)
if err != nil {
statusLegacy, err := mcutil.StatusLegacy(host, port)
if err != nil {
return &JavaStatusResponse{
StatusResponse: StatusResponse{
Online: false,
Host: host,
Port: port,
EULABlocked: IsBlockedAddress(host),
RetrievedAt: time.Now().UnixMilli(),
ExpiresAt: time.Now().Add(ttl).UnixMilli(),
},
}
}
response := &JavaStatusResponse{
StatusResponse: StatusResponse{
Online: true,
Host: host,
Port: port,
EULABlocked: IsBlockedAddress(host),
RetrievedAt: time.Now().UnixMilli(),
ExpiresAt: time.Now().Add(ttl).UnixMilli(),
},
JavaStatus: &JavaStatus{
Version: nil,
Players: JavaPlayers{
Online: statusLegacy.Players.Online,
Max: statusLegacy.Players.Max,
List: make([]Player, 0),
},
MOTD: MOTD{
Raw: statusLegacy.MOTD.Raw,
Clean: statusLegacy.MOTD.Clean,
HTML: statusLegacy.MOTD.HTML,
},
Icon: nil,
Mods: make([]Mod, 0),
},
}
if statusLegacy.Version != nil {
response.Version = &JavaVersion{
NameRaw: statusLegacy.Version.NameRaw,
NameClean: statusLegacy.Version.NameClean,
NameHTML: statusLegacy.Version.NameHTML,
Protocol: statusLegacy.Version.Protocol,
}
}
return response
}
playerList := make([]Player, 0)
if status.Players.Sample != nil {
for _, player := range status.Players.Sample {
playerList = append(playerList, Player{
UUID: player.ID,
NameRaw: player.NameRaw,
NameClean: player.NameClean,
NameHTML: player.NameHTML,
})
}
}
modList := make([]Mod, 0)
if status.ModInfo != nil {
for _, mod := range status.ModInfo.Mods {
modList = append(modList, Mod{
Name: mod.ID,
Version: mod.Version,
})
}
}
return &JavaStatusResponse{
StatusResponse: StatusResponse{
Online: true,
Host: host,
Port: port,
EULABlocked: IsBlockedAddress(host),
RetrievedAt: time.Now().UnixMilli(),
ExpiresAt: time.Now().Add(ttl).UnixMilli(),
},
JavaStatus: &JavaStatus{
Version: &JavaVersion{
NameRaw: status.Version.NameRaw,
NameClean: status.Version.NameClean,
NameHTML: status.Version.NameHTML,
Protocol: status.Version.Protocol,
},
Players: JavaPlayers{
Online: status.Players.Online,
Max: status.Players.Max,
List: playerList,
},
MOTD: MOTD{
Raw: status.MOTD.Raw,
Clean: status.MOTD.Clean,
HTML: status.MOTD.HTML,
},
Icon: status.Favicon,
Mods: modList,
},
}
}
func FetchBedrockStatus(host string, port uint16, ttl time.Duration) *BedrockStatusResponse {
status, err := mcutil.StatusBedrock(host, port)
if err != nil {
return &BedrockStatusResponse{
StatusResponse: StatusResponse{
Online: false,
Host: host,
Port: port,
EULABlocked: IsBlockedAddress(host),
RetrievedAt: time.Now().UnixMilli(),
ExpiresAt: time.Now().Add(ttl).UnixMilli(),
},
}
}
response := &BedrockStatusResponse{
StatusResponse: StatusResponse{
Online: true,
Host: host,
Port: port,
EULABlocked: IsBlockedAddress(host),
RetrievedAt: time.Now().UnixMilli(),
ExpiresAt: time.Now().Add(ttl).UnixMilli(),
},
BedrockStatus: &BedrockStatus{
Version: nil,
Players: nil,
MOTD: nil,
Gamemode: status.Gamemode,
ServerID: status.ServerID,
Edition: status.Edition,
},
}
if status.Version != nil {
if response.Version == nil {
response.Version = &BedrockVersion{
Name: nil,
Protocol: nil,
}
}
response.Version.Name = status.Version
}
if status.ProtocolVersion != nil {
if response.Version == nil {
response.Version = &BedrockVersion{
Name: nil,
Protocol: nil,
}
}
response.Version.Protocol = status.ProtocolVersion
}
if status.OnlinePlayers != nil {
if response.Players == nil {
response.Players = &BedrockPlayers{
Online: nil,
Max: nil,
}
}
response.Players.Online = status.OnlinePlayers
}
if status.MaxPlayers != nil {
if response.Players == nil {
response.Players = &BedrockPlayers{
Online: nil,
Max: nil,
}
}
response.Players.Max = status.MaxPlayers
}
if status.MOTD != nil {
response.MOTD = &MOTD{
Raw: status.MOTD.Raw,
Clean: status.MOTD.Clean,
HTML: status.MOTD.HTML,
}
}
return response
}