I would like to stop a timer (discord) - javascript

I am new in this world and I am trying things.
I was trying to build a timer bot... And now I have a little problem, I would like to stop my timer whenever I want.
bot.on('message', message => {
let timer = setInterval(() => {
if (message.content.startsWith('!start'))
message.channel.send("I print something");
}, 10 * 1000)
if (message.content.startsWith('!stop')) {
message.channel.send("Interaval Cleared");
clearInterval(timer);
}})
When I type !stop in my discord channel, it displays me the message but it doesn't stop my timer... I tried with a return; but it didn't work.
Could you help me please ?
Thanks,
Have a good day !

You're starting a new interval each time you run the function. Also, your timer value is scoped to each function call, and not "shared" between calls, you need to make it available between them. The behavior you want should look something like this instead:
bot = {}
bot.timer = 0; // ensures clearInterval doesn't throw an error if bot.timer hasn't been set
bot.listen = message =>{
if(message == 'start'){
clearInterval(bot.timer); // stops the interval if it been previously started
bot.timer = setInterval(()=>console.log('I print something'),1000)
}
if(message == 'stop') clearInterval(bot.timer);
}

Related

multiple setInterval timers on node server

My app is a game where a user has 30 mins to finish....node backend
Each time a user starts a game then a setInterval function is triggered server side....once 30mins is counted down then I clearInterval.
How do I make sure that each setInterval is unique to the particular user and the setInterval variable is not overwritten each time a new user starts a game? (or all setInterval's are cleared each time I clear).
Seems like I might need to create a unique "interval" variable for each new user that starts game??
Below code is triggered each time a new user starts a game
let secondsLeft = 300000;
let interval = setInterval(() => {
secondsLeft -= 1000;
if (secondsLeft === 0) {
console.log("now exit");
clearInterval(interval);
}
}, 10000);
Thanks!!
We used agenda for a pretty big strategy game backend which offers the benefit of persistence if the node app crashes etc.
We incorporated the user id into the job name and would then schedule the job, along with data to process, to run at a determined time specifying a handler to execute.
The handler would then run the job and perform the relevant tasks.
// create a unique jobname
const jobName = `${player.id}|${constants.events.game.createBuilding}`;
// define a job to run with handler
services.scheduler.define(jobName, checkCreateBuildingComplete);
// schedule it to run and pass the data
services.scheduler.schedule(at.toISOString(), jobName, {
id: id,
instance: instance,
started: when
});
Worked pretty well and offered decent protection against crashes. Maybe worth considering.
First: Concurrent Intervals and Timers are not the best design approach in JS, it is better to use one global timer and a list of objects storing the start, end, userid etc and update these in a loop.
Anyway. To have your interval id bound to a certain scope, you can use a Promise like so:
const createTimer = (duration, userid) => new Promise(res => {
const start = new Date().getTime();
let iid;
(function loop () {
const
now = new Date().getTime(),
delta = now - start
;
//elapsed
if (delta >= duration) {
clearTimeout(iid);
res(userid);
//try again later
} else {
iid = setTimeout(loop, 100)
}
})();
});
This way each timer will run »on its own«. I used setTimeout here since that wont requeue loop before it did everything it had to. It should work with setInterval as well and look like that:
const runTimer = (duration, userid, ontick) => new Promise(res => {
const
start = new Date().getTime(),
iid = setInterval(
() => {
const delta = new Date().getTime() - start;
if (delta < duration) {
//if you want to trigger something each time
ontick(delta, userid);
} else {
clearInterval(iid);
res(userid);
}
}, 500)
;
});
You do not even need a promise, a simple function will do as well, but then you have to build some solution for triggering stuff when the timer is elapsed.
Thanks #Chev and #philipp these are both good answers.
I was also made aware of a technique where you use an array for the setInterval variable.....this would make my code as follows;
let intervals = []
let secondsLeft = 300000;
intervals['i'+userId] = setInterval(() => {
secondsLeft -= 1000;
if (secondsLeft === 0) {
console.log("now exit");
clearInterval(interval);
}
}, 10000);
Does anyone else foresee this working?.
UPDATE 6.56pm PST.....it works!!

There's a problem with a voicestateupdate in node.js

I want my bot to give coins to members that spent 1 minute in any voice channel. When I'm sitting in voice channel it's working good, but if I am quitting a channel, the bot still gives me 1 coin per minute. What did I do wrong?
I tried to stop a function when the user leaves a channel, tried to clear a timeout function, but it's still working that way:
bot.on("voiceStateUpdate",(oldMember,newMember)=>{
let nuc = newMember.voiceChannel
if(nuc !== undefined){
function smth() {
setTimeout(function coin() {
db.add(`money_${newMember.id}`, 1)
setTimeout(coin, 60000);
}, 60000)}
smth()
newMember.send('You're in voicechannel')
} else {
return newMember.send('You're out of voicechannel')
}
})

Make my discord bot send message at specific hours

I have a problem I almost resolved but i'm now stuck.
I want to make my bot send a message in a channel at mirror hours (00h00, 01h01, 02h02...) for a running gag with my friends and currently I made this:
At the top of my code I have var currentdate = new Date();
And then, later in my source code:
if(currentdate.getMinutes() == currentdate.getHours())
{
bot.channels.get('SPECIFICCHANNELID').send('Touchez votre nez :nose:');
}
It's sort of working since the message is sent by the bot in the right channel, but the message is only sent when the bot detects a message, so if during any mirror hour, no one send a message, then the bot will not send anything.
And if there is multiples messages during this interval of time, the bot will also send the message multiple times, of course I want it to send the message only 1 time for exemple at 11:11:00.
Thank you for the help and sorry if my english is bad !
You need to be checking at some interval whether or not to send a message.
Something like setInterval would work.
setInterval(function(){
if(currentdate.getMinutes() == currentdate.getHours())
{
bot.channels.get('SPECIFICCHANNELID').send('Touchez votre nez :nose:');
}
}, MIN_INTERVAL)
You want MIN_INTERVAL to be the minimum amount of time in milliseconds to check for sending messages.
If you want to check every minute
const MIN_INTERVAL = 1000 * 60
You have to use if statement and you didn't specified hour or minutes, so the bot can't send message.
async function verifyTime() {
var d = new Date();
if (d.getHours() == d.getMinutes()) {
//your code goes here
} catch (error) {
console.log(error);
}
setTimeout(() => {
verifyTime();
}, 61 * 1000);
} else {
setTimeout(() => {
verifyTime();
}, 1000);
}
}
client.login(token);
//⬇ remember to place this under your client.login
setTimeout(() => {
verifyTime();
}, 5000);

Killing a "personalized" Interval

I've made this system so users can login to my website and play a game that requires some interval timing. When the user is done with playing I basically want to kill the interval. While everything seems to be running fine, there is something wrong with killing the interval.
Here is the problem Whenever a user is done playing the interval gets killed, not only for the user playing but for everyone. This might be because I'm assigning a variable to the interval and when a user is done playing a game I'm killing the interval, am I right that it then would kill the other intervals as well?
Here is some code I've written for this question,
var user; //this is a variable that has all info about the user. (its not usually empty)
var usersPlaying = [];
socket.on('game', function(game) {
if(game.type == "start"){
usersPlaying.push({
user_id: user.id
});
var game = setInterval(function(){
if(findUser(user.id) !== undefined){
console.log('Second passed!');
}else{
clearInterval(game); //stop the interval
}
}, 1000);
}else if(game.type == "stop"){
console.log("User has decided to quit playing the game!");
usersPlaying.splice(usersPlaying.findIndex(user => user === user.id), 1); //remove user from playing
}
});
There might be some mistakes in there since I rewritten and simplified the code otherwise it would be way to hard to help me out.
Anyways, how can I make it so it only clears the interval running for a certain specified person?
Thanks!
The setInterval call returns a unique id. You can use that id to clear that interval timer afterwards:
var uniqueId = setInterval(function () { /* ... */ }, 1000);
Later on ...
clearInterval(uniqueId);
will kill that specific timer.
I suggest storing the uniqueId for each user inside the usersPlaying array.
Store the interval for that specific socket inside its own scope :
var user; //this is a variable that has all info about the user. (its not usually empty)
var usersPlaying = [];
socket.on('game', function(game) {
if(game.type == "start"){
usersPlaying.push({
user_id: user.id
});
socket.game = setInterval(function(){
if(findUser(user.id) !== undefined){
console.log('Second passed!');
}else{
clearInterval(socket.game); //stop the interval
}
}, 1000);
}else if(game.type == "stop"){
console.log("User has decided to quit playing the game!");
usersPlaying.splice(usersPlaying.findIndex(user => user === user.id), 1); //remove user from playing
}
});
So you can also kill it when disconnections occur :
socket.on('disconnecting',function(){
if(socket.game){clearInterval(socket.game);}
});
EDIT :
var user; //this is a variable that has all info about the user. (its not usually empty)
better store all that inside the scope of the socket (each client socket object in the server will have its own "user" key instead of making use of ugly global variables
So store it like socket.user = {id:"foo"} and you can access the specific user object for that client performing the socket event request like if(findUser(socketuser.id) !== undefined){

How to stop consuming after an amount of time of no messages

I'm trying to close my connection after the queue hasn't been active for 5 minutes. I have:
ch.consume(receivingQueue, async function (msg) {
if (msg !== null) {
console.log(msg.content.toString()));
}
});
I read about Channel.cancel() but i'm just not quite sure where to insert that into the flow here since the process is just sitting and waiting for a new message, and I'm not sure where to get the consumerTag as it is not in the msg variable.
I have not tested this, but logic is as follows. setTimeout is set to close connection after 5 mins on every message. If a new message arrives the old timer is cleared by the new message and a new timer is recreated. otherwise the connection closes after 5 mins
const closeConnection = function () {
ch.close()
}
let timer = setTimeout(()=>{}, 0); //initial timer for cleartimeout Maybe refactor this?
ch.consume(receivingQueue, async function (msg) {
clearTimeout(timer);
timer = setTimeout(closeConnection, 300000)
if (msg !== null) {
console.log(msg.content.toString()));
}
});

Categories