fs.writeFile not updating when multiple users use the command - discord

setTimeout(() => {
if (!defFile[cduser].cd) {
} else {
let var1 = defFile[mentionId].autodefensa;
let var3 = defFile[mentionId].bomba;
defFile[mentionId] = {
autodefensa: var1,
defensaext: 0,
bomba: var3
}
message.channel.send('Message here')
fs.writeFile ("./defensa.json", JSON.stringify(defFile, null, 4), err => {
if (err) throw err;
});
} message.author.send(cdyou2)
}, 30000)
What is meant to do is that, whenever a user inputs the command, in gives a boost and after a short time it goes. mentionId works fine, however fs.writeFile only updates the last user and not the ones who where before. This only happens when more than 1 person inputs the command before the timer goes, tho. Any solution for this?

Related

Earn Credits for Each Message Sent Bot Discord.js

I need help with my Discord bot, I am using discord.js
So I made this:
client.on("message", async(message) => {
if (!message.guild) return;
if (message.author.bot) return;
if (mentionn) {
const randomAmountOfCredits = Math.floor(Math.random() * 29) + 1; // Min 1, Max 30
(message.author.id, message.guild.id, randomAmountOfCredits);
if (collected.first().content === number) {
m.delete();
collected.first().delete();
credits[mentionn.id].credits += (+randomAmountOfCredits);
fs.writeFile(path, JSON.stringify(credits, null, 5), function(err) {
if (err) console.log(err)
});
if (collected.first().content !== number) {
return m.delete();
} else if (!mentionn) {
credits[author].credits += (+randomAmountOfCredits);
fs.writeFile(path, JSON.stringify(credits, null, 5), function(err) {
if (err) console.log(err)
});
}
}
}
});
It's like earning credits by each message sent, but I am not earning any credits, there are no errors on the console:
Thats the console
And here I must get credits, but nothing happens:
Thats the results
I am a starter, thank you
I didn't understand a line of this code snippet, and I didn't understand your answer to Pascal Stockert's question, and neither did I understand what a collected (from a collector?) var's doing here. but I'll try my best. This is how I would add this feature, feel free to mess around with this code and add as many conditions as you want.
client.on("message", async msg => {
// First, generate a random number
const newXP = Math.ceiling(Math.random() * 30);
// Read the existing XPs
const file = fs.readFileSync("xp.json");
// Add some XP to the author of the message
file[msg.author.id].credits += newXP;
// Write new XP file
fs.writeFileSync("xp.json", JSON.stringify(file, null, 4));
// Done.
});
I didn't add it, but be careful, it looks like you don't handle the situation where file[msg.author.id] doesn't exist.

Discord poll bot async issues

