Javascript - Function calls not maintaining order - javascript

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.

Related

clearTimeout function does not run

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.

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
}
})

Firebase clearTimeout not stop the setTimeout

How can I stop a setTimeout function before starting from the onWrite event on a "Firebase Cloud Function"? I try with setTimeout, but the clearTimeout do not stop the setTimeout.
P.S.: I've already raised the script timeout from the Firebase panel from 60 seconds (default) to 360 seconds.
var timeOutOnline = {};
exports.online = functions.database.ref('/server/{serverId}/online/time').onWrite(event => {
const serverId = event.params.serverId;
var time = event.data.val();
var lastDateOnline = new Date( time * 1000);
var dateString = lastDateOnline.toGMTString();
clearTimeout(timeOutOnline[serverId]);
refGet = db.ref('/server/'+serverId+'/online/');
refGet.once('value').then(function(snapshot) {
var onlineSnap = snapshot.val();
if (onlineSnap && onlineSnap.alarm == true) {
sendMail(serverId,false, 'not responding' , 'Server '+ serverId + ' not responding from '+dateString);
setAlarmStatus(serverId,false);
} else {
timeOutOnline[serverId] = setTimeout(function() {
sendMail(serverId,true, 'not responding' , 'Server '+ serverId + ' not responding from '+dateString);
setAlarmStatus(serverId,true);
}, 21000);
}
});
return true;
});
UPDATE:
Now I use promise, but clearTimeout still not working, not clearing setTimeout function. What am I doing wrong?
var timeOutOnline = {};
exports.online = functions.database.ref('/server/{serverId}/online/time').onWrite(event => {
const serverId = event.params.serverId;
var time = event.data.val();
var lastDateOnline = new Date( time * 1000);
var dateString = lastDateOnline.toGMTString();
console.log(v);
if(!timeOutOnline[serverId]) {
timeOutOnline[serverId] = [];
} else {
timeOutOnline[serverId].length;
for (var i = 0; i < timeOutOnline[serverId].length; i++) {
if (timeOutOnline[serverId][i]) {
timeOutOnline[serverId][i].cancel();
timeOutOnline[serverId][i] = null;
}
}
}
timeOutOnline[serverId] = timeOutOnline[serverId].filter(n => n);
refGet = db.ref('/server/'+serverId+'/online/');
refGet.once('value').then(function(snapshot) {
var onlineSnap = snapshot.val();
if (onlineSnap && onlineSnap.alarm == true) {
sendMail(serverId,false, 'not responding' , 'Server '+ serverId + ' not responding from '+dateString);
setAlarmStatus(serverId,false);
} else {
timeOutOnline[serverId].push(waitForServer(210000));
var index = timeOutOnline[serverId].length - 1;
return timeOutOnline[serverId][index].promise.then(function(i) {
console.log('Server '+ serverId + ' not responding from '+dateString);
sendMail(serverId,true, 'not responding' , 'Server '+ serverId + ' not responding from '+dateString);
setAlarmStatus(serverId,true);
});
}
});
return true;
});
function waitForServer(ms) {
var timeout, promise;
promise = new Promise(function(resolve, reject) {
timeout = setTimeout(function() {
resolve('timeout done');
}, ms);
});
return {
promise:promise,
cancel:function(){
console.log('cancel timeout: '+timeout);
clearTimeout(timeout);
}
};
}
There's a lot of things wrong in this function.
First of all, it's not clear to me why you want to use setTimeout() in this function. In fact, there are almost no valid use cases for setTimeout() with Cloud Functions. Functions are supposed to execute as fast as possible, and setTimeout only really just incurs extra cost to your processing. Cloud Functions does not enable you to run "background work" that survives past the invocation of the function - that's just not how it works.
Second of all, you're performing async work here, but you're not returning a promise to indicate when that work completes. If you don't return a promise that's resolved when your work completes, your function is highly likely to exhibit strange problems, including work not completing as you'd expect.

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 );

how do i create a RXJS pausable data flow that doesnt reset on each resume?

i have tried out the documented example for RXJS pausable and while it pauses ok it resets on resume. how do i modify the example below to have my stream resume from where i paused it rather than reset?
var pauser = new Rx.Subject();
var source = Rx.Observable
.interval(1000)
.timeInterval()
.pausable(pauser);
var subscription = source.subscribe(
function (x) {
$("#result").append('Next: ' + JSON.stringify(x) + '<br>');
},
function (err) {
$("#result").append('Error: ' + err);
},
function () {
$("#result").append('Completed');
});
pauser.onNext(true);
var paused = false;
$("#result").click(function() {
$(this).append("mouse clicked");
paused = (paused === false) ? true : false;
pauser.onNext(paused);
});
this is giving me the following output:
Next: {"value":0,"interval":1002}
Next: {"value":1,"interval":1000}
Next: {"value":2,"interval":999}
mouse clicked
mouse clicked
Next: {"value":0,"interval":1001}
Next: {"value":1,"interval":999}
Next: {"value":2,"interval":1000}
As mentioned in the pausable documentation, pausable is to be used on hot sources.
One way to make a source hot is to use share. However, this will not work as is in conjunction with pausable because share will disconnect its source when it has no subscribers, which will happen when you will pause.
So here are two ways to make this work. One is to use share and keep a dummy subscriber so that share never disconnects from its source as there will always be at least one subscriber. The second way is to use publish, and connect the observable once all the wiring has been made.
Example 1 with dummy subscriber:
var pauser = new Rx.Subject();
function noop(){}
var source = Rx.Observable
.interval(1000)
.timeInterval()
.share();
var pausableSource = source.pausable(pauser);
var subscription = pausableSource.subscribe(
function (x) {
$("#ta_result").append('Next: ' + JSON.stringify(x) + '<br>');
},
function (err) {
$("#ta_result").append('Error: ' + err);
},
function () {
$("#ta_result").append('Completed');
});
source.subscribe(noop);
pauser.onNext(false);
var paused = false;
$("#result").click(function() {
$("#ta_change").append("mouse clicked\n");
paused = !paused;
pauser.onNext(paused);
});
Example 2 with connect:
var pauser = new Rx.Subject();
var source = Rx.Observable
.interval(1000)
.timeInterval()
.publish();
var pausableSource = source.pausable(pauser);
// source.subscribe(function(){});
var subscription = pausableSource.subscribe(
function (x) {
$("#ta_result").append('Next: ' + JSON.stringify(x) + '<br>');
},
function (err) {
$("#ta_result").append('Error: ' + err);
},
function () {
$("#ta_result").append('Completed');
});
source.connect();
pauser.onNext(false);
var paused = false;
$("#result").click(function() {
$("#ta_change").append("mouse clicked\n");
paused = !paused;
pauser.onNext(paused);
});

Categories