add docker specific columns to server table

This commit is contained in:
2026-03-18 19:15:19 +01:00
parent 747adc77a5
commit 4aa67db3fd
9 changed files with 163 additions and 10 deletions

0
local/migrations/001_upgrade_password_security.go Normal file → Executable file
View File

0
local/migrations/002_migrate_to_uuid.go Normal file → Executable file
View File

0
local/migrations/003_update_state_history_sessions.go Normal file → Executable file
View File

0
local/migrations/004_fix_ddl_comments.go Normal file → Executable file
View File

View File

@@ -0,0 +1,33 @@
package migrations
import (
"acc-server-manager/local/utl/logging"
"fmt"
"gorm.io/gorm"
)
func RunAddPlatformColumnsMigration(db *gorm.DB) error {
if err := db.AutoMigrate(&MigrationRecord{}); err != nil {
return fmt.Errorf("failed to ensure migration_records table: %v", err)
}
var record MigrationRecord
if err := db.Where("migration_name = ?", "005_add_platform_columns").First(&record).Error; err == nil {
logging.Info("Platform columns migration already applied, skipping")
return nil
}
record = MigrationRecord{
MigrationName: "005_add_platform_columns",
AppliedAt: "datetime('now')",
Success: true,
Notes: "Added Platform and ContainerID columns to servers table via GORM AutoMigrate",
}
if err := db.Create(&record).Error; err != nil {
return fmt.Errorf("failed to record migration 005: %v", err)
}
logging.Info("Platform columns migration recorded")
return nil
}

2
local/model/server.go Normal file → Executable file
View File

