server.js 7.0 KB

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