Code cleanup, only fetch stale blocked servers

This commit is contained in:
Jacob Gunther 2022-08-20 23:55:18 -05:00
parent e9d4b5590e
commit e7ada7435f
No known key found for this signature in database
GPG Key ID: FD93EF55818E3D85
5 changed files with 171 additions and 88 deletions

3
.gitignore vendored
View File

@ -1,3 +1,4 @@
bin/
config.yml
.DS_Store
.DS_Store
blocked-servers.json

View File

@ -24,18 +24,20 @@ func init() {
log.Fatal(err)
}
if err := r.Connect(config.Redis); err != nil {
log.Fatal(err)
}
r.SetEnabled(config.Cache.Enable)
log.Println("Successfully connected to Redis")
if config.Cache.Enable {
if err := r.Connect(config.Redis); err != nil {
log.Fatal(err)
}
log.Println("Successfully connected to Redis")
}
if err := GetBlockedServerList(); err != nil {
log.Fatal(err)
}
log.Println("Successfully retrieved EULA blocked servers")
if instanceID := os.Getenv("INSTANCE_ID"); len(instanceID) > 0 {
value, err := strconv.ParseUint(instanceID, 10, 16)

View File

@ -9,10 +9,19 @@ import (
)
type Redis struct {
Client *redis.Client
Enabled bool
Client *redis.Client
}
func (r *Redis) SetEnabled(value bool) {
r.Enabled = value
}
func (r *Redis) Connect(uri string) error {
if !r.Enabled {
return nil
}
opts, err := redis.ParseURL(uri)
if err != nil {
@ -29,6 +38,10 @@ func (r *Redis) Connect(uri string) error {
}
func (r *Redis) Exists(key string) (bool, error) {
if !r.Enabled {
return false, nil
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
@ -45,6 +58,10 @@ func (r *Redis) Exists(key string) (bool, error) {
}
func (r *Redis) GetString(key string) (string, error) {
if !r.Enabled {
return "", nil
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
@ -59,6 +76,10 @@ func (r *Redis) GetString(key string) (string, error) {
}
func (r *Redis) GetBytes(key string) ([]byte, error) {
if !r.Enabled {
return nil, nil
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
@ -73,6 +94,10 @@ func (r *Redis) GetBytes(key string) ([]byte, error) {
}
func (r *Redis) Set(key string, value interface{}, ttl time.Duration) error {
if !r.Enabled {
return nil
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
@ -81,6 +106,10 @@ func (r *Redis) Set(key string, value interface{}, ttl time.Duration) error {
}
func (r *Redis) SetJSON(key string, value interface{}, ttl time.Duration) error {
if !r.Enabled {
return nil
}
data, err := json.Marshal(value)
if err != nil {
@ -91,5 +120,9 @@ func (r *Redis) SetJSON(key string, value interface{}, ttl time.Duration) error
}
func (r *Redis) Close() error {
if !r.Enabled {
return nil
}
return r.Client.Close()
}

View File

@ -8,7 +8,7 @@ import (
"github.com/mcstatus-io/mcutil"
)
type StatusOffline struct {
type StatusResponse struct {
Online bool `json:"online"`
Host string `json:"host"`
Port uint16 `json:"port"`
@ -16,28 +16,22 @@ type StatusOffline struct {
}
type JavaStatusResponse struct {
Online bool `json:"online"`
Host string `json:"host"`
Port uint16 `json:"port"`
EULABlocked bool `json:"eula_blocked"`
Version *JavaVersion `json:"version"`
Players JavaPlayers `json:"players"`
MOTD MOTD `json:"motd"`
Icon *string `json:"icon"`
Mods []Mod `json:"mods"`
StatusResponse
Version *JavaVersion `json:"version"`
Players JavaPlayers `json:"players"`
MOTD MOTD `json:"motd"`
Icon *string `json:"icon"`
Mods []Mod `json:"mods"`
}
type BedrockStatusResponse struct {
Online bool `json:"online"`
Host string `json:"host"`
Port uint16 `json:"port"`
EULABlocked bool `json:"eula_blocked"`
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"`
StatusResponse
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 {
@ -84,24 +78,20 @@ type Mod struct {
func GetJavaStatus(host string, port uint16) (interface{}, error) {
cacheKey := fmt.Sprintf("java:%s-%d", host, port)
if config.Cache.Enable {
exists, err := r.Exists(cacheKey)
cacheExists, err := r.Exists(cacheKey)
if err != nil {
return nil, err
}
if err != nil {
return nil, err
}
if exists {
return r.GetString(cacheKey)
}
if cacheExists {
return r.GetString(cacheKey)
}
response := FetchJavaStatus(host, port)
if config.Cache.Enable {
if err := r.SetJSON(cacheKey, response, config.Cache.JavaCacheDuration); err != nil {
return nil, err
}
if err := r.SetJSON(cacheKey, response, config.Cache.JavaCacheDuration); err != nil {
return nil, err
}
return response, nil
@ -110,24 +100,20 @@ func GetJavaStatus(host string, port uint16) (interface{}, error) {
func GetBedrockStatus(host string, port uint16) (interface{}, error) {
cacheKey := fmt.Sprintf("bedrock:%s-%d", host, port)
if config.Cache.Enable {
exists, err := r.Exists(cacheKey)
cacheExists, err := r.Exists(cacheKey)
if err != nil {
return nil, err
}
if err != nil {
return nil, err
}
if exists {
return r.GetString(cacheKey)
}
if cacheExists {
return r.GetString(cacheKey)
}
response := FetchBedrockStatus(host, port)
if config.Cache.Enable {
if err := r.SetJSON(cacheKey, response, config.Cache.BedrockCacheDuration); err != nil {
return nil, err
}
if err := r.SetJSON(cacheKey, response, config.Cache.BedrockCacheDuration); err != nil {
return nil, err
}
return response, nil
@ -136,16 +122,14 @@ func GetBedrockStatus(host string, port uint16) (interface{}, error) {
func GetServerIcon(host string, port uint16) ([]byte, error) {
cacheKey := fmt.Sprintf("icon:%s-%d", host, port)
if config.Cache.Enable {
exists, err := r.Exists(cacheKey)
cacheExists, err := r.Exists(cacheKey)
if err != nil {
return nil, err
}
if err != nil {
return nil, err
}
if exists {
return r.GetBytes(cacheKey)
}
if cacheExists {
return r.GetBytes(cacheKey)
}
icon := defaultIconBytes
@ -162,10 +146,8 @@ func GetServerIcon(host string, port uint16) ([]byte, error) {
icon = data
}
if config.Cache.Enable {
if err := r.Set(cacheKey, icon, config.Cache.IconCacheDuration); err != nil {
return nil, err
}
if err := r.Set(cacheKey, icon, config.Cache.IconCacheDuration); err != nil {
return nil, err
}
return icon, nil
@ -178,7 +160,7 @@ func FetchJavaStatus(host string, port uint16) interface{} {
statusLegacy, err := mcutil.StatusLegacy(host, port)
if err != nil {
return StatusOffline{
return StatusResponse{
Online: false,
Host: host,
Port: port,
@ -187,11 +169,13 @@ func FetchJavaStatus(host string, port uint16) interface{} {
}
response := JavaStatusResponse{
Online: true,
Host: host,
Port: port,
EULABlocked: IsBlockedAddress(host),
Version: nil,
StatusResponse: StatusResponse{
Online: true,
Host: host,
Port: port,
EULABlocked: IsBlockedAddress(host),
},
Version: nil,
Players: JavaPlayers{
Online: statusLegacy.Players.Online,
Max: statusLegacy.Players.Max,
@ -243,10 +227,12 @@ func FetchJavaStatus(host string, port uint16) interface{} {
}
return JavaStatusResponse{
Online: true,
Host: host,
Port: port,
EULABlocked: IsBlockedAddress(host),
StatusResponse: StatusResponse{
Online: true,
Host: host,
Port: port,
EULABlocked: IsBlockedAddress(host),
},
Version: &JavaVersion{
NameRaw: status.Version.NameRaw,
NameClean: status.Version.NameClean,
@ -272,7 +258,7 @@ func FetchBedrockStatus(host string, port uint16) interface{} {
status, err := mcutil.StatusBedrock(host, port)
if err != nil {
return StatusOffline{
return StatusResponse{
Online: false,
Host: host,
Port: port,
@ -281,16 +267,18 @@ func FetchBedrockStatus(host string, port uint16) interface{} {
}
response := BedrockStatusResponse{
Online: true,
Host: host,
Port: port,
EULABlocked: IsBlockedAddress(host),
Version: nil,
Players: nil,
MOTD: nil,
Gamemode: status.Gamemode,
ServerID: status.ServerID,
Edition: status.Edition,
StatusResponse: StatusResponse{
Online: true,
Host: host,
Port: port,
EULABlocked: IsBlockedAddress(host),
},
Version: nil,
Players: nil,
MOTD: nil,
Gamemode: status.Gamemode,
ServerID: status.ServerID,
Edition: status.Edition,
}
if status.Version != nil {

View File

@ -4,20 +4,29 @@ import (
"crypto/sha1"
_ "embed"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"regexp"
"strconv"
"strings"
"time"
)
var (
//go:embed icon.png
defaultIconBytes []byte
ipAddressRegExp = regexp.MustCompile("^\\d{1,3}(\\.\\d{1,3}){3}$")
ipAddressRegExp = regexp.MustCompile(`^\d{1,3}(\.\d{1,3}){3}$`)
)
type BlockedServersFile struct {
LastUpdated time.Time `json:"last_updated"`
Servers []string `json:"servers"`
}
func Contains[T comparable](arr []T, v T) bool {
for _, value := range arr {
if v == value {
@ -29,6 +38,36 @@ func Contains[T comparable](arr []T, v T) bool {
}
func GetBlockedServerList() error {
f, err := os.OpenFile("blocked-servers.json", os.O_CREATE|os.O_RDWR, 0777)
if err != nil {
return err
}
defer f.Close()
data, err := ioutil.ReadAll(f)
if err != nil {
return err
}
if len(data) > 0 {
var blockedServersFile BlockedServersFile
if err = json.Unmarshal(data, &blockedServersFile); err != nil {
return err
}
if time.Since(blockedServersFile.LastUpdated).Hours() < 24 {
blockedServersMutex.Lock()
blockedServers = blockedServersFile.Servers
blockedServersMutex.Unlock()
return nil
}
}
resp, err := http.Get("https://sessionserver.mojang.com/blockedservers")
if err != nil {
@ -39,6 +78,8 @@ func GetBlockedServerList() error {
return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
}
log.Println("Successfully retrieved EULA blocked servers")
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
@ -49,9 +90,27 @@ func GetBlockedServerList() error {
blockedServersMutex.Lock()
blockedServers = strings.Split(string(body), "\n")
blockedServersMutex.Unlock()
return nil
defer blockedServersMutex.Unlock()
if data, err = json.Marshal(BlockedServersFile{
LastUpdated: time.Now(),
Servers: blockedServers,
}); err != nil {
return err
}
if err = f.Truncate(0); err != nil {
return err
}
if _, err = f.Seek(0, 0); err != nil {
return err
}
_, err = f.Write(data)
return err
}
func IsBlockedAddress(address string) bool {