Dockerfile, Error handling, comments, docker-compose (#2)
This commit is contained in:
parent
4488a9db70
commit
3c83c64f1a
43
Makefile
43
Makefile
@ -1,14 +1,37 @@
|
|||||||
build:
|
# Variables
|
||||||
go build -o bin/main src/*.go
|
BINARY := bin/main
|
||||||
|
SOURCES := $(wildcard src/*.go)
|
||||||
|
|
||||||
build-linux:
|
# Build for the current platform
|
||||||
GOOS=linux go build -o bin/main src/*.go
|
build: $(BINARY)
|
||||||
|
|
||||||
build-windows:
|
$(BINARY): $(SOURCES)
|
||||||
GOOS=windows go build -o bin/main src/*.go
|
go build -o $(BINARY) $(SOURCES)
|
||||||
|
|
||||||
run:
|
# Build for Linux
|
||||||
go run src/*.go
|
build-linux: GOOS := linux
|
||||||
|
build-linux: EXTENSION :=
|
||||||
|
build-linux: build-cross
|
||||||
|
|
||||||
flush-cache:
|
# Build for Windows
|
||||||
go run src/*.go --flush-cache
|
build-windows: GOOS := windows
|
||||||
|
build-windows: EXTENSION := .exe
|
||||||
|
build-windows: build-cross
|
||||||
|
|
||||||
|
# Cross-compile for a specific platform (used by build-linux and build-windows)
|
||||||
|
build-cross: export GOOS := $(GOOS)
|
||||||
|
build-cross: BINARY := $(BINARY)$(EXTENSION)
|
||||||
|
build-cross: $(BINARY)
|
||||||
|
|
||||||
|
# Run the application
|
||||||
|
run: build
|
||||||
|
./$(BINARY)
|
||||||
|
|
||||||
|
# Flush cache
|
||||||
|
flush-cache: build
|
||||||
|
./$(BINARY) --flush-cache
|
||||||
|
|
||||||
|
# Clean up generated files
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm -f $(BINARY) $(BINARY).exe
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
environment: production
|
environment: development
|
||||||
host: 127.0.0.1
|
host: 0.0.0.0
|
||||||
port: 3001
|
port: 3001
|
||||||
redis: redis://username:password@127.0.0.1:6379/0
|
redis: ${REDIS_URL} # Use an environment variable to define the Redis URL
|
||||||
cache:
|
cache:
|
||||||
java_status_duration: 1m
|
java_status_duration: 1m
|
||||||
bedrock_status_duration: 1m
|
bedrock_status_duration: 1m
|
||||||
icon_duration: 15m
|
icon_duration: 24h
|
||||||
36
docker-compose.yml
Normal file
36
docker-compose.yml
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
version: "3.9"
|
||||||
|
|
||||||
|
services:
|
||||||
|
ping-server:
|
||||||
|
build: .
|
||||||
|
image: ping-server
|
||||||
|
ports:
|
||||||
|
- "3001:3001"
|
||||||
|
depends_on:
|
||||||
|
- redis
|
||||||
|
networks:
|
||||||
|
- app_network
|
||||||
|
environment:
|
||||||
|
REDIS_URL: "redis://redis:6379" # Define the Redis URL using the hostname of the Redis service
|
||||||
|
volumes:
|
||||||
|
- type: bind
|
||||||
|
source: ./config.example.yml
|
||||||
|
target: /app/config.yml
|
||||||
|
read_only: true
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: "redis:latest"
|
||||||
|
command: ["redis-server", "--appendonly", "yes"]
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
|
networks:
|
||||||
|
- app_network
|
||||||
|
volumes:
|
||||||
|
- redis_data:/data
|
||||||
|
|
||||||
|
networks:
|
||||||
|
app_network:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
redis_data:
|
||||||
40
dockerfile
Normal file
40
dockerfile
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# Build stage
|
||||||
|
FROM golang:1.18 AS build
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install required dependencies
|
||||||
|
COPY go.mod go.sum ./
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
|
# Copy the source code
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Build the executable with CGO disabled
|
||||||
|
RUN CGO_ENABLED=0 go build -o bin/main src/*.go
|
||||||
|
RUN mv config.example.yml ./bin/config.yml
|
||||||
|
|
||||||
|
|
||||||
|
#######################
|
||||||
|
# Test stage
|
||||||
|
FROM build as test
|
||||||
|
RUN go test -v ./...
|
||||||
|
|
||||||
|
|
||||||
|
#######################
|
||||||
|
# Runtime stage
|
||||||
|
|
||||||
|
FROM gcr.io/distroless/base
|
||||||
|
|
||||||
|
# Set the working directory
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy the binary from the build stage
|
||||||
|
COPY --from=build /app/bin/main /app/main
|
||||||
|
COPY --from=build /app/bin/config.yml /app/config.yml
|
||||||
|
|
||||||
|
# Expose the port the app runs on (replace with your desired port)
|
||||||
|
EXPOSE 3001
|
||||||
|
|
||||||
|
# Run the app
|
||||||
|
CMD ["./main"]
|
||||||
@ -1,18 +1,22 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// CacheConfig contains cache-related settings.
|
||||||
type CacheConfig struct {
|
type CacheConfig struct {
|
||||||
JavaStatusDuration time.Duration `yaml:"java_status_duration" json:"java_status_duration"`
|
JavaStatusDuration time.Duration `yaml:"java_status_duration" json:"java_status_duration"`
|
||||||
BedrockStatusDuration time.Duration `yaml:"bedrock_status_duration" json:"bedrock_status_duration"`
|
BedrockStatusDuration time.Duration `yaml:"bedrock_status_duration" json:"bedrock_status_duration"`
|
||||||
IconDuration time.Duration `yaml:"icon_duration" json:"icon_duration"`
|
IconDuration time.Duration `yaml:"icon_duration" json:"icon_duration"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Config represents the application configuration.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Environment string `yaml:"environment"`
|
Environment string `yaml:"environment"`
|
||||||
Host string `yaml:"host"`
|
Host string `yaml:"host"`
|
||||||
@ -21,12 +25,40 @@ type Config struct {
|
|||||||
Cache CacheConfig `yaml:"cache"`
|
Cache CacheConfig `yaml:"cache"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReadFile reads the configuration from the given file and overrides values using environment variables.
|
||||||
func (c *Config) ReadFile(file string) error {
|
func (c *Config) ReadFile(file string) error {
|
||||||
data, err := os.ReadFile(file)
|
data, err := os.ReadFile(file)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return yaml.Unmarshal(data, c)
|
if err := yaml.Unmarshal(data, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.overrideWithEnvVars()
|
||||||
|
}
|
||||||
|
|
||||||
|
// overrideWithEnvVars overrides configuration values using environment variables.
|
||||||
|
func (c *Config) overrideWithEnvVars() error {
|
||||||
|
if env := os.Getenv("ENVIRONMENT"); env != "" {
|
||||||
|
c.Environment = env
|
||||||
|
}
|
||||||
|
|
||||||
|
if host := os.Getenv("HOST"); host != "" {
|
||||||
|
c.Host = host
|
||||||
|
}
|
||||||
|
|
||||||
|
if port := os.Getenv("PORT"); port != "" {
|
||||||
|
portInt, err := strconv.Atoi(port)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("invalid port value in environment variable")
|
||||||
|
}
|
||||||
|
c.Port = uint16(portInt)
|
||||||
|
}
|
||||||
|
if redisURL := os.Getenv("REDIS_URL"); redisURL != "" {
|
||||||
|
c.Redis = &redisURL
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
19
src/main.go
19
src/main.go
@ -15,8 +15,7 @@ var (
|
|||||||
app *fiber.App = fiber.New(fiber.Config{
|
app *fiber.App = fiber.New(fiber.Config{
|
||||||
DisableStartupMessage: true,
|
DisableStartupMessage: true,
|
||||||
ErrorHandler: func(ctx *fiber.Ctx, err error) error {
|
ErrorHandler: func(ctx *fiber.Ctx, err error) error {
|
||||||
log.Println(ctx.Request().URI(), err)
|
log.Printf("Error: %v - URI: %v\n", err, ctx.Request().URI())
|
||||||
|
|
||||||
return ctx.SendStatus(http.StatusInternalServerError)
|
return ctx.SendStatus(http.StatusInternalServerError)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -25,24 +24,26 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
// Read config file
|
||||||
if err := config.ReadFile("config.yml"); err != nil {
|
if err := config.ReadFile("config.yml"); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatalf("Failed to read config file: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the blocked server list
|
||||||
if err := GetBlockedServerList(); err != nil {
|
if err := GetBlockedServerList(); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatalf("Failed to retrieve EULA blocked servers: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("Successfully retrieved EULA blocked servers")
|
log.Println("Successfully retrieved EULA blocked servers")
|
||||||
|
|
||||||
|
// Connect to Redis if the config is set
|
||||||
if config.Redis != nil {
|
if config.Redis != nil {
|
||||||
if err := r.Connect(); err != nil {
|
if err := r.Connect(); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatalf("Failed to connect to Redis: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("Successfully connected to Redis")
|
log.Println("Successfully connected to Redis")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set up middleware
|
||||||
app.Use(recover.New(recover.Config{
|
app.Use(recover.New(recover.Config{
|
||||||
EnableStackTrace: true,
|
EnableStackTrace: true,
|
||||||
}))
|
}))
|
||||||
@ -65,5 +66,7 @@ func main() {
|
|||||||
defer r.Close()
|
defer r.Close()
|
||||||
|
|
||||||
log.Printf("Listening on %s:%d\n", config.Host, config.Port)
|
log.Printf("Listening on %s:%d\n", config.Host, config.Port)
|
||||||
log.Fatal(app.Listen(fmt.Sprintf("%s:%d", config.Host, config.Port)))
|
if err := app.Listen(fmt.Sprintf("%s:%d", config.Host, config.Port)); err != nil {
|
||||||
|
log.Fatalf("Failed to start server: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
26
src/redis.go
26
src/redis.go
@ -2,38 +2,45 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-redis/redis/v8"
|
"github.com/go-redis/redis/v8"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const defaultTimeout = 5 * time.Second
|
||||||
|
|
||||||
|
// Redis is a wrapper around the Redis client.
|
||||||
type Redis struct {
|
type Redis struct {
|
||||||
Client *redis.Client
|
Client *redis.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Connect establishes a connection to the Redis server using the configuration.
|
||||||
func (r *Redis) Connect() error {
|
func (r *Redis) Connect() error {
|
||||||
opts, err := redis.ParseURL(*config.Redis)
|
if config.Redis == nil {
|
||||||
|
return errors.New("missing Redis configuration")
|
||||||
|
}
|
||||||
|
|
||||||
|
opts, err := redis.ParseURL(*config.Redis)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
r.Client = redis.NewClient(opts)
|
r.Client = redis.NewClient(opts)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
|
||||||
|
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
return r.Client.Ping(ctx).Err()
|
return r.Client.Ping(ctx).Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get retrieves the value and TTL for a given key.
|
||||||
func (r *Redis) Get(key string) ([]byte, time.Duration, error) {
|
func (r *Redis) Get(key string) ([]byte, time.Duration, error) {
|
||||||
if r.Client == nil {
|
if r.Client == nil {
|
||||||
return nil, 0, nil
|
return nil, 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
|
||||||
|
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
p := r.Client.Pipeline()
|
p := r.Client.Pipeline()
|
||||||
@ -54,30 +61,31 @@ func (r *Redis) Get(key string) ([]byte, time.Duration, error) {
|
|||||||
return data, ttl.Val(), err
|
return data, ttl.Val(), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set sets the value and TTL for a given key.
|
||||||
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.Client == nil {
|
if r.Client == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
|
||||||
|
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
return r.Client.Set(ctx, key, value, ttl).Err()
|
return r.Client.Set(ctx, key, value, ttl).Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Increment increments the integer value of a key by 1.
|
||||||
func (r *Redis) Increment(key string) error {
|
func (r *Redis) Increment(key string) error {
|
||||||
if r.Client == nil {
|
if r.Client == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
|
||||||
|
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
return r.Client.Incr(ctx, key).Err()
|
return r.Client.Incr(ctx, key).Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close closes the Redis client connection.
|
||||||
func (r *Redis) Close() error {
|
func (r *Redis) Close() error {
|
||||||
if r.Client == nil {
|
if r.Client == nil {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -18,20 +18,24 @@ func init() {
|
|||||||
app.Use(NotFoundHandler)
|
app.Use(NotFoundHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StatisticsResponse is the structure for the response of the statistics route.
|
||||||
type StatisticsResponse struct {
|
type StatisticsResponse struct {
|
||||||
Cache CacheConfig `json:"cache"`
|
Cache CacheConfig `json:"cache"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PingHandler responds with a 200 OK status for simple health checks.
|
||||||
func PingHandler(ctx *fiber.Ctx) error {
|
func PingHandler(ctx *fiber.Ctx) error {
|
||||||
return ctx.SendStatus(http.StatusOK)
|
return ctx.SendStatus(http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StatisticsHandler returns the cache configuration in the response.
|
||||||
func StatisticsHandler(ctx *fiber.Ctx) error {
|
func StatisticsHandler(ctx *fiber.Ctx) error {
|
||||||
return ctx.JSON(StatisticsResponse{
|
return ctx.JSON(StatisticsResponse{
|
||||||
Cache: config.Cache,
|
Cache: config.Cache,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// JavaStatusHandler returns the status of the Java edition Minecraft server specified in the address parameter.
|
||||||
func JavaStatusHandler(ctx *fiber.Ctx) error {
|
func JavaStatusHandler(ctx *fiber.Ctx) error {
|
||||||
host, port, err := ParseAddress(ctx.Params("address"), 25565)
|
host, port, err := ParseAddress(ctx.Params("address"), 25565)
|
||||||
|
|
||||||
@ -58,6 +62,7 @@ func JavaStatusHandler(ctx *fiber.Ctx) error {
|
|||||||
return ctx.JSON(response)
|
return ctx.JSON(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BedrockStatusHandler returns the status of the Bedrock edition Minecraft server specified in the address parameter.
|
||||||
func BedrockStatusHandler(ctx *fiber.Ctx) error {
|
func BedrockStatusHandler(ctx *fiber.Ctx) error {
|
||||||
host, port, err := ParseAddress(ctx.Params("address"), 19132)
|
host, port, err := ParseAddress(ctx.Params("address"), 19132)
|
||||||
|
|
||||||
@ -84,6 +89,7 @@ func BedrockStatusHandler(ctx *fiber.Ctx) error {
|
|||||||
return ctx.JSON(response)
|
return ctx.JSON(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IconHandler returns the server icon for the specified Java edition Minecraft server.
|
||||||
func IconHandler(ctx *fiber.Ctx) error {
|
func IconHandler(ctx *fiber.Ctx) error {
|
||||||
host, port, err := ParseAddress(ctx.Params("address"), 25565)
|
host, port, err := ParseAddress(ctx.Params("address"), 25565)
|
||||||
|
|
||||||
@ -106,10 +112,12 @@ func IconHandler(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Type("png").Send(icon)
|
return ctx.Type("png").Send(icon)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DefaultIconHandler returns the default server icon.
|
||||||
func DefaultIconHandler(ctx *fiber.Ctx) error {
|
func DefaultIconHandler(ctx *fiber.Ctx) error {
|
||||||
return ctx.Type("png").Send(defaultIcon)
|
return ctx.Type("png").Send(defaultIcon)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NotFoundHandler handles requests to routes that do not exist and returns a 404 Not Found status.
|
||||||
func NotFoundHandler(ctx *fiber.Ctx) error {
|
func NotFoundHandler(ctx *fiber.Ctx) error {
|
||||||
return ctx.SendStatus(http.StatusNotFound)
|
return ctx.SendStatus(http.StatusNotFound)
|
||||||
}
|
}
|
||||||
|
|||||||
46
src/util.go
46
src/util.go
@ -16,18 +16,19 @@ import (
|
|||||||
var (
|
var (
|
||||||
//go:embed icon.png
|
//go:embed icon.png
|
||||||
defaultIcon []byte
|
defaultIcon []byte
|
||||||
blockedServers *MutexArray[string] = nil
|
blockedServers *MutexArray = nil
|
||||||
ipAddressRegExp *regexp.Regexp = regexp.MustCompile(`^\d{1,3}(\.\d{1,3}){3}$`)
|
ipAddressRegex *regexp.Regexp = regexp.MustCompile(`^\d{1,3}(\.\d{1,3}){3}$`)
|
||||||
)
|
)
|
||||||
|
|
||||||
type MutexArray[K comparable] struct {
|
// MutexArray is a thread-safe array for storing and checking values.
|
||||||
List []K
|
type MutexArray struct {
|
||||||
|
List []interface{}
|
||||||
Mutex *sync.Mutex
|
Mutex *sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MutexArray[K]) Has(value K) bool {
|
// Has checks if the given value is present in the array.
|
||||||
|
func (m *MutexArray) Has(value interface{}) bool {
|
||||||
m.Mutex.Lock()
|
m.Mutex.Lock()
|
||||||
|
|
||||||
defer m.Mutex.Unlock()
|
defer m.Mutex.Unlock()
|
||||||
|
|
||||||
for _, v := range m.List {
|
for _, v := range m.List {
|
||||||
@ -39,9 +40,11 @@ func (m *MutexArray[K]) Has(value K) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// GetBlockedServerList fetches the list of blocked servers from Mojang's session server.
|
||||||
func GetBlockedServerList() error {
|
func GetBlockedServerList() error {
|
||||||
resp, err := http.Get("https://sessionserver.mojang.com/blockedservers")
|
resp, err := http.Get("https://sessionserver.mojang.com/blockedservers")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -53,43 +56,44 @@ func GetBlockedServerList() error {
|
|||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
blockedServers = &MutexArray[string]{
|
// Convert []string to []interface{}
|
||||||
List: strings.Split(string(body), "\n"),
|
strSlice := strings.Split(string(body), "\n")
|
||||||
|
interfaceSlice := make([]interface{}, len(strSlice))
|
||||||
|
for i, v := range strSlice {
|
||||||
|
interfaceSlice[i] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
blockedServers = &MutexArray{
|
||||||
|
List: interfaceSlice,
|
||||||
Mutex: &sync.Mutex{},
|
Mutex: &sync.Mutex{},
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// IsBlockedAddress checks if the given address is in the blocked servers list.
|
||||||
func IsBlockedAddress(address string) bool {
|
func IsBlockedAddress(address string) bool {
|
||||||
split := strings.Split(strings.ToLower(address), ".")
|
split := strings.Split(strings.ToLower(address), ".")
|
||||||
isIPAddress := ipAddressRegExp.MatchString(address)
|
isIPAddress := ipAddressRegex.MatchString(address)
|
||||||
|
|
||||||
for k := range split {
|
for k := range split {
|
||||||
newAddress := ""
|
var newAddress string
|
||||||
|
|
||||||
switch k {
|
switch k {
|
||||||
case 0:
|
case 0:
|
||||||
{
|
|
||||||
newAddress = strings.Join(split, ".")
|
newAddress = strings.Join(split, ".")
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
{
|
|
||||||
if isIPAddress {
|
if isIPAddress {
|
||||||
newAddress = fmt.Sprintf("%s.*", strings.Join(split[0:len(split)-k], "."))
|
newAddress = fmt.Sprintf("%s.*", strings.Join(split[0:len(split)-k], "."))
|
||||||
} else {
|
} else {
|
||||||
newAddress = fmt.Sprintf("*.%s", strings.Join(split[k:], "."))
|
newAddress = fmt.Sprintf("*.%s", strings.Join(split[k:], "."))
|
||||||
}
|
}
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
newAddressBytes := sha1.Sum([]byte(newAddress))
|
newAddressBytes := sha1.Sum([]byte(newAddress))
|
||||||
@ -103,6 +107,7 @@ func IsBlockedAddress(address string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseAddress extracts the hostname and port from the given address string, and returns the default port if none is provided.
|
||||||
func ParseAddress(address string, defaultPort uint16) (string, uint16, error) {
|
func ParseAddress(address string, defaultPort uint16) (string, uint16, error) {
|
||||||
result := strings.SplitN(address, ":", 2)
|
result := strings.SplitN(address, ":", 2)
|
||||||
|
|
||||||
@ -115,7 +120,6 @@ func ParseAddress(address string, defaultPort uint16) (string, uint16, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
port, err := strconv.ParseUint(result[1], 10, 16)
|
port, err := strconv.ParseUint(result[1], 10, 16)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 0, err
|
return "", 0, err
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user