The chat application is built on Node.js utilizing Socket.io and express for real-time client-server communication. The software is designed to handle up to 3 users and the chat doesn't start unless there's a minimum of 3 users connected.The issue lies in the timer logic in the chat application. The timer is supposed to start only when the minimum number of users (3 users) is connected. However, the timer appears to start even with fewer users when a user disconnevts.We have revised the code to ensure checks for minimum users before starting the timer, specifically within the 'disconnect', 'set-username', and 'Input Submit' events. But it seems the timer is still activating with fewer users starting immediatly after the third user leaves the room but freezing when it reaches 1 second , important to note that we didn't test by sending messages we tested by the timer display each user is given 20 seconds to write a message if the timer displayes this means its the user turn There might possibly be an issue with the scope of the variable that is controlling the timer activation ('TimerActive') or the way the timer is initialized and cleared.The goal is to ensure that the timer function (startTurnTimer) only activates when the minimum number of users is connected, and when user disconnects, timer should restart if remaining connected users equal or exceed the minimum, or halt otherwise
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const { Server } = require("socket.io");
const io = new Server(server);
app.use(express.static('public'));
let connectedUsers = [];
let maxUsers = 3;
let minUsers =3;
let turnIndex = 0;
let turnTimer = null;
let TimerActive=false;
const turnTimeout = 20;
function startTurnTimer() {
let remainingTime = turnTimeout;
TimerActive = true;
turnTimer = setInterval(() => {
remainingTime--;
if (remainingTime <= 0) {
io.to(connectedUsers[turnIndex].id).emit('turn-timeout');
NextTurn();
} else {
io.to(connectedUsers[turnIndex].id).emit('timer', remainingTime);
}
}, 1000);
}
function IsMinimum () {
if (connectedUsers.length >= minUsers) {
return true;
} else {
return false;
}
}
function IsTurn (SocketID){
if (connectedUsers[turnIndex] && SocketID === connectedUsers[turnIndex].id){
return true;
} else{
return false;
}
}
function NextTurn (){
if (connectedUsers.length === 0) {
return;
}
turnIndex = (turnIndex + 1) % connectedUsers.length;
}
io.on('connection', (socket) => {
if (connectedUsers.length >= maxUsers) {
console.log('Chat is full, rejecting connection.');
socket.emit('full');
socket.disconnect(true);
return;
}else{
socket.emit('joined');
socket.on('set-username', (username) => {
const user = { id: socket.id, username: username };
connectedUsers.push(user);
console.log('A user connected!', connectedUsers);
socket.emit('user-count', connectedUsers.length);
socket.broadcast.emit('user-count', connectedUsers.length);
if (IsMinimum() && !TimerActive) {
startTurnTimer();
}
});
socket.on('Input Submit', (msg) => {
let UsersCheck=IsMinimum();
let TurnCheck = IsTurn(socket.id);
if (UsersCheck === true) {
io.emit('all_users_connected');
if (TurnCheck === true) {
io.emit('Input Submit', {
msg
});
NextTurn();
startTurnTimer();
} else {
console.log('It is not your turn to send a message.');
socket.emit('no_turn');
}
} else {
socket.emit('no_users');
}
}
);
socket.on('disconnect', () => {
if (IsTurn(socket.id)) {
NextTurn();
}
clearInterval(turnTimer);
turnTimer = null;
TimerActive = false;
if (IsMinimum()) {
startTurnTimer();
}
connectedUsers = connectedUsers.filter(user => user.id !== socket.id);
io.emit('user-count', connectedUsers.length);
socket.broadcast.emit('user-count', connectedUsers.length);
console.log('A user disconnected!');
});
}
});
server.listen(5000, () => {
console.log(' Server listening on port 3000');
});
What I have tried:
i tried multiple things and there is one that partially works ,i separated the code that cleared the timer into its own function and now it solved the issue of timer state not changing after the third user reconnects but there are multiples of issues 1- even when no diconnection happens it appears that the timer is not taking next turns it only executes for the first user and freezes when it reaches 1 and does not move to the next user 2- it appears when i try to diconnect a third user the timer still immediatly starts and takes next turn for a next user until the timer reaches 1 and it doesn't move to the next user 3- when i attempt to reconnect the third user the timer restarts but only for one turn and then it reaches 1 and freezes repeating the same behavior
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const { Server } = require("socket.io");
const io = new Server(server);
app.use(express.static('public'));
let connectedUsers = [];
let maxUsers = 3;
let minUsers =3;
let turnIndex = 0;
let turnTimer = null;
let TimerActive=false;
const turnTimeout = 20;
function startTurnTimer() {
let remainingTime = turnTimeout;
TimerActive = true;
turnTimer = setInterval(() => {
remainingTime--;
if (remainingTime <= 0) {
io.to(connectedUsers[turnIndex].id).emit('turn-timeout');
NextTurn();
} else {
io.to(connectedUsers[turnIndex].id).emit('timer', remainingTime);
}
}, 1000);
}
function IsMinimum () {
if (connectedUsers.length >= minUsers) {
return true;
} else {
return false;
}
}
function IsTurn (SocketID){
if (connectedUsers[turnIndex] && SocketID === connectedUsers[turnIndex].id){
return true;
} else{
return false;
}
}
function NextTurn (){
if (connectedUsers.length === 0) {
return;
}
turnIndex = (turnIndex + 1) % connectedUsers.length;
}
function clearTurnTimer() {
if (turnTimer) {
clearInterval(turnTimer);
turnTimer = null;
TimerActive = false;
}
}
io.on('connection', (socket) => {
if (connectedUsers.length >= maxUsers) {
console.log('Chat is full, rejecting connection.');
socket.emit('full');
socket.disconnect(true);
return;
}else{
socket.emit('joined');
socket.on('set-username', (username) => {
const user = { id: socket.id, username: username };
connectedUsers.push(user);
console.log('A user connected!', connectedUsers);
socket.emit('user-count', connectedUsers.length);
socket.broadcast.emit('user-count', connectedUsers.length);
clearTurnTimer();
if (IsMinimum() && !TimerActive) {
startTurnTimer();
}
});
socket.on('Input Submit', (msg) => {
let UsersCheck=IsMinimum();
let TurnCheck = IsTurn(socket.id);
if (UsersCheck === true) {
io.emit('all_users_connected');
if (TurnCheck === true) {
io.emit('Input Submit', {
msg
});
NextTurn();
startTurnTimer();
} else {
console.log('It is not your turn to send a message.');
socket.emit('no_turn');
}
} else {
socket.emit('no_users');
}
}
);
socket.on('disconnect', () => {
if (IsTurn(socket.id)) {
NextTurn();
}
clearTurnTimer();
if (IsMinimum()) {
startTurnTimer();
}
connectedUsers = connectedUsers.filter(user => user.id !== socket.id);
io.emit('user-count', connectedUsers.length);
socket.broadcast.emit('user-count', connectedUsers.length);
console.log('A user disconnected!');
});
}
});
server.listen(5000, () => {
console.log(' Server listening on port 3000');
});