Discord.js - Without using Client EventEmitter cannot get channels property - node.js

I still have yet to get a better grasp of Node.js, but as I was tinkering around with my Discord bot, I couldn't seem to find a way to get the list of channels the bot was in without putting it in an EventEmitter. I'm rather confused as to why this wouldn't work, is there something that I'm missing?
Code:
const Discord = require("discord.js");
const client = new Discord.Client();
require('dotenv').config();
//this works
client.on('ready', ()=> {
const channelID = '803359668054786118';
const channel = client.channels.cache.get(channelID);
channel.send('working'); //this works
});
//this doesn't work
//intially tried using a wait function to see if the reason was because bot didn't have enough time to log on properly
setTimeout(function() {
const channelID = '803359668054786118';
const channel = client.channels.cache.get(channelID);
console.log(client.channels); //this is telling me that there's no channels in the collection...
//channel.send('working');
}, 500);

This is because the client is not logged in at that point of your code. At the compile stage of your file, the compiler runs through your code and compiles everything outside of event listeners. Once Client#login() is called, this is when the client has it's context. All of it's event listeners (ready, message ect.) are binded to the client.
In other words, the Discord client is not logged in when code outside of events being is compiled. Code inside events are executed once the client is logged in & the event itself is emitted.

Related

TypeError: throw new TypeError('CLIENT_MISSING_INTENTS'); Issue

I am recieving this message even though I added intents to my Index.js
Discord.js version: 13.3.1
Node: 16.6.1
Code of my Index.js
const config = require('../config.json');
const mongoose = require('mongoose');
const Discord = require("discord.js");
const bot = new Discord.Client();
const { Intents } = require('discord.js');
const client = new Client({ intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES] });
bot.on("ready", () => {
console.log(`Bot is online!\n${bot.users.size} users, in ${bot.guilds.size} servers connected.`);
});
// HERE IS MONGODB BUT NOT SHOWING
const Client = require('./Structures/Client');
const WelcomeSchema = require(`../src/Models/welcome`)
bot.on("guildMemberAdd", async (member, guil) => {
WelcomeSchema.findOne({ guildId: member.guild.id }, async (err, data) => {
if(!data) return;
const user = member.user;
const channel = member.guild.channels.cache.get(data.channelId);
channel.send({embed: {color: "BLUE", description: `sd`}})
})
})
const client = new Client(config);
client.start();
Would mean a lot if you could help me find the issue. Thanks!
I now realise that there are quite a few issues with the code you have provided.
No. 1 - Client Definitions
It looks like you're defining three different clients. (bot, client, and possibly Client.)
You should organise your code in such a way that all events and commands are tied to one client object, as having multiple clients running can lead to rate-limiting and performance issues. (as well as being completely and utterly pointless.)
The error seems to be stating that bot is not given any intents during its creation, which could be fixed with the use of...
// ...
const bot = new Discord.Client({ intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES] });
// ...
No. 2: Reference to an Undefined Variable
On the line where you define client at the start of the file, you use new Client, despite the fact that Client has not been imported yet, and is imported later in the file. This won't work, as Client is undefined at that point in the program.
No. 3: Re-assignment of a constant
It also seems that you re-assign another const client near the end of your file. This will cause an error, as client is already a defined constant which cannot be over-written.
No. 4: Access to Message Intents (maybe???)
As of recently, discord requires that you enable Gateway Intents to be able to access certain events and data (such as Server Messages and Members).
To enable the intents, head to the Discord Developer Dashboard for your bot, select "Bot" from the sidebar, and enable the intents you need access to.
While this intent is not required to be able to read messages until April 30th, 2022, if your bot specifies the GUILD_MESSAGES intent, this option needs to be enabled.
If your bot is in more than 100 servers, you will need to verify your bot to be able to continue accessing data which requires these intents. More about that here.

How to share a single promise based RabbitMQ connection across files or controllers in Node js instead of creating a new Connection each time?

amqplib library lets you create a rabbitmq connection and that object will be a segue to doing other things such as creating a channel and etc.
suppose that I'm going for a Producer/Consumer pattern, where each time a user hits a specific route, a job is produced and sent to the rabbitmq server where it's processed by certain consumers(workers).
app.post("/routethatdelegatesheavywork", async (req,res) => {
const amqpServerLink =
"link-to-cloudmq";
const connection = await amqp.connect(amqpServerLink);
const channel = await connection.createChannel();
//do other stuff with channel
})
while this "works", but i don't want to re-create that connection every time the controller is invoked since it makes the producer very slow and it's really not how it's supposed to be done.
here is where my problem comes:
how do i initialize one connection and re-use it every time i need it?
i have tried to create a connection outside controllers and use it when necessary but it's not possible since the connection is promise-based and await doesn't work on entry point and it has to be inside an async function to work.
although it is possible to run await without async using ESM (es modules) i don't want to do so since i have written all of the application using CommonJS (require("package")), changing that would require me to go through a lot of files and change every import/export according to ESM.
So, is there any other way to create one connection(that is promise based) and re-use it without having to migrate to ESM syntax?
Yes, remember that require in nodejs are singletons. Make a new amqpServerInterface module, and do
const amqpServerLink = "link-to-cloudmq"
const connection = amqp.connect(amqpServerLink)
function connect() {
return connection
}
module.exports = {
connect
}
Then in your controllers
const amqpServerInterface = require('amqpServerInterface')
app.post("/routethatdelegatesheavywork", async (req,res) => {
const connection = await amqpServerInterface.connect();
const channel = await connection.createChannel();
//do other stuff with channel
})
This will always return the same connection promise and will resolve to the save connection.

