server.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  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('ipaddress', process.env.OPENSHIFT_NODEJS_IP || '127.0.0.1');
  10. app.set('port', process.env.OPENSHIFT_NODEJS_PORT || 3000);
  11. app.set('views', __dirname + '/views');
  12. app.set('view engine', 'jade');
  13. app.use(express.favicon());
  14. app.use(express.logger('dev'));
  15. app.use(express.bodyParser());
  16. app.use(express.methodOverride());
  17. app.use(express.cookieParser('45710b553b5b7293753d03bd3601f70a'));
  18. app.use(express.session());
  19. app.use(app.router);
  20. app.use(express.static(path.join(__dirname, 'public')));
  21. });
  22. app.configure('development', function() {
  23. app.use(express.errorHandler());
  24. });
  25. app.get('/', function(req, res) {
  26. res.render('index');
  27. });
  28. app.get('/about', function(req, res) {
  29. res.render('about');
  30. });
  31. app.get('/play/:token/:time/:increment', function(req, res) {
  32. res.render('play', {
  33. 'token': req.params.token,
  34. 'time': req.params.time,
  35. 'increment': req.params.increment
  36. });
  37. });
  38. app.get('/logs', function(req, res) {
  39. fs.readFile(__dirname + '/logs/games.log', function (err, data) {
  40. if (err) {
  41. res.redirect('/');
  42. }
  43. res.set('Content-Type', 'text/plain');
  44. res.send(data);
  45. });
  46. });
  47. var server = http.createServer(app).listen(app.get('port'), app.get('ipaddress'), function() {
  48. console.log("Express server listening on port " + app.get('port'));
  49. });
  50. var games = {};
  51. var timer;
  52. /**
  53. * Winston logger
  54. */
  55. winston.add(winston.transports.File, {
  56. filename: __dirname + '/logs/games.log',
  57. handleExceptions: true,
  58. exitOnError: false,
  59. json: false
  60. });
  61. winston.remove(winston.transports.Console);
  62. winston.handleExceptions(new winston.transports.Console());
  63. winston.exitOnError = false;
  64. /**
  65. * Sockets
  66. */
  67. var io = require('socket.io').listen(server, {log: false});
  68. if (process.env.OPENSHIFT_NODEJS_IP) {
  69. io.configure(function(){
  70. io.set('transports', ['websocket']);
  71. });
  72. }
  73. io.sockets.on('connection', function (socket) {
  74. socket.on('start', function (data) {
  75. var token;
  76. var b = new Buffer(Math.random() + new Date().getTime() + socket.id);
  77. token = b.toString('base64').slice(12, 32);
  78. games[token] = {
  79. 'creator': socket,
  80. 'players': [],
  81. 'interval': null
  82. };
  83. socket.emit('created', {
  84. 'token': token
  85. });
  86. });
  87. socket.on('join', function (data) {
  88. var game, color, time = data.time;
  89. if (!(data.token in games)) {
  90. return;
  91. }
  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. opponent.socket.emit('opponent-disconnected');
  192. clearInterval(games[token].interval);
  193. delete games[token];
  194. }
  195. }
  196. }
  197. });
  198. socket.on('send-message', function (data) {
  199. if (data.token in games) {
  200. var opponent = getOpponent(data.token, socket);
  201. opponent.socket.emit('receive-message', data);
  202. }
  203. });
  204. });
  205. function runTimer(color, token, socket) {
  206. var player, time_left, game = games[token];
  207. if (!game) return;
  208. for (var i in game.players) {
  209. player = game.players[i];
  210. if (player.socket === socket && player.color === color) {
  211. clearInterval(games[token].interval);
  212. games[token].players[i].time += games[token].players[i].increment;
  213. return games[token].interval = setInterval(function() {
  214. games[token].players[i].time -= 1;
  215. time_left = games[token].players[i].time;
  216. if (time_left >= 0) {
  217. io.sockets.in(token).emit('countdown', {
  218. 'time': time_left,
  219. 'color': color
  220. });
  221. } else {
  222. io.sockets.in(token).emit('countdown-gameover', {
  223. 'color': color
  224. });
  225. clearInterval(games[token].interval);
  226. }
  227. }, 1000);
  228. }
  229. }
  230. }
  231. function getOpponent(token, socket) {
  232. var player, game = games[token];
  233. for (var j in game.players) {
  234. player = game.players[j];
  235. if (player.socket === socket) {
  236. var opponent = game.players[Math.abs(j - 1)];
  237. return opponent;
  238. }
  239. }
  240. }