API/GameServer/server.js
2026-01-24 16:47:19 -04:00

203 lines
6.4 KiB
JavaScript

/**
* Game Server - Real-time Multiplayer
* Handles actual game instances, player connections, and real-time gameplay
*/
const express = require('express');
const http = require('http');
const socketIo = require('socket.io');
const cors = require('cors');
const helmet = require('helmet');
const compression = require('compression');
const dotenv = require('dotenv');
require('dotenv').config();
const logger = require('./utils/logger');
const connectDB = require('./config/database');
const { initializeGameSystems } = require('./systems/GameSystem');
const SocketHandlers = require('./socket/socketHandlers');
const ServerRegistrationService = require('./services/ServerRegistrationService');
const ModService = require('./services/ModService');
const modRoutes = require('./routes/mods');
const { errorHandler, notFound } = require('./middleware/errorHandler');
const app = express();
const server = http.createServer(app);
const io = socketIo(server, {
cors: {
origin: ["https://galaxystrike.online", "https://api.korvarix.com", "http://localhost:3000"],
methods: ["GET", "POST"],
credentials: true
}
});
// Middleware
app.use(helmet());
app.use(compression());
app.use(cors({
origin: ["https://galaxystrike.online", "https://api.korvarix.com", "http://localhost:3000"],
credentials: true
}));
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true }));
// Game Server Routes (minimal - mostly for health checks and server management)
app.get('/health', (req, res) => {
res.status(200).json({
status: 'Game Server OK',
service: 'galaxystrikeonline-game',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
activeServers: Object.keys(gameServers).length,
connectedPlayers: connectedPlayers.size
});
});
// Get server status
app.get('/api/game/status', (req, res) => {
res.json({
activeServers: Object.keys(gameServers).length,
connectedPlayers: connectedPlayers.size,
timestamp: new Date().toISOString()
});
});
// Mod management routes
app.use('/api/mods', modRoutes);
// Error handling
app.use(notFound);
app.use(errorHandler);
// Global game server instances
const gameServers = {};
let serverRegistration; // Global reference to registration service
// Player tracking
const connectedPlayers = new Set(); // Track actual player connections
let socketHandlers;
io.on('connection', (socket) => {
logger.info(`Game Server: Player connected - ${socket.id}`);
socketHandlers.handleConnection(socket);
});
// Handle uncaught errors
process.on('uncaughtException', (error) => {
logger.error('Uncaught Exception:', error);
});
process.on('unhandledRejection', (reason, promise) => {
logger.error('Unhandled Rejection at:', promise, 'reason:', reason);
});
// Graceful shutdown handlers
async function gracefulShutdown(signal) {
logger.info(`[GRACEFUL SHUTDOWN] Received ${signal}, shutting down gracefully...`);
try {
// Stop accepting new connections
server.close(async () => {
logger.info('[GRACEFUL SHUTDOWN] HTTP server closed');
// Unregister from API
if (serverRegistration) {
await serverRegistration.stopHeartbeat();
const unregistered = await serverRegistration.unregisterWithAPI();
if (unregistered) {
logger.info('[GRACEFUL SHUTDOWN] Server unregistered from API successfully');
} else {
logger.warn('[GRACEFUL SHUTDOWN] Failed to unregister from API');
}
}
// Shutdown mod service
await ModService.shutdown();
// Close database connections
const mongoose = require('mongoose');
await mongoose.connection.close();
logger.info('[GRACEFUL SHUTDOWN] Database connections closed');
process.exit(0);
});
// Force shutdown after 30 seconds
setTimeout(() => {
logger.error('[GRACEFUL SHUTDOWN] Forced shutdown after timeout');
process.exit(1);
}, 30000);
} catch (error) {
logger.error('[GRACEFUL SHUTDOWN] Error during shutdown:', error);
process.exit(1);
}
}
process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
process.on('SIGINT', () => gracefulShutdown('SIGINT'));
// Handle Socket.IO adapter errors
io.engine.on('connection_error', (err) => {
logger.error('Socket.IO connection error:', err);
});
io.of('/').adapter.on('error', (err) => {
logger.error('Socket.IO adapter error:', err);
});
// Initialize database and game systems
async function startGameServer() {
try {
// Connect to database
await connectDB();
logger.info('Game Server: Database connected successfully');
// Initialize mod service
await ModService.initialize();
logger.info('Game Server: Mod service initialized');
// Initialize game systems
await initializeGameSystems();
logger.info('Game Server: Game systems initialized');
// Initialize server registration service
const gameServerUrl = `https://api.korvarix.com:${process.env.GAME_PORT || 3002}`;
const apiUrl = process.env.API_SERVER_URL || 'https://api.korvarix.com';
const serverName = process.env.SERVER_NAME || 'Game Server';
const serverRegion = process.env.SERVER_REGION || 'us-east';
const maxPlayers = parseInt(process.env.MAX_PLAYERS) || 10;
serverRegistration = new ServerRegistrationService(gameServerUrl, apiUrl, serverName, serverRegion, maxPlayers);
// Set up player count callback
serverRegistration.setPlayerCountCallback(() => connectedPlayers.size);
serverRegistration.startHeartbeat();
// Initialize socket handlers
socketHandlers = new SocketHandlers(io, gameServers, connectedPlayers);
// Make registration service available to socket handlers
socketHandlers.serverRegistration = serverRegistration;
// Start server
const PORT = process.env.GAME_PORT || 3002; // Game Server on port 3002
server.listen(PORT, () => {
logger.info(`Game Server running on port ${PORT}`);
logger.info('Game Server handles: Real-time Multiplayer, Game Instances, Socket.IO');
logger.info(`Game Server Name: ${serverName}`);
logger.info(`Game Server Region: ${serverRegion}`);
logger.info(`Game Server URL: ${gameServerUrl}`);
logger.info(`API Server URL: ${apiUrl}`);
});
} catch (error) {
logger.error('Failed to start Game Server:', error);
process.exit(1);
}
}
startGameServer();
module.exports = { app, server, io, gameServers };