fix caching issues

This commit is contained in:
Fran Jurmanović
2025-05-31 21:57:08 +02:00
parent 53bc7f42a3
commit d08695025a
9 changed files with 146 additions and 87 deletions

View File

@@ -3,7 +3,7 @@ package controller
import (
"acc-server-manager/local/service"
"acc-server-manager/local/utl/common"
"log"
"acc-server-manager/local/utl/logging"
"strings"
"github.com/gofiber/fiber/v2"
@@ -89,6 +89,7 @@ func (ac *ApiController) startServer(c *fiber.Ctx) error {
c.Locals("serverId", model.ServerId)
apiModel, err := ac.service.ApiStartServer(c)
if err != nil {
logging.Error(strings.ReplaceAll(err.Error(), "\x00", ""))
return c.Status(400).SendString(strings.ReplaceAll(err.Error(), "\x00", ""))
}
return c.SendString(apiModel)
@@ -111,7 +112,7 @@ func (ac *ApiController) stopServer(c *fiber.Ctx) error {
c.Locals("serverId", model.ServerId)
apiModel, err := ac.service.ApiStopServer(c)
if err != nil {
log.Print(strings.ReplaceAll(err.Error(), "\x00", ""))
logging.Error(strings.ReplaceAll(err.Error(), "\x00", ""))
return c.Status(400).SendString(strings.ReplaceAll(err.Error(), "\x00", ""))
}
return c.SendString(apiModel)
@@ -134,7 +135,7 @@ func (ac *ApiController) restartServer(c *fiber.Ctx) error {
c.Locals("serverId", model.ServerId)
apiModel, err := ac.service.ApiRestartServer(c)
if err != nil {
log.Print(strings.ReplaceAll(err.Error(), "\x00", ""))
logging.Error(strings.ReplaceAll(err.Error(), "\x00", ""))
return c.Status(400).SendString(strings.ReplaceAll(err.Error(), "\x00", ""))
}
return c.SendString(apiModel)

View File

@@ -3,7 +3,7 @@ package controller
import (
"acc-server-manager/local/service"
"acc-server-manager/local/utl/common"
"log"
"acc-server-manager/local/utl/logging"
"github.com/gofiber/fiber/v2"
)
@@ -51,7 +51,7 @@ func (ac *ConfigController) updateConfig(c *fiber.Ctx) error {
var config map[string]interface{}
if err := c.BodyParser(&config); err != nil {
log.Print("Invalid config format")
logging.Error("Invalid config format")
return c.Status(400).JSON(fiber.Map{"error": "Invalid config format"})
}
@@ -59,11 +59,11 @@ func (ac *ConfigController) updateConfig(c *fiber.Ctx) error {
if err != nil {
return c.Status(400).SendString(err.Error())
}
log.Print("restart", restart)
logging.Info("restart", restart)
if restart {
_, err := ac.apiService.ApiRestartServer(c)
if err != nil {
log.Print(err.Error())
logging.Error(err.Error())
}
}
@@ -82,7 +82,7 @@ func (ac *ConfigController) updateConfig(c *fiber.Ctx) error {
func (ac *ConfigController) getConfig(c *fiber.Ctx) error {
Model, err := ac.service.GetConfig(c)
if err != nil {
log.Print(err.Error())
logging.Error(err.Error())
return c.Status(400).SendString(err.Error())
}
return c.JSON(Model)
@@ -99,7 +99,7 @@ func (ac *ConfigController) getConfig(c *fiber.Ctx) error {
func (ac *ConfigController) getConfigs(c *fiber.Ctx) error {
Model, err := ac.service.GetConfigs(c)
if err != nil {
log.Print(err.Error())
logging.Error(err.Error())
return c.Status(400).SendString(err.Error())
}
return c.JSON(Model)

View File

@@ -2,7 +2,7 @@ package controller
import (
"acc-server-manager/local/service"
"log"
"acc-server-manager/local/utl/logging"
"go.uber.org/dig"
)
@@ -17,26 +17,26 @@ func InitializeControllers(c *dig.Container) {
err := c.Invoke(NewApiController)
if err != nil {
log.Panic("unable to initialize api controller")
logging.Panic("unable to initialize api controller")
}
err = c.Invoke(NewConfigController)
if err != nil {
log.Panic("unable to initialize config controller")
logging.Panic("unable to initialize config controller")
}
err = c.Invoke(NewServerController)
if err != nil {
log.Panic("unable to initialize server controller")
logging.Panic("unable to initialize server controller")
}
err = c.Invoke(NewLookupController)
if err != nil {
log.Panic("unable to initialize lookup controller")
logging.Panic("unable to initialize lookup controller")
}
err = c.Invoke(NewStateHistoryController)
if err != nil {
log.Panic("unable to initialize stateHistory controller")
logging.Panic("unable to initialize stateHistory controller")
}
}

View File

@@ -36,7 +36,7 @@ func (as *ApiService) SetServerService(serverService *ServerService) {
as.serverService = serverService
}
func (as ApiService) GetStatus(ctx *fiber.Ctx) (string, error) {
func (as *ApiService) GetStatus(ctx *fiber.Ctx) (string, error) {
serviceName, err := as.GetServiceName(ctx)
if err != nil {
return "", err
@@ -59,7 +59,7 @@ func (as ApiService) GetStatus(ctx *fiber.Ctx) (string, error) {
return status.String(), nil
}
func (as ApiService) ApiStartServer(ctx *fiber.Ctx) (string, error) {
func (as *ApiService) ApiStartServer(ctx *fiber.Ctx) (string, error) {
serviceName, err := as.GetServiceName(ctx)
if err != nil {
return "", err
@@ -79,7 +79,7 @@ func (as ApiService) ApiStartServer(ctx *fiber.Ctx) (string, error) {
return status.String(), nil
}
func (as ApiService) ApiStopServer(ctx *fiber.Ctx) (string, error) {
func (as *ApiService) ApiStopServer(ctx *fiber.Ctx) (string, error) {
serviceName, err := as.GetServiceName(ctx)
if err != nil {
return "", err
@@ -99,7 +99,7 @@ func (as ApiService) ApiStopServer(ctx *fiber.Ctx) (string, error) {
return status.String(), nil
}
func (as ApiService) ApiRestartServer(ctx *fiber.Ctx) (string, error) {
func (as *ApiService) ApiRestartServer(ctx *fiber.Ctx) (string, error) {
serviceName, err := as.GetServiceName(ctx)
if err != nil {
return "", err
@@ -119,31 +119,49 @@ func (as ApiService) ApiRestartServer(ctx *fiber.Ctx) (string, error) {
return status.String(), nil
}
func (as ApiService) StatusServer(serviceName string) (string, error) {
func (as *ApiService) StatusServer(serviceName string) (string, error) {
return ManageService(serviceName, "status")
}
func (as ApiService) StartServer(serviceName string) (string, error) {
func (as *ApiService) StartServer(serviceName string) (string, error) {
status, err := ManageService(serviceName, "start")
if err != nil {
return "", err
}
server, err := as.serverRepository.GetFirstByServiceName(context.Background(), serviceName)
if err != nil {
return "", err
}
as.serverService.StartAccServerRuntime(server)
return status, err
}
func (as ApiService) StopServer(serviceName string) (string, error) {
func (as *ApiService) StopServer(serviceName string) (string, error) {
status, err := ManageService(serviceName, "stop")
if err != nil {
return "", err
}
server, err := as.serverRepository.GetFirstByServiceName(context.Background(), serviceName)
if err != nil {
return "", err
}
as.serverService.instances.Delete(server.ID)
return status, err
}
func (as ApiService) RestartServer(serviceName string) (string, error) {
func (as *ApiService) RestartServer(serviceName string) (string, error) {
status, err := ManageService(serviceName, "restart")
if err != nil {
return "", err
}
server, err := as.serverRepository.GetFirstByServiceName(context.Background(), serviceName)
if err != nil {
return "", err
}
as.serverService.StartAccServerRuntime(server)
return status, err
}
@@ -162,7 +180,7 @@ func ManageService(serviceName string, action string) (string, error) {
return cleaned, nil
}
func (as ApiService) GetServiceName(ctx *fiber.Ctx) (string, error) {
func (as *ApiService) GetServiceName(ctx *fiber.Ctx) (string, error) {
var server *model.Server
var err error
serviceName, ok := ctx.Locals("service").(string)

View File

@@ -4,11 +4,12 @@ import (
"acc-server-manager/local/model"
"acc-server-manager/local/repository"
"acc-server-manager/local/utl/common"
"acc-server-manager/local/utl/logging"
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"log"
"os"
"path/filepath"
"strconv"
@@ -72,7 +73,7 @@ func NewConfigService(repository *repository.ConfigRepository, serverRepository
return &ConfigService{
repository: repository,
serverRepository: serverRepository,
configCache: model.NewServerConfigCache(model.CacheConfig{
configCache: model.NewServerConfigCache(model.CacheConfig{
ExpirationTime: 5 * time.Minute, // Cache configs for 5 minutes
ThrottleTime: 1 * time.Second, // Prevent rapid re-reads
DefaultStatus: model.StatusUnknown,
@@ -91,14 +92,14 @@ func (as *ConfigService) SetServerService(serverService *ServerService) {
// context.Context: Application context
// Returns:
// string: Application version
func (as ConfigService) UpdateConfig(ctx *fiber.Ctx, body *map[string]interface{}) (*model.Config, error) {
func (as *ConfigService) UpdateConfig(ctx *fiber.Ctx, body *map[string]interface{}) (*model.Config, error) {
serverID := ctx.Locals("serverId").(int)
configFile := ctx.Params("file")
override := ctx.QueryBool("override", false)
server, err := as.serverRepository.GetByID(ctx.UserContext(), serverID)
if err != nil {
log.Print("Server not found")
logging.Error("Server not found")
return nil, fiber.NewError(404, "Server not found")
}
@@ -177,14 +178,14 @@ func (as ConfigService) UpdateConfig(ctx *fiber.Ctx, body *map[string]interface{
// context.Context: Application context
// Returns:
// string: Application version
func (as ConfigService) GetConfig(ctx *fiber.Ctx) (interface{}, error) {
func (as *ConfigService) GetConfig(ctx *fiber.Ctx) (interface{}, error) {
serverID, _ := ctx.ParamsInt("id")
configFile := ctx.Params("file")
serverIDStr := strconv.Itoa(serverID)
server, err := as.serverRepository.GetByID(ctx.UserContext(), serverID)
if err != nil {
log.Print("Server not found")
logging.Error("Server not found")
return nil, fiber.NewError(404, "Server not found")
}
@@ -246,25 +247,33 @@ func (as ConfigService) GetConfig(ctx *fiber.Ctx) (interface{}, error) {
// GetConfigs
// Gets all configurations for a server, using cache when possible.
func (as ConfigService) GetConfigs(ctx *fiber.Ctx) (*model.Configurations, error) {
func (as *ConfigService) GetConfigs(ctx *fiber.Ctx) (*model.Configurations, error) {
serverID, _ := ctx.ParamsInt("id")
serverIDStr := strconv.Itoa(serverID)
server, err := as.serverRepository.GetByID(ctx.UserContext(), serverID)
if err != nil {
log.Print("Server not found")
logging.Error("Server not found")
return nil, fiber.NewError(404, "Server not found")
}
return as.LoadConfigs(server)
}
func (as *ConfigService) LoadConfigs(server *model.Server) (*model.Configurations, error) {
serverIDStr := strconv.Itoa(int(server.ID))
logging.Info("Loading configs for server ID: %s at path: %s", serverIDStr, server.ConfigPath)
configs := &model.Configurations{}
// Load configuration
if cached, ok := as.configCache.GetConfiguration(serverIDStr); ok {
logging.Debug("Using cached configuration for server %s", serverIDStr)
configs.Configuration = *cached
} else {
logging.Debug("Loading configuration from disk for server %s", serverIDStr)
config, err := mustDecode[model.Configuration](ConfigurationJson, server.ConfigPath)
if err != nil {
return nil, err
logging.Error("Failed to load configuration for server %s: %v", serverIDStr, err)
return nil, fmt.Errorf("failed to load configuration: %v", err)
}
configs.Configuration = config
as.configCache.UpdateConfiguration(serverIDStr, config)
@@ -272,11 +281,14 @@ func (as ConfigService) GetConfigs(ctx *fiber.Ctx) (*model.Configurations, error
// Load assist rules
if cached, ok := as.configCache.GetAssistRules(serverIDStr); ok {
logging.Debug("Using cached assist rules for server %s", serverIDStr)
configs.AssistRules = *cached
} else {
logging.Debug("Loading assist rules from disk for server %s", serverIDStr)
rules, err := mustDecode[model.AssistRules](AssistRulesJson, server.ConfigPath)
if err != nil {
return nil, err
logging.Error("Failed to load assist rules for server %s: %v", serverIDStr, err)
return nil, fmt.Errorf("failed to load assist rules: %v", err)
}
configs.AssistRules = rules
as.configCache.UpdateAssistRules(serverIDStr, rules)
@@ -284,23 +296,30 @@ func (as ConfigService) GetConfigs(ctx *fiber.Ctx) (*model.Configurations, error
// Load event config
if cached, ok := as.configCache.GetEvent(serverIDStr); ok {
logging.Debug("Using cached event config for server %s", serverIDStr)
configs.Event = *cached
} else {
logging.Debug("Loading event config from disk for server %s", serverIDStr)
event, err := mustDecode[model.EventConfig](EventJson, server.ConfigPath)
if err != nil {
return nil, err
logging.Error("Failed to load event config for server %s: %v", serverIDStr, err)
return nil, fmt.Errorf("failed to load event config: %v", err)
}
configs.Event = event
logging.Debug("Updating event config for server %s with track: %s", serverIDStr, event.Track)
as.configCache.UpdateEvent(serverIDStr, event)
}
// Load event rules
if cached, ok := as.configCache.GetEventRules(serverIDStr); ok {
logging.Debug("Using cached event rules for server %s", serverIDStr)
configs.EventRules = *cached
} else {
logging.Debug("Loading event rules from disk for server %s", serverIDStr)
rules, err := mustDecode[model.EventRules](EventRulesJson, server.ConfigPath)
if err != nil {
return nil, err
logging.Error("Failed to load event rules for server %s: %v", serverIDStr, err)
return nil, fmt.Errorf("failed to load event rules: %v", err)
}
configs.EventRules = rules
as.configCache.UpdateEventRules(serverIDStr, rules)
@@ -308,16 +327,20 @@ func (as ConfigService) GetConfigs(ctx *fiber.Ctx) (*model.Configurations, error
// Load settings
if cached, ok := as.configCache.GetSettings(serverIDStr); ok {
logging.Debug("Using cached settings for server %s", serverIDStr)
configs.Settings = *cached
} else {
logging.Debug("Loading settings from disk for server %s", serverIDStr)
settings, err := mustDecode[model.ServerSettings](SettingsJson, server.ConfigPath)
if err != nil {
return nil, err
logging.Error("Failed to load settings for server %s: %v", serverIDStr, err)
return nil, fmt.Errorf("failed to load settings: %v", err)
}
configs.Settings = settings
as.configCache.UpdateSettings(serverIDStr, settings)
}
logging.Info("Successfully loaded all configs for server %s", serverIDStr)
return configs, nil
}
@@ -336,14 +359,14 @@ func readAndDecode[T interface{}](path string, configFile string) (T, error) {
}
func readFile(path string, configFile string) ([]byte, error) {
configPath := filepath.Join(path, "\\server\\cfg", configFile)
configPath := filepath.Join(path, "server", "cfg", configFile)
oldData, err := os.ReadFile(configPath)
if err != nil && !errors.Is(err, os.ErrNotExist) {
if err != nil {
if errors.Is(err, os.ErrNotExist) {
return nil, fmt.Errorf("config file %s does not exist at %s", configFile, configPath)
}
return nil, err
} else if errors.Is(err, os.ErrNotExist) {
return nil, nil
}
return oldData, nil
}
@@ -360,17 +383,17 @@ func DecodeUTF16LEBOM(input []byte) ([]byte, error) {
func DecodeToMap[T interface{}](input []byte) (T, error) {
var zero T
if input == nil {
return zero, nil
return zero, fmt.Errorf("cannot decode nil input")
}
configUTF8 := new(T)
decoded, err := DecodeUTF16LEBOM(input)
if err != nil {
return zero, err
return zero, fmt.Errorf("failed to decode UTF16: %v", err)
}
err = json.Unmarshal(decoded, configUTF8)
if err != nil {
return zero, err
return zero, fmt.Errorf("failed to unmarshal JSON: %v", err)
}
return *configUTF8, nil
}
@@ -389,3 +412,31 @@ func transformBytes(t transform.Transformer, input []byte) ([]byte, error) {
return buf.Bytes(), nil
}
func (as *ConfigService) GetEventConfig(server *model.Server) (*model.EventConfig, error) {
serverIDStr := strconv.Itoa(int(server.ID))
if cached, ok := as.configCache.GetEvent(serverIDStr); ok {
return cached, nil
}
event, err := mustDecode[model.EventConfig](EventJson, server.ConfigPath)
if err != nil {
return nil, err
}
as.configCache.UpdateEvent(serverIDStr, event)
return &event, nil
}
func (as *ConfigService) GetConfiguration(server *model.Server) (*model.Configuration, error) {
serverIDStr := strconv.Itoa(int(server.ID))
if cached, ok := as.configCache.GetConfiguration(serverIDStr); ok {
return cached, nil
}
config, err := mustDecode[model.Configuration](ConfigurationJson, server.ConfigPath)
if err != nil {
return nil, err
}
as.configCache.UpdateConfiguration(serverIDStr, config)
return &config, nil
}

View File

@@ -6,7 +6,6 @@ import (
"acc-server-manager/local/utl/logging"
"acc-server-manager/local/utl/tracking"
"context"
"log"
"path/filepath"
"strconv"
"sync"
@@ -64,9 +63,10 @@ func NewServerService(repository *repository.ServerRepository, stateHistoryRepo
return service
}
for _, server := range *servers {
for i := range *servers {
// Initialize instance regardless of status
service.StartAccServerRuntime(&server)
logging.Info("Starting server runtime for server ID: %d", (*servers)[i].ID)
service.StartAccServerRuntime(&(*servers)[i])
}
return service
@@ -132,31 +132,17 @@ func (s *ServerService) insertStateHistory(serverID uint, state *model.ServerSta
}
func (s *ServerService) updateSessionDuration(server *model.Server, sessionType string) {
serverIDStr := strconv.FormatUint(uint64(server.ID), 10)
// Get event config from cache or load it
var event model.EventConfig
if cached, ok := s.configService.configCache.GetEvent(serverIDStr); ok {
event = *cached
} else {
event, err := mustDecode[model.EventConfig](EventJson, server.ConfigPath)
if err != nil {
logging.Error("Failed to load event config for server %d: %v", server.ID, err)
return
}
s.configService.configCache.UpdateEvent(serverIDStr, event)
// Get configs using helper methods
event, err := s.configService.GetEventConfig(server)
if err != nil {
logging.Error("Failed to get event config for server %d: %v", server.ID, err)
return
}
var configuration model.Configuration
if cached, ok := s.configService.configCache.GetConfiguration(serverIDStr); ok {
configuration = *cached
} else {
configuration, err := mustDecode[model.Configuration](ConfigurationJson, server.ConfigPath)
if err != nil {
logging.Error("Failed to load configuration config for server %d: %v", server.ID, err)
return
}
s.configService.configCache.UpdateConfiguration(serverIDStr, configuration)
configuration, err := s.configService.GetConfiguration(server)
if err != nil {
logging.Error("Failed to get configuration for server %d: %v", server.ID, err)
return
}
if instance, ok := s.instances.Load(server.ID); ok {
@@ -181,6 +167,8 @@ func (s *ServerService) updateSessionDuration(server *model.Server, sessionType
break
}
}
} else {
logging.Error("No instance found for server ID: %d", server.ID)
}
}
@@ -247,14 +235,15 @@ func (s *ServerService) StartAccServerRuntime(server *model.Server) {
// context.Context: Application context
// Returns:
// string: Application version
func (s ServerService) GetAll(ctx *fiber.Ctx, filter *model.ServerFilter) (*[]model.Server, error) {
func (s *ServerService) GetAll(ctx *fiber.Ctx, filter *model.ServerFilter) (*[]model.Server, error) {
servers, err := s.repository.GetAll(ctx.UserContext(), filter)
if err != nil {
logging.Error("Failed to get servers: %v", err)
return nil, err
}
for i, server := range *servers {
for i := range *servers {
server := &(*servers)[i]
status, err := s.apiService.StatusServer(server.ServiceName)
if err != nil {
logging.Error("Failed to get status for server %s: %v", server.ServiceName, err)
@@ -266,7 +255,7 @@ func (s ServerService) GetAll(ctx *fiber.Ctx, filter *model.ServerFilter) (*[]mo
} else {
serverInstance := instance.(*tracking.AccServerInstance)
if serverInstance.State != nil {
(*servers)[i].State = *serverInstance.State
(*server).State = *serverInstance.State
}
}
}
@@ -281,23 +270,23 @@ func (s ServerService) GetAll(ctx *fiber.Ctx, filter *model.ServerFilter) (*[]mo
// context.Context: Application context
// Returns:
// string: Application version
func (as ServerService) GetById(ctx *fiber.Ctx, serverID int) (*model.Server, error) {
func (as *ServerService) GetById(ctx *fiber.Ctx, serverID int) (*model.Server, error) {
server, err := as.repository.GetByID(ctx.UserContext(), serverID)
if err != nil {
return nil, err
}
status, err := as.apiService.StatusServer(server.ServiceName)
if err != nil {
log.Print(err.Error())
logging.Error(err.Error())
}
server.Status = model.ParseServiceStatus(status)
instance, ok := as.instances.Load(server.ID)
if !ok {
log.Print("Unable to retrieve instance for server of ID: ", server.ID)
logging.Error("Unable to retrieve instance for server of ID: %d", server.ID)
} else {
serverInstance := instance.(*tracking.AccServerInstance)
if (serverInstance.State != nil) {
server.State = *serverInstance.State
(*server).State = *serverInstance.State
}
}

View File

@@ -2,8 +2,8 @@ package service
import (
"acc-server-manager/local/repository"
"acc-server-manager/local/utl/logging"
"context"
"log"
"go.uber.org/dig"
)
@@ -34,6 +34,6 @@ func InitializeServices(c *dig.Container) {
lookup.cache.Set("sessions", lookup.repository.GetSessionTypes(context.Background()))
})
if err != nil {
log.Panic("unable to initialize services:", err)
logging.Panic("unable to initialize services: " + err.Error())
}
}

View File

@@ -3,7 +3,7 @@ package service
import (
"acc-server-manager/local/model"
"acc-server-manager/local/repository"
"log"
"acc-server-manager/local/utl/logging"
"sort"
"time"
@@ -30,7 +30,7 @@ func NewStateHistoryService(repository *repository.StateHistoryRepository) *Stat
func (s *StateHistoryService) GetAll(ctx *fiber.Ctx, filter *model.StateHistoryFilter) (*[]model.StateHistory, error) {
result, err := s.repository.GetAll(ctx.UserContext(), filter)
if err != nil {
log.Printf("Error getting state history: %v", err)
logging.Error("Error getting state history: %v", err)
return nil, err
}
return result, nil
@@ -38,7 +38,7 @@ func (s *StateHistoryService) GetAll(ctx *fiber.Ctx, filter *model.StateHistoryF
func (s *StateHistoryService) Insert(ctx *fiber.Ctx, model *model.StateHistory) error {
if err := s.repository.Insert(ctx.UserContext(), model); err != nil {
log.Printf("Error inserting state history: %v", err)
logging.Error("Error inserting state history: %v", err)
return err
}
return nil
@@ -48,7 +48,7 @@ func (s *StateHistoryService) GetStatistics(ctx *fiber.Ctx, filter *model.StateH
// Get all state history entries based on filter
entries, err := s.repository.GetAll(ctx.UserContext(), filter)
if err != nil {
log.Printf("Error getting state history for statistics: %v", err)
logging.Error("Error getting state history for statistics: %v", err)
return nil, err
}

View File

@@ -1,10 +1,10 @@
package common
import (
"acc-server-manager/local/utl/logging"
"bytes"
"encoding/json"
"fmt"
"log"
"net"
"os"
"os/exec"
@@ -27,7 +27,7 @@ type RouteGroups struct {
func CheckError(err error) {
if err != nil {
log.Printf("Error occured. %v", err)
logging.Error("Error occured. %v", err)
}
}