How to make a ping-pong discord bot with websocket in Nodejs?

Im trying to make a simple ping-pong discord bot in Nodejs without any lib like discord.js in Nodejs
I think that using websockets with the rest api of discord is the best solution but I cant find any help or any code example to do it
I found this course : https://courses.cs.washington.edu/courses/cse154/17au/exploration/websockets/slides.html#/
with this "solution" that I can't understant : https://courses.cs.washington.edu/courses/cse154/17au/exploration/websockets/solution/
And this is an extract from the course :
const BOT_TOKEN = "xxx";
// Discord Gateway url
const GATEWAY_URL = "wss://gateway.discord.gg/?v=6&encoding=json";
// Websocket object
let ws = null;
connect();
// connect to gateway
function connect() {
ws = new WebSocket(GATEWAY_URL); // opens the websocket connection and creates WS object
ws.onmessage = messageHandler; // on message event
ws.onclose = connect; // reopen websockets when closed by discord
}
What I want to do can be simply done with this code using discord.js :
const Discord = require('discord.js');
const bot = new Discord.Client();
bot.on('ready', function () {
console.log("Connected !")
})
bot.on('message', message => {
if (message.content === 'ping') {
message.reply('pong !')
}
})
bot.login(token)
Any help please ?
I'm the one who provided this talk. While the lecture code does interact with Discord, it is not the most optimal method of doing so. Personally I would suggest using discord.js to create a bot that would respond to your ping.
For reference, the lecture I demonstrated in class is to showcase the functionality of websockets. It is executed within the browser and not with the help of node.js.
Under the hood, discord.js handles connection to Discord websocket gateway well. It responds to things like heartbeats and make sure Discord gateway does not boot the client from inactivity. The code I have demonstrated in lecture can only run for about 30 seconds at a time before being booted from Discord for inactivity.
However, if you are curious about the lecture, the session from Spring 18 is recorded live and can be viewable here.
I hope this help!

Websockets & NodeJS - Changing Browser Tabs & Sessions

I've started writing a node.js websocket solution using socket.io.
The browsers connects to the node server successfully and I get see the socket.id and all config associated with console.log(socket). I also pass a userid back with the initial connection and can see this on the server side to.
Question: I'm not sure the best way to associate a user with a connection. I can see the socket.id changes every page change and when a tab is opened up. How can I track a user and send 'a message' to all required sockets. (Could be one page or could be 3 tabs etc).
I tried to have a look at 'express-socket.io-session' but I'm unsure how to code for it and this situation.
Question: I have 'io' and 'app' variables below. Is it possible to use the 2 together? app.use(io);
Essentially I want to be able to track users (I guess by session - but unsure of how to handle different socket id's for tabs etc) and know how to reply to user or one or more sockets.
thankyou
The best way to handle the situation is rely on SocketIO's rooms. Name the room after the user's unique ID. This will support multiple connections out of the box. Then, whenever you need to communicate with a particular user, simply call the message function and pass in their id, the event, and any relevant data. You don't need to worry about explicitly leaving a room, SocketIO does that for you whenever their session times out or they close their browser tab. (We do explicitly leave a room whenever they log out though obviously)
On the server:
var express = require('express');
var socketio = require('socket.io');
var app = express();
var server = http.createServer(app);
var io = socketio(server);
io.on('connect', function (socket) {
socket.on('userConnected', socket.join); // Client sends userId
socket.on('userDisconnected', socket.leave); // Cliend sends userId
});
// Export this function to be used throughout the server
function message (userId, event, data) {
io.sockets.to(userId).emit(event, data);
}
On the client:
var socket = io('http://localhost:9000'); // Server endpoint
socket.on('connect', connectUser);
socket.on('message', function (data) {
console.log(data);
});
// Call whenever a user logs in or is already authenticated
function connectUser () {
var userId = ... // Retrieve userId somehow
if (!userId) return;
socket.emit('userConnected', userId);
}
// Call whenever a user disconnects
function disconnectUser () {
var userId = ... // Retrieve userId somehow
if (!userId) return;
socket.emit('userDisconnected', userId);
}

sails.io.js - nodejs - Resourceful PubSub not receiving model events

I am trying to subscribe a nodejs application to model events in sails. Here is my code:
var socketIOClient = require('socket.io-client'),
sailsIOClient = require('sails.io.js');
var io = sailsIOClient(socketIOClient);
io.sails.url = 'http://localhost:1337';
io.socket.on("agent", function(event) {
console.log(event);
})
io.socket.get("/agent", function(resData, jwres) {})
Here is a link to all of the output on the sails server when the client(nodejs) connects:
https://gist.github.com/CiscoKidxx/e5af93ebcc24702ba4f8
My understanding is that when I create a new agent it should trigger a console.log(event) which lists the changes. This is not happening. I do get a "now connected to sails" upon script start up. Any thoughts?
Here is my call to create a new agent in my UserController:
Agent.create({
syncToken: token,
owner: user.id
}).exec(function (err, newAgent) {
Agent.publishUpdate(newAgent.id, {syncToken: newAgent.syncToken});
The server side code snippet above doesn't show a call to Agent.publishCreate in the callback, but rather a publishUpdate.
From what I understand, the publishCreate is only automatically triggered when using the blueprints - but not for programatic calls like your Agent.create above.
So changing it from publishUpdate to publishCreate might fix it in your context.

Resources