- Update gitignore and serena config - Improve connection and voting stores - Enhance admin routes and socket handling - Update client-screen views - Add auth middleware Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
89 lines
2.9 KiB
TypeScript
89 lines
2.9 KiB
TypeScript
import { createServer } from 'http';
|
||
import { app, logger } from './app';
|
||
import { config } from './config';
|
||
import { connectRedis } from './config/redis';
|
||
import { connectDatabase, disconnectDatabase } from './config/db';
|
||
import { initializeSocket } from './socket';
|
||
import { loadLuaScripts } from './services/vote.service';
|
||
import { loadVotingScripts } from './services/voting.engine';
|
||
import { prizeConfigService } from './services/prize-config.service';
|
||
import { programConfigService } from './services/program-config.service';
|
||
import { participantService } from './services/participant.service';
|
||
|
||
async function main(): Promise<void> {
|
||
try {
|
||
if (!config.adminAccessCode) {
|
||
logger.warn('ADMIN_ACCESS_CODE 未配置,管理员登录将被拒绝');
|
||
}
|
||
if (!config.isDev && config.jwtSecret === 'dev-secret-change-in-production') {
|
||
logger.error('生产环境禁止使用默认 JWT_SECRET,请配置环境变量');
|
||
process.exit(1);
|
||
}
|
||
// Connect to Database
|
||
logger.info('Connecting to Database...');
|
||
await connectDatabase();
|
||
|
||
// Connect to Redis
|
||
logger.info('Connecting to Redis...');
|
||
await connectRedis();
|
||
|
||
// Load Lua scripts
|
||
logger.info('Loading Lua scripts...');
|
||
await loadLuaScripts();
|
||
await loadVotingScripts();
|
||
|
||
// Load prize configuration
|
||
logger.info('Loading prize configuration...');
|
||
await prizeConfigService.load();
|
||
|
||
// Load program configuration
|
||
logger.info('Loading program configuration...');
|
||
await programConfigService.load();
|
||
|
||
// Restore participants from Redis
|
||
logger.info('Restoring participants from Redis...');
|
||
await participantService.restoreFromRedis();
|
||
|
||
// Create HTTP server
|
||
const httpServer = createServer(app);
|
||
|
||
// Initialize Socket.io
|
||
logger.info('Initializing Socket.io...');
|
||
await initializeSocket(httpServer);
|
||
|
||
// Start server - listen on all interfaces for LAN access
|
||
httpServer.listen(config.port, '0.0.0.0', () => {
|
||
logger.info({ port: config.port, env: config.nodeEnv }, 'Server started');
|
||
logger.info(`Health check: http://localhost:${config.port}/health`);
|
||
logger.info(`LAN access: http://192.168.1.5:${config.port}`);
|
||
});
|
||
|
||
// Graceful shutdown
|
||
const shutdown = async (signal: string) => {
|
||
logger.info({ signal }, 'Shutdown signal received');
|
||
|
||
// Disconnect from database
|
||
await disconnectDatabase();
|
||
|
||
httpServer.close(() => {
|
||
logger.info('HTTP server closed');
|
||
process.exit(0);
|
||
});
|
||
|
||
// Force exit after 10 seconds
|
||
setTimeout(() => {
|
||
logger.error('Forced shutdown after timeout');
|
||
process.exit(1);
|
||
}, 10000);
|
||
};
|
||
|
||
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
||
process.on('SIGINT', () => shutdown('SIGINT'));
|
||
} catch (error) {
|
||
logger.error({ error }, 'Failed to start server');
|
||
process.exit(1);
|
||
}
|
||
}
|
||
|
||
main();
|