Fetch blocked servers without Redis

This commit is contained in:
Jacob Gunther
2023-02-26 14:22:03 -06:00
parent b2ffb03e1d
commit 4a5ff4938e
11 changed files with 166 additions and 133 deletions

View File

@@ -1,48 +0,0 @@
package main
import (
"fmt"
"io"
"log"
"net/http"
"strings"
"time"
)
func StartBlockedServersGoroutine() {
for {
if err := GetBlockedServerList(); err != nil {
log.Println(err)
}
time.Sleep(time.Hour)
}
}
func GetBlockedServerList() error {
resp, err := http.Get("https://sessionserver.mojang.com/blockedservers")
if err != nil {
return err
}
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
for _, hash := range strings.Split(string(body), "\n") {
if err = r.Set(fmt.Sprintf("blocked:%s", hash), "true", time.Hour*24); err != nil {
return err
}
}
return nil
}

View File

@@ -8,19 +8,15 @@ import (
)
type Config struct {
Environment string `yaml:"environment"`
Host string `yaml:"host"`
Port uint16 `yaml:"port"`
Redis struct {
Host string `yaml:"host"`
Port uint16 `yaml:"port"`
Username string `yaml:"username"`
Password string `yaml:"password"`
Database int `yaml:"database"`
JavaCacheDuration time.Duration `yaml:"java_cache_duration"`
BedrockCacheDuration time.Duration `yaml:"bedrock_cache_duration"`
IconCacheDuration time.Duration `yaml:"icon_cache_duration"`
} `yaml:"redis"`
Environment string `yaml:"environment"`
Host string `yaml:"host"`
Port uint16 `yaml:"port"`
Redis *string `yaml:"redis"`
Cache struct {
JavaStatusDuration time.Duration `yaml:"java_status_duration"`
BedrockStatusDuration time.Duration `yaml:"bedrock_status_duration"`
IconDuration time.Duration `yaml:"icon_duration"`
} `yaml:"cache"`
}
func (c *Config) ReadFile(file string) error {

View File

@@ -29,11 +29,19 @@ func init() {
log.Fatal(err)
}
if err := r.Connect(); err != nil {
if err := GetBlockedServerList(); err != nil {
log.Fatal(err)
}
log.Println("Successfully connected to Redis")
log.Println("Successfully retrieved EULA blocked servers")
if config.Redis != nil {
if err := r.Connect(); err != nil {
log.Fatal(err)
}
log.Println("Successfully connected to Redis")
}
app.Use(recover.New())
@@ -41,11 +49,11 @@ func init() {
app.Use(cors.New(cors.Config{
AllowOrigins: "*",
AllowMethods: "HEAD,OPTIONS,GET",
ExposeHeaders: "Content-Type,X-Cache-Time-Remaining",
ExposeHeaders: "X-Cache-Time-Remaining",
}))
app.Use(logger.New(logger.Config{
Format: "${time} ${ip}:${port} -> ${method} ${path} -> ${status}\n",
Format: "${time} ${ip}:${port} -> ${status}: ${method} ${path} (${latency})\n",
TimeFormat: "2006/01/02 15:04:05",
}))
}
@@ -54,8 +62,6 @@ func init() {
func main() {
defer r.Close()
go StartBlockedServersGoroutine()
log.Printf("Listening on %s:%d\n", config.Host, config.Port)
log.Fatal(app.Listen(fmt.Sprintf("%s:%d", config.Host, config.Port)))
}

View File

@@ -2,7 +2,6 @@ package main
import (
"context"
"fmt"
"time"
"github.com/go-redis/redis/v8"
@@ -13,12 +12,13 @@ type Redis struct {
}
func (r *Redis) Connect() error {
r.Client = redis.NewClient(&redis.Options{
Addr: fmt.Sprintf("%s:%d", config.Redis.Host, config.Redis.Port),
Username: config.Redis.Username,
Password: config.Redis.Password,
DB: config.Redis.Database,
})
opts, err := redis.ParseURL(*config.Redis)
if err != nil {
return err
}
r.Client = redis.NewClient(opts)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)

View File

@@ -126,7 +126,7 @@ func GetJavaStatus(host string, port uint16) (*JavaStatusResponse, *time.Duratio
return nil, nil, err
}
if err := r.Set(cacheKey, data, config.Redis.JavaCacheDuration); err != nil {
if err := r.Set(cacheKey, data, config.Cache.JavaStatusDuration); err != nil {
return nil, nil, err
}
@@ -172,7 +172,7 @@ func GetBedrockStatus(host string, port uint16) (*BedrockStatusResponse, *time.D
return nil, nil, err
}
if err := r.Set(cacheKey, data, config.Redis.BedrockCacheDuration); err != nil {
if err := r.Set(cacheKey, data, config.Cache.BedrockStatusDuration); err != nil {
return nil, nil, err
}
@@ -214,7 +214,7 @@ func GetServerIcon(host string, port uint16) ([]byte, *time.Duration, error) {
icon = data
}
if err := r.Set(cacheKey, icon, config.Redis.IconCacheDuration); err != nil {
if err := r.Set(cacheKey, icon, config.Cache.IconDuration); err != nil {
return nil, nil, err
}
@@ -222,12 +222,6 @@ func GetServerIcon(host string, port uint16) ([]byte, *time.Duration, error) {
}
func FetchJavaStatus(host string, port uint16) (*JavaStatusResponse, error) {
isEULABlocked, err := IsBlockedAddress(host)
if err != nil {
return nil, err
}
status, err := mcutil.Status(host, port)
if err != nil {
@@ -239,9 +233,9 @@ func FetchJavaStatus(host string, port uint16) (*JavaStatusResponse, error) {
Online: false,
Host: host,
Port: port,
EULABlocked: isEULABlocked,
EULABlocked: IsBlockedAddress(host),
RetrievedAt: time.Now().UnixMilli(),
ExpiresAt: time.Now().Add(config.Redis.JavaCacheDuration).UnixMilli(),
ExpiresAt: time.Now().Add(config.Cache.JavaStatusDuration).UnixMilli(),
},
}, nil
}
@@ -251,9 +245,9 @@ func FetchJavaStatus(host string, port uint16) (*JavaStatusResponse, error) {
Online: true,
Host: host,
Port: port,
EULABlocked: isEULABlocked,
EULABlocked: IsBlockedAddress(host),
RetrievedAt: time.Now().UnixMilli(),
ExpiresAt: time.Now().Add(config.Redis.JavaCacheDuration).UnixMilli(),
ExpiresAt: time.Now().Add(config.Cache.JavaStatusDuration).UnixMilli(),
},
JavaStatus: &JavaStatus{
Version: nil,
@@ -313,9 +307,9 @@ func FetchJavaStatus(host string, port uint16) (*JavaStatusResponse, error) {
Online: true,
Host: host,
Port: port,
EULABlocked: isEULABlocked,
EULABlocked: IsBlockedAddress(host),
RetrievedAt: time.Now().UnixMilli(),
ExpiresAt: time.Now().Add(config.Redis.JavaCacheDuration).UnixMilli(),
ExpiresAt: time.Now().Add(config.Cache.JavaStatusDuration).UnixMilli(),
},
JavaStatus: &JavaStatus{
Version: &JavaVersion{
@@ -341,12 +335,6 @@ func FetchJavaStatus(host string, port uint16) (*JavaStatusResponse, error) {
}
func FetchBedrockStatus(host string, port uint16) (*BedrockStatusResponse, error) {
isEULABlocked, err := IsBlockedAddress(host)
if err != nil {
return nil, err
}
status, err := mcutil.StatusBedrock(host, port)
if err != nil {
@@ -355,9 +343,9 @@ func FetchBedrockStatus(host string, port uint16) (*BedrockStatusResponse, error
Online: false,
Host: host,
Port: port,
EULABlocked: isEULABlocked,
EULABlocked: IsBlockedAddress(host),
RetrievedAt: time.Now().UnixMilli(),
ExpiresAt: time.Now().Add(config.Redis.BedrockCacheDuration).UnixMilli(),
ExpiresAt: time.Now().Add(config.Cache.BedrockStatusDuration).UnixMilli(),
},
}, nil
}
@@ -367,9 +355,9 @@ func FetchBedrockStatus(host string, port uint16) (*BedrockStatusResponse, error
Online: true,
Host: host,
Port: port,
EULABlocked: isEULABlocked,
EULABlocked: IsBlockedAddress(host),
RetrievedAt: time.Now().UnixMilli(),
ExpiresAt: time.Now().Add(config.Redis.BedrockCacheDuration).UnixMilli(),
ExpiresAt: time.Now().Add(config.Cache.BedrockStatusDuration).UnixMilli(),
},
BedrockStatus: &BedrockStatus{
Version: nil,

View File

@@ -5,20 +5,69 @@ import (
_ "embed"
"encoding/hex"
"fmt"
"io"
"net/http"
"regexp"
"strconv"
"strings"
"sync"
)
var (
//go:embed icon.png
defaultIcon []byte
ipAddressRegExp *regexp.Regexp = regexp.MustCompile(`^\d{1,3}(\.\d{1,3}){3}$`)
blockedServers *MutexArray[string] = nil
ipAddressRegExp *regexp.Regexp = regexp.MustCompile(`^\d{1,3}(\.\d{1,3}){3}$`)
)
func IsBlockedAddress(address string) (bool, error) {
split := strings.Split(strings.ToLower(address), ".")
type MutexArray[K comparable] struct {
List []K
Mutex *sync.Mutex
}
func (m *MutexArray[K]) Has(value K) bool {
m.Mutex.Lock()
defer m.Mutex.Unlock()
for _, v := range m.List {
if v == value {
return true
}
}
return false
}
func GetBlockedServerList() error {
resp, err := http.Get("https://sessionserver.mojang.com/blockedservers")
if err != nil {
return err
}
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
blockedServers = &MutexArray[string]{
List: strings.Split(string(body), "\n"),
Mutex: &sync.Mutex{},
}
return nil
}
func IsBlockedAddress(address string) bool {
split := strings.Split(strings.ToLower(address), ".")
isIPAddress := ipAddressRegExp.MatchString(address)
for k := range split {
@@ -44,19 +93,14 @@ func IsBlockedAddress(address string) (bool, error) {
}
newAddressBytes := sha1.Sum([]byte(newAddress))
newAddressHash := hex.EncodeToString(newAddressBytes[:])
exists, err := r.Exists(fmt.Sprintf("blocked:%s", hex.EncodeToString(newAddressBytes[:])))
if err != nil {
return false, err
}
if exists {
return true, nil
if blockedServers.Has(newAddressHash) {
return true
}
}
return false, nil
return false
}
func ParseAddress(address string, defaultPort uint16) (string, uint16, error) {