0
votes

The issue is that whenever there is a connection hiccup then the bot reconnects because I want it to, it will send multiple messages at a time essentially spamming a channel. I run it 24/7 on a raspberry pi so it accumulates multiple hiccups per day and I'm guessing this is what happening. On occasion it has send tens of messages when its time schedule hits.

I have been able to replicate it duplicating 2 messages by unconnecting my internet while running the bot for a few mins then when it reconnects the next time the event happens (I have it set to trigger every 60 seconds rather than midnight for debugging reasons.) So far I cannot figure out why it would be sending multiple messages.

const Discord = require('discord.js');
const bot = new Discord.Client({autoReconnect: true});
const cfg = require('./config.json');
const fs = require('fs');
const folder = './countdown/';
const schedule = require('node-schedule')
var currentdate =  new Date();
const days = 1000 * 60 * 60 * 24;

//This section checks which command is used
bot.on('message', message => {
    //This will check if the message starts with the command prefix '!'. Then it will store the parameters in $args and #command
    if (!message.content.startsWith(cfg.prefix) || message.author.bot) return; 
    const eventName = message.content.slice(cfg.prefix.length).split(/ +/); 
    const command = eventName.shift();
    const args = eventName.splice(0,3);
    console.log(`Args: ${args}\nCommand: ${command}`);

    switch(command.toLowerCase()){
        //This will check if the event is in the past or not, if not then it will store it as a json with information: Event name and date
        case "countdown":
            var releasedate = new Date(`${args}`),
            currentdate = new Date(),
            diff = releasedate - currentdate;
            if(Math.ceil(diff / days) > 0 && `${eventName.length}` > 0){ //this will check if the event has a name and if it has happened
                message.channel.send(Math.ceil(diff / days) + ` days until ${eventName.join(' ')}`);
                //This will create a .json file with a specific format containing the event name and date
                var fileContent = `{\n"releasedate": "${args.join(' ')}", \n"eventName": "${eventName.join(' ')}"\n}`,
                filepath = `./countdown/${eventName.join('_')}.json`;
                fs.writeFile(filepath, fileContent, (err) => {
                if (err) throw err;
                console.log("The file was succesfully saved!");
                });
            }
            else if(`${eventName.length}` == 0){ //if the event does not have a name
                message.channel.send('Please enter an event date.')
            }
            else{ //if the user enters a date that already occured
                message.channel.send('Event already occured. Use "!days_since" instead.')
            }
            break;     
        //This will tell how many days has happened since an event
        case "days_since":
            var start = new Date(`${args}`), //ex January 1, 2016"
            end = new Date(),
            diff = end - start;
            message.channel.send(Math.floor(diff / days) + " days have passed since " + start)
            break;
        case "help":
            message.channel.send('usage is !{command} \n!countdown notation is Month Day Year Eventname ex. January 1, 2019 New Years!\n!days_since notation is the same as !countdown without {name}');
            break;
        default:
            message.channel.send('This is not a command refer to !help');
    }
});
    bot.on('ready', () => {
        var sendChannel = bot.channels.find(channel => channel.id === '556254985114091531') //id of channel to send in 277649480877211649 = countdown chat 556254985114091531 = test channel

        //This is a cron job which activates at 00:01 every day
        var j = schedule.scheduleJob('01 * * * * *', function(){ //second(0 - 59)(optional), minute(0 - 59), hour(0 - 23), day(1 - 31), month (1 - 12), day of week(0 - 7)
            var currentdate = new Date();

            //This function will read the data in the .json files and retrieve the data
            fs.readdir(folder, (err, files) => {
                if(files.length < 24 && !files.length == 0) { //this will check if there are more than 25 files, and not 0 so that .addField does not error (max 25).
                    var embed = new Discord.RichEmbed()
                    for(i = 0; i < files.length; i++){ //loop through all files in ./countdown
                        var input = require(folder+files[i]);
                            if(((new Date(input.releasedate) - currentdate) / days) > 0) //this checks if the event has happened or not
                            {
                                //This section creates the embeded message of all current active countdowns 
                                embed.addField(input.eventName, Math.ceil((new Date(input.releasedate) - currentdate) / days) + ' days until ' + input.eventName, true) //this adds however many events are stored
                                r = Math.floor(Math.random() * 256).toString(16);
                                g = Math.floor(Math.random() * 256).toString(16);
                                b = Math.floor(Math.random() * 256).toString(16);
                                r = (r.length==2)?r:'0' + r; //this checks if r.length is 2 digits then if not adds a 0 infront
                                g = (g.length==2)?g:'0' + g;
                                b = (b.length==2)?b:'0' + b;
                                var color = `#${r}${g}${b}`;
                                embed.setColor(color);
                            }
                            else if(Math.ceil((new Date(input.releasedate) - currentdate) / days) == 0){ //this will send a message saying today is "x" 
                                sendChannel.send(`Today is ${input.eventName}!`);
                                console.log(`${input.eventName} is today`);
                            }
                            else //this lets you know which .json value is negative
                            {
                                console.log("arg not passed, invalid or past: "+input.eventName)
                            }   
                    }       
                }
                else if(files.length == 0){
                    sendChannel.send('Add an event to start counting down.')
                }
                else{
                    sendChannel.send('Too many events, contact owner to remove some.');
                }
                sendChannel.send(embed);
            });
        });

        console.log("Ready")
        console.log(`Logged in at ${currentdate}`)
        console.log(`Logged in as ${bot.user.tag} (${bot.user.id}) on ${bot.guilds.size} servers`);
        bot.user.setActivity(`Counting things down | ${bot.guilds.size} servers`);
    });
bot.on('error', err => {
    console.error(err);
});

bot.login(cfg.token);

The expected result would be to only send one message per schedule event, but it is sending multiple

1

1 Answers

0
votes

use combination of Promise and a isReady flag to make Sure bot is ready to send messages

const client = new Client();
let isReady = false
client.on('error', function (d) {
  console.log(d.responsee, 'discord client err')
})
client.on('ready', function (d) {
  isReady = true
})
function sendMessage(text = 'no text') {
  text = String(text)
  return new Promise((resolve, reject) => {
    if (isReady) {
      let message = client.channels.get(config.discordChannel)
      message.send(text)
        .then(a => {
          resolve({ success: true })
        }).catch(e => {
          reject(e)
        })
    }
  })
}
client.login(config.discord).then(a => {
  console.log(a, 'discord client login')
}).catch(e => {
  console.log(e, 'discord login err')
});