Linting
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

This commit is contained in:
Logan Cusano
2024-08-11 15:57:46 -04:00
parent 5cd47378d6
commit 117cbea67f
37 changed files with 2273 additions and 1738 deletions

View File

@@ -1,33 +1,45 @@
import { DebugBuilder } from "../modules/debugger.mjs";
const log = new DebugBuilder("server", "addonManager");
import { fileURLToPath } from 'url';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from "url";
import fs from "fs";
import path from "path";
// Function to load addons from the addons directory
export const loadAddons = async (nodeIo) => {
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const addonsDir = path.join(__dirname, '../addons');
const addonsDir = path.join(__dirname, "../addons");
// Read the directory containing addon modules
const addonDirectories = await fs.readdirSync(addonsDir, { withFileTypes: true });
// Read the directory containing addon modules
const addonDirectories = await fs.readdirSync(addonsDir, {
withFileTypes: true,
});
addonDirectories.forEach(addonDir => {
if (addonDir.isDirectory()) {
const addonConfigPath = path.join(addonsDir, addonDir.name, 'config.json');
if (fs.existsSync(addonConfigPath)) {
const addonConfig = JSON.parse(fs.readFileSync(addonConfigPath, 'utf-8'));
if (addonConfig.enabled) {
const addonIndexPath = path.join(addonsDir, addonDir.name, 'index.js');
import(`file://${addonIndexPath}`).then(addonModule => {
log.DEBUG("Loading addon: ", addonModule);
addonModule.initialize(nodeIo, addonConfig);
log.DEBUG(`Addon ${addonConfig.name} loaded.`);
});
}
}
addonDirectories.forEach((addonDir) => {
if (addonDir.isDirectory()) {
const addonConfigPath = path.join(
addonsDir,
addonDir.name,
"config.json",
);
if (fs.existsSync(addonConfigPath)) {
const addonConfig = JSON.parse(
fs.readFileSync(addonConfigPath, "utf-8"),
);
if (addonConfig.enabled) {
const addonIndexPath = path.join(
addonsDir,
addonDir.name,
"index.js",
);
import(`file://${addonIndexPath}`).then((addonModule) => {
log.DEBUG("Loading addon: ", addonModule);
addonModule.initialize(nodeIo, addonConfig);
log.DEBUG(`Addon ${addonConfig.name} loaded.`);
});
}
});
}
}
}
});
};

View File

@@ -1,10 +1,10 @@
// Import necessary modules
import debug from 'debug';
import { config } from 'dotenv';
import debug from "debug";
import { config } from "dotenv";
config();
import { promises as fs } from 'fs';
import { join, dirname } from 'path';
import { inspect } from 'util';
import { promises as fs } from "fs";
import { join, dirname } from "path";
import { inspect } from "util";
/**
* Write a given message to the log file
@@ -12,24 +12,27 @@ import { inspect } from 'util';
* @param {string} appName The app name that created the log entry
*/
const writeToLog = async (logMessage, appName) => {
const logLocation = join(process.env.LOG_LOCATION ?? `./logs/${appName}.log`);
const logLocation = join(process.env.LOG_LOCATION ?? `./logs/${appName}.log`);
// Ensure the log directory exists
try {
await fs.mkdir(dirname(logLocation), { recursive: true });
} catch (err) {
console.error(err);
}
// Ensure the log directory exists
try {
await fs.mkdir(dirname(logLocation), { recursive: true });
} catch (err) {
console.error(err);
}
// Ensure the message is a string
logMessage = `${String(logMessage)}\n`;
// Ensure the message is a string
logMessage = `${String(logMessage)}\n`;
// Write to the file
try {
await fs.writeFile(logLocation, logMessage, { encoding: 'utf-8', flag: 'a+' });
} catch (err) {
console.error(err);
}
// Write to the file
try {
await fs.writeFile(logLocation, logMessage, {
encoding: "utf-8",
flag: "a+",
});
} catch (err) {
console.error(err);
}
};
/**
@@ -39,33 +42,37 @@ const writeToLog = async (logMessage, appName) => {
* @param {string} fileName The name of the file calling the builder to be used in the 'fileName' portion of the namespace
*/
export class DebugBuilder {
constructor(appName, fileName) {
const buildLogger = (level) => (...messageParts) => {
const logger = debug(`${appName}:${fileName}:${level}`);
logger(messageParts);
constructor(appName, fileName) {
const buildLogger =
(level) =>
(...messageParts) => {
const logger = debug(`${appName}:${fileName}:${level}`);
logger(messageParts);
const timeStamp = new Date().toLocaleString('en-US', { timeZone: 'America/New_York' });
const message = `${timeStamp} - ${appName}:${fileName}:${level}\t-\t${messageParts.map(part => inspect(part)).join(' ')}`;
const timeStamp = new Date().toLocaleString("en-US", {
timeZone: "America/New_York",
});
const message = `${timeStamp} - ${appName}:${fileName}:${level}\t-\t${messageParts.map((part) => inspect(part)).join(" ")}`;
// Write to console
console.log(message);
// Write to logfile
writeToLog(message, appName);
};
// Write to console
console.log(message);
this.INFO = buildLogger('INFO');
this.DEBUG = buildLogger('DEBUG');
this.VERBOSE = buildLogger('VERBOSE');
this.WARN = buildLogger('WARNING');
this.ERROR = (...messageParts) => {
buildLogger('ERROR')(...messageParts);
// Write to logfile
writeToLog(message, appName);
};
if (process.env.EXIT_ON_ERROR && process.env.EXIT_ON_ERROR > 0) {
writeToLog("!--- EXITING ---!", appName);
const exitDelay = parseInt(process.env.EXIT_ON_ERROR_DELAY, 10) || 0;
setTimeout(() => process.exit(1), exitDelay);
}
};
}
this.INFO = buildLogger("INFO");
this.DEBUG = buildLogger("DEBUG");
this.VERBOSE = buildLogger("VERBOSE");
this.WARN = buildLogger("WARNING");
this.ERROR = (...messageParts) => {
buildLogger("ERROR")(...messageParts);
if (process.env.EXIT_ON_ERROR && process.env.EXIT_ON_ERROR > 0) {
writeToLog("!--- EXITING ---!", appName);
const exitDelay = parseInt(process.env.EXIT_ON_ERROR_DELAY, 10) || 0;
setTimeout(() => process.exit(1), exitDelay);
}
};
}
}

