+
+{/*
+ dsadasd
+*/}
+
Server Name:
setServ((p) => ({ ...p, serverName: e.target.value }))} >
diff --git a/go.mod b/go.mod
index d29a538..bb30606 100644
--- a/go.mod
+++ b/go.mod
@@ -4,11 +4,13 @@ go 1.18
require (
github.com/adrg/xdg v0.4.0
+ github.com/jensvandewiel/gosteamcmd v0.1.2
github.com/sethvargo/go-password v0.2.0
github.com/wailsapp/wails/v2 v2.6.0
)
require (
+ github.com/UserExistsError/conpty v0.1.1 // indirect
github.com/bep/debounce v1.2.1 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/google/uuid v1.3.1 // indirect
diff --git a/go.sum b/go.sum
index 286f436..97b00bd 100644
--- a/go.sum
+++ b/go.sum
@@ -1,3 +1,5 @@
+github.com/UserExistsError/conpty v0.1.1 h1:cHDsU/XeoeDAQmVvCTV53SrXLG39YJ4++Pp3iAi1gXE=
+github.com/UserExistsError/conpty v0.1.1/go.mod h1:PDglKIkX3O/2xVk0MV9a6bCWxRmPVfxqZoTG/5sSd9I=
github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=
github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E=
github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
@@ -11,6 +13,8 @@ github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
+github.com/jensvandewiel/gosteamcmd v0.1.2 h1:NHichoj0v3GvSVN2Fn36dSOLosHAytpaKnLnDHTMQPI=
+github.com/jensvandewiel/gosteamcmd v0.1.2/go.mod h1:Y7hP+iXFIOs8II68VrbdR+W1wwpB8LXYe9lfgjyTLIw=
github.com/labstack/echo/v4 v4.11.2 h1:T+cTLQxWCDfqDEoydYm5kCobjmHwOwcv4OJAPHilmdE=
github.com/labstack/echo/v4 v4.11.2/go.mod h1:UcGuQ8V6ZNRmSweBIJkPvGfwCMIlFmiqrPqiEBfPYws=
github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
@@ -80,6 +84,7 @@ golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
diff --git a/helpers/helpers.go b/helpers/helpers.go
new file mode 100644
index 0000000..072f834
--- /dev/null
+++ b/helpers/helpers.go
@@ -0,0 +1,22 @@
+package helpers
+
+import (
+ "context"
+ "github.com/wailsapp/wails/v2/pkg/runtime"
+)
+
+type HelpersController struct {
+ ctx context.Context
+}
+
+func NewHelpersController() *HelpersController {
+ return &HelpersController{}
+}
+
+func (c *HelpersController) Startup(ctx context.Context) {
+ c.ctx = ctx
+}
+
+func (c *HelpersController) OpenDirectoryDialog() (string, error) {
+ return runtime.OpenDirectoryDialog(c.ctx, runtime.OpenDialogOptions{})
+}
diff --git a/installer/installer_controller.go b/installer/installer_controller.go
new file mode 100644
index 0000000..861e741
--- /dev/null
+++ b/installer/installer_controller.go
@@ -0,0 +1,87 @@
+package installer
+
+import (
+ "context"
+ "fmt"
+ "github.com/jensvandewiel/gosteamcmd"
+ "github.com/jensvandewiel/gosteamcmd/console"
+ "github.com/wailsapp/wails/v2/pkg/runtime"
+ "io"
+ "strconv"
+ "strings"
+)
+
+type InstallerController struct {
+ ctx context.Context
+}
+
+func NewInstallerController() *InstallerController {
+ return &InstallerController{}
+}
+
+func (c *InstallerController) Startup(ctx context.Context) {
+ c.ctx = ctx
+}
+
+/*
+Events:
+- "installingUpdateAction" sends updates about the installers args: "action"
+- "installingUpdateProgress" sends updates about the installers args: "progress"
+- "appInstalled" sends when app ist installed with the id as arg
+
+*/
+
+// Install installs the server and returns true is successful and error and false if failed
+func (c *InstallerController) Install(installPath string) error {
+
+ prompts := []*gosteamcmd.Prompt{
+ gosteamcmd.ForceInstallDir(installPath),
+ gosteamcmd.Login("", "", ""),
+ gosteamcmd.AppUpdate(2430930, "", true),
+ }
+
+ cmd := gosteamcmd.New(io.Discard, prompts, "")
+
+ cmd.Console.Parser.OnInformationReceived = func(action console.Action, progress float64, currentWritten, total uint64) {
+ actionString := ""
+
+ switch action {
+ case console.Downloading:
+ actionString = "downloading"
+ case console.Verifying:
+ actionString = "verifying"
+ case console.Preallocating:
+ actionString = "preallocating"
+ default:
+ actionString = "unknown"
+ }
+
+ runtime.EventsEmit(c.ctx, "installingUpdateAction", actionString)
+ runtime.EventsEmit(c.ctx, "installingUpdateProgress", progress)
+
+ runtime.LogDebug(c.ctx, "Installer info received: action: "+actionString+" progress: "+fmt.Sprintf("%f", progress))
+ }
+ cmd.Console.Parser.OnAppInstalled = func(app uint32) {
+ runtime.LogDebug(c.ctx, "Installer info received: App installed: "+strconv.Itoa(int(app)))
+
+ runtime.EventsEmit(c.ctx, "appInstalled", app)
+ }
+ i, err := cmd.Run()
+
+ if err != nil {
+
+ if strings.Contains(err.Error(), "The system cannot find the file specified") {
+ runtime.LogError(c.ctx, "failed to install: "+err.Error()+" (this is likely because STEAMCMD is not installed to path)")
+ return fmt.Errorf("failed to install: " + err.Error() + " (this is likely because STEAMCMD is not installed to path)")
+ } else {
+ runtime.LogError(c.ctx, "failed to install: "+err.Error())
+ return fmt.Errorf("failed to install: " + err.Error())
+ }
+
+ }
+
+ if i != 0 {
+ return fmt.Errorf("failed to install: returned non 0 return code: " + strconv.Itoa(int(i)))
+ }
+ return nil
+}
diff --git a/main.go b/main.go
index 4d18adb..188c225 100644
--- a/main.go
+++ b/main.go
@@ -4,6 +4,8 @@ import (
"context"
"embed"
"github.com/JensvandeWiel/ArkAscendedServerManager/config"
+ "github.com/JensvandeWiel/ArkAscendedServerManager/helpers"
+ "github.com/JensvandeWiel/ArkAscendedServerManager/installer"
"github.com/JensvandeWiel/ArkAscendedServerManager/logger"
"github.com/JensvandeWiel/ArkAscendedServerManager/server"
"github.com/wailsapp/wails/v2"
@@ -34,6 +36,8 @@ func main() {
app := NewApp()
c := config.NewConfigController()
s := server.NewServerController()
+ i := installer.NewInstallerController()
+ h := helpers.NewHelpersController()
// Create application with options
err = wails.Run(&options.App{
@@ -48,6 +52,8 @@ func main() {
app.startup(ctx)
c.Startup(ctx)
s.Startup(ctx)
+ i.Startup(ctx)
+ h.Startup(ctx)
},
Logger: l,
LogLevel: wailsLogger.TRACE,
@@ -55,6 +61,8 @@ func main() {
app,
c,
s,
+ i,
+ h,
},
})
diff --git a/server/helpers.go b/server/helpers.go
index c976722..0383fa0 100644
--- a/server/helpers.go
+++ b/server/helpers.go
@@ -11,7 +11,7 @@ import (
// region Local Helpers
// findHighestKey returns the highest key in a map with int as key
-func findHighestKey(m map[int]Server) int {
+func findHighestKey(m map[int]*Server) int {
var highestKey int = -1
for key := range m {
@@ -25,20 +25,20 @@ func findHighestKey(m map[int]Server) int {
func generateNewDefaultServer(id int) Server {
- serverPassword, err := password.Generate(18, 6, 6, false, false)
+ /*serverPassword, err := password.Generate(18, 6, 6, false, false)
if err != nil {
serverPassword = ""
- }
+ }*/
adminPassword, err := password.Generate(18, 6, 6, false, false)
if err != nil {
adminPassword = "default"
}
- spectatorPassword, err := password.Generate(18, 6, 6, false, false)
+ /*spectatorPassword, err := password.Generate(18, 6, 6, false, false)
if err != nil {
spectatorPassword = "default"
- }
+ }*/
return Server{
Id: id,
@@ -46,15 +46,18 @@ func generateNewDefaultServer(id int) Server {
ServerName: "A server managed by ArkAscendedServerManager",
- ServerPassword: serverPassword,
+ ServerPassword: "",
AdminPassword: adminPassword,
- SpectatorPassword: spectatorPassword,
+ SpectatorPassword: "",
IpAddress: "0.0.0.0",
ServerPort: 7777,
PeerPort: 7778,
QueryPort: 27015,
RCONPort: 28015,
+
+ ServerMap: "TheIsland_WP",
+ MaxPlayers: 70,
}
}
diff --git a/server/server.go b/server/server.go
index 708aebe..dae35ec 100644
--- a/server/server.go
+++ b/server/server.go
@@ -1,21 +1,103 @@
package server
+import (
+ "fmt"
+ "os/exec"
+ "path"
+ "strconv"
+)
+
// Server contains the server "stuff"
+
+type GameUserSettings struct {
+}
+
type Server struct {
- Id int `json:"id"`
+ Command *exec.Cmd `json:"-"`
+
+ //CONFIGURATION VARIABLES
+
+ // Id is the id of the server
+ Id int `json:"id"`
+
+ // ServerAlias is the name of the config (an alias for the server)
ServerAlias string `json:"serverAlias"`
+ // ServerPath is the path where the server is installed/should be.
+ ServerPath string `json:"serverPath"`
+
//Server Name and Passwords
ServerName string `json:"serverName"`
- ServerPassword string `json:"serverPassword"`
+ ServerPassword string `json:"serverPassword"` //TODO: Implement in startup/config
AdminPassword string `json:"adminPassword"`
- SpectatorPassword string `json:"spectatorPassword"`
+ SpectatorPassword string `json:"spectatorPassword"` //TODO: Implement in startup/config
//Server Networking
IpAddress string `json:"ipAddress"`
ServerPort int `json:"serverPort"`
- PeerPort int `json:"peerPort"`
+ PeerPort int `json:"peerPort"` //TODO: Implement in startup/config
QueryPort int `json:"queryPort"`
RCONPort int `json:"rconPort"`
+
+ //Server configuration
+ ServerMap string `json:"serverMap"`
+ MaxPlayers int `json:"maxPlayers"`
+}
+
+// UpdateConfig updates the configuration files for the server e.g.: GameUserSettings.ini
+func (s *Server) UpdateConfig() error {
+
+ return nil
+}
+
+//TODO Add configuration parsing/loading/saving for server specific files
+//TODO Add startup arguments parsing
+
+func (s *Server) Start() error {
+
+ err := s.UpdateConfig()
+ if err != nil {
+ return fmt.Errorf("error starting server: failed updating server configuration: %v", err)
+ }
+
+ if s.Command != nil {
+ return fmt.Errorf("error starting server: server is already started")
+ }
+
+ s.Command = exec.Command(path.Join(s.ServerPath, "ShooterGame\\Binaries\\Win64\\ArkAscendedServer.exe"), s.CreateArguments())
+ err = s.Command.Start()
+ if err != nil {
+ return fmt.Errorf("error starting server: %v", err)
+ }
+
+ return nil
+}
+
+// ForceStop forces the server to stop "quitting/killing the process"
+func (s *Server) ForceStop() error {
+
+ if s.Command == nil {
+ return fmt.Errorf("error stopping server: s.Command is nil")
+ }
+ err := s.Command.Process.Kill()
+ if err != nil {
+ return fmt.Errorf("error stopping server: %v", err)
+ }
+
+ s.Command = nil
+
+ return nil
+}
+
+func (s *Server) CreateArguments() string {
+ basePrompt := s.ServerMap + "?listen"
+ basePrompt += "?MultiHome=" + s.IpAddress
+ basePrompt += "?Port=" + strconv.Itoa(s.ServerPort)
+ basePrompt += "?QueryPort=" + strconv.Itoa(s.QueryPort)
+ basePrompt += "?RCONEnabled=true?RCONServerGameLogBuffer=600?RCONPort=" + strconv.Itoa(s.RCONPort)
+ basePrompt += "?MaxPlayers=" + strconv.Itoa(s.MaxPlayers)
+ basePrompt += "?ServerAdminPassword=" + s.AdminPassword
+
+ return basePrompt
}
diff --git a/server/server_controller.go b/server/server_controller.go
index 4b4afd5..a6847d2 100644
--- a/server/server_controller.go
+++ b/server/server_controller.go
@@ -29,14 +29,16 @@ const (
// ServerController struct
type ServerController struct {
ctx context.Context
- Servers map[int]Server
+ Servers map[int]*Server
serverDir string
}
+//region Struct Initialization and Creation
+
// NewServerController creates a new ServerController application struct
func NewServerController() *ServerController {
return &ServerController{
- Servers: make(map[int]Server),
+ Servers: make(map[int]*Server),
}
}
@@ -53,114 +55,48 @@ func (c *ServerController) Startup(ctx context.Context) {
c.serverDir = serverDir
}
-// GetServer returns the server with the given id if it does not exist it returns an empty server. This function checks the server dir too. If it does not exist in the map, and it does in the dir then it will add it to the map. It can error which is catch-able in the frontend
-func (c *ServerController) GetServer(id int) (Server, error) {
- server, err := c.GetServerWithError(id)
- if err != nil {
- newErr := fmt.Errorf("Failed getting server: " + strconv.Itoa(id) + " with: " + err.Error())
- runtime.LogError(c.ctx, newErr.Error())
- return server, newErr
- }
- return server, nil
-}
+//endregion
+
+//region Saving and Loading
// GetServerWithError returns the server with the given id if it does not exist it returns an empty server. This function checks the server dir too. If it does not exist in the map, and it does in the dir then it will add it to the map.
-func (c *ServerController) GetServerWithError(id int) (Server, error) {
+func (c *ServerController) GetServerWithError(id int, addToMap bool) (*Server, error) {
server, exists := c.Servers[id]
// If it does not exist in the map check the server dir
if !exists {
s, err := c.getServerFromDir(id, false)
if err != nil {
- return Server{}, fmt.Errorf("Error getting server instance: %s", err.Error())
+ return nil, fmt.Errorf("Error getting server instance: %s", err.Error())
+ }
+
+ if addToMap {
+ c.Servers[id] = &s
}
- c.Servers[id] = s
runtime.EventsEmit(c.ctx, "gotServer", s.Id)
- return s, nil
+ return &s, nil
} else {
runtime.EventsEmit(c.ctx, "gotServer", server.Id)
return server, nil
}
}
-// getServerFromDir gets the server from the server dir if it does not exist and shouldReturnNew is true it returns a new server.
-func (c *ServerController) getServerFromDir(id int, shouldReturnNew bool) (Server, error) {
- serverDir := path.Join(c.serverDir, strconv.Itoa(id))
-
- /*// Check if config dir exists
- if _, err := os.Stat(serverDir); os.IsNotExist(err) {
- runtime.LogDebug(c.ctx, "Server config "+strconv.Itoa(id)+" does not exist, returning new server instance")
- return Server{
- id: id,
- }
- }*/
-
- // If config file does not exist return a new instance
- _, err := os.Stat(path.Join(serverDir, configFileName))
- if err != nil {
- if os.IsNotExist(err) {
- if shouldReturnNew {
- runtime.LogDebug(c.ctx, "Server config "+strconv.Itoa(id)+" does not exist, returning new server instance")
- return Server{
- Id: id,
- }, nil
- } else {
- runtime.LogDebug(c.ctx, "Server config "+strconv.Itoa(id)+" does not exist, returning empty server instance, with error \"Server does not exist\"")
- return Server{}, fmt.Errorf("server does not exist")
- }
- }
- return Server{}, fmt.Errorf("Error reading server config file: " + err.Error())
- }
-
- //It exists so read the file
- scf, err := os.ReadFile(path.Join(serverDir, configFileName))
- if err != nil {
- return Server{}, fmt.Errorf("Error reading server config file: " + err.Error())
- }
-
- serv := Server{}
-
- err = json.Unmarshal(scf, &serv)
- if err != nil {
- return Server{}, fmt.Errorf("Error unmarshalling server config file: " + err.Error())
- }
-
- // Check if server is correct.
- if err := CheckIfServerCorrect(serv); err != nil {
- return Server{}, fmt.Errorf("Parsing server instance failed: " + err.Error())
- }
-
- return serv, nil
-}
-
-// CreateServer Creates a new server, returns it and adds it to the map. If it fails it returns an error which is catch-able in the Frontend.
-func (c *ServerController) CreateServer(saveToConfig bool) (Server, error) {
- _, server, err := c.CreateServerWithError(saveToConfig)
- if err != nil {
- newErr := fmt.Errorf("Failed saving new server: " + err.Error())
- runtime.LogError(c.ctx, newErr.Error())
- return Server{}, newErr
- }
- return server, nil
-
-}
-
// CreateServerWithError Creates a new server, returns it and adds it to the map, it also returns the key. If it fails it returns an error and an empty server and int -1
-func (c *ServerController) CreateServerWithError(saveToConfig bool) (int, Server, error) {
+func (c *ServerController) CreateServerWithError(saveToConfig bool) (int, *Server, error) {
// get the highest in to generate new id
maxKey := findHighestKey(c.Servers)
id := maxKey + 1
if _, exists := c.Servers[id]; exists {
- return -1, Server{}, fmt.Errorf("Found a server with an key higher than the maximum key, max key: " + strconv.Itoa(maxKey) + " exists: " + strconv.Itoa(id))
+ return -1, nil, fmt.Errorf("Found a server with an key higher than the maximum key, max key: " + strconv.Itoa(maxKey) + " exists: " + strconv.Itoa(id))
}
// Check if it exists
if _, exists := c.Servers[id]; exists {
- return -1, Server{}, fmt.Errorf("Found a server with new key in c.Servers key: " + strconv.Itoa(id))
+ return -1, nil, fmt.Errorf("Found a server with new key in c.Servers key: " + strconv.Itoa(id))
}
NewServer := generateNewDefaultServer(id)
- c.Servers[id] = NewServer
+ c.Servers[id] = &NewServer
if saveToConfig {
err := c.SaveServerWithError(c.Servers[id])
@@ -172,25 +108,13 @@ func (c *ServerController) CreateServerWithError(saveToConfig bool) (int, Server
runtime.EventsEmit(c.ctx, "serverCreated", NewServer.Id)
- return id, NewServer, nil
-}
-
-// SaveServer saves the server with the given id, and returns bool if successful
-func (c *ServerController) SaveServer(server Server) error {
- err := c.SaveServerWithError(server)
- if err != nil {
- newErr := fmt.Errorf("Error saving server: " + err.Error())
- runtime.LogError(c.ctx, newErr.Error())
- return newErr
- }
- return nil
+ return id, &NewServer, nil
}
// SaveServerWithError saves the server, and returns an error if it fails
-func (c *ServerController) SaveServerWithError(server Server) error {
-
+func (c *ServerController) SaveServerWithError(server *Server) error {
// Check if server is correct.
- if err := CheckIfServerCorrect(server); err != nil {
+ if err := CheckIfServerCorrect(*server); err != nil {
return fmt.Errorf("Parsing server instance failed: " + err.Error())
}
@@ -223,22 +147,9 @@ func (c *ServerController) SaveServerWithError(server Server) error {
return nil
}
-// GetAllServers gets all servers and saves them to ServerController.Servers and also returns them, if it fails it returns nil and false. If they already exist in the map it will just get that.
-func (c *ServerController) GetAllServers() (map[int]Server, error) {
-
- servers, err := c.GetAllServersWithError()
- if err != nil {
- newErr := fmt.Errorf("Failed to get all servers " + c.serverDir + " error: " + err.Error())
- runtime.LogError(c.ctx, newErr.Error())
- return nil, newErr
- }
-
- c.Servers = servers
- return c.Servers, nil
-}
+// GetAllServersWithError gets all servers and saves them to ServerController.Servers and also returns them, if it fails it returns nil and error. If they already exist in the map it will just get that.
+func (c *ServerController) GetAllServersWithError() (map[int]*Server, error) {
-// GetAllServersWithError gets all servers and saves them to ServerController.Servers and also returns them, if it fails it returns nil and false. If they already exist in the map it will just get that.
-func (c *ServerController) GetAllServersWithError() (map[int]Server, error) {
allServerDir := c.serverDir
if _, err := os.Stat(allServerDir); err != nil {
@@ -253,7 +164,7 @@ func (c *ServerController) GetAllServersWithError() (map[int]Server, error) {
return nil, fmt.Errorf("Failed to read children in " + c.serverDir + " error: " + err.Error())
}
- servers := make(map[int]Server)
+ servers := make(map[int]*Server)
for _, child := range children {
if child.IsDir() {
@@ -262,7 +173,7 @@ func (c *ServerController) GetAllServersWithError() (map[int]Server, error) {
return nil, fmt.Errorf("Failed to parse to int: " + child.Name() + " error: " + err.Error())
}
- server, err := c.GetServerWithError(index)
+ server, err := c.GetServerWithError(index, false)
if err != nil {
return nil, fmt.Errorf("Failed to get server: " + child.Name() + " error: " + err.Error())
}
@@ -277,7 +188,7 @@ func (c *ServerController) GetAllServersWithError() (map[int]Server, error) {
}
// GetAllServersFromDir gets all servers from dir and saves them to ServerController.Servers and also returns them, if it fails it returns nil and an error which is catch-able in the frontend. This will overwrite c.Servers!
-func (c *ServerController) GetAllServersFromDir() (map[int]Server, error) {
+func (c *ServerController) GetAllServersFromDir() (map[int]*Server, error) {
allserverDir := c.serverDir
if _, err := os.Stat(allserverDir); err != nil {
@@ -298,7 +209,7 @@ func (c *ServerController) GetAllServersFromDir() (map[int]Server, error) {
return nil, newErr
}
- servers := make(map[int]Server)
+ servers := make(map[int]*Server)
for _, child := range children {
if child.IsDir() {
@@ -315,7 +226,7 @@ func (c *ServerController) GetAllServersFromDir() (map[int]Server, error) {
runtime.LogError(c.ctx, newErr.Error())
return nil, newErr
}
- servers[index] = server
+ servers[index] = &server
}
}
@@ -323,3 +234,191 @@ func (c *ServerController) GetAllServersFromDir() (map[int]Server, error) {
return c.Servers, nil
}
+
+//region Boilerplate functions
+
+// GetAllServers gets all servers and saves them to ServerController.Servers and also returns them, if it fails it returns nil and error. If they already exist in the map it will just get that.
+func (c *ServerController) GetAllServers() (map[int]Server, error) {
+
+ servers, err := c.GetAllServersWithError()
+ if err != nil {
+ newErr := fmt.Errorf("Failed to get all servers " + c.serverDir + " error: " + err.Error())
+ runtime.LogError(c.ctx, newErr.Error())
+ return nil, newErr
+ }
+
+ newMap := make(map[int]Server)
+
+ // Copy the data from the original map to the new map
+ for key, value := range servers {
+ newMap[key] = *value
+ }
+ return newMap, nil
+}
+
+// SaveServer saves the server with the given id, and returns bool if successful
+func (c *ServerController) SaveServer(server Server) error {
+
+ //TODO Make sure oldserv members get passed over to new instance since frontend will change all members even Command (which should not be updated by the frontend)
+
+ oldServ, err := c.GetServerWithError(server.Id, true)
+ if err != nil {
+ newErr := fmt.Errorf("Error saving server: " + err.Error())
+ runtime.LogError(c.ctx, newErr.Error())
+ return newErr
+ }
+
+ server.Command = oldServ.Command
+
+ err = c.SaveServerWithError(&server)
+ if err != nil {
+ newErr := fmt.Errorf("Error saving server: " + err.Error())
+ runtime.LogError(c.ctx, newErr.Error())
+ return newErr
+ }
+ return nil
+}
+
+// GetServer returns the server with the given id if it does not exist it returns an empty server. This function checks the server dir too. If it does not exist in the map, and it does in the dir then it will add it to the map. It can error which is catch-able in the frontend
+func (c *ServerController) GetServer(id int) (Server, error) {
+ server, err := c.GetServerWithError(id, true)
+ if err != nil {
+ newErr := fmt.Errorf("Failed getting server: " + strconv.Itoa(id) + " with: " + err.Error())
+ runtime.LogError(c.ctx, newErr.Error())
+ return *server, newErr
+ }
+ return *server, nil
+}
+
+// CreateServer Creates a new server, returns it and adds it to the map. If it fails it returns an error which is catch-able in the Frontend.
+func (c *ServerController) CreateServer(saveToConfig bool) (Server, error) {
+ _, server, err := c.CreateServerWithError(saveToConfig)
+ if err != nil {
+ newErr := fmt.Errorf("Failed saving new server: " + err.Error())
+ runtime.LogError(c.ctx, newErr.Error())
+ return Server{}, newErr
+ }
+ return *server, nil
+
+}
+
+//region Private
+
+// getServerFromDir gets the server from the server dir if it does not exist and shouldReturnNew is true it returns a new server.
+func (c *ServerController) getServerFromDir(id int, shouldReturnNew bool) (Server, error) {
+ serverDir := path.Join(c.serverDir, strconv.Itoa(id))
+
+ /*// Check if config dir exists
+ if _, err := os.Stat(serverDir); os.IsNotExist(err) {
+ runtime.LogDebug(c.ctx, "Server config "+strconv.Itoa(id)+" does not exist, returning new server instance")
+ return Server{
+ id: id,
+ }
+ }*/
+
+ // If config file does not exist return a new instance
+ _, err := os.Stat(path.Join(serverDir, configFileName))
+ if err != nil {
+ if os.IsNotExist(err) {
+ if shouldReturnNew {
+ runtime.LogDebug(c.ctx, "Server config "+strconv.Itoa(id)+" does not exist, returning new server instance")
+ return Server{
+ Id: id,
+ }, nil
+ } else {
+ runtime.LogDebug(c.ctx, "Server config "+strconv.Itoa(id)+" does not exist, returning empty server instance, with error \"Server does not exist\"")
+ return Server{}, fmt.Errorf("server does not exist")
+ }
+ }
+ return Server{}, fmt.Errorf("Error reading server config file: " + err.Error())
+ }
+
+ //It exists so read the file
+ scf, err := os.ReadFile(path.Join(serverDir, configFileName))
+ if err != nil {
+ return Server{}, fmt.Errorf("Error reading server config file: " + err.Error())
+ }
+
+ serv := Server{}
+
+ err = json.Unmarshal(scf, &serv)
+ if err != nil {
+ return Server{}, fmt.Errorf("Error unmarshalling server config file: " + err.Error())
+ }
+
+ // Check if server is correct.
+ if err := CheckIfServerCorrect(serv); err != nil {
+ return Server{}, fmt.Errorf("Parsing server instance failed: " + err.Error())
+ }
+
+ return serv, nil
+}
+
+//endregion
+
+//endregion
+
+//endregion
+
+//region Server starting & stopping
+
+// StartServer starts the server. It will only start a server that exists in the map
+func (c *ServerController) StartServer(id int) error {
+
+ server, exists := c.Servers[id]
+ if !exists {
+ err := fmt.Errorf("error starting server " + strconv.Itoa(id) + ": server does not exist in map")
+ runtime.LogError(c.ctx, err.Error())
+ return err
+ }
+
+ err := server.Start()
+ if err != nil {
+ err := fmt.Errorf("error starting server " + strconv.Itoa(id) + ": " + err.Error())
+ runtime.LogError(c.ctx, err.Error())
+ return err
+ }
+
+ return nil
+}
+
+func (c *ServerController) ForceStopServer(id int) error {
+
+ server, exists := c.Servers[id]
+ if !exists {
+ err := fmt.Errorf("error starting server " + strconv.Itoa(id) + ": server does not exist in map")
+ runtime.LogError(c.ctx, err.Error())
+ return err
+ }
+
+ err := server.ForceStop()
+ if err != nil {
+ err := fmt.Errorf("error starting server " + strconv.Itoa(id) + ": " + err.Error())
+ runtime.LogError(c.ctx, err.Error())
+ return err
+ }
+
+ return nil
+}
+
+//endregion
+
+//region ServerController helper functions
+
+// CheckServerInstalled Checks if the server dir exists.
+//
+// TODO: This should check more in depth.
+func (c *ServerController) CheckServerInstalled(id int) (bool, error) {
+
+ server := c.Servers[id]
+
+ if _, err := os.Stat(path.Join(server.ServerPath, "\\ShooterGame\\Binaries\\Win64\\ArkAscendedServer.exe")); os.IsNotExist(err) {
+ return false, nil
+ } else if err != nil {
+ return false, fmt.Errorf("error checking if server installed: %v", err)
+ }
+
+ return true, nil
+}
+
+//endregion