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
5 changed files with 171 additions and 88 deletions

1
.gitignore vendored
View File

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

View File

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

View File

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

View File

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

View File

@@ -4,20 +4,29 @@ import (
"crypto/sha1" "crypto/sha1"
_ "embed" _ "embed"
"encoding/hex" "encoding/hex"
"encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"log"
"net/http" "net/http"
"os"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
"time"
) )
var ( var (
//go:embed icon.png //go:embed icon.png
defaultIconBytes []byte 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 { func Contains[T comparable](arr []T, v T) bool {
for _, value := range arr { for _, value := range arr {
if v == value { if v == value {
@@ -29,6 +38,36 @@ func Contains[T comparable](arr []T, v T) bool {
} }
func GetBlockedServerList() error { 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") resp, err := http.Get("https://sessionserver.mojang.com/blockedservers")
if err != nil { if err != nil {
@@ -39,6 +78,8 @@ func GetBlockedServerList() error {
return fmt.Errorf("unexpected status code: %d", resp.StatusCode) return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
} }
log.Println("Successfully retrieved EULA blocked servers")
defer resp.Body.Close() defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body) body, err := ioutil.ReadAll(resp.Body)
@@ -49,9 +90,27 @@ func GetBlockedServerList() error {
blockedServersMutex.Lock() blockedServersMutex.Lock()
blockedServers = strings.Split(string(body), "\n") 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 { func IsBlockedAddress(address string) bool {