clearTimeout function does not run - javascript

I've made a quiz game using socket.io. When a new socket connects, this runs:
io.on('connection', function (socket) {
let gameTimer = null;
After receiving a certain socket from the client, this function starts:
gameTimer = setTimeout(function () {
//Reveal if the players' answers are right or wrong
revealAnswer(answeredPlayers, playerData[socket.id].room);
//Start the countdown for the next question
countToNextQuestion(playerData[socket.id].room);
}, 21000)
When a player answers, this socket function runs in the server:
socket.on('Answered Question', function (userAnswer, answeredPlayerUsername, timeAnswered) {
//Stop the count
clearTimeout(gameTimer);
/*
*Extra code below that works...
*/
But this does not stop the timeout. Any reason why this is happening, and how to fix it?
EDIT: Here's the full socket code. It's a bit long, apologies:
io.on('connection', function (socket) {
console.log('Someone connected');
//Will hold the questions used for the session
let gameSessionQuestions = null;
//Holds the current question
let currentQuestion = null;
//Holds the correct answer to the current question
let currentQuestionAnswer = null;
//Give the socket player details
//and add this player to the dictionary
playerData[socket.id] = {
name: null,
room: null,
host: false,
score: 0
};
//Timer for questions
let gameTimer = null;
/*
SOCKET OPERATIONS
*/
socket.on('Get Total Score', async function(playerUsername){
let playerTotalScore = await gameController.getTotalScore(playerUsername);
socket.emit('Receive Total Score', playerTotalScore);
})
//Adds a room to the list of rooms
socket.on('Add Room', function (questionType) {
let newRoom = newRoomCreation(questionType);
//Since this player created the room, assign them the host value
playerData[socket.id].host = true;
playerData[socket.id].room = newRoom;
socket.join(newRoom);
io.sockets.to(newRoom).emit('Room Added', newRoom);
})
//Make the specified room a closed room
socket.on('Close the room', function (room) {
closeRoom(room);
})
socket.on('Room Availability', function (roomCode, questionType) {
if (!roomMap.get(roomCode)) {
socket.emit('Unavailable Room');
}
else {
//Check if the room has the question type the user chose
if (roomQuestionType.get(roomCode) == questionType) {
socket.emit('Available Room');
} else {
socket.emit('Unavailable Room');
}
}
})
socket.on('Open Room Availability', function (questionType) {
let roomFound = false;
for (let room of roomMap.keys()) {
if (!closedRoomsList.includes(room)) {
if (roomQuestionType.get(room) == questionType) {
roomFound = true;
socket.emit('Available Open Room', room);
}
}
}
if (roomFound == false) {
socket.emit('Unavailable Open Room');
}
})
socket.on('Join Room', function (values) {
//Give this player's 'name' variable a value
playerData[socket.id].name = values.p1;
//Give this player's 'room' variable a value
playerData[socket.id].room = values.p2;
//DELETE SOON: Checking the data before addition
console.log("Data in the room '" + values.p2 + "' before addition: ");
console.log(roomMap.get(values.p2));
//Put this player in the new room
socket.join(values.p2);
//Add the player's socketID and Name to the Room Map
let playersList = roomMap.get(values.p2);
playersList.push(values.p1);
//DELETE SOON: Checking the data after addition
console.log("Data in the room '" + values.p2 + "' after addition: ");
console.log(roomMap.get(values.p2));
io.sockets.to(values.p2).emit('Output Players', playersList);
if (playerData[socket.id].host == true) {
io.sockets.to(playerData[socket.id].room).emit('Current Host');
}
})
socket.on('Request Game Start', async function (room) {
//Checks if the user who started the game truly is the host
if (playerData[socket.id].host == false) {
return;
}
//Holds all the questions to be asked and their answers
gameSessionQuestions = await selectedQuestions(2, roomQuestionType.get(room));
//Reset the 'answered player' count
answeredPlayers.set(playerData[socket.id].room, 0);
io.sockets.to(room).emit('Game Start');
})
socket.on('Start Game Countdown', function () {
let pos = 0;
let countArr = ["2", "1", "Go"];
let counter = setInterval(function () {
//Update the count for all those in the room
io.sockets.to(playerData[socket.id].room).emit('Update Countdown', countArr[pos]);
if (pos == countArr.length) {
clearInterval(counter);
io.sockets.to(playerData[socket.id].room).emit('End Countdown');
currentQuestion = getQuestion(gameSessionQuestions[0], playerData[socket.id].room);
io.sockets.to(playerData[socket.id].room).emit('Receive Questions', currentQuestion);
//Holds the answer for the current question
currentQuestionAnswer = currentQuestionCorrectAnswer(gameSessionQuestions[0], playerData[socket.id].room);
//The answer to the question presented in this room is stored here
questionAnswers.set(playerData[socket.id].room, currentQuestionAnswer);
gameTimer = setTimeout(function () {
//Reveal if the players' answers are right or wrong
revealAnswer(answeredPlayers, playerData[socket.id].room);
//Start the countdown for the next question
countToNextQuestion(playerData[socket.id].room);
}, 21000)
} else {
pos++;
}
}, 1000);
})
socket.on('Answered Question', function (userAnswer, answeredPlayerUsername, timeAnswered) {
socket.broadcast.to(playerData[socket.id].room).emit('Display Answered Player', answeredPlayerUsername);
//DELETE SOON: Check the current question
console.log("Current Question's Answer: " + questionAnswers.get(playerData[socket.id].room));
console.log("Your answer: " + userAnswer);
let answerResult;
if (questionAnswers.get(playerData[socket.id].room) === userAnswer) {
answerResult = "btn-success";
//Add to the person's overall score
playerData[socket.id].score = addToScore(playerData[socket.id].score, timeAnswered);
socket.emit('Answer Check', answerResult);
}
else {
answerResult = "btn-danger";
socket.emit('Answer Check', answerResult);
}
//DELETE SOON: Checks the scores for the user
console.log("The score for '" + playerData[socket.id].name + "' is '" + playerData[socket.id].score + "'")
//Add 1 to the number of people who have answered in this room
answeredPlayers.set(playerData[socket.id].room, (answeredPlayers.get(playerData[socket.id].room)) + 1)
//DELETE SOON: Checks if the value is updating
console.log("Number of people who have answered: " + answeredPlayers.get(playerData[socket.id].room))
//If all users in the room have answered...
if (answeredPlayers.get(playerData[socket.id].room) == (roomMap.get(playerData[socket.id].room)).length) {
//DELETE SOON: Outputs message confirming all users answering
console.log("Everyone has answered");
//Stop the count
clearTimeout(gameTimer);
//Reveal if the players' answers are right or wrong
revealAnswer(answeredPlayers, playerData[socket.id].room);
//Start the countdown for the next question
countToNextQuestion(playerData[socket.id].room);
}
})
//Get the next question from the host
socket.on('Find Host', async function () {
if (playerData[socket.id].host == true) {
//DELETE SOON: Check the number of questions before
console.log('Question count before: ' + gameSessionQuestions.length)
gameSessionQuestions.shift();
//DELETE SOON: Check the number of questions after removing the one just asked
console.log('Question count after: ' + gameSessionQuestions.length)
//If there are still questions to be asked, send the next question and set the new correct answer
if (gameSessionQuestions.length != 0) {
//Get the next question and send it
currentQuestion = getQuestion(gameSessionQuestions[0], playerData[socket.id].room);
io.sockets.to(playerData[socket.id].room).emit('Receive Questions', currentQuestion);
//Get this question's correct answer
currentQuestionAnswer = currentQuestionCorrectAnswer(gameSessionQuestions[0], playerData[socket.id].room);
questionAnswers.set(playerData[socket.id].room, currentQuestionAnswer);
gameTimer = setTimeout(function () {
//Reveal if the players' answers are right or wrong
revealAnswer(answeredPlayers, playerData[socket.id].room);
//Start the countdown for the next question
countToNextQuestion(playerData[socket.id].room);
}, 21000)
} else {
//Holds the username and scores for all users in this room
let players_Scores = [];
let roomCode = playerData[socket.id].room;
let playerKeys = Object.keys(playerData);
for (let i = 0; i < playerKeys.length; i++) {
if (playerData[playerKeys[i]].room == roomCode) {
let scoreDetails = {
username: playerData[playerKeys[i]].name,
score: playerData[playerKeys[i]].score
}
players_Scores.push(scoreDetails)
await gameController.uploadScore(playerData[playerKeys[i]].name, playerData[playerKeys[i]].score, roomQuestionType.get(roomCode));
}
}
io.sockets.to(roomCode).emit('Show Scores', players_Scores);
}
}
})
//Remove details while reloading the menu page
socket.on('Back to Start', function () {
//Remove the player from the room in socketio
socket.leave(playerData[socket.id].room);
//If this is the host, delete the room
if (playerData[socket.id].host == true) {
roomMap.delete(playerData[socket.id].room);
roomQuestionType.delete(playerData[socket.id].room);
questionAnswers.delete(playerData[socket.id].room);
answeredPlayers.delete(playerData[socket.id].room);
}
//Remove this player's details
delete playerData[socket.id];
})
socket.on('disconnect', function () {
if (playerData[socket.id] && roomMap.get(playerData[socket.id].room) != undefined) {
//DELETE SOON: Check who left and from which room
console.log(playerData[socket.id].name + " has left the room '" + playerData[socket.id].room + "'");
//If on the lobby page, remove that player and update everyone's lists
let playerList = roomMap.get(playerData[socket.id].room);
playerList.splice(playerList.indexOf(playerData[socket.id].name), 1);
io.sockets.to(playerData[socket.id].room).emit('Output Players', playerList);
/*If this is the host,
* stop game timer
* alert all the players in the room,
* delete the room they were in*/
if (playerData[socket.id].host == true) {
clearTimeout(gameTimer);
socket.broadcast.to(playerData[socket.id].room).emit('Host Left');
roomMap.delete(playerData[socket.id].room);
roomQuestionType.delete(playerData[socket.id].room);
questionAnswers.delete(playerData[socket.id].room);
answeredPlayers.delete(playerData[socket.id].room);
}
delete playerData[socket.id];
}
})
})

Your issue in the smallest code to rep
let gameTimer;
let pos = 0;
let countArr = ["2", "1", "Go"];
let counter = setInterval(function () {
if (pos == countArr.length) {
console.log("Creating a new gameTimer", Date.now());
gameTimer = setTimeout(function () {
console.log('gameTimer executed')
}, 2100);
} else {
pos++;
}
}, 1000);
So your code keeps creating new timeouts. The previous timeouts exist, they do not get removed.
So you need to either remove the gameTimer before you create a new one, or do not create gameTimer if it is already running
let gameTimer;
let pos = 0;
let countArr = ["2", "1", "Go"];
let counter = setInterval(function () {
if (pos == countArr.length) {
if (gameTimer) return; // if gameTimer is defined, exit
console.log("Creating a new gameTimer", Date.now());
gameTimer = setTimeout(function () {
console.log('gameTimer executed')
}, 2100);
} else {
pos++;
}
}, 1000);

It seems to be an error when accessing the variable, but without the entire code, it is not viable.

Related

Javascript - Function calls not maintaining order

I have following code where I call same function twice with delay of 2 seconds.
But all those log prints inside isPermanentDisconnect() are printed at the end of checkStatePermanent after log('After secondflag check') is printed in the console. Can you please guide me as what is wrong with this code.
function customdelay(miliseconds) {
var currentTime = new Date().getTime();
while (currentTime + miliseconds >= new Date().getTime()) {
}
}
function checkStatePermanent(iceState) {
videoReceivedBytetCount = 0;
audioReceivedByteCount = 0;
log('before First call')
let firstFlag = isPermanentDisconnect();
log('after First call')
log('Disconnect Flag is: ' + firstFlag)
customdelay(2000);
log('after 2 secs')
let secondFlag = isPermanentDisconnect(); //Call this func again after 2 seconds to check whether data is still coming in.
log('after second call')
log('Disconnect Flag is: ' + secondFlag)
if(secondFlag){ //If permanent disconnect then we hangup i.e no audio/video is fllowing
log('Disconnect Flag = Permanent')
if (iceState == 'disconnected'){
hangUpCall(); //Hangup instead of closevideo() because we want to record call end in db
}
}
log('After secondflag check')
...
}
function isPermanentDisconnect(){
var isPermanentDisconnectFlag = false;
var videoIsAlive = false;
var audioIsAlive = false;
myPeerConnection.getStats(null).then(stats => {
stats.forEach(report => {
log('Report Type: '+report.type+ ' Report Kind :'+ report.kind)
if(report.type === 'inbound-rtp' && (report.kind === 'audio' || report.kind === 'video')){ //check for inbound data only
if(report.kind === 'audio'){
//Here we must compare previous data count with current
if(report.bytesReceived > audioReceivedByteCount){
// If current count is greater than previous then that means data is flowing to other peer. So this disconnected or failed ICE state is temporary
audioIsAlive = true;
} else {
audioIsAlive = false;
}
log('Previous Audio count: ' +audioReceivedByteCount + ' Now audio count: ' + report.bytesReceived + ' audio is alive: '+ audioIsAlive)
audioReceivedByteCount = report.bytesReceived;
}
if(report.kind === 'video'){
if(report.bytesReceived > videoReceivedBytetCount){
// If current count is greater than previous then that means data is flowing to other peer. So this disconnected or failed ICE state is temporary
videoIsAlive = true;
} else{
videoIsAlive = false;
}
log('Previous video count: ' +videoReceivedBytetCount + ' Now video count: ' + report.bytesReceived + ' video is alive: ' + videoIsAlive)
videoReceivedBytetCount = report.bytesReceived;
}
if(audioIsAlive || videoIsAlive){ //either audio or video is being recieved.
log('Either video or audio is alive')
isPermanentDisconnectFlag = false; //Disconnected is temp
} else {
isPermanentDisconnectFlag = true;
}
}
})
});
return isPermanentDisconnectFlag;
}
Try making checkStatePermanent(iceState) an async function and await your calls to isPermanentDisconnect(). This way code execution will be halted untill isPermanentDisconnect() completes
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
Managed to get it worked. Posting the answer in case it is useful to others.
Changed the delay function to this
const customdelay = ms => new Promise(res => setTimeout(res, ms));
In the below function notice the async and await
async function isPermanentDisconnect (){
var isPermanentDisconnectFlag = false;
var videoIsAlive = false;
var audioIsAlive = false;
await myPeerConnection.getStats(null).then(stats => {
stats.forEach(report => {
if(report.type === 'inbound-rtp' && (report.kind === 'audio' || report.kind === 'video')){ //check for inbound data only
if(report.kind === 'audio'){
//Here we must compare previous data count with current
if(report.bytesReceived > audioReceivedByteCount){
// If current count is greater than previous then that means data is flowing to other peer. So this disconnected or failed ICE state is temporary
audioIsAlive = true;
} else {
audioIsAlive = false;
}
log('Previous Audio count: ' +audioReceivedByteCount + ' Now audio count: ' + report.bytesReceived + ' audio is alive: '+ audioIsAlive)
audioReceivedByteCount = report.bytesReceived;
}
if(report.kind === 'video'){
if(report.bytesReceived > videoReceivedBytetCount){
// If current count is greater than previous then that means data is flowing to other peer. So this disconnected or failed ICE state is temporary
videoIsAlive = true;
} else{
videoIsAlive = false;
}
log('Previous video count: ' +videoReceivedBytetCount + ' Now video count: ' + report.bytesReceived + ' video is alive: ' + videoIsAlive)
videoReceivedBytetCount = report.bytesReceived;
}
if(audioIsAlive || videoIsAlive){ //either audio or video is being recieved.
log('Either video or audio is alive')
isPermanentDisconnectFlag = false; //Disconnected is temp
} else {
isPermanentDisconnectFlag = true;
}
}
})
});
return isPermanentDisconnectFlag;
}
I think the issue i was facing was due to myPeerConnection.getStats(null).then(stats => { stats.forEach(report => {..
It had to have await as shown in the function above.
Then call the above functions.Notice the async and await.
async function checkStatePermanent (iceState) {
videoReceivedBytetCount = 0;
audioReceivedByteCount = 0;
log('after First call')
let firstFlag = await isPermanentDisconnect();
log('Disconnect Flag is: ' + firstFlag)
log('after First call')
await customdelay(2000);
log('after 2 secs')
let secondFlag = await isPermanentDisconnect(); //Call this func again after 2 seconds to check whether data is still coming in.
log('after second call')
if(secondFlag){ //If permanent disconnect then we hangup i.e no audio/video is fllowing
log('Disconnect Flag = Permanent')
if (iceState == 'disconnected'){
hangUpCall();
}
}
..
}
Log prints as expected and order seems to be maintained now.
Thank you all.

Multiple SUB in a mqtt JS file

So, im making a project for a subject, and i have a file (weather.js) that publishes two variables, one in local/temperature and another in local/time. I'm making a file that subscribes to both of them and operates with the values (blinds.js), but it mixes them. I send temperature and the hour at the same time, and in the subscriber it gives the 1st value to the temperature local variable (inside blinds.js) and then to the time local variable. What can i do?
Here's the weather.js file.
//Variables
var mqtt = require('mqtt')
var client = mqtt.connect('mqtt://localhost:1884')
var topic_temp = 'local/temperature'
var topic_time = 'local/time'
//Publisher (topic)
client.on('connect',() => {
setInterval(() => {
console.log('--------------------');
//creating random temperatures between -5 and 5
var temperature = Math.floor((Math.random() * 30) + 5);
var msg1 = temperature.toString();
//sending the temperature values
client.publish(topic_temp,msg1);
console.log('Temperature is ' + msg1 + 'ºC');
//Console log sent message
console.log('Temperature sent!');
setTimeout(function(){
//creating random time value 24h format
var time = Math.floor((Math.random() * 24));
var msg2 = time.toString();
//sending time value
client.publish(topic_time,msg2);
console.log('Time is ' + msg2 + 'h');
//Console log sent message
console.log('Time sent!');
console.log('--------------------');
}, 3000);
},15000)
})
And this is the blinds.js file.
//Variables
var mqtt = require('mqtt')
var client = mqtt.connect('mqtt://localhost:1884')
var topic_sub1 = 'local/temperature'
var msg1 = false;
var topic_sub2 = 'local/time'
msg2 = false;
var topic_post = 'appliances/blinds'
var blinds = false;
//Subscribing to the topic_sub1
client.on('connect',() => {
client.subscribe(topic_sub1)
})
//Receiving temp messages
client.on('message',(topic_sub1,temperature) => {
if (msg2 == false) {
msg1 = true;
temp = temperature.toString();
console.log('--------------------');
console.log(temp + 'ºC');
}
})
//Subscribing to the topic_sub2
client.on('connect',() => {
client.subscribe(topic_sub2)
})
//Receiving time messages
client.on('message',(topic_sub2,times) => {
if (msg1) {
msg2 = true;
time = times.toString();
console.log(time + 'h');
console.log('--------------------');
blind();
}
})
//blinds function
function blind() {
if (temp > 28 || time < 9) {
blinds = true;
console.log('Blinds are CLOSED');
}else if (temp > 28 || time > 19){
blinds = true;
console.log('Blinds are CLOSED');
}else{
blinds = false;
console.log('Blinds are OPEN');
}
//sending the temperature values
client.publish(topic_post,blinds.toString());
msg2 = false;
msg1 = false;
}
You can't add multiple client.on('message') listeners, there can only be one.
So just add an if statement in the callback to check what topic the message arrived on.
client.on('message', (topic, message) => {
if (topic == topic_sub1) {
//handle temp
} else if ( topic == topic_sub2) {
//handle time
}
})

How can I account for when the user inputs nothing to Alexa after this.emit(":ask", speech)?

I'm writing a game for Alexa but the user input is required. If there is no answer, then the game should end with a unique message of the user's score. Currently, I have the Alexa prompting the user like this.
this.emit(":ask", speech);
However, if the user chooses not to answer, the Alexa ends without any sort of message. I checked whether I could account for this in the Stop or Cancel handler, but the program doesn't seem to exit that way. How can I account for no input and specify a exit message? Here is my full code for reference.
'use strict';
const Alexa = require('alexa-sdk');
//Messages
const WELCOME_MESSAGE = "Welcome to three six nine. You can play three six nine with just me or with friends. Say help for how to play";
const START_GAME_MESSAGE = "OK. I will start!";
const EXIT_SKILL_MESSAGE = "Better luck next time!";
const HELP_MESSAGE = "Three six nine is a game where we take turns counting up from one. If the number is divisible by three, you're going to say quack. If the number has a three, six, or nine anywhere, you're going to say quack";
const speechConsWrong = ["Argh", "Aw man", "Blarg", "Blast", "Boo", "Bummer", "Darn", "D'oh", "Dun dun dun", "Eek", "Honk", "Le sigh",
"Mamma mia", "Oh boy", "Oh dear", "Oof", "Ouch", "Ruh roh", "Shucks", "Uh oh", "Wah wah", "Whoops a daisy", "Yikes"];
const states = {
START: "_START",
GAME: "_GAME"
};
//Game Variables
var counter = 1;
var numPlayers = 1; //By default is one
const handlers = {
//Game goes straight to play currently
"LaunchRequest": function() {
this.handler.state = states.START;
this.emitWithState("Start");
},
"PlayIntent": function() {
this.handler.state = states.GAME;
this.emitWithState("NextNumber");
},
"PlayWithFriends": function() {
const itemSlot = this.event.request.intent.slots.numFriends.value;
numPlayers = itemSlot;
this.handler.state = states.GAME;
this.emitWithState("NextNumber");
},
"AMAZON.HelpIntent": function() {
this.response.speak(HELP_MESSAGE).listen(HELP_MESSAGE);
this.emit(":responseReady");
},
"Unhandled": function() {
this.handler.state = states.START;
this.emitWithState("Start");
}
};
//When skill is in START state
const startHandlers = Alexa.CreateStateHandler(states.START,{
"Start": function() {
this.response.speak(WELCOME_MESSAGE).listen(HELP_MESSAGE);
this.emit(":responseReady");
},
"PlayIntent": function() {
this.handler.state = states.GAME;
this.emitWithState("NextNumber");
},
"PlayWithFriends": function() {
const itemSlot = this.event.request.intent.slots.Item;
numPlayers = itemSlot; //set number to slot value
this.handler.state = states.GAME;
this.emitWithState("NextNumber");
},
"AMAZON.StopIntent": function() {
this.response.speak(EXIT_SKILL_MESSAGE);
this.emit(":responseReady");
},
"AMAZON.CancelIntent": function() {
this.response.speak(EXIT_SKILL_MESSAGE);
this.emit(":responseReady");
},
"AMAZON.HelpIntent": function() {
this.response.speak(HELP_MESSAGE).listen(HELP_MESSAGE);
this.emit(":responseReady");
},
"Unhandled": function() {
this.emitWithState("Start");
}
});
const gameHandlers = Alexa.CreateStateHandler(states.GAME,{
"Game": function() {
let speech = "";
let turnDivisible = (counter-1) % (numPlayers+1);
if (turnDivisible != 0) {
this.emit(":ask", speech);
} else {
this.emitWithState("NextNumber");
}
},
"NextNumber": function() {
//If the counter is at 1, the game is beginning with Alexa
if (counter == 1) {
this.attributes.response = START_GAME_MESSAGE + " ";
} else {
this.attributes.response = " ";
}
//check if number contains three, six, nine or divisible by nine
let speech = " ";
let divisible = counter % 3;
let counterString = counter.toString();
if (counterString.indexOf('3') > - 1 || counterString.indexOf('6') > - 1 || counterString.indexOf('9') > - 1 || divisible === 0) {
speech = this.attributes.response + "quack";
} else {
speech = this.attributes.response + counter;
}
//update variables
counter++;
this.emit(":ask", speech);
},
"AnswerIntent": function() {
let correct = checkAnswer(this.event.request.intent.slots, counter);
//Game continues when you get the correct value
if (correct) {
counter++;
this.emitWithState("Game");
}
//Game ends when the value is incorrect
else {
let speechOutput = endGame();
this.response.speak(speechOutput);
this.emit(":responseReady");
}
},
"AMAZON.StopIntent": function() {
this.response.speak(EXIT_SKILL_MESSAGE);
endGame();
this.emit(":responseReady");
},
"AMAZON.CancelIntent": function() {
this.response.speak(EXIT_SKILL_MESSAGE);
endGame();
this.emit(":responseReady");
},
"AMAZON.HelpIntent": function() {
this.response.speak(HELP_MESSAGE).listen(HELP_MESSAGE);
this.emit(":responseReady");
},
"Unhandled": function() {
this.emitWithState("Game");
}
});
function checkAnswer(slots, value)
{
for (var slot in slots) {
if (slots[slot].value !== undefined)
{
let slotValue = slots[slot].value.toString().toLowerCase();
let counterValue = value.toString();
let divisible = value % 3;
if (divisible === 0) {
if (slotValue == "quack") {
return true;
} else {
return false;
}
}
else if (counterValue.indexOf('3') > - 1 || counterValue.indexOf('6') > - 1 || counterValue.indexOf('9') > - 1) {
if (slotValue == "quack") {
return true;
} else {
return false;
}
}
else if (slotValue == value.toString().toLowerCase())
{
return true;
}
else
{
return false;
}
}
}
return false;
}
function endGame() {
let speechOutput = "";
let response = getSpeechCon(false);
response += "your final score is " + counter;
speechOutput = response + ". " + EXIT_SKILL_MESSAGE;
counter = 1;
numPlayers = 1;
return speechOutput;
}
function getSpeechCon(type) {
return "<say-as interpret-as='interjection'>" + speechConsWrong[getRandom(0, speechConsWrong.length-1)] + " </say-as><break strength='strong'/>";
}
function getRandom(min, max) {
return Math.floor(Math.random() * (max-min+1)+min);
}
exports.handler = (event, context) => {
const alexa = Alexa.handler(event, context);
//alexa.appId = APP_ID;
alexa.registerHandlers(handlers, startHandlers, gameHandlers);
alexa.execute();
};
You should look for the SessionEndedRequest when the session ends, so you can listen for that and respond accordingly. It should be request.type == 'SessionEndedRequest'. Much like LaunchRequest, it is not actually an intent, and I see you are already handling LaunchRequest, so it should be easy to add.

Javascript function triggered twice

I currently have a javascript application that plays a couple of videos and asks a series of questions, based on the wait time in each question.
However, after a new video is triggered (2th video), my code skips the first question and I can't really find out why. Any ideas? Thank you.
Settings.js
var settings = {
'appname': 'ExperimentX',
'masterpassword': 'xxxx'
};
var videos = [
{
'video': 'movie 1.mp4',
'questions': [
{
'text': `
blabla
`,
'wait': 2 * 60 + 51
},
{
'text': 'How sad are you right now',
'wait': 1 * 60 + 57
},
{
'text': '',
'wait': 57
}
]
},
{
'video': 'movie 2.mp4',
'questions': [
{
'text': 'How happy are you right now',
'wait': 2
},
{
'text': 'How sad are you right now',
'wait': 5
}
]
}
}
And the real JS code:
// -- base settings
identifier = new Date().getTime();
videos_path = 'videos/';
// -- create elements
var player = videojs('video');
var slider = $('#ex1');
// -- variables
var debug = true;
var timer = null;
var questions = [];
var currquestion = 0;
var currvideo = 0;
function log(msg){
if (debug)
console.log(msg);
}
function checkForLocalStorage(){
var result = false;
try {
result = (typeof window.localStorage == 'undefined');
} catch (err){
result = false;
}
return result;
}
function save(key, value){
log('Saving ' + key + ' -> ' + value);
var sessionObject = localStorage.getItem( identifier );
sessionObject = (null == sessionObject) ? {} : JSON.parse(sessionObject);
sessionObject[key] = value;
localStorage.setItem(identifier, JSON.stringify(sessionObject));
}
function toDate(ms){
var d = new Date(0);
d.setUTCSeconds(ms / 1000);
return d.toLocaleString();
}
function loadAll(){
var result = [];
log('Loading from localstorage:');
for (var i = 0; i < localStorage.length; i++){
var key = localStorage.key(i);
var obj = JSON.parse( localStorage.getItem(key) );
obj['timestamp'] = toDate(key);
log(obj);
result.push( obj );
}
return result;
}
function refreshVideoCount(){
log('Refreshing video counter');
$('#currvideoCounter').text( currvideo +1 );
$('#totalvideoCounter').text( videos.length );
}
function showEnd(){
log('Showing end page');
$('#ending').removeClass('hidden');
$('#videoPlayer').addClass('hidden');
$('#menuEnd').addClass('active');
$('#menuVideos').removeClass('active');
}
function showQuestion(){
console.log('Showing question, currquestion ' + currquestion + ' currvideo ' + currvideo);
clearTimeout(timer);
$('#modalTitle').html( questions[currquestion]['text'] );
$('#modalQuestion').modal('show');
$('#btnModal').on('click', function(){
log('btnModal clicked, saving answer');
save('V' + currvideo + ' Q' + currquestion, slider.slider('getValue'));
log('Refreshing slider');
slider.slider('refresh');
var next = (currquestion >= questions.length-1);
if (next == true){
log('currquestion is the last one, cycling to next video');
currvideo = currvideo +1;
currquestion = 0;
cycleVideos();
} else {
log('cycling to next question of this video');
currquestion = currquestion +1;
cycleQuestions();
}
});
}
function cycleQuestions(){
log('Resuming video');
var questionText = questions[currquestion]['text'];
var questionWait = questions[currquestion]['wait'];
player.play();
if (timer){
log('Clearing timer (cycleQuestions)');
clearTimeout(timer);
timer = null;
}
log('Setting new timer');
timer = setTimeout(function(){
log('Timer triggered, pausing player and showing question');
player.pause();
showQuestion();
}, questionWait * 1000);
}
function cycleVideos(){
log('Cycling to next video');
if (timer){
log('Clearing timer (cycleVideos)');
clearTimeout(timer);
timer = null;
}
if (currvideo > videos.length -1){
log('Video is the last one, showing end page');
player.pause();
player.exitFullscreen();
return showEnd();
}
log('Setting videofile and question variable');
videoFile = videos_path + videos[currvideo]['video'];
questions = videos[currvideo]['questions'];
refreshVideoCount();
log('Playing player');
player.src({ 'src' : videoFile });
player.play();
cycleQuestions();
}
function showOverview(){
log('Showing management page');
$('#intro').addClass('hidden');
$('#overview').removeClass('hidden');
var items = loadAll();
var content = '';
log('Generating table');
var table =
$('<table>')
.addClass('table')
.append('<thead><tr>');
for (var prop in items[0])
table.append('<th>' + prop + '</th>');
table
.append('</tr></thead>')
.append('<tbody>');
items.forEach(function(object){
// for every entry
var row = '<tr>';
for (var property in items[0]) {
if (object.hasOwnProperty(property)) {
// for every property
row = row.concat(
'<td>' + object[property] + '</td>'
);
}
}
row.concat('</tr>');
table.append(row);
});
table.append('</table>');
$('#overviewText').html(table);
$('#btnClear').on('click', function(){
log('Clearing storage');
if ( confirm('Do you really want to clear all results?') ){
localStorage.clear();
location.reload();
}
});
}
function showIntro(){
log('Showing intro page');
$('#menuIntro').addClass('active');
refreshVideoCount();
$('#intro').removeClass('hidden');
$('#introInput').keyup(function(event){
if(event.keyCode == 13)
$("#introBtn").click();
});
$('#introBtn').on('click', function(){
var name = $('#introInput').val();
var age = $('#introAge').val();
var gender = $('#introGender').val();
if (name.trim().length == 0)
return alert('You need to fill in your name.');
if (age.trim().length == 0)
return alert('You need to fill in your age.');
if (name === settings['masterpassword'])
return showOverview();
save('name', name);
save('age', age);
save('gender', gender);
$('#intro').addClass('hidden');
$('#videoPlayer').removeClass('hidden');
$('#menuIntro').removeClass('active');
$('#menuVideos').addClass('active');
slider.slider({});
player.requestFullscreen();
cycleVideos();
});
}
function disableRefresh(){
log('Disabling F5');
$(document).on("keydown", function(e){
if ((e.which || e.keyCode) == 116)
e.preventDefault();
});
}
// setup base stuff
checkForLocalStorage();
$('#logo').text( settings['appname'] );
$('#title').text( settings['appname'] );
disableRefresh();
// show intro page
showIntro( identifier );

Socket.io --- One object for multiple users

I am building an application in node.js with socket.io where I want people to be able to vote on questions and have a timer included which will give them a time limit for answering questions. The issue that I am running into (which I will highlight below) is that every time someone connects to the page, it will log the tick from the stopwatch object another time. Even after people leave, it will continue to log it one time for every time someone connected. Here is my code for the project thus far.
Stopwatch.js:
function Stopwatch() {
if (false === (this instanceof Stopwatch)) {
return new Stopwatch();
}
this.hour = 3600000;
this.minute = 60000;
this.second = 1000;
this.time = this.hour;
this.interval = undefined;
events.EventEmitter.call(this);
_.bindAll(this, 'start', 'stop', 'reset', 'onTick');
};
util.inherits(Stopwatch, events.EventEmitter);
Stopwatch.prototype.start = function() {
console.log("Starting the Timer!");
this.interval = setInterval(this.onTick, this.second);
this.emit('start');
};
Stopwatch.prototype.onTick = function() {
var remainder = this.time,
numhours,
numMinutes,
numSeconds,
output = "";
if (this.time === 0) {
this.stop();
return;
}
numHours = String(parseInt(remainder / this.hour, 10));
remainder -= this.hour * numHours;
numMinutes = String(parseInt(remainder / this.minute, 10));
remainder -= this.minute * numMinutes;
numSeconds = String(parseInt(remainder / this.second, 10));
output = _.map([numHours, numMinutes, numSeconds], function(str) {
if (str.length === 1) {
str = "0" + str;
}
return str;
}).join(":");
this.emit('tick', output);
this.time -= this.second;
}
module.exports = Stopwatch;
}
socket.js:
var Stopwatch = require('../models/stopwatch');
var people = {};
var stopwatch = Stopwatch();
module.exports = function (io) {
io.on('connection', function (socket) {
//console.log("Someone joined...");
//socket.on('join', function () {
if (Object.keys(people).length === 0) {
console.log('host joined');
people[socket.id] = {"name": "host", "image": "fake picture", "host": true};
} else {
console.log("Someone else joined");
people[socket.id] = {"name": "person", "image": "other picture", "host": false};
}
console.log(people);
//});
socket.on('startTimer', function() {
stopwatch.start();
});
socket.on('disconnect', function() {
delete people[socket.id];
console.log("someone left");
console.log(people);
});
stopwatch.on('tick', function(time) {
console.log(socket.id + '---stopwatch tick!' + time);
socket.emit('timer', { countdown: time });
});
});
};
The javascript on the client:
var socket;
$(document).ready(function() {
socket = io();
socket.on('timer', function (data) {
$('#timer').html(data.countdown);
});
$('#start-timer').click(function() {
socket.emit('startTimer');
});
});
Thanks in advance! I can't figure out why it still logs each user and the time, even after they disconnect from the server.
What's happening is that every time a new client opens a connection to the server, you're assigning an event listener to the stopwatch and never remove it, this causes the behaviour you're experiencing. You must remove your eventListener when the socket disconnects as stated in the node event emitter class.
You should end up with something like this:
io.on('connection', function (socket) {
//console.log("Someone joined...");
//socket.on('join', function () {
if (Object.keys(people).length === 0) {
console.log('host joined');
people[socket.id] = {"name": "host", "image": "fake picture", "host": true};
} else {
console.log("Someone else joined");
people[socket.id] = {"name": "person", "image": "other picture", "host": false};
}
console.log(people);
socket.on('startTimer', function() {
stopwatch.start();
});
var _tickListener = function(time) {
console.log(socket.id + '---stopwatch tick!' + time);
socket.emit('timer', { countdown: time });
};
socket.on('disconnect', function() {
delete people[socket.id];
stopwatch.removeListener('tick', _tickListener);
console.log("someone left");
console.log(people);
});
stopwatch.on('tick', _tickListener);
});

Categories