Getting API latency inside of a commandhandler - javascript

Making a ping command for my bot,
want to show the api latency with Math.round(client.ws.ping), when I use it inside of my index.js, it works fine. When I use it inside of my ping command in my command handler, it won't work and returns to NaN.
Do I need to require something to use it?
Here is my code inside of ping.js
const Discord = require('discord.js');
const client = new Discord.Client();
const fs = require('fs');
module.exports = {
name: 'ping',
description: 'measures ping',
execute(message, args){
async function pingFunction(){
const embedPingtest = new Discord.MessageEmbed()
.setTitle('Pinging...')
.setColor(0xC1CCDE)
const msg = await message.channel.send(embedPingtest);
const embedPing = new Discord.MessageEmbed()
.setTitle('Pong!')
.setDescription("Bot Latency: ``" + Math.floor(msg.createdTimestamp - message.createdTimestamp) + " ms``\nAPI Latency: ``" + Math.round(client.ws.ping) + " ms``")
.setColor(0xC1CCDE)
console.log(apiLatency)
msg.edit(embedPing)
}
pingFunction()
}
}

This is because you create a new client instance. This one doesn't has a ping as it is not logged in so not online. I suggest you pass your old instance as function parameter, to make your code look something like:
const Discord = require('discord.js');
module.exports = {
name: 'ping',
description: 'measures ping',
execute(message, args, client) {
(async () => {
const embedPingtest = new Discord.MessageEmbed()
.setTitle('Pinging...')
.setColor(0xC1CCDE)
const msg = await message.channel.send(embedPingtest);
const embedPing = new Discord.MessageEmbed()
.setTitle('Pong!')
.setDescription("Bot Latency: ``" + Math.floor(msg.createdTimestamp - message.createdTimestamp) + " ms``\nAPI Latency: ``" + Math.round(client.ws.ping) + " ms``")
.setColor(0xC1CCDE)
console.log(apiLatency)
msg.edit(embedPing)
})();
}
}
I know most guides only make you using the structure of run(message, args) but in my bot I usually use message, args, client? (mine works different tho as I modified my module structure). This also won't throw an error in your code, as JS doesn't care how many arguments you pass or don't pass.

Instead of creating a new Discord.Client(), you could refer to Zer0's answer, or an even easier way would to just use the message object.
message has a client property, which will return the client that instantiated the message.
Instead of:
Math.round(client.ws.ping)
Use:
Math.round(message.client.ws.ping)

Related

How to .deferReply to specified channel?

How can I have it so that the bot sends a message to a specific channel, while using .deferReply and .editReply? Currently, I'm getting an error saying that suggestionChannel.deferReply is not a function. Here's my code:
const { SlashCommandBuilder } = require("#discordjs/builders");
const { MessageEmbed } = require("discord.js");
module.exports = {
data: new SlashCommandBuilder()
.setName("suggest")
.setDescription("Send your suggestion to the specified channel")
.addStringOption((option) =>
option
.setName("suggestion")
.setDescription("Your suggestion")
.setRequired(true)
),
async execute(interaction, client) {
var suggestionChannelID = "900982140504793109";
var suggestionChannel = client.channels.cache.get(suggestionChannelID);
const embed = new MessageEmbed()
.setColor("#0099ff")
.setTitle(`New suggestion by ${interaction.member.displayName}`)
.setDescription(`${interaction.options.getString("suggestion")}`);
await suggestionChannel.deferReply();
await suggestionChannel
.editReply({
embeds: [embed],
})
.then(function (interaction) {
interaction.react(`👍`).then(interaction.react(`👎`));
});
},
};
How can I have it so that the bot sends a message to a specific
channel, while using .deferReply and .editReply?
Well, the short answer is; you can't. But you can do this:
As the error already says, deferReply() is not a method of the TextBasedChannels class, defined by your suggestionChannel.
Instead, try sending a message to the channel instead of replying. Replies can only be executed in the interaction's channel:
var suggestionChannelID = "900982140504793109";
var suggestionChannel = client.channels.cache.get(suggestionChannelID);
const embed = new MessageEmbed()
.setColor("#0099ff")
.setTitle(`New suggestion by ${interaction.member.displayName}`)
.setDescription(`${interaction.options.getString("suggestion")}`);
// use this instead
await suggestionChannel.send({
embeds: [embed],
});
P.S side note, deferReply() starts a 15-minute timer before the interaction expires and triggers that 'x is thinking...' text to appear when the client is calculating stuff, so try to call it as soon as possible. By default, interactions expire after 3 seconds, so if your bot fails to finish whatever it needs to accomplish within that timeframe, that interaction will fail.

