Code cleanup and organization

This commit is contained in:
Jacob Gunther
2023-07-28 15:27:42 -05:00
parent be7a307d19
commit 71ce3ea8b4
3 changed files with 113 additions and 79 deletions

View File

@@ -1,5 +0,0 @@
package main
func ListenAndServe(host string, port uint16) {
}

View File

@@ -114,83 +114,98 @@ 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, enableQuery bool) (*JavaStatusResponse, time.Duration, error) { func GetJavaStatus(host string, port uint16, query bool) (*JavaStatusResponse, time.Duration, error) {
cacheKey := fmt.Sprintf("java:%v-%s-%d", enableQuery, host, port) cacheKey := GetCacheKey(host, port, query)
// Wait for any other processes to finish fetching the status of this server
if conf.Cache.EnableLocks { if conf.Cache.EnableLocks {
mutex := r.NewMutex(fmt.Sprintf("java-lock:%v-%s-%d", enableQuery, host, port)) mutex := r.NewMutex(fmt.Sprintf("java-lock:%s", cacheKey))
mutex.Lock() mutex.Lock()
defer mutex.Unlock() defer mutex.Unlock()
} }
cache, ttl, err := r.Get(cacheKey) // Fetch the cached status if it exists
{
cache, ttl, err := r.Get(fmt.Sprintf("java:%s", cacheKey))
if err != nil { if err != nil {
return nil, 0, err return nil, 0, err
}
if cache != nil {
var response JavaStatusResponse
err = json.Unmarshal(cache, &response)
return &response, ttl, err
}
} }
if cache != nil { // Fetch a fresh status from the server itself
var response JavaStatusResponse {
response := FetchJavaStatus(host, port, query)
err = json.Unmarshal(cache, &response) data, err := json.Marshal(response)
return &response, ttl, err if err != nil {
return nil, 0, err
}
if err := r.Set(fmt.Sprintf("java:%s", cacheKey), data, conf.Cache.JavaStatusDuration); err != nil {
return nil, 0, err
}
return &response, 0, nil
} }
response := FetchJavaStatus(host, port, enableQuery)
data, err := json.Marshal(response)
if err != nil {
return nil, 0, err
}
if err := r.Set(cacheKey, data, conf.Cache.JavaStatusDuration); err != nil {
return nil, 0, err
}
return &response, 0, nil
} }
// 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) (*BedrockStatusResponse, time.Duration, error) {
cacheKey := fmt.Sprintf("bedrock:%s-%d", host, port) cacheKey := GetCacheKey(host, port, false)
// Wait for any other processes to finish fetching the status of this server
if conf.Cache.EnableLocks { if conf.Cache.EnableLocks {
mutex := r.NewMutex(fmt.Sprintf("bedrock-lock:%s-%d", host, port)) mutex := r.NewMutex(fmt.Sprintf("bedrock-lock:%s", cacheKey))
mutex.Lock() mutex.Lock()
defer mutex.Unlock() defer mutex.Unlock()
} }
cache, ttl, err := r.Get(cacheKey) // Fetch the cached status if it exists
{
cache, ttl, err := r.Get(fmt.Sprintf("bedrock:%s", cacheKey))
if err != nil { if err != nil {
return nil, 0, err return nil, 0, err
}
if cache != nil {
var response BedrockStatusResponse
err = json.Unmarshal(cache, &response)
return &response, ttl, err
}
} }
if cache != nil { var (
var response BedrockStatusResponse err error = nil
response *BedrockStatusResponse = nil
data []byte = nil
)
err = json.Unmarshal(cache, &response) // Fetch a fresh status from the server itself
{
response = FetchBedrockStatus(host, port)
return &response, ttl, err if data, err = json.Marshal(response); err != nil {
return nil, 0, err
}
} }
response, err := FetchBedrockStatus(host, port) // Put the status into the cache for future requests
if err = r.Set(fmt.Sprintf("bedrock:%s", cacheKey), data, conf.Cache.BedrockStatusDuration); err != nil {
if err != nil {
return nil, 0, err
}
data, err := json.Marshal(response)
if err != nil {
return nil, 0, err
}
if err := r.Set(cacheKey, data, conf.Cache.BedrockStatusDuration); err != nil {
return nil, 0, err return nil, 0, err
} }
@@ -199,33 +214,44 @@ 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) ([]byte, time.Duration, error) {
cacheKey := fmt.Sprintf("icon:%s-%d", host, port) cacheKey := GetCacheKey(host, port, false)
cache, ttl, err := r.Get(cacheKey) // Fetch the cached icon if it exists
{
if err != nil { cache, ttl, err := r.Get(fmt.Sprintf("icon:%s", cacheKey))
return nil, 0, err
}
if cache != nil {
return cache, ttl, err
}
icon := assets.DefaultIcon
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 { if err != nil {
return nil, 0, err return nil, 0, err
} }
icon = data if cache != nil {
return cache, ttl, err
}
} }
if err := r.Set(cacheKey, icon, conf.Cache.IconDuration); err != nil { var (
icon []byte = nil
)
// Fetch the icon from the server itself
{
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, 0, err
}
icon = data
} else {
icon = assets.DefaultIcon
}
}
// Put the icon into the cache for future requests
if err := r.Set(fmt.Sprintf("icon:%s", cacheKey), icon, conf.Cache.IconDuration); err != nil {
return nil, 0, err return nil, 0, err
} }
@@ -242,16 +268,18 @@ func FetchJavaStatus(host string, port uint16, enableQuery bool) JavaStatusRespo
wg.Add(1) wg.Add(1)
} }
var status interface{} = nil var (
var query *response.FullQuery = nil statusResult interface{} = nil
queryResult *response.FullQuery = nil
)
// Status // Status
{ {
go func() { go func() {
if result, _ := mcutil.Status(host, port); result != nil { if result, _ := mcutil.Status(host, port); result != nil {
status = result statusResult = result
} else if result, _ := mcutil.StatusLegacy(host, port); result != nil { } else if result, _ := mcutil.StatusLegacy(host, port); result != nil {
status = result statusResult = result
} }
wg.Done() wg.Done()
@@ -261,7 +289,7 @@ func FetchJavaStatus(host string, port uint16, enableQuery bool) JavaStatusRespo
// Query // Query
if enableQuery { if enableQuery {
go func() { go func() {
query, _ = mcutil.FullQuery(host, port, options.Query{ queryResult, _ = mcutil.FullQuery(host, port, options.Query{
Timeout: time.Second, Timeout: time.Second,
}) })
@@ -271,11 +299,11 @@ func FetchJavaStatus(host string, port uint16, enableQuery bool) JavaStatusRespo
wg.Wait() wg.Wait()
return BuildJavaResponse(host, port, status, query) return BuildJavaResponse(host, port, statusResult, 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, error) { func FetchBedrockStatus(host string, port uint16) *BedrockStatusResponse {
status, err := mcutil.StatusBedrock(host, port) status, err := mcutil.StatusBedrock(host, port)
if err != nil { if err != nil {
@@ -288,7 +316,7 @@ func FetchBedrockStatus(host string, port uint16) (*BedrockStatusResponse, error
RetrievedAt: time.Now().UnixMilli(), RetrievedAt: time.Now().UnixMilli(),
ExpiresAt: time.Now().Add(conf.Cache.BedrockStatusDuration).UnixMilli(), ExpiresAt: time.Now().Add(conf.Cache.BedrockStatusDuration).UnixMilli(),
}, },
}, nil }
} }
response := &BedrockStatusResponse{ response := &BedrockStatusResponse{
@@ -362,7 +390,7 @@ func FetchBedrockStatus(host string, port uint16) (*BedrockStatusResponse, error
} }
} }
return response, nil return response
} }
// BuildJavaResponse builds the response data from the status and query information. // BuildJavaResponse builds the response data from the status and query information.

View File

@@ -8,6 +8,7 @@ import (
"io" "io"
"log" "log"
"net/http" "net/http"
"net/url"
"os" "os"
"regexp" "regexp"
"strconv" "strconv"
@@ -136,6 +137,16 @@ func GetInstanceID() (uint16, error) {
return 0, nil return 0, nil
} }
// GetCacheKey generates a unique key used for caching status results in Redis.
func GetCacheKey(host string, port uint16, query bool) string {
values := &url.Values{}
values.Set("host", host)
values.Set("port", strconv.FormatUint(uint64(port), 10))
values.Set("query", strconv.FormatBool(query))
return SHA256(values.Encode())
}
// SHA256 returns the result of hashing the input value using SHA256 algorithm. // SHA256 returns the result of hashing the input value using SHA256 algorithm.
func SHA256(input string) string { func SHA256(input string) string {
result := sha1.Sum([]byte(input)) result := sha1.Sum([]byte(input))