forked from DecentCMS/DecentCMS
-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.js
137 lines (126 loc) · 4.4 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
// DecentCMS (c) 2014 Bertrand Le Roy, under MIT license. See license.txt for licensing details.
'use strict';
// TODO: move all require statements closer to usage in order to speed up startup time. Services are required when the server boots, which slows down things for complex dependencies.
var domain = require('domain');
var http = require('http');
var https = require('https');
var cluster = require('cluster');
var moduleDiscovery = require('./modules/core/multi-tenancy/lib/module-discovery');
var Shell = require('./modules/core/multi-tenancy/lib/shell');
var port = process.env.PORT || 1337;
var host = process.env.IP;
var workerCount = +process.env.WorkerCount || 1;
var runInCluster = !!process.env.RunInCluster;
if (runInCluster && cluster.isMaster) {
for (var i = 0; i < workerCount; i++) {
cluster.fork();
}
cluster.on('disconnect', function() {
console.error('Worker disconnected');
cluster.fork();
});
} else {
var bootDomain = domain.create();
bootDomain.on('error', function(err) {
console.error('Error at boot', err.stack || err.message || err);
});
bootDomain.run(function() {
// TODO: make even booting the shells asynchronous. Incoming requests can be queued until it's done.
// Discover all modules in the system
moduleDiscovery.discover();
// Discover all tenants
Shell.discover({
port: port,
host: host,
availableModules: moduleDiscovery.modules
});
// Load each tenant
for (var shellName in Shell.list) {
var shell = Shell.list[shellName];
shell.load();
}
});
var handler = function(req, res) {
var d = domain.create();
d.on('error', function(err) {
console.error('Unrecoverable error', err.stack || err.message || err);
try {
// Close down within 30 seconds
var killTimer = setTimeout(function() {
process.exit(1);
}, 30000);
// But don't keep the process open just for that!
killTimer.unref();
// stop taking new requests.
httpServer.close();
// Let the master know we're dead. This will trigger a
// 'disconnect' in the cluster master, and then it will fork
// a new worker.
if (runInCluster) {
cluster.worker.disconnect();
}
if (res && !res.finished) {
// try to send an error to the request that triggered the problem
res.statusCode = 500;
// TODO: let route handlers set headers, including powered by.
res.end('Oops, the server choked on this request!\n');
// TODO: broadcast the error to give loggers a chance to use it.
}
} catch (er2) {
// oh well, not much we can do at this point.
console.error('Error sending 500!', er2.stack);
return;
}
});
d.add(req);
d.add(res);
var shell = Shell.resolve(req);
if (!shell) {
console.error('Could not resolve shell.', {url: req.url, host: req.headers.host});
return;
}
d.add(shell);
// Now run the handler function in the domain.
d.run(function() {
shell.handleRequest(req, res, function() {
res.end('');
});
});
};
var httpServer;
var httpsServers = {};
var server;
// If iisnode, only create one server
if (process.env.IISNODE_VERSION && port.substr(0, 9) === '\\\\.\\pipe\\') {
server = httpServer = httpServer || http.createServer(handler);
server.listen(port);
return;
}
// Listen for each tenant
for (var shellName in Shell.list) {
var shell = Shell.list[shellName];
var hosts = Array.isArray(shell.host) ? shell.host : [shell.host];
for (i = 0; i < hosts.length; i++) {
var host = hosts[i];
if (shell.https) {
var sslParamsId = (shell.key || "") + (shell.cert || "") + (shell.pfx || "");
server = httpsServers.hasOwnProperty(sslParamsId)
? httpsServers[sslParamsId]
: httpsServers[sslParamsId] = https.createServer({
key: shell.key,
cert: shell.cert,
pfx: shell.pfx
}, handler);
}
else {
server = httpServer = httpServer || http.createServer(handler);
}
var currentPort = shell.port !== '*' ? shell.port : port;
server._portsInUse = server._portsInUse || {};
if (!server._portsInUse.hasOwnProperty('p' + currentPort)) {
server._portsInUse['p' + currentPort] = true;
server.listen(currentPort);
}
}
}
}