I am trying to make a poll command for a discord bot in which the user chooses a number of options in the first command (ie '!poll 4') and then chooses the questions and the options. I am having some issues getting the bot to wait for a response before it moves on to the next option in the loop. When I try and use await in the loop it says I cannot use await because it's not an async function, but it is an async function I think. I am very inexperienced with this so I am sure it is a simple error or probably multiple. If anyone can give me advice on a way to make the loop work as intended and ask for each option I would appreciate it. Also is there a way to add if statements to do addFields to an embed? Here is my code:
const Discord = module.require('discord.js');
module.exports = {
name: 'poll',
async execute(message, args) {
function isNumber(n) { return !isNaN(parseFloat(n)) && !isNaN(n - 0) }
if(isNumber(args[1])){
if(args[1]<2) return message.channel.send('Please choose a higher number of options for the poll :)');
if(args[1]>10) return message.channel.send('Please choose a lower number of options for the poll :)');
const filter = response => {
if(!response.author.bot) return response;
};
var question;
var options;
message.channel.send('What question would you like to ask?').then(() => {
message.channel.awaitMessages(filter, { max: 1, time: 15000})
.then(collected => {
question = `${collected.first()}?`;
message.channel.send('Question: ' + question);
for (var i = 0; i < args[1]; i++) {
message.channel.send('What is option ' + (i + 1) + '?').then(() => {
message.channel.awaitMessages(filter, { max: 1, time: 15000})
.then(collected => {
options[i] = collected.first;
message.channel.send(`Option ${i}: ${options[i]}`);
})
.catch(collected => {
message.channel.send('Poll has timed out.');
});
})
}
})
.catch(collected => {
message.channel.send('Poll has timed out.');
});
const embed = new Discord.MessageEmbed()
.setColor(3447003)
.setTitle(question)
.setDescription('choose an option')
/*
if (options[0]) .addField('1️⃣:' + option[0])
if (options[1]) .addField('2️⃣:' + option[1])
if (options[2]) .addField('3️⃣:' + option[2])
if (options[3]) .addField('4️⃣:' + option[3])
if (options[4]) .addField('5️⃣:' + option[4])
if (options[5]) .addField('6️⃣:' + option[5])
if (options[6]) .addField('7️⃣:' + option[6])
if (options[7]) .addField('8️⃣:' + option[7])
if (options[8]) .addField('9️⃣:' + option[8])
if (options[9]) .addField('🔟:' + option[9])
*/
message.channel.send(embed).then(embedMessage => {
if (options[0]) embedMessage.react('1️⃣');
if (options[1]) embedMessage.react('2️⃣');
if (options[2]) embedMessage.react('3️⃣');
if (options[3]) embedMessage.react('4️⃣');
if (options[4]) embedMessage.react('5️⃣');
if (options[5]) embedMessage.react('6️⃣');
if (options[6]) embedMessage.react('7️⃣');
if (options[7]) embedMessage.react('8️⃣');
if (options[8]) embedMessage.react('9️⃣');
if (options[9]) embedMessage.react('🔟');
});
});
}
}
}
Since you say you are trying to use await in your loop, let me take the function it is contained in out from your snippet, format it a little, and try to do some explaining. Disclaimer: I am no expert, so I am learning as well.
.then(collected => {
question = `${collected.first()}?`;
message.channel.send(`Question: ${question}`);
for (var i = 0; i < args[1]; i++) {
message.channel.send(
`What is option ${i + 1}?`
).then(() => {
message.channel.awaitMessages(filter, {
"max": 1,
"time": 15000,
}).then(collected => {
options[i] = collected.first;
message.channel.send(`Option ${i}: ${options[i]}`);
}).catch(collected => {
message.channel.send("Poll has timed out.");
});
});
}
});
But before that, as the first inner .then() still returns a Promise, you can chain the second inner .then() in the outer scope to avoid nesting them too deep, and leave a single .catch() at the end. On that note, it would probably be more accurate to call the catch's parameter something like error. So here's the new snippet:
.then(collected => {
question = `${collected.first()}?`;
message.channel.send('Question: ' + question);
for (var i = 0; i < args[1]; i++) {
message.channel.send(
`What is option ${i + 1}?`
).then(() => {
message.channel.awaitMessages(filter, {
"max": 1,
"time": 15000,
});
}).then(collected => { // Change .then() chaining
options[i] = collected.first;
message.channel.send(`Option ${i}: ${options[i]}`);
}).catch(error => { // Change parameter name
message.channel.send("Poll has timed out.");
});
}
})
What's happening now is that each iteration is running one after the other immediately. You .send() a whole bunch of messages which each return a Promise, and off that Promise, you pass a callback function to .then() which runs once each Promise resolves into a Message. That callback implicitly returns the result of .awaitMessages(), which is also a promise, and once that resolves, the next callback in the next .then() runs with the value of whatever the previous promise resolved to passed in as an argument, and so on.
Alright, so you want to the entire Promise chain to finish processing and resolve before proceeding to the next iteration, right? You can use the await keyword to suspend progress in the relevant anonymous function, until its associated promise-based operation either resolves or rejects. The catch is that that function has to be marked with the async keyword, and in your code, that is not actually the case, you are just making use of Promises and callback functions (regarding "but it is an async function I think"). So, let's add both the aforementioned keywords:
.then(async collected => { // Mark as async
question = `${collected.first()}?`;
message.channel.send('Question: ' + question);
for (var i = 0; i < args[1]; i++) {
await message.channel.send( // Wait for this entire Promise chain to resolve before proceeding
`What is option ${i + 1}?`
).then(() => {
message.channel.awaitMessages(filter, {
"max": 1,
"time": 15000,
});
}).then(collected => {
options[i] = collected.first;
message.channel.send(`Option ${i}: ${options[i]}`);
}).catch(error => {
message.channel.send("Poll has timed out.");
});
}
})
That should cause your desired behaviour, though my edits may have syntax errors as I have not ran it myself. If I got something wrong, please do comment.
You can read more here:
Using async-await
Using Promises

