From 71ce3ea8b44da273b6f7ff6154ce476b1761a138 Mon Sep 17 00:00:00 2001 From: Jacob Gunther Date: Fri, 28 Jul 2023 15:27:42 -0500 Subject: [PATCH] Code cleanup and organization --- src/server.go | 5 -- src/status.go | 176 +++++++++++++++++++++++++++++--------------------- src/util.go | 11 ++++ 3 files changed, 113 insertions(+), 79 deletions(-) delete mode 100644 src/server.go diff --git a/src/server.go b/src/server.go deleted file mode 100644 index bd2b881..0000000 --- a/src/server.go +++ /dev/null @@ -1,5 +0,0 @@ -package main - -func ListenAndServe(host string, port uint16) { - -} diff --git a/src/status.go b/src/status.go index 0f107fe..5a7ebb0 100644 --- a/src/status.go +++ b/src/status.go @@ -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. -func GetJavaStatus(host string, port uint16, enableQuery bool) (*JavaStatusResponse, time.Duration, error) { - cacheKey := fmt.Sprintf("java:%v-%s-%d", enableQuery, host, port) +func GetJavaStatus(host string, port uint16, query bool) (*JavaStatusResponse, time.Duration, error) { + cacheKey := GetCacheKey(host, port, query) + // Wait for any other processes to finish fetching the status of this server 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() 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 { - return nil, 0, err + if err != nil { + return nil, 0, err + } + + if cache != nil { + var response JavaStatusResponse + + err = json.Unmarshal(cache, &response) + + return &response, ttl, err + } } - if cache != nil { - var response JavaStatusResponse + // Fetch a fresh status from the server itself + { + 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. 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 { - mutex := r.NewMutex(fmt.Sprintf("bedrock-lock:%s-%d", host, port)) + mutex := r.NewMutex(fmt.Sprintf("bedrock-lock:%s", cacheKey)) mutex.Lock() 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 { - return nil, 0, err + if err != nil { + return nil, 0, err + } + + if cache != nil { + var response BedrockStatusResponse + + err = json.Unmarshal(cache, &response) + + return &response, ttl, err + } } - if cache != nil { - var response BedrockStatusResponse + var ( + 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) - - 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 { + // Put the status into the cache for future requests + if err = r.Set(fmt.Sprintf("bedrock:%s", cacheKey), data, conf.Cache.BedrockStatusDuration); err != nil { 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. 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) - - if err != nil { - 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,")) + // Fetch the cached icon if it exists + { + cache, ttl, err := r.Get(fmt.Sprintf("icon:%s", cacheKey)) if err != nil { 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 } @@ -242,16 +268,18 @@ func FetchJavaStatus(host string, port uint16, enableQuery bool) JavaStatusRespo wg.Add(1) } - var status interface{} = nil - var query *response.FullQuery = nil + var ( + statusResult interface{} = nil + queryResult *response.FullQuery = nil + ) // Status { go func() { if result, _ := mcutil.Status(host, port); result != nil { - status = result + statusResult = result } else if result, _ := mcutil.StatusLegacy(host, port); result != nil { - status = result + statusResult = result } wg.Done() @@ -261,7 +289,7 @@ func FetchJavaStatus(host string, port uint16, enableQuery bool) JavaStatusRespo // Query if enableQuery { go func() { - query, _ = mcutil.FullQuery(host, port, options.Query{ + queryResult, _ = mcutil.FullQuery(host, port, options.Query{ Timeout: time.Second, }) @@ -271,11 +299,11 @@ func FetchJavaStatus(host string, port uint16, enableQuery bool) JavaStatusRespo wg.Wait() - return BuildJavaResponse(host, port, status, query) + return BuildJavaResponse(host, port, statusResult, queryResult) } // 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) if err != nil { @@ -288,7 +316,7 @@ func FetchBedrockStatus(host string, port uint16) (*BedrockStatusResponse, error RetrievedAt: time.Now().UnixMilli(), ExpiresAt: time.Now().Add(conf.Cache.BedrockStatusDuration).UnixMilli(), }, - }, nil + } } 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. diff --git a/src/util.go b/src/util.go index f2d5957..ca89a71 100644 --- a/src/util.go +++ b/src/util.go @@ -8,6 +8,7 @@ import ( "io" "log" "net/http" + "net/url" "os" "regexp" "strconv" @@ -136,6 +137,16 @@ func GetInstanceID() (uint16, error) { 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. func SHA256(input string) string { result := sha1.Sum([]byte(input))