Discord.JS - Storing the client and forwarding messages from the event-listener

Hi!

I'm currently using Discord.JS and Nodered to create a Discord bot. I have set up an function node which establishes the connection and then stores the session(the client) in gobal context for later use. The function node also listens for new messages. If i were to send this message through the flow for further processing, then NodeRed would crash. I have to extract the properties i want into a new object(contains user id's, message content and so on) .

If i want to process this message in another function node, i would have to import the client from global context, and use the newly created object to determine which message the bot would reply to etc. This creates extra overhead due to me then having to create new objects all the time, instead of being able to just using the built in methods in the message. Is there a way to forward the object and its content and functions created by the event-listener?

I have set up examples with codesnippets to further help me explain my issues due to me not being fluent in neither English or Javascript :stuck_out_tongue:

In a regular nodejs-app you would handle 'everything' in a single file

const Discord = require('discord.js');
const client = new Discord.Client();

client.on('ready', () => {
  console.log(`Logged in as ${client.user.tag}!`);
});
// This is the event listener and message object im talking about. It's pretty easy to reply to the message by using the .reply-method. 
client.on('message', msg => {
  if (msg.content === 'ping') {
    msg.reply('Pong!');
  }
});

client.login('token');

If i want to handle the bots logic using nodered and its flow-based approach, i would have to do something like this:

The node which establishes the connection:

const client = new Discord.Client();

// Makes the client session available for  later use
global.set('DCClient', client);

// This is the event listener and message object im talking about. 
client.on('message', message => {
    // Do not react to own messages
    if (message.author.bot) return;

    const ChannelId = message.channel.id
    const MessageId = message.id
    const GuildId = message.guild.id
    const SenderMemberId = message.member.id
    const Content = message.content
    const Attachments = message.attachments

    // I have to create a new object due to not being able to send the 'message'-object
    let msg = {
        ChannelId: ChannelId,
        MessageId: MessageId,
        GuildId: GuildId,
        SenderMemberId: SenderMemberId,
        Content: Content,
        Attachments: Attachments
    }

    // node.send(message) does not work
    node.send(msg)

})

The node connected to the listeneer-node which replies to the message:

const client = global.get('DCClient')

if(msg.Content === 'ping'){
   client.channels.cache.get(msg.ChannelId).send(msg.payload)
}

May not seem much from the examples provided, but it's bothering me.

It might be related to the message being cloned by node.send

Personally I would still send a msg object but request that it is not cloned e.g...

var msg = {
   message: message
}
node.send(msg, false);

This is very inexpensive operation since it only assigns a reference to the message in the msg object (it doesn't copy it).

To read up on the cloning and why it happens, see "Cloning messages in a flow : Node-RED" Cloning messages in a flow : Node-RED

Hi, Steve!

Tried your suggestion, but NodeRed crashed and reported this error:

RangeError: Maximum call stack size exceeded
nodered     |     at /usr/src/node-red/node_modules/lodash.clonedeep/index.js:252:23
nodered     |     at Map.forEach (<anonymous>)
nodered     |     at mapToArray (/usr/src/node-red/node_modules/lodash.clonedeep/index.js:252:7)
nodered     |     at cloneMap (/usr/src/node-red/node_modules/lodash.clonedeep/index.js:1030:34)
nodered     |     at initCloneByTag (/usr/src/node-red/node_modules/lodash.clonedeep/index.js:1290:14)
nodered     |     at baseClone (/usr/src/node-red/node_modules/lodash.clonedeep/index.js:877:16)
nodered     |     at /usr/src/node-red/node_modules/lodash.clonedeep/index.js:897:30
nodered     |     at arrayEach (/usr/src/node-red/node_modules/lodash.clonedeep/index.js:140:9)
nodered     |     at baseClone (/usr/src/node-red/node_modules/lodash.clonedeep/index.js:891:3)
nodered     |     at /usr/src/node-red/node_modules/lodash.clonedeep/index.js:897:30
nodered     |     at arrayEach (/usr/src/node-red/node_modules/lodash.clonedeep/index.js:140:9)
nodered     |     at baseClone (/usr/src/node-red/node_modules/lodash.clonedeep/index.js:891:3)
nodered     |     at /usr/src/node-red/node_modules/lodash.clonedeep/index.js:897:30
nodered     |     at arrayEach (/usr/src/node-red/node_modules/lodash.clonedeep/index.js:140:9)
nodered     |     at baseClone (/usr/src/node-red/node_modules/lodash.clonedeep/index.js:891:3)
nodered     |     at /usr/src/node-red/node_modules/lodash.clonedeep/index.js:897:30
nodered     |     at arrayEach (/usr/src/node-red/node_modules/lodash.clonedeep/index.js:140:9)
nodered     |     at baseClone (/usr/src/node-red/node_modules/lodash.clonedeep/index.js:891:3)
nodered     |     at /usr/src/node-red/node_modules/lodash.clonedeep/index.js:897:30
nodered     |     at arrayEach (/usr/src/node-red/node_modules/lodash.clonedeep/index.js:140:9)
nodered     |     at baseClone (/usr/src/node-red/node_modules/lodash.clonedeep/index.js:891:3)
nodered     |     at cloneMap (/usr/src/node-red/node_modules/lodash.clonedeep/index.js:1030:24)
nodered     |     at initCloneByTag (/usr/src/node-red/node_modules/lodash.clonedeep/index.js:1290:14)
nodered     |     at baseClone (/usr/src/node-red/node_modules/lodash.clonedeep/index.js:877:16)
nodered     |     at /usr/src/node-red/node_modules/lodash.clonedeep/index.js:897:30
nodered     |     at arrayEach (/usr/src/node-red/node_modules/lodash.clonedeep/index.js:140:9)
nodered     |     at baseClone (/usr/src/node-red/node_modules/lodash.clonedeep/index.js:891:3)
nodered     |     at /usr/src/node-red/node_modules/lodash.clonedeep/index.js:897:30

Would you share your flow - still looks like it's being cloned.

I removed small parts of the code(Comments etc), but here is the function node which also acts as a listener:

const client = new Discord.Client();
const guildmanager = new Discord.Guild(client);
const ApiKey = global.get('Bot','secrets')

global.set('DCClient',client)

client.on('ready', () => {
    node.warn(`logged in as ${client.user.tag}`);
    node.status({fill:"green",shape:"dot",text:"connected"});
});


client.on('message', message => {
    // Do not react to own messages
    if(message.author.bot) return;
    var msg = {
        message: message
    }
    node.send(msg, false)
    
    
})


client.login(ApiKey)

client.on('disconnect', () => {
    node.status({fill:"red",shape:"dot",text:"disconnected"});
    node.warn(`${client.user.tag} disconnected.`);

    global.set('DCClient',null)
    
});


node.on('close', () => {
    client.destroy();
    node.status({fill:"red",shape:"ring",text:"disconnected"});
    node.warn(`${client.user.tag} disconnected.`);

    global.set('DCClient',null)
}) 

It seems that you are correct about the cloning part, @Steve-Mcl ! Thanks for pointing me in the right direction. I frequently use debug nodes, so if i connect my initial node to a debug node and another function node, my flow is indeed branching and therefore cloning the message-object. Is there a way to let the debug-node bypass this?

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.