Jatong Su
Jatong Su

Reputation: 33

How can I make a timer on the backend that is unique to every user which can be cleared using socketio events

I am making a turn based multiplayer game using the MERN stack and SocketIO. I want each player to have 60 seconds to play their turn before the game kicks them out. Once that player plays I want the timer to be canceled. I have tried creating a setTimeout function for each player in the game and then using clearTimeout to cancel the timer based on socketIO events, but the timers don't actually get canceled. It could be an implementation problem, so I was wondering what is the best way to implement this functionality? Here's my current implementation:

socket.on('Start Countdown', () => {
    let user = getUser(socket.id);
    user.countDown = setTimeout(() => {
      socket.emit('Error', { error: { msg: 'You took too long' } });
      socket.emit('AFK');
    }, 60000);
  });
  socket.on('Stop Countdown', () => {
    let user = getUser(socket.id);
    if (user.countDown) {
      clearTimeout(user.countDown);
      console.log(user.countDown);
    }
    console.log(user.countDown);
  });

As mentioned earlier, when "Stop Countdown" happens, the timer doesn't get canceled. Note: getUser returns a js object, user, of the form {socketId, userId, roomId, countDown} from a users array based on the provided socket.id. There will be no two elements in that array with the same userId and upon refresh, the socketId element will get updated to the correct socket.id. So you can assume that getUser will return the same user object every time, even after refresh.

Upvotes: 0

Views: 1208

Answers (2)

alain00
alain00

Reputation: 171

I don't know how getUser works, but if fetching from a database the user var is destroyed when the Start Countdown event ends, you can try to define an object and assign some unique property of the user such as the id or the username as the key and the timeout as the value:


var timeouts = {} //this must go outside the socket connection event

socket.on('Start Countdown', () => {
    let user = getUser(socket.id);
    //it could be user.id, user.username or some property of user that is unique and unvariable
    timeouts[user.userId] = setTimeout(() => {
      socket.emit('Error', { error: { msg: 'You took too long' } });
      socket.emit('AFK');
    }, 60000);
  });
  socket.on('Stop Countdown', () => {
    let user = getUser(socket.id);
    if (timeouts[user.userId]) {
      clearTimeout(timeouts[user.userId]);
      console.log(timeouts[user.userId]);
    }
    console.log(timeouts[user.userId]);
  });

Upvotes: 0

Rechdan
Rechdan

Reputation: 126

Guess that should work, but you can try defining a new empty object where its ID is the client.id, so you assign it with the setTimeout value, from there you can check if there is a timer already running for that user or cancel it at the end.

const timers = {};

socket.on('Start Countdown', () => {
    if (typeof timers[socket.id] !== 'undefined') {
        clearTimeout(timers[socket.id]);
    }

    timers[socket.id] = setTimeout(() => {
        socket.emit('Error', { error: { msg: 'You took too long' } });
        socket.emit('AFK');
    }, 60000);
});

socket.on('Stop Countdown', () => {
    if (typeof timers[socket.id] !== 'undefined') {
        clearTimeout(timers[socket.id]);
        delete timers[socket.id];
    }
});

Hope that helps you! 😁

Upvotes: 0

Related Questions