diff --git a/src/api/handlers.go b/src/api/handlers.go index 65d3d82c..053430c7 100644 --- a/src/api/handlers.go +++ b/src/api/handlers.go @@ -10,6 +10,7 @@ import ( "net/http" "os" "path/filepath" + "strconv" "sync" "time" @@ -84,14 +85,28 @@ func SaveSession(w http.ResponseWriter, r *http.Request, session *sessions.Sessi // Lists all save files in the factorio/saves directory func ListSaves(w http.ResponseWriter, r *http.Request) { var resp interface{} - config := bootstrap.GetConfig() defer func() { WriteResponse(w, resp) }() w.Header().Set("Content-Type", "application/json;charset=UTF-8") - savesList, err := factorio.ListSaves(config.FactorioSavesDir) + latestParam := r.URL.Query().Get("latest") + + var withLatest bool + + if latestParam != "" { + var err error + withLatest, err = strconv.ParseBool(latestParam) + if err != nil { + resp = fmt.Sprintf("Error parsing latestParam: %s", err) + log.Println(resp) + w.WriteHeader(http.StatusBadRequest) + return + } + } + + savesList, err := factorio.ListSaves() if err != nil { resp = fmt.Sprintf("Error listing save files: %s", err) log.Println(resp) @@ -99,8 +114,19 @@ func ListSaves(w http.ResponseWriter, r *http.Request) { return } - loadLatest := factorio.Save{Name: "Load Latest"} - savesList = append(savesList, loadLatest) + // get actual latest and add name + // but only if requested + if withLatest && len(savesList) != 0 { + latestSave, err := factorio.GetLatestSave() + if err != nil { + resp = fmt.Sprintf("Error getting latest save: %s", err) + log.Println(resp) + w.WriteHeader(http.StatusInternalServerError) + return + } + latestSave.Name = fmt.Sprintf("Load Latest (%s)", latestSave.Name) + savesList = append(savesList, latestSave) + } resp = savesList } diff --git a/src/bootstrap/user.go b/src/bootstrap/user.go index 07c8ff19..01a76a54 100644 --- a/src/bootstrap/user.go +++ b/src/bootstrap/user.go @@ -14,9 +14,9 @@ import ( type User struct { gorm.Model - Username string `json:"username",gorm:"uniqueIndex,not null"` - Password string `json:"password",gorm:"not null"` - Role string `json:"role",gorm:"not null"` + Username string `json:"username" gorm:"uniqueIndex,not null"` + Password string `json:"password" gorm:"not null"` + Role string `json:"role" gorm:"not null"` Email string `json:"email"` } diff --git a/src/factorio/save.go b/src/factorio/save.go index a97cd6e3..3d37b0f4 100644 --- a/src/factorio/save.go +++ b/src/factorio/save.go @@ -293,7 +293,7 @@ func readString(r io.Reader, game Version, forceOptimized bool) (s string, err e return string(d), nil } -func (h SaveHeader) readStats(r io.Reader) (stats map[byte][]map[uint16]uint32, err error) { +func (h *SaveHeader) readStats(r io.Reader) (stats map[byte][]map[uint16]uint32, err error) { var scratch [4]byte stats = make(map[byte][]map[uint16]uint32) diff --git a/src/factorio/saves.go b/src/factorio/saves.go index f4e31b2f..16bf300f 100644 --- a/src/factorio/saves.go +++ b/src/factorio/saves.go @@ -18,14 +18,15 @@ type Save struct { Size int64 `json:"size"` } -func (s Save) String() string { +func (s *Save) String() string { return s.Name } // Lists save files in factorio/saves -func ListSaves(saveDir string) (saves []Save, err error) { +func ListSaves() (saves []Save, err error) { + config := bootstrap.GetConfig() saves = []Save{} - err = filepath.Walk(saveDir, func(path string, info os.FileInfo, err error) error { + err = filepath.Walk(config.FactorioSavesDir, func(path string, info os.FileInfo, err error) error { if info == nil || (info.IsDir() && info.Name() == "saves") { return nil } @@ -40,8 +41,7 @@ func ListSaves(saveDir string) (saves []Save, err error) { } func FindSave(name string) (*Save, error) { - config := bootstrap.GetConfig() - saves, err := ListSaves(config.FactorioSavesDir) + saves, err := ListSaves() if err != nil { return nil, fmt.Errorf("error listing saves: %v", err) } @@ -84,3 +84,24 @@ func CreateSave(filePath string) (string, error) { return result, nil } + +func GetLatestSave() (save Save, err error) { + config := bootstrap.GetConfig() + + err = filepath.Walk(config.FactorioSavesDir, func(path string, info os.FileInfo, err error) error { + if info == nil || (info.IsDir() && info.Name() == "saves") { + return nil + } + + if save.LastMod.Before(info.ModTime()) { + save = Save{ + Name: info.Name(), + LastMod: info.ModTime(), + Size: info.Size(), + } + } + return nil + }) + + return +} diff --git a/src/factorio/server.go b/src/factorio/server.go index a6423b82..a8a80d97 100644 --- a/src/factorio/server.go +++ b/src/factorio/server.go @@ -231,7 +231,7 @@ func (server *Server) Run() error { ioutil.WriteFile(config.SettingsFile, data, 0644) } - saves, err := ListSaves(config.FactorioSavesDir) + saves, err := ListSaves() if err != nil { log.Println("Failed to get saves list: ", err) } @@ -260,12 +260,12 @@ func (server *Server) Run() error { args = append(args, "--server-adminlist", config.FactorioAdminFile) } - if server.Savefile == "Load Latest" { + if strings.HasPrefix(server.Savefile, "Load Latest") { args = append(args, "--start-server-load-latest") } else { args = append(args, "--start-server", filepath.Join(config.FactorioSavesDir, server.Savefile)) } - + // Write chat log to a different file if requested (if not it will be mixed-in with the default logfile) if config.ChatLogFile != "" { args = append(args, "--console-log", config.ChatLogFile) @@ -278,7 +278,7 @@ func (server *Server) Run() error { log.Println("Starting server with command: ", config.FactorioBinary, args) server.Cmd = exec.Command(config.FactorioBinary, args...) } - + server.StdOut, err = server.Cmd.StdoutPipe() if err != nil { log.Printf("Error opening stdout pipe: %s", err) diff --git a/ui/App/components/Select.jsx b/ui/App/components/Select.jsx index 941407d9..f3de0573 100644 --- a/ui/App/components/Select.jsx +++ b/ui/App/components/Select.jsx @@ -1,15 +1,22 @@ -import React, {useState} from "react"; +import React, {useEffect, useState} from "react"; -const Select = ({register, options, className = "", defaultValue = ""}) => { +const Select = ({register, options, className = "", defaultValue = "", disabled = undefined}) => { const [value, setValue] = useState(defaultValue); + useEffect(() => { + if (value === "") { + setValue(defaultValue) + } + }); + return (