|
1 | 1 | /* global log */
|
| 2 | +var cluster = require('cluster'); |
| 3 | +var redis = require('redis'); |
| 4 | +global.config = require('./config.js'); |
2 | 5 |
|
3 |
| -var args = require('optimist').argv; |
4 |
| -global.config = require(args.config || './config.js'); |
5 |
| -var net = require('net'); |
6 |
| -var tls = require('tls'); |
7 |
| -var events = require('events'); |
8 |
| -var express = require('express'); |
9 |
| -var fs = require('fs'); |
10 |
| -var sets = require('simplesets'); |
11 |
| -var mysql = require('mysql'); |
12 |
| -var bodyParser = require('body-parser'); |
13 |
| -// websocket requires |
14 |
| -var websocket = require('websocket-driver'); |
15 |
| -var parser = require('http-string-parser'); |
16 |
| -var WebSocketStream = require('./src/WebSocketStream'); |
17 |
| - |
18 |
| -global.log = require('./src/Logging'); |
19 |
| - |
20 |
| -var Session = require('./src/Session'); |
21 |
| -var Room = require('./src/Room'); |
22 |
| -var Plugins = require('./src/Plugins'); |
23 |
| - |
24 |
| -function Server() { |
25 |
| - var d = new Date(); |
26 |
| - this._sessions = new sets.Set(); |
27 |
| - this._rooms = {}; |
28 |
| - this._userList = Array(); |
29 |
| - this._partyList = {}; |
30 |
| - this._plugins = new Plugins(this); |
31 |
| - |
32 |
| -} |
33 |
| - |
34 |
| -Server.prototype.getRoom = function (roomId) { |
35 |
| - if (this._rooms[roomId] === undefined) { |
36 |
| - this._rooms[roomId] = new Room(roomId); |
37 |
| - } |
38 |
| - |
39 |
| - return this._rooms[roomId]; |
40 |
| -}; |
41 |
| - |
42 |
| -// ## Check if username is in use ## |
43 |
| -Server.prototype.isNameFree = function (name) { |
44 |
| - |
45 |
| - var free = true; |
46 |
| - this._sessions.each(function (s) { |
47 |
| - if (s.id === name) { |
48 |
| - free = false; |
49 |
| - } |
50 |
| - }); |
51 |
| - return free; |
52 |
| -}; |
53 |
| - |
54 |
| -// ## Start Socket Server ## |
55 |
| -Server.prototype.start = function (callback) { |
| 6 | +if (cluster.isMaster && global.config.multiprocess.enabled) { |
| 7 | + var numCPUs = global.config.multiproccess.processes; |
| 8 | + console.log(`Starting ${numCPUs} workers`); |
56 | 9 | console.log('========================');
|
57 |
| - console.log('Janus VR Presence Server'); |
| 10 | + console.log('Janus VR Presence Server (clustered)'); |
58 | 11 | console.log('========================');
|
59 |
| - log.info('Startup date/time: ' + Date()); |
60 |
| - |
61 |
| - console.log('See server.log for activity information and config.js for configuration'); |
62 |
| - console.log('Log level: ' + config.logLevel); |
| 12 | + console.log('See config.js for configuration'); |
63 | 13 | console.log('Startup date/time: ' + Date());
|
64 |
| - |
65 |
| - this.server = net.createServer(this.onConnect.bind(this)); |
66 |
| - this.server.listen(config.port, "::", function (err) { |
67 |
| - |
68 |
| - if (err) { |
69 |
| - log.error('Socket Server error listening on port: ' + config.port); |
70 |
| - process.exit(1); |
71 |
| - } |
72 |
| - |
73 |
| - log.info('Socket Server listening on port: ' + config.port); |
74 |
| - console.log('Socket Server listening on port: ' + config.port); |
75 |
| - |
76 |
| - }); |
77 |
| - |
78 |
| - if (config.ssl) { |
79 |
| - |
80 |
| - this.ssl = tls.createServer(config.ssl.options, this.onConnect.bind(this)); |
81 |
| - this.ssl.listen(config.ssl.port, "::", function (err) { |
82 |
| - |
83 |
| - if (err) { |
84 |
| - log.error('SSL Server error listening on port: ' + config.ssl.port); |
85 |
| - process.exit(1); |
86 |
| - } |
87 |
| - |
88 |
| - console.log('SSL Server listening on port: ' + config.ssl.port); |
89 |
| - log.info('SSL Server listening on port: ' + config.ssl.port); |
90 |
| - |
91 |
| - }); |
92 |
| - } |
93 |
| - |
94 |
| - if (config.startWebServer) { |
95 |
| - this.startWebServer(); |
96 |
| - } |
97 |
| - if (callback && typeof(callback) == "function") |
98 |
| - callback(); |
99 |
| -}; |
100 |
| - |
101 |
| - |
102 |
| -// ## start web server ## |
103 |
| -Server.prototype.startWebServer = function () { |
104 |
| - var http = require('http'), |
105 |
| - https = require('https'); |
106 |
| - var self = this; |
107 |
| - |
108 |
| - this.ws = express(); |
109 |
| - |
110 |
| - this.ws.use(bodyParser.json()); |
111 |
| - var router = express.Router(); |
112 |
| - |
113 |
| - console.log('starting web server on port ' + config.webServerPort); |
114 |
| - |
115 |
| - if (global.config.hookPlugins.hasOwnProperty('enter_room') && |
116 |
| - global.config.hookPlugins.enter_room.plugins.indexOf('janus-mysql-popular') > -1) |
117 |
| - { |
118 |
| - this._conn = mysql.createPool({ |
119 |
| - host : config.MySQL_Hostname, |
120 |
| - user : config.MySQL_Username, |
121 |
| - password : config.MySQL_Password, |
122 |
| - database : config.MySQL_Database |
| 14 | + var redisClient = redis.createClient(global.config.redis); |
| 15 | + redisClient.del('userlist:multi'); |
| 16 | + redisClient.del('partylist:multi'); |
| 17 | + for (var i = 0; i < numCPUs; i++) { |
| 18 | + var child = cluster.fork(); |
| 19 | + child.on('exit', () => { |
| 20 | + redisClient.hdel('userlist', child.process.pid); |
| 21 | + redisClient.hdel('partylist', child.process.pid); |
123 | 22 | });
|
124 |
| - |
125 |
| - router.get('/getPopularRooms', function (req, res) { |
126 |
| - var limit = parseInt(req.query.limit, 10) || 20, |
127 |
| - offset = parseInt(req.query.offset, 10) || 0, |
128 |
| - orderBy = req.query.orderBy || "weight", |
129 |
| - desc = (req.query.desc && req.query.desc === "true") ? "DESC" : "", |
130 |
| - contains = req.query.urlContains ? "%" + req.query.urlContains + "%" : "%"; |
131 |
| - var sql = "SELECT roomName, url as roomUrl, count, weight, UNIX_TIMESTAMP(lastSeen) as lastEntered, thumbnail FROM `popular` WHERE url LIKE ? ORDER BY ?? "+desc+" LIMIT ?,?"; |
132 |
| - this._conn.query(sql, [contains, orderBy, offset, limit], function(err, results) { |
133 |
| - if (err) { |
134 |
| - console.log(err); |
135 |
| - res.json({"success": false, "data": [{"error": "Error querying the DB"}]}); |
136 |
| - return; |
137 |
| - } |
138 |
| - |
139 |
| - res.json({"success": true, "data": results}); |
140 |
| - }) |
141 |
| - }.bind(this)); |
142 |
| - |
143 |
| - router.post('/addThumb', function (req, res) { |
144 |
| - data = req.body; |
145 |
| - if (!data['token'] || |
146 |
| - data['token'] !== global.config.popularRooms.masterToken) |
147 |
| - return res.json({"success": false, "data": [{"error": "Invalid token"}]}); |
148 |
| - if (!data['roomUrl'] || !data['thumbnail']) |
149 |
| - return res.json({"success": false, "data": [{"error": "Must POST roomUrl and thumbnail parameters"}]}); |
150 |
| - var roomUrl = data['roomUrl'], |
151 |
| - thumbnail = data['thumbnail']; |
152 |
| - var sql = "UPDATE popular SET thumbnail = ? WHERE url = ?"; |
153 |
| - this._conn.query(sql, [thumbnail, roomUrl], (err, results) => { |
154 |
| - if (err) { |
155 |
| - console.log(err); |
156 |
| - return res.json({"success": false, "data": [{"error": "Error querying the DB"}]}); |
157 |
| - } |
158 |
| - return res.json({"success": true}); |
159 |
| - }); |
160 |
| - }.bind(this)); |
161 | 23 | }
|
162 |
| - router.get('/log', function (req, res) { |
163 |
| - res.writeHead(200, {'Content-Type': 'text/plain', 'Content-Length': -1, 'Transfer-Encoding': 'chunked'}); |
164 |
| - var logFile = fs.createReadStream('server.log'); |
165 |
| - logFile.pipe(res); |
166 |
| - }); |
167 |
| - |
168 |
| - router.get('/get_partylist', function (req, res) { |
169 |
| - //console.log("get_partylist: " + JSON.stringify(self._partyList)); |
170 |
| - res.json(self._partyList); |
171 |
| - }); |
172 | 24 |
|
173 |
| - router.get('/', function (req, res) { |
174 |
| - res.send(200, 'Nothing to see here ... yet'); |
175 |
| - }); |
176 |
| - |
177 |
| - |
178 |
| - this.ws.use(router); |
179 |
| - |
180 |
| - //this.webserver = this.ws.listen(config.webServerPort, "::"); |
181 |
| - |
182 |
| - this.webserver = http.createServer(this.ws) |
183 |
| - this.webserver.listen(config.webServerPort, "::"); |
184 |
| - log.info('Webserver (http) started on port: ' + config.webServerPort); |
185 |
| - this.webserverHttps = https.createServer(config.ssl.options, this.ws).listen(config.webServerPortHttps); |
186 |
| - console.log('webserver', typeof(this.webserverHttps)); |
187 |
| - log.info('Webserver (https) started on port: ' + config.webServerPortHttps); |
188 |
| - console.log('Start Date/Time: ' + Date()); |
189 |
| -}; |
190 |
| - |
191 |
| -Server.prototype.close = function(cb) { |
192 |
| - this.server.close( (err) => { |
193 |
| - if (config.startWebServer && this.webserver) { |
194 |
| - this.webserver.close( (err) => { |
195 |
| - return cb(err); |
196 |
| - }); |
197 |
| - } |
198 |
| - else { |
199 |
| - return cb(err); |
200 |
| - } |
| 25 | + Object.keys(cluster.workers).forEach(function(id) { |
| 26 | + console.log('SPAWNED', cluster.workers[id].process.pid); |
201 | 27 | });
|
202 | 28 | }
|
203 | 29 |
|
204 |
| -// ## action on client connection ## |
205 |
| -Server.prototype.onConnect = function (socket) { |
206 |
| - |
207 |
| - var self = this; |
208 |
| - var addr = socket.remoteAddress; |
209 |
| - var s; |
210 |
| - |
211 |
| - log.info('Client connected ' + addr); |
212 |
| - |
213 |
| - // setup for websocket |
214 |
| - var driver = websocket.server({'protocols': 'binary'}); |
215 |
| - socket.on('error', function (err) { |
216 |
| - log.error(addr); |
217 |
| - log.error('Socket error: ', err); |
218 |
| - }); |
219 |
| - socket.on('close', function () { |
220 |
| - log.info('Client disconnected: ' + addr); |
221 |
| - if (s) |
222 |
| - self._sessions.remove(s); |
223 |
| - }); |
224 |
| - |
225 |
| - socket.once('data', function (data) { |
226 |
| - // try to parse the packet as http |
227 |
| - var request = parser.parseRequest(data.toString()); |
228 |
| - |
229 |
| - if (Object.keys(request.headers).length === 0) |
230 |
| - { |
231 |
| - // there are no http headers, this is a raw tcp connection |
232 |
| - s = new Session(self, socket); |
233 |
| - self._sessions.add(s); |
234 |
| - |
235 |
| - // emit the first message so the session gets it |
236 |
| - socket.emit('data', data); |
237 |
| - } |
238 |
| - }); |
239 |
| - |
240 |
| - driver.on('connect', function () { |
241 |
| - if (websocket.isWebSocket(driver)) { |
242 |
| - log.info('Websocket connection:', addr); |
243 |
| - driver.start(); |
244 |
| - |
245 |
| - s = new Session(self, new WebSocketStream(driver, socket)); |
246 |
| - self._sessions.add(s) |
247 |
| - |
248 |
| - driver.on('error', function (err) { |
249 |
| - log.error(addr); |
250 |
| - log.error('Websocket error: ', err); |
251 |
| - }); |
252 |
| - } |
253 |
| - }); |
254 |
| - socket.pipe(driver.io).pipe(socket); |
255 |
| -}; |
256 |
| -if (require.main === module) { |
257 |
| - (new Server()).start(); |
258 |
| -} |
259 | 30 | else {
|
260 |
| - module.exports = Server; |
| 31 | + var Server = require("./src/Server.js"); |
| 32 | + (new Server()).start(); |
261 | 33 | }
|
262 |
| - |
0 commit comments