update caching and server creation

This commit is contained in:
Fran Jurmanović
2025-06-01 19:48:39 +02:00
parent 8a3b11b1ef
commit d57013bb50
26 changed files with 888 additions and 249 deletions

View File

@@ -1,6 +1,7 @@
package model
import (
"acc-server-manager/local/utl/logging"
"sync"
"time"
)
@@ -89,6 +90,7 @@ type LookupCache struct {
// NewLookupCache creates a new lookup cache
func NewLookupCache() *LookupCache {
logging.Debug("Initializing new LookupCache")
return &LookupCache{
data: make(map[string]interface{}),
}
@@ -100,6 +102,11 @@ func (c *LookupCache) Get(key string) (interface{}, bool) {
defer c.RUnlock()
value, exists := c.data[key]
if exists {
logging.Debug("Cache HIT for key: %s", key)
} else {
logging.Debug("Cache MISS for key: %s", key)
}
return value, exists
}
@@ -109,6 +116,7 @@ func (c *LookupCache) Set(key string, value interface{}) {
defer c.Unlock()
c.data[key] = value
logging.Debug("Cache SET for key: %s", key)
}
// Clear removes all entries from the cache
@@ -117,6 +125,7 @@ func (c *LookupCache) Clear() {
defer c.Unlock()
c.data = make(map[string]interface{})
logging.Debug("Cache CLEARED")
}
// ConfigEntry represents a cached configuration entry with its update time
@@ -129,8 +138,12 @@ type ConfigEntry[T any] struct {
func getConfigFromCache[T any](cache map[string]*ConfigEntry[T], serverID string, expirationTime time.Duration) (*T, bool) {
if entry, ok := cache[serverID]; ok {
if time.Since(entry.UpdatedAt) < expirationTime {
logging.Debug("Config cache HIT for server ID: %s", serverID)
return &entry.Data, true
}
logging.Debug("Config cache EXPIRED for server ID: %s", serverID)
} else {
logging.Debug("Config cache MISS for server ID: %s", serverID)
}
return nil, false
}
@@ -141,6 +154,7 @@ func updateConfigInCache[T any](cache map[string]*ConfigEntry[T], serverID strin
Data: data,
UpdatedAt: time.Now(),
}
logging.Debug("Config cache SET for server ID: %s", serverID)
}
// ServerConfigCache manages cached server configurations
@@ -156,6 +170,7 @@ type ServerConfigCache struct {
// NewServerConfigCache creates a new server configuration cache
func NewServerConfigCache(config CacheConfig) *ServerConfigCache {
logging.Debug("Initializing new ServerConfigCache with expiration time: %v, throttle time: %v", config.ExpirationTime, config.ThrottleTime)
return &ServerConfigCache{
configuration: make(map[string]*ConfigEntry[Configuration]),
assistRules: make(map[string]*ConfigEntry[AssistRules]),
@@ -170,6 +185,7 @@ func NewServerConfigCache(config CacheConfig) *ServerConfigCache {
func (c *ServerConfigCache) GetConfiguration(serverID string) (*Configuration, bool) {
c.RLock()
defer c.RUnlock()
logging.Debug("Attempting to get configuration from cache for server ID: %s", serverID)
return getConfigFromCache(c.configuration, serverID, c.config.ExpirationTime)
}
@@ -177,6 +193,7 @@ func (c *ServerConfigCache) GetConfiguration(serverID string) (*Configuration, b
func (c *ServerConfigCache) GetAssistRules(serverID string) (*AssistRules, bool) {
c.RLock()
defer c.RUnlock()
logging.Debug("Attempting to get assist rules from cache for server ID: %s", serverID)
return getConfigFromCache(c.assistRules, serverID, c.config.ExpirationTime)
}
@@ -184,6 +201,7 @@ func (c *ServerConfigCache) GetAssistRules(serverID string) (*AssistRules, bool)
func (c *ServerConfigCache) GetEvent(serverID string) (*EventConfig, bool) {
c.RLock()
defer c.RUnlock()
logging.Debug("Attempting to get event config from cache for server ID: %s", serverID)
return getConfigFromCache(c.event, serverID, c.config.ExpirationTime)
}
@@ -191,6 +209,7 @@ func (c *ServerConfigCache) GetEvent(serverID string) (*EventConfig, bool) {
func (c *ServerConfigCache) GetEventRules(serverID string) (*EventRules, bool) {
c.RLock()
defer c.RUnlock()
logging.Debug("Attempting to get event rules from cache for server ID: %s", serverID)
return getConfigFromCache(c.eventRules, serverID, c.config.ExpirationTime)
}
@@ -198,6 +217,7 @@ func (c *ServerConfigCache) GetEventRules(serverID string) (*EventRules, bool) {
func (c *ServerConfigCache) GetSettings(serverID string) (*ServerSettings, bool) {
c.RLock()
defer c.RUnlock()
logging.Debug("Attempting to get settings from cache for server ID: %s", serverID)
return getConfigFromCache(c.settings, serverID, c.config.ExpirationTime)
}
@@ -205,6 +225,7 @@ func (c *ServerConfigCache) GetSettings(serverID string) (*ServerSettings, bool)
func (c *ServerConfigCache) UpdateConfiguration(serverID string, config Configuration) {
c.Lock()
defer c.Unlock()
logging.Debug("Updating configuration cache for server ID: %s", serverID)
updateConfigInCache(c.configuration, serverID, config)
}
@@ -212,6 +233,7 @@ func (c *ServerConfigCache) UpdateConfiguration(serverID string, config Configur
func (c *ServerConfigCache) UpdateAssistRules(serverID string, rules AssistRules) {
c.Lock()
defer c.Unlock()
logging.Debug("Updating assist rules cache for server ID: %s", serverID)
updateConfigInCache(c.assistRules, serverID, rules)
}
@@ -219,6 +241,7 @@ func (c *ServerConfigCache) UpdateAssistRules(serverID string, rules AssistRules
func (c *ServerConfigCache) UpdateEvent(serverID string, event EventConfig) {
c.Lock()
defer c.Unlock()
logging.Debug("Updating event config cache for server ID: %s", serverID)
updateConfigInCache(c.event, serverID, event)
}
@@ -226,6 +249,7 @@ func (c *ServerConfigCache) UpdateEvent(serverID string, event EventConfig) {
func (c *ServerConfigCache) UpdateEventRules(serverID string, rules EventRules) {
c.Lock()
defer c.Unlock()
logging.Debug("Updating event rules cache for server ID: %s", serverID)
updateConfigInCache(c.eventRules, serverID, rules)
}
@@ -233,6 +257,7 @@ func (c *ServerConfigCache) UpdateEventRules(serverID string, rules EventRules)
func (c *ServerConfigCache) UpdateSettings(serverID string, settings ServerSettings) {
c.Lock()
defer c.Unlock()
logging.Debug("Updating settings cache for server ID: %s", serverID)
updateConfigInCache(c.settings, serverID, settings)
}
@@ -241,6 +266,7 @@ func (c *ServerConfigCache) InvalidateServerCache(serverID string) {
c.Lock()
defer c.Unlock()
logging.Debug("Invalidating all cache entries for server ID: %s", serverID)
delete(c.configuration, serverID)
delete(c.assistRules, serverID)
delete(c.event, serverID)
@@ -253,6 +279,7 @@ func (c *ServerConfigCache) Clear() {
c.Lock()
defer c.Unlock()
logging.Debug("Clearing all server config cache entries")
c.configuration = make(map[string]*ConfigEntry[Configuration])
c.assistRules = make(map[string]*ConfigEntry[AssistRules])
c.event = make(map[string]*ConfigEntry[EventConfig])

View File

@@ -3,6 +3,7 @@ package model
import (
"encoding/json"
"fmt"
"os"
"strconv"
"time"
)
@@ -106,6 +107,26 @@ type Configuration struct {
ConfigVersion IntString `json:"configVersion"`
}
type SystemConfig struct {
ID uint `json:"id"`
Key string `json:"key"`
Value string `json:"value"`
DefaultValue string `json:"defaultValue"`
Description string `json:"description"`
DateModified string `json:"dateModified"`
}
// Known configuration keys
const (
ConfigKeySteamCMDPath = "steamcmd_path"
ConfigKeyNSSMPath = "nssm_path"
)
// Cache keys
const (
CacheKeySystemConfig = "system_config_%s" // Format with config key
)
func (i *IntString) UnmarshalJSON(b []byte) error {
var str string
if err := json.Unmarshal(b, &str); err == nil {
@@ -136,4 +157,36 @@ func (i IntString) ToString() string {
func (i IntString) ToInt() (int) {
return int(i)
}
func (c *SystemConfig) Validate() error {
if c.Key == "" {
return fmt.Errorf("key is required")
}
// Validate paths exist for certain config keys
switch c.Key {
case ConfigKeySteamCMDPath, ConfigKeyNSSMPath:
if c.Value == "" {
if c.DefaultValue == "" {
return fmt.Errorf("value or default value is required for path configuration")
}
// Use default value if value is empty
c.Value = c.DefaultValue
}
// Check if path exists
if _, err := os.Stat(c.Value); os.IsNotExist(err) {
return fmt.Errorf("path does not exist: %s", c.Value)
}
}
return nil
}
func (c *SystemConfig) GetEffectiveValue() string {
if c.Value != "" {
return c.Value
}
return c.DefaultValue
}

View File

@@ -22,10 +22,11 @@ type Server struct {
Status ServiceStatus `json:"status" gorm:"-"`
IP string `gorm:"not null" json:"-"`
Port int `gorm:"not null" json:"-"`
ConfigPath string `gorm:"not null" json:"configPath"` // e.g. "/acc/servers/server1/"
Path string `gorm:"not null" json:"path"` // e.g. "/acc/servers/server1/"
ServiceName string `gorm:"not null" json:"serviceName"` // Windows service name
State ServerState `gorm:"-" json:"state"`
DateCreated time.Time `json:"dateCreated"`
FromSteamCMD bool `gorm:"not null; default:true" json:"-"`
}
type PlayerState struct {
@@ -91,8 +92,8 @@ func (s *Server) BeforeCreate(tx *gorm.DB) error {
if s.ServiceName == "" {
s.ServiceName = s.GenerateServiceName()
}
if s.ConfigPath == "" {
s.ConfigPath = s.GenerateConfigPath()
if s.Path == "" {
s.Path = s.GenerateServerPath(BaseServerPath)
}
// Set creation date if not set
@@ -113,13 +114,34 @@ func (s *Server) GenerateServiceName() string {
return fmt.Sprintf("%s-%d", ServiceNamePrefix, time.Now().UnixNano())
}
// GenerateConfigPath creates the config path based on the service name
func (s *Server) GenerateConfigPath() string {
// GenerateServerPath creates the config path based on the service name
func (s *Server) GenerateServerPath(steamCMDPath string) string {
// Ensure service name is set
if s.ServiceName == "" {
s.ServiceName = s.GenerateServiceName()
}
return filepath.Join(BaseServerPath, s.ServiceName)
if (steamCMDPath == "") {
steamCMDPath = BaseServerPath
}
return filepath.Join(steamCMDPath, "servers", s.ServiceName)
}
func (s *Server) GetServerPath() string {
if (!s.FromSteamCMD) {
return s.Path
}
return filepath.Join(s.Path, "server")
}
func (s *Server) GetConfigPath() string {
return filepath.Join(s.GetServerPath(), "cfg")
}
func (s *Server) GetLogPath() string {
if (!s.FromSteamCMD) {
return s.Path
}
return filepath.Join(s.GetServerPath(), "log")
}
func (s *Server) Validate() error {