209 lines
5.1 KiB
Go
209 lines
5.1 KiB
Go
package main
|
|
|
|
import (
|
|
"eq2emu/internal/udp"
|
|
"fmt"
|
|
"log"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// LoginServer manages the main login server functionality
|
|
type LoginServer struct {
|
|
config *Config
|
|
server *udp.Server
|
|
database *Database
|
|
worldList *WorldList
|
|
webServer *WebServer
|
|
clients map[string]*LoginClient
|
|
clientMutex sync.RWMutex
|
|
|
|
// Statistics
|
|
stats struct {
|
|
ConnectionCount int32
|
|
LoginAttempts int32
|
|
SuccessfulLogins int32
|
|
StartTime time.Time
|
|
}
|
|
}
|
|
|
|
// NewLoginServer creates a new login server instance
|
|
func NewLoginServer(config *Config) (*LoginServer, error) {
|
|
ls := &LoginServer{
|
|
config: config,
|
|
clients: make(map[string]*LoginClient),
|
|
}
|
|
|
|
ls.stats.StartTime = time.Now()
|
|
|
|
// Initialize database
|
|
db, err := NewDatabase(config.Database)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("database initialization failed: %w", err)
|
|
}
|
|
ls.database = db
|
|
|
|
// Initialize world list
|
|
ls.worldList = NewWorldList(db)
|
|
|
|
// Create UDP server with login packet handler
|
|
udpConfig := udp.DefaultConfig()
|
|
udpConfig.MaxConnections = config.MaxConnections
|
|
udpConfig.Timeout = time.Duration(config.TimeoutSeconds) * time.Second
|
|
udpConfig.EnableCompression = config.EnableCompression
|
|
udpConfig.EnableEncryption = config.EnableEncryption
|
|
|
|
server, err := udp.NewServer(fmt.Sprintf(":%d", config.Port), ls.handlePacket, udpConfig)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("UDP server creation failed: %w", err)
|
|
}
|
|
ls.server = server
|
|
|
|
// Initialize web server if configured
|
|
if config.WebServer.Enabled {
|
|
webServer, err := NewWebServer(config.WebServer, ls)
|
|
if err != nil {
|
|
log.Printf("Web server initialization failed: %v", err)
|
|
} else {
|
|
ls.webServer = webServer
|
|
}
|
|
}
|
|
|
|
return ls, nil
|
|
}
|
|
|
|
// Start begins accepting connections and processing packets
|
|
func (ls *LoginServer) Start() error {
|
|
log.Println("Starting login server components...")
|
|
|
|
// Start world list monitoring
|
|
go ls.worldList.Start()
|
|
|
|
// Start web server if configured
|
|
if ls.webServer != nil {
|
|
go ls.webServer.Start()
|
|
}
|
|
|
|
// Start UDP server
|
|
return ls.server.Start()
|
|
}
|
|
|
|
// Stop gracefully shuts down the server
|
|
func (ls *LoginServer) Stop() {
|
|
log.Println("Stopping login server...")
|
|
|
|
if ls.webServer != nil {
|
|
ls.webServer.Stop()
|
|
}
|
|
|
|
ls.worldList.Stop()
|
|
ls.server.Stop()
|
|
ls.database.Close()
|
|
}
|
|
|
|
// handlePacket processes incoming packets from clients
|
|
func (ls *LoginServer) handlePacket(conn *udp.Connection, packet *udp.ApplicationPacket) {
|
|
clientKey := conn.GetSessionID()
|
|
|
|
// Get or create client
|
|
ls.clientMutex.Lock()
|
|
client, exists := ls.clients[fmt.Sprintf("%d", clientKey)]
|
|
if !exists {
|
|
client = NewLoginClient(conn, ls)
|
|
ls.clients[fmt.Sprintf("%d", clientKey)] = client
|
|
}
|
|
ls.clientMutex.Unlock()
|
|
|
|
// Process packet
|
|
client.ProcessPacket(packet)
|
|
}
|
|
|
|
// RemoveClient removes a client from the active clients list
|
|
func (ls *LoginServer) RemoveClient(sessionID string) {
|
|
ls.clientMutex.Lock()
|
|
delete(ls.clients, sessionID)
|
|
ls.clientMutex.Unlock()
|
|
}
|
|
|
|
// UpdateStats updates server statistics
|
|
func (ls *LoginServer) UpdateStats() {
|
|
ls.clientMutex.RLock()
|
|
ls.stats.ConnectionCount = int32(len(ls.clients))
|
|
ls.clientMutex.RUnlock()
|
|
|
|
// Update world server statistics
|
|
ls.worldList.UpdateStats()
|
|
|
|
// Clean up old database entries
|
|
ls.database.CleanupOldEntries()
|
|
|
|
log.Printf("Stats: %d connections, %d login attempts, %d successful logins",
|
|
ls.stats.ConnectionCount, ls.stats.LoginAttempts, ls.stats.SuccessfulLogins)
|
|
}
|
|
|
|
// CleanupStaleConnections removes inactive connections
|
|
func (ls *LoginServer) CleanupStaleConnections() {
|
|
var staleClients []string
|
|
|
|
ls.clientMutex.RLock()
|
|
for sessionID, client := range ls.clients {
|
|
if client.IsStale() {
|
|
staleClients = append(staleClients, sessionID)
|
|
}
|
|
}
|
|
ls.clientMutex.RUnlock()
|
|
|
|
ls.clientMutex.Lock()
|
|
for _, sessionID := range staleClients {
|
|
if client, exists := ls.clients[sessionID]; exists {
|
|
client.Disconnect()
|
|
delete(ls.clients, sessionID)
|
|
}
|
|
}
|
|
ls.clientMutex.Unlock()
|
|
|
|
if len(staleClients) > 0 {
|
|
log.Printf("Cleaned up %d stale connections", len(staleClients))
|
|
}
|
|
}
|
|
|
|
// GetStats returns current server statistics
|
|
func (ls *LoginServer) GetStats() map[string]any {
|
|
ls.clientMutex.RLock()
|
|
connectionCount := len(ls.clients)
|
|
ls.clientMutex.RUnlock()
|
|
|
|
return map[string]any{
|
|
"connection_count": connectionCount,
|
|
"login_attempts": ls.stats.LoginAttempts,
|
|
"successful_logins": ls.stats.SuccessfulLogins,
|
|
"uptime_seconds": int(time.Since(ls.stats.StartTime).Seconds()),
|
|
"world_server_count": ls.worldList.GetActiveCount(),
|
|
}
|
|
}
|
|
|
|
// IncrementLoginAttempts atomically increments login attempt counter
|
|
func (ls *LoginServer) IncrementLoginAttempts() {
|
|
ls.stats.LoginAttempts++
|
|
}
|
|
|
|
// IncrementSuccessfulLogins atomically increments successful login counter
|
|
func (ls *LoginServer) IncrementSuccessfulLogins() {
|
|
ls.stats.SuccessfulLogins++
|
|
}
|
|
|
|
// GetDatabase returns the database instance
|
|
func (ls *LoginServer) GetDatabase() *Database {
|
|
return ls.database
|
|
}
|
|
|
|
// GetWorldList returns the world list instance
|
|
func (ls *LoginServer) GetWorldList() *WorldList {
|
|
return ls.worldList
|
|
}
|
|
|
|
// GetConfig returns the server configuration
|
|
func (ls *LoginServer) GetConfig() *Config {
|
|
return ls.config
|
|
}
|