diff --git a/.gitignore b/.gitignore index 961366d..34383be 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ mix-manifest.json /app/*.js* /app/*.css* .vscode +.env diff --git a/src/.env.example b/src/.env.example new file mode 100644 index 0000000..752c749 --- /dev/null +++ b/src/.env.example @@ -0,0 +1,5 @@ +factorio_username= +factorio_password= +conf=../../conf.json.example +mod_dir=dev +mod_pack_dir=dev_pack \ No newline at end of file diff --git a/src/api/handlers.go b/src/api/handlers.go index 3ecad45..9711520 100644 --- a/src/api/handlers.go +++ b/src/api/handlers.go @@ -249,7 +249,7 @@ func LoadConfig(w http.ResponseWriter, r *http.Request) { func StartServer(w http.ResponseWriter, r *http.Request) { var err error var resp interface{} - var server, _ = factorio.GetFactorioServer() + var server = factorio.GetFactorioServer() defer func() { WriteResponse(w, resp) }() @@ -326,7 +326,7 @@ func StopServer(w http.ResponseWriter, r *http.Request) { }() w.Header().Set("Content-Type", "application/json;charset=UTF-8") - var server, _ = factorio.GetFactorioServer() + var server = factorio.GetFactorioServer() if server.Running { err := server.Stop() if err != nil { @@ -353,7 +353,7 @@ func KillServer(w http.ResponseWriter, r *http.Request) { }() w.Header().Set("Content-Type", "application/json;charset=UTF-8") - var server, _ = factorio.GetFactorioServer() + var server = factorio.GetFactorioServer() if server.Running { err := server.Kill() if err != nil { @@ -378,7 +378,7 @@ func CheckServer(w http.ResponseWriter, r *http.Request) { }() w.Header().Set("Content-Type", "application/json;charset=UTF-8") - var server, _ = factorio.GetFactorioServer() + var server = factorio.GetFactorioServer() if server.Running { resp["status"] = "running" resp["port"] = strconv.Itoa(server.Port) @@ -397,7 +397,7 @@ func FactorioVersion(w http.ResponseWriter, r *http.Request) { }() w.Header().Set("Content-Type", "application/json;charset=UTF-8") - var server, _ = factorio.GetFactorioServer() + var server = factorio.GetFactorioServer() resp["version"] = server.Version.String() resp["base_mod_version"] = server.BaseModVersion } @@ -577,7 +577,7 @@ func GetServerSettings(w http.ResponseWriter, r *http.Request) { }() w.Header().Set("Content-Type", "application/json;charset=UTF-8") - var server, _ = factorio.GetFactorioServer() + var server = factorio.GetFactorioServer() resp = server.Settings log.Printf("Sent server settings response") @@ -597,7 +597,7 @@ func UpdateServerSettings(w http.ResponseWriter, r *http.Request) { return } log.Printf("Received settings JSON: %s", body) - var server, _ = factorio.GetFactorioServer() + var server = factorio.GetFactorioServer() err = json.Unmarshal(body, &server.Settings) if err != nil { resp = fmt.Sprintf("Error unmarhaling server settings JSON: %s", err) diff --git a/src/api/mods_handler_test.go b/src/api/mods_handler_test.go index cf043ca..5bff7f0 100644 --- a/src/api/mods_handler_test.go +++ b/src/api/mods_handler_test.go @@ -3,6 +3,7 @@ package api import ( "bytes" "github.com/gorilla/mux" + "github.com/joho/godotenv" "github.com/mroote/factorio-server-manager/bootstrap" "github.com/mroote/factorio-server-manager/factorio" "github.com/stretchr/testify/assert" @@ -21,6 +22,8 @@ import ( func TestMain(m *testing.M) { var err error + godotenv.Load("../.env") + // basic setup stuff bootstrap.NewConfig([]string{ "--dir", os.Getenv("dir"), @@ -28,9 +31,11 @@ func TestMain(m *testing.M) { "--mod-pack-dir", os.Getenv("mod_pack_dir"), "--mod-dir", os.Getenv("mod_dir"), }) - FactorioServ := new(factorio.Server) - FactorioServ.Version = factorio.Version{1, 0, 0, 0} - FactorioServ.BaseModVersion = "1.0.0" + + factorio.SetFactorioServer(factorio.Server{ + Version: factorio.Version{0, 18, 30, 0}, + BaseModVersion: "0.18.30", + }) // check login status var cred factorio.Credentials diff --git a/src/api/wsroutes.go b/src/api/wsroutes.go index 4759d3e..df0bfc7 100644 --- a/src/api/wsroutes.go +++ b/src/api/wsroutes.go @@ -42,7 +42,7 @@ func LogSubscribe(client *Client, data interface{}) { } func CommandSend(client *Client, data interface{}) { - var server, _ = factorio.GetFactorioServer() + server := factorio.GetFactorioServer() if server.Running { go func() { log.Printf("Received command: %v", data) @@ -66,7 +66,7 @@ func CommandSend(client *Client, data interface{}) { } func ServerStatusSubscribe(client *Client, data interface{}) { - var server, _ = factorio.GetFactorioServer() + var server = factorio.GetFactorioServer() log.Printf("Subcribed to Server Status") go func() { isRunning := server.Running diff --git a/src/factorio/mod_modInfo.go b/src/factorio/mod_modInfo.go index 31664fd..89e59fc 100644 --- a/src/factorio/mod_modInfo.go +++ b/src/factorio/mod_modInfo.go @@ -83,6 +83,7 @@ func (modInfoList *ModInfoList) listInstalledMods() error { continue } + // skip optional and incompatible dependencies parts := strings.Split(dep, " ") if len(parts) > 3 { log.Printf("skipping dependency '%s' in '%s': invalid format\n", dep, modInfo.Name) @@ -107,7 +108,7 @@ func (modInfoList *ModInfoList) listInstalledMods() error { break } - server, _ := GetFactorioServer() + server := GetFactorioServer() if !base.Equals(NilVersion) { modInfo.Compatibility = server.Version.Compare(base, op) diff --git a/src/factorio/mod_modpack.go b/src/factorio/mod_modpack.go index 7f3b131..c706282 100644 --- a/src/factorio/mod_modpack.go +++ b/src/factorio/mod_modpack.go @@ -53,8 +53,7 @@ func (modPackMap *ModPackMap) reload() error { var err error newModPackMap := make(ModPackMap) config := bootstrap.GetConfig() - abs, err := filepath.Abs(config.FactorioModPackDir) - println(abs) + err = filepath.Walk(config.FactorioModPackDir, func(path string, info os.FileInfo, err error) error { if path == config.FactorioModPackDir || !info.IsDir() { return nil diff --git a/src/factorio/mod_portal.go b/src/factorio/mod_portal.go index d520e0e..b912f89 100644 --- a/src/factorio/mod_portal.go +++ b/src/factorio/mod_portal.go @@ -33,22 +33,25 @@ type ModPortalStruct struct { func ModPortalList() (interface{}, error, int) { req, err := http.NewRequest(http.MethodGet, "https://mods.factorio.com/api/mods?page_size=max", nil) if err != nil { - return "error", err, 500 + return "error", err, http.StatusInternalServerError } resp, err := http.DefaultClient.Do(req) if err != nil { - return "error", err, 500 + return "error", err, http.StatusInternalServerError } text, err := ioutil.ReadAll(resp.Body) resp.Body.Close() if err != nil { - return "error", err, 500 + return "error", err, http.StatusInternalServerError } var jsonVal interface{} - json.Unmarshal(text, &jsonVal) + err = json.Unmarshal(text, &jsonVal) + if err != nil { + return "error", err, http.StatusInternalServerError + } return jsonVal, nil, resp.StatusCode } @@ -59,27 +62,27 @@ func ModPortalModDetails(modId string) (ModPortalStruct, error, int) { req, err := http.NewRequest(http.MethodGet, "https://mods.factorio.com/api/mods/"+modId, nil) if err != nil { - return mod, err, 500 + return mod, err, http.StatusInternalServerError } resp, err := http.DefaultClient.Do(req) if err != nil { - return mod, err, 500 + return mod, err, http.StatusInternalServerError } text, err := ioutil.ReadAll(resp.Body) resp.Body.Close() if err != nil { - return mod, err, 500 + return mod, err, http.StatusInternalServerError } - json.Unmarshal(text, &mod) - - server, err := GetFactorioServer() + err = json.Unmarshal(text, &mod) if err != nil { - return mod, err, resp.StatusCode + return mod, err, http.StatusInternalServerError } + server := GetFactorioServer() + installedBaseVersion := Version{} _ = installedBaseVersion.UnmarshalText([]byte(server.BaseModVersion)) requiredVersion := NilVersion diff --git a/src/factorio/rcon.go b/src/factorio/rcon.go index 2b19ac2..ba8f8f7 100644 --- a/src/factorio/rcon.go +++ b/src/factorio/rcon.go @@ -12,7 +12,7 @@ func connectRC() error { var err error config := bootstrap.GetConfig() rconAddr := config.ServerIP + ":" + strconv.Itoa(config.FactorioRconPort) - server, err := GetFactorioServer() + server := GetFactorioServer() server.Rcon, err = rcon.Dial(rconAddr, config.FactorioRconPass) if err != nil { log.Printf("Cannot create rcon session: %s", err) diff --git a/src/factorio/server.go b/src/factorio/server.go index c72c0e9..889b698 100644 --- a/src/factorio/server.go +++ b/src/factorio/server.go @@ -59,141 +59,150 @@ func (f *Server) autostart() { } -func GetFactorioServer() (f Server, err error) { - once.Do(func() { - f = Server{} - f.Settings = make(map[string]interface{}) - config := bootstrap.GetConfig() - if err = os.MkdirAll(config.FactorioConfigDir, 0755); err != nil { - log.Printf("failed to create config directory: %v", err) +func SetFactorioServer(server Server) { + instantiated = server +} + +func NewFactorioServer() (err error) { + f := Server{} + f.Settings = make(map[string]interface{}) + config := bootstrap.GetConfig() + if err = os.MkdirAll(config.FactorioConfigDir, 0755); err != nil { + log.Printf("failed to create config directory: %v", err) + return + } + + settingsPath := filepath.Join(config.FactorioConfigDir, config.SettingsFile) + var settings *os.File + + if _, err = os.Stat(settingsPath); os.IsNotExist(err) { + // copy example settings to supplied settings file, if not exists + log.Printf("Server settings at %s not found, copying example server settings.\n", settingsPath) + + examplePath := filepath.Join(config.FactorioDir, "data", "server-settings.example.json") + + var example *os.File + example, err = os.Open(examplePath) + if err != nil { + log.Printf("failed to open example server settings: %v", err) + return + } + defer example.Close() + + settings, err = os.Create(settingsPath) + if err != nil { + log.Printf("failed to create server settings file: %v", err) + return + } + defer settings.Close() + + _, err = io.Copy(settings, example) + if err != nil { + log.Printf("failed to copy example server settings: %v", err) return } - settingsPath := filepath.Join(config.FactorioConfigDir, config.SettingsFile) - var settings *os.File + err = example.Close() + if err != nil { + log.Printf("failed to close example server settings: %s", err) + return + } + } else { + // otherwise, open file normally + settings, err = os.Open(settingsPath) + if err != nil { + log.Printf("failed to open server settings file: %v", err) + return + } + defer settings.Close() + } - if _, err := os.Stat(settingsPath); os.IsNotExist(err) { - // copy example settings to supplied settings file, if not exists - log.Printf("Server settings at %s not found, copying example server settings.\n", settingsPath) + // before reading reset offset + if _, err = settings.Seek(0, 0); err != nil { + log.Printf("error while seeking in settings file: %v", err) + return + } - examplePath := filepath.Join(config.FactorioDir, "data", "server-settings.example.json") + if err = json.NewDecoder(settings).Decode(&f.Settings); err != nil { + log.Printf("error reading %s: %v", settingsPath, err) + return + } - example, err := os.Open(examplePath) - if err != nil { - log.Printf("failed to open example server settings: %v", err) - return - } - defer example.Close() + log.Printf("Loaded Factorio settings from %s\n", settingsPath) - settings, err = os.Create(settingsPath) - if err != nil { - log.Printf("failed to create server settings file: %v", err) - return - } - defer settings.Close() + out := []byte{} + //Load factorio version + if config.GlibcCustom == "true" { + out, err = exec.Command(config.GlibcLocation, "--library-path", config.GlibcLibLoc, config.FactorioBinary, "--version").Output() + } else { + out, err = exec.Command(config.FactorioBinary, "--version").Output() + } - _, err = io.Copy(settings, example) - if err != nil { - log.Printf("failed to copy example server settings: %v", err) - return - } + if err != nil { + log.Printf("error on loading factorio version: %s", err) + return + } - err = example.Close() - if err != nil { - log.Printf("failed to close example server settings: %s", err) - return - } + reg := regexp.MustCompile("Version.*?((\\d+\\.)?(\\d+\\.)?(\\*|\\d+)+)") + found := reg.FindStringSubmatch(string(out)) + err = f.Version.UnmarshalText([]byte(found[1])) + if err != nil { + log.Printf("could not parse version: %v", err) + return + } + + //Load baseMod version + baseModInfoFile := filepath.Join(config.FactorioDir, "data", "base", "info.json") + bmifBa, err := ioutil.ReadFile(baseModInfoFile) + if err != nil { + log.Printf("couldn't open baseMods info.json: %s", err) + return + } + var modInfo ModInfo + err = json.Unmarshal(bmifBa, &modInfo) + if err != nil { + log.Printf("error unmarshalling baseMods info.json to a modInfo: %s", err) + return + } + + f.BaseModVersion = modInfo.Version + + // load admins from additional file + if (f.Version.Greater(Version{0, 17, 0})) { + if _, err = os.Stat(filepath.Join(config.FactorioConfigDir, config.FactorioAdminFile)); os.IsNotExist(err) { + //save empty admins-file + _ = ioutil.WriteFile(filepath.Join(config.FactorioConfigDir, config.FactorioAdminFile), []byte("[]"), 0664) } else { - // otherwise, open file normally - settings, err = os.Open(settingsPath) + var data []byte + data, err = ioutil.ReadFile(filepath.Join(config.FactorioConfigDir, config.FactorioAdminFile)) if err != nil { - log.Printf("failed to open server settings file: %v", err) + log.Printf("Error loading FactorioAdminFile: %s", err) return } - defer settings.Close() - } - // before reading reset offset - if _, err = settings.Seek(0, 0); err != nil { - log.Printf("error while seeking in settings file: %v", err) - return - } - - if err = json.NewDecoder(settings).Decode(&f.Settings); err != nil { - log.Printf("error reading %s: %v", settingsPath, err) - return - } - - log.Printf("Loaded Factorio settings from %s\n", settingsPath) - - out := []byte{} - //Load factorio version - if config.GlibcCustom == "true" { - out, err = exec.Command(config.GlibcLocation, "--library-path", config.GlibcLibLoc, config.FactorioBinary, "--version").Output() - } else { - out, err = exec.Command(config.FactorioBinary, "--version").Output() - } - - if err != nil { - log.Printf("error on loading factorio version: %s", err) - return - } - - reg := regexp.MustCompile("Version.*?((\\d+\\.)?(\\d+\\.)?(\\*|\\d+)+)") - found := reg.FindStringSubmatch(string(out)) - err = f.Version.UnmarshalText([]byte(found[1])) - if err != nil { - log.Printf("could not parse version: %v", err) - return - } - - //Load baseMod version - baseModInfoFile := filepath.Join(config.FactorioDir, "data", "base", "info.json") - bmifBa, err := ioutil.ReadFile(baseModInfoFile) - if err != nil { - log.Printf("couldn't open baseMods info.json: %s", err) - return - } - var modInfo ModInfo - err = json.Unmarshal(bmifBa, &modInfo) - if err != nil { - log.Printf("error unmarshalling baseMods info.json to a modInfo: %s", err) - return - } - - f.BaseModVersion = modInfo.Version - - // load admins from additional file - if (f.Version.Greater(Version{0, 17, 0})) { - if _, err := os.Stat(filepath.Join(config.FactorioConfigDir, config.FactorioAdminFile)); os.IsNotExist(err) { - //save empty admins-file - _ = ioutil.WriteFile(filepath.Join(config.FactorioConfigDir, config.FactorioAdminFile), []byte("[]"), 0664) - } else { - data, err := ioutil.ReadFile(filepath.Join(config.FactorioConfigDir, config.FactorioAdminFile)) - if err != nil { - log.Printf("Error loading FactorioAdminFile: %s", err) - return - } - - var jsonData interface{} - err = json.Unmarshal(data, &jsonData) - if err != nil { - log.Printf("Error unmarshalling FactorioAdminFile: %s", err) - return - } - - f.Settings["admins"] = jsonData + var jsonData interface{} + err = json.Unmarshal(data, &jsonData) + if err != nil { + log.Printf("Error unmarshalling FactorioAdminFile: %s", err) + return } + + f.Settings["admins"] = jsonData } + } - instantiated = f + SetFactorioServer(f) - if config.Autostart == "true" { - go instantiated.autostart() - } - }) + if config.Autostart == "true" { + go instantiated.autostart() + } - return instantiated, nil + return +} + +// todo refactor remove return value err +func GetFactorioServer() (f Server) { + return instantiated } func (f *Server) Run() error { diff --git a/src/go.mod b/src/go.mod index 14ecf34..a02d32a 100644 --- a/src/go.mod +++ b/src/go.mod @@ -11,6 +11,7 @@ require ( github.com/gorilla/websocket v1.4.1 github.com/hpcloud/tail v1.0.0 github.com/jessevdk/go-flags v1.4.0 + github.com/joho/godotenv v1.3.0 github.com/lib/pq v1.2.0 // indirect github.com/majormjr/rcon v0.0.0-20120923215419-8fbb8268b60a github.com/mattn/go-sqlite3 v1.11.0 // indirect diff --git a/src/go.sum b/src/go.sum index fa94276..b7a836e 100644 --- a/src/go.sum +++ b/src/go.sum @@ -28,6 +28,8 @@ github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= diff --git a/src/main.go b/src/main.go index d36544a..9ed1001 100644 --- a/src/main.go +++ b/src/main.go @@ -17,7 +17,7 @@ func main() { factorio.ModStartUp() // Initialize Factorio Server struct - _, err := factorio.GetFactorioServer() + err := factorio.NewFactorioServer() if err != nil { log.Printf("Error occurred during Server initializaion: %v\n", err) return