Merge of /utilities

This commit is contained in:
Logan Cusano
2023-05-06 15:09:19 -04:00
parent f3a4f25f85
commit b0e52920a7
6 changed files with 391 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
// Debug
const debug = require('debug');
// Read .env file to process.env
require('dotenv').config();
/**
* Create the different logging methods for a function
* Namespace template = ("[app]:[fileName]:['INFO', 'WARNING', 'DEBUG', 'ERROR']")
* @param {string} appName The name of the app to be used in the 'app' portion of the namespace
* @param {string} fileName The name of the file calling the builder to be used in the 'fileName' portion of the namespace
*/
exports.DebugBuilder = class DebugBuilder {
constructor(appName, fileName) {
this.INFO = debug(`${appName}:${fileName}:INFO`);
this.DEBUG = debug(`${appName}:${fileName}:DEBUG`);
this.VERBOSE = debug(`${appName}:${fileName}:VERBOSE`);
this.WARN = debug(`${appName}:${fileName}:WARNING`);
this.ERROR = (...messageParts) => {
const error = debug(`${appName}:${fileName}:ERROR`);
error(messageParts);
if (process.env.EXIT_ON_ERROR && process.env.EXIT_ON_ERROR > 0) setTimeout(process.exit, process.env.EXIT_ON_ERROR_DELAY ?? 0);
}
}
}

View File

@@ -0,0 +1,49 @@
const { REST, Routes } = require('discord.js');
require('dotenv').config();
const token = process.env.TOKEN;
//const clientId = process.env.clientId;
//const guildId = process.env.guildId;
const fs = require('node:fs');
const path = require('node:path');
const { DebugBuilder } = require("./debugBuilder");
const log = new DebugBuilder("server", "deployCommands");
const commands = [];
// Grab all the command files from the commands directory you created earlier
const commandsPath = path.resolve(__dirname, '../commands');
const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js'));
exports.deploy = (clientId, guildIDs) => {
log.DEBUG("Deploying commands for: ", guildIDs);
if (Array.isArray(guildIDs)) guildIDs = [guildIDs];
// Grab the SlashCommandBuilder#toJSON() output of each command's data for deployment
for (const file of commandFiles) {
const command = require(`${path.resolve(commandsPath, file)}`);
commands.push(command.data.toJSON());
}
// Construct and prepare an instance of the REST module
const rest = new REST({ version: '10' }).setToken(token);
// and deploy your commands!
for (const guildId of guildIDs){
(async () => {
try {
log.DEBUG(`Started refreshing ${commands.length} application (/) commands for guild ID: ${guildId}.`);
// The put method is used to fully refresh all commands in the guild with the current set
const data = await rest.put(
Routes.applicationGuildCommands(clientId, guildId),
{ body: commands },
);
log.DEBUG(`Successfully reloaded ${data.length} application (/) commands for guild ID: ${guildId}.`);
} catch (error) {
// And of course, make sure you catch and log any errors!
log.ERROR("ERROR Deploying commands: ", error, "Body from error: ", commands);
}
})()
}
};

View File

@@ -0,0 +1,68 @@
// Debug
const { DebugBuilder } = require("../utilities/debugBuilder.js");
const log = new DebugBuilder("server", "httpRequests");
// Modules
const http = require("http");
exports.requestOptions = class requestOptions {
/**
* Construct an HTTP request
* @param {*} method Method of request to use [GET, POST]
* @param {*} headers Headers of the request, not required but will get filled with default values if not set
* @param {*} hostname The destination of the request
* @param {*} port The port for the destination, will use 3001 by default
*/
constructor(path, method, hostname, port = 3001, headers = undefined, timeout = undefined) {
this.hostname = hostname;
this.path = path;
this.port = port;
this.method = method;
this.timeout = timeout;
if (method === "POST"){
this.headers = headers ?? {
'Content-Type': 'application/json',
}
}
}
}
/**
* Send the HTTP request to the server
* @param requestOptions
* @param data
* @param callback
*/
exports.sendHttpRequest = function sendHttpRequest(requestOptions, data, callback){
log.DEBUG("Sending a request to: ", requestOptions.hostname, requestOptions.port)
// Create the request
const req = http.request(requestOptions, res => {
res.on('data', (data) => {
const responseObject = {
"statusCode": res.statusCode,
"body": data
};
try {
responseObject.body = JSON.parse(responseObject.body)
}
catch (err) {
}
log.DEBUG("Response Object: ", responseObject);
return callback(responseObject);
})
}).on('error', err => {
log.ERROR('Error: ', err.message)
// TODO need to handle if the server is down
})
if (requestOptions.timeout) {
req.setTimeout(requestOptions.timeout, () => {
return callback(false);
});
}
// Write the data to the request and send it
req.write(data)
req.end()
}

