Skip to content
This repository has been archived by the owner on Apr 4, 2024. It is now read-only.

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
xstar97 committed Mar 8, 2024
1 parent 4237622 commit 7c4285d
Show file tree
Hide file tree
Showing 10 changed files with 561 additions and 207 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ You can customize the behavior of *palworld-query-api* using the following comma
| `-port` | Web port | `3000` |
| `-cli-config` | Root path to rcon.yaml | `/config/rcon.yaml`|
| `-logs-path` | Logs path | `/logs` |
| `-cache-path` | Cache path | `/cache` |

Replace the default values as needed when running the binary.

Expand Down Expand Up @@ -56,6 +57,7 @@ services:
- "3000:3000"
volumes:
- ./config:/config
- ./cache:/cache
- ./logs:/logs
```
Expand All @@ -79,11 +81,11 @@ an env variable `CONFIG_JSON` can be set to automatically create the rcon.yaml f

try increasing the timeout value if using a remote server; the min recommended timeout for palworld is 60s; if the server is not local to you; increase it.

### HomePage intregation CustomAPI
### HomePage Integration CustomAPI Rcon route

Integrate PalWorld server information seamlessly into your homepage using the CustomAPI widget. By specifying the server environment name, you can display key details such as server name, version, and current player count. Keep your users informed with real-time updates on server status.

the output of the api /servers/:name
the output of this route /rcon/:name

```json
{
Expand All @@ -103,7 +105,7 @@ the output of the api /servers/:name
description: A clone PKM game
widget:
type: customapi
url: "http://localhost:3000/servers/default" # change the name given to server env (not palworld server name!)
url: "http://localhost:3000/rcon/default" # change the name given to server env (not palworld server name!)
refreshInterval: 10000
method: GET
mappings:
Expand Down
10 changes: 7 additions & 3 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,17 @@ func main() {
port := fmt.Sprintf(":%s", config.Config.Port)
routeRoot := config.Routes.Index
routeHealth := config.Routes.Health
routeServers := config.Routes.Servers
routRcon := config.Routes.Rcon
routeApi := config.Routes.Api

// Register healthz route
http.HandleFunc(routeHealth, routes.HealthHandler)

// Register servers route
http.HandleFunc(routeServers, routes.ServersHandler)
// Register rcon route
http.HandleFunc(routRcon, routes.RconHandler)

// Register api route
http.HandleFunc(routeApi, routes.ApiHandler)

// Register root route to list available routes
http.HandleFunc(routeRoot, routes.IndexHandler)
Expand Down
66 changes: 66 additions & 0 deletions internal/config/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package config

import (
"io/ioutil"
"os"
"sync"
"time"
)

var (
mutex sync.RWMutex
cachedData []byte
lastUpdated time.Time
cacheFile = Config.CachePath+"cached_data.json" // Name of the file to store cached data
)

func init() {
// Load cached data from file when the package is initialized
loadCachedDataFromFile()
}

func loadCachedDataFromFile() {
// Check if the cache file exists
if _, err := os.Stat(cacheFile); os.IsNotExist(err) {
return // Cache file does not exist, no data to load
}

// Read cached data from file
data, err := ioutil.ReadFile(cacheFile)
if err != nil {
// Error reading cache file
// Log the error or handle it accordingly
return
}

// Update cached data and lastUpdated time
mutex.Lock()
defer mutex.Unlock()
cachedData = data
lastUpdated = time.Now()
}

func SetCachedData(data []byte) {
mutex.Lock()
defer mutex.Unlock()
cachedData = data
lastUpdated = time.Now()

// Save cached data to file
err := ioutil.WriteFile(cacheFile, data, 0644)
if err != nil {
// Error saving cache file
// Log the error or handle it accordingly
}
}

func GetCachedData() []byte {
mutex.RLock()
defer mutex.RUnlock()
return cachedData
}

func NeedToUpdateCache() bool {
// Update cache every hour
return time.Since(lastUpdated) >= time.Hour
}
5 changes: 5 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ var Config = struct {
ConfigJson string
CliConfig string
LogsPath string
CachePath string
}{
Port: "3000",
ConfigJson: "",
CliConfig: "/config/rcon.yaml",
LogsPath: "/logs",
CachePath: "/cache",
}

// setIfNotEmpty sets the value of a string variable if the corresponding environment variable is not empty.
Expand All @@ -32,6 +34,7 @@ func setConfigFromEnv() {
setIfNotEmpty("CLI_CONFIG", &Config.CliConfig)
setIfNotEmpty("CONFIG_JSON", &Config.ConfigJson)
setIfNotEmpty("LOGS_PATH", &Config.LogsPath)
setIfNotEmpty("CACHE_PATH", &Config.CachePath)
}

// init parses flags and sets configuration.
Expand All @@ -43,6 +46,7 @@ func init() {
flag.StringVar(&Config.CliConfig, "cli-config", Config.CliConfig, "path to rcon.yaml")
flag.StringVar(&Config.ConfigJson, "config-json", Config.ConfigJson, "json object")
flag.StringVar(&Config.LogsPath, "logs-path", Config.LogsPath, "Logs path")
flag.StringVar(&Config.CachePath, "cache-path", Config.CachePath, "Cache path")
flag.Parse()
// Check if CONFIG_JSON is set
if Config.ConfigJson != "" {
Expand All @@ -57,4 +61,5 @@ func init() {
log.Printf("Server port: %s", Config.Port)
log.Printf("Root path to rcon.yaml: %s", Config.CliConfig)
log.Printf("Logs path: %s", Config.LogsPath)
log.Printf("Cache path: %s", Config.CachePath)
}
61 changes: 61 additions & 0 deletions internal/config/ip.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package config

import (
"log"
"net"
"strings"
"fmt"
)

// checks if the given string is a valid IP address.
func IsValidIPAddress(ip string) bool {
return net.ParseIP(ip) != nil
}

// checks if the given string is a valid domain name.
func IsValidDomain(domain string) bool {
parts := strings.Split(domain, ".")
for _, part := range parts {
if len(part) == 0 {
return false
}
}
return true
}

// isAddressValid checks if the address is a valid IP address or a domain.
// If it's a domain, it resolves it to its public IP address and compares with the provided value.
func IsAddressValid(address, value string) bool {
if IsValidIPAddress(address) {
log.Printf("Valid IP address: %s", address)
return address == value
}
if IsValidDomain(address) {
log.Printf("Valid domain: %s", address)
ipAddr, err := GetPublicIP(address)
if err != nil {
log.Printf("Error resolving domain: %s", err)
return false
}
log.Printf("Resolved IP address for domain %s: %s", address, ipAddr)
return ipAddr == value
}
log.Printf("Invalid address format: %s", address)
return false
}

func GetPublicIP(domain string) (string, error) {
addrs, err := net.LookupIP(domain)
if err != nil {
return "", err
}

// Find the IPv4 address
for _, addr := range addrs {
if ipv4 := addr.To4(); ipv4 != nil {
return ipv4.String(), nil
}
}

return "", fmt.Errorf("no IPv4 address found for domain %s", domain)
}
Loading

0 comments on commit 7c4285d

Please sign in to comment.