@@ -42,6 +42,8 @@ type Server struct {
Port int `gorm:"not null" json:"-"` Port int `gorm:"not null" json:"-"`
Path string `gorm:"not null" json:"path"` Path string `gorm:"not null" json:"path"`
ServiceName string `gorm:"not null" json:"serviceName"` ServiceName string `gorm:"not null" json:"serviceName"`
Platform string `gorm:"not null;default:'windows'" json:"platform"`
ContainerID string `gorm:"default:''" json:"-"`
State *ServerState `gorm:"-" json:"state"` State *ServerState `gorm:"-" json:"state"`
DateCreated time.Time `json:"dateCreated"` DateCreated time.Time `json:"dateCreated"`
FromSteamCMD bool `gorm:"not null; default:true" json:"-"` FromSteamCMD bool `gorm:"not null; default:true" json:"-"`

64
local/utl/env/env.go vendored Normal file → Executable file
View File

@@ -6,10 +6,26 @@ import (
) )
const ( const (
DefaultSteamCMDPath = "c:\\steamcmd\\steamcmd.exe" DefaultSteamCMDPath = "c:\\steamcmd\\steamcmd.exe"
DefaultNSSMPath = ".\\nssm.exe" DefaultNSSMPath = ".\\nssm.exe"
DefaultPlatform = "windows"
DefaultACCImage = "acc-wine:latest"
DefaultACCGameVolume = "/data/acc-game"
DefaultACCConfigBasePath = "/data/configs"
DefaultLinuxSteamCMDPath = "/usr/games/steamcmd"
) )
func GetPlatform() string {
if p := os.Getenv("PLATFORM"); p != "" {
return p
}
return DefaultPlatform
}
func IsDockerPlatform() bool {
return GetPlatform() == "docker"
}
func GetSteamCMDPath() string { func GetSteamCMDPath() string {
if path := os.Getenv("STEAMCMD_PATH"); path != "" { if path := os.Getenv("STEAMCMD_PATH"); path != "" {
return path return path
@@ -17,6 +33,13 @@ func GetSteamCMDPath() string {
return DefaultSteamCMDPath return DefaultSteamCMDPath
} }
func GetLinuxSteamCMDPath() string {
if path := os.Getenv("STEAMCMD_LINUX_PATH"); path != "" {
return path
}
return DefaultLinuxSteamCMDPath
}
func GetSteamCMDDirPath() string { func GetSteamCMDDirPath() string {
steamCMDPath := GetSteamCMDPath() steamCMDPath := GetSteamCMDPath()
return filepath.Dir(steamCMDPath) return filepath.Dir(steamCMDPath)
@@ -29,17 +52,40 @@ func GetNSSMPath() string {
return DefaultNSSMPath return DefaultNSSMPath
} }
func GetACCImage() string {
if img := os.Getenv("ACC_IMAGE"); img != "" {
return img
}
return DefaultACCImage
}
func GetACCGameVolume() string {
if v := os.Getenv("ACC_GAME_VOLUME"); v != "" {
return v
}
return DefaultACCGameVolume
}
func GetACCConfigBasePath() string {
if p := os.Getenv("ACC_CONFIG_BASE_PATH"); p != "" {
return p
}
return DefaultACCConfigBasePath
}
func ValidatePaths() map[string]error { func ValidatePaths() map[string]error {
errors := make(map[string]error) errors := make(map[string]error)
steamCMDPath := GetSteamCMDPath() if !IsDockerPlatform() {
if _, err := os.Stat(steamCMDPath); os.IsNotExist(err) { steamCMDPath := GetSteamCMDPath()
errors["STEAMCMD_PATH"] = err if _, err := os.Stat(steamCMDPath); os.IsNotExist(err) {
} errors["STEAMCMD_PATH"] = err
}
nssmPath := GetNSSMPath() nssmPath := GetNSSMPath()
if _, err := os.Stat(nssmPath); os.IsNotExist(err) { if _, err := os.Stat(nssmPath); os.IsNotExist(err) {
errors["NSSM_PATH"] = err errors["NSSM_PATH"] = err
}
} }
return errors return errors

View File

@@ -0,0 +1,72 @@
package network
import (
"context"
"fmt"
"os"
"strconv"
"sync"
"gorm.io/gorm"
)
const (
defaultPortPoolMin = 9600
defaultPortPoolMax = 9700
)
type PortPoolManager struct {
mu sync.Mutex
min int
max int
inUse map[int]struct{}
}
func NewPortPoolManager(db *gorm.DB) (*PortPoolManager, error) {
min := portEnvInt("PORT_POOL_MIN", defaultPortPoolMin)
max := portEnvInt("PORT_POOL_MAX", defaultPortPoolMax)
var ports []int
if err := db.Raw("SELECT port FROM servers WHERE platform = 'docker' AND port > 0").Scan(&ports).Error; err != nil {
return nil, fmt.Errorf("failed to seed port pool from database: %v", err)
}
inUse := make(map[int]struct{}, len(ports))
for _, p := range ports {
inUse[p] = struct{}{}
}
return &PortPoolManager{
min: min,
max: max,
inUse: inUse,
}, nil
}
func (p *PortPoolManager) Acquire(_ context.Context) (int, error) {
p.mu.Lock()
defer p.mu.Unlock()
for port := p.min; port <= p.max; port++ {
if _, used := p.inUse[port]; !used {
p.inUse[port] = struct{}{}
return port, nil
}
}
return 0, fmt.Errorf("no available ports in pool [%d-%d]", p.min, p.max)
}
func (p *PortPoolManager) Release(_ context.Context, port int) {
p.mu.Lock()
defer p.mu.Unlock()
delete(p.inUse, port)
}
func portEnvInt(key string, defaultVal int) int {
if v := os.Getenv(key); v != "" {
if n, err := strconv.Atoi(v); err == nil {
return n
}
}
return defaultVal
}

View File

@@ -44,7 +44,7 @@ func Start(di *dig.Container) *fiber.App {
app.Use(cors.New(cors.Config{ app.Use(cors.New(cors.Config{
AllowOrigins: allowedOrigin, AllowOrigins: allowedOrigin,
AllowHeaders: "Origin, Content-Type, Accept, Authorization, Access-Token", AllowHeaders: "Origin, Content-Type, Accept, Authorization, Access-Key",
AllowMethods: "GET, POST, PUT, DELETE, OPTIONS", AllowMethods: "GET, POST, PUT, DELETE, OPTIONS",
AllowCredentials: true, AllowCredentials: true,
MaxAge: 86400, // 24 hours MaxAge: 86400, // 24 hours