How can I determine the time to send the message

How can I set the duration of the message Example:
if (message.content === 'test') {
message.channel.send (`he say test in 22seconds`)
}
If you're looking for the time it took to the bot to receive the message, use:
if (message.content === 'test') {
const seconds = ((Date.now()-message.createdTimestamp)/1000).toFixed(2);
message.channel.send (`he say test in ${seconds} seconds`)
}
What you are looking for is setTimeout() function.
if (message.content === 'test') {
setTimeout(function(){
message.channel.send (`it took me 22seconds to send this message.`);
}, 22000);
}
Hmm.. the question is not too clear but I'm guessing you mean once the user types a command, the bot says something and then the user can reply with test and the bot tells you how long it took you to type test? (Give the code a try and if its not what you wanted you can take parts out. :) )
The code:
const prefix = ''; //Put whatever prefix you want in the `(prefix goes here)`
var intervals;
bot.on("message", msg => {
let args = msg.content.substring(prefix.length).split(" ");
switch (args[0]) {
case "test": // You can call the command whatever you want
let timer = 3;
msg.channel.send("Get ready").then(msg => {
intervals = setInterval(function() {
msg.edit(`Type test in the chat in **${timer--}**..`);
}, 1000);
});
setTimeout(() => {
clearInterval(intervals);
msg.channel
.send(`Type test in the chat`)
.then(() => {
const time = Date.now();
msg.channel
.awaitMessages(
function(userMsg) {
if (userMsg.content === "test") return true;
},
{
max: 1,
time: 10000,
errors: ["time"]
}
)
.then(function(collected) {
const endTime = Date.now();
let successMsg = "Congratulations!\n";
let collectedArr = Array.from(collected.values());
for (let msg of collectedArr) {
let timeDiff = (endTime - msg.createdTimestamp) / 100;
successMsg += `You took ${timeDiff} seconds to type test.\n`;
}
msg.channel.send(successMsg);
})
.catch(function(collected) {
msg.channel.send(`You did not answer in time!`);
});
})
.catch(function(err) {
console.log(err);
});
}, 5000);
break;
}
});
I'm not too sure what you're asking for but hope this is it! Again, give it a try and see if it works.
Im guessing you need the bot to send that message in 22 seconds. If thats the case then do this
if (message.content === 'test') {
setTimeout(() => { // setTimeout function dalays code inside of it for a set period of time
message.channel.send (`he say test in 22seconds`); // Your code
}, 22000); // The amount of time it should be delayed for. 22000 (milliseconds) = 22 seconds
}

Unsubscribe from timer in rxjs