View File

@@ -0,0 +1,132 @@
const mysql = require('mysql');
const databaseConfig = require('../config/databaseConfig');
const utils = require('./utils');
const connection = mysql.createPool({
host: databaseConfig.database_host,
user: databaseConfig.database_user,
password: databaseConfig.database_password,
database: databaseConfig.database_database
});
const nodesTable = `${databaseConfig.database_database}.nodes`;
/** Get all nodes the server knows about regardless of status
* @param {*} callback Callback function
*/
exports.getAllNodes = (callback) => {
const sqlQuery = `SELECT * FROM ${nodesTable}`
runSQL(sqlQuery, (rows) => {
return callback(rows);
})
}
/** Get all nodes that have the online status set true (are online)
* @param callback Callback function
*/
exports.getOnlineNodes = (callback) => {
const sqlQuery = `SELECT * FROM ${nodesTable} WHERE online = 1;`
runSQL(sqlQuery, (rows) => {
return callback(rows);
})
}
/** Get info on a node based on ID
* @param nodeId The ID of the node
* @param callback Callback function
*/
exports.getNodeInfoFromId = (nodeId, callback) => {
const sqlQuery = `SELECT * FROM ${nodesTable} WHERE id = ${nodeId}`
runSQL(sqlQuery, (rows) => {
// Call back the first (and theoretically only) row
// Specify 0 so downstream functions don't have to worry about it
return callback(rows[0]);
})
}
/** Add a new node to the DB
* @param nodeObject Node information object
* @param callback Callback function
*/
exports.addNewNode = (nodeObject, callback) => {
if (!nodeObject.name) throw new Error("No name provided");
const name = nodeObject.name,
ip = nodeObject.ip,
port = nodeObject.port,
location = nodeObject.location,
nearbySystems = utils.JsonToBuffer(nodeObject.nearbySystems),
online = nodeObject.online;
const sqlQuery = `INSERT INTO ${nodesTable} (name, ip, port, location, nearbySystems, online) VALUES ('${name}', '${ip}', ${port}, '${location}', '${nearbySystems}', ${online})`;
runSQL(sqlQuery, (rows) => {
return callback(rows);
})
}
/** Update the known info on a node
* @param nodeObject Node information object
* @param callback Callback function
*/
exports.updateNodeInfo = (nodeObject, callback) => {
const name = nodeObject.name,
ip = nodeObject.ip,
port = nodeObject.port,
location = nodeObject.location,
online = nodeObject.online;
let queryParams = [],
nearbySystems = nodeObject.nearbySystems;
if (name) queryParams.push(`name = '${name}'`);
if (ip) queryParams.push(`ip = '${ip}'`);
if (port) queryParams.push(`port = ${port}`);
if (location) queryParams.push(`location = '${location}'`);
if (nearbySystems) {
nearbySystems = utils.JsonToBuffer(nearbySystems)
queryParams.push(`nearbySystems = '${nearbySystems}'`);
}
if (typeof online === "boolean") {
if (online) queryParams.push(`online = 1`);
else queryParams.push(`online = 0`);
}
let sqlQuery = `UPDATE ${nodesTable} SET`
if (!queryParams || queryParams.length === 0) return callback(undefined);
if (queryParams.length === 1) {
sqlQuery = `${sqlQuery} ${queryParams[0]}`
} else {
let i = 0;
for (const param of queryParams) {
if (i === queryParams.length-1) {
sqlQuery = `${sqlQuery} ${param}`
i += 1;
}
else {
sqlQuery = `${sqlQuery} ${param},`
i += 1;
}
}
}
sqlQuery = `${sqlQuery} WHERE id = ${nodeObject.id};`
runSQL(sqlQuery, (rows) => {
if (rows.affectedRows === 1) return callback(true);
else return callback(rows);
})
}
// Function to run and handle SQL errors
function runSQL(sqlQuery, callback, error = (err) => {
console.log(err);
throw err;
}) {
connection.query(sqlQuery, (err, rows) => {
if (err) return error(err);
//console.log('The rows are:', rows);
return callback(rows);
})
}
exports.closeConnection = () => {
connection.end()
}

