130 lines
3.4 KiB
Go
130 lines
3.4 KiB
Go
package model
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"path/filepath"
|
|
"sync"
|
|
"time"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
const (
|
|
BaseServerPath = "servers"
|
|
ServiceNamePrefix = "ACC-Server"
|
|
)
|
|
|
|
// Server represents an ACC server instance
|
|
type Server struct {
|
|
ID uint `gorm:"primaryKey" json:"id"`
|
|
Name string `gorm:"not null" json:"name"`
|
|
Status ServiceStatus `json:"status" gorm:"-"`
|
|
IP string `gorm:"not null" json:"-"`
|
|
Port int `gorm:"not null" json:"-"`
|
|
ConfigPath string `gorm:"not null" json:"configPath"` // e.g. "/acc/servers/server1/"
|
|
ServiceName string `gorm:"not null" json:"serviceName"` // Windows service name
|
|
State ServerState `gorm:"-" json:"state"`
|
|
DateCreated time.Time `json:"dateCreated"`
|
|
}
|
|
|
|
type PlayerState struct {
|
|
CarID int // Car ID in broadcast packets
|
|
DriverName string // Optional: pulled from registration packet
|
|
TeamName string
|
|
CarModel string
|
|
CurrentLap int
|
|
LastLapTime int // in milliseconds
|
|
BestLapTime int // in milliseconds
|
|
Position int
|
|
ConnectedAt time.Time
|
|
DisconnectedAt *time.Time
|
|
IsConnected bool
|
|
}
|
|
|
|
type State struct {
|
|
Session string `json:"session"`
|
|
SessionStart time.Time `json:"sessionStart"`
|
|
PlayerCount int `json:"playerCount"`
|
|
// Players map[int]*PlayerState
|
|
// etc.
|
|
}
|
|
|
|
type ServerState struct {
|
|
sync.RWMutex
|
|
Session string `json:"session"`
|
|
SessionStart time.Time `json:"sessionStart"`
|
|
PlayerCount int `json:"playerCount"`
|
|
Track string `json:"track"`
|
|
MaxConnections int `json:"maxConnections"`
|
|
SessionDurationMinutes int `json:"sessionDurationMinutes"`
|
|
// Players map[int]*PlayerState
|
|
// etc.
|
|
}
|
|
|
|
// ServerFilter defines filtering options for Server queries
|
|
type ServerFilter struct {
|
|
BaseFilter
|
|
ServerBasedFilter
|
|
Name string `query:"name"`
|
|
ServiceName string `query:"service_name"`
|
|
Status string `query:"status"`
|
|
}
|
|
|
|
// ApplyFilter implements the Filterable interface
|
|
func (f *ServerFilter) ApplyFilter(query *gorm.DB) *gorm.DB {
|
|
// Apply server filter
|
|
if f.ServerID != 0 {
|
|
query = query.Where("id = ?", f.ServerID)
|
|
}
|
|
|
|
return query
|
|
}
|
|
|
|
// BeforeCreate is a GORM hook that runs before creating a new server
|
|
func (s *Server) BeforeCreate(tx *gorm.DB) error {
|
|
if s.Name == "" {
|
|
return errors.New("server name is required")
|
|
}
|
|
|
|
// Generate service name and config path if not set
|
|
if s.ServiceName == "" {
|
|
s.ServiceName = s.GenerateServiceName()
|
|
}
|
|
if s.ConfigPath == "" {
|
|
s.ConfigPath = s.GenerateConfigPath()
|
|
}
|
|
|
|
// Set creation date if not set
|
|
if s.DateCreated.IsZero() {
|
|
s.DateCreated = time.Now().UTC()
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GenerateServiceName creates a unique service name based on the server name
|
|
func (s *Server) GenerateServiceName() string {
|
|
// If ID is set, use it
|
|
if s.ID > 0 {
|
|
return fmt.Sprintf("%s-%d", ServiceNamePrefix, s.ID)
|
|
}
|
|
// Otherwise use a timestamp-based unique identifier
|
|
return fmt.Sprintf("%s-%d", ServiceNamePrefix, time.Now().UnixNano())
|
|
}
|
|
|
|
// GenerateConfigPath creates the config path based on the service name
|
|
func (s *Server) GenerateConfigPath() string {
|
|
// Ensure service name is set
|
|
if s.ServiceName == "" {
|
|
s.ServiceName = s.GenerateServiceName()
|
|
}
|
|
return filepath.Join(BaseServerPath, s.ServiceName)
|
|
}
|
|
|
|
func (s *Server) Validate() error {
|
|
if s.Name == "" {
|
|
return errors.New("server name is required")
|
|
}
|
|
return nil
|
|
} |