title: Socket.io emitting values inside ES6 class
body: <p>I wonder if any smart individuals could show me how to implement Socket.IO in an OOP environment with ES6 classes. The main problem I keep running into with Socket.io is passing around the server object, in my case called 'io'. Almost every example I've seen of socket.io has been pure spaghetti code, one file with many socket related events and logic. First I tried to pass the server object, io, to new class's constructor, but for some reason you end up with a nasty "RangeError: Maximum call stack size exceeded" error message. Then I've tried to wrap my classes in module.exports function which parameter should contain the io object. Which is fine for the first class. Let's say I pass the io object into my Game, great works as expected. But when I try to reference the io object down to the Round class(Game holds an array of Rounds) I can't. Because that is one hell of a bad practice in NodeJS, require should be global and not inside the modules/functions. So I'm once again back with the same issue.</p>
  
  <p><strong>app.js(where I require the main sockets file)</strong></p>
  
  <pre><code>const io = socketio(server, { origins: '*:*' });
  ...
  require('./sockets')(io);
  </code></pre>
  
  <p><strong>sockets/index.js(where I initialize my game server, and handle incoming messages from client sockets)</strong></p>
  
  <pre><code>const actions = require('../actions.js');
  const chatSockets = require('./chat-sockets');
  const climbServer = require('./climb-server');
  const authFunctions = require('../auth-functions');
  
  module.exports = (io) =&gt; {
      io.on('connection', (client) =&gt; {
          console.log('client connected...');
          // Standard join, verify the requested room; if it exists let the client join it.
          client.on('join', (data) =&gt; {
              console.log(data);
              console.log(`User ${data.username} tries to join ${data.room}`);
              console.log(`Client joined ${data.room}`);
              client.join(data.room);
          });
  
          client.on('disconnect', () =&gt; {
              console.log('Client disconnected');
          });
  
          client.on(actions.CREATE_GAME, (hostParticipant) =&gt; {
              console.log('CREATE_GAME', hostParticipant);
  
              // Authorize socket sender by token?
              // Create a new game, and set the host to the host participant
              climbServer.createGame(io, hostParticipant);
          });
  
          client.on(actions.JOIN_GAME, (tokenizedGameId) =&gt; {
              console.log('JOIN_GAME');
  
              const user = authFunctions.getPayload(tokenizedGameId.token);
  
              // Authorize socket sender by token?
              // Create a new game, and set the host to the host participant
              const game = climbServer.findGame(tokenizedGameId.content);
              game.joinGame(user);
          });
      });
  };
  </code></pre>
  
  <p><strong>climbServer.js(My game server that keeps track of active games)</strong></p>
  
  <pre><code>const actions = require('../actions.js');
  const Game = require('../models/game');
  
  const climbServer = { games: { }, gameCount: 0 };
  
  climbServer.createGame = (io, hostParticipant) =&gt; {
      // Create a new game instance
      const newGame = new Game(hostParticipant);
      console.log('New game object created', newGame);
  
      // Store it in the list of game
      climbServer.games[newGame.id] = newGame;
  
      // Keep track
      climbServer.gameCount += 1;
  
      // Notify clients that a new game was created
      io.sockets.in('climb').emit(actions.CLIMB_GAME_CREATED, newGame);
  };
  
  climbServer.findGame = gameId =&gt; climbServer.games[gameId];
  
  module.exports = climbServer;
  </code></pre>
  
  <p><strong>Game.js(ES6 class that SHOULD be able to emit to all connected sockets)</strong></p>
  
  <pre><code>const UUID = require('uuid');
  const Round = require('./round');
  
  class Game {
      // Constructor
      constructor(hostParticipant) {
          this.id = UUID();
          this.playerHost = hostParticipant;
          this.playerClient = null;
          this.playerCount = 1;
          this.rounds = [];
          this.timestamp = Date.now();
      }
  
      joinGame(clientParticipant) {
          console.log('Joining game', clientParticipant);
          this.playerClient = clientParticipant;
          this.playerCount += 1;
  
          // Start the game by creating the first round
          return this.createRound();
      }
  
      createRound() {
          console.log('Creating new round at Game: ', this.id);
          const newRound = new Round(this.id);
  
          return this.rounds.push(newRound);
      }
  }
  
  module.exports = Game;
  </code></pre>
  
  <p><strong>Round.js(ES6 class that is used by the Game class(stored in a rounds array))</strong></p>
  
  <pre><code>const actions = require('../actions.js');
  
  class Round {
      constructor(gameId) {
          console.log('Initializing round of gameId', gameId);
          this.timeLeft = 60;
          this.gameId = gameId;
          this.winner = null;
          this.timestamp = Date.now();
  
          // Start countdown when class is instantiated
          this.startCountdown();
      }
  
      startCountdown() {
          const countdown = setInterval(() =&gt; {
              // broadcast to every client
              io.sockets.in(this.gameId).emit(actions.ROUND_TIMER, { gameId: this.gameId, timeLeft: this.timeLeft });
              if (this.timeLeft === 0) {
                  // when no time left, stop counting down
                  clearInterval(countdown);
                  this.onRoundEnd();
              } else {
                  // Countdown
                  this.timeLeft -= 1;
                  console.log('Countdown', this.timeLeft);
              }
          }, 1000);
      }
  
      onRoundEnd() {
          // Evaluate who won
          console.log('onRoundEnd: ', this.gameId);
      }
  }
  
  module.exports = Round;
  </code></pre>
  
  <p><strong>TO SUMMARIZE with a question: How can I pass a reference of io to my classes so that I'm able to emit to connected sockets within these classes?</strong>
  This doesn't necessarily have to be ES6 classes, it can be NodeJS objects using the .prototype property. I just want a mainatainable way to handle my game server with sockets... ANY HELP IS APPRECIATED!</p>