How to receive Discord.js interactions though POST requests at my endpoint - node.js

I am creating a Discord Bot using Discord.js and want to change it to receive interactions through POST requests instead of websockets, as the new option for Discord Apps:
You can optionally configure an interactions endpoint to receive interactions via HTTP POSTs rather than over Gateway with a bot user.
Slash commands and interactions works as expected with websocks by using:
client.ws.on('INTERACTION_CREATE', async (interaction) => {
// receive and answer the interaction
})
The problem is, I can't find on the documentation how to explicitly receive interactions through http POST neither options to set the listening PORT.

Related

Better strategy for bot posting messages to multiple channels with DiscordJs

I am trying to execute bot functions from a node express server and it seems the best option is the DiscordJs package (correct me if I'm wrong for this use-case). For example, a user takes some action on my web application that would grant them a role to access different channels. The DiscordJs docs all seem to focus on actions like this being prompted from the discord server through bot commands or detecting changes with members.
I would like to execute bot functions from my express server by instantiating one client, logging that client in, and executing functions from the server. Something to the effect of
const client = new Discord.Client({intents: [Discord.Intents.FLAGS.GUILDS, "GUILD_MESSAGES", "GUILD_MEMBERS"]});
client.on("<some event on express server>", (event) =>{
//event actions
});
client.login(token)
Is DiscordJs the right tool for this use case? Should I be using something other than Discord.Client to do this? Any suggestions/input would be appreciated.
DiscordJs is a great package, I have a fair amount of experience using it.
For your use case I think it would work great.
client.on(event, function) will only take Discord events as event arguments. These are listed here:
https://discord.js.org/#/docs/discord.js/stable/class/Client
You could however use events from your web server using something similar to below
const client = new Discord.Client({intents: [Discord.Intents.FLAGS.GUILDS, "GUILD_MESSAGES", "GUILD_MEMBERS"]});
yourWebServer.on("yourEvent", (event) => {
client.doSomething()
}
client.login(token)
The main problem to tackle if you wish to use the discord client in this way is identifying the Guild/Message/Role/Whatever you want to change.
Normally, discord bots react to messages so they have access to a lot of data very quickly. In the below example, the bot can get a great deal of information from the message data alone, like the author, the guild it was posted in, the roles in that guild etc. You can see a list of properties here: https://discord.js.org/#/docs/discord.js/stable/class/Message
const client = new Discord.Client({intents: [Discord.Intents.FLAGS.GUILDS, "GUILD_MESSAGES", "GUILD_MEMBERS"]});
client.on("messageCreate", (message) => {
client.doSomething()
});
client.login(token)
If you plan to use this discord bot on just 1 server messing around with your friends or whatever (i do this a lot), you can find your server's Guild ID and hardcode it somewhere into your bot. You can then fetch all roles/messages/users/whatever as you wish.
For any wider usage you'd have to get the context from somewhere else, e.g. inputting ids on a form on your web server.
Have a good read of the discord.js documentation, its very well made in my opinion. Get an idea of what information you want to access, and how you can access it. It will then be easier to determine what context you need to give the bot to find this information.
For those wondering how to use discordjs client commands outside of an event listener it is possible but requires diligent use of async/await. Check this thread for more insight https://github.com/discordjs/discord.js/issues/3100

Connecting Heroku Webhooks with Discord

I am trying to have updates to my heroku app sent to a Discord channel via webhook. However, the delivery attempts fail. I've double checked the Payload URL and it is correct. Not sure how to proceed from here.
Heroku's webhook format is not compatible with Discord so you can't just put a Discord webhook URL into Heroku. You need a middle-man server to receive events from Heroku, and construct and send corresponding messages to Discord.
Found this JS code, should work (change params variable and where it says webhook to your webhook url)
let x = new XMLHttpRequest();
x.open("POST", `<webhook link>`);
x.setRequestHeader('Content-type', 'application/json');
let params = {
username: "Webhook Bot",
content: "<message content as a string>"
}
x.send(JSON.stringify(params));
i should mention that to mention a channel instead of #channel-name you'll have to use <#channelid>, for example <#1234567890> instead of #foo-bar
(this is my first post, sorry if it's a bit bad)
Without being able to see your code and the request structure you are using it will be hard to determine where the issue is coming from exactly, but one thing you might what to check is how you are sending the JSON payload to the Discord webhook URL.
Discord does not seem to accept the request unless you specify that the body of the payload is JSON. I discovered this because of an application I am working on currently. I know this answer is coming significantly after the fact, but it might help someone else down the line!

Using Socket.io with Sequelize

I am trying to use Socket.io and Sequelize to create a chat app. Socket.io will handle the socket to allow for instant messaging. Sequelize will handle storing the messages so when you refresh the screen you still have your messages.
What is happening is that on localhost my socket works, but it does not send the messages to the database. When I put it onto Heroku, my database worked, but it does not use the sockets.
My socket is located in app.js and my database route is located in routes/messages.js.
I have been working on this bug for a while now and I have been trying to get help with it. I think the best way to share this is with my markdown I created detailing my efforts to fix my bug that can be found at here. My repo for this can be found here.
There are a few different parts that you need to distinguish:
the HTTP server, in your code represented by the variable http
the Express app, represented by app
the Socket.IO server, represented by io
a Socket.IO (client) connection (see below)
The HTTP server directs "normal" HTTP requests to the Express app, which will handle them according to the middleware and routes that are set up. A router handler gets called with (at least) two arguments, generally called req and res, to represent the (incoming) HTTP request and the (outgoing) HTTP response.
The Socket.IO server gets to handle specific Socket.IO requests, which get sent to the server by the Socket.IO client (running in the browser). When such a client sets up a connection with the server, the connection event gets triggered on the server. Any handlers for this event will get passed an argument, generally called socket, that represents the (bidirectional) connection with that client.
That Socket.IO connection can receive messages (sent from the client running in the browser), which trigger events on the socket. You can install a handler to listen for particular messages (like "chat message"), which will receive, as argument, the data that was sent to it by the client.
The issue in your code seems to be with setting up everything to handle those chat messages. The correct setup order would be:
listen on the Socket.IO server for connection events
when such an event is received, add a listener for the chat message event on the connection
when such an event is received, write the data to the database.
In code:
// Listen for new client connections.
io.on('connection', function(socket) {
// Listen for the client to send a _"chat message"_ message.
socket.on('chat message', function(data) {
// Store the data in the database.
models.Messages.create({
message : data.message,
username : data.username
});
});
});
As you can see, req and res aren't available inside of those Socket.IO event handlers, because those are only used for normal HTTP requests.
Also, as opposed to HTTP, you don't necessarily have to send anything back to the client when you have received a message, so I left that part out. The handler above only writes the message data to the database (it also doesn't check for, or handle, errors, which eventually you should add).

Node.JS and Asynchronous Messaging

Ok, this is not what you think it is, I am not asking for help with the async/wait pattern or asynchronous programming I am well versed with those. I am however querying whether something is possible within a Node.JS Express service.
The Scenario
I have a web service which is developed in Node.JS and uses Express.JS to expose some REST endpoints that a client can connect to and send a POST request. For the most part these are Synchronous and will create a SOAP message and send that on to an external service and receive an immediate response which can then be returned to the client, all really simple stuff which is already implemented. So what's your point I hear you say, I am coming to that.
I have a couple of POST interactions that will build a SOAP message to send to an Asynchronous external endpoint where the response will be received asynchronously through an inbound endpoint.
Option 1: What I am looking for in these cases is to be able to build the SOAP message, create a listener (so I can listen for the response to my request), and then send the request to the external service which immediately returns a 200.
Option 2: When I setup the service I want to also setup and listen for incoming requests from the external service whilst also listening for REST requests from the internal service.
The Question
Is either option possible in Node and Express? and, if so how would one achieve this?
NOTE: I know its possible in C# using WCF or a Listener but I would like to avoid this and use Node.JS so any help would be greatly appreciated.
First of all check node-soap if it fits your needs.
Option 1: What I am looking for in these cases is to be able to build the SOAP message, create a listener (so I can listen for the response to my request), and then send the request to the external service which immediately returns a 200.
Here's a very basic non-soap service implementation.
let request = require('request-promise');
let express = require('express');
let app = express();
//Validate the parameters for the request
function validateRequest(req) { ... }
//Transform the request to match the internal API endpoint
function transformRequest(req) { ... }
app.post('/external', function(req, res) {
if(!validateRequest(req))
return res.status(400).json({success: false, error: 'Bad request format');
res.status(200).send();
let callbackUrl = req.query.callback;
let transformedRequest = transformRequest(req);
let internalServiceUrl = 'https://internal.service.com/internal'
request.post(internalServiceUrl, {body: transformedRequest}).then(function (internalResponse){
//Return some of the internal response?
return request.get(callbackUrl, {success: true, processed: true});
}).catch(function (e) {
request.get(callbackUrl, {success: false, error: e});
});
});
Option 2: When I setup the service I want to also setup and listen for incoming requests from the external service whilst also listening for REST requests from the internal service.
There is no "listening" in http. Check socket.io if you need realtime listening. It uses websockets.
Your other option is to poll the internal service (say if you want to check for its availability).

How to send a message to all subscribed users with kik bot

I'm just a beginner trying to learn how to write a bot for kik.
I'm trying to write it with the node js framework that kik has provided.
I want to send a message to all subscribed users of the bot; I found this in their docs:
bot.send(Bot.Message.text('Hey, nice to meet you!'), 'a.username');
but I'm confused as to how they get the username of the subscribed user. I tried using bot.getUserProfile.username, but it seems to be undefined.
Thanks for any help! Also, any tips on how this bot works would be appreciated! I have no web development experience; why does this bot have to be on a server?
First of all, if you want to send a blast to all of your users, I'd recommend using the broadcast API, which allows you to send messages by batches of 100 (instead of 25 for the regular send() API).
You can use the broadcast API like this:
bot.broadcast(Bot.Message.text('some message'), ['username1', 'username2']);
Documentation for this method can be found here.
As for sending messages to all of your users, you will need to have a list of usernames somewhere (in a database, for example). At the moment, Kik does not provide a way to get your list of subscribers.
Something like this would work:
bot.use((msg, next) => {
let username = msg.from; // Find the username from the incoming message
registerInDatabase(username); // Save it somewhere
next(); // Keep processing the message
});
You will need to make sure that this is placed before you declare any other handler (such as bot.onTextMessage(), for instance).

Resources