0

So I've just recently decided to try creating a Discord bot. I am only a beginner at the moment so I've been having some difficulty with creating one command for my discord bot. I want to create a command that can kill any previously running command, such as a //say or a //spam (This is a fun orientated bot that I'm playing around with, so it allows some "spammy" exploits such as the bot constantly replying to itself (ie. //say //say //say //say etc. causes the bot to run the //say command until all the //says have been executed.)

Because of this, I want there to be a way to kill the command if it gets out of hand with another command. I've tried a bunch of stuff, but nothing seems to work.

Here is what I tried first: (note: task is defined, so that is not the issue, it is just not visible in this codeblock)

//stuff up to this point works fine
  if (msg.content.startsWith(`${prefix}say`)) {
    task = 1;
    var text = msg.content.split(' ').slice(1).join(' ');
    if(!text) return msg.reply('hello?');
        if (task === 1) {
        msg.channel.send(text);
    } else if (task === 0) {
            return;   
    }
  if (msg.content.startsWith(`${prefix}cease`)) {
    task = 0;
    msg.channel.send('Task terminated successfully.');
  }
});

However, the bot completely ignores this and continues running the //say command even if the user has attempted to execute a //cease command.

I decided to try and play around with while loops after that, like this:

//stuff up to this point work fine
  if (msg.content.startsWith(`${prefix}say`)) {
    task = 1;
    var text = msg.content.split(' ').slice(1).join(' ');
    if(!text) return msg.reply('hello?');
    while (task === 1) {
        msg.channel.send(text);
    }
    }
  if (msg.content.startsWith(`${prefix}cease`)) {
    task = 0;
    msg.channel.send('Task terminated successfully.');
  }
});

However, this just makes the command prompt completely freak out with random stuff that I don't have the slightest clue about what it means. All I can understand is that the process ran out of memory...I think.

Here's what happens.

<--- Last few GCs --->

[18668:000002D05FC41820]    31983 ms: Mark-sweep 1397.8 (1425.2) -> 1397.3 (1424.7) MB, 892.1 / 0.0 ms  (average mu = 0.089, current mu = 0.015) allocation failure scavenge might not succeed
[18668:000002D05FC41820]    31990 ms: Scavenge 1398.1 (1424.7) -> 1397.6 (1425.2) MB, 5.5 / 0.0 ms  (average mu = 0.089, current mu = 0.015) allocation failure


<--- JS stacktrace --->

==== JS stack trace =========================================

    0: ExitFrame [pc: 000003DFF175C5C1]
    1: StubFrame [pc: 000003DFF175D9BF]
Security context: 0x00069561e6e9 <JSObject>
    2: Channel [00000127FFD14059] [C:\Users\[removed]\Documents\epic-bot\node_modules\discord.js\src\util\Constants.js:~165] [pc=000003DFF1A16AA6](this=0x0127ffd12799 <Object map = 0000023F67AEB559>,channelID=0x0199da820629 <Channel map = 000001B00E5314E1>)
    3: /* anonymous */(aka /* anonymous */) [000000DACB142C...

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
 1: 00007FF6F1A9F04A v8::internal::GCIdleTimeHandler::GCIdleTimeHandler+5114
 2: 00007FF6F1A7A0C6 node::MakeCallback+4518
 3: 00007FF6F1A7AA30 node_module_register+2032
 4: 00007FF6F1D020EE v8::internal::FatalProcessOutOfMemory+846
 5: 00007FF6F1D0201F v8::internal::FatalProcessOutOfMemory+639
 6: 00007FF6F2222BC4 v8::internal::Heap::MaxHeapGrowingFactor+9556
 7: 00007FF6F2219C46 v8::internal::ScavengeJob::operator=+24310
 8: 00007FF6F221829C v8::internal::ScavengeJob::operator=+17740
 9: 00007FF6F2220F87 v8::internal::Heap::MaxHeapGrowingFactor+2327
10: 00007FF6F2221006 v8::internal::Heap::MaxHeapGrowingFactor+2454
11: 00007FF6F1DDCDB7 v8::internal::Factory::NewFillerObject+55
12: 00007FF6F1E72CC6 v8::internal::WasmJs::Install+29414
13: 000003DFF175C5C1

The answer is probably super basic but as I said, I'm just starting out.

Any help would be appreciated.

Thanks!

1 Answers1

1

Disclaimer: Your current usage would be considered API abuse. This answer is for learning purposes and not intended to be implemented.

You're correct about your error; your while loop causes a crash because your CPU runs out of available memory. It goes on infinitely and uses all the available resources it can. As explained here, setInterval() with an interval of 0 milliseconds is a better option, but still demanding.

Because Discord has rate limits in place, your bot would stop sending messages if it tried to send more than 5 within a time span of 5 seconds. Therefore, you could do something like this...

const args = message.content.trim().split(/ +/g);

/* say command */
const text = args.slice(1).join(' ');
if (!text) return;

const interval = setInterval(function() {
  message.channel.send(text)
    .catch(err => {
      console.error(err);
      clearInterval(interval);
    });
}, 1000);

task = interval;


/* cease command */
clearInterval(task);
slothiful
  • 5,548
  • 3
  • 12
  • 36
  • Out of curiosity, how is this API abuse? – MoneyHurricane May 13 '19 at 13:07
  • This seems to be more harmful and negative than fun. It's spam and could be used to annoy users. Going any faster than 1 second would also hit rate limits which should not be ignored. – slothiful May 13 '19 at 13:40
  • Ah, I see where you're coming from. However, I've been allowed to test this bot only in one of the spam channels in the server that I am in, so it's all good. :) – MoneyHurricane May 13 '19 at 21:53
  • Ok, so I did some tinkering with the code, and changed up the format a bit because it was throwing unexpected token errors and undefined errors. However, the cease command still doesn't work. Except now, the bot just keeps spamming the post until my system gets overloaded and crashes the program, as well as freezes my pc. With your way, there is no way for the command to naturally end, as there was before. Can you review my code on Github and tell me what is wrong since I can't make these more than 500 characters? Thanks. https://github.com/moneyhurricane/EpicBot/blob/master/bot.js – MoneyHurricane May 14 '19 at 01:37
  • 1
    @MoneyHurricane at line 10 you (re)define the task variable on each message recieved. Thus when you first call the `//say` command, `task` is filled with the interval but when you call the `//cease` command, the `task` variable will be reset because of line 10. To fix this, you have to define the `task` variable outside of the message handler. In other words, move line 10 to line 3 or line 7 – T. Dirks May 14 '19 at 08:33
  • Moved the task variable to Line 3 of my code. Bot is able to run on local host, but still ignores the //cease command, and continues to run until I Ctrl+C it in the command prompt, or it makes my PC lag. Heroku, the service I'm using to host the bot 24/7, just crashes before the app is even able to boot, with exit code 0. – MoneyHurricane May 14 '19 at 23:50
  • Forked and updated code. See [here](https://github.com/moneyhurricane/EpicBot/compare/master...slothiful:patch-1?diff=split). – slothiful May 15 '19 at 00:03
  • Finally got this working after some additional tinkering! Thanks, you're help is greatly appreciated. I probably wouldn't have figured it out without you. – MoneyHurricane May 15 '19 at 01:35
  • Make sure to mark the Answer with the green tick @MoneyHurricane! – PLASMA chicken May 18 '19 at 22:40