add docker specific columns to server table
This commit is contained in:
0
local/migrations/001_upgrade_password_security.go
Normal file → Executable file
0
local/migrations/001_upgrade_password_security.go
Normal file → Executable file
0
local/migrations/002_migrate_to_uuid.go
Normal file → Executable file
0
local/migrations/002_migrate_to_uuid.go
Normal file → Executable file
0
local/migrations/003_update_state_history_sessions.go
Normal file → Executable file
0
local/migrations/003_update_state_history_sessions.go
Normal file → Executable file
0
local/migrations/004_fix_ddl_comments.go
Normal file → Executable file
0
local/migrations/004_fix_ddl_comments.go
Normal file → Executable file
33
local/migrations/005_add_platform_columns.go
Normal file
33
local/migrations/005_add_platform_columns.go
Normal 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
2
local/model/server.go
Normal file → Executable 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:"-"`
|
||||||
|
|||||||
46
local/utl/env/env.go
vendored
Normal file → Executable file
46
local/utl/env/env.go
vendored
Normal file → Executable file
@@ -8,8 +8,24 @@ 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,9 +52,31 @@ 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)
|
||||||
|
|
||||||
|
if !IsDockerPlatform() {
|
||||||
steamCMDPath := GetSteamCMDPath()
|
steamCMDPath := GetSteamCMDPath()
|
||||||
if _, err := os.Stat(steamCMDPath); os.IsNotExist(err) {
|
if _, err := os.Stat(steamCMDPath); os.IsNotExist(err) {
|
||||||
errors["STEAMCMD_PATH"] = err
|
errors["STEAMCMD_PATH"] = err
|
||||||
@@ -41,6 +86,7 @@ func ValidatePaths() map[string]error {
|
|||||||
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
|
||||||
}
|
}
|
||||||
|
|||||||
72
local/utl/network/port_pool.go
Normal file
72
local/utl/network/port_pool.go
Normal 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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user