View File

@@ -0,0 +1,99 @@
// This is for record builders
const { DebugBuilder } = require("./debugBuilder");
const log = new DebugBuilder("server", "recordHelper");
class baseRSSRecord {
/**
*
* @param {*} _id The ID of the post from the DB
* @param {*} _title The title of the post
* @param {*} _link The link to the post
* @param {*} _category The category of the post
*/
constructor(_id, _title, _link, _category) {
this.id = _id;
this.title = _title;
this.link= _link;
this.category = _category;
}
getId() {
return this.id;
}
get(key) {
log.DEBUG(`Getting key '${key}' from: `, Object(this));
if (!Object.keys(this).includes(key)) throw new Error(`Key is invalid ${key}`);
return this[key]
}
}
exports.baseRSSRecord = baseRSSRecord;
/**
* Build a Source record.
*
* A source record is the record of an RSS feed itself. Something like "https://www.leafly.com/feed".
*/
exports.RSSSourceRecord = class RSSSourceRecord extends baseRSSRecord{
/**
* @param {*} _id The ID of the post from the DB
* @param {*} _title The title of the post
* @param {*} _link The link to the post
* @param {*} _category The category of the post
* @param {*} _guild_id The guild id to receive updates on this source
* @param {*} _channel_id The channel to send updates from this source
*/
constructor(_id, _title, _link, _category, _guild_id, _channel_id) {
super(_id, _title, _link, _category);
this.guild_id = _guild_id;
this.channel_id = _channel_id;
}
}
/**
* Build a Post record.
*
* A post is an individual article/post/link from an RSS feed. Each individual post will be added to the database to be recalled and sent later.
*/
exports.RSSPostRecord = class RSSPostRecord extends baseRSSRecord{
/**
* @param {*} _id The ID of the post from the DB
* @param {*} _title The title of the post
* @param {*} _link The link to the post
* @param {*} _category The category of the post
* @param {*} _guid The ID of this post
*/
constructor(_id, _title, _link, _category, _guid) {
super(_id, _title, _link, _category);
this.guid = _guid;
}
}
/**
* Base transaction
*/
class BaseTransaction {
constructor(_provider_transaction_id, _account_id, _discord_tokens_used, _provider_tokens_used, _provider_id) {
this.transaction_id = _provider_transaction_id;
this.account_id = _account_id;
this.discord_tokens_used = _discord_tokens_used;
this.provider_tokens_used = _provider_tokens_used;
this.provider_id = _provider_id;
}
}
exports.BaseTransaction = BaseTransaction;
/**
* Base transaction
*/
class BaseUserAccount {
constructor(_discord_account_id, _account_id) {
this.discord_account_id = _discord_account_id;
this.account_id = _account_id;
}
}
exports.BaseUserAccount = BaseUserAccount;

19
Server/utilities/utils.js Normal file
View File

@@ -0,0 +1,19 @@
// Convert a JSON object to a buffer for the DB
exports.JsonToBuffer = (jsonObject) => {
return Buffer.from(JSON.stringify(jsonObject))
}
// Convert a buffer from the DB to JSON object
exports.BufferToJson = (buffer) => {
return JSON.parse(buffer.toString());
}
/** Find a key in an object by its value
*
* @param {*} object The object to search
* @param {*} value The value to search the arrays in the object for
* @returns The key of the object that contains the value
*/
exports.getKeyByArrayValue = (object, value) => {
return Object.keys(object).find(key => object[key].includes(value));
}