From ed33654b8c565e4eb52d78c7f6f7affdd21439dc Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Sun, 11 Feb 2024 04:32:58 -0500 Subject: [PATCH] Updates to join (server/client) - Check if the available nodes are connected to a vc in the given guild --- client/discordAudioBot/dab.mjs | 7 +++ client/modules/socketClient.mjs | 19 +++++++- server/discordBot/commands/join.mjs | 35 +++++++------ server/modules/socketServerWrappers.mjs | 65 +++++++++++++++++++++++-- 4 files changed, 103 insertions(+), 23 deletions(-) diff --git a/client/discordAudioBot/dab.mjs b/client/discordAudioBot/dab.mjs index 1190a08..e916b02 100644 --- a/client/discordAudioBot/dab.mjs +++ b/client/discordAudioBot/dab.mjs @@ -7,6 +7,7 @@ import { AudioPlayerStatus, VoiceConnectionStatus, joinVoiceChannel, + getVoiceConnection, } from '@discordjs/voice'; import { GatewayIntentBits } from 'discord-api-types/v10'; @@ -90,6 +91,12 @@ export async function getVoiceChannelFromID(client, channelID) { return client.channels.cache.get(channelID) } +export async function checkIfConnectedToVC(guildId) { + const connection = getVoiceConnection(guildId) + console.log("Connection!", connection); + return connection +} + export async function initDiscordBotClient(token, readyCallback){ const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.GuildVoiceStates, GatewayIntentBits.MessageContent], diff --git a/client/modules/socketClient.mjs b/client/modules/socketClient.mjs index 05b06cc..7319f5c 100644 --- a/client/modules/socketClient.mjs +++ b/client/modules/socketClient.mjs @@ -1,5 +1,5 @@ import { io } from "socket.io-client"; -import { connectToChannel, initDiscordBotClient, getVoiceChannelFromID } from '../discordAudioBot/dab.mjs'; +import { connectToChannel, initDiscordBotClient, getVoiceChannelFromID, checkIfConnectedToVC } from '../discordAudioBot/dab.mjs'; import { logIntoServerWrapper, sendNodeUpdateWrapper } from "./socketClientWrappers.mjs"; export const initSocketConnection = async (localNodeConfig) => { @@ -25,8 +25,23 @@ export const initSocketConnection = async (localNodeConfig) => { }); }); - socket.on('node-leave', () => { + socket.on('node-leave', async () => { console.log("Leave requested"); + const connection = await getVoiceConnection(myVoiceChannel.guild.id); + if (connection) { + console.log("There is an open VC connection, closing it now"); + connection.destroy(); + } + }); + + socket.on('node-check-connected-status', async (guildId, socketCallback) => { + console.log("Requested status check"); + if (await checkIfConnectedToVC(guildId)) { + console.log("There is an open VC connection"); + socketCallback(true); + } else { + socketCallback(false); + } }); socket.on('disconnect', () => { diff --git a/server/discordBot/commands/join.mjs b/server/discordBot/commands/join.mjs index a37f61b..26892dd 100644 --- a/server/discordBot/commands/join.mjs +++ b/server/discordBot/commands/join.mjs @@ -1,5 +1,5 @@ import { SlashCommandBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } from 'discord.js'; -import { requestNodeJoinSystem } from '../../modules/socketServerWrappers.mjs'; +import { requestNodeJoinSystem, checkIfNodeIsConnectedToVC } from '../../modules/socketServerWrappers.mjs'; import { getSystemsByNuid, getAllSystems, getSystemByName } from '../../modules/mongoSystemsWrappers.mjs'; // Exporting data property @@ -39,32 +39,35 @@ export async function execute(nodeIo, interaction) { const selectedSystem = interaction.options.getString('system'); try { - // Get all open socket nodes - const openSockets = await nodeIo.allSockets(); // TODO - Filter the returned nodes to only nodes that have the radio capability - console.log("All open sockets: ", openSockets); - // Get the selected system object from the DB const system = await getSystemByName(selectedSystem); // Function wrapper to request the selected/only node to join the selected system const joinSelectedNode = async (selectedNodeSocketId) => { const openSocket = await nodeIo.sockets.sockets.get(selectedNodeSocketId); - console.log("Joining selected open socket:", openSocket.id, system.name, channelToJoin.id, openSocket.node.name); + console.log("Joining selected open socket:", selectedNodeSocketId, system.name, channelToJoin.id, openSocket.node.name); // Ask the node to join the selected channel and system await requestNodeJoinSystem(openSocket, system.name, channelToJoin.id); } + // Get all open socket nodes + const openSockets = [...await nodeIo.allSockets()]; // TODO - Filter the returned nodes to only nodes that have the radio capability + console.log("All open sockets: ", openSockets); + var availableNodes = []; - // Check each open socket to see if the ID is included in the selected system - await openSockets.forEach(openSocket => { - openSocket = nodeIo.sockets.sockets.get(openSocket); - // TODO - Determine if the node is already connected elsewhere - // 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); + // 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); + const connected = await checkIfNodeIsConnectedToVC(nodeIo, interaction.guild.id, openSocket.node.nuid); + console.log("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); + } } - }); + })); console.log("Availble nodes:", availableNodes, availableNodes.map(socket => socket.node.name)); @@ -77,7 +80,7 @@ export async function execute(nodeIo, interaction) { // Request the node to join await joinSelectedNode(availableNodes[0].id); // Let the user know - await interaction.editReply({ content: `Ok ${interaction.member.id}, a bot will join your channel listening to *'${system.name}'* shortly`, components: [] }); + await interaction.editReply({ content: `Ok <@${interaction.member.id}>, a bot will join your channel listening to *'${system.name}'* shortly`, components: [] }); } else if (availableNodes.length > 1) { // There is more than one node availble for the requested system const nodeSelectionButtons = [] @@ -104,7 +107,7 @@ export async function execute(nodeIo, interaction) { // Run the local wrapper to listen to the selected node await joinSelectedNode(selectedNode.customId); // Let the user know - await selectedNodeConfirmation.update({ content: `Ok ${interaction.member.id}, a bot will join your channel listening to *'${system.name}'*`, components: [] }); + await selectedNodeConfirmation.update({ content: `Ok <@${interaction.member.id}>, a bot will join your channel listening to *'${system.name}'*`, components: [] }); } catch (e) { console.error(e); // Timeout the prompt if the user doesn't interact with it diff --git a/server/modules/socketServerWrappers.mjs b/server/modules/socketServerWrappers.mjs index ef5085f..609fc3d 100644 --- a/server/modules/socketServerWrappers.mjs +++ b/server/modules/socketServerWrappers.mjs @@ -114,7 +114,7 @@ export const nearbySystemsUpdateWraper = async (nuid, nearbySystems) => { } else { // The systems are not the same // TODO - Implement logic to handle if system names match, but they are for different frequencies or have additional freqs - + // Check if the current node is listed in the nodes, if not add it if (!existingSystem.nodes.includes(nuid)) { existingSystem.nodes.push(nuid); @@ -141,23 +141,78 @@ export const nearbySystemsUpdateWraper = async (nuid, nearbySystems) => { * @param {string} nuid The NUID to find within the open sockets * @returns {string|null} Will return the open socket ID or NULL */ -const getSocketIdByNuid = async (nuid) => { - for (const openSocket in openSockets) { +const getSocketIdByNuid = async (nodeIo, nuid) => { + for (const openSocket in await nodeIo.allSockets()) { if (openSockets[openSocket] == nuid) return openSocket; } return null; } +/** + * Get all nodes that are connected to a voice channel + * @param {any} nodeIo + * @param {any} guildId The guild ID string for the guild we are looking in + * @returns {any} + */ +export const getAllSocketsConnectedToVC = async (nodeIo, guildId) => { + // Get all open socket nodes + // TODO - require a server guild to filter the results, ie this would be able to check what server the VCs the nodes are connected are in + const openSockets = [...await nodeIo.allSockets()]; // TODO - Filter the returned nodes to only nodes that have the radio capability + // Check each open socket to see if the node has the requested system + const socketsConnectedToVC = [] + await Promise.all(openSockets.map(async openSocket => { + openSocket = await nodeIo.sockets.sockets.get(openSocket); + await new Promise((res) => { + openSocket.emit('node-check-connected-status', guildId, (status) => { + if (status) { + console.log("Socket is connected to VC:", openSocket.node.name); + socketsConnectedToVC.push(openSocket); + } else { + console.log("Socket is NOT connected to VC:", openSocket.node.name); + } + res(); + }) + }); + })); + return socketsConnectedToVC; +} +/** + * Wrapper to check if the given NUID is connected to a VC + * @param {any} nodeIo The nodeIo object that contains the IO server + * @param {any} nuid The NUID string that we would like to find in the open socket connections + * @returns {any} + */ +export const checkIfNodeIsConnectedToVC = async (nodeIo, guildId, nuid) => { + const socketsConnectedToVC = await getAllSocketsConnectedToVC(nodeIo, guildId); + for (const socket of socketsConnectedToVC) { + if (socket.node.nuid === nuid) { + return true; + } + } + return false; +} + +/** + * Request a given socket node to join a given voice channel + * @param {any} socket The socket object of the node the request should be sent to + * @param {any} systemName The system preset name that we would like to listen to + * @param {any} discordChanelId The Discord channel ID to join the listening bot to + * @returns {any} + */ export const requestNodeJoinSystem = async (socket, systemName, discordChanelId) => { - // Check for System updates // Check for open client IDs const joinData = { 'clientID': "MTE5NjAwNTM2ODYzNjExMjk3Nw.GuCMXg.24iNNofNNumq46FIj68zMe9RmQgugAgfrvelEA", 'channelID': discordChanelId, 'preset': systemName } - sendNodeCommand(socket, "node-join", joinData); + // Send the command to the node + await sendNodeCommand(socket, "node-join", joinData); +} + +export const requestBotLeave = async () => { + } \ No newline at end of file