Still needed: - Way to update clients' versions - Way to delete nodes - working dashboard - working search function
212 lines
8.5 KiB
JavaScript
212 lines
8.5 KiB
JavaScript
// Config
|
|
require('dotenv').config();
|
|
// Debug
|
|
const { DebugBuilder } = require("../utilities/debugBuilder.js");
|
|
const log = new DebugBuilder("server", "adminController");
|
|
// Utilities
|
|
const { getAllClientIds } = require("../utilities/utils");
|
|
const { getOnlineNodes, updateNodeInfo, addNodeConnection, getConnectionByNodeId, getNodeInfoFromId, checkNodeConnectionByClientId, removeNodeConnectionByNodeId } = require("../utilities/mysqlHandler");
|
|
const { requestOptions, sendHttpRequest } = require("../utilities/httpRequests");
|
|
|
|
/** Get the presets of all online nodes, can be used for functions
|
|
*
|
|
* @param callback Callback function
|
|
* @returns {*} A list of the systems online
|
|
*/
|
|
async function getPresetsOfOnlineNodes(callback) {
|
|
getOnlineNodes((onlineNodes) => {
|
|
return callback(onlineNodes);
|
|
});
|
|
}
|
|
|
|
async function getNodeBotStatus(nodeId, callback) {
|
|
getNodeInfoFromId(nodeId, (nodeObject) =>{
|
|
reqOptions = new requestOptions("/bot/status", "GET", nodeObject.ip, nodeObject.port, undefined, 5);
|
|
sendHttpRequest(reqOptions, JSON.stringify({}), (responseObject) => {
|
|
if (responseObject === false) {
|
|
// Bot is joined
|
|
}
|
|
else {
|
|
// Bot is free
|
|
}
|
|
return callback(responseObject);
|
|
});
|
|
});
|
|
}
|
|
|
|
|
|
/** Return to requests for the presets of all online nodes, cannot be used in functions
|
|
*
|
|
* @param {*} req Express request parameter
|
|
* @param {*} res Express response parameter
|
|
*/
|
|
exports.getAvailablePresets = async (req, res) => {
|
|
await getPresetsOfOnlineNodes((systems) => {
|
|
res.status(200).json({
|
|
"systemsOnline": systems
|
|
});
|
|
})
|
|
}
|
|
|
|
/** Request a node to join the server listening to a specific preset
|
|
*
|
|
* @param {*} req Express request parameter
|
|
* @var {*} req.body.preset The preset to join (REQ)
|
|
* @var {*} req.body.nodeId The specific node to join (OPT/REQ if more than one node has the preset)
|
|
* @var {*} req.body.clientId The ID of the client that we want to join with
|
|
* @var {*} req.body.channelId The channel Id of the discord channel to join
|
|
* @param {*} res Express response parameter
|
|
*/
|
|
exports.joinPreset = async (req, res) => {
|
|
if (!req.body.preset) return res.status(400).json("No preset specified");
|
|
if (!req.body.nodeId) return res.status(400).json("No node ID specified");
|
|
if (!req.body.clientId) return res.status(400).json("No client ID specified");
|
|
if (!req.body.channelId) return res.status(400).json("No channel ID specified");
|
|
|
|
const preset = req.body.preset;
|
|
const nodeId = req.body.nodeId;
|
|
const clientId = req.body.clientId;
|
|
const channelId = req.body.channelId;
|
|
|
|
const joinedClient = await joinServerWrapper(preset, channelId, clientId, nodeId);
|
|
if (!joinedClient) return res.send(400).json("No joined client");
|
|
return res.status(200).json(joinedClient);
|
|
}
|
|
|
|
/** Request a node to join the server listening to a specific preset
|
|
*
|
|
* @param {*} req Express request parameter
|
|
* @param {*} res Express response parameter
|
|
* @var {*} req.body.nodeId The ID of the node to disconnect
|
|
*/
|
|
exports.leaveServer = async (req, res) => {
|
|
if (!req.body.nodeId) return res.status(400).json("No node ID specified");
|
|
|
|
const nodeId = req.body.nodeId;
|
|
const currentConnection = await getConnectionByNodeId(nodeId);
|
|
log.DEBUG("Current Connection for node: ", currentConnection);
|
|
|
|
if (!currentConnection) return res.status(400).json("Node is not connected")
|
|
|
|
await leaveServerWrapper(currentConnection.clientObject)
|
|
|
|
return res.status(200).json(currentConnection.clientObject.name);
|
|
}
|
|
|
|
/**
|
|
* * 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 {*} connections 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
|
|
* @param {number} nodeId [OPTIONAL] The node ID to join with (will join with another node if given node is not available)
|
|
* @returns
|
|
*/
|
|
async function joinServerWrapper(presetName, channelId, connections, nodeId = 0) {
|
|
// 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.presets.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 currentConnection = await getConnectionByNodeId(node.id);
|
|
log.DEBUG("Checking to see if there is a connection for Node: ", node, currentConnection);
|
|
if(!currentConnection) nodesCurrentlyAvailable.push(node);
|
|
}
|
|
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 getAllClientIds();
|
|
log.DEBUG("All clients: ", Object.keys(availableClientIds));
|
|
|
|
var selectedClientId;
|
|
if (typeof connections === 'string') {
|
|
for (const availableClientId of availableClientIds) {
|
|
if (availableClientId.discordId != connections ) selectedClientId = availableClientId;
|
|
}
|
|
}
|
|
else {
|
|
log.DEBUG("Open connections: ", connections);
|
|
for (const connection of connections) {
|
|
log.DEBUG("Used Client ID: ", connection);
|
|
availableClientIds = availableClientIds.filter(cid => cid.discordId != connection.clientObject.discordId);
|
|
}
|
|
|
|
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[0];
|
|
}
|
|
|
|
let selectedNode;
|
|
if (nodeId > 0) {
|
|
for(const availableNode of nodesCurrentlyAvailable){
|
|
if (availableNode.id == nodeId) selectedNode = availableNode;
|
|
}
|
|
}
|
|
|
|
if (!selectedNode) selectedNode = nodesCurrentlyAvailable[0];
|
|
|
|
const reqOptions = new requestOptions("/bot/join", "POST", selectedNode.ip, selectedNode.port);
|
|
const postObject = {
|
|
"channelId": channelId,
|
|
"clientId": selectedClientId.clientId,
|
|
"presetName": presetName
|
|
};
|
|
log.INFO("Post Object: ", postObject);
|
|
sendHttpRequest(reqOptions, JSON.stringify(postObject), async (responseObj) => {
|
|
log.VERBOSE("Response Object from node ", selectedNode, responseObj);
|
|
if (!responseObj || !responseObj.statusCode == 200) return false;
|
|
// Node has connected to discord
|
|
// Updating node Object in DB
|
|
const updatedNode = await updateNodeInfo(selectedNode);
|
|
log.DEBUG("Updated Node: ", updatedNode);
|
|
|
|
// Adding a new node connection
|
|
const nodeConnection = await addNodeConnection(selectedNode, selectedClientId);
|
|
log.DEBUG("Node Connection: ", nodeConnection);
|
|
});
|
|
|
|
return selectedClientId;
|
|
}
|
|
exports.joinServerWrapper = joinServerWrapper;
|
|
|
|
/**
|
|
*
|
|
* @param {*} clientIdObject The client ID object for the node to leave the server. Either 'clientId'||'name' can be set.
|
|
* @returns
|
|
*/
|
|
async function leaveServerWrapper(clientIdObject) {
|
|
if (!clientIdObject.clientId || !clientIdObject.name) return log.ERROR("Tried to leave server without client ID and/or Name");
|
|
|
|
const node = await checkNodeConnectionByClientId(clientIdObject);
|
|
|
|
reqOptions = new requestOptions("/bot/leave", "POST", node.ip, node.port);
|
|
|
|
const responseObj = await new Promise((recordResolve, recordReject) => {
|
|
sendHttpRequest(reqOptions, JSON.stringify({}), async (responseObj) => {
|
|
recordResolve(responseObj);
|
|
});
|
|
});
|
|
|
|
log.VERBOSE("Response Object from node ", node, responseObj);
|
|
if (!responseObj || !responseObj.statusCode == 202) return false;
|
|
// Node has disconnected from discor
|
|
// Removing the node connection from the DB
|
|
const removedConnection = removeNodeConnectionByNodeId(node.id);
|
|
log.DEBUG("Removed Node Connection: ", removedConnection);
|
|
|
|
return;
|
|
}
|
|
exports.leaveServerWrapper = leaveServerWrapper; |