server.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. var express = require('express')
  2. , favicon = require('serve-favicon')
  3. , bodyParser = require('body-parser')
  4. , logger = require('morgan')
  5. , cookieParser = require('cookie-parser')
  6. , session = require('express-session')
  7. , methodOverride = require('express-method-override')
  8. , errorhandler = require('errorhandler')
  9. , path = require('path')
  10. , crypto = require('crypto')
  11. , http = require('http')
  12. , winston = require('winston')
  13. , fs = require('fs');
  14. var app = express();
  15. app.set('port', process.env.OPENSHIFT_NODEJS_PORT || 8181);
  16. app.set('views', __dirname + '/views');
  17. app.set('view engine', 'jade');
  18. //app.use(favicon());
  19. //app.use(logger('dev'));
  20. app.use(bodyParser());
  21. app.use(methodOverride());
  22. app.use(cookieParser('45710b553b5b7293753d03bd3601f70a'));
  23. app.use(session());
  24. //app.use(app.router);
  25. app.use(express.static(path.join(__dirname, 'public')));
  26. //app.use(errorHandler());
  27. app.get('/', function(req, res) {
  28. res.render('index');
  29. });
  30. app.get('/about', function(req, res) {
  31. res.render('about');
  32. });
  33. app.get('/play/:token/:time/:increment', function(req, res) {
  34. res.render('play', {
  35. 'token': req.params.token,
  36. 'time': req.params.time,
  37. 'increment': req.params.increment
  38. });
  39. });
  40. app.get('/logs', function(req, res) {
  41. fs.readFile(__dirname + '/logs/games.log', function (err, data) {
  42. if (err) {
  43. res.redirect('/');
  44. }
  45. res.set('Content-Type', 'text/plain');
  46. res.send(data);
  47. });
  48. });
  49. var server = http.createServer(app).listen(app.get('port'), app.get('ipaddress'), function() {
  50. console.log("Express server listening on port " + app.get('port'));
  51. });
  52. var games = {};
  53. var timer;
  54. /**
  55. * Sockets
  56. */
  57. var io = require('socket.io').listen(server, {log: false});
  58. if (process.env.OPENSHIFT_NODEJS_IP) {
  59. io.configure(function(){
  60. io.set('transports', ['websocket']);
  61. });
  62. }
  63. io.sockets.on('connection', function (socket) {
  64. socket.on('start', function (data) {
  65. var token;
  66. var b = new Buffer(Math.random() + new Date().getTime() + socket.id);
  67. token = b.toString('base64').slice(12, 32);
  68. //token is valid for 5 minutes
  69. var timeout = setTimeout(function () {
  70. if (games[token].players.length === 0) {
  71. delete games[token];
  72. socket.emit('token-expired');
  73. }
  74. }, 5 * 60 * 1000);
  75. games[token] = {
  76. 'creator': socket,
  77. 'players': [],
  78. 'interval': null,
  79. 'timeout': timeout
  80. };
  81. socket.emit('created', {
  82. 'token': token
  83. });
  84. });
  85. socket.on('join', function (data) {
  86. var game, color, time = data.time;
  87. if (!(data.token in games)) {
  88. socket.emit('token-invalid');
  89. return;
  90. }
  91. clearTimeout(games[data.token].timeout);
  92. game = games[data.token];
  93. if (game.players.length >= 2) {
  94. socket.emit('full');
  95. return;
  96. } else if (game.players.length === 1) {
  97. if (game.players[0].color === 'black') {
  98. color = 'white';
  99. } else {
  100. color = 'black';
  101. }
  102. winston.log('info', 'Number of currently running games', { '#': Object.keys(games).length });
  103. } else {
  104. var colors = ['black', 'white'];
  105. color = colors[Math.floor(Math.random() * 2)];
  106. }
  107. //join room
  108. socket.join(data.token);
  109. games[data.token].players.push({
  110. 'id': socket.id,
  111. 'socket': socket,
  112. 'color': color,
  113. 'time': data.time - data.increment + 1,
  114. 'increment': data.increment
  115. });
  116. game.creator.emit('ready', {});
  117. socket.emit('joined', {
  118. 'color': color
  119. });
  120. });
  121. socket.on('timer-white', function (data) {
  122. runTimer('white', data.token, socket);
  123. });
  124. socket.on('timer-black', function (data) {
  125. runTimer('black', data.token, socket);
  126. });
  127. socket.on('timer-clear-interval', function (data) {
  128. if (data.token in games) {
  129. clearInterval(games[data.token].interval);
  130. }
  131. });
  132. socket.on('new-move', function (data) {
  133. var opponent;
  134. if (data.token in games) {
  135. opponent = getOpponent(data.token, socket);
  136. if (opponent) {
  137. opponent.socket.emit('move', {
  138. 'move': data.move
  139. });
  140. }
  141. }
  142. });
  143. socket.on('resign', function (data) {
  144. if (data.token in games) {
  145. clearInterval(games[data.token].interval);
  146. io.sockets.in(data.token).emit('player-resigned', {
  147. 'color': data.color
  148. });
  149. }
  150. });
  151. socket.on('rematch-offer', function (data) {
  152. var opponent;
  153. if (data.token in games) {
  154. opponent = getOpponent(data.token, socket);
  155. if (opponent) {
  156. opponent.socket.emit('rematch-offered');
  157. }
  158. }
  159. });
  160. socket.on('rematch-decline', function (data) {
  161. var opponent;
  162. if (data.token in games) {
  163. opponent = getOpponent(data.token, socket);
  164. if (opponent) {
  165. opponent.socket.emit('rematch-declined');
  166. }
  167. }
  168. });
  169. socket.on('rematch-confirm', function (data) {
  170. var opponent;
  171. if (data.token in games) {
  172. for(var j in games[data.token].players) {
  173. games[data.token].players[j].time = data.time - data.increment + 1;
  174. games[data.token].players[j].increment = data.increment;
  175. games[data.token].players[j].color = games[data.token].players[j].color === 'black' ? 'white' : 'black';
  176. }
  177. opponent = getOpponent(data.token, socket);
  178. if (opponent) {
  179. io.sockets.in(data.token).emit('rematch-confirmed');
  180. }
  181. }
  182. })
  183. socket.on('disconnect', function (data) {
  184. var player, opponent, game;
  185. for (var token in games) {
  186. game = games[token];
  187. for (var j in game.players) {
  188. player = game.players[j];
  189. if (player.socket === socket) {
  190. opponent = game.players[Math.abs(j - 1)];
  191. if (opponent) {
  192. opponent.socket.emit('opponent-disconnected');
  193. }
  194. clearInterval(games[token].interval);
  195. delete games[token];
  196. }
  197. }
  198. }
  199. });
  200. socket.on('send-message', function (data) {
  201. if (data.token in games) {
  202. var opponent = getOpponent(data.token, socket);
  203. if (opponent) {
  204. opponent.socket.emit('receive-message', data);
  205. }
  206. }
  207. });
  208. });
  209. function runTimer(color, token, socket) {
  210. var player, time_left, game = games[token];
  211. if (!game) return;
  212. for (var i in game.players) {
  213. player = game.players[i];
  214. if (player.socket === socket && player.color === color) {
  215. clearInterval(games[token].interval);
  216. games[token].players[i].time += games[token].players[i].increment;
  217. return games[token].interval = setInterval(function() {
  218. games[token].players[i].time -= 1;
  219. time_left = games[token].players[i].time;
  220. if (time_left >= 0) {
  221. io.sockets.in(token).emit('countdown', {
  222. 'time': time_left,
  223. 'color': color
  224. });
  225. } else {
  226. io.sockets.in(token).emit('countdown-gameover', {
  227. 'color': color
  228. });
  229. clearInterval(games[token].interval);
  230. }
  231. }, 1000);
  232. }
  233. }
  234. }
  235. function getOpponent(token, socket) {
  236. var player, game = games[token];
  237. for (var j in game.players) {
  238. player = game.players[j];
  239. if (player.socket === socket) {
  240. var opponent = game.players[Math.abs(j - 1)];
  241. return opponent;
  242. }
  243. }
  244. }