This repository has been archived by the owner on Jan 21, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
/
server.js
166 lines (146 loc) · 4.77 KB
/
server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
'use strict';
process
.on('uncaughtException', console.error)
.on('unhandledRejection', console.error);
const express = require('express')
, session = require('express-session')
, redisStore = require('connect-redis')(session)
, path = require('path')
, app = express()
, server = require('http').createServer(app)
, cookieParser = require('cookie-parser')
, { cacheTemplates, boardDefaults, sessionSecret, globalLimits,
enableUserBoardCreation, enableUserAccountCreation, secureCookies,
debugLogs, ipHashPermLevel, meta, port, enableWebring } = require(__dirname+'/configs/main.js')
, referrerCheck = require(__dirname+'/helpers/referrercheck.js')
, { themes, codeThemes } = require(__dirname+'/helpers/themes.js')
, Mongo = require(__dirname+'/db/db.js')
, Socketio = require(__dirname+'/socketio.js')
, commit = require(__dirname+'/helpers/commit.js')
, dynamicResponse = require(__dirname+'/helpers/dynamic.js')
, { DAY } = require(__dirname+'/helpers/timeutils.js')
, CachePugTemplates = require('cache-pug-templates');
(async () => {
const env = process.env.NODE_ENV;
const production = env === 'production';
debugLogs && console.log('STARTING IN MODE:', env);
// connect to mongodb
debugLogs && console.log('CONNECTING TO MONGODB');
await Mongo.connect();
await Mongo.checkVersion();
// connect to redis
debugLogs && console.log('CONNECTING TO REDIS');
const { redisClient } = require(__dirname+'/redis.js');
// connect socketio
debugLogs && console.log('STARTING WEBSOCKET');
Socketio.connect(server);
// disable useless express header
app.disable('x-powered-by');
// parse forms
app.use(express.urlencoded({extended: false}));
// parse cookies
app.use(cookieParser());
// session store
app.use(session({
secret: sessionSecret,
store: new redisStore({
client: redisClient,
}),
resave: false,
saveUninitialized: false,
rolling: true,
cookie: {
httpOnly: true,
secure: secureCookies && production,
sameSite: 'strict',
maxAge: DAY,
}
}));
//trust proxy for nginx
app.set('trust proxy', 1);
//self explanatory middlewares
app.use(referrerCheck);
// use pug view engine
const views = path.join(__dirname, 'views/pages');
app.set('view engine', 'pug');
app.set('views', views);
//cache loaded templates
if (cacheTemplates === true) {
app.enable('view cache');
}
//default settings
app.locals.enableUserAccountCreation = enableUserAccountCreation;
app.locals.enableUserBoardCreation = enableUserBoardCreation;
app.locals.defaultTheme = boardDefaults.theme;
app.locals.defaultCodeTheme = boardDefaults.codeTheme;
app.locals.globalLimits = globalLimits;
app.locals.ipHashPermLevel = ipHashPermLevel;
app.locals.enableWebring = enableWebring;
app.locals.commit = commit;
app.locals.meta = meta;
// routes
if (!production) {
app.use(express.static(__dirname+'/static'));
app.use(express.static(__dirname+'/static/html'));
app.use(express.static(__dirname+'/static/json'));
}
app.use('/forms', require(__dirname+'/controllers/forms.js'));
app.use('/', require(__dirname+'/controllers/pages.js'));
//404 catchall
app.get('*', (req, res) => {
res.status(404).render('404');
})
// catch any unhandled errors
app.use((err, req, res, next) => {
if (err.code === 'EBADCSRFTOKEN') {
return dynamicResponse(req, res, 403, 'message', {
'title': 'Forbidden',
'message': 'Invalid CSRF token'
});
}
console.error(err);
return dynamicResponse(req, res, 500, 'message', {
'title': 'Internal Server Error',
'error': 'Internal Server Error', //what to put here?
'redirect': req.headers.referer || '/'
});
})
//listen
server.listen(port, '127.0.0.1', () => {
new CachePugTemplates({ app, views }).start();
debugLogs && console.log(`LISTENING ON :${port}`);
//let PM2 know that this is ready for graceful reloads and to serialise startup
if (typeof process.send === 'function') {
//make sure we are a child process of PM2 i.e. not in dev
debugLogs && console.log('SENT READY SIGNAL TO PM2');
process.send('ready');
}
});
const gracefulStop = () => {
debugLogs && console.log('SIGINT SIGNAL RECEIVED');
// Stops the server from accepting new connections and finishes existing connections.
Socketio.io.close((err) => {
// if error, log and exit with error (1 code)
debugLogs && console.log('CLOSING SERVER');
if (err) {
console.error(err);
process.exit(1);
}
// close database connection
debugLogs && console.log('DISCONNECTING MONGODB');
Mongo.client.close();
//close redis connection
debugLogs && console.log('DISCONNECTING REDIS')
redisClient.quit();
// now close without error
process.exit(0);
});
};
//graceful stop
process.on('SIGINT', gracefulStop);
process.on('message', (message) => {
if (message === 'shutdown') {
gracefulStop();
}
});
})();