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

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!

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.

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

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.

Discord bot stopped sending welcome messages

So, my code for making the bot greet new users stopped working, and i have no idea why or how
this is the code that im using for the welcome event itself ```module.exports = (client) => {
const channelId = '757493821251649608' // welcome channel
const targetChannelId = '757521186929246219' // rules and info
client.on('guildMemberAdd', (member) => {
const message = `Hi, hope you enjoy your stay <#${
member.id
}> , Oh i almost forgot to tell you, check out! ${member.guild.channels.cache
.get(targetChannelId)
.toString()}`
const channel = member.guild.channels.cache.get(channelId)
channel.send(message)
})
}```
And this is how i make the bot execute it
const hi = require('./events/hi')
const hello = require('./events/hello')
const yo = require('./events/yo')
const whatsup = require('./events/whatsUp')
const bye = require('./events/bye')
client.once('ready', () =>{
console.log('Aiko is working!');
client.user.setActivity(' your orders!|Prefix is +', { type: "LISTENING" });
hi(client)
hello(client)
yo(client)
whatsup(client)
bye(client)
welcome(client)
});```
The event that should also send a message when someone leaves the server also doesn't go off, anyone any idea why?
This is most likely a privileged intents problem, which recently became required. Check out this question to see if it solves it. Also read the discord API docs for privileged intents

how do i send a message to a specific user in ws library?

I'm exploring different websocket library for self-learning and I found that this library is really amazing ws-node. I'm building a basic 1 on 1 chat in ws-node library
My question is what is the equivalent of socket.io function which is socket.to().emit() in ws? because i want to send a message to a specific user.
Frontend - socket.io
socket.emit("message", { message: "my name is dragon", userID: "123"});
Serverside - socket.io
// listening on Message sent by users
socket.on("message", (data) => {
// Send to a specific user for 1 on 1 chat
socket.to(data.userID).emit(data.message);
});
WS - backend
const express = require('express');
const http = require('http');
const WebSocket = require('ws');
const express = require('express');
const http = require('http');
const WebSocket = require('ws');
const app = express();
const server = http.createServer(app);
const wss = new WebSocket.Server({ server });
wss.on('connection', (ws) => {
ws.on('message', (data) => {
\\ I can't give it a extra parameter so that I can listen on the client side, and how do I send to a specific user?
ws.send(`Hello, you sent -> ${data.message}`);
});
});
Honestly, the best approach is to abstract away the WebSocket using a pub/sub service.
The issue with client<=(server)=>client communication using WebSockets is that client connections are specific to the process (and machine) that "owns" the connection.
The moment your application expands beyond a single process (i.e., due to horizontal scaling requirements), the WebSocket "collection" becomes irrelevant at best. The array / dictionary in which you stored all your WebSocket connections now only stores some of the connections.
To correct approach would be to use a pub/sub approach, perhaps using something similar to Redis.
This allows every User to "subscribe" to a private "channel" (or "subject"). Users can subscribe to more than one "channel" (for example, a global notification channel).
To send a private message, another user "publishes" to that private "channel" - and that's it.
The pub/sub service routes the messages from the "channels" to the correct subscribers - even if they don't share the same process or the same machine.
This allows a client connected to your server in Germany to send a private message to a client connected to your server in Oregon (USA) without anyone being worried about the identity of the server / process that "owns" the connection.
There isn't an equivalent method. socket.io comes with a lot of helpers and functionalities, that will make your life easier, such as rooms, events...
socket.io is a realtime application framework, while ws is just a WebSocket client.
You will need to make your custom wrapper:
const sockets = {};
function to(user, data) {
if(sockets[user] && sockets[user].readyState === WebSocket.OPEN)
sockets[user].send(data);
}
wss.on('connection', (ws) => {
const userId = getUserIdSomehow(ws);
sockets[userId] = ws;
ws.on('message', function incoming(message) {
// Or get user in here
});
ws.on('close', function incoming(message) {
delete sockets[userId];
});
});
And then use it like this:
to('userId', 'some data');
In my opinion, if you seek that functionality, you should use socket.io. Which it's easy to integrate, has a lot of support, and have client libraries for multiple languages.
If your front-end uses socket.io you must use it on the server too.

Skype Bot responding with empty body

I'm trying to get a Skype bot up and running based off of the echo example but I'm struggling to make a successful POST to my app. When I send a post to /v1/chat I get back a status of 201 (successful creation), and nothing in the body. My console.log does not print anything either, which leads me to believe that the botService.on('personalMessage', ...) function is not being run. Does anyone have any insight into how these POST requests should be formatted? I cannot seem to find anything in the documentation.
My code:
const fs = require('fs');
const restify = require('restify');
const skype = require('skype-sdk');
const botService = new skype.BotService({
messaging: {
botId: '28:<bot’s id="ID176db9ab-e313-4d76-a60c-bc2a280e9825">',
serverUrl : "https://apis.skype.com",
requestTimeout : 15000,
appId: process.env.APP_ID,
appSecret: process.env.APP_SECRET
}
});
botService.on('contactAdded', (bot, data) => {
console.log('contact added');
bot.reply('Hello ${data.fromDisplayName}!', true);
});
botService.on('personalMessage', (bot, data) => {
console.log('message incoming');
console.log(data);
bot.reply('Hey ${data.from}. Thank you for your message: "${data.content}".', true);
});
const server = restify.createServer();
server.post('/v1/chat', skype.messagingHandler(botService));
const port = process.env.PORT || 8080;
server.listen(port);
console.log('Listening for incoming requests on port ' + port);
Final Edit & Solution: I think the problem caused by Heroku somehow(it could be something with their free tier ,1 dyno). After some effort, I uploaded the program to Azure, and it is now working perfectly.
Potential Solution: You need to change the server address in the server.post command. If you run your program in "https:\www.yourwebsite.com/v1/chat" , you need to modify this;
server.post('/v1/chat', skype.messagingHandler(botService));
to this;
server.post('https:\\www.yourwebsite.com/v1/chat', skype.messagingHandler(botService));
Of course, don't forget to specify your app id, bot id, and app secret. If you don't have one, you need to generate a password in your Skype application page.
I have the exact problem with the OP. I followed the tutorial, and it doesn't specify how to modify our code to comply with our server. So, after running the program it only returns this;
{"code":"ResourceNotFound","message":"/ does not exist"}
In the Echo example in the Skype Bot Webpage; it says;
"We'll assume the bot's URL for messaging was set to https://echobot.azurewebsites.net/v1/chat during registration."
Make sure that Procfile and worker processes are setup.
My bot is working fine on heroku itself

Resources