diff --git a/UIMod/onboard_bundled/twoboxform/twoboxform.css b/UIMod/onboard_bundled/twoboxform/twoboxform.css index 5a5d7795..5d505a44 100644 --- a/UIMod/onboard_bundled/twoboxform/twoboxform.css +++ b/UIMod/onboard_bundled/twoboxform/twoboxform.css @@ -489,11 +489,6 @@ footer { display: none !important; } } -@media (max-height: 1050px) { - .progress-bar { - display: none !important; - } -} .progress-bar { display: flex; diff --git a/src/cli/runtimecommands.go b/src/cli/runtimecommands.go index f495a287..9207d780 100644 --- a/src/cli/runtimecommands.go +++ b/src/cli/runtimecommands.go @@ -161,6 +161,7 @@ func init() { RegisterCommand("supportmode", WrapNoReturn(supportMode), "sm") RegisterCommand("supportpackage", WrapNoReturn(supportPackage), "sp") RegisterCommand("getbuildid", WrapNoReturn(getBuildID), "gbid") + RegisterCommand("setdummybuildid", WrapNoReturn(setDummyBuildID), "sdbid") RegisterCommand("printconfig", WrapNoReturn(printConfig), "pc") } @@ -209,6 +210,11 @@ func getBuildID() { logger.Core.Info("Build ID: " + buildID) } +func setDummyBuildID() { + config.SetCurrentBranchBuildID("dummy") + logger.Core.Info("Dummy build ID set") +} + func testLocalization() { currentLanguageSetting := config.GetLanguageSetting() s := localization.GetString("UIText_StartButton") diff --git a/src/core/loader/loader.go b/src/core/loader/loader.go index 78e1a1e6..72830a12 100644 --- a/src/core/loader/loader.go +++ b/src/core/loader/loader.go @@ -13,6 +13,7 @@ import ( "github.com/JacksonTheMaster/StationeersServerUI/v5/src/managers/detectionmgr" "github.com/JacksonTheMaster/StationeersServerUI/v5/src/setup" "github.com/JacksonTheMaster/StationeersServerUI/v5/src/setup/update" + "github.com/JacksonTheMaster/StationeersServerUI/v5/src/steamcmd" ) // only call this once at startup @@ -23,6 +24,7 @@ func InitBackend(wg *sync.WaitGroup) { ReloadSSCM() ReloadBackupManager() ReloadLocalizer() + ReloadAppInfoPoller() ReloadDiscordBot() InitDetector() } @@ -35,6 +37,7 @@ func ReloadBackend() { ReloadSSCM() ReloadBackupManager() ReloadLocalizer() + ReloadAppInfoPoller() PrintConfigDetails() logger.Core.Info("Backend reload done!") } @@ -87,6 +90,10 @@ func ReloadLocalizer() { localization.ReloadLocalizer() } +func ReloadAppInfoPoller() { + steamcmd.AppInfoPoller() +} + // InitBundler initialized the onboard bundled assets for the web UI func InitVirtFS(v1uiFS embed.FS) { config.SetV1UIFS(v1uiFS) diff --git a/src/steamcmd/getappinfo.go b/src/steamcmd/getappinfo.go index d693693d..0d592c7d 100644 --- a/src/steamcmd/getappinfo.go +++ b/src/steamcmd/getappinfo.go @@ -64,6 +64,17 @@ func AppInfoPoller() { // getAppInfo fetches the branches and their build IDs for the specified app ID using SteamCMD // and stores them in the package-level branches map. func getAppInfo() error { + if steamMu.TryLock() { + // Successfully acquired the lock; no other func holds it + logger.Core.Debug("🔄 Locking SteamMu for SteamCMD AppInfo...") + } else { + // Another goroutine holds the lock; log and wait. + logger.Core.Warn("🔄 SteamMu is currently locked, waiting for it to be unlocked and then continuing...") + steamMu.Lock() // Block until steamMu becomes available, then snack it and lock it again + logger.Core.Debug("🔄 Locking SteamMu for SteamCMD AppInfo...") + } + defer steamMu.Unlock() + defer logger.Core.Debug("🔄 Unlocking SteamMu after SteamCMD AppInfo...") steamcmddir := SteamCMDLinuxDir executable := "steamcmd.sh" appid := config.GetGameServerAppID() @@ -109,7 +120,7 @@ func getAppInfo() error { branchesLock.Lock() maps.Copy(branches, newBranches) branchesLock.Unlock() - + wasRunning := false currentBranch := config.GetGameBranch() if buildID, ok := branches[currentBranch]; ok { if config.GetCurrentBranchBuildID() != "" && config.GetCurrentBranchBuildID() != buildID { @@ -133,12 +144,15 @@ func getAppInfo() error { commandmgr.WriteCommand("say Update found, stopping server in 10 seconds...") time.Sleep(10 * time.Second) gamemgr.InternalStopServer() + wasRunning = true } _, err := InstallAndRunSteamCMD() if err != nil { logger.Install.Error("❌ Failed to update gameserver: " + err.Error() + "\n") } - gamemgr.InternalStartServer() + if wasRunning { + gamemgr.InternalStartServer() + } } } config.SetCurrentBranchBuildID(buildID) diff --git a/src/steamcmd/steamcmd.go b/src/steamcmd/steamcmd.go index e6dbb0fc..292ed1ce 100644 --- a/src/steamcmd/steamcmd.go +++ b/src/steamcmd/steamcmd.go @@ -8,6 +8,7 @@ import ( "path/filepath" "runtime" "strings" + "sync" "github.com/JacksonTheMaster/StationeersServerUI/v5/src/logger" "github.com/JacksonTheMaster/StationeersServerUI/v5/src/managers/gamemgr" @@ -15,6 +16,9 @@ import ( "github.com/JacksonTheMaster/StationeersServerUI/v5/src/config" ) +var steamMu sync.Mutex +var isUpdatingMu sync.Mutex + // ExtractorFunc is a type that represents a function for extracting archives. // It takes an io.ReaderAt, the size of the content, and the destination directory. type ExtractorFunc func(io.ReaderAt, int64, string) error @@ -30,6 +34,16 @@ const ( // InstallAndRunSteamCMD installs and runs SteamCMD based on the platform (Windows/Linux). // It returns the exit status of the SteamCMD execution and any error encountered. func InstallAndRunSteamCMD() (int, error) { + if isUpdatingMu.TryLock() { + // Successfully acquired the lock; we are not updating currently + logger.Core.Debug("🔄 Locking isUpdatingMu for SteamCMD Update run...") + } else { + // already updating, return + logger.Core.Warn("🔄 isUpdatingMu is currently locked, cannot update server using SteamCMD right now...") + return -1, fmt.Errorf("already updating") + } + defer isUpdatingMu.Unlock() + defer logger.Core.Debug("🔄 Unlocking isUpdatingMu after SteamCMD Update run...") if gamemgr.InternalIsServerRunning() { logger.Core.Warn("Server is running, stopping server first...") @@ -54,6 +68,17 @@ func InstallAndRunSteamCMD() (int, error) { // runSteamCMD runs the SteamCMD command to update the game and returns its exit status and any error. func runSteamCMD(steamCMDDir string) (int, error) { + if steamMu.TryLock() { + // Successfully acquired the lock; no other func holds it + logger.Core.Debug("🔄 Locking SteamMu for SteamCMD execution...") + } else { + // Another goroutine holds the lock; log and wait. + logger.Core.Warn("🔄 SteamMu is currently locked, waiting for it to be unlocked and then continuing...") + steamMu.Lock() // Block until steamMu becomes available, then snack it and lock it again + logger.Core.Debug("🔄 Locking SteamMu for SteamCMD execution..") + } + defer steamMu.Unlock() + defer logger.Core.Debug("🔄 Unlocking SteamMu after SteamCMD execution...") currentDir, err := os.Getwd() if err != nil { logger.Install.Error("❌ Error getting current working directory: " + err.Error() + "\n") @@ -99,7 +124,7 @@ func runSteamCMD(steamCMDDir string) (int, error) { // buildSteamCMDCommand constructs the SteamCMD command based on the OS. func buildSteamCMDCommand(steamCMDDir, currentDir string) *exec.Cmd { //print the config.GameBranch and config.GameServerAppID - logger.Install.Info("🔍 Game Branch: " + config.GetBranch()) + logger.Install.Info("🔍 Game Branch: " + config.GetGameBranch()) logger.Install.Debug("🔍 Game Server App ID: " + config.GetGameServerAppID()) if runtime.GOOS == "windows" { diff --git a/src/web/http.go b/src/web/http.go index 5f99f9fe..fd010f65 100644 --- a/src/web/http.go +++ b/src/web/http.go @@ -7,7 +7,6 @@ import ( "net/http" "os" "strings" - "time" "github.com/JacksonTheMaster/StationeersServerUI/v5/src/config" "github.com/JacksonTheMaster/StationeersServerUI/v5/src/localization" @@ -118,12 +117,9 @@ func HandleIsSSCMEnabled(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) } -var lastSteamCMDExecution time.Time // last time SteamCMD was executed via API. - // run SteamCMD from API, but only allow once every 5 minutes to "kinda" prevent concurrent executions although that woluldnt hurn. // If the user has a 5mbit connection, I cannot help them anyways. func HandleRunSteamCMD(w http.ResponseWriter, r *http.Request) { - const rateLimitDuration = 30 * time.Second // Only allow GET requests if r.Method != http.MethodGet { @@ -131,17 +127,10 @@ func HandleRunSteamCMD(w http.ResponseWriter, r *http.Request) { return } - // Check rate limit - if time.Since(lastSteamCMDExecution) < rateLimitDuration { - json.NewEncoder(w).Encode(map[string]string{"statuscode": "200", "status": "Rejected", "message": "Slow down, you just called SteamCMD.", "advanced": "Use SSUICLI or restart SSUI to run SteamCMD repeatedly without limit."}) - return - } - logger.Core.Info("Running SteamCMD") _, err := steamcmd.InstallAndRunSteamCMD() // Update last execution time - lastSteamCMDExecution = time.Now() // Success: return 202 Accepted and JSON w.WriteHeader(http.StatusOK)