fix(backend): replace mutex with atomic state machine in ProcessManager and SteamCmdManager
- ProcessManager: atomic.Int32 state enum (idle/starting/running/stopping) eliminates race between IsRunning check and Start/Stop - SteamCmdManager: atomic.Bool with CompareAndSwap for same protection - Restart() now propagates Stop() errors instead of swallowing them
This commit is contained in:
@@ -6,7 +6,7 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -24,9 +24,8 @@ const arma3AppID = "233780"
|
||||
type SteamCmdManager struct {
|
||||
serverfileDir string
|
||||
streamer *LogStreamer
|
||||
mu sync.Mutex
|
||||
running atomic.Bool
|
||||
cancel context.CancelFunc
|
||||
running bool
|
||||
}
|
||||
|
||||
func NewSteamCmdManager(serverfileDir string, streamer *LogStreamer) *SteamCmdManager {
|
||||
@@ -37,18 +36,13 @@ func NewSteamCmdManager(serverfileDir string, streamer *LogStreamer) *SteamCmdMa
|
||||
}
|
||||
|
||||
func (s *SteamCmdManager) IsRunning() bool {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return s.running
|
||||
return s.running.Load()
|
||||
}
|
||||
|
||||
func (s *SteamCmdManager) UpdateGame(branch, user string) error {
|
||||
s.mu.Lock()
|
||||
if s.running {
|
||||
s.mu.Unlock()
|
||||
if !s.running.CompareAndSwap(false, true) {
|
||||
return fmt.Errorf("steamcmd already running")
|
||||
}
|
||||
s.mu.Unlock()
|
||||
|
||||
args := []string{
|
||||
"+force_install_dir", s.serverfileDir,
|
||||
@@ -68,12 +62,9 @@ func (s *SteamCmdManager) DownloadMod(modID string) error {
|
||||
}
|
||||
|
||||
func (s *SteamCmdManager) DownloadMods(modIDs []string) error {
|
||||
s.mu.Lock()
|
||||
if s.running {
|
||||
s.mu.Unlock()
|
||||
if !s.running.CompareAndSwap(false, true) {
|
||||
return fmt.Errorf("steamcmd already running")
|
||||
}
|
||||
s.mu.Unlock()
|
||||
|
||||
if len(modIDs) == 0 {
|
||||
return fmt.Errorf("no mod ids provided")
|
||||
@@ -104,33 +95,31 @@ func (s *SteamCmdManager) run(label string, args []string) error {
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
cancel()
|
||||
s.running.Store(false)
|
||||
return fmt.Errorf("stdout pipe: %w", err)
|
||||
}
|
||||
stderr, err := cmd.StderrPipe()
|
||||
if err != nil {
|
||||
cancel()
|
||||
s.running.Store(false)
|
||||
return fmt.Errorf("stderr pipe: %w", err)
|
||||
}
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
cancel()
|
||||
s.running.Store(false)
|
||||
return fmt.Errorf("start steamcmd: %w", err)
|
||||
}
|
||||
|
||||
s.mu.Lock()
|
||||
s.running = true
|
||||
s.cancel = cancel
|
||||
s.mu.Unlock()
|
||||
|
||||
go s.streamer.Stream("steamcmd", stdout, "")
|
||||
go s.streamer.Stream("steamcmd", stderr, "")
|
||||
|
||||
go func() {
|
||||
err := cmd.Wait()
|
||||
s.mu.Lock()
|
||||
s.running = false
|
||||
s.running.Store(false)
|
||||
s.cancel = nil
|
||||
s.mu.Unlock()
|
||||
if err == nil {
|
||||
s.streamer.Broadcast("steamcmd", "[STEAMCMD] SUCCESS: "+label+" finished")
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user