Files
Connect-5/server.js

235 lines
8.5 KiB
JavaScript

const express = require('express');
const http = require('http');
const socketIO = require('socket.io');
const cors = require('cors');
const path = require('path');
const { initializeDatabase, db } = require('./database');
const GameManager = require('./gameManager');
const app = express();
const server = http.createServer(app);
const io = socketIO(server, {
cors: {
origin: "*",
methods: ["GET", "POST"]
}
});
const PORT = process.env.PORT || 3000;
// Middleware
app.use(cors());
app.use(express.json());
app.use(express.static(path.join(__dirname)));
// Serve index.html for root route
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'index.html'));
});
// Database health check endpoint with detailed diagnostics
app.get('/api/db-status', async (req, res) => {
const startTime = Date.now();
const dbConfig = require('./db.config.js');
let status = {
connected: false,
latency: 0,
writeCapable: false,
timestamp: new Date().toISOString(),
error: null,
// Additional diagnostic info for testing phase
host: dbConfig.host || 'unknown',
database: dbConfig.database || 'unknown',
user: dbConfig.user || 'unknown',
connectionLimit: dbConfig.connectionLimit || 'unknown',
poolStats: null
};
try {
console.log(`[DB-STATUS] Testing connection to ${status.host}/${status.database}...`);
// Test connection with a simple query
const [result] = await db.pool.query('SELECT 1 as test');
const latency = Date.now() - startTime;
if (result && result[0].test === 1) {
status.connected = true;
status.latency = latency;
console.log(`[DB-STATUS] ✅ Connection successful (${latency}ms)`);
// Get pool statistics
try {
status.poolStats = {
totalConnections: db.pool.pool._allConnections.length,
freeConnections: db.pool.pool._freeConnections.length,
queuedRequests: db.pool.pool._connectionQueue.length
};
console.log(`[DB-STATUS] Pool stats:`, status.poolStats);
} catch (poolError) {
console.log(`[DB-STATUS] Could not retrieve pool stats:`, poolError.message);
}
// Test write capability
try {
console.log(`[DB-STATUS] Testing write capability...`);
const testTableName = '_health_check_test';
// Create test table if it doesn't exist
await db.pool.query(`
CREATE TABLE IF NOT EXISTS ${testTableName} (
id INT AUTO_INCREMENT PRIMARY KEY,
test_value VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`);
// Try to insert a test record
const testValue = `test_${Date.now()}`;
await db.pool.query(
`INSERT INTO ${testTableName} (test_value) VALUES (?)`,
[testValue]
);
// Clean up old test records (keep only last 10)
await db.pool.query(`
DELETE FROM ${testTableName}
WHERE id NOT IN (
SELECT id FROM (
SELECT id FROM ${testTableName}
ORDER BY created_at DESC
LIMIT 10
) AS keep_records
)
`);
status.writeCapable = true;
console.log(`[DB-STATUS] ✅ Write test successful`);
} catch (writeError) {
console.error(`[DB-STATUS] ❌ Write test failed:`, writeError.message);
status.writeCapable = false;
status.error = `Write test failed: ${writeError.message}`;
}
}
} catch (error) {
console.error(`[DB-STATUS] ❌ Connection failed:`, error.message);
console.error(`[DB-STATUS] Error code:`, error.code);
console.error(`[DB-STATUS] Error errno:`, error.errno);
status.connected = false;
status.latency = Date.now() - startTime;
// Provide more detailed error messages
let errorMessage = error.message;
if (error.code === 'ECONNREFUSED') {
errorMessage = `Connection refused to ${status.host}. Is MySQL running?`;
} else if (error.code === 'ER_ACCESS_DENIED_ERROR') {
errorMessage = `Access denied for user '${status.user}'. Check credentials.`;
} else if (error.code === 'ER_BAD_DB_ERROR') {
errorMessage = `Database '${status.database}' does not exist.`;
} else if (error.code === 'ENOTFOUND') {
errorMessage = `Host '${status.host}' not found. Check hostname.`;
}
status.error = errorMessage;
}
res.json(status);
});
// Initialize game manager
const gameManager = new GameManager(io, db);
// Socket.io connection handling
io.on('connection', (socket) => {
console.log(`✅ Player connected: ${socket.id}`);
// Player registration
socket.on('register_player', async (data) => {
console.log('📝 Registration request from', socket.id, 'username:', data.username);
const result = await gameManager.registerPlayer(socket, data.username);
console.log('📝 Registration result:', result);
socket.emit('registration_result', result);
});
// Send challenge
socket.on('send_challenge', async (data) => {
const result = await gameManager.sendChallenge(socket, data.targetUsername, data.boardSize);
socket.emit('challenge_result', result);
});
// Accept challenge
socket.on('accept_challenge', async (data) => {
const result = await gameManager.acceptChallenge(socket, data.challengeId);
if (result.success) {
socket.emit('challenge_accepted', result);
} else {
socket.emit('challenge_error', result);
}
});
// Decline challenge
socket.on('decline_challenge', (data) => {
gameManager.declineChallenge(socket, data.challengeId);
});
// Make move
socket.on('make_move', async (data) => {
const result = await gameManager.handleMove(socket, data);
socket.emit('move_result', result);
});
// Heartbeat to keep session alive
socket.on('heartbeat', async () => {
await gameManager.heartbeat(socket);
});
// Request active players
socket.on('request_active_players', async () => {
const activePlayers = await db.getActivePlayers();
socket.emit('active_players_update', activePlayers);
});
// Disconnect
socket.on('disconnect', async () => {
console.log(`❌ Player disconnected: ${socket.id}`);
await gameManager.handleDisconnect(socket);
});
});
// Cleanup stale sessions periodically
setInterval(async () => {
await db.cleanupStaleSessions();
}, 60000); // Every minute
// Error handling
process.on('unhandledRejection', (error) => {
console.error('Unhandled promise rejection:', error);
});
// Initialize database and start server
async function startServer() {
try {
await initializeDatabase();
server.listen(PORT, () => {
console.log('');
console.log('═══════════════════════════════════════════════════');
console.log('🎮 Connect-5 Multiplayer Server');
console.log('═══════════════════════════════════════════════════');
console.log(`🌐 Server running on port ${PORT}`);
console.log(`📡 WebSocket server ready`);
console.log(`🗄️ Database connected`);
console.log('');
console.log(`🎯 Open your browser to: http://localhost:${PORT}`);
console.log('═══════════════════════════════════════════════════');
console.log('');
});
} catch (error) {
console.error('Failed to start server:', error);
process.exit(1);
}
}
startServer();