UNPKG

jok-play

Version:

creating online games never was so easy

601 lines (485 loc) 17.9 kB
var Helper = (function () { function Helper() { } Helper.SendMail = function (to, subject, body) { try { if (!Helper.pluginSendgrid) { var sendgrid = require('sendgrid'); if (sendgrid) Helper.pluginSendgrid = sendgrid(process.env.SENDGRID_USERNAME, process.env.SENDGRID_PASSWORD); } } catch (err) { return; } if (!Helper.pluginSendgrid) return; var sendObject = { to: to, from: 'no-reply@jok.io', subject: subject, text: body }; var errorSending = function (err, json) { if (err) { return console.error('Sendmail failed', err); } }; Helper.pluginSendgrid.send(sendObject, errorSending); }; Helper.HttpGet = function (url, cb, parseJson) { if (typeof parseJson === "undefined") { parseJson = false; } try { if (!Helper.pluginHttp) { Helper.pluginHttp = require('http'); } } catch (err) { return; } if (!Helper.pluginHttp) return; Helper.pluginHttp.get(url, function (res) { var data = ''; res.on('data', function (chunk) { data += chunk; }); res.on('end', function () { if (parseJson) { try { var oldData = data; data = JSON.parse(data); } catch (err) { cb && cb(false, err.message, oldData); } } cb && cb(true, data); }); }).on('error', function (e) { cb && cb(false, e.message, e); }); }; Helper.ChannelSockets = function (channel) { if (!Helper.IO || !Helper.IO.adapter) return; var channelClients = Helper.IO.adapter().clients(channel); var result = []; for (var id in channelClients) { var client_sid = channelClients[id]; if (!client_sid) continue; var socket = Helper.IO.clients[client_sid]; if (!socket) continue; result.push(socket); } return result; }; Helper.SaveErrorLog = function (err) { try { if (!Helper.pluginMongojs) { Helper.pluginMongojs = require('mongojs'); } } catch (err) { return; } if (!process.env.MONGOHQ_URL) return; try { var db = Helper.pluginMongojs(process.env.MONGOHQ_URL, ['ErrorLog']); db.ErrorLog.save({ Error: err, Stack: err.stack, CreateDate: Date.now() }, function (err) { return err && console.log(err); }); } catch (err) { console.log(err); } }; Helper.FinishGame = function (obj, cb) { try { if (!Helper.pluginHttp) { Helper.pluginHttp = require('http'); } } catch (err) { return; } var userString = JSON.stringify(obj); var headers = { 'Content-Type': 'application/json', 'Content-Length': userString.length }; var options = { hostname: 'api.jok.io', port: 80, path: '/game/finish', method: 'POST', headers: headers }; var req = Helper.pluginHttp.request(options, function (res) { var result = ''; res.setEncoding('utf8'); res.on('data', function (chunk) { return result += chunk; }); res.on('end', function () { try { result = JSON.parse(result); } catch (err) { } cb && cb(null, result); }); }); req.on('error', function (err) { return cb && cb(err); }); req.write(userString); req.end(); }; return Helper; })(); Array.prototype.unique = function () { var arr = []; for (var i = 0; i < this.length; i++) { if (!arr.contains(this[i])) { arr.push(this[i]); } } return arr; }; Array.prototype.contains = function (v) { for (var i = 0; i < this.length; i++) { if (this[i] === v) return true; } return false; }; Array.prototype.remove = function (item) { var index = this.indexOf(item); if (index == -1) return false; this.splice(index, 1); return true; }; var GamePlayerBase = (function () { function GamePlayerBase(UserID, IPAddress, IsVIP, IsOnline) { this.UserID = UserID; this.IPAddress = IPAddress; this.IsVIP = IsVIP; this.IsOnline = IsOnline; this.HasAnyMoveMade = false; } GamePlayerBase.prototype.send = function (command) { var params = []; for (var _i = 0; _i < (arguments.length - 1); _i++) { params[_i] = arguments[_i + 1]; } if (!this.IsOnline) return; var sockets = Helper.ChannelSockets('User' + this.UserID); if (!sockets) return; params.unshift(command); var cmd = JSON.stringify(params); sockets.forEach(function (s) { return s.send(cmd); }); }; return GamePlayerBase; })(); var GameTableBase = (function () { function GameTableBase(GamePlayerClass, Channel, Mode, MaxPlayersCount, IsVIPTable) { if (typeof Channel === "undefined") { Channel = ''; } if (typeof Mode === "undefined") { Mode = 0; } if (typeof MaxPlayersCount === "undefined") { MaxPlayersCount = 2; } if (typeof IsVIPTable === "undefined") { IsVIPTable = false; } this.GamePlayerClass = GamePlayerClass; this.Channel = Channel; this.Mode = Mode; this.MaxPlayersCount = MaxPlayersCount; this.IsVIPTable = IsVIPTable; this.Status = 0 /* New */; this.ID = require('node-uuid').v4(); this.Players = []; } GameTableBase.prototype.join = function (user, ipaddress, channel, mode) { var player = this.Players.filter(function (p) { return p.UserID == user.UserID; })[0]; if (!player) player = new this.GamePlayerClass(user.UserID, ipaddress, user.IsVIP, true); player.IsOnline = true; switch (this.Status) { case 0 /* New */: { if (!this.Players.contains(player)) { this.Players.push(player); this.playersChanged(); } if (this.Players.length == this.MaxPlayersCount) { this.start(); } } break; case 1 /* Started */: case 2 /* StartedWaiting */: { if (!this.Players.contains(player)) return; this.Status = 1 /* Started */; this.playersChanged(); } break; } return player; }; GameTableBase.prototype.leave = function (userid) { var player = this.Players.filter(function (p) { return p.UserID == userid; })[0]; if (player == null) return; player.IsOnline = false; switch (this.Status) { case 0 /* New */: { this.Players.remove(player); this.playersChanged(); } break; case 1 /* Started */: { if (this.Players.filter(function (p) { return p.HasAnyMoveMade; }).length != 2) { this.Status = 0 /* New */; this.Players.remove(player); this.playersChanged(); break; } this.Status = 2 /* StartedWaiting */; this.playersChanged(); } break; case 3 /* Finished */: { this.Players.remove(player); this.playersChanged(); } break; } return player; }; GameTableBase.prototype.start = function () { }; GameTableBase.prototype.finish = function () { }; GameTableBase.prototype.playersChanged = function () { }; GameTableBase.prototype.send = function (command) { var params = []; for (var _i = 0; _i < (arguments.length - 1); _i++) { params[_i] = arguments[_i + 1]; } params.unshift(command); this.Players.forEach(function (p) { return p.send.apply(p, params); }); }; GameTableBase.prototype.getNextPlayer = function (player) { if (this.Players.length <= 1) return; if (!player) player = this.ActivePlayer; if (!player) return; var index = this.Players.indexOf(player); return this.Players[index < this.Players.length - 1 ? ++index : 0]; }; return GameTableBase; })(); var TableStatus; (function (TableStatus) { TableStatus[TableStatus["New"] = 0] = "New"; TableStatus[TableStatus["Started"] = 1] = "Started"; TableStatus[TableStatus["StartedWaiting"] = 2] = "StartedWaiting"; TableStatus[TableStatus["Finished"] = 3] = "Finished"; })(TableStatus || (TableStatus = {})); var engine = require('engine.io'); var engineRooms = require('engine.io-rooms'); var http = require('http'); var urlParser = require('url'); var Server = (function () { function Server(port, GameTableClass, GamePlayerClass) { if (typeof port === "undefined") { port = process.env.PORT || 9003; } var _this = this; this.port = port; this.GameTableClass = GameTableClass; this.GamePlayerClass = GamePlayerClass; this.GameTables = []; this.UsersCount = 0; var server = http.createServer(this.httpHandler.bind(this)); this.io = engine.attach(server); this.io = engineRooms(this.io); Helper.IO = this.io; this.StartTime = Date.now(); this.io.on('connection', this.onConnectionOpen.bind(this)); server.listen(this.port, function () { console.log('server listening at port:', _this.port); }); Helper.SendMail('status-update@jok.io', 'jok-realtime-server started', 'StartTime: ' + new Date()); } Server.prototype.httpHandler = function (req, res) { var urlInfo = urlParser.parse(req.url, true); switch (urlInfo.pathname) { case '/stats': { res.end(JSON.stringify({ ConnectionsCount: this.io.clientsCount, UsersCount: this.UsersCount, TablesCount: this.GameTables.length, Uptime: (Date.now() - this.StartTime) / (1000 * 60) + ' min.' })); } break; default: { res.end('Hi, Bye'); } break; } }; Server.prototype.onConnectionOpen = function (socket) { var _this = this; var sid = socket.request.query.token; var gameid = socket.request.query.gameid; var gamemode = socket.request.query.gamemode; var channel = socket.request.query.channel; var ipaddress = socket.request.headers["x-forwarded-for"]; if (!channel) channel = ''; channel = channel.toLowerCase(); if (ipaddress) { var list = ipaddress.split(","); ipaddress = list[list.length - 1]; } else { ipaddress = socket.request.connection.remoteAddress; } if (!sid || !ipaddress || !gameid) return; var userid; var disconnected; var gameTable; var url = Server.API_ROOT_URL + 'User/InfoBySID?sid=' + sid + '&ipaddress=' + ipaddress + '&gameid=' + gameid; Helper.HttpGet(url, function (isSuccess, data) { if (!isSuccess || !data.UserID || disconnected) return; userid = data.UserID; _this.UsersCount++; var userChannel = 'User' + userid; var oldConnections = Helper.ChannelSockets(userChannel); socket.join(userChannel); if (oldConnections) oldConnections.forEach(function (c) { return c.close(); }); gameTable = _this.findTable(data, channel, gamemode); if (!gameTable) { console.log('GameTable not found, it must not happen. Passed parameters:', channel, gamemode); return; } socket.send(JSON.stringify(['UserAuthenticated', userid])); gameTable.join(data, ipaddress, channel, gamemode); }, true); socket.on('message', function (msg) { if (!userid || !gameTable || !msg) return; try { if (typeof msg == 'string') msg = JSON.parse(msg); } catch (err) { } if (Object.prototype.toString.call(msg) !== '[object Array]') { return; } if (!msg.length) return; var command = msg.shift(); var params = msg; if (!command) { console.log('Every message must have "command" and optionaly "params" properties'); return; } var reservedWords = ['Join', 'Leave']; if (command in reservedWords) { console.log('Reserved words cant be used as command:', reservedWords); return; } command = 'on' + command; if (typeof gameTable[command] != 'function') { console.log('GameTable method not found with name:', command); return; } params.unshift(userid); gameTable[command].apply(gameTable, params); }); socket.on('close', function () { disconnected = true; if (!userid) return; _this.UsersCount--; gameTable && gameTable.leave(userid); if (!gameTable.Players.length || !gameTable.Players.filter(function (p) { return p.IsOnline; }).length) { var index = _this.GameTables.indexOf(gameTable); if (index > -1) _this.GameTables.splice(index, 1); } }); }; Server.prototype.findTable = function (user, channel, mode) { var _this = this; var table = this.GameTables.filter(function (t) { return (t.Players.filter(function (p) { return p.UserID == user.UserID; })[0] != undefined) && (t.Status == 1 /* Started */ || t.Status == 2 /* StartedWaiting */) && (t.Status != 3 /* Finished */); })[0]; if (table) return table; table = this.GameTables.filter(function (t) { return t.Channel == channel && t.Mode == mode && t.Players.length < t.MaxPlayersCount && (t.Status != 1 /* Started */) && (t.Status != 3 /* Finished */) && _this.isTournamentValid(channel, t, user); })[0]; if (table) return table; if (!this.createTable) return; table = this.createTable(user, channel, mode); if (!table) return; this.GameTables.push(table); return table; }; Server.prototype.createTable = function (user, channel, mode) { return new this.GameTableClass(this.GamePlayerClass, channel, mode, 2, this.isTournamentChannel(channel) ? user.IsVIP : false); }; Server.prototype.isTournamentValid = function (channel, table, user) { if (!this.isTournamentChannel(channel)) return true; return (user.IsVIP == table.IsVIPTable); }; Server.prototype.isTournamentChannel = function (channel) { return (channel == 'tournament'); }; Server.Start = function (port, TGameTable, TGamePlayerClass) { return new Server(port, TGameTable, TGamePlayerClass); }; Server.API_ROOT_URL = 'http://api.jok.io/'; return Server; })(); exports.Server = Server; exports.Helper = Helper; exports.GameTableBase = GameTableBase; exports.GamePlayerBase = GamePlayerBase; exports.TableStatus = TableStatus; //# sourceMappingURL=App.js.map