opt-cc/server/server.js

195 lines
7.1 KiB
JavaScript

'use strict';
const express = require('express');
const path = require('path');
const favicon = require('serve-favicon');
const bodyParser = require('body-parser');
const requestLogger = require('morgan');
// logger
const debug = require('debug');
const error = debug('cc:server:err');
const logger = debug('cc:server');
logger.log = console.log.bind(console);
const cors = require('cors');
const mongoose = require('mongoose');
const {exec} = require('child_process');
// cluster mode
const cluster = require('cluster');
const envWorkerNum = process.env.NODE_WORKER_COUNT;
const numWorkers = (envWorkerNum) ? envWorkerNum : 2;
// own modules
const config = require('./config/config');
const urls = require('./config/api-url');
const restAPIchecks = require('./middleware/request-checks.js');
const errorResponseWare = require('./middleware/error-response');
const apiAuthenticationMiddleware = require('./middleware/auth-middleware');
const checkAdmin = require('./middleware/permission-check').checkAdmin;
const signatureCronJob = require('./cron-job/cron').cronJobSignature;
const backupCronJob = require('./cron-job/cron').cronJobBackup;
// router modules
const authenticateRouter = require('./routes/authenticate');
const accountRouter = require('./routes/account');
const overviewRouter = require('./routes/overview');
const userRouter = require('./routes/users');
const squadRouter = require('./routes/squads');
const rankRouter = require('./routes/ranks');
const decorationRouter = require('./routes/decorations');
const awardingRouter = require('./routes/awardings');
const requestRouter = require('./routes/request');
const playerRouter = require('./routes/players');
const signatureRouter = require('./routes/signatures');
const commandRouter = require('./routes/command');
const campaignRouter = require('./routes/campaigns');
const warRouter = require('./routes/wars');
const logRouter = require('./routes/logs');
const slottingRouter = require('./routes/slotting');
// Configuration ***********************************
// mongoose promise setup
mongoose.Promise = global.Promise;
// app creation
const app = express();
// Middlewares *************************************************
// setup CORS-middleware
const corsOptions = {
methods: ['GET'],
optionsSuccessStatus: 200,
};
app.use(cors(corsOptions));
app.use(favicon(path.join(__dirname + '/..', 'public', 'favicon.ico')));
app.use(express.static(path.join(__dirname + '/..', 'public')));
app.use(bodyParser.json({limit: '10mb'}));
app.use(bodyParser.urlencoded({limit: '10mb', extended: true}));
// API request checks for API-version and JSON etc.
app.use(restAPIchecks);
// Routes ******************************************************
app.use(urls.signatures, signatureRouter);
// initialize logging at this point to exclude /signature requests
if (process.env.NODE_ENV === config.dev.env) {
// development logging
app.use(requestLogger('dev'));
} else if (process.env.NODE_ENV !== config.test.dredd.env && process.env.NODE_ENV !== config.test.unit.env) {
// production logging, apache style
app.use(requestLogger(':date[clf] :method :url :response-time ms :status'));
}
app.use(urls.auth, authenticateRouter);
app.use(urls.overview, overviewRouter);
app.use(urls.users, userRouter);
app.use(urls.squads, squadRouter);
app.use(urls.ranks, rankRouter);
app.use(urls.decorations, decorationRouter);
app.use(urls.request, requestRouter);
app.use(urls.awards, awardingRouter);
app.use(urls.wars, warRouter);
app.use(urls.players, playerRouter);
app.use(urls.campaigns, campaignRouter);
app.use(urls.logs, logRouter);
app.use(urls.slotting, slottingRouter);
app.use(urls.command, apiAuthenticationMiddleware, checkAdmin, commandRouter);
app.use(urls.account, apiAuthenticationMiddleware, checkAdmin, accountRouter);
// send index.html on all different paths
app.use((req, res) => {
res.sendFile('public/index.html', {root: __dirname + '/..'});
});
// register error handlers
errorResponseWare(app);
// Start the server
if (process.env.NODE_ENV === config.test.unit.env || process.env.NODE_ENV === config.test.dredd.env) {
const MongodbMemoryServer = require('mongodb-memory-server').default;
const mongoServer = new MongodbMemoryServer();
mongoose.Promise = Promise;
mongoServer.getConnectionString()
.then((mongoUri) => {
mongoose.connect(mongoUri, config.database.mongooseConfig);
mongoose.connection.on('error', (e) => {
if (e.message.code === 'ETIMEDOUT') {
error(e);
mongoose.connect(mongoUri);
}
error(e);
});
if (process.env.NODE_ENV === config.test.dredd.env) {
const mongoPortAndDB = mongoUri.replace('mongodb://localhost:', '').split('/');
exec(
__dirname + '/apib/dredd/populate-data.sh'
.concat(' -p ').concat(mongoPortAndDB[0])
.concat(' -d ').concat(mongoPortAndDB[1]), (err, stdout, stderr) => {
if (err) {
error(err.message);
} else {
logger('\x1b[32m%s\x1b[0m', stderr);
}
});
}
mongoose.connection.once('open', () => {
logger(`MongoDB successfully connected to ${mongoUri}`);
app.listen(config.test.port);
logger('Listening on port ' + config.test.port);
});
});
} else {
mongoose.connect(config.database.uri + config.database.db, config.database.mongooseConfig)
.then((db) => {
let cronWorkerPID;
if (cluster.isMaster) {
// Fork workers
for (let i = 0; i < numWorkers; i++) {
if (i === 0) {
const spawnedWorker = cluster.fork({START_CRON: true});
cronWorkerPID = spawnedWorker.process.pid;
} else {
cluster.fork();
}
}
logger(`Master ${process.pid} is running. Forking ${numWorkers} workers`);
// Check if worker id is died
cluster.on('exit', (worker, code, signal) => {
logger(`worker ${worker.process.pid} died`);
if (worker.process.pid === cronWorkerPID) {
const spawnedWorker = cluster.fork({START_CRON: true});
cronWorkerPID = spawnedWorker.process.pid;
} else {
cluster.fork();
}
});
} else {
app.listen(config.port, (err) => {
if (err) {
error(`Error on startup ${err}`);
} else {
logger(`Worker ${process.pid} started. Listening on port ${config.port}`);
if (process.env.START_CRON) {
logger(`Attaching cronJobs to cluster worker ${process.pid}`);
signatureCronJob.start();
backupCronJob.start();
}
}
});
}
});
}
module.exports = app;