147 lines
4.9 KiB
JavaScript
147 lines
4.9 KiB
JavaScript
const express = require('express');
|
|
const http = require('http');
|
|
const cors = require('cors');
|
|
const helmet = require('helmet');
|
|
const rateLimit = require('express-rate-limit');
|
|
require('dotenv').config();
|
|
|
|
const authRoutes = require('./routes/authRoutes');
|
|
const domainRoutes = require('./routes/domainRoutes');
|
|
const messagingRoutes = require('./routes/messagingRoutes');
|
|
const messagesRoutes = require('./routes/messagesRoutes');
|
|
const channelsRoutes = require('./routes/channelsRoutes');
|
|
const voiceRoutes = require('./routes/voiceRoutes');
|
|
const gameforgeRoutes = require('./routes/gameforgeRoutes');
|
|
const callRoutes = require('./routes/callRoutes');
|
|
const messageApiRoutes = require('./routes/messageApiRoutes');
|
|
const channelApiRoutes = require('./routes/channelApiRoutes');
|
|
const realtimeMessagesRoutes = require('./routes/realtimeMessagesRoutes');
|
|
const voiceCallRoutes = require('./routes/voiceCallRoutes');
|
|
const liveKitRoutes = require('./routes/liveKitRoutes');
|
|
const chatRoutes = require('./routes/chatRoutes');
|
|
const serverRoutes = require('./routes/serverRoutes');
|
|
const socketService = require('./services/socketService');
|
|
|
|
const path = require('path');
|
|
|
|
const app = express();
|
|
const httpServer = http.createServer(app);
|
|
const PORT = process.env.PORT || 3000;
|
|
|
|
// Trust proxy for Codespaces/containers
|
|
app.set('trust proxy', 1);
|
|
|
|
// Security middleware
|
|
app.use(helmet());
|
|
app.use(cors({
|
|
origin: function(origin, callback) {
|
|
const allowed = [
|
|
'https://atx-connect.up.railway.app',
|
|
process.env.FRONTEND_URL
|
|
];
|
|
|
|
// Allow localhost on any port in dev
|
|
if (!origin || origin.includes('localhost') || origin.includes('127.0.0.1')) {
|
|
return callback(null, true);
|
|
}
|
|
|
|
if (allowed.includes(origin)) {
|
|
return callback(null, true);
|
|
}
|
|
|
|
callback(new Error('CORS not allowed'));
|
|
},
|
|
credentials: true
|
|
}));
|
|
|
|
// Rate limiting
|
|
const limiter = rateLimit({
|
|
windowMs: parseInt(process.env.RATE_LIMIT_WINDOW_MS) || 15 * 60 * 1000, // 15 minutes
|
|
max: parseInt(process.env.RATE_LIMIT_MAX_REQUESTS) || 100,
|
|
message: 'Too many requests from this IP, please try again later.',
|
|
standardHeaders: true,
|
|
legacyHeaders: false,
|
|
});
|
|
|
|
app.use('/api/', limiter);
|
|
|
|
// Body parsing middleware
|
|
app.use(express.json());
|
|
app.use(express.urlencoded({ extended: true }));
|
|
|
|
// Health check endpoint
|
|
app.get('/health', (req, res) => {
|
|
res.json({ status: 'ok', timestamp: new Date().toISOString() });
|
|
});
|
|
|
|
// Serve React frontend build
|
|
const frontendPath = path.join(__dirname, '../frontend/dist');
|
|
app.use(express.static(frontendPath));
|
|
|
|
// API routes
|
|
app.use('/api/auth', authRoutes);
|
|
app.use('/api/passport/domain', domainRoutes);
|
|
app.use('/api/messaging', messagingRoutes);
|
|
app.use('/api/messages', messagesRoutes);
|
|
app.use('/api/channels', channelsRoutes);
|
|
app.use('/api/gameforge', gameforgeRoutes);
|
|
app.use('/api/calls', callRoutes);
|
|
app.use('/api/message', messageApiRoutes);
|
|
app.use('/api/channel', channelApiRoutes);
|
|
app.use('/api/realtime/messages', realtimeMessagesRoutes);
|
|
app.use('/api/voice', voiceCallRoutes);
|
|
app.use('/api/livekit', liveKitRoutes);
|
|
app.use('/api/chat', chatRoutes);
|
|
app.use('/api/servers', serverRoutes);
|
|
|
|
// Initialize Socket.io
|
|
const io = socketService.initialize(httpServer);
|
|
app.set('io', io); // Make io available in routes
|
|
|
|
// SPA fallback - serve index.html for all non-API routes (React Router)
|
|
app.get('*', (req, res) => {
|
|
// Don't serve index.html for API routes
|
|
if (req.path.startsWith('/api/')) {
|
|
return res.status(404).json({
|
|
success: false,
|
|
error: 'Endpoint not found'
|
|
});
|
|
}
|
|
res.sendFile(path.join(__dirname, '../frontend/dist/index.html'));
|
|
});
|
|
|
|
// Error handler
|
|
app.use((err, req, res, next) => {
|
|
console.error('Server error:', err);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: process.env.NODE_ENV === 'development' ? err.message : 'Internal server error'
|
|
});
|
|
});
|
|
|
|
// Start server - bind to 0.0.0.0 for Railway/containers
|
|
httpServer.listen(PORT, '0.0.0.0', () => {
|
|
console.log(`
|
|
╔═══════════════════════════════════════════════════════╗
|
|
║ AeThex Connect - Communication Platform ║
|
|
║ Server running on port ${PORT} ║
|
|
║ Environment: ${process.env.NODE_ENV || 'development'} ║
|
|
╚═══════════════════════════════════════════════════════╝
|
|
`);
|
|
console.log(`Health check: http://localhost:${PORT}/health`);
|
|
console.log(`API Base URL: http://localhost:${PORT}/api`);
|
|
console.log(`Socket.io: Enabled`);
|
|
});
|
|
|
|
// Graceful shutdown
|
|
process.on('SIGTERM', () => {
|
|
console.log('SIGTERM received, shutting down gracefully...');
|
|
process.exit(0);
|
|
});
|
|
|
|
process.on('SIGINT', () => {
|
|
console.log('SIGINT received, shutting down gracefully...');
|
|
process.exit(0);
|
|
});
|
|
|
|
module.exports = app;
|