Importing variables from other files

I am trying to import a variable from one of my files (File 1) and use it in File 2. I have imported File 2 into File 1 but I am receiving error. My channel ID is correct, in this case you would have to choose the channel so the channel ID is not the issue here.
TypeError: setr.send is not a function
File 1
const Discord = require("discord.js");
const axios = require("axios");
let config = require("../config.json");
module.exports = {
name: "setrestart",
description: "sets the restart channel",
async execute(message, args) {
const perm = new Discord.MessageEmbed()
.setDescription(":x: You do not have permission to use this command.")
.setColor("#E74C3C");
if (!message.guild.me.hasPermission("ADMINISTRATOR"))
return message.channel.send(perm);
if (message.author.id !== "ID")
return message.channel.send(perm);
const channelx =
message.mentions.channels.first() ||
message.guild.channels.cache.find((c) => c.id === args[0]);
if (!channelx)
return message.channel.send(
`:x: Please specify the channel where server restarts will go!`
);
message.reply(`All server restart logs will now go to ${channelx}.`)
},
};
File 2
const Discord = require("discord.js");
const axios = require("axios");
let config = require("../config.json");
let setr = require("./setrestart"); // This is importing file 1
module.exports = {
name: "restart",
description: "send a restart message in status channel",
async execute(message, args) {
const perm = new Discord.MessageEmbed()
.setDescription(":x: You do not have permission to use this command.")
.setColor("#E74C3C");
if (!message.guild.me.hasPermission("ADMINISTRATOR"))
return message.channel.send(perm);
if (message.author.id !== "ID")
return message.channel.send(perm);
const restart = new Discord.MessageEmbed()
.setTitle(" Server Restarted! ")
.setDescription(`F8 connect to ${config.SERVER_URL} `)
.setColor("RANDOM")
.setTimestamp()
.setFooter(`${config.SERVER_LOGO}`);
setr.channelx.send(restart) // This does not work.
},
};
Help is much appreciated.
Edit: I left out the most crucial thing about what I am trying to import.
I am trying to import channelx which is in File 1 and I am trying to use the variable in File 2.
Output
User: /setrestart #channel
Bot: All server restart logs will now go to ${channelx}.
User: /restart
Bot: Embed sent in channelx
The variable channelx is accessible only in the function scope of execute(), you can't import it. Basically after the function goes out of scope the variable is lost. Use a global object, note that the object is destroyed when the program exits. So if you are trying to make some kind of bot's configuration, you want to save the object to a file.
Here is an example of how to properly implement what you are trying to do.
File 1 (file1.js):
// ... Load storage from a JSON file ...
const storage = {};
module.exports = {
name: "setrestart",
description: "sets the restart channel",
async execute(message, args) {
// ... Permission checking ...
const channelx = message.mentions.channels.first() ||
message.guild.channels.cache.find((c) => c.id === args[0]);
if (!channelx) {
return message.channel.send(
`:x: Please specify the channel where server restarts will go!`
);
}
// Store restart channel id per guild
storage[message.guild.id] = channelx.id;
message.reply(`All server restart logs will now go to ${channelx}.`);
// ... Write to the storage JSON file and update it with new data ...
},
};
module.exports.storage = storage;
File 2 (file2.js):
const Discord = require("discord.js");
const file1 = require("./file1.js");
module.exports = {
name: "restart",
description: "send a restart message in status channel",
async execute(message, args) {
// ... Permission checking ...
const restart = new Discord.MessageEmbed()
.setTitle(" Server Restarted! ")
.setColor("RANDOM")
.setTimestamp();
const channelId = file1.storage[message.guild.id];
// If there is no restart channel set, default to the system channel
if (!channelId) channelId = message.guild.systemChannelID;
const channel = await message.client.channels.fetch(channelId);
channel.send(restart);
},
};
Note that I have remove some parts of your code, to make it work on my machine.
Using discord.js ^12.5.3.
I am pretty sure you can't use the module.exports in that way. You should just add the channelx to the exports instead.
using this.channelx = channelx.
This is not how importing and exporting works. Your channelx variable is defined within the execution of a function, and you are not returning it.
I am not sure how the whole Discord API works and what are the shapes that get returned, but you should be able to do something like this:
File 1
module.exports = {
name: "setrestart",
description: "sets the restart channel",
async execute(message, args) {
// ... everything as per your file
message.reply(`All server restart logs will now go to ${channelx}.`);
return channelx;
},
};
File 2
module.exports = {
name: "restart",
description: "send a restart message in status channel",
async execute(message, args) {
// ... everything the same as per your file
const channelx = await setr.execute(message, args);
channelx.send(restart);
},
};
Basically, what is happening here is that the first module exposes a function that figures out your target channel and then returns it.
Once you return it, you can do whatever you want with that.
Please be aware that your first function might not need to be async as you don't have any await instruction.
Read more about scope: https://developer.mozilla.org/en-US/docs/Glossary/Scope

