diff --git a/frontend/src/pages/server/Administration.tsx b/frontend/src/pages/server/Administration.tsx index 7ae1b8f..f385379 100644 --- a/frontend/src/pages/server/Administration.tsx +++ b/frontend/src/pages/server/Administration.tsx @@ -124,6 +124,7 @@ function ServerAdministrationCard({setServ, serv, onServerFilesDeleted}: {setSer ; } + function ServerStartupCard({setServ, serv}: {setServ: React.Dispatch>, serv: server.Server}) { const [showServerCommandModalOpen, setShowServerCommandModalOpen] = useState(false) @@ -211,6 +212,38 @@ function ServerStartupCard({setServ, serv}: {setServ: React.Dispatch ) } + +function AutoSaveSettingsCard({ setServ, serv }: {setServ: React.Dispatch>, serv: server.Server}) { + return ( + + + Auto-Save Settings + + + +
+
+ setServ((p) => ({ + ...p, + autoSaveEnabled: e.target.checked, + convertValues: p.convertValues + }))}/>
+ + Auto-Save Interval (minutes) + setServ((p) => ({ + ...p, + autoSaveInterval: parseInt(e.target.value), + convertValues: p.convertValues + }))}> + +
+
+
+ ) +} + function ExtraSettingsCard({setServ, serv}: {setServ: React.Dispatch>, serv: server.Server}) { return ( @@ -257,12 +290,11 @@ function ExtraSettingsCard({setServ, serv}: {setServ: React.Dispatch + ); diff --git a/server/server.go b/server/server.go index 33ed1bd..04b99df 100644 --- a/server/server.go +++ b/server/server.go @@ -3,15 +3,16 @@ package server import ( "context" "fmt" - "github.com/JensvandeWiel/ArkAscendedServerManager/helpers" - "github.com/keybase/go-ps" - "github.com/wailsapp/wails/v2/pkg/runtime" "os/exec" "path" "path/filepath" "strconv" "strings" "time" + + "github.com/JensvandeWiel/ArkAscendedServerManager/helpers" + "github.com/keybase/go-ps" + "github.com/wailsapp/wails/v2/pkg/runtime" ) // Server contains the server "stuff" @@ -69,6 +70,9 @@ type Server struct { MaxPlayers int `json:"maxPlayers"` StartWithApplication bool `json:"startWithApplication"` + + AutoSaveEnabled bool `json:"autoSaveEnabled"` + AutoSaveInterval int `json:"autoSaveInterval"` } // UpdateConfig updates the configuration files for the server e.g.: GameUserSettings.ini @@ -182,7 +186,7 @@ func (s *Server) Stop() error { } } - _, err := s.helpers.SendRconCommand("saveworld", s.IpAddress, s.RCONPort, s.AdminPassword) + err := s.SaveWorld() if err != nil { return err } @@ -258,3 +262,12 @@ func (s *Server) CreateArguments() []string { return args } + +// save the world +func (s *Server) SaveWorld() error { + _, err := s.helpers.SendRconCommand("saveworld", s.IpAddress, s.RCONPort, s.AdminPassword) + if err != nil { + return err + } + return nil +} diff --git a/server/server_controller.go b/server/server_controller.go index 84ac37f..845863e 100644 --- a/server/server_controller.go +++ b/server/server_controller.go @@ -15,12 +15,14 @@ import ( "context" "encoding/json" "fmt" - "github.com/JensvandeWiel/ArkAscendedServerManager/helpers" - "github.com/adrg/xdg" - "github.com/wailsapp/wails/v2/pkg/runtime" "os" "path" "strconv" + "time" + + "github.com/JensvandeWiel/ArkAscendedServerManager/helpers" + "github.com/adrg/xdg" + "github.com/wailsapp/wails/v2/pkg/runtime" ) const ( @@ -29,10 +31,11 @@ const ( // ServerController struct type ServerController struct { - ctx context.Context - Servers map[int]*Server - helpers *helpers.HelpersController - serverDir string + ctx context.Context + Servers map[int]*Server + helpers *helpers.HelpersController + autoSaveIterations int + serverDir string } //region Struct Initialization and Creation @@ -57,8 +60,12 @@ func (c *ServerController) Startup(ctx context.Context) { c.serverDir = serverDir c.StartServersWithApplication() + c.RunAutoSaveTimers() } +// endregion + +// region Backend Functions func (c *ServerController) StartServersWithApplication() { servers, err := c.getAllServers() if err != nil { @@ -69,13 +76,64 @@ func (c *ServerController) StartServersWithApplication() { for id := range servers { server := c.Servers[id] - runtime.LogInfof(c.ctx, "StartWithApplication: %t", server.StartWithApplication) + runtime.LogInfof(c.ctx, "Starting server %s automatically", server.ServerName) if server.StartWithApplication { c.StartServer(server.Id) } } } +// start repeating timer that calls auto-save +// having one timer that manages all servers is advantageous: +// - catches conditions where a user enables auto-save after the timer has started +// - catches interval changes made after the timer has started +func (c *ServerController) RunAutoSaveTimers() { + c.autoSaveIterations = 0 + + autoSave := time.NewTicker(time.Minute) + for { + select { + case <-autoSave.C: + c.AutoSaveServers() + default: + continue + } + } +} + +func (c *ServerController) AutoSaveServers() { + servers, err := c.getAllServers() + if err != nil { + newErr := fmt.Errorf("Error getting all servers " + err.Error()) + runtime.LogErrorf(c.ctx, newErr.Error()) + return + } + + c.autoSaveIterations += 1 + // seconds in a minute * hours in a day * days, increase days if more days are required + // d + if c.autoSaveIterations == (60 * 24 * 7) { // one week in seconds + // very early max int catch (definitely extendable in the future if necessary) + c.autoSaveIterations = 0 + } + + for id := range servers { + server := c.Servers[id] + if server.AutoSaveEnabled { + // if interval is multiple of iterations + if c.autoSaveIterations%server.AutoSaveInterval == 0 { + runtime.LogInfo(c.ctx, "Running autosave for "+server.ServerName) + + err = server.SaveWorld() + if err != nil { + newErr := fmt.Errorf("Server auto-save created an error: " + err.Error()) + runtime.LogErrorf(c.ctx, newErr.Error()) + } + } + } + } +} + //endregion //region Frontend functions