From 657eb6f66da94ebb63fc96c0a6fde63744434e27 Mon Sep 17 00:00:00 2001 From: Alonzo Coeus Date: Sat, 5 Jan 2019 19:44:38 +0000 Subject: [PATCH 1/2] Moving to ES6 Moving to ES6. Switching to normal class statements --- src/Plugins.js | 103 +++++++------- src/Room.js | 92 ++++++------ src/Server.js | 309 +++++++++++++++++++++-------------------- src/Session.js | 191 +++++++++++++------------ src/WebSocketStream.js | 59 ++++---- 5 files changed, 394 insertions(+), 360 deletions(-) diff --git a/src/Plugins.js b/src/Plugins.js index 97c7be5..14c0967 100644 --- a/src/Plugins.js +++ b/src/Plugins.js @@ -2,66 +2,73 @@ var args = require('optimist').argv; var config = require(args.config || '../config.js'); var Session = require('./Session'); -function Plugins(server) { - this._plugins = []; - this._intervals = []; - this._methodPlugins = []; - this._server = server; +class Plugins +{ + constructor(server) + { + this._plugins = []; + this._intervals = []; + this._methodPlugins = []; + this._server = server; - this.intervalLoad(); - this.methodLoad(); -} - -Plugins.prototype.intervalLoad = function() { - var plugins = config.intervalPlugins; + this.intervalLoad(); + this.methodLoad(); + } - for(var p in plugins) { - var file = plugins[p].plugin; - var plugin = require(file); - var interval = new plugin(this._server); + intervalLoad() + { + var plugins = config.intervalPlugins; - this._intervals[p] = setInterval(function() { interval.call(this._server); }, (plugins[p].interval * 1000)); + for(var p in plugins) { + var file = plugins[p].plugin; + var plugin = require(file); + var interval = new plugin(this._server); + + this._intervals[p] = setInterval(function() { interval.call(this._server); }, (plugins[p].interval * 1000)); + } } -} -Plugins.prototype.methodLoad = function() { - var plugins = config.methodPlugins; + methodLoad() + { + var plugins = config.methodPlugins; - for(var method in plugins) { - var file = plugins[method].plugin; - var plugin = require(file); - Session.validMethods.push(method); - Session.prototype[method] = plugin.call; + for(var method in plugins) { + var file = plugins[method].plugin; + var plugin = require(file); + Session.validMethods.push(method); + Session.prototype[method] = plugin.call; + } } -} -Plugins.prototype.call = function(name, socket, command) { - var hook = config.hookPlugins[name]; + call() + { + var hook = config.hookPlugins[name]; - for(var k in hook.plugins) { - var p = hook.plugins[k]; + for(var k in hook.plugins) { + var p = hook.plugins[k]; + + if(p === undefined) { + err = "Unable to load plugin " + p; + log.info(err); + console.log(err); + return; + } - if(p === undefined) { - err = "Unable to load plugin " + p; - log.info(err); - console.log(err); - return; - } - - if(this._plugins[name] === undefined) { - this._plugins[name] = Array(); - } - - if(this._plugins[name][p] === undefined) { - this.load(name, p); + if(this._plugins[name] === undefined) { + this._plugins[name] = Array(); + } + + if(this._plugins[name][p] === undefined) { + this.load(name, p); + } + this._plugins[name][p].call(name, socket, command); + } } - this._plugins[name][p].call(name, socket, command); - } -} - -Plugins.prototype.load = function(name, file) { - this._plugins[name][file] = require(file); + load(name, file) + { + this._plugins[name][file] = require(file); + } } module.exports = Plugins; diff --git a/src/Room.js b/src/Room.js index f943baf..95184b1 100644 --- a/src/Room.js +++ b/src/Room.js @@ -1,53 +1,59 @@ var sets = require('simplesets'); - -function Room(id, server) { - this.server = server; - this.id = id; - this._sessions = new sets.Set(); - if (global.config.multiprocess.enabled) { - this.sub = server.redis.sub; - this.pub = server.redis.pub; - // subscribe from here, then have a global handler that hands off to room - this.sub.psubscribe(id + ':*'); +class Room +{ + constructor(id, server) { + this.server = server; + this.id = id; + this._sessions = new sets.Set(); + if (global.config.multiprocess.enabled) { + this.sub = server.redis.sub; + this.pub = server.redis.pub; + // subscribe from here, then have a global handler that hands off to room + this.sub.psubscribe(id + ':*'); + } } -} -module.exports = Room; + addSession(session) + { + this._sessions.add(session); + } + removeSession(session) + { + this._sessions.remove(session); + } -Room.prototype.addSession = function(session) { - this._sessions.add(session); -}; + isEmpty() + { + return this._sessions.size() === 0; + } -Room.prototype.removeSession = function(session) { - this._sessions.remove(session); -}; + emitFromChannel(message) + { + this._sessions.each(function(s) { + s.send(message); + }); + } -Room.prototype.isEmpty = function() { - return this._sessions.size() === 0; + emit(event, data, relay) + { + relay = relay || true; + if (!global.config.multiprocess.enabled) relay = false; + var packet = JSON.stringify({method:event, data: data}) + "\r\n"; + // relay is a boolean switch to control whether the data + // should be relayed to the redis channel for this room + if (relay) + this.pub.publish(this.id + ':' + this.server.workerId, packet); + + this._sessions.each(function(s) { + //Dont echo events back to originiating session + if(data.userId === s.id) { + return; + } + s.send(packet); + }); + } } -Room.prototype.emitFromChannel = function(message) { - this._sessions.each(function(s) { - s.send(message); - }); -}; - -Room.prototype.emit = function(event, data, relay) { - relay = relay || true; - if (!global.config.multiprocess.enabled) relay = false; - var packet = JSON.stringify({method:event, data: data}) + "\r\n"; - // relay is a boolean switch to control whether the data - // should be relayed to the redis channel for this room - if (relay) - this.pub.publish(this.id + ':' + this.server.workerId, packet); - - this._sessions.each(function(s) { - //Dont echo events back to originiating session - if(data.userId === s.id) { - return; - } - s.send(packet); - }); -}; +module.exports = Room; diff --git a/src/Server.js b/src/Server.js index d5a2e5a..642ed60 100644 --- a/src/Server.js +++ b/src/Server.js @@ -26,62 +26,6 @@ var Room = require('./Room'); var Plugins = require('./Plugins'); var redis = require('redis'); -function Server() { - var d = new Date(); - this._sessions = new sets.Set(); - this._rooms = {}; - this.workerId = process.pid.toString(); - console.log(this.workerId, 'started'); - if (global.config.multiprocess.enabled) { - this.redisClient = redis.createClient(config.redis); - this.redis = { - pub: redis.createClient(config.redis), - sub: redis.createClient(config.redis) - } - this.redis.sub.on("pmessage", (pattern, channel, message) => { - var split = channel.split(':'); - if (split[1] !== this.workerId && this._rooms[split[0]] !== undefined) { - this._rooms[split[0]].emitFromChannel(message); - } - }); - } - this.userListHandler = { - set: function(obj, prop, val) { - obj[prop] = val; - this.saveUserList(); - }.bind(this), - deleteProperty: function(obj, prop) { - delete obj[prop]; - this.saveUserList(); - }.bind(this) - }; - - this._userList = new Proxy({}, this.userListHandler); - this._partyList = {}; - this._plugins = new Plugins(this); - this.savePartyList(); - - this.isNameFree = global.config.multiprocess.enabled ? isNameFreeMulti.bind(this) : isNameFreeSingle.bind(this); -} - -Server.prototype.getRoom = function (roomId) { - if (this._rooms[roomId] === undefined) { - this._rooms[roomId] = new Room(roomId, this); - } - - return this._rooms[roomId]; -}; - -Server.prototype.saveUserList = function () { - if (global.config.multiprocess.enabled) - this.redisClient.hmset("multi:userlist", this.workerId, JSON.stringify(this._userList)); -}; - -Server.prototype.savePartyList = function() { - if (global.config.multiprocess.enabled) - this.redisClient.hmset("multi:partylist", this.workerId, JSON.stringify(this._partyList)); -}; - function isNameFreeMulti(name, cb) { var free = true; this.redisClient.hgetall('multi:userlist', (err, obj) => { @@ -108,113 +52,174 @@ function isNameFreeSingle(name, cb) { return cb(null, free); } -// ## Start Socket Server ## -Server.prototype.start = function (callback) { - - this.server = net.createServer(this.onConnect.bind(this)); - this.server.listen(config.port, "::", function (err) { - - if (err) { - log.error('Socket Server error listening on port: ' + config.port); - process.exit(1); +class Server +{ + constructor() + { + var d = new Date(); + this._sessions = new sets.Set(); + this._rooms = {}; + this.workerId = process.pid.toString(); + console.log(this.workerId, 'started'); + if (global.config.multiprocess.enabled) { + this.redisClient = redis.createClient(config.redis); + this.redis = { + pub: redis.createClient(config.redis), + sub: redis.createClient(config.redis) + } + this.redis.sub.on("pmessage", (pattern, channel, message) => { + var split = channel.split(':'); + if (split[1] !== this.workerId && this._rooms[split[0]] !== undefined) { + this._rooms[split[0]].emitFromChannel(message); + } + }); } + this.userListHandler = { + set: function(obj, prop, val) { + obj[prop] = val; + this.saveUserList(); + }.bind(this), + deleteProperty: function(obj, prop) { + delete obj[prop]; + this.saveUserList(); + }.bind(this) + }; + + this._userList = new Proxy({}, this.userListHandler); + this._partyList = {}; + this._plugins = new Plugins(this); + this.savePartyList(); + + this.isNameFree = global.config.multiprocess.enabled ? isNameFreeMulti.bind(this) : isNameFreeSingle.bind(this); + } - log.info('Socket Server listening on port: ' + config.port); - console.log('Socket Server listening on port: ' + config.port); - - }); + getRoom(roomId) + { + if (this._rooms[roomId] === undefined) { + this._rooms[roomId] = new Room(roomId, this); + } + + return this._rooms[roomId]; + } - if (config.ssl) { + saveUserList() + { + if (global.config.multiprocess.enabled) + this.redisClient.hmset("multi:userlist", this.workerId, JSON.stringify(this._userList)); + } - this.ssl = tls.createServer(config.ssl.options, this.onConnect.bind(this)); - this.ssl.listen(config.ssl.port, "::", function (err) { + savePartyList() + { + if (global.config.multiprocess.enabled) + this.redisClient.hmset("multi:partylist", this.workerId, JSON.stringify(this._partyList)); + } + // ## Start Socket Server ## + start(callback) { + this.server = net.createServer(this.onConnect.bind(this)); + this.server.listen(config.port, "::", function (err) { + if (err) { - log.error('SSL Server error listening on port: ' + config.ssl.port); + log.error('Socket Server error listening on port: ' + config.port); process.exit(1); } - - console.log('SSL Server listening on port: ' + config.ssl.port); - log.info('SSL Server listening on port: ' + config.ssl.port); - + + log.info('Socket Server listening on port: ' + config.port); + console.log('Socket Server listening on port: ' + config.port); + }); - } - - if (callback && typeof(callback) == "function") - callback(); -}; - - - -Server.prototype.close = function(cb) { - if (this.redisClient) this.redisClient.quit(); - this.server.close( (err) => { - return cb(err); - }); -} - - -// ## action on client connection ## -Server.prototype.onConnect = function (socket) { - var self = this; - var addr = socket.remoteAddress; - var s; - - log.info('Client connected ' + addr + ' pid: ' + process.pid); - - // setup for websocket - var driver = websocket.server({'protocols': 'binary'}); - socket.on('error', function (err) { - log.error(addr); - log.error('Socket error: ', err); - }); - - socket.on('close', function () { - log.info('Client disconnected: ' + addr); - if (s) { - self._sessions.remove(s); - s = null; - } - }); - /* disable until timeout is set - socket.on('timeout', function() { - log.info('Client timed out: ' + addr); - if (s) - self._sessions.remove(s); - socket.destroy(); - }); - */ - socket.once('data', function (data) { - // try to parse the packet as http - var request = parser.parseRequest(data.toString()); - - if (Object.keys(request.headers).length === 0) - { - // there are no http headers, this is a raw tcp connection - s = new Session(self, socket); - self._sessions.add(s); - - // emit the first message so the session gets it - socket.emit('data', data); + if (config.ssl) { + + this.ssl = tls.createServer(config.ssl.options, this.onConnect.bind(this)); + this.ssl.listen(config.ssl.port, "::", function (err) { + + if (err) { + log.error('SSL Server error listening on port: ' + config.ssl.port); + process.exit(1); + } + + console.log('SSL Server listening on port: ' + config.ssl.port); + log.info('SSL Server listening on port: ' + config.ssl.port); + + }); } - }); - - driver.on('connect', function () { - if (websocket.isWebSocket(driver)) { - log.info('Websocket connection:', addr); - driver.start(); + + if (callback && typeof(callback) == "function") + callback(); + } - s = new Session(self, new WebSocketStream(driver, socket)); - self._sessions.add(s) + close(cb) + { + if (this.redisClient) this.redisClient.quit(); + this.server.close( (err) => { + return cb(err); + }); + } - driver.on('error', function (err) { - log.error(addr); - log.error('Websocket error: ', err); - }); - } - }); - socket.pipe(driver.io).pipe(socket); -}; + // ## action on client connection ## + onConnect(socket) + { + var self = this; + var addr = socket.remoteAddress; + var s; + + log.info('Client connected ' + addr + ' pid: ' + process.pid); + + // setup for websocket + var driver = websocket.server({'protocols': 'binary'}); + + socket.on('error', function (err) { + log.error(addr); + log.error('Socket error: ', err); + }); + + socket.on('close', function () { + log.info('Client disconnected: ' + addr); + if (s) { + self._sessions.remove(s); + s = null; + } + }); + /* disable until timeout is set + socket.on('timeout', function() { + log.info('Client timed out: ' + addr); + if (s) + self._sessions.remove(s); + socket.destroy(); + }); + */ + socket.once('data', function (data) { + // try to parse the packet as http + var request = parser.parseRequest(data.toString()); + + if (Object.keys(request.headers).length === 0) + { + // there are no http headers, this is a raw tcp connection + s = new Session(self, socket); + self._sessions.add(s); + + // emit the first message so the session gets it + socket.emit('data', data); + } + }); + + driver.on('connect', function () { + if (websocket.isWebSocket(driver)) { + log.info('Websocket connection:', addr); + driver.start(); + + s = new Session(self, new WebSocketStream(driver, socket)); + self._sessions.add(s) + + driver.on('error', function (err) { + log.error(addr); + log.error('Websocket error: ', err); + }); + } + }); + socket.pipe(driver.io).pipe(socket); + } +} -module.exports = Server; +module.exports = Server; \ No newline at end of file diff --git a/src/Session.js b/src/Session.js index 9918cc0..04782b1 100644 --- a/src/Session.js +++ b/src/Session.js @@ -5,107 +5,118 @@ var CRLF = "\r\n"; const okayMessage = JSON.stringify({"method": "okay"}) + CRLF; var getMiddleware = require('./MethodMiddleware'); -function Session(server, socket) { - - var self = this; - - this._socket = socket; - - this._userLocked = false; - this._authed = false; - - this._server = server; - this._rooms = []; - this._usernames = []; - - this.id = null; - this.currentRoom = null; - - this.methods = getMiddleware(this); - byline(socket).on('data', this.parseMessage.bind(this)); - - socket.on('close', function() { - // let's remove the userId from the online list - delete self._server._userList[self.id]; - delete self._server._partyList[self.id]; - self._server.savePartyList(); - if ( self.currentRoom ) { - self.currentRoom.emit('user_disconnected', { userId:self.id }); - } - - self._rooms.forEach(function(room) { - room.removeSession(self); +class Session +{ + constructor(server, socket) + { + var self = this; + + this._socket = socket; + + this._userLocked = false; + this._authed = false; + + this._server = server; + this._rooms = []; + this._usernames = []; + + this.id = null; + this.currentRoom = null; + + this.methods = getMiddleware(this); + byline(socket).on('data', this.parseMessage.bind(this)); + + socket.on('close', function() { + // let's remove the userId from the online list + delete self._server._userList[self.id]; + delete self._server._partyList[self.id]; + self._server.savePartyList(); + if ( self.currentRoom ) { + self.currentRoom.emit('user_disconnected', { userId:self.id }); + } + + self._rooms.forEach(function(room) { + room.removeSession(self); + }); }); - }); -}; - - -Session.prototype.makeMessage = function(method, data) { - return JSON.stringify({method: method, data: data}) + CRLF; -} - -Session.prototype.makeError = function(data) { - return JSON.stringify({method: "error", data: {message: data}}) + CRLF; -}; - -module.exports = Session; + } -Session.prototype.send = function(message) { - if (!this._socket.destroyed) - this._socket.write(message); -}; + makeMessage(method, data) + { + return JSON.stringify({method: method, data: data}) + CRLF; + } -Session.prototype.clientError = function(message) { - log.error('Client error ('+this._socket.remoteAddress + ', ' + (this.id || 'Unnamed') + '): ' + message); - this.send(this.makeError(message)); -}; + makeError(data) + { + return JSON.stringify({method: "error", data: {message: data}}) + CRLF; + } -Session.prototype.clientOkay = function() { - this.send(okayMessage); - log.info("S->C:", okayMessage); -} + send(message) + { + if (!this._socket.destroyed) + this._socket.write(message); + } -Session.validMethods = [ - 'logon', - 'subscribe', - 'unsubscribe', - 'enter_room', - 'move', - 'chat', - 'portal', - 'users_online', - 'get_partylist', -]; + clientError(message) + { + log.error('Client error ('+this._socket.remoteAddress + ', ' + (this.id || 'Unnamed') + '): ' + message); + this.send(this.makeError(message)); + } -Session.prototype.parseMessage = function(data) { + clientOkay() + { + this.send(okayMessage); + log.info("S->C:", okayMessage); + } + + static get validMethods() + { + return [ + 'logon', + 'subscribe', + 'unsubscribe', + 'enter_room', + 'move', + 'chat', + 'portal', + 'users_online', + 'get_partylist', + ]; + } - //log.info('C->S: ' + data); + parseMessage(data) + { + //log.info('C->S: ' + data); - var payload; + var payload; - try { - payload = JSON.parse(data); - } - catch(e) { - log.info("data: " + data); - log.info("payload: " + payload); - return this.clientError('Unable to parse last message'); - } + try { + payload = JSON.parse(data); + } + catch(e) { + log.info("data: " + data); + log.info("payload: " + payload); + return this.clientError('Unable to parse last message'); + } - if(Session.validMethods.indexOf(payload.method) === -1) - return this.clientError('Invalid method: ' + payload.method); + if(Session.validMethods.indexOf(payload.method) === -1) + return this.clientError('Invalid method: ' + payload.method); - if(payload.method !== 'logon' && !this._authed ) - return this.clientError('You must call "logon" before sending any other commands.'); + if(payload.method !== 'logon' && !this._authed ) + return this.clientError('You must call "logon" before sending any other commands.'); - if(payload.data === undefined) payload.data = {}; - if(typeof(payload.data)!= "object") payload.data = { "data": payload.data }; - payload.data._userId = this.id; - payload.data._userList = this._server._userList; - payload.data._roomEmit = (method, data) => { this.currentRoom.emit(method, data) }; - this.methods[payload.method](payload.data); -}; + if(payload.data === undefined) payload.data = {}; + if(typeof(payload.data)!= "object") payload.data = { "data": payload.data }; + payload.data._userId = this.id; + payload.data._userList = this._server._userList; + payload.data._roomEmit = (method, data) => { this.currentRoom.emit(method, data) }; + this.methods[payload.method](payload.data); + } -Session.prototype.get_partylist = function(data) { - this.send(this.makeMessage('get_partylist', this._server._partyList)); + get_partylist(data) + { + this.send(this.makeMessage('get_partylist', this._server._partyList)); + } } + +module.exports = Session; diff --git a/src/WebSocketStream.js b/src/WebSocketStream.js index d3ce028..6183d90 100644 --- a/src/WebSocketStream.js +++ b/src/WebSocketStream.js @@ -1,35 +1,40 @@ var Stream = require('stream'), util = require('util'); -function WebSocketStream(driver, socket) { - Stream.call(this); - this.destroyed = false; - this._driver = driver; - this._socket = socket; - this.readable = this.writable = true; - - this.localAddress = socket.localAddress; - this.localPort = socket.localPort; - - this.remoteFamily = socket.remoteFamily; - this.remoteAddress = socket.remoteAddress; - this.remotePort = socket.remotePort; +class WebSocketStream +{ + constructor(driver, socket) + { + Stream.call(this); + this.destroyed = false; + this._driver = driver; + this._socket = socket; + this.readable = this.writable = true; - this._driver.on('message', function(message) { - this.emit('data', message.data); - }.bind(this)); - - - this._driver.on('close', function() { - this.emit('close'); - this.destroyed = true; - }.bind(this)); + this.localAddress = socket.localAddress; + this.localPort = socket.localPort; + + this.remoteFamily = socket.remoteFamily; + this.remoteAddress = socket.remoteAddress; + this.remotePort = socket.remotePort; + + this._driver.on('message', function(message) { + this.emit('data', message.data); + }.bind(this)); + + + this._driver.on('close', function() { + this.emit('close'); + this.destroyed = true; + }.bind(this)); + } + + write(message) + { + this._driver.text(message); + } } util.inherits(WebSocketStream, Stream); -module.exports = WebSocketStream; - -WebSocketStream.prototype.write = function(message) { - this._driver.text(message); -} +module.exports = WebSocketStream; \ No newline at end of file From 6ca6c106f447e3480005e3cf8d75cf292245b5bc Mon Sep 17 00:00:00 2001 From: Alonzo Coeus Date: Sun, 6 Jan 2019 13:27:11 +0000 Subject: [PATCH 2/2] Update Server.js return trueish :) --- src/Server.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Server.js b/src/Server.js index 642ed60..de288e2 100644 --- a/src/Server.js +++ b/src/Server.js @@ -78,10 +78,12 @@ class Server set: function(obj, prop, val) { obj[prop] = val; this.saveUserList(); + return true; }.bind(this), deleteProperty: function(obj, prop) { - delete obj[prop]; + delete obj[prop]; this.saveUserList(); + return true; }.bind(this) };