View File

@@ -1,8 +1,12 @@
import { DebugBuilder } from "../../modules/debugger.mjs";
const log = new DebugBuilder("server", "mongoDiscordIDWrappers");
import { insertDocument, getDocuments, connectToDatabase } from "./mongoHandler.mjs";
import {
insertDocument,
getDocuments,
connectToDatabase,
} from "./mongoHandler.mjs";
const collectionName = 'discord-ids';
const collectionName = "discord-ids";
// Wrapper for inserting a Discord ID
export const createDiscordID = async (discordID) => {
@@ -10,7 +14,7 @@ export const createDiscordID = async (discordID) => {
const insertedId = await insertDocument(collectionName, discordID);
return insertedId;
} catch (error) {
log.ERROR('Error creating Discord ID:', error);
log.ERROR("Error creating Discord ID:", error);
throw error;
}
};
@@ -21,7 +25,7 @@ export const getAllDiscordIDs = async () => {
const discordIDs = await getDocuments(collectionName);
return discordIDs;
} catch (error) {
log.ERROR('Error getting all Discord IDs:', error);
log.ERROR("Error getting all Discord IDs:", error);
throw error;
}
};
@@ -29,17 +33,14 @@ export const getAllDiscordIDs = async () => {
// Wrapper for retrieving a Discord ID by name or discord_id
export const getDiscordID = async (identifier) => {
const db = await connectToDatabase();
try {
try {
const collection = db.db().collection(collectionName);
const discordID = await collection.findOne({
$or: [
{ name: identifier },
{ discord_id: identifier }
]
$or: [{ name: identifier }, { discord_id: identifier }],
});
return discordID;
} catch (error) {
log.ERROR('Error getting Discord ID:', error);
log.ERROR("Error getting Discord ID:", error);
throw error;
} finally {
// Close the connection
@@ -52,16 +53,16 @@ export const updateDiscordID = async (identifier, updatedFields) => {
const db = await connectToDatabase();
try {
const collection = db.db().collection(collectionName);
const result = await collection.updateOne({
$or: [
{ name: identifier },
{ discord_id: identifier }
]
}, { $set: updatedFields });
log.INFO('Discord ID updated:', result.modifiedCount);
const result = await collection.updateOne(
{
$or: [{ name: identifier }, { discord_id: identifier }],
},
{ $set: updatedFields },
);
log.INFO("Discord ID updated:", result.modifiedCount);
return result.modifiedCount;
} catch (error) {
log.ERROR('Error updating Discord ID:', error);
log.ERROR("Error updating Discord ID:", error);
throw error;
} finally {
// Close the connection
@@ -72,21 +73,18 @@ export const updateDiscordID = async (identifier, updatedFields) => {
// Wrapper for deleting a Discord ID by name or discord_id
export const deleteDiscordID = async (identifier) => {
const db = await connectToDatabase();
try {
try {
const collection = db.db().collection(collectionName);
const result = await collection.deleteOne({
$or: [
{ name: identifier },
{ discord_id: identifier }
]
$or: [{ name: identifier }, { discord_id: identifier }],
});
log.INFO('Discord ID deleted:', result.deletedCount);
log.INFO("Discord ID deleted:", result.deletedCount);
return result.deletedCount;
} catch (error) {
log.ERROR('Error deleting Discord ID:', error);
log.ERROR("Error deleting Discord ID:", error);
throw error;
} finally {
// Close the connection
await db.close();
}
};
};

View File

@@ -1,112 +1,124 @@
import { DebugBuilder } from "../../modules/debugger.mjs";
const log = new DebugBuilder("server", "mongoFeedsWrappers");
import {
insertDocument,
getDocuments,
getDocumentByField,
updateDocumentByField,
deleteDocumentByField,
} from "./mongoHandler.mjs";
const feedCollectionName = 'feeds';
const postCollectionName = 'posts';
// Wrapper for inserting a feed
export const createFeed = async (feed) => {
try {
const insertedId = await insertDocument(feedCollectionName, feed);
return insertedId;
} catch (error) {
log.ERROR('Error creating feed:', error);
throw error;
}
};
// Wrapper for retrieving all feeds
export const getAllFeeds = async () => {
try {
const feeds = await getDocuments(feedCollectionName);
return feeds;
} catch (error) {
log.ERROR('Error getting all feeds:', error);
throw error;
}
};
// Wrapper for retrieving a feed by link
export const getFeedByLink = async (link) => {
try {
const feed = await getDocumentByField(feedCollectionName, 'link', link);
return feed;
} catch (error) {
log.ERROR('Error getting feed by link:', error);
throw error;
}
};
insertDocument,
getDocuments,
getDocumentByField,
updateDocumentByField,
deleteDocumentByField,
} from "./mongoHandler.mjs";
// Wrapper for retrieving a feed by the title
export const getFeedByTitle = async (title) => {
try {
const feed = await getDocumentByField(feedCollectionName, 'title', title);
return feed;
} catch (error) {
log.ERROR('Error getting feed by link:', error);
throw error;
}
};
// Wrapper for updating a feed by link
export const updateFeedByLink = async (link, updatedFields) => {
try {
const modifiedCount = await updateDocumentByField(feedCollectionName, 'link', link, updatedFields);
return modifiedCount;
} catch (error) {
log.ERROR('Error updating feed by link:', error);
throw error;
}
};
// Wrapper for deleting a feed by link
export const deleteFeedByLink = async (link) => {
try {
const deletedCount = await deleteDocumentByField(feedCollectionName, 'link', link);
return deletedCount;
} catch (error) {
log.ERROR('Error deleting feed by link:', error);
throw error;
}
};
const feedCollectionName = "feeds";
const postCollectionName = "posts";
// Wrapper for deleting a feed by title
export const deleteFeedByTitle = async (title) => {
try {
const deletedCount = await deleteDocumentByField(feedCollectionName, 'title', title);
return deletedCount;
} catch (error) {
log.ERROR('Error deleting feed by link:', error);
throw error;
}
};
// Wrapper for inserting a post
export const createPost = async (post) => {
try {
const insertedId = await insertDocument(postCollectionName, post);
return insertedId;
} catch (error) {
log.ERROR('Error creating post:', error);
throw error;
}
};
// Wrapper for retrieving a post by postId
export const getPostByPostId = async (postId) => {
try {
const post = await getDocumentByField(postCollectionName, 'postId', postId);
return post;
} catch (error) {
log.ERROR('Error getting post by postId:', error);
throw error;
}
};
// Wrapper for inserting a feed
export const createFeed = async (feed) => {
try {
const insertedId = await insertDocument(feedCollectionName, feed);
return insertedId;
} catch (error) {
log.ERROR("Error creating feed:", error);
throw error;
}
};
// Wrapper for retrieving all feeds
export const getAllFeeds = async () => {
try {
const feeds = await getDocuments(feedCollectionName);
return feeds;
} catch (error) {
log.ERROR("Error getting all feeds:", error);
throw error;
}
};
// Wrapper for retrieving a feed by link
export const getFeedByLink = async (link) => {
try {
const feed = await getDocumentByField(feedCollectionName, "link", link);
return feed;
} catch (error) {
log.ERROR("Error getting feed by link:", error);
throw error;
}
};
// Wrapper for retrieving a feed by the title
export const getFeedByTitle = async (title) => {
try {
const feed = await getDocumentByField(feedCollectionName, "title", title);
return feed;
} catch (error) {
log.ERROR("Error getting feed by link:", error);
throw error;
}
};
// Wrapper for updating a feed by link
export const updateFeedByLink = async (link, updatedFields) => {
try {
const modifiedCount = await updateDocumentByField(
feedCollectionName,
"link",
link,
updatedFields,
);
return modifiedCount;
} catch (error) {
log.ERROR("Error updating feed by link:", error);
throw error;
}
};
// Wrapper for deleting a feed by link
export const deleteFeedByLink = async (link) => {
try {
const deletedCount = await deleteDocumentByField(
feedCollectionName,
"link",
link,
);
return deletedCount;
} catch (error) {
log.ERROR("Error deleting feed by link:", error);
throw error;
}
};
// Wrapper for deleting a feed by title
export const deleteFeedByTitle = async (title) => {
try {
const deletedCount = await deleteDocumentByField(
feedCollectionName,
"title",
title,
);
return deletedCount;
} catch (error) {
log.ERROR("Error deleting feed by link:", error);
throw error;
}
};
// Wrapper for inserting a post
export const createPost = async (post) => {
try {
const insertedId = await insertDocument(postCollectionName, post);
return insertedId;
} catch (error) {
log.ERROR("Error creating post:", error);
throw error;
}
};
// Wrapper for retrieving a post by postId
export const getPostByPostId = async (postId) => {
try {
const post = await getDocumentByField(postCollectionName, "postId", postId);
return post;
} catch (error) {
log.ERROR("Error getting post by postId:", error);
throw error;
}
};

View File

@@ -1,10 +1,10 @@
// Import necessary modules
import { MongoClient } from 'mongodb';
import { DebugBuilder } from '../debugger.mjs';
const log = new DebugBuilder("server", 'mongoHandler');
import { MongoClient } from "mongodb";
import { DebugBuilder } from "../debugger.mjs";
const log = new DebugBuilder("server", "mongoHandler");
import dotenv from 'dotenv';
dotenv.config()
import dotenv from "dotenv";
dotenv.config();
// MongoDB connection URI
const uri = process.env.MONGO_URL;
@@ -15,7 +15,7 @@ export const connectToDatabase = async () => {
const client = await MongoClient.connect(uri);
return client;
} catch (error) {
console.error('Error connecting to the database:', error);
console.error("Error connecting to the database:", error);
throw error;
}
};
@@ -24,13 +24,13 @@ export const connectToDatabase = async () => {
export const insertDocument = async (collectionName, document) => {
const db = await connectToDatabase();
log.DEBUG("Inserting document:", collectionName, document);
try {
try {
const collection = db.db().collection(collectionName);
const result = await collection.insertOne(document);
log.DEBUG('Document inserted:', result.insertedId);
log.DEBUG("Document inserted:", result.insertedId);
return result.insertedId;
} catch (error) {
console.error('Error inserting document:', error);
console.error("Error inserting document:", error);
throw error;
} finally {
// Close the connection
@@ -42,13 +42,13 @@ export const insertDocument = async (collectionName, document) => {
export const getDocuments = async (collectionName) => {
log.DEBUG("Getting all documents:", collectionName);
const db = await connectToDatabase();
try {
try {
const collection = db.db().collection(collectionName);
const documents = await collection.find({}).toArray();
log.DEBUG('Documents retrieved:', documents);
log.DEBUG("Documents retrieved:", documents);
return documents;
} catch (error) {
console.error('Error retrieving documents:', error);
console.error("Error retrieving documents:", error);
throw error;
} finally {
// Close the connection
@@ -65,7 +65,7 @@ export const getDocumentByField = async (collectionName, field, value) => {
const document = await collection.findOne({ [field]: value });
return document;
} catch (error) {
console.error('Error retrieving document:', error);
console.error("Error retrieving document:", error);
throw error;
} finally {
await db.close();
@@ -73,16 +73,30 @@ export const getDocumentByField = async (collectionName, field, value) => {
};
// Function to update a document by a specific field
export const updateDocumentByField = async (collectionName, field, value, updatedFields) => {
log.DEBUG("Update document by field:", collectionName, field, value, updatedFields);
export const updateDocumentByField = async (
collectionName,
field,
value,
updatedFields,
) => {
log.DEBUG(
"Update document by field:",
collectionName,
field,
value,
updatedFields,
);
const db = await connectToDatabase();
try {
const collection = db.db().collection(collectionName);
const result = await collection.updateOne({ [field]: value }, { $set: updatedFields });
log.DEBUG('Document updated:', result.modifiedCount);
const result = await collection.updateOne(
{ [field]: value },
{ $set: updatedFields },
);
log.DEBUG("Document updated:", result.modifiedCount);
return result.modifiedCount;
} catch (error) {
console.error('Error updating document:', error);
console.error("Error updating document:", error);
throw error;
} finally {
await db.close();
@@ -96,12 +110,12 @@ export const deleteDocumentByField = async (collectionName, field, value) => {
try {
const collection = db.db().collection(collectionName);
const result = await collection.deleteOne({ [field]: value });
log.DEBUG('Document deleted:', result.deletedCount);
log.DEBUG("Document deleted:", result.deletedCount);
return result.deletedCount;
} catch (error) {
console.error('Error deleting document:', error);
console.error("Error deleting document:", error);
throw error;
} finally {
await db.close();
}
};
};

View File

@@ -1,8 +1,12 @@
import { DebugBuilder } from "../../modules/debugger.mjs";
const log = new DebugBuilder("server", "mongoNodesWrappers");
import { insertDocument, getDocuments, connectToDatabase } from "./mongoHandler.mjs";
import {
insertDocument,
getDocuments,
connectToDatabase,
} from "./mongoHandler.mjs";
const collectionName = 'nodes';
const collectionName = "nodes";
// Wrapper for inserting a node
export const createNode = async (node) => {
@@ -10,7 +14,7 @@ export const createNode = async (node) => {
const insertedId = await insertDocument(collectionName, node);
return insertedId;
} catch (error) {
log.ERROR('Error creating node:', error);
log.ERROR("Error creating node:", error);
throw error;
}
};
@@ -21,7 +25,7 @@ export const getAllNodes = async () => {
const nodes = await getDocuments(collectionName);
return nodes;
} catch (error) {
log.ERROR('Error getting all nodes:', error);
log.ERROR("Error getting all nodes:", error);
throw error;
}
};
@@ -29,12 +33,12 @@ export const getAllNodes = async () => {
// Wrapper for retrieving a node by NUID
export const getNodeByNuid = async (nuid) => {
const db = await connectToDatabase();
try {
try {
const collection = db.db().collection(collectionName);
const node = await collection.findOne({ nuid });
return node;
} catch (error) {
log.ERROR('Error getting node by NUID:', error);
log.ERROR("Error getting node by NUID:", error);
throw error;
} finally {
// Close the connection
@@ -47,11 +51,14 @@ export const updateNodeByNuid = async (nuid, updatedFields) => {
const db = await connectToDatabase();
try {
const collection = db.db().collection(collectionName);
const result = await collection.updateOne({ nuid }, { $set: updatedFields });
log.INFO('Node updated:', result.modifiedCount);
const result = await collection.updateOne(
{ nuid },
{ $set: updatedFields },
);
log.INFO("Node updated:", result.modifiedCount);
return result.modifiedCount;
} catch (error) {
log.ERROR('Error updating node by NUID:', error);
log.ERROR("Error updating node by NUID:", error);
throw error;
} finally {
// Close the connection
@@ -62,16 +69,16 @@ export const updateNodeByNuid = async (nuid, updatedFields) => {
// Wrapper for deleting a node by NUID
export const deleteNodeByNuid = async (nuid) => {
const db = await connectToDatabase();
try {
try {
const collection = db.db().collection(collectionName);
const result = await collection.deleteOne({ nuid });
log.INFO('Node deleted:', result.deletedCount);
log.INFO("Node deleted:", result.deletedCount);
return result.deletedCount;
} catch (error) {
log.ERROR('Error deleting node by NUID:', error);
log.ERROR("Error deleting node by NUID:", error);
throw error;
} finally {
// Close the connection
await db.close();
}
};
};

View File

@@ -1,113 +1,119 @@
import { DebugBuilder } from "../../modules/debugger.mjs";
const log = new DebugBuilder("server", "mongoSystemsWrappers");
import { insertDocument, getDocuments, connectToDatabase } from "./mongoHandler.mjs";
import {
insertDocument,
getDocuments,
connectToDatabase,
} from "./mongoHandler.mjs";
const collectionName = 'radio-systems';
const collectionName = "radio-systems";
// Local wrapper to remove any local files from radio systems
const removeLocalFilesFromsystem = async (system) => {
if (system.trunkFile) delete system.trunkFile;
if (system.whitelistFile) delete system.whitelistFile;
}
if (system.trunkFile) delete system.trunkFile;
if (system.whitelistFile) delete system.whitelistFile;
};
// Wrapper for inserting a system
export const createSystem = async (name, system, nuid) => {
try {
// Remove any local files
await removeLocalFilesFromsystem(system);
// Add the NUID of the node that created this system
system.nodes = [nuid];
// Add the name of the system
system.name = name
const insertedId = await insertDocument(collectionName, system);
return insertedId;
} catch (error) {
log.ERROR('Error creating system:', error);
throw error;
}
try {
// Remove any local files
await removeLocalFilesFromsystem(system);
// Add the NUID of the node that created this system
system.nodes = [nuid];
// Add the name of the system
system.name = name;
const insertedId = await insertDocument(collectionName, system);
return insertedId;
} catch (error) {
log.ERROR("Error creating system:", error);
throw error;
}
};
// Wrapper for retrieving all systems
export const getAllSystems = async () => {
try {
const systems = await getDocuments(collectionName);
return systems;
} catch (error) {
log.ERROR('Error getting all systems:', error);
throw error;
}
try {
const systems = await getDocuments(collectionName);
return systems;
} catch (error) {
log.ERROR("Error getting all systems:", error);
throw error;
}
};
// Wrapper for retrieving a system by name
export const getSystemByName = async (name) => {
const db = await connectToDatabase();
try {
const collection = db.db().collection(collectionName);
const system = await collection.findOne({ name });
return system;
} catch (error) {
log.ERROR('Error getting system by name:', error);
throw error;
} finally {
// Close the connection
await db.close();
}
const db = await connectToDatabase();
try {
const collection = db.db().collection(collectionName);
const system = await collection.findOne({ name });
return system;
} catch (error) {
log.ERROR("Error getting system by name:", error);
throw error;
} finally {
// Close the connection
await db.close();
}
};
// Wrapper to get all systems from a given node
export const getSystemsByNuid = async (nuid) => {
const db = await connectToDatabase();
try {
const collection = db.db().collection(collectionName);
const db = await connectToDatabase();
try {
const collection = db.db().collection(collectionName);
// Query for documents where the 'nodes' array contains the given nodeID
const query = { nodes: nuid };
const systems = await collection.find(query).toArray();
// Query for documents where the 'nodes' array contains the given nodeID
const query = { nodes: nuid };
const systems = await collection.find(query).toArray();
return systems;
} catch (error) {
log.ERROR('Error finding entries:', error);
throw error;
} finally {
// Close the connection
await db.close();
}
return systems;
} catch (error) {
log.ERROR("Error finding entries:", error);
throw error;
} finally {
// Close the connection
await db.close();
}
};
// Wrapper for updating a system by name
export const updateSystemByName = async (name, updatedSystem) => {
// Remove any local files
await removeLocalFilesFromsystem(updatedSystem);
const db = await connectToDatabase();
try {
const collection = db.db().collection(collectionName);
const result = await collection.updateOne({ name }, { $set: updatedSystem });
log.INFO('System updated:', result.modifiedCount);
return result.modifiedCount;
} catch (error) {
log.ERROR('Error updating system by name:', error);
throw error;
} finally {
// Close the connection
await db.close();
}
// Remove any local files
await removeLocalFilesFromsystem(updatedSystem);
const db = await connectToDatabase();
try {
const collection = db.db().collection(collectionName);
const result = await collection.updateOne(
{ name },
{ $set: updatedSystem },
);
log.INFO("System updated:", result.modifiedCount);
return result.modifiedCount;
} catch (error) {
log.ERROR("Error updating system by name:", error);
throw error;
} finally {
// Close the connection
await db.close();
}
};
// Wrapper for deleting a system by name
export const deleteSystemByName = async (name) => {
const db = await connectToDatabase();
try {
const collection = db.db().collection(collectionName);
const result = await collection.deleteOne({ name });
log.INFO('System deleted:', result.deletedCount);
return result.deletedCount;
} catch (error) {
log.ERROR('Error deleting system by name:', error);
throw error;
} finally {
// Close the connection
await db.close();
}
};
const db = await connectToDatabase();
try {
const collection = db.db().collection(collectionName);
const result = await collection.deleteOne({ name });
log.INFO("System deleted:", result.deletedCount);
return result.deletedCount;
} catch (error) {
log.ERROR("Error deleting system by name:", error);
throw error;
} finally {
// Close the connection
await db.close();
}
};

View File

@@ -1,41 +1,47 @@
import { DebugBuilder } from "../modules/debugger.mjs";
const log = new DebugBuilder("server", "socketServer");
import express from 'express';
import { createServer } from 'node:http';
import { Server } from 'socket.io';
import morgan from 'morgan';
import { nodeLoginWrapper, nodeUpdateWrapper, nodeDisconnectWrapper, nearbySystemsUpdateWraper } from "./socketServerWrappers.mjs";
import express from "express";
import { createServer } from "node:http";
import { Server } from "socket.io";
import morgan from "morgan";
import {
nodeLoginWrapper,
nodeUpdateWrapper,
nodeDisconnectWrapper,
nearbySystemsUpdateWraper,
} from "./socketServerWrappers.mjs";
export const app = express();
export const server = createServer(app);
export const nodeIo = new Server(server);
app.use(morgan('tiny'));
app.use(morgan("tiny"));
app.get('/', (req, res) => {
res.send('<h1>Hello world</h1>');
app.get("/", (req, res) => {
res.send("<h1>Hello world</h1>");
});
nodeIo.on('connection', (socket) => {
log.INFO('a user connected', socket.id);
nodeIo.on("connection", (socket) => {
log.INFO("a user connected", socket.id);
socket.on('node-login', async (data) => {
await nodeLoginWrapper(data, socket);
await socket.emit('node-login-successful');
})
socket.on("node-login", async (data) => {
await nodeLoginWrapper(data, socket);
await socket.emit("node-login-successful");
});
socket.on('node-update', async (data) => {
let tempPromises = [];
tempPromises.push(nodeUpdateWrapper(data.node));
tempPromises.push(nearbySystemsUpdateWraper(data.node.nuid, data.nearbySystems));
socket.on("node-update", async (data) => {
let tempPromises = [];
tempPromises.push(nodeUpdateWrapper(data.node));
tempPromises.push(
nearbySystemsUpdateWraper(data.node.nuid, data.nearbySystems),
);
await Promise.all(tempPromises);
await Promise.all(tempPromises);
await socket.emit('node-update-successful')
})
await socket.emit("node-update-successful");
});
socket.on('disconnect', () => {
nodeDisconnectWrapper(socket.id);
});
});
socket.on("disconnect", () => {
nodeDisconnectWrapper(socket.id);
});
});

View File

@@ -1,7 +1,17 @@
import { DebugBuilder } from "../modules/debugger.mjs";
const log = new DebugBuilder("server", "socketServerWrappers");
import { createNode, getNodeByNuid, updateNodeByNuid } from "./mongo-wrappers/mongoNodesWrappers.mjs"
import { createSystem, getSystemByName, updateSystemByName, getSystemsByNuid, deleteSystemByName } from "./mongo-wrappers/mongoSystemsWrappers.mjs"
import {
createNode,
getNodeByNuid,
updateNodeByNuid,
} from "./mongo-wrappers/mongoNodesWrappers.mjs";
import {
createSystem,
getSystemByName,
updateSystemByName,
getSystemsByNuid,
deleteSystemByName,
} from "./mongo-wrappers/mongoSystemsWrappers.mjs";
/**
* Description
@@ -11,11 +21,11 @@ import { createSystem, getSystemByName, updateSystemByName, getSystemsByNuid, de
* @returns {any}
*/
const sendNodeCommand = async (socket, command, data) => {
// TODO - Check to see if the command exists
// TODO - Check to see if the socket is alive?
// TODO - Validate the given data
socket.emit(command, data);
}
// TODO - Check to see if the command exists
// TODO - Check to see if the socket is alive?
// TODO - Validate the given data
socket.emit(command, data);
};
/**
* Log the node into the network
@@ -24,25 +34,25 @@ const sendNodeCommand = async (socket, command, data) => {
* @returns {any}
*/
export const nodeLoginWrapper = async (data, socket) => {
log.INFO(`Login requested from node: ${data.nuid}`, data);
// Check to see if node exists
var node = await getNodeByNuid(data.nuid);
if (!node) {
const insertedId = await createNode(data);
log.DEBUG("Added new node to the database:", insertedId);
} else {
// Check for updates
const updatedNode = await updateNodeByNuid(data.nuid, data)
log.DEBUG("Updated node:", updatedNode);
}
log.INFO(`Login requested from node: ${data.nuid}`, data);
// Check to see if node exists
var node = await getNodeByNuid(data.nuid);
if (!node) {
const insertedId = await createNode(data);
log.DEBUG("Added new node to the database:", insertedId);
} else {
// Check for updates
const updatedNode = await updateNodeByNuid(data.nuid, data);
log.DEBUG("Updated node:", updatedNode);
}
node = await getNodeByNuid(data.nuid);
node = await getNodeByNuid(data.nuid);
// Add the socket/node connection
socket.node = node;
// Add the socket/node connection
socket.node = node;
return;
}
return;
};
/**
* Disconnect the client from the server
@@ -50,9 +60,9 @@ export const nodeLoginWrapper = async (data, socket) => {
* @returns {any}
*/
export const nodeDisconnectWrapper = async (socketId) => {
// TODO - Let any server know that a bot has disconnected if the bot was joined to vc? might not be worth cpu lol
return;
}
// TODO - Let any server know that a bot has disconnected if the bot was joined to vc? might not be worth cpu lol
return;
};
/**
* Update node data in the database
@@ -60,10 +70,10 @@ export const nodeDisconnectWrapper = async (socketId) => {
* @returns {any}
*/
export const nodeUpdateWrapper = async (nodeData) => {
log.DEBUG("Data update sent by node: ", nodeData);
const updateResults = await updateNodeByNuid(nodeData.nuid, nodeData);
return;
}
log.DEBUG("Data update sent by node: ", nodeData);
const updateResults = await updateNodeByNuid(nodeData.nuid, nodeData);
return;
};
/**
* Wrapper to update the systems from the nearbySystems object passed from clients
@@ -71,89 +81,103 @@ export const nodeUpdateWrapper = async (nodeData) => {
* @param {object} nearbySystems The nearby systems object passed from the node to be updated
*/
export const nearbySystemsUpdateWraper = async (nuid, nearbySystems) => {
log.DEBUG("System updates sent by node: ", nuid, nearbySystems);
// Check to see if the node removed any systems
const existingSystems = await getSystemsByNuid(nuid);
log.DEBUG("Existing systems:", existingSystems);
if (existingSystems !== nearbySystems) {
for (const existingSystem of existingSystems) {
if (existingSystem.name in nearbySystems) {
// Skip this system if it's in the given systems update
continue;
}
log.DEBUG("System updates sent by node: ", nuid, nearbySystems);
// Check to see if the node removed any systems
const existingSystems = await getSystemsByNuid(nuid);
log.DEBUG("Existing systems:", existingSystems);
if (existingSystems !== nearbySystems) {
for (const existingSystem of existingSystems) {
if (existingSystem.name in nearbySystems) {
// Skip this system if it's in the given systems update
continue;
}
log.DEBUG("System exists that was not given by node", existingSystem);
// Check if this node was the only node on this system
if (existingSystem.nodes.filter(node => node !== nuid).length === 0) {
// Remove the system if so
log.INFO("Given node was the only node on this system, removing the system...");
await deleteSystemByName(existingSystem.name);
} else {
// Remove the node from the array if there are other nodes with this system
log.INFO("Other nodes found on this system, removing the given NUID");
existingSystem.nodes = existingSystem.nodes.filter(node => node !== nuid);
log.DEBUG(existingSystem);
await updateSystemByName(existingSystem.name, existingSystem);
}
}
log.DEBUG("System exists that was not given by node", existingSystem);
// Check if this node was the only node on this system
if (existingSystem.nodes.filter((node) => node !== nuid).length === 0) {
// Remove the system if so
log.INFO(
"Given node was the only node on this system, removing the system...",
);
await deleteSystemByName(existingSystem.name);
} else {
// Remove the node from the array if there are other nodes with this system
log.INFO("Other nodes found on this system, removing the given NUID");
existingSystem.nodes = existingSystem.nodes.filter(
(node) => node !== nuid,
);
log.DEBUG(existingSystem);
await updateSystemByName(existingSystem.name, existingSystem);
}
}
}
// Add and update the given systems
for (const nearbySystem in nearbySystems) {
// Check if the system exists already on another node
const existingSystem = await getSystemByName(nearbySystem);
if (existingSystem) {
// Verify the frequencies match (to make sure the name isn't just the same)
if (JSON.stringify(existingSystem.frequencies) === JSON.stringify(nearbySystems[nearbySystem].frequencies)) {
// The systems are the same
// Add and update the given systems
for (const nearbySystem in nearbySystems) {
// Check if the system exists already on another node
const existingSystem = await getSystemByName(nearbySystem);
if (existingSystem) {
// Verify the frequencies match (to make sure the name isn't just the same)
if (
JSON.stringify(existingSystem.frequencies) ===
JSON.stringify(nearbySystems[nearbySystem].frequencies)
) {
// The systems are the same
// Check if the current node is listed in the nodes, if not add it
if (!existingSystem.nodes.includes(nuid)) {
existingSystem.nodes.push(nuid);
// Update the system with the added node
const updateResults = await updateSystemByName(nearbySystem, existingSystem);
if (updateResults) log.INFO("System updated", nearbySystem);
}
} 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);
nearbySystems[nearbySystem].nodes = existingSystem.nodes;
}
// Update the system with the added node
const updateResults = await updateSystemByName(nearbySystem, nearbySystems[nearbySystem]);
if (updateResults) log.INFO("System updated", nearbySystem);
}
// Check if the current node is listed in the nodes, if not add it
if (!existingSystem.nodes.includes(nuid)) {
existingSystem.nodes.push(nuid);
// Update the system with the added node
const updateResults = await updateSystemByName(
nearbySystem,
existingSystem,
);
if (updateResults) log.INFO("System updated", nearbySystem);
}
else {
// Create a new system
const newSystem = await createSystem(nearbySystem, nearbySystems[nearbySystem], nuid);
log.INFO("New system created", nearbySystem, newSystem);
} 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);
nearbySystems[nearbySystem].nodes = existingSystem.nodes;
}
// Update the system with the added node
const updateResults = await updateSystemByName(
nearbySystem,
nearbySystems[nearbySystem],
);
if (updateResults) log.INFO("System updated", nearbySystem);
}
} else {
// Create a new system
const newSystem = await createSystem(
nearbySystem,
nearbySystems[nearbySystem],
nuid,
);
log.INFO("New system created", nearbySystem, newSystem);
}
return;
}
}
return;
};
/**
* Get the open socket connection ID for a node from the NUID
* Get the open socket connection ID for a node from the NUID
* @param {string} nuid The NUID to find within the open sockets
* @returns {string|null} Will return the open socket ID or NULL
*/
export const getSocketIdByNuid = async (nodeIo, nuid) => {
const openSockets = await nodeIo.allSockets();
for (const openSocketId of openSockets) {
log.DEBUG(openSockets)
const openSocket = await nodeIo.sockets.sockets.get(openSocketId);
if (openSocket.node.nuid == nuid)
return openSocket;
}
return null;
}
const openSockets = await nodeIo.allSockets();
for (const openSocketId of openSockets) {
log.DEBUG(openSockets);
const openSocket = await nodeIo.sockets.sockets.get(openSocketId);
if (openSocket.node.nuid == nuid) return openSocket;
}
return null;
};
/**
* Get all nodes that are connected to a voice channel
@@ -162,29 +186,34 @@ export const getSocketIdByNuid = async (nodeIo, nuid) => {
* @returns {Array} The sockets connected to VC in a given server
*/
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) {
log.INFO("Socket is connected to VC:", openSocket.node.name, status);
socketsConnectedToVC.push(openSocket);
} else {
log.INFO("Socket is NOT connected to VC:", openSocket.node.name);
}
res();
})
// 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) {
log.INFO(
"Socket is connected to VC:",
openSocket.node.name,
status,
);
socketsConnectedToVC.push(openSocket);
} else {
log.INFO("Socket is NOT connected to VC:", openSocket.node.name);
}
res();
});
}));
return socketsConnectedToVC;
}
});
}),
);
return socketsConnectedToVC;
};
/**
* Check if the given node has an open discord client
@@ -192,45 +221,65 @@ export const getAllSocketsConnectedToVC = async (nodeIo, guildId) => {
* @returns {boolean} If the given node has an open discord client or not
*/
export const checkIfNodeHasOpenDiscordClient = async (openSocket) => {
// Check the open socket to see if the node has an open discord client
let hasOpenDiscordClient = false;
await new Promise((res) => {
log.INFO("Checking if socket has an open connection:", openSocket.node.name)
openSocket.emit('node-check-discord-open-client', (status) => {
if (status) {
log.INFO("Socket has an open discord client:", openSocket.node.name, status);
hasOpenDiscordClient = true;
} else {
log.INFO("Socket does NOT have an open discord client:", openSocket.node.name);
}
res();
})
// Check the open socket to see if the node has an open discord client
let hasOpenDiscordClient = false;
await new Promise((res) => {
log.INFO(
"Checking if socket has an open connection:",
openSocket.node.name,
);
openSocket.emit("node-check-discord-open-client", (status) => {
if (status) {
log.INFO(
"Socket has an open discord client:",
openSocket.node.name,
status,
);
hasOpenDiscordClient = true;
} else {
log.INFO(
"Socket does NOT have an open discord client:",
openSocket.node.name,
);
}
res();
});
});
return hasOpenDiscordClient;
}
return hasOpenDiscordClient;
};
export const getNodeCurrentListeningSystem = async (openSocket) => {
const hasOpenClient = checkIfNodeHasOpenDiscordClient(openSocket);
if (!hasOpenClient) return undefined;
const hasOpenClient = checkIfNodeHasOpenDiscordClient(openSocket);
if (!hasOpenClient) return undefined;
// check what system the socket is listening to
let currentSystem = undefined;
await new Promise((res) => {
log.INFO("Checking system node is currently listening to:", openSocket.node.name)
openSocket.emit('node-check-current-system', (system) => {
if (system) {
log.INFO("Socket is listening to system:", openSocket.node.name, system);
currentSystem = system;
} else {
log.INFO("Socket is not currently listening to a system:", openSocket.node.name);
}
res();
})
// check what system the socket is listening to
let currentSystem = undefined;
await new Promise((res) => {
log.INFO(
"Checking system node is currently listening to:",
openSocket.node.name,
);
openSocket.emit("node-check-current-system", (system) => {
if (system) {
log.INFO(
"Socket is listening to system:",
openSocket.node.name,
system,
);
currentSystem = system;
} else {
log.INFO(
"Socket is not currently listening to a system:",
openSocket.node.name,
);
}
res();
});
});
return currentSystem;
}
return currentSystem;
};
/**
* Wrapper to check if the given NUID is connected to a VC
@@ -239,14 +288,17 @@ export const getNodeCurrentListeningSystem = async (openSocket) => {
* @returns {boolean} If the node is connected to VC in the given server
*/
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;
}
const socketsConnectedToVC = await getAllSocketsConnectedToVC(
nodeIo,
guildId,
);
for (const socket of socketsConnectedToVC) {
if (socket.node.nuid === nuid) {
return true;
}
return false;
}
}
return false;
};
/**
* Get the discord username from a given socket
@@ -255,12 +307,12 @@ export const checkIfNodeIsConnectedToVC = async (nodeIo, guildId, nuid) => {
* @returns {string} The username of the bot in the requested server
*/
export const getNodeDiscordUsername = async (socket, guildId) => {
return await new Promise((res) => {
socket.emit('node-get-discord-username', guildId, (username) => {
res(username);
});
return await new Promise((res) => {
socket.emit("node-get-discord-username", guildId, (username) => {
res(username);
});
}
});
};
/**
* Get the discord ID from a given socket
@@ -268,12 +320,12 @@ export const getNodeDiscordUsername = async (socket, guildId) => {
* @returns {string} The ID of the bot
*/
export const getNodeDiscordID = async (socket) => {
return await new Promise((res) => {
socket.emit('node-get-discord-id', (discordID) => {
res(discordID);
});
return await new Promise((res) => {
socket.emit("node-get-discord-id", (discordID) => {
res(discordID);
});
}
});
};
/**
* Request a given socket node to join a given voice channel
@@ -281,16 +333,21 @@ export const getNodeDiscordID = async (socket) => {
* @param {any} systemName The system preset name that we would like to listen to
* @param {string} discordChanelId The Discord channel ID to join the listening bot to
*/
export const requestNodeJoinSystem = async (socket, systemName, discordChanelId, discordToken = "MTE5NjAwNTM2ODYzNjExMjk3Nw.GuCMXg.24iNNofNNumq46FIj68zMe9RmQgugAgfrvelEA") => {
// Join the system
const joinData = {
'clientID': discordToken,
'channelID': discordChanelId,
'system': systemName
}
// Send the command to the node
await sendNodeCommand(socket, "node-join", joinData);
}
export const requestNodeJoinSystem = async (
socket,
systemName,
discordChanelId,
discordToken = "MTE5NjAwNTM2ODYzNjExMjk3Nw.GuCMXg.24iNNofNNumq46FIj68zMe9RmQgugAgfrvelEA",
) => {
// Join the system
const joinData = {
clientID: discordToken,
channelID: discordChanelId,
system: systemName,
};
// Send the command to the node
await sendNodeCommand(socket, "node-join", joinData);
};
/**
* Request a given socket node to leave VC in a given server
@@ -298,21 +355,20 @@ export const requestNodeJoinSystem = async (socket, systemName, discordChanelId,
* @param {string} guildId The guild ID to disconnect the socket node from
*/
export const requestBotLeaveServer = async (socket, guildId) => {
// Send the command to the node
await sendNodeCommand(socket, "node-leave", guildId);
}
// Send the command to the node
await sendNodeCommand(socket, "node-leave", guildId);
};
/**
* Requset a given socket node to update themselves
* @param {any} socket The socket object of the node to request to update
*/
export const requestNodeUpdate = async (socket) => {
await sendNodeCommand(socket, 'node-update', (status) => {
if (status) {
log.INFO("Node is out of date, updating now", socket.node.name);
} else {
log.INFO("Node is up to date", socket.node.name);
}
});
}
await sendNodeCommand(socket, "node-update", (status) => {
if (status) {
log.INFO("Node is out of date, updating now", socket.node.name);
} else {
log.INFO("Node is up to date", socket.node.name);
}
});
};