zlh-agent/internal/state/state.go
2025-12-13 20:54:18 +00:00

174 lines
4.0 KiB
Go
Executable File

package state
import (
"encoding/json"
"log"
"os"
"sync"
"time"
)
/* --------------------------------------------------------------------------
CONFIG STRUCT
----------------------------------------------------------------------------*/
type Config struct {
VMID int `json:"vmid"`
Game string `json:"game"`
Variant string `json:"variant"`
Version string `json:"version"`
World string `json:"world"`
Ports []int `json:"ports"`
ArtifactPath string `json:"artifact_path"`
JavaPath string `json:"java_path"`
MemoryMB int `json:"memory_mb"`
// Steam + admin credentials
SteamUser string `json:"steam_user,omitempty"`
SteamPass string `json:"steam_pass,omitempty"`
SteamAuth string `json:"steam_auth,omitempty"`
AdminUser string `json:"admin_user,omitempty"`
AdminPass string `json:"admin_pass,omitempty"`
}
/* --------------------------------------------------------------------------
AGENT STATE ENUM
----------------------------------------------------------------------------*/
type AgentState string
const (
StateIdle AgentState = "idle"
StateInstalling AgentState = "installing"
StateStarting AgentState = "starting"
StateRunning AgentState = "running"
StateStopping AgentState = "stopping"
StateCrashed AgentState = "crashed"
StateError AgentState = "error"
)
/* --------------------------------------------------------------------------
GLOBAL STATE STRUCT
----------------------------------------------------------------------------*/
type agentStatus struct {
mu sync.Mutex
state AgentState
lastChange time.Time
installStep string
lastError error
crashCount int
lastCrash time.Time
}
var global = &agentStatus{
state: StateIdle,
lastChange: time.Now(),
}
/* --------------------------------------------------------------------------
STATE GETTERS
----------------------------------------------------------------------------*/
func GetState() AgentState {
global.mu.Lock()
defer global.mu.Unlock()
return global.state
}
func GetInstallStep() string {
global.mu.Lock()
defer global.mu.Unlock()
return global.installStep
}
func GetError() error {
global.mu.Lock()
defer global.mu.Unlock()
return global.lastError
}
func GetCrashCount() int {
global.mu.Lock()
defer global.mu.Unlock()
return global.crashCount
}
func GetLastChange() time.Time {
global.mu.Lock()
defer global.mu.Unlock()
return global.lastChange
}
/* --------------------------------------------------------------------------
STATE SETTERS — unified with logging
----------------------------------------------------------------------------*/
func SetState(s AgentState) {
global.mu.Lock()
defer global.mu.Unlock()
if global.state != s {
log.Printf("[state] %s → %s\n", global.state, s)
global.state = s
global.lastChange = time.Now()
}
}
func SetInstallStep(step string) {
global.mu.Lock()
defer global.mu.Unlock()
global.installStep = step
}
func SetError(err error) {
global.mu.Lock()
defer global.mu.Unlock()
global.lastError = err
}
func RecordCrash(err error) {
global.mu.Lock()
defer global.mu.Unlock()
log.Printf("[state] crash detected: %v", err)
global.state = StateCrashed
global.lastError = err
global.crashCount++
global.lastCrash = time.Now()
}
/* --------------------------------------------------------------------------
CONFIG SAVE / LOAD
----------------------------------------------------------------------------*/
const configPath = "/opt/zlh-agent/config/payload.json"
func SaveConfig(cfg *Config) error {
if err := os.MkdirAll("/opt/zlh-agent/config", 0o755); err != nil {
return err
}
b, err := json.MarshalIndent(cfg, "", " ")
if err != nil {
return err
}
return os.WriteFile(configPath, b, 0o644)
}
func LoadConfig() (*Config, error) {
b, err := os.ReadFile(configPath)
if err != nil {
return nil, err
}
var cfg Config
if err := json.Unmarshal(b, &cfg); err != nil {
return nil, err
}
return &cfg, nil
}