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'") } }