// Modules const { customSlashCommandBuilder } = require('../utilities/customSlashCommandBuilder'); const { DebugBuilder } = require("../utilities/debugBuilder"); const { BufferToJson, getMembersInRole, getKeyByArrayValue } = require("../utilities/utils"); const { requestOptions, sendHttpRequest } = require("../utilities/httpRequests"); const { readFileSync } = require('fs'); const { getOnlineNodes, getNodeInfoFromId, updateNodeInfo } = require("../utilities/mysqlHandler"); const path = require('path'); // Global Vars const log = new DebugBuilder("server", "join"); /** * * This wrapper will check if there is an available node with the requested preset and if so checks for an available client ID to join with * * @param {*} presetName The preset name to listen to on the client * @param {*} channelId The channel ID to join the bot to * @param {*} clientIdsUsed EITHER A collection of clients that are currently connected OR a single discord client ID (NOT dev portal ID) that should be used to join the server with * @returns */ async function joinServerWrapper(presetName, channelId, clientIdsUsed) { // Get nodes online var onlineNodes = await new Promise((recordResolve, recordReject) => { getOnlineNodes((nodeRows) => { recordResolve(nodeRows); }); }); // Check which nodes have the selected preset onlineNodes = onlineNodes.filter(node => node.nearbySystems.includes(presetName)); log.DEBUG("Filtered Online Nodes: ", onlineNodes); // Check if any nodes with this preset are available var nodesCurrentlyAvailable = []; for (const node of onlineNodes) { const reqOptions = new requestOptions("/bot/status", "GET", node.ip, node.port); await new Promise(resolve => sendHttpRequest(reqOptions, "", (responseObj) => { if (!responseObj || !responseObj.statusCode == 200) return resolve(false); log.VERBOSE("Response Object from node ", node, responseObj); nodesCurrentlyAvailable.push(node); resolve(true); })); } log.DEBUG("Nodes Currently Available: ", nodesCurrentlyAvailable); // If not, let the user know if (!nodesCurrentlyAvailable.length > 0) return Error("All nodes with this channel are unavailable, consider swapping one of the currently joined bots."); // If so, join with the first node var availableClientIds = await Object(JSON.parse(readFileSync(path.resolve(__dirname, '../clientIds.json')))); log.DEBUG("All clients: ", Object.keys(availableClientIds)); var selectedClientId; if (typeof clientIdsUsed === 'string') { if (Object.keys(availableClientIds).includes(clientIdsUsed)) selectedClientId = availableClientIds[clientIdsUsed]; } else { log.DEBUG("Client IDs Used: ", clientIdsUsed.keys()); for (const usedClientId of clientIdsUsed.keys()) { log.DEBUG("Used Client ID: ", usedClientId); if (Object.keys(availableClientIds).includes(usedClientId)) { delete availableClientIds[usedClientId]; } } log.DEBUG("Available Client IDs: ", availableClientIds); if (!Object.keys(availableClientIds).length > 0) return log.ERROR("All client ID have been used, consider swapping one of the curretly joined bots or adding more Client IDs to the pool.") selectedClientId = availableClientIds[Object.keys(availableClientIds)[0]]; } const selectedNode = nodesCurrentlyAvailable[0]; const reqOptions = new requestOptions("/bot/join", "POST", selectedNode.ip, selectedNode.port); sendHttpRequest(reqOptions, JSON.stringify({ "channelId": channelId, "clientId": selectedClientId.id, "presetName": presetName }), async (responseObj) => { log.VERBOSE("Response Object from node ", selectedNode, responseObj); if (!responseObj || !responseObj.statusCode == 200) return false; // Node has connected to discord selectedNode.connected = true; const updatedNode = await updateNodeInfo(selectedNode) log.DEBUG("Updated Node: ", updatedNode); }); } exports.joinServerWrapper = joinServerWrapper; module.exports = { data: new customSlashCommandBuilder() .setName('join') .setDescription('Join the channel you are in with the preset you choose') .addAllSystemPresetOptions(), example: "join", isPrivileged: false, requiresTokens: false, defaultTokenUsage: 0, deferInitialReply: true, async execute(interaction) { try{ const guildId = interaction.guild.id; const presetName = interaction.options.getString('preset'); const channelId = interaction.member.voice.channel.id; log.DEBUG(`Join requested by: ${interaction.user.username}, to: '${presetName}', in channel: ${channelId} / ${guildId}`); await interaction.editReply('**Pong.**'); const onlineBots = await getMembersInRole(interaction); log.DEBUG("Online Bots: ", onlineBots); await joinServerWrapper(presetName, channelId, onlineBots.online); //await interaction.channel.send('**Pong.**'); // This will send a message to the channel of the interaction outside of the initial reply }catch(err){ log.ERROR(err) //await interaction.reply(err.toString()); } } }