122 lines
4.6 KiB
JavaScript
122 lines
4.6 KiB
JavaScript
import express from 'express';
|
||
import path from 'path';
|
||
import { fileURLToPath } from 'url';
|
||
import crypto from 'crypto';
|
||
import chatRouter from './routers/chatRouter.js';
|
||
import authRouter from './routers/authRouter.js';
|
||
import navigationRouter from './routers/navigationRouter.js';
|
||
import settingsRouter from './routers/settingsRouter.js';
|
||
import adminRouter from './routers/adminRouter.js';
|
||
import contactRouter from './routers/contactRouter.js';
|
||
import socialnetworkRouter from './routers/socialnetworkRouter.js';
|
||
import forumRouter from './routers/forumRouter.js';
|
||
import falukantRouter from './routers/falukantRouter.js';
|
||
import friendshipRouter from './routers/friendshipRouter.js';
|
||
import modelsProxyRouter from './routers/modelsProxyRouter.js';
|
||
import blogRouter from './routers/blogRouter.js';
|
||
import match3Router from './routers/match3Router.js';
|
||
import taxiRouter from './routers/taxiRouter.js';
|
||
import taxiMapRouter from './routers/taxiMapRouter.js';
|
||
import taxiHighscoreRouter from './routers/taxiHighscoreRouter.js';
|
||
import termineRouter from './routers/termineRouter.js';
|
||
import vocabRouter from './routers/vocabRouter.js';
|
||
import dashboardRouter from './routers/dashboardRouter.js';
|
||
import newsRouter from './routers/newsRouter.js';
|
||
import calendarRouter from './routers/calendarRouter.js';
|
||
import cors from 'cors';
|
||
import './jobs/sessionCleanup.js';
|
||
|
||
const __filename = fileURLToPath(import.meta.url);
|
||
const __dirname = path.dirname(__filename);
|
||
|
||
const app = express();
|
||
|
||
// Request-Timing (aktivierbar per ENV)
|
||
// - LOG_SLOW_REQ_MS=200: Logge Requests, die länger dauern als X ms (Default 500)
|
||
// - LOG_ALL_REQ=1: Logge alle Requests
|
||
const LOG_ALL_REQ = process.env.LOG_ALL_REQ === '1';
|
||
const LOG_SLOW_REQ_MS = Number.parseInt(process.env.LOG_SLOW_REQ_MS || '500', 10);
|
||
const corsOrigins = (process.env.CORS_ORIGINS || process.env.FRONTEND_URL || '')
|
||
.split(',')
|
||
.map((origin) => origin.trim())
|
||
.filter(Boolean);
|
||
|
||
app.use((req, res, next) => {
|
||
const reqId = req.headers['x-request-id'] || (crypto.randomUUID ? crypto.randomUUID() : crypto.randomBytes(8).toString('hex'));
|
||
req.reqId = reqId;
|
||
res.setHeader('x-request-id', reqId);
|
||
const t0 = Date.now();
|
||
res.on('finish', () => {
|
||
const ms = Date.now() - t0;
|
||
if (LOG_ALL_REQ || ms >= LOG_SLOW_REQ_MS) {
|
||
console.log(`⏱️ REQ ${ms}ms ${res.statusCode} ${req.method} ${req.originalUrl} rid=${reqId}`);
|
||
}
|
||
});
|
||
next();
|
||
});
|
||
|
||
const corsOptions = {
|
||
origin(origin, callback) {
|
||
if (!origin) {
|
||
return callback(null, true);
|
||
}
|
||
|
||
if (corsOrigins.length === 0 || corsOrigins.includes(origin)) {
|
||
return callback(null, true);
|
||
}
|
||
|
||
return callback(null, false);
|
||
},
|
||
methods: ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE'],
|
||
allowedHeaders: ['Content-Type', 'Authorization', 'userid', 'authcode', 'userId', 'authCode'],
|
||
credentials: true,
|
||
preflightContinue: false,
|
||
optionsSuccessStatus: 204
|
||
};
|
||
|
||
app.use(cors(corsOptions));
|
||
app.options('*', cors(corsOptions));
|
||
app.use(express.json()); // To handle JSON request bodies
|
||
|
||
app.use('/api/chat', chatRouter);
|
||
app.use('/api/auth', authRouter);
|
||
app.use('/api/navigation', navigationRouter);
|
||
app.use('/api/settings', settingsRouter);
|
||
app.use('/api/admin', adminRouter);
|
||
app.use('/api/match3', match3Router);
|
||
app.use('/api/taxi', taxiRouter);
|
||
app.use('/api/taxi-maps', taxiMapRouter);
|
||
app.use('/api/taxi/highscores', taxiHighscoreRouter);
|
||
app.use('/images', express.static(path.join(__dirname, '../frontend/public/images')));
|
||
app.use('/api/contact', contactRouter);
|
||
app.use('/api/socialnetwork', socialnetworkRouter);
|
||
app.use('/api/vocab', vocabRouter);
|
||
app.use('/api/forum', forumRouter);
|
||
app.use('/api/falukant', falukantRouter);
|
||
app.use('/api/friendships', friendshipRouter);
|
||
app.use('/api/models', modelsProxyRouter);
|
||
app.use('/api/blog', blogRouter);
|
||
app.use('/api/termine', termineRouter);
|
||
app.use('/api/dashboard', dashboardRouter);
|
||
app.use('/api/news', newsRouter);
|
||
app.use('/api/calendar', calendarRouter);
|
||
|
||
// Serve frontend SPA for non-API routes to support history mode clean URLs
|
||
// /models/* nicht statisch ausliefern – nur über /api/models (Proxy mit Komprimierung)
|
||
const frontendDir = path.join(__dirname, '../frontend');
|
||
app.use((req, res, next) => {
|
||
if (req.path.startsWith('/models/')) {
|
||
return res.status(404).send('Use /api/models/ for 3D models (optimized).');
|
||
}
|
||
next();
|
||
});
|
||
app.use(express.static(path.join(frontendDir, 'dist')));
|
||
app.get(/^\/(?!api\/).*/, (req, res) => {
|
||
res.sendFile(path.join(frontendDir, 'dist', 'index.html'));
|
||
});
|
||
|
||
// Fallback 404 for unknown API routes
|
||
app.use('/api/*', (req, res) => res.status(404).send('404 Not Found'));
|
||
|
||
export default app;
|