Code cleanup and add exported function comments
This commit is contained in:
@@ -9,17 +9,35 @@ import (
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultConfig is the default configuration values used by the application.
|
||||
DefaultConfig *Config = &Config{
|
||||
Environment: "production",
|
||||
Host: "127.0.0.1",
|
||||
Port: 3001,
|
||||
Redis: nil,
|
||||
Cache: ConfigCache{
|
||||
JavaStatusDuration: time.Minute,
|
||||
BedrockStatusDuration: time.Minute,
|
||||
IconDuration: time.Minute * 15,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// Config represents the application configuration.
|
||||
type Config struct {
|
||||
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" json:"java_status_duration"`
|
||||
BedrockStatusDuration time.Duration `yaml:"bedrock_status_duration" json:"bedrock_status_duration"`
|
||||
IconDuration time.Duration `yaml:"icon_duration" json:"icon_duration"`
|
||||
} `yaml:"cache"`
|
||||
Environment string `yaml:"environment"`
|
||||
Host string `yaml:"host"`
|
||||
Port uint16 `yaml:"port"`
|
||||
Redis *string `yaml:"redis"`
|
||||
Cache ConfigCache `yaml:"cache"`
|
||||
}
|
||||
|
||||
// ConfigCache represents the caching durations of various responses.
|
||||
type ConfigCache struct {
|
||||
JavaStatusDuration time.Duration `yaml:"java_status_duration" json:"java_status_duration"`
|
||||
BedrockStatusDuration time.Duration `yaml:"bedrock_status_duration" json:"bedrock_status_duration"`
|
||||
IconDuration time.Duration `yaml:"icon_duration" json:"icon_duration"`
|
||||
}
|
||||
|
||||
// ReadFile reads the configuration from the given file and overrides values using environment variables.
|
||||
@@ -37,6 +55,17 @@ func (c *Config) ReadFile(file string) error {
|
||||
return c.overrideWithEnvVars()
|
||||
}
|
||||
|
||||
// WriteFile writes the configuration values to a file.
|
||||
func (c *Config) WriteFile(file string) error {
|
||||
data, err := yaml.Marshal(c)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return os.WriteFile(file, data, 0777)
|
||||
}
|
||||
|
||||
// overrideWithEnvVars overrides configuration values using environment variables.
|
||||
func (c *Config) overrideWithEnvVars() error {
|
||||
if value := os.Getenv("ENVIRONMENT"); value != "" {
|
||||
|
||||
30
src/main.go
30
src/main.go
@@ -1,9 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/cors"
|
||||
@@ -20,24 +22,32 @@ var (
|
||||
return ctx.SendStatus(http.StatusInternalServerError)
|
||||
},
|
||||
})
|
||||
r *Redis = &Redis{}
|
||||
config *Config = &Config{}
|
||||
r *Redis = &Redis{}
|
||||
conf *Config = DefaultConfig
|
||||
)
|
||||
|
||||
func init() {
|
||||
if err := config.ReadFile("config.yml"); err != nil {
|
||||
log.Fatalf("failed to read config file: %v", err)
|
||||
if err := conf.ReadFile("config.yml"); err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
log.Printf("config.yml does not exist, writing default config\n")
|
||||
|
||||
if err = conf.WriteFile("config.yml"); err != nil {
|
||||
log.Fatalf("Failed to write config file: %v", err)
|
||||
}
|
||||
} else {
|
||||
log.Printf("Failed to read config file: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := GetBlockedServerList(); err != nil {
|
||||
log.Fatalf("failed to retrieve EULA blocked servers: %v", err)
|
||||
log.Fatalf("Failed to retrieve EULA blocked servers: %v", err)
|
||||
}
|
||||
|
||||
log.Println("Successfully retrieved EULA blocked servers")
|
||||
|
||||
if config.Redis != nil {
|
||||
if conf.Redis != nil {
|
||||
if err := r.Connect(); err != nil {
|
||||
log.Fatalf("failed to connect to Redis: %v", err)
|
||||
log.Fatalf("Failed to connect to Redis: %v", err)
|
||||
}
|
||||
|
||||
log.Println("Successfully connected to Redis")
|
||||
@@ -47,7 +57,7 @@ func init() {
|
||||
EnableStackTrace: true,
|
||||
}))
|
||||
|
||||
if config.Environment == "development" {
|
||||
if conf.Environment == "development" {
|
||||
app.Use(cors.New(cors.Config{
|
||||
AllowOrigins: "*",
|
||||
AllowMethods: "HEAD,OPTIONS,GET",
|
||||
@@ -64,9 +74,9 @@ func init() {
|
||||
func main() {
|
||||
defer r.Close()
|
||||
|
||||
log.Printf("Listening on %s:%d\n", config.Host, config.Port)
|
||||
log.Printf("Listening on %s:%d\n", conf.Host, conf.Port)
|
||||
|
||||
if err := app.Listen(fmt.Sprintf("%s:%d", config.Host, config.Port)); err != nil {
|
||||
if err := app.Listen(fmt.Sprintf("%s:%d", conf.Host, conf.Port)); err != nil {
|
||||
log.Fatalf("failed to start server: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,11 +17,12 @@ type Redis struct {
|
||||
|
||||
// Connect establishes a connection to the Redis server using the configuration.
|
||||
func (r *Redis) Connect() error {
|
||||
if config.Redis == nil {
|
||||
if conf.Redis == nil {
|
||||
return errors.New("missing Redis configuration")
|
||||
}
|
||||
|
||||
opts, err := redis.ParseURL(*config.Redis)
|
||||
opts, err := redis.ParseURL(*conf.Redis)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -29,6 +30,7 @@ func (r *Redis) Connect() error {
|
||||
r.Client = redis.NewClient(opts)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
|
||||
|
||||
defer cancel()
|
||||
|
||||
return r.Client.Ping(ctx).Err()
|
||||
@@ -41,6 +43,7 @@ func (r *Redis) Get(key string) ([]byte, time.Duration, error) {
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
|
||||
|
||||
defer cancel()
|
||||
|
||||
p := r.Client.Pipeline()
|
||||
@@ -68,6 +71,7 @@ func (r *Redis) Set(key string, value interface{}, ttl time.Duration) error {
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
|
||||
|
||||
defer cancel()
|
||||
|
||||
return r.Client.Set(ctx, key, value, ttl).Err()
|
||||
@@ -80,6 +84,7 @@ func (r *Redis) Increment(key string) error {
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
|
||||
|
||||
defer cancel()
|
||||
|
||||
return r.Client.Incr(ctx, key).Err()
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/mcstatus-io/mcutil"
|
||||
)
|
||||
|
||||
// StatusResponse is the root response for returning any status response from the API.
|
||||
type StatusResponse struct {
|
||||
Online bool `json:"online"`
|
||||
Host string `json:"host"`
|
||||
@@ -19,11 +20,13 @@ type StatusResponse struct {
|
||||
ExpiresAt int64 `json:"expires_at"`
|
||||
}
|
||||
|
||||
// JavaStatusResponse is the combined response of the root response and the Java Edition status response.
|
||||
type JavaStatusResponse struct {
|
||||
StatusResponse
|
||||
*JavaStatus
|
||||
}
|
||||
|
||||
// JavaStatus is the status response properties for Java Edition.
|
||||
type JavaStatus struct {
|
||||
Version *JavaVersion `json:"version"`
|
||||
Players JavaPlayers `json:"players"`
|
||||
@@ -32,11 +35,13 @@ type JavaStatus struct {
|
||||
Mods []Mod `json:"mods"`
|
||||
}
|
||||
|
||||
// BedrockStatusResponse is the combined response of the root response and the Bedrock Edition status response.
|
||||
type BedrockStatusResponse struct {
|
||||
StatusResponse
|
||||
*BedrockStatus
|
||||
}
|
||||
|
||||
// BedrockStatus is the status response properties for Bedrock Edition.
|
||||
type BedrockStatus struct {
|
||||
Version *BedrockVersion `json:"version"`
|
||||
Players *BedrockPlayers `json:"players"`
|
||||
@@ -46,29 +51,34 @@ type BedrockStatus struct {
|
||||
Edition *string `json:"edition"`
|
||||
}
|
||||
|
||||
// JavaVersion holds the properties for the version of Java Edition responses.
|
||||
type JavaVersion struct {
|
||||
NameRaw string `json:"name_raw"`
|
||||
NameClean string `json:"name_clean"`
|
||||
NameHTML string `json:"name_html"`
|
||||
Protocol int `json:"protocol"`
|
||||
Protocol int64 `json:"protocol"`
|
||||
}
|
||||
|
||||
// BedrockVersion holds the properties for the version of Bedrock Edition responses.
|
||||
type BedrockVersion struct {
|
||||
Name *string `json:"name"`
|
||||
Protocol *int64 `json:"protocol"`
|
||||
}
|
||||
|
||||
// JavaPlayers holds the properties for the players of Java Edition responses.
|
||||
type JavaPlayers struct {
|
||||
Online int `json:"online"`
|
||||
Max int `json:"max"`
|
||||
Online *int64 `json:"online"`
|
||||
Max *int64 `json:"max"`
|
||||
List []Player `json:"list"`
|
||||
}
|
||||
|
||||
// BedrockPlayers holds the properties for the players of Bedrock Edition responses.
|
||||
type BedrockPlayers struct {
|
||||
Online *int64 `json:"online"`
|
||||
Max *int64 `json:"max"`
|
||||
}
|
||||
|
||||
// Player is a single sample player used in Java Edition status responses.
|
||||
type Player struct {
|
||||
UUID string `json:"uuid"`
|
||||
NameRaw string `json:"name_raw"`
|
||||
@@ -76,17 +86,20 @@ type Player struct {
|
||||
NameHTML string `json:"name_html"`
|
||||
}
|
||||
|
||||
// MOTD is a group of formatted and unformatted properties for status responses.
|
||||
type MOTD struct {
|
||||
Raw string `json:"raw"`
|
||||
Clean string `json:"clean"`
|
||||
HTML string `json:"html"`
|
||||
}
|
||||
|
||||
// Mod is a single Forge mod installed on any Java Edition status response.
|
||||
type Mod struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
// GetJavaStatus returns the status response of a Java Edition server, either using cache or fetching a fresh status.
|
||||
func GetJavaStatus(host string, port uint16) (*JavaStatusResponse, time.Duration, error) {
|
||||
cacheKey := fmt.Sprintf("java:%s-%d", host, port)
|
||||
|
||||
@@ -116,13 +129,14 @@ func GetJavaStatus(host string, port uint16) (*JavaStatusResponse, time.Duration
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if err := r.Set(cacheKey, data, config.Cache.JavaStatusDuration); err != nil {
|
||||
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)
|
||||
|
||||
@@ -152,13 +166,14 @@ func GetBedrockStatus(host string, port uint16) (*BedrockStatusResponse, time.Du
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if err := r.Set(cacheKey, data, config.Cache.BedrockStatusDuration); err != nil {
|
||||
if err := r.Set(cacheKey, data, conf.Cache.BedrockStatusDuration); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return response, 0, nil
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
||||
@@ -186,13 +201,14 @@ func GetServerIcon(host string, port uint16) ([]byte, time.Duration, error) {
|
||||
icon = data
|
||||
}
|
||||
|
||||
if err := r.Set(cacheKey, icon, config.Cache.IconDuration); err != nil {
|
||||
if err := r.Set(cacheKey, icon, conf.Cache.IconDuration); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return icon, 0, nil
|
||||
}
|
||||
|
||||
// FetchJavaStatus fetches a fresh status of a Java Edition server.
|
||||
func FetchJavaStatus(host string, port uint16) (*JavaStatusResponse, error) {
|
||||
status, err := mcutil.Status(host, port)
|
||||
|
||||
@@ -207,7 +223,7 @@ func FetchJavaStatus(host string, port uint16) (*JavaStatusResponse, error) {
|
||||
Port: port,
|
||||
EULABlocked: IsBlockedAddress(host),
|
||||
RetrievedAt: time.Now().UnixMilli(),
|
||||
ExpiresAt: time.Now().Add(config.Cache.JavaStatusDuration).UnixMilli(),
|
||||
ExpiresAt: time.Now().Add(conf.Cache.JavaStatusDuration).UnixMilli(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
@@ -219,13 +235,13 @@ func FetchJavaStatus(host string, port uint16) (*JavaStatusResponse, error) {
|
||||
Port: port,
|
||||
EULABlocked: IsBlockedAddress(host),
|
||||
RetrievedAt: time.Now().UnixMilli(),
|
||||
ExpiresAt: time.Now().Add(config.Cache.JavaStatusDuration).UnixMilli(),
|
||||
ExpiresAt: time.Now().Add(conf.Cache.JavaStatusDuration).UnixMilli(),
|
||||
},
|
||||
JavaStatus: &JavaStatus{
|
||||
Version: nil,
|
||||
Players: JavaPlayers{
|
||||
Online: statusLegacy.Players.Online,
|
||||
Max: statusLegacy.Players.Max,
|
||||
Online: &statusLegacy.Players.Online,
|
||||
Max: &statusLegacy.Players.Max,
|
||||
List: make([]Player, 0),
|
||||
},
|
||||
MOTD: MOTD{
|
||||
@@ -281,7 +297,7 @@ func FetchJavaStatus(host string, port uint16) (*JavaStatusResponse, error) {
|
||||
Port: port,
|
||||
EULABlocked: IsBlockedAddress(host),
|
||||
RetrievedAt: time.Now().UnixMilli(),
|
||||
ExpiresAt: time.Now().Add(config.Cache.JavaStatusDuration).UnixMilli(),
|
||||
ExpiresAt: time.Now().Add(conf.Cache.JavaStatusDuration).UnixMilli(),
|
||||
},
|
||||
JavaStatus: &JavaStatus{
|
||||
Version: &JavaVersion{
|
||||
@@ -306,6 +322,7 @@ func FetchJavaStatus(host string, port uint16) (*JavaStatusResponse, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// FetchBedrockStatus fetches a fresh status of a Bedrock Edition server.
|
||||
func FetchBedrockStatus(host string, port uint16) (*BedrockStatusResponse, error) {
|
||||
status, err := mcutil.StatusBedrock(host, port)
|
||||
|
||||
@@ -317,7 +334,7 @@ func FetchBedrockStatus(host string, port uint16) (*BedrockStatusResponse, error
|
||||
Port: port,
|
||||
EULABlocked: IsBlockedAddress(host),
|
||||
RetrievedAt: time.Now().UnixMilli(),
|
||||
ExpiresAt: time.Now().Add(config.Cache.BedrockStatusDuration).UnixMilli(),
|
||||
ExpiresAt: time.Now().Add(conf.Cache.BedrockStatusDuration).UnixMilli(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
@@ -329,7 +346,7 @@ func FetchBedrockStatus(host string, port uint16) (*BedrockStatusResponse, error
|
||||
Port: port,
|
||||
EULABlocked: IsBlockedAddress(host),
|
||||
RetrievedAt: time.Now().UnixMilli(),
|
||||
ExpiresAt: time.Now().Add(config.Cache.BedrockStatusDuration).UnixMilli(),
|
||||
ExpiresAt: time.Now().Add(conf.Cache.BedrockStatusDuration).UnixMilli(),
|
||||
},
|
||||
BedrockStatus: &BedrockStatus{
|
||||
Version: nil,
|
||||
|
||||
Reference in New Issue
Block a user