io.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. 'use strict';
  2. /**
  3. * Socket.IO
  4. */
  5. var io = require('socket.io').listen();
  6. var winston = require('./winston');
  7. var games = {};
  8. var timer;
  9. io.sockets.on('connection', function (socket) {
  10. socket.on('start', function (data) {
  11. var token;
  12. var b = new Buffer(Math.random() + new Date().getTime() + socket.id);
  13. token = b.toString('base64').slice(12, 32);
  14. // token is valid for 5 minutes
  15. var timeout = setTimeout(function () {
  16. if (games[token].players.length === 0) {
  17. delete games[token];
  18. socket.emit('token-expired');
  19. }
  20. }, 5 * 60 * 1000);
  21. games[token] = {
  22. 'creator': socket,
  23. 'players': [],
  24. 'interval': null,
  25. 'timeout': timeout
  26. };
  27. socket.emit('created', {
  28. 'token': token
  29. });
  30. });
  31. socket.on('join', function (data) {
  32. var game, color, time = data.time;
  33. if (!(data.token in games)) {
  34. socket.emit('token-invalid');
  35. return;
  36. }
  37. clearTimeout(games[data.token].timeout);
  38. game = games[data.token];
  39. if (game.players.length >= 2) {
  40. socket.emit('full');
  41. return;
  42. } else if (game.players.length === 1) {
  43. if (game.players[0].color === 'black') {
  44. color = 'white';
  45. } else {
  46. color = 'black';
  47. }
  48. winston.log('info', 'Number of currently running games', { '#': Object.keys(games).length });
  49. } else {
  50. var colors = ['black', 'white'];
  51. color = colors[Math.floor(Math.random() * 2)];
  52. }
  53. // join room
  54. socket.join(data.token);
  55. games[data.token].players.push({
  56. 'id': socket.id,
  57. 'socket': socket,
  58. 'color': color,
  59. 'time': data.time - data.increment + 1,
  60. 'increment': data.increment
  61. });
  62. game.creator.emit('ready', {});
  63. socket.emit('joined', {
  64. 'color': color
  65. });
  66. });
  67. socket.on('timer-white', function (data) {
  68. runTimer('white', data.token, socket);
  69. });
  70. socket.on('timer-black', function (data) {
  71. runTimer('black', data.token, socket);
  72. });
  73. socket.on('timer-clear-interval', function (data) {
  74. if (data.token in games) {
  75. clearInterval(games[data.token].interval);
  76. }
  77. });
  78. socket.on('new-move', function (data) {
  79. var opponent;
  80. if (data.token in games) {
  81. opponent = getOpponent(data.token, socket);
  82. if (opponent) {
  83. opponent.socket.emit('move', {
  84. 'move': data.move
  85. });
  86. }
  87. }
  88. });
  89. socket.on('resign', function (data) {
  90. if (data.token in games) {
  91. clearInterval(games[data.token].interval);
  92. io.sockets.in(data.token).emit('player-resigned', {
  93. 'color': data.color
  94. });
  95. }
  96. });
  97. socket.on('rematch-offer', function (data) {
  98. var opponent;
  99. if (data.token in games) {
  100. opponent = getOpponent(data.token, socket);
  101. if (opponent) {
  102. opponent.socket.emit('rematch-offered');
  103. }
  104. }
  105. });
  106. socket.on('rematch-decline', function (data) {
  107. var opponent;
  108. if (data.token in games) {
  109. opponent = getOpponent(data.token, socket);
  110. if (opponent) {
  111. opponent.socket.emit('rematch-declined');
  112. }
  113. }
  114. });
  115. socket.on('rematch-confirm', function (data) {
  116. var opponent;
  117. if (data.token in games) {
  118. for(var j in games[data.token].players) {
  119. games[data.token].players[j].time = data.time - data.increment + 1;
  120. games[data.token].players[j].increment = data.increment;
  121. games[data.token].players[j].color = games[data.token].players[j].color === 'black' ? 'white' : 'black';
  122. }
  123. opponent = getOpponent(data.token, socket);
  124. if (opponent) {
  125. io.sockets.in(data.token).emit('rematch-confirmed');
  126. }
  127. }
  128. });
  129. socket.on('disconnect', function (data) {
  130. var player, opponent, game;
  131. for (var token in games) {
  132. game = games[token];
  133. for (var j in game.players) {
  134. player = game.players[j];
  135. if (player.socket === socket) {
  136. opponent = game.players[Math.abs(j - 1)];
  137. if (opponent) {
  138. opponent.socket.emit('opponent-disconnected');
  139. }
  140. clearInterval(games[token].interval);
  141. delete games[token];
  142. }
  143. }
  144. }
  145. });
  146. socket.on('send-message', function (data) {
  147. if (data.token in games) {
  148. var opponent = getOpponent(data.token, socket);
  149. if (opponent) {
  150. opponent.socket.emit('receive-message', data);
  151. }
  152. }
  153. });
  154. });
  155. function runTimer(color, token, socket) {
  156. var player, time_left, game = games[token];
  157. if (!game) return;
  158. for (var i in game.players) {
  159. player = game.players[i];
  160. if (player.socket === socket && player.color === color) {
  161. clearInterval(games[token].interval);
  162. games[token].players[i].time += games[token].players[i].increment;
  163. return games[token].interval = setInterval(function() {
  164. games[token].players[i].time -= 1;
  165. time_left = games[token].players[i].time;
  166. if (time_left >= 0) {
  167. io.sockets.in(token).emit('countdown', {
  168. 'time': time_left,
  169. 'color': color
  170. });
  171. } else {
  172. io.sockets.in(token).emit('countdown-gameover', {
  173. 'color': color
  174. });
  175. clearInterval(games[token].interval);
  176. }
  177. }, 1000);
  178. }
  179. }
  180. }
  181. function getOpponent(token, socket) {
  182. var player, game = games[token];
  183. for (var j in game.players) {
  184. player = game.players[j];
  185. if (player.socket === socket) {
  186. var opponent = game.players[Math.abs(j - 1)];
  187. return opponent;
  188. }
  189. }
  190. }
  191. module.exports = io;