From f78a9a4005885b8078d46bda70a0d7719b80ad33 Mon Sep 17 00:00:00 2001 From: knox Date: Thu, 11 Jul 2024 22:21:14 +0200 Subject: [PATCH] - remove Load Latest from save overviews (except under Controls) - add actual latest save to Load Latest - disable Controls and Load Mods from Save when no save is present --- src/api/handlers.go | 34 ++++++++++++++++++++--- src/bootstrap/user.go | 6 ++-- src/factorio/save.go | 2 +- src/factorio/saves.go | 31 +++++++++++++++++---- src/factorio/server.go | 8 +++--- ui/App/components/Select.jsx | 11 ++++++-- ui/App/views/Controls.jsx | 25 +++++++++++------ ui/App/views/Mods/components/LoadMods.jsx | 10 +++++-- ui/App/views/Saves/Saves.jsx | 16 +++++------ ui/api/resources/saves.js | 8 ++++-- 10 files changed, 110 insertions(+), 41 deletions(-) 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 (
@@ -90,6 +94,7 @@ const Controls = ({serverStatus}) => { type="number" min={1} defaultValue={"34197"} + disabled={isDisabled} register={register('port',{required: true})} /> @@ -103,12 +108,14 @@ const Controls = ({serverStatus}) => {
new Object({ name: save.name, value: save.name }))} /> - + ) } diff --git a/ui/App/views/Saves/Saves.jsx b/ui/App/views/Saves/Saves.jsx index 04cde049..fa8adeb1 100644 --- a/ui/App/views/Saves/Saves.jsx +++ b/ui/App/views/Saves/Saves.jsx @@ -74,15 +74,13 @@ const Saves = ({serverStatus}) => { {(new Date(save.last_mod)).toLocaleString()} {parseFloat(save.size / 1024 / 1024).toFixed(3)} MB - { save.name !== 'Load Latest' && <> - - - - deleteSave(save)} icon={faTrashAlt}/> - } + + + + deleteSave(save)} icon={faTrashAlt}/> )} diff --git a/ui/api/resources/saves.js b/ui/api/resources/saves.js index d0cd79f8..9d05f54c 100644 --- a/ui/api/resources/saves.js +++ b/ui/api/resources/saves.js @@ -1,8 +1,12 @@ import client from "../client"; export default { - list: async () => { - const response = await client.get('/api/saves/list'); + list: async (latest) => { + const response = await client.get('/api/saves/list', { + params: { + latest + } + }); return response.data; }, delete: async (save) => {