Files
drb-server/discordBot/modules/wrappers.mjs
Logan Cusano 117cbea67f
All checks were successful
release-tag / release-image (push) Successful in 1m52s
Lint JavaScript/Node.js / lint-js (push) Successful in 11s
DRB Tests / drb_mocha_tests (push) Successful in 29s
Linting
2024-08-11 15:57:46 -04:00

240 lines
7.5 KiB
JavaScript

import { DebugBuilder } from "../../modules/debugger.mjs";
const log = new DebugBuilder("server", "discordBot.modules.wrappers");
import {
checkIfNodeIsConnectedToVC,
getNodeDiscordID,
getNodeDiscordUsername,
checkIfNodeHasOpenDiscordClient,
getNodeCurrentListeningSystem,
requestNodeJoinSystem,
} from "../../modules/socketServerWrappers.mjs";
import { getAllDiscordIDs } from "../../modules/mongo-wrappers/mongoDiscordIDWrappers.mjs";
import { ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js";
export const checkOnlineBotsInGuild = async (nodeIo, guildId) => {
let onlineBots = [];
const openSockets = [...(await nodeIo.allSockets())];
await Promise.all(
openSockets.map(async (openSocket) => {
openSocket = await nodeIo.sockets.sockets.get(openSocket);
const connected = await checkIfNodeIsConnectedToVC(
nodeIo,
guildId,
openSocket.node.nuid,
);
log.INFO("Connected:", connected);
if (connected) {
const username = await getNodeDiscordUsername(openSocket, guildId);
const discordID = await getNodeDiscordID(openSocket);
onlineBots.push({
name: username,
discord_id: discordID,
nuid: openSocket.node.nuid,
});
}
}),
);
return onlineBots;
};
export const getAvailableTokensInGuild = async (nodeIo, guildId) => {
try {
// Execute both asynchronous functions concurrently
const [discordIDs, onlineBots] = await Promise.all([
getAllDiscordIDs(), // Fetch all Discord IDs
checkOnlineBotsInGuild(nodeIo, guildId), // Check online bots in the guild
]);
// Use the results of both promises here
log.INFO("Available Discord IDs:", discordIDs);
log.INFO("Online bots in the guild:", onlineBots);
// Filter any discordIDs that are not active
const availableDiscordIDs = discordIDs
.filter((discordID) => discordID.active == true)
.filter(
(discordID) =>
!onlineBots.some(
(bot) => Number(bot.discord_id) == discordID.discord_id,
),
);
// Return the unavailable discordIDs
return availableDiscordIDs;
} catch (error) {
console.error("Error getting available tokens in guild:", error);
throw error;
}
};
/**
* Get the nodes with given system that are available to be used within a given server
* @param {any} nodeIo The nodeIO object contained in the discord server object
* @param {any} guildId The guild ID to search in
* @param {any} system The system to filter the nodes by
* @returns {any}
*/
export const getAvailableNodes = async (nodeIo, guildId, system) => {
// Get all open socket nodes
const openSockets = [...(await nodeIo.allSockets())]; // TODO - Filter the returned nodes to only nodes that have the radio capability
log.DEBUG("All open sockets: ", openSockets);
var availableNodes = [];
// Check each open socket to see if the node has the requested system
await Promise.all(
openSockets.map(async (openSocket) => {
openSocket = await nodeIo.sockets.sockets.get(openSocket);
// Check if the node has an existing open client (meaning the radio is already being listened to)
const hasOpenClient = await checkIfNodeHasOpenDiscordClient(openSocket);
if (hasOpenClient) {
let currentSystem = await getNodeCurrentListeningSystem(openSocket);
if (currentSystem != system.name) {
log.INFO(
"Node is listening to a different system than requested",
openSocket.node.name,
);
return;
}
}
// Check if the bot has an open voice connection in the requested server already
const connected = await checkIfNodeIsConnectedToVC(
nodeIo,
guildId,
openSocket.node.nuid,
);
log.INFO("Connected:", connected);
if (!connected) {
// Check if this node has the requested system, if so add it to the availble array
if (system.nodes.includes(openSocket.node.nuid)) {
availableNodes.push(openSocket);
}
}
}),
);
log.DEBUG(
"Availble nodes:",
availableNodes.map((socket) => socket.node.name),
);
return availableNodes;
};
/**
* Gets the voice channel the user is currently in.
* @param {any} interaction - The interaction object.
* @returns {any} - The voice channel object, or null if the user is not in a voice channel.
*/
export const getUserVoiceChannel = (interaction) => {
if (!interaction.member.voice.channel) {
interaction.editReply({
content: `<@${interaction.member.id}>, you need to enter a voice channel before using this command`,
ephemeral: true,
});
return null;
}
return interaction.member.voice.channel;
};
/**
* Joins a node to a specified system and voice channel.
* @param {any} nodeIo - The nodeIO server for manipulation of sockets.
* @param {any} interaction - The interaction object.
* @param {string} nodeId - The ID of the node to join.
* @param {any} system - The system object to join.
* @param {any} channel - The voice channel to join.
*/
export const joinNode = async (
nodeIo,
interaction,
nodeId,
system,
channel,
) => {
try {
const openSocket = await nodeIo.sockets.sockets.get(nodeId);
const discordTokens = await getAvailableTokensInGuild(
nodeIo,
interaction.guild.id,
);
if (discordTokens.length === 0) {
await interaction.editReply({
content: `<@${interaction.member.id}>, there are no free bots available.`,
ephemeral: true,
});
return;
}
log.INFO(
"Joining node:",
nodeId,
system.name,
channel.id,
openSocket.node.name,
discordTokens[0].token,
);
await requestNodeJoinSystem(
openSocket,
system.name,
channel.id,
discordTokens[0].token,
);
await interaction.editReply({
content: `<@${interaction.member.id}>, a bot will join your channel listening to '${system.name}' shortly.`,
ephemeral: true,
});
} catch (err) {
log.ERROR("Failed to join node:", err);
await interaction.editReply({
content: `<@${interaction.member.id}>, an error occurred while joining the node: ${err.message}`,
ephemeral: true,
});
}
};
/**
* Prompts the user to select a node from available nodes.
* @param {any} interaction - The interaction object.
* @param {Array} availableNodes - The list of available nodes.
* @param {Function} onNodeSelected - Callback function to handle the selected node.
*/
export const promptNodeSelection = async (
interaction,
availableNodes,
onNodeSelected,
) => {
const nodeSelectionButtons = availableNodes.map((node) =>
new ButtonBuilder()
.setCustomId(node.id)
.setLabel(node.node.name)
.setStyle(ButtonStyle.Primary),
);
const actionRow = new ActionRowBuilder().addComponents(nodeSelectionButtons);
const response = await interaction.editReply({
content: `<@${interaction.member.id}>, please select the Node you would like to join with this system:`,
components: [actionRow],
ephemeral: true,
});
const collectorFilter = (i) => i.user.id === interaction.user.id;
try {
const selectedNode = await response.awaitMessageComponent({
filter: collectorFilter,
time: 60_000,
});
await onNodeSelected(selectedNode.customId);
} catch (e) {
log.ERROR("Node selection timeout:", e);
await interaction.editReply({
content: "Confirmation not received within 1 minute, cancelling.",
components: [],
});
}
};