Skip to content

Commit

Permalink
JensvandeWiel#121: Fix auto-save
Browse files Browse the repository at this point in the history
This PR fixes auto-save divide by 0
error.
  • Loading branch information
Jordan Dalby committed Nov 18, 2023
1 parent 5492eef commit 88392a6
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 15 deletions.
56 changes: 53 additions & 3 deletions frontend/src/pages/server/Administration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ function ServerAdministrationCard({setServ, serv, onServerFilesDeleted}: {setSer
</div>
</Card>;
}

function ServerStartupCard({setServ, serv}: {setServ: React.Dispatch<React.SetStateAction<server.Server>>, serv: server.Server}) {

const [showServerCommandModalOpen, setShowServerCommandModalOpen] = useState(false)
Expand Down Expand Up @@ -167,7 +168,7 @@ function ServerStartupCard({setServ, serv}: {setServ: React.Dispatch<React.SetSt
setServerCommand(cmd)
}).catch((err) => {
console.error(err);
addAlert(err, "danger");
addAlert(err, "danger")
})
}}>Show startup command</Button>
</div>
Expand Down Expand Up @@ -211,6 +212,56 @@ function ServerStartupCard({setServ, serv}: {setServ: React.Dispatch<React.SetSt
</Card>
)
}

function AutoSaveSettingsCard({ setServ, serv }: {setServ: React.Dispatch<React.SetStateAction<server.Server>>, serv: server.Server}) {

const {addAlert} = useAlert();

const handleAutoSaveIntervalChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newAutoSaveInterval = parseInt(e.target.value, 10);

if (newAutoSaveInterval > 0) {
setServ((prev) => ({
...prev,
autoSaveInterval: newAutoSaveInterval,
convertValues: prev.convertValues,
}));
} else {
addAlert("'Auto-Save Interval' must be greater than 0", "danger")
}
};

return (
<Card variant="soft" className={''}>
<Typography level="title-md">
Auto-Save Settings
</Typography>
<Divider className={'mx-2'}/>

<div className={'space-x-4 w-full flex'}>
<div className={'inline-block'}>
<Checkbox label="Enable Auto-Save" checked={serv?.autoSaveEnabled}
onChange={(e) => setServ((p) => ({
...p,
autoSaveEnabled: e.target.checked,
convertValues: p.convertValues
}))}/><br/>

<FormLabel>Auto-Save Interval (minutes)</FormLabel>
<Input
className={''}
type={'number'}
required
value={serv?.autoSaveInterval}
disabled={!serv?.autoSaveEnabled}
onChange={handleAutoSaveIntervalChange}
/>
</div>
</div>
</Card>
)
}

function ExtraSettingsCard({setServ, serv}: {setServ: React.Dispatch<React.SetStateAction<server.Server>>, serv: server.Server}) {
return (
<Card variant="soft" className={''}>
Expand Down Expand Up @@ -257,12 +308,11 @@ function ExtraSettingsCard({setServ, serv}: {setServ: React.Dispatch<React.SetSt
}

export function Administration({setServ, serv, onServerFilesDeleted}: Props) {


return (
<TabPanel value={3} className={'space-y-8'}>
<ServerAdministrationCard serv={serv} setServ={setServ} onServerFilesDeleted={onServerFilesDeleted}/>
<ServerStartupCard serv={serv} setServ={setServ} />
<AutoSaveSettingsCard setServ={setServ} serv={serv}/>
<ExtraSettingsCard setServ={setServ} serv={serv}/>
</TabPanel>
);
Expand Down
21 changes: 17 additions & 4 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
79 changes: 71 additions & 8 deletions server/server_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand All @@ -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
Expand All @@ -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 {
Expand All @@ -69,13 +76,69 @@ 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 server.AutoSaveInterval <= 0 {
runtime.LogError(c.ctx, "Server auto-save interval set 0 or below")
continue
}

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
Expand Down

0 comments on commit 88392a6

Please sign in to comment.