commit 3406ab47437c1305a1b3113e1d9ed3b5c6f8c820 Author: Raum0x2A Date: Sat Dec 13 03:17:50 2025 -0700 Initial commit Simple Factorio Server manager diff --git a/.vscode/factoryman.code-workspace b/.vscode/factoryman.code-workspace new file mode 100644 index 0000000..2a0ed79 --- /dev/null +++ b/.vscode/factoryman.code-workspace @@ -0,0 +1,7 @@ +{ + "folders": [ + { + "path": ".." + } + ] +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..b9a11c4 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,23 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch Package", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceFolder}" + }, + { + "name": "Launch file", + "type": "go", + "request": "launch", + "mode": "debug", + "program": "${file}" + } + + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..6950f91 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,13 @@ +{ + "editor.defaultFormatter": "golang.go", + "files.exclude": { + "*.swp": true + }, + + "[go]": { + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.organizeImports": "explicit" + } +} +} \ No newline at end of file diff --git a/config.yml b/config.yml new file mode 100644 index 0000000..8da28ea --- /dev/null +++ b/config.yml @@ -0,0 +1,9 @@ +server: + serverFolder: "factorio" + port: 34197 + worldFile: "factorio/newworld.zip" + serverSettings: "factorio/data/server-settings.json" + backupDir: "backups" + serverExec: "factorio/bin/x64/factorio" + screen: True + screenName: "Factorio" diff --git a/factoryman b/factoryman new file mode 100755 index 0000000..51e8981 Binary files /dev/null and b/factoryman differ diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..ab17687 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module gitlab.com/Raum0x2A/factoryman + +go 1.22.2 + +require gopkg.in/yaml.v3 v3.0.1 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..a62c313 --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go new file mode 100644 index 0000000..db0bc0d --- /dev/null +++ b/main.go @@ -0,0 +1,143 @@ +package main + +import ( + "fmt" + "log" + "os" + "os/exec" + "time" + + "gopkg.in/yaml.v3" +) + +const fmConfig = "config.yml" + +type GoConfig struct { + Config struct { + ServDir string `yaml:"serverFolder"` + ServPort int `yaml:"port"` + WorldFile string `yaml:"worldFile"` + ServCfg string `yaml:"serverSettings"` + ServExec string `yaml:"serverExec"` + BackupDir string `yaml:"backupDir"` + UseScreen bool `yaml:"screen"` + ScreenName string `yaml:"screenName"` + } `yaml:"server"` +} + +func readCfg(factCfg string) GoConfig { + //read config file (YAML) + fileBytes, err := os.ReadFile(factCfg) + if err != nil { + log.Fatalf("Error reading config file: %v", err) + } + // return Struct + var config GoConfig + err = yaml.Unmarshal(fileBytes, &config) + if err != nil { + log.Fatalf("Error unmarshalling YAML file: %v", err) + } + return config +} + +func startStopServer(cmd string, con GoConfig) { + switch cmd { + case "start": + x := fmt.Sprintf("%s --port %d --server-settings %s --start-server %s", con.Config.ServExec, con.Config.ServPort, con.Config.ServCfg, con.Config.WorldFile) + + //x := fmt.Sprintf("%s --port %d --server-settings %s --start-server %s; exec sh", con.Config.ServExec, con.Config.ServPort, con.Config.ServCfg, con.Config.WorldFile) + ///home/raum/factorio-serverfmt.Println(x) + if con.Config.UseScreen { + fmt.Println("Starting factorio server in screen session") + startScreenCmd := exec.Command("screen", "-dmS", con.Config.ScreenName, "bash", "-c", x, "; exec sh") + err := startScreenCmd.Run() + if err != nil { + log.Fatalf("Failed to start server: %s", err) + } else { + fmt.Printf("Started server on port %d, in screen named %s\n", con.Config.ServPort, con.Config.ScreenName) + } + } else { + startSrvCmd := exec.Command(x) + err := startSrvCmd.Run() + if err != nil { + log.Fatalf("Failed to start server: %s", err) + } + } + case "stop": + quitServerCmd := exec.Command("screen", "-S", con.Config.ScreenName, "-p", "0", "-X", "stuff", "/quit\n") + err := quitServerCmd.Run() + if err != nil { + log.Fatalf("Command failed: %s, Error: %v", quitServerCmd.Args, err) + } else { + fmt.Printf("Server in screen %s stopped\n", con.Config.ScreenName) + } + fmt.Println("Waiting for server to shutdown\r") + //time.Sleep(20 * time.Second) + //fmt.Println("Closing screen session ", con.Config.ScreenName) + //stopScreenCmd := exec.Command("screen", "-S", con.Config.ScreenName, "-p", "0", "-X", "stuff", "exit\n") + //err = stopScreenCmd.Run() + //if err != nil { + // log.Fatalf("Command failed: %s, Error: %v", stopScreenCmd.Args, err) + //} else { + // fmt.Printf("Screen \"%s\" closed\n", con.Config.ScreenName) + //} + } +} + +func backUp(cmd string, c GoConfig) { + switch cmd { + case "full": + fmt.Println("Starting full server backup") + t := time.Now() + timeStamp := t.Format(time.RFC3339) + fullBackupName := fmt.Sprintf("%s/ServerBackup.%s.tgz", c.Config.BackupDir, timeStamp) + fullBackup := exec.Command("tar", "-czf", fullBackupName, c.Config.ServDir) + err := fullBackup.Run() + if err != nil { + fmt.Printf("Backup Failed: %s\n", err) + } + case "saves": + fmt.Println("Backing up saves") + t := time.Now() + timeStamp := t.Format(time.RFC3339) + savesBackupName := fmt.Sprintf("%s/SaveBackup.%s.tgz", c.Config.BackupDir, timeStamp) + saveDir := fmt.Sprintf("%s/saves", c.Config.ServDir) + savesBackup := exec.Command("tar", "-czf", savesBackupName, saveDir) + err := savesBackup.Run() + if err != nil { + fmt.Printf("Backup Failed: %s\n", err) + } + } +} + +func main() { + c := readCfg(fmConfig) + + if len(os.Args) > 1 { + switch os.Args[1] { + case "start": + startStopServer("start", c) + case "stop": + startStopServer("stop", c) + case "backup": + if len(os.Args) > 2 { + switch os.Args[2] { + case "full": + backUp("full", c) + case "saves": + backUp("saves", c) + default: + fmt.Println("Invalid backup type: use 'full' or 'saves'") + } + } else { + fmt.Println("Missing backup type: use 'full' or 'saves'") + } + default: + fmt.Printf("Unknown command: %s. Use 'start', 'stop', or 'backup'.\n", os.Args[1]) + } + } else { + fmt.Println("Use 'start', 'stop', or 'backup' command") + fmt.Println("ex. factoryman start") + fmt.Println("To configure edit 'conifg.yml'") + } +}