JS Discord buttons error : 'Cannot send empty message'

Hi I'm making a Javascript based Discord bot, and I really wanted to implement the new Discord Buttons feature, the problem is, even using the documentation examples, I get the same error, again and again :
(node:6184) UnhandledPromiseRejectionWarning: DiscordAPIError: Cannot send an empty message
Here is the code (I am using module.exports with separated files for each commands) :
const { MessageButton } = require('discord-buttons')
module.exports = {
name: 'invite',
descritipion: 'test command',
async execute(client, message, args) {
let button = new MessageButton()
.setStyle('url')
.setURL('https://npmjs.com/discord-buttons')
.setLabel('Click me !')
await message.channel.send('Hey, I am powered by npm discord-buttons : https://npmjs.com/discord-buttons');
await message.channel.send(button);
}
}
You cannot just send a button on its own. Instead, try adding the button to the previous message so they both get sent in one message as shown below
The official documentation for this is here
// Replace these
const { MessageButton } = require('discord-buttons')
await message.channel.send('Hey, I am powered by npm discord-buttons : https://npmjs.com/discord-buttons');
await message.channel.send(button);
// With these
const { MessageButton, MessageActionRow } = require('discord-buttons')
await message.channel.send('Hey, I am powered by npm discord-buttons : https://npmjs.com/discord-buttons', {
component: new MessageActionRow().addComponent(button)
});
Also, did you forget to initialize DiscordButtons? Do it when you initialize your discord bot
// Where you initialized your discord bot
const bot = new Discord.Client()
// Add this line
require("discord-button")(bot)

Make a dog command in Discord.JS

I'm trying to figure out how to make a command that makes a GET request to this dog API and return the image in an embed. Here's the code I've tried:
const Discord = require('discord.js');
const fetch = require('node-fetch');
module.exports = {
name: 'afv!dog',
description: 'Grab a cute doggo from dog.ceo',
execute(msg, args, bot) {
const prevmsg = msg
const fetchEmbed = new Discord.MessageEmbed()
.setColor('#e3dcd3')
.setTitle(':dog: Woof! Let me find you a doggo! <a:AFVloading:748218375909539923>')
.setDescription("This shouldn't take long...")
msg.reply(fetchEmbed).then(msg => {
const { message } = await fetch('https://dog.ceo/api/breeds/image/random').then(response => response.text());
console.log(message)
const doneEmbed = new Discord.MessageEmbed()
.setColor('#e3dcd3')
.setTitle(':dog: Woof! Found one!')
.setImage(message)
msg.delete();
prevmsg.channel.send(doneEmbed);
})
},
};
This happens when I try to run index.js:
const { message } = await fetch('https://dog.ceo/api/breeds/image/random').then(response => response.json());
^^^^^
SyntaxError: await is only valid in async function
You need to use response.json() instead of response.text(). .text() is for standard html plain text, however the dog API you are using returns an object.
You're not awaiting prevmsg.channel.send(doneEmbed);, if I see it correctly
Edit: I am wrong

discord.js client.user.setPresence() breaks bot

My bot currently runs fine. I decided to add a 'playing ' status to it. This is the relevant code:
// Import the discord.js modules required
const Discord = require('discord.js');
// Create an instance of a Discord client
const client = new Discord.Client();
// Load config properties from 'config.json'
const config = require("./config.json");
const contest = config.contest;
// Set bots status to playing 'contest' defined in 'config.json'
client.user.setPresence({
game:{
name:contest
},
status:'online'
});
In 'config.json':
{
"contest": "Example Game"
}
When I add this, the bot no longer works, and appears offline. Any ideas?
EDIT:
Source of the information:
https://discord.js.org/#/docs/main/stable/class/ClientUser?scrollTo=setPresence
In the example section:
// Set the client user's presence
client.user.setPresence({ game: { name: 'with discord.js' }, status: 'idle' })
.then(console.log)
.catch(console.error);
You need to read the config, instead of
const config = require(...)
You need
const fs = require("fs");
const config = JSON.parse(fs.readFileSync("config.json"));
const contest = config.contest;
Then
game:{
name:contest
}
Figured it out - this needs to be placed inside an event, otherwise it's just floating code. For example, I placed this inside a
client.on('ready) event.

Categories

Resources