Hi I have a timer running which is like it should show a component for 30sec after every 10 seconds. My code is like this`
import { timer } from "rxjs";
componentWillReceiveProps(nextProps, nextState) {
console.log("RECEIVED PROPS");
if (this.props.venuesBonusOfferDuration === 0) {
this.subscribe.unsubscribe();
}
this.firstTimerSubscription;
this.secondTimerSubscription;
// if (this.state.isMounted) {
if (
nextProps.showBonusObj &&
(!nextProps.exitVenue.exitVenueSuccess || nextProps.enterVenues)
) {
// console.log("isMounted" + this.state.isMounted);
//if (this.state.isMounted) {
let milliseconds = nextProps.venuesBonusOfferDuration * 1000;
this.source = timer(milliseconds);
this.firstTimerSubscription = this.source.subscribe(val => {
console.log("hiding bonus offer");
this.firstTimerSubscription.unsubscribe();
this.props.hideBonusOffer();
this.secondTimerSubscription = bonusApiTimer.subscribe(val => {
console.log("caling timer" + val);
this.props.getVenuesBonusOffer(
this.props.venues.venues.id,
this.props.uid,
this.props.accessToken
);
});
});
//}
} else {
try {
if (this.secondTimerSubscription != undefined) {
this.secondTimerSubscription.unsubscribe();
console.log("secondTimer UNSUBSCRIBED");
}
if (this.firstTimerSubscription != undefined) {
this.firstTimerSubscription.unsubscribe();
console.log("firstTimer UNSUBSCRIBED");
}
} catch (error) {
console.log(
"error when removing bonusoffer timer" + JSON.stringify(error)
);
}
//}
}
}
`
Problem is if I try to unsubscribe this * this.firstTimerSubscription* and this.secondTimerSubscription like this
try {
if (this.secondTimerSubscription != undefined) {
this.secondTimerSubscription.unsubscribe();
console.log("secondTimerunmount UNSUBSCRIBED");
}
if (this.firstTimerSubscription != undefined) {
this.firstTimerSubscription.unsubscribe();
console.log("firstTimerunmount UNSUBSCRIBED");
}
} catch (error) {
console.log("error bonusoffer timer" + JSON.stringify(error));
}
its still prints logs within timer like "hiding bonus offer" and "calling timer".
Can someone please point out the issue. It been a day since am into this.
Any help is appreciated.
The problem is that you subscribe multiple times (whenever component receives props) and reassign newest subscription to firstTimerSubscription or secondTimerSubscription references. But doing that, subscriptions does not magically vanish. To see how it works here is a demo:
const source = timer(1000, 1000);
let subscribe;
subscribe = source.subscribe(val => console.log(val));
subscribe = source.subscribe(val => console.log(val));
setTimeout(() => {
subscribe.unsubscribe();
}, 2000)
Even though you unsubscribed, the first subscription keeps emiting. And the problem is that you lost a reference to it, so you can't unsubscribe now.
Easy fix could be to check whether you already subscribed and unsubscribe if so, before subscribing:
this.firstTimerSubscription ? this.firstTimerSubscription.unsubscribe: false;
this.firstTimerSubscription = this.source.subscribe(...
I wouldn't use a second timer. Just do a interval of 10 seconds. The interval emits the iteration number 1, 2, 3..... You can use the modulo operator on that tick. Following example code (for example with 1 second interval) prints true and false in console. After true it needs 3 seconds to show false. After false it needs 1 second to show true.
interval(1000).pipe(
map(tick => tick % 4 !== 0),
distinctUntilChanged(),
).subscribe(x => console.log(x));

Can anyone explain why my state is getting updated even when i dont set it manually

So I just spent an hour debugging this code and finally got it to work, but I would want to know why this happened in the first place. I have a function that takes a value from my state, operates on it and saves the output in another variable in the state. This is the fuction:
getFolderNames = async () => {
const promises = this.state.rows.map(async item => {
if (item[".tag"] == "folder" && item.name.length > 20) {
item.name = await getFolderName(item.name);
return item;
} else return item;
});
const result = await Promise.all(promises);
this.setState({
rowsToDisplay: result
});
};
when i run this function, it was updating both the rows and rowsToDisplay to the result variable when i was only calling setState on only one of them.
Changing the function as below solves the issue but I would like to know why.
getFolderNames = async () => {
const promises = this.state.rows.map(async item => {
if (item[".tag"] == "folder" && item.name.length > 20) {
let item2 = {
...item
};
item2.name = await getFolderName(item.name);
return item2;
} else return item;
});
const result = await Promise.all(promises);
this.setState({
rowsToDisplay: result
});
};
It's because of how JavaScript handles variables. When you set a variable to an array or object, it doesn't make a new object but rather just references the original array/object.
As such, if you set a variable to equal some object, and then set a property of that variable, the original object will also be updated. Check this snippet for an example.
var foo = {changed: false};
var bar = foo;
bar.changed = true;
console.log("foo", foo.changed)
console.log("bar", bar.changed)
You can read more about the subject here: https://codeburst.io/explaining-value-vs-reference-in-javascript-647a975e12a0
I hope this helps you in the future, since I know I also spent many hours banging my head against exactly the sort of cases you described in your original question.

Resources