Linting
This commit is contained in:
@@ -4,16 +4,19 @@ const log = new DebugBuilder("server", "server");
|
||||
|
||||
// Function called by the main application to initialize the addon
|
||||
export function initialize(nodeIo, config) {
|
||||
log.INFO(`Initializing ${config.name}`);
|
||||
|
||||
// Call other functions within the addon module
|
||||
registerSocketEvents(nodeIo, config);
|
||||
// Call additional initialization functions if needed
|
||||
log.INFO(`Initializing ${config.name}`);
|
||||
|
||||
// Call other functions within the addon module
|
||||
registerSocketEvents(nodeIo, config);
|
||||
// Call additional initialization functions if needed
|
||||
}
|
||||
|
||||
// Function to register Socket.IO event handlers
|
||||
function registerSocketEvents(nodeIo, config) {
|
||||
nodeIo.on(config.options.eventName, (data) => {
|
||||
log.DEBUG(`Received event "${config.options.eventName}" from client:`, data);
|
||||
});
|
||||
nodeIo.on(config.options.eventName, (data) => {
|
||||
log.DEBUG(
|
||||
`Received event "${config.options.eventName}" from client:`,
|
||||
data,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,51 +3,55 @@ const log = new DebugBuilder("server", "discordBot.addons.gptInteraction");
|
||||
import { gptHandler } from "../modules/gptHandler.mjs";
|
||||
|
||||
export const gptInteraction = async (nodeIo, message) => {
|
||||
let conversation = [];
|
||||
let conversation = [];
|
||||
|
||||
let prevMessages = await message.channel.messages.fetch({ limit: 10 });
|
||||
prevMessages.reverse();
|
||||
let prevMessages = await message.channel.messages.fetch({ limit: 10 });
|
||||
prevMessages.reverse();
|
||||
|
||||
prevMessages.forEach((msg) => {
|
||||
// Check if the message was sent within the last 24 hours
|
||||
if (new Date().getTime() - msg.createdTimestamp > (24 * 60 * 60 * 1000)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if it's from a bot other than the server
|
||||
if (msg.author.bot && msg.author.id !== nodeIo.serverClient.user.id) return;
|
||||
|
||||
const username = msg.author.username.replace(/\s+/g, '_').replace(/[^\w\s]/gi, '');
|
||||
|
||||
if (msg.author.id === nodeIo.serverClient.user.id) {
|
||||
conversation.push({
|
||||
role: 'assistant',
|
||||
//name: msg.author.id,
|
||||
content: msg.content,
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
conversation.push({
|
||||
role: 'user',
|
||||
//name: msg.author.id,
|
||||
content: msg.content.replace(`<@${nodeIo.serverClient.user.id}>`, ''),
|
||||
});
|
||||
});
|
||||
const response = await gptHandler(conversation);
|
||||
if (response) {
|
||||
const responseMessage = response;
|
||||
const chunkSize = 2500;
|
||||
|
||||
for (let i = 0; i < responseMessage.length; i += chunkSize) {
|
||||
const chunk = responseMessage.substring(i, i + chunkSize);
|
||||
|
||||
log.DEBUG("Sending message chunk:", chunk);
|
||||
|
||||
await message.reply(chunk);
|
||||
}
|
||||
} else {
|
||||
message.channel.send('Sorry, I encountered an error while processing your request.');
|
||||
prevMessages.forEach((msg) => {
|
||||
// Check if the message was sent within the last 24 hours
|
||||
if (new Date().getTime() - msg.createdTimestamp > 24 * 60 * 60 * 1000) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if it's from a bot other than the server
|
||||
if (msg.author.bot && msg.author.id !== nodeIo.serverClient.user.id) return;
|
||||
|
||||
const username = msg.author.username
|
||||
.replace(/\s+/g, "_")
|
||||
.replace(/[^\w\s]/gi, "");
|
||||
|
||||
if (msg.author.id === nodeIo.serverClient.user.id) {
|
||||
conversation.push({
|
||||
role: "assistant",
|
||||
//name: msg.author.id,
|
||||
content: msg.content,
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
conversation.push({
|
||||
role: "user",
|
||||
//name: msg.author.id,
|
||||
content: msg.content.replace(`<@${nodeIo.serverClient.user.id}>`, ""),
|
||||
});
|
||||
});
|
||||
const response = await gptHandler(conversation);
|
||||
if (response) {
|
||||
const responseMessage = response;
|
||||
const chunkSize = 2500;
|
||||
|
||||
for (let i = 0; i < responseMessage.length; i += chunkSize) {
|
||||
const chunk = responseMessage.substring(i, i + chunkSize);
|
||||
|
||||
log.DEBUG("Sending message chunk:", chunk);
|
||||
|
||||
await message.reply(chunk);
|
||||
}
|
||||
} else {
|
||||
message.channel.send(
|
||||
"Sorry, I encountered an error while processing your request.",
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,83 +1,93 @@
|
||||
import { DebugBuilder } from "../../modules/debugger.mjs";
|
||||
const log = new DebugBuilder("server", "discordBot.addons.linkCop");
|
||||
import { gptHandler } from "../modules/gptHandler.mjs";
|
||||
import dotenv from 'dotenv';
|
||||
import dotenv from "dotenv";
|
||||
dotenv.config();
|
||||
|
||||
const approvedLinksChannel = "767303243285790721";
|
||||
const restrictedChannelIds = process.env.LINKCOP_RESTRICTED_CHANNEL_IDS.split(',');
|
||||
const restrictedChannelIds =
|
||||
process.env.LINKCOP_RESTRICTED_CHANNEL_IDS.split(",");
|
||||
|
||||
const linkRegExp = /(?:http[s]?:\/\/)?(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&\/=]*)/g
|
||||
const linkRegExp =
|
||||
/(?:http[s]?:\/\/)?(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&\/=]*)/g;
|
||||
|
||||
export const linkCop = async (nodeIo, message) => {
|
||||
if (message.channel.id == approvedLinksChannel || !restrictedChannelIds.includes(message.channel.id)) return false;
|
||||
if (
|
||||
message.channel.id == approvedLinksChannel ||
|
||||
!restrictedChannelIds.includes(message.channel.id)
|
||||
)
|
||||
return false;
|
||||
|
||||
const urls = String(message.content).matchAll(linkRegExp);
|
||||
if (!urls || urls.length === 0) return false;
|
||||
log.DEBUG("Found URLs: ", urls);
|
||||
const urls = String(message.content).matchAll(linkRegExp);
|
||||
if (!urls || urls.length === 0) return false;
|
||||
log.DEBUG("Found URLs: ", urls);
|
||||
|
||||
let conversation = [];
|
||||
let conversation = [];
|
||||
|
||||
let prevMessages = await message.channel.messages.fetch({ limit: 2 });
|
||||
prevMessages.reverse();
|
||||
let prevMessages = await message.channel.messages.fetch({ limit: 2 });
|
||||
prevMessages.reverse();
|
||||
|
||||
prevMessages.forEach((msg) => {
|
||||
// Check if the message was sent within the last 5 minutes
|
||||
if (new Date().getTime() - msg.createdTimestamp > (5 * 60 * 1000)) {
|
||||
return;
|
||||
}
|
||||
prevMessages.forEach((msg) => {
|
||||
// Check if the message was sent within the last 5 minutes
|
||||
if (new Date().getTime() - msg.createdTimestamp > 5 * 60 * 1000) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if it's from a bot other than the server
|
||||
if (msg.author.bot && msg.author.id !== nodeIo.serverClient.user.id) return;
|
||||
// Check if it's from a bot other than the server
|
||||
if (msg.author.bot && msg.author.id !== nodeIo.serverClient.user.id) return;
|
||||
|
||||
const username = msg.author.username.replace(/\s+/g, '_').replace(/[^\w\s]/gi, '');
|
||||
const username = msg.author.username
|
||||
.replace(/\s+/g, "_")
|
||||
.replace(/[^\w\s]/gi, "");
|
||||
|
||||
if (msg.author.id === nodeIo.serverClient.user.id) {
|
||||
conversation.push({
|
||||
role: 'assistant',
|
||||
//name: msg.author.id,
|
||||
content: msg.content,
|
||||
});
|
||||
if (msg.author.id === nodeIo.serverClient.user.id) {
|
||||
conversation.push({
|
||||
role: "assistant",
|
||||
//name: msg.author.id,
|
||||
content: msg.content,
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
conversation.push({
|
||||
role: 'user',
|
||||
//name: msg.author.id,
|
||||
content: msg.content.replace(`<@${nodeIo.serverClient.user.id}>`, ''),
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
conversation.push({
|
||||
role: 'assistant',
|
||||
content: `There has been a link posted to a channel that links are not allowed in. The above messages are from the channel that links are not allowed including the message with the link. The message with the link is going to be deleted and moved to the '#links' channels. You are replying to the message with the link to let the user know.`
|
||||
role: "user",
|
||||
//name: msg.author.id,
|
||||
content: msg.content.replace(`<@${nodeIo.serverClient.user.id}>`, ""),
|
||||
});
|
||||
});
|
||||
|
||||
const response = await gptHandler(conversation);
|
||||
conversation.push({
|
||||
role: "assistant",
|
||||
content: `There has been a link posted to a channel that links are not allowed in. The above messages are from the channel that links are not allowed including the message with the link. The message with the link is going to be deleted and moved to the '#links' channels. You are replying to the message with the link to let the user know.`,
|
||||
});
|
||||
|
||||
if (response) {
|
||||
const responseMessage = response;
|
||||
const chunkSize = 2000;
|
||||
const response = await gptHandler(conversation);
|
||||
|
||||
for (let i = 0; i < responseMessage.length; i += chunkSize) {
|
||||
const chunk = responseMessage.substring(i, i + chunkSize);
|
||||
if (response) {
|
||||
const responseMessage = response;
|
||||
const chunkSize = 2000;
|
||||
|
||||
log.DEBUG("Sending message chunk:", chunk);
|
||||
for (let i = 0; i < responseMessage.length; i += chunkSize) {
|
||||
const chunk = responseMessage.substring(i, i + chunkSize);
|
||||
|
||||
await message.reply(chunk);
|
||||
}
|
||||
log.DEBUG("Sending message chunk:", chunk);
|
||||
|
||||
const messageContent = {
|
||||
'author': message.author,
|
||||
'content': `<@${message.author.id}> - ${String(message.content)}`,
|
||||
'channelId': message.channelId,
|
||||
'links': urls
|
||||
}
|
||||
|
||||
await message.delete();
|
||||
log.DEBUG("Message content: ", messageContent);
|
||||
|
||||
message.client.channels.cache.get(approvedLinksChannel).send(messageContent);
|
||||
}
|
||||
}
|
||||
await message.reply(chunk);
|
||||
}
|
||||
|
||||
const messageContent = {
|
||||
author: message.author,
|
||||
content: `<@${message.author.id}> - ${String(message.content)}`,
|
||||
channelId: message.channelId,
|
||||
links: urls,
|
||||
};
|
||||
|
||||
await message.delete();
|
||||
log.DEBUG("Message content: ", messageContent);
|
||||
|
||||
message.client.channels.cache
|
||||
.get(approvedLinksChannel)
|
||||
.send(messageContent);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { DebugBuilder } from "../../modules/debugger.mjs";
|
||||
const log = new DebugBuilder("server", "discordBot.command.ping");
|
||||
import { SlashCommandBuilder } from 'discord.js';
|
||||
import { SlashCommandBuilder } from "discord.js";
|
||||
|
||||
// Exporting data property that contains the command structure for discord including any params
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('connections')
|
||||
.setDescription('Check to see what bots are online.');
|
||||
.setName("connections")
|
||||
.setDescription("Check to see what bots are online.");
|
||||
|
||||
// Exporting other properties
|
||||
export const example = "/connections"; // An example of how the command would be run in discord chat, this will be used for the help command
|
||||
@@ -33,20 +33,20 @@ export async function autocomplete(nodeIo, interaction) {
|
||||
*/
|
||||
export const execute = async (nodeIo, interaction) => {
|
||||
try {
|
||||
const sockets = await nodeIo.allSockets();
|
||||
log.DEBUG("All open sockets: ",sockets);
|
||||
let socketMessage = "";
|
||||
|
||||
// Create the message for discord with each socket on a new line
|
||||
sockets.forEach(socket => {
|
||||
socketMessage += `\n${socket}`
|
||||
});
|
||||
const sockets = await nodeIo.allSockets();
|
||||
log.DEBUG("All open sockets: ", sockets);
|
||||
let socketMessage = "";
|
||||
|
||||
await interaction.reply(`**Online Sockets: '${socketMessage}'**`);
|
||||
//await interaction.reply('**Pong.**');
|
||||
//await interaction.channel.send('**Pong.**');
|
||||
// Create the message for discord with each socket on a new line
|
||||
sockets.forEach((socket) => {
|
||||
socketMessage += `\n${socket}`;
|
||||
});
|
||||
|
||||
await interaction.reply(`**Online Sockets: '${socketMessage}'**`);
|
||||
//await interaction.reply('**Pong.**');
|
||||
//await interaction.channel.send('**Pong.**');
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
// await interaction.reply(err.toString());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,19 +1,28 @@
|
||||
import { DebugBuilder } from "../../modules/debugger.mjs";
|
||||
import { SlashCommandBuilder } from 'discord.js';
|
||||
import { joinNode, getAvailableNodes, promptNodeSelection, getUserVoiceChannel } from '../modules/wrappers.mjs';
|
||||
import { getAllSystems, getSystemByName } from '../../modules/mongo-wrappers/mongoSystemsWrappers.mjs';
|
||||
import { SlashCommandBuilder } from "discord.js";
|
||||
import {
|
||||
joinNode,
|
||||
getAvailableNodes,
|
||||
promptNodeSelection,
|
||||
getUserVoiceChannel,
|
||||
} from "../modules/wrappers.mjs";
|
||||
import {
|
||||
getAllSystems,
|
||||
getSystemByName,
|
||||
} from "../../modules/mongo-wrappers/mongoSystemsWrappers.mjs";
|
||||
|
||||
const log = new DebugBuilder("server", "discordBot.command.join");
|
||||
|
||||
// Exporting data property
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('join')
|
||||
.setDescription('Listen to the selected radio system in your channel')
|
||||
.addStringOption(system =>
|
||||
system.setName('system')
|
||||
.setDescription('The radio system you would like to listen to')
|
||||
.setName("join")
|
||||
.setDescription("Listen to the selected radio system in your channel")
|
||||
.addStringOption((system) =>
|
||||
system
|
||||
.setName("system")
|
||||
.setDescription("The radio system you would like to listen to")
|
||||
.setRequired(true)
|
||||
.setAutocomplete(true)
|
||||
.setAutocomplete(true),
|
||||
);
|
||||
|
||||
// Exporting other properties
|
||||
@@ -28,16 +37,17 @@ export const deferInitialReply = true;
|
||||
export async function autocomplete(nodeIo, interaction) {
|
||||
const focusedValue = interaction.options.getFocused();
|
||||
const choices = await getAllSystems();
|
||||
const filtered = choices.filter(choice => choice.name.startsWith(focusedValue));
|
||||
const filtered = choices.filter((choice) =>
|
||||
choice.name.startsWith(focusedValue),
|
||||
);
|
||||
|
||||
log.DEBUG(focusedValue, choices, filtered);
|
||||
|
||||
try {
|
||||
await interaction.respond(
|
||||
filtered.map(choice => ({ name: choice.name, value: choice.name }))
|
||||
filtered.map((choice) => ({ name: choice.name, value: choice.name })),
|
||||
);
|
||||
}
|
||||
catch (e) {
|
||||
} catch (e) {
|
||||
log.WARN("Autocomplete interaction failure", e);
|
||||
}
|
||||
}
|
||||
@@ -54,40 +64,66 @@ export async function execute(nodeIo, interaction) {
|
||||
if (!channelToJoin) return;
|
||||
|
||||
// Get the selected system
|
||||
const selectedSystemName = interaction.options.getString('system');
|
||||
const selectedSystemName = interaction.options.getString("system");
|
||||
const system = await getSystemByName(selectedSystemName);
|
||||
|
||||
// Check if there was a system found by the given system name
|
||||
if (!system) {
|
||||
await interaction.editReply({ content: `System '${selectedSystemName}' not found.`, ephemeral: true });
|
||||
await interaction.editReply({
|
||||
content: `System '${selectedSystemName}' not found.`,
|
||||
ephemeral: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the available nodes for this system
|
||||
const availableNodes = await getAvailableNodes(nodeIo, interaction.guild.id, system);
|
||||
const availableNodes = await getAvailableNodes(
|
||||
nodeIo,
|
||||
interaction.guild.id,
|
||||
system,
|
||||
);
|
||||
|
||||
// Check if there are available nodes
|
||||
if (availableNodes.length === 0) {
|
||||
// If not, let the user know
|
||||
await interaction.editReply(`<@${interaction.member.id}>, the selected system has no available nodes`);
|
||||
await interaction.editReply(
|
||||
`<@${interaction.member.id}>, the selected system has no available nodes`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// If there is one available node, request that node join
|
||||
if (availableNodes.length === 1) {
|
||||
await joinNode(nodeIo, interaction, availableNodes[0].id, system, channelToJoin);
|
||||
await joinNode(
|
||||
nodeIo,
|
||||
interaction,
|
||||
availableNodes[0].id,
|
||||
system,
|
||||
channelToJoin,
|
||||
);
|
||||
}
|
||||
|
||||
// If there are more than one available, prompt the user for their selected node
|
||||
else {
|
||||
await promptNodeSelection(interaction, availableNodes, async selectedNode => {
|
||||
await joinNode(nodeIo, interaction, selectedNode, system, channelToJoin);
|
||||
});
|
||||
await promptNodeSelection(
|
||||
interaction,
|
||||
availableNodes,
|
||||
async (selectedNode) => {
|
||||
await joinNode(
|
||||
nodeIo,
|
||||
interaction,
|
||||
selectedNode,
|
||||
system,
|
||||
channelToJoin,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
catch (err) {
|
||||
} catch (err) {
|
||||
log.ERROR(err);
|
||||
await interaction.editReply({ content: `An error occurred: ${err.message}`, ephemeral: true });
|
||||
await interaction.editReply({
|
||||
content: `An error occurred: ${err.message}`,
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
import { DebugBuilder } from "../../modules/debugger.mjs";
|
||||
import { SlashCommandBuilder } from 'discord.js';
|
||||
import { requestBotLeaveServer, getSocketIdByNuid } from '../../modules/socketServerWrappers.mjs';
|
||||
import { checkOnlineBotsInGuild } from '../modules/wrappers.mjs';
|
||||
import { SlashCommandBuilder } from "discord.js";
|
||||
import {
|
||||
requestBotLeaveServer,
|
||||
getSocketIdByNuid,
|
||||
} from "../../modules/socketServerWrappers.mjs";
|
||||
import { checkOnlineBotsInGuild } from "../modules/wrappers.mjs";
|
||||
|
||||
const log = new DebugBuilder("server", "discordBot.command.leave");
|
||||
|
||||
// Exporting data property
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('leave')
|
||||
.setDescription('Disconnect a bot from the server')
|
||||
.addStringOption(system =>
|
||||
system.setName('bot')
|
||||
.setDescription('The bot you would like to disconnect')
|
||||
.setName("leave")
|
||||
.setDescription("Disconnect a bot from the server")
|
||||
.addStringOption((system) =>
|
||||
system
|
||||
.setName("bot")
|
||||
.setDescription("The bot you would like to disconnect")
|
||||
.setRequired(true)
|
||||
.setAutocomplete(true)
|
||||
.setAutocomplete(true),
|
||||
);
|
||||
|
||||
// Exporting other properties
|
||||
@@ -32,15 +36,14 @@ export async function autocomplete(nodeIo, interaction) {
|
||||
log.DEBUG(choices);
|
||||
|
||||
const filtered = choices
|
||||
.filter(choice => choice.name.startsWith(focusedValue))
|
||||
.map(choice => ({ name: choice.name, value: choice.nuid }));
|
||||
.filter((choice) => choice.name.startsWith(focusedValue))
|
||||
.map((choice) => ({ name: choice.name, value: choice.nuid }));
|
||||
|
||||
log.DEBUG(focusedValue, choices, filtered);
|
||||
|
||||
try{
|
||||
try {
|
||||
await interaction.respond(filtered);
|
||||
}
|
||||
catch (e) {
|
||||
} catch (e) {
|
||||
log.WARN("Autocomplete interaction failure", e);
|
||||
}
|
||||
}
|
||||
@@ -52,19 +55,27 @@ export async function autocomplete(nodeIo, interaction) {
|
||||
*/
|
||||
export async function execute(nodeIo, interaction) {
|
||||
try {
|
||||
const selectedNode = interaction.options.getString('bot');
|
||||
const selectedNode = interaction.options.getString("bot");
|
||||
const socket = await getSocketIdByNuid(nodeIo, selectedNode);
|
||||
|
||||
if (!socket) {
|
||||
await interaction.editReply({ content: `Bot '${selectedNode}' not found or not connected.`, ephemeral: true });
|
||||
await interaction.editReply({
|
||||
content: `Bot '${selectedNode}' not found or not connected.`,
|
||||
ephemeral: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await requestBotLeaveServer(socket, interaction.guild.id);
|
||||
|
||||
await interaction.editReply(`Ok <@${interaction.member.id}>, the bot is leaving shortly.`);
|
||||
await interaction.editReply(
|
||||
`Ok <@${interaction.member.id}>, the bot is leaving shortly.`,
|
||||
);
|
||||
} catch (err) {
|
||||
log.ERROR("Failed to disconnect bot:", err);
|
||||
await interaction.editReply({ content: `An error occurred: ${err.message}`, ephemeral: true });
|
||||
await interaction.editReply({
|
||||
content: `An error occurred: ${err.message}`,
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { DebugBuilder } from "../../modules/debugger.mjs";
|
||||
const log = new DebugBuilder("server", "discordBot.command.ping");
|
||||
import { SlashCommandBuilder } from 'discord.js';
|
||||
import { SlashCommandBuilder } from "discord.js";
|
||||
|
||||
// Exporting data property that contains the command structure for discord including any params
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('ping')
|
||||
.setDescription('Replies with your input!');
|
||||
.setName("ping")
|
||||
.setDescription("Replies with your input!");
|
||||
|
||||
// Exporting other properties
|
||||
export const example = "/ping"; // An example of how the command would be run in discord chat, this will be used for the help command
|
||||
@@ -33,13 +33,13 @@ export async function autocomplete(nodeIo, interaction) {
|
||||
*/
|
||||
export const execute = async (nodeIo, interaction) => {
|
||||
try {
|
||||
const sockets = await nodeIo.allSockets();
|
||||
log.DEBUG("All open sockets: ",sockets);
|
||||
//await interaction.reply(`**Online Sockets: '${sockets}'**`);
|
||||
await interaction.reply('**Pong.**');
|
||||
//await interaction.channel.send('**Pong.**');
|
||||
const sockets = await nodeIo.allSockets();
|
||||
log.DEBUG("All open sockets: ", sockets);
|
||||
//await interaction.reply(`**Online Sockets: '${sockets}'**`);
|
||||
await interaction.reply("**Pong.**");
|
||||
//await interaction.channel.send('**Pong.**');
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
// await interaction.reply(err.toString());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,28 +1,34 @@
|
||||
|
||||
import { SlashCommandBuilder } from 'discord.js';
|
||||
import { SlashCommandBuilder } from "discord.js";
|
||||
import { DebugBuilder } from "../../modules/debugger.mjs";
|
||||
import { addSource } from '../../rss-manager/sourceManager.mjs'
|
||||
import { addSource } from "../../rss-manager/sourceManager.mjs";
|
||||
const log = new DebugBuilder("server", "discordBot.command.rssAdd");
|
||||
|
||||
// Exporting data property that contains the command structure for discord including any params
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('rss-add')
|
||||
.setDescription('Add RSS Source')
|
||||
.addStringOption(option =>
|
||||
option.setName('title')
|
||||
.setDescription('The title of the RSS feed')
|
||||
.setRequired(true))
|
||||
.addStringOption(option =>
|
||||
option.setName('link')
|
||||
.setDescription('The link to the RSS feed')
|
||||
.setRequired(true))
|
||||
.addStringOption(option =>
|
||||
option.setName('category')
|
||||
.setName("rss-add")
|
||||
.setDescription("Add RSS Source")
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName("title")
|
||||
.setDescription("The title of the RSS feed")
|
||||
.setRequired(true),
|
||||
)
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName("link")
|
||||
.setDescription("The link to the RSS feed")
|
||||
.setRequired(true),
|
||||
)
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName("category")
|
||||
.setDescription('The category for the RSS feed *("ALL" by default")*')
|
||||
.setRequired(false))
|
||||
.setRequired(false),
|
||||
);
|
||||
|
||||
// Exporting other properties
|
||||
export const example = "/rss-add [title] [https://domain.com/feed.xml] [category]"; // An example of how the command would be run in discord chat, this will be used for the help command
|
||||
export const example =
|
||||
"/rss-add [title] [https://domain.com/feed.xml] [category]"; // An example of how the command would be run in discord chat, this will be used for the help command
|
||||
export const deferInitialReply = false; // If we the initial reply in discord should be deferred. This gives extra time to respond, however the method of replying is different.
|
||||
|
||||
/**
|
||||
@@ -49,24 +55,37 @@ export async function autocomplete(nodeIo, interaction) {
|
||||
*/
|
||||
export const execute = async (nodeIo, interaction) => {
|
||||
try {
|
||||
var title = interaction.options.getString('title');
|
||||
var link = interaction.options.getString('link');
|
||||
var category = interaction.options.getString('category');
|
||||
var title = interaction.options.getString("title");
|
||||
var link = interaction.options.getString("link");
|
||||
var category = interaction.options.getString("category");
|
||||
|
||||
if (!category) category = "ALL";
|
||||
await interaction.reply(`Adding ${title} to the list of RSS sources, please wait...`);
|
||||
await interaction.reply(
|
||||
`Adding ${title} to the list of RSS sources, please wait...`,
|
||||
);
|
||||
|
||||
await addSource(title, link, category, interaction.guildId, interaction.channelId, (err, result) => {
|
||||
log.DEBUG("Result from adding entry", result);
|
||||
await addSource(
|
||||
title,
|
||||
link,
|
||||
category,
|
||||
interaction.guildId,
|
||||
interaction.channelId,
|
||||
(err, result) => {
|
||||
log.DEBUG("Result from adding entry", result);
|
||||
|
||||
if (result) {
|
||||
interaction.editReply(`Successfully added ${title} to the list of RSS sources`);
|
||||
} else {
|
||||
interaction.editReply(`${title} already exists in the list of RSS sources`);
|
||||
}
|
||||
});
|
||||
if (result) {
|
||||
interaction.editReply(
|
||||
`Successfully added ${title} to the list of RSS sources`,
|
||||
);
|
||||
} else {
|
||||
interaction.editReply(
|
||||
`${title} already exists in the list of RSS sources`,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
} catch (err) {
|
||||
log.ERROR(err)
|
||||
log.ERROR(err);
|
||||
await interaction.editReply(err.toString());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
|
||||
import { SlashCommandBuilder } from 'discord.js';
|
||||
import { SlashCommandBuilder } from "discord.js";
|
||||
import { DebugBuilder } from "../../modules/debugger.mjs";
|
||||
import { removeSource } from '../../rss-manager/sourceManager.mjs'
|
||||
import { getAllFeeds, deleteFeedByTitle } from '../../modules/mongo-wrappers/mongoFeedsWrappers.mjs'
|
||||
import { removeSource } from "../../rss-manager/sourceManager.mjs";
|
||||
import {
|
||||
getAllFeeds,
|
||||
deleteFeedByTitle,
|
||||
} from "../../modules/mongo-wrappers/mongoFeedsWrappers.mjs";
|
||||
const log = new DebugBuilder("server", "discordBot.command.rssRemove");
|
||||
|
||||
// Exporting data property that contains the command structure for discord including any params
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('rss-remove')
|
||||
.setDescription('Add RSS Source')
|
||||
.addStringOption(option =>
|
||||
option.setName('title')
|
||||
.setDescription('The title of the RSS feed')
|
||||
.setName("rss-remove")
|
||||
.setDescription("Add RSS Source")
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName("title")
|
||||
.setDescription("The title of the RSS feed")
|
||||
.setRequired(true)
|
||||
.setAutocomplete(true))
|
||||
.setAutocomplete(true),
|
||||
);
|
||||
|
||||
// Exporting other properties
|
||||
export const example = "/rss-remove [title]"; // An example of how the command would be run in discord chat, this will be used for the help command
|
||||
@@ -27,11 +31,15 @@ export const deferInitialReply = false; // If we the initial reply in discord sh
|
||||
|
||||
export async function autocomplete(nodeIo, interaction) {
|
||||
const focusedValue = interaction.options.getFocused();
|
||||
const choices = await getAllFeeds() ?? [];
|
||||
const choices = (await getAllFeeds()) ?? [];
|
||||
log.INFO("RSS Remove Choices:", choices);
|
||||
const filtered = choices.filter(choice => choice.title.startsWith(focusedValue));
|
||||
const filtered = choices.filter((choice) =>
|
||||
choice.title.startsWith(focusedValue),
|
||||
);
|
||||
log.DEBUG(focusedValue, choices, filtered);
|
||||
await interaction.respond(filtered.map(choice => ({ name: choice.title, value: choice.title })));
|
||||
await interaction.respond(
|
||||
filtered.map((choice) => ({ name: choice.title, value: choice.title })),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,8 +49,10 @@ export async function autocomplete(nodeIo, interaction) {
|
||||
*/
|
||||
export const execute = async (nodeIo, interaction) => {
|
||||
try {
|
||||
var title = interaction.options.getString('title');
|
||||
await interaction.reply(`Removing ${title} from the list of RSS sources, please wait...`);
|
||||
var title = interaction.options.getString("title");
|
||||
await interaction.reply(
|
||||
`Removing ${title} from the list of RSS sources, please wait...`,
|
||||
);
|
||||
|
||||
const results = await deleteFeedByTitle(title);
|
||||
if (!results) {
|
||||
@@ -50,9 +60,11 @@ export const execute = async (nodeIo, interaction) => {
|
||||
await interaction.editReply(`Failed to remove source: '${title}'`);
|
||||
return;
|
||||
}
|
||||
await interaction.editReply(`${title} was successfully removed from the RSS sources.`)
|
||||
await interaction.editReply(
|
||||
`${title} was successfully removed from the RSS sources.`,
|
||||
);
|
||||
} catch (err) {
|
||||
log.ERROR(err)
|
||||
log.ERROR(err);
|
||||
await interaction.editReply(err.toString());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { DebugBuilder } from "../../modules/debugger.mjs";
|
||||
const log = new DebugBuilder("server", "discordBot.command.rssTrigger");
|
||||
import { SlashCommandBuilder } from 'discord.js';
|
||||
import { updateFeeds } from '../../rss-manager/feedHandler.mjs'
|
||||
import { SlashCommandBuilder } from "discord.js";
|
||||
import { updateFeeds } from "../../rss-manager/feedHandler.mjs";
|
||||
|
||||
// Exporting data property that contains the command structure for discord including any params
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('rss-trigger')
|
||||
.setDescription('Manually triggers an RSS feed update');
|
||||
.setName("rss-trigger")
|
||||
.setDescription("Manually triggers an RSS feed update");
|
||||
|
||||
// Exporting other properties
|
||||
export const example = "/rss-trigger"; // An example of how the command would be run in discord chat, this will be used for the help command
|
||||
@@ -33,15 +33,15 @@ export async function autocomplete(nodeIo, interaction) {
|
||||
* @param {any} interaction The interaction object
|
||||
*/
|
||||
export const execute = async (nodeIo, interaction) => {
|
||||
try {
|
||||
//const sockets = await nodeIo.allSockets();
|
||||
//await interaction.reply(`**Online Sockets: '${sockets}'**`);
|
||||
await interaction.reply('Triggering RSS update');
|
||||
await updateFeeds(interaction.client);
|
||||
await interaction.editReply('RSS Update Completed');
|
||||
//await interaction.channel.send('**Pong.**');
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
// await interaction.reply(err.toString());
|
||||
}
|
||||
}
|
||||
try {
|
||||
//const sockets = await nodeIo.allSockets();
|
||||
//await interaction.reply(`**Online Sockets: '${sockets}'**`);
|
||||
await interaction.reply("Triggering RSS update");
|
||||
await updateFeeds(interaction.client);
|
||||
await interaction.editReply("RSS Update Completed");
|
||||
//await interaction.channel.send('**Pong.**');
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
// await interaction.reply(err.toString());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { DebugBuilder } from "../../modules/debugger.mjs";
|
||||
const log = new DebugBuilder("server", "discordBot.command.update");
|
||||
import { SlashCommandBuilder } from 'discord.js';
|
||||
import { requestNodeUpdate } from '../../modules/socketServerWrappers.mjs';
|
||||
import { SlashCommandBuilder } from "discord.js";
|
||||
import { requestNodeUpdate } from "../../modules/socketServerWrappers.mjs";
|
||||
|
||||
// Exporting data property that contains the command structure for discord including any params
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('update')
|
||||
.setDescription('Updates all nodes currently logged on');
|
||||
.setName("update")
|
||||
.setDescription("Updates all nodes currently logged on");
|
||||
|
||||
// Exporting other properties
|
||||
export const example = "/update"; // An example of how the command would be run in discord chat, this will be used for the help command
|
||||
@@ -19,19 +19,21 @@ export const deferInitialReply = false; // If we the initial reply in discord sh
|
||||
*/
|
||||
export const execute = async (nodeIo, interaction) => {
|
||||
try {
|
||||
const openSockets = [...await nodeIo.allSockets()]; // TODO - Filter the returned nodes to only nodes that have the radio capability
|
||||
const openSockets = [...(await nodeIo.allSockets())]; // TODO - Filter the returned nodes to only nodes that have the radio capability
|
||||
log.DEBUG("All open sockets: ", openSockets);
|
||||
|
||||
// Check each open socket to see if the node has the requested system
|
||||
await Promise.all(openSockets.map(openSocket => {
|
||||
openSocket = nodeIo.sockets.sockets.get(openSocket);
|
||||
requestNodeUpdate(openSocket);
|
||||
}));
|
||||
await Promise.all(
|
||||
openSockets.map((openSocket) => {
|
||||
openSocket = nodeIo.sockets.sockets.get(openSocket);
|
||||
requestNodeUpdate(openSocket);
|
||||
}),
|
||||
);
|
||||
//await interaction.reply(`**Online Sockets: '${sockets}'**`);
|
||||
await interaction.reply('All nodes have been requested to update');
|
||||
await interaction.reply("All nodes have been requested to update");
|
||||
//await interaction.channel.send('**Pong.**');
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
// await interaction.reply(err.toString());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
import { DebugBuilder } from "../modules/debugger.mjs";
|
||||
import { Client, GatewayIntentBits, Collection } from 'discord.js';
|
||||
import { registerActiveCommands, unregisterAllCommands } from './modules/registerCommands.mjs'
|
||||
import { RSSController } from '../rss-manager/rssController.mjs'
|
||||
import { join, dirname } from 'path';
|
||||
import { readdirSync } from 'fs';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { Client, GatewayIntentBits, Collection } from "discord.js";
|
||||
import {
|
||||
registerActiveCommands,
|
||||
unregisterAllCommands,
|
||||
} from "./modules/registerCommands.mjs";
|
||||
import { RSSController } from "../rss-manager/rssController.mjs";
|
||||
import { join, dirname } from "path";
|
||||
import { readdirSync } from "fs";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
import dotenv from 'dotenv';
|
||||
dotenv.config()
|
||||
import dotenv from "dotenv";
|
||||
dotenv.config();
|
||||
|
||||
const log = new DebugBuilder("server", "discordBot");
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
|
||||
/**
|
||||
* Add the enabled commands to the bot to be used by users in discord
|
||||
* (commands that end in '.mjs' will be enabled, to disable just remove the extension or replace with '.mjs.disabled')
|
||||
@@ -22,36 +24,41 @@ const __dirname = dirname(__filename);
|
||||
* @param {any} _commandsPath="./commands"
|
||||
* @returns {any}
|
||||
*/
|
||||
export const addEnabledCommands = async (serverClient, _commandsPath = "./commands") => {
|
||||
// Setup commands for the Discord bot
|
||||
serverClient.commands = new Collection();
|
||||
const commandsPath = join(__dirname, _commandsPath);
|
||||
const commandFiles = readdirSync(commandsPath).filter(file => file.endsWith('.mjs'));
|
||||
export const addEnabledCommands = async (
|
||||
serverClient,
|
||||
_commandsPath = "./commands",
|
||||
) => {
|
||||
// Setup commands for the Discord bot
|
||||
serverClient.commands = new Collection();
|
||||
const commandsPath = join(__dirname, _commandsPath);
|
||||
const commandFiles = readdirSync(commandsPath).filter((file) =>
|
||||
file.endsWith(".mjs"),
|
||||
);
|
||||
|
||||
for (const file of commandFiles) {
|
||||
const filePath = await join(commandsPath, file);
|
||||
log.INFO(`Adding enabled command: ${filePath}`);
|
||||
await import(`file://${filePath}`).then(command => {
|
||||
if (command.data instanceof Promise) {
|
||||
command.data.then(async (builder) => {
|
||||
command.data = builder;
|
||||
log.DEBUG("Importing command: ", command.data.name, command);
|
||||
// Set a new item in the Collection
|
||||
// With the key as the command name and the value as the exported module
|
||||
serverClient.commands.set(command.data.name, command);
|
||||
});
|
||||
} else {
|
||||
log.DEBUG("Importing command: ", command.data.name, command);
|
||||
// Set a new item in the Collection
|
||||
// With the key as the command name and the value as the exported module
|
||||
serverClient.commands.set(command.data.name, command);
|
||||
}
|
||||
})
|
||||
}
|
||||
for (const file of commandFiles) {
|
||||
const filePath = await join(commandsPath, file);
|
||||
log.INFO(`Adding enabled command: ${filePath}`);
|
||||
await import(`file://${filePath}`).then((command) => {
|
||||
if (command.data instanceof Promise) {
|
||||
command.data.then(async (builder) => {
|
||||
command.data = builder;
|
||||
log.DEBUG("Importing command: ", command.data.name, command);
|
||||
// Set a new item in the Collection
|
||||
// With the key as the command name and the value as the exported module
|
||||
serverClient.commands.set(command.data.name, command);
|
||||
});
|
||||
} else {
|
||||
log.DEBUG("Importing command: ", command.data.name, command);
|
||||
// Set a new item in the Collection
|
||||
// With the key as the command name and the value as the exported module
|
||||
serverClient.commands.set(command.data.name, command);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Register the commands currently in use by the bot
|
||||
await registerActiveCommands(serverClient);
|
||||
}
|
||||
// Register the commands currently in use by the bot
|
||||
await registerActiveCommands(serverClient);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add the enabled event listeners to the bot
|
||||
@@ -60,42 +67,60 @@ export const addEnabledCommands = async (serverClient, _commandsPath = "./comman
|
||||
* @param {any} _eventsPath="./events"
|
||||
* @returns {any}
|
||||
*/
|
||||
export function addEnabledEventListeners(serverClient, _eventsPath = "./events") {
|
||||
const eventsPath = join(__dirname, _eventsPath);
|
||||
const eventFiles = readdirSync(eventsPath).filter(file => file.endsWith('.mjs'));
|
||||
export function addEnabledEventListeners(
|
||||
serverClient,
|
||||
_eventsPath = "./events",
|
||||
) {
|
||||
const eventsPath = join(__dirname, _eventsPath);
|
||||
const eventFiles = readdirSync(eventsPath).filter((file) =>
|
||||
file.endsWith(".mjs"),
|
||||
);
|
||||
|
||||
for (const file of eventFiles) {
|
||||
const filePath = join(eventsPath, file);
|
||||
log.INFO(`Adding enabled event listener: ${filePath}`);
|
||||
import(`file://${filePath}`).then(event => {
|
||||
log.DEBUG("Adding event: ", event);
|
||||
if (event.once) {
|
||||
serverClient.once(event.name, (...args) => event.execute(serverClient.nodeIo, ...args));
|
||||
} else {
|
||||
serverClient.on(event.name, (...args) => event.execute(serverClient.nodeIo, ...args));
|
||||
}
|
||||
})
|
||||
}
|
||||
for (const file of eventFiles) {
|
||||
const filePath = join(eventsPath, file);
|
||||
log.INFO(`Adding enabled event listener: ${filePath}`);
|
||||
import(`file://${filePath}`).then((event) => {
|
||||
log.DEBUG("Adding event: ", event);
|
||||
if (event.once) {
|
||||
serverClient.once(event.name, (...args) =>
|
||||
event.execute(serverClient.nodeIo, ...args),
|
||||
);
|
||||
} else {
|
||||
serverClient.on(event.name, (...args) =>
|
||||
event.execute(serverClient.nodeIo, ...args),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// The discord client
|
||||
export const serverClient = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent, GatewayIntentBits.GuildMembers, GatewayIntentBits.GuildPresences] });
|
||||
export const serverClient = new Client({
|
||||
intents: [
|
||||
GatewayIntentBits.Guilds,
|
||||
GatewayIntentBits.GuildVoiceStates,
|
||||
GatewayIntentBits.GuildMessages,
|
||||
GatewayIntentBits.MessageContent,
|
||||
GatewayIntentBits.GuildMembers,
|
||||
GatewayIntentBits.GuildPresences,
|
||||
],
|
||||
});
|
||||
|
||||
// Run when the bot is ready
|
||||
serverClient.on('ready', async () => {
|
||||
log.INFO(`Logged in as ${serverClient.user.tag}!`);
|
||||
serverClient.on("ready", async () => {
|
||||
log.INFO(`Logged in as ${serverClient.user.tag}!`);
|
||||
|
||||
// Add and register commands
|
||||
await addEnabledCommands(serverClient);
|
||||
// Add and register commands
|
||||
await addEnabledCommands(serverClient);
|
||||
|
||||
// Config the discord bot with events
|
||||
await addEnabledEventListeners(serverClient);
|
||||
// Config the discord bot with events
|
||||
await addEnabledEventListeners(serverClient);
|
||||
|
||||
// Start the RSS Controller
|
||||
serverClient.RSSController = await new RSSController(serverClient);
|
||||
serverClient.RSSController.start();
|
||||
// Start the RSS Controller
|
||||
serverClient.RSSController = await new RSSController(serverClient);
|
||||
serverClient.RSSController.start();
|
||||
|
||||
log.INFO("RSS Controller:", serverClient.RSSController);
|
||||
log.INFO("RSS Controller:", serverClient.RSSController);
|
||||
});
|
||||
|
||||
// Startup the discord bot
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
import { DebugBuilder } from "../../modules/debugger.mjs";
|
||||
const log = new DebugBuilder("server", "discordBot.events.guildCreate");
|
||||
import { Events } from 'discord.js';
|
||||
import { addEnabledCommands, addEnabledEventListeners } from "../discordBot.mjs";
|
||||
import { Events } from "discord.js";
|
||||
import {
|
||||
addEnabledCommands,
|
||||
addEnabledEventListeners,
|
||||
} from "../discordBot.mjs";
|
||||
|
||||
export const name = Events.GuildMemberAdd;
|
||||
|
||||
export async function execute(nodeIo, guild) {
|
||||
log.INFO("Bot has joined a new server", guild);
|
||||
log.INFO("Bot has joined a new server", guild);
|
||||
|
||||
log.DEBUG("Refreshing commands enabled");
|
||||
await addEnabledCommands(nodeIo.serverClient);
|
||||
log.DEBUG("Refreshing commands enabled");
|
||||
await addEnabledCommands(nodeIo.serverClient);
|
||||
|
||||
log.DEBUG("Refreshing events enabled");
|
||||
await addEnabledEventListeners(nodeIo.serverClient);
|
||||
}
|
||||
log.DEBUG("Refreshing events enabled");
|
||||
await addEnabledEventListeners(nodeIo.serverClient);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { DebugBuilder } from "../../modules/debugger.mjs";
|
||||
const log = new DebugBuilder("server", "discordBot.events.guildMemberAdd");
|
||||
import dotenv from 'dotenv';
|
||||
import dotenv from "dotenv";
|
||||
dotenv.config();
|
||||
import { Events } from 'discord.js';
|
||||
import { Events } from "discord.js";
|
||||
import { gptHandler } from "../modules/gptHandler.mjs";
|
||||
|
||||
const welcomeChannel = process.env.WELCOME_CHANNEL_ID; // TODO - Need to add a DB section for server configs so it's not static to one server
|
||||
@@ -10,25 +10,24 @@ const welcomeChannel = process.env.WELCOME_CHANNEL_ID; // TODO - Need to add a D
|
||||
export const name = Events.GuildMemberAdd;
|
||||
|
||||
export async function execute(nodeIo, member) {
|
||||
log.INFO("New user joined the server", member);
|
||||
let conversation = [];
|
||||
conversation.push({
|
||||
role: 'assistant',
|
||||
content: `A new user has joined the server. Their name is '<@${member.id}>'. Please welcome them to the server and remind them about the rules.`
|
||||
})
|
||||
log.INFO("New user joined the server", member);
|
||||
let conversation = [];
|
||||
conversation.push({
|
||||
role: "assistant",
|
||||
content: `A new user has joined the server. Their name is '<@${member.id}>'. Please welcome them to the server and remind them about the rules.`,
|
||||
});
|
||||
|
||||
const response = await gptHandler(conversation);
|
||||
if (response) {
|
||||
const responseMessage = response.choices[0].message.content;
|
||||
const chunkSize = 2500;
|
||||
const response = await gptHandler(conversation);
|
||||
if (response) {
|
||||
const responseMessage = response.choices[0].message.content;
|
||||
const chunkSize = 2500;
|
||||
|
||||
for (let i = 0; i < responseMessage.length; i += chunkSize) {
|
||||
const chunk = responseMessage.substring(i, i + chunkSize);
|
||||
for (let i = 0; i < responseMessage.length; i += chunkSize) {
|
||||
const chunk = responseMessage.substring(i, i + chunkSize);
|
||||
|
||||
log.DEBUG("Sending message chunk:", chunk);
|
||||
log.DEBUG("Sending message chunk:", chunk);
|
||||
|
||||
await nodeIo.serverClient.channels.cache.get(welcomeChannel).send(chunk);
|
||||
}
|
||||
await nodeIo.serverClient.channels.cache.get(welcomeChannel).send(chunk);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { DebugBuilder } from "../../modules/debugger.mjs";
|
||||
const log = new DebugBuilder("server", "discordBot.events.interactionCreate");
|
||||
import { Events } from 'discord.js';
|
||||
import { Events } from "discord.js";
|
||||
|
||||
export const name = Events.InteractionCreate;
|
||||
|
||||
@@ -22,7 +22,9 @@ export async function execute(nodeIo, interaction) {
|
||||
return;
|
||||
}
|
||||
|
||||
log.INFO(`${interaction.member.user} is running '${interaction.commandName}'`);
|
||||
log.INFO(
|
||||
`${interaction.member.user} is running '${interaction.commandName}'`,
|
||||
);
|
||||
|
||||
// Defer the initial reply if the command has the parameter set
|
||||
if (command.deferInitialReply) {
|
||||
@@ -31,4 +33,4 @@ export async function execute(nodeIo, interaction) {
|
||||
|
||||
// Execute the command
|
||||
command.execute(nodeIo, interaction);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
import { DebugBuilder } from "../../modules/debugger.mjs";
|
||||
const log = new DebugBuilder("server", "discordBot.events.messageCreate");
|
||||
import dotenv from 'dotenv';
|
||||
import dotenv from "dotenv";
|
||||
dotenv.config();
|
||||
import { Events } from 'discord.js';
|
||||
import { gptInteraction } from '../addons/gptInteraction.mjs';
|
||||
import { linkCop } from '../addons/linkCop.mjs';
|
||||
import { Events } from "discord.js";
|
||||
import { gptInteraction } from "../addons/gptInteraction.mjs";
|
||||
import { linkCop } from "../addons/linkCop.mjs";
|
||||
|
||||
const IGNORED_CHANNELS = process.env.IGNORED_CHANNEL_IDS.split(',');
|
||||
const IGNORED_CHANNELS = process.env.IGNORED_CHANNEL_IDS.split(",");
|
||||
|
||||
export const name = Events.MessageCreate;
|
||||
|
||||
export async function execute(nodeIo, message) {
|
||||
// Ignore ignored channels
|
||||
if (IGNORED_CHANNELS.includes(message.channel.id)) return;
|
||||
// Ignore ignored channels
|
||||
if (IGNORED_CHANNELS.includes(message.channel.id)) return;
|
||||
|
||||
// Ignore messages from a bot
|
||||
if (message.author.bot) return;
|
||||
// Ignore messages from a bot
|
||||
if (message.author.bot) return;
|
||||
|
||||
log.INFO("Message create", message);
|
||||
log.INFO("Message create", message);
|
||||
|
||||
// Check if the message mentions the bot
|
||||
if (message.mentions.users.has(nodeIo.serverClient.user.id)) {
|
||||
return await gptInteraction(nodeIo, message);
|
||||
}
|
||||
// Check if the message mentions the bot
|
||||
if (message.mentions.users.has(nodeIo.serverClient.user.id)) {
|
||||
return await gptInteraction(nodeIo, message);
|
||||
}
|
||||
|
||||
// Check if the message contains a link in a channel it shouldn't
|
||||
if (await linkCop(nodeIo, message)) return;
|
||||
}
|
||||
// Check if the message contains a link in a channel it shouldn't
|
||||
if (await linkCop(nodeIo, message)) return;
|
||||
}
|
||||
|
||||
@@ -1,122 +1,117 @@
|
||||
import { DebugBuilder } from "../../modules/debugger.mjs";
|
||||
const log = new DebugBuilder("server", "discordBot.modules.gptHandler");
|
||||
import dotenv from 'dotenv';
|
||||
import dotenv from "dotenv";
|
||||
dotenv.config();
|
||||
|
||||
import { OpenAI } from 'openai';
|
||||
import { EventEmitter } from 'events';
|
||||
import { OpenAI } from "openai";
|
||||
import { EventEmitter } from "events";
|
||||
|
||||
const openai = new OpenAI(process.env.OPENAI_API_KEY);
|
||||
|
||||
const assistant = await openai.beta.assistants.create({
|
||||
name: "Emmelia",
|
||||
instructions: process.env.DRB_SERVER_INITIAL_PROMPT,
|
||||
model: "gpt-4o",
|
||||
name: "Emmelia",
|
||||
instructions: process.env.DRB_SERVER_INITIAL_PROMPT,
|
||||
model: "gpt-4o",
|
||||
});
|
||||
|
||||
class EventHandler extends EventEmitter {
|
||||
constructor(client) {
|
||||
super();
|
||||
this.client = client;
|
||||
}
|
||||
constructor(client) {
|
||||
super();
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
async onEvent(event) {
|
||||
try {
|
||||
console.log(event);
|
||||
// Retrieve events that are denoted with 'requires_action'
|
||||
// since these will have our tool_calls
|
||||
if (event.event === "thread.run.requires_action") {
|
||||
await this.handleRequiresAction(
|
||||
event.data,
|
||||
event.data.id,
|
||||
event.data.thread_id,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error handling event:", error);
|
||||
}
|
||||
async onEvent(event) {
|
||||
try {
|
||||
console.log(event);
|
||||
// Retrieve events that are denoted with 'requires_action'
|
||||
// since these will have our tool_calls
|
||||
if (event.event === "thread.run.requires_action") {
|
||||
await this.handleRequiresAction(
|
||||
event.data,
|
||||
event.data.id,
|
||||
event.data.thread_id,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error handling event:", error);
|
||||
}
|
||||
}
|
||||
|
||||
async handleRequiresAction(data, runId, threadId) {
|
||||
try {
|
||||
const toolOutputs =
|
||||
data.required_action.submit_tool_outputs.tool_calls.map((toolCall) => {
|
||||
// Call the function
|
||||
switch (toolCall.function.name) {
|
||||
case "getCurrentTemperature": return {
|
||||
tool_call_id: toolCall.id,
|
||||
output: "57",
|
||||
};
|
||||
}
|
||||
});
|
||||
// Submit all the tool outputs at the same time
|
||||
await this.submitToolOutputs(toolOutputs, runId, threadId);
|
||||
} catch (error) {
|
||||
console.error("Error processing required action:", error);
|
||||
}
|
||||
async handleRequiresAction(data, runId, threadId) {
|
||||
try {
|
||||
const toolOutputs =
|
||||
data.required_action.submit_tool_outputs.tool_calls.map((toolCall) => {
|
||||
// Call the function
|
||||
switch (toolCall.function.name) {
|
||||
case "getCurrentTemperature":
|
||||
return {
|
||||
tool_call_id: toolCall.id,
|
||||
output: "57",
|
||||
};
|
||||
}
|
||||
});
|
||||
// Submit all the tool outputs at the same time
|
||||
await this.submitToolOutputs(toolOutputs, runId, threadId);
|
||||
} catch (error) {
|
||||
console.error("Error processing required action:", error);
|
||||
}
|
||||
}
|
||||
|
||||
async submitToolOutputs(toolOutputs, runId, threadId) {
|
||||
try {
|
||||
// Use the submitToolOutputsStream helper
|
||||
const stream = this.client.beta.threads.runs.submitToolOutputsStream(
|
||||
threadId,
|
||||
runId,
|
||||
{ tool_outputs: toolOutputs },
|
||||
);
|
||||
for await (const event of stream) {
|
||||
this.emit("event", event);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error submitting tool outputs:", error);
|
||||
}
|
||||
async submitToolOutputs(toolOutputs, runId, threadId) {
|
||||
try {
|
||||
// Use the submitToolOutputsStream helper
|
||||
const stream = this.client.beta.threads.runs.submitToolOutputsStream(
|
||||
threadId,
|
||||
runId,
|
||||
{ tool_outputs: toolOutputs },
|
||||
);
|
||||
for await (const event of stream) {
|
||||
this.emit("event", event);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error submitting tool outputs:", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const eventHandler = new EventHandler(openai);
|
||||
eventHandler.on("event", eventHandler.onEvent.bind(eventHandler));
|
||||
|
||||
export const gptHandler = async (additionalMessages) => {
|
||||
const thread = await openai.beta.threads.create();
|
||||
const thread = await openai.beta.threads.create();
|
||||
|
||||
// Add the additional messages to the conversation
|
||||
for (const msgObj of additionalMessages) {
|
||||
await openai.beta.threads.messages.create(
|
||||
thread.id,
|
||||
msgObj
|
||||
);
|
||||
// Add the additional messages to the conversation
|
||||
for (const msgObj of additionalMessages) {
|
||||
await openai.beta.threads.messages.create(thread.id, msgObj);
|
||||
}
|
||||
|
||||
log.DEBUG("AI Conversation:", thread);
|
||||
|
||||
// Run the thread to get a response
|
||||
try {
|
||||
const stream = await openai.beta.threads.runs.stream(
|
||||
thread.id,
|
||||
{ assistant_id: assistant.id },
|
||||
eventHandler,
|
||||
);
|
||||
|
||||
for await (const event of stream) {
|
||||
eventHandler.emit("event", event);
|
||||
}
|
||||
|
||||
log.DEBUG("AI Conversation:", thread);
|
||||
let response;
|
||||
const messages = await openai.beta.threads.messages.list(thread.id);
|
||||
response = messages.data[0].content[0].text.value;
|
||||
|
||||
// Run the thread to get a response
|
||||
try {
|
||||
const stream = await openai.beta.threads.runs.stream(
|
||||
thread.id,
|
||||
{ assistant_id: assistant.id },
|
||||
eventHandler,
|
||||
);
|
||||
log.DEBUG("AI Response:", response);
|
||||
|
||||
for await (const event of stream) {
|
||||
eventHandler.emit("event", event);
|
||||
}
|
||||
|
||||
let response;
|
||||
const messages = await openai.beta.threads.messages.list(
|
||||
thread.id
|
||||
);
|
||||
response = messages.data[0].content[0].text.value;
|
||||
|
||||
log.DEBUG("AI Response:", response);
|
||||
|
||||
if (!response) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return response;
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error generating response:', error);
|
||||
return false;
|
||||
if (!response) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.error("Error generating response:", error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
51
discordBot/modules/presenceManager.mjs
Normal file
51
discordBot/modules/presenceManager.mjs
Normal file
@@ -0,0 +1,51 @@
|
||||
import { getConfig } from "./configHandler.mjs";
|
||||
|
||||
class PresenceManager {
|
||||
/**
|
||||
* Creates an instance of PresenceManager.
|
||||
* @param {import('discord.js').Client} client - The Discord client instance.
|
||||
*/
|
||||
constructor(client) {
|
||||
this.client = client;
|
||||
this.defaultStatus = "online";
|
||||
this.defaultActivityType = "LISTENING";
|
||||
this.defaultActivityName = "for your commands";
|
||||
this.defaultUrl = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bot's presence.
|
||||
* @param {"online"|"idle"|"dnd"} status - The status of the bot (online, idle, dnd).
|
||||
* @param {"PLAYING"|"STREAMING"|"LISTENING"|"WATCHING"|"COMPETING"} activityType - The type of activity.
|
||||
* @param {string} activityName - The name of the activity.
|
||||
* @param {string} [url=null] - The URL for STREAMING activity type (optional).
|
||||
*/
|
||||
setPresence(status, activityType, activityName, url = null) {
|
||||
const activityOptions = {
|
||||
type: activityType.toUpperCase(),
|
||||
name: activityName,
|
||||
};
|
||||
|
||||
if (activityType.toUpperCase() === "STREAMING" && url) {
|
||||
activityOptions.url = url;
|
||||
}
|
||||
|
||||
this.client.user.setPresence({
|
||||
status: status,
|
||||
activities: [activityOptions],
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the bot's presence to the default state.
|
||||
*/
|
||||
resetToDefault() {
|
||||
const defaultPresence = getConfig("presence");
|
||||
console.log("Default Presence:", defaultPresence);
|
||||
|
||||
// Update your bot's presence using this configuration
|
||||
this.client.user.setPresence(defaultPresence);
|
||||
}
|
||||
}
|
||||
|
||||
export default PresenceManager;
|
||||
@@ -1,73 +1,92 @@
|
||||
import { DebugBuilder } from "../../modules/debugger.mjs";
|
||||
const log = new DebugBuilder("server", "discordBot.modules.registerCommands");
|
||||
import { REST, Routes } from 'discord.js';
|
||||
import { REST, Routes } from "discord.js";
|
||||
|
||||
import dotenv from 'dotenv';
|
||||
dotenv.config()
|
||||
import dotenv from "dotenv";
|
||||
dotenv.config();
|
||||
|
||||
const discordToken = process.env.DISCORD_TOKEN;
|
||||
|
||||
export const registerActiveCommands = async (serverClient) => {
|
||||
const guildIDs = serverClient.guilds.cache;
|
||||
const clientId = serverClient.user.id;
|
||||
const commands = await serverClient.commands.map(command => command = command.data.toJSON());
|
||||
const guildIDs = serverClient.guilds.cache;
|
||||
const clientId = serverClient.user.id;
|
||||
const commands = await serverClient.commands.map(
|
||||
(command) => (command = command.data.toJSON()),
|
||||
);
|
||||
|
||||
// Construct and prepare an instance of the REST module
|
||||
const rest = new REST({ version: '10' }).setToken(discordToken);
|
||||
// Construct and prepare an instance of the REST module
|
||||
const rest = new REST({ version: "10" }).setToken(discordToken);
|
||||
|
||||
// and deploy your commands!
|
||||
guildIDs.forEach(guild => {
|
||||
log.INFO("Deploying commands for: ", guild.id);
|
||||
log.DEBUG("Commands", commands);
|
||||
(async () => {
|
||||
try {
|
||||
log.DEBUG(`Started refreshing application (/) commands for guild ID: ${guild.id}.`);
|
||||
// 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, guild.id),
|
||||
{ body: commands },
|
||||
);
|
||||
// and deploy your commands!
|
||||
guildIDs.forEach((guild) => {
|
||||
log.INFO("Deploying commands for: ", guild.id);
|
||||
log.DEBUG("Commands", commands);
|
||||
(async () => {
|
||||
try {
|
||||
log.DEBUG(
|
||||
`Started refreshing application (/) commands for guild ID: ${guild.id}.`,
|
||||
);
|
||||
// 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, guild.id),
|
||||
{ body: commands },
|
||||
);
|
||||
|
||||
log.DEBUG(`Successfully reloaded ${data.length} application (/) commands for guild ID: ${guild.id}.`);
|
||||
} catch (error) {
|
||||
// And of course, make sure you catch and log any errors!
|
||||
log.ERROR("ERROR Deploying commands: ", error, "Body from error: ", commands);
|
||||
}
|
||||
})()
|
||||
})
|
||||
log.DEBUG(
|
||||
`Successfully reloaded ${data.length} application (/) commands for guild ID: ${guild.id}.`,
|
||||
);
|
||||
} catch (error) {
|
||||
// And of course, make sure you catch and log any errors!
|
||||
log.ERROR(
|
||||
"ERROR Deploying commands: ",
|
||||
error,
|
||||
"Body from error: ",
|
||||
commands,
|
||||
);
|
||||
}
|
||||
})();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove all commands for a given bot in a given guild
|
||||
*
|
||||
*
|
||||
* @param {any} serverClient The discord bot client
|
||||
*/
|
||||
export const unregisterAllCommands = async (serverClient) => {
|
||||
const guildIDs = serverClient.guilds.cache;
|
||||
const clientId = serverClient.user.id;
|
||||
commands = [];
|
||||
const guildIDs = serverClient.guilds.cache;
|
||||
const clientId = serverClient.user.id;
|
||||
commands = [];
|
||||
|
||||
const rest = new REST({ version: '10' }).setToken(discordToken);
|
||||
guildIDs.forEach(guild => {
|
||||
log.INFO("Removing commands for: ", clientId, guild.id);
|
||||
(async () => {
|
||||
try {
|
||||
log.DEBUG(`Started removal of ${commands.length} application (/) commands for guild ID: ${guild.id}.`);
|
||||
// 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, guild.id),
|
||||
{ body: commands },
|
||||
);
|
||||
const rest = new REST({ version: "10" }).setToken(discordToken);
|
||||
guildIDs.forEach((guild) => {
|
||||
log.INFO("Removing commands for: ", clientId, guild.id);
|
||||
(async () => {
|
||||
try {
|
||||
log.DEBUG(
|
||||
`Started removal of ${commands.length} application (/) commands for guild ID: ${guild.id}.`,
|
||||
);
|
||||
// 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, guild.id),
|
||||
{ body: commands },
|
||||
);
|
||||
|
||||
log.DEBUG(`Successfully removed ${data.length} application (/) commands for guild ID: ${guild.id}.`);
|
||||
} catch (error) {
|
||||
// And of course, make sure you catch and log any errors!
|
||||
log.ERROR("ERROR removing commands: ", error, "Body from error: ", commands);
|
||||
}
|
||||
})()
|
||||
})
|
||||
|
||||
}
|
||||
log.DEBUG(
|
||||
`Successfully removed ${data.length} application (/) commands for guild ID: ${guild.id}.`,
|
||||
);
|
||||
} catch (error) {
|
||||
// And of course, make sure you catch and log any errors!
|
||||
log.ERROR(
|
||||
"ERROR removing commands: ",
|
||||
error,
|
||||
"Body from error: ",
|
||||
commands,
|
||||
);
|
||||
}
|
||||
})();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* This named wrapper will remove all commands and then re-add the commands back, effectively refreshing them
|
||||
@@ -75,11 +94,13 @@ export const unregisterAllCommands = async (serverClient) => {
|
||||
* @returns {any}
|
||||
*/
|
||||
export const refreshActiveCommandsWrapper = async (serverClient) => {
|
||||
// Remove all commands
|
||||
log.INFO("Removing/Unregistering all commands from all connected servers/guilds");
|
||||
await unregisterAllCommands(serverClient);
|
||||
// Deploy the active commands
|
||||
log.INFO("Adding commands to all connected servers/guilds");
|
||||
await registerActiveCommands(serverClient);
|
||||
return;
|
||||
}
|
||||
// Remove all commands
|
||||
log.INFO(
|
||||
"Removing/Unregistering all commands from all connected servers/guilds",
|
||||
);
|
||||
await unregisterAllCommands(serverClient);
|
||||
// Deploy the active commands
|
||||
log.INFO("Adding commands to all connected servers/guilds");
|
||||
await registerActiveCommands(serverClient);
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -1,37 +1,39 @@
|
||||
// Import necessary modules
|
||||
import { EmbedBuilder } from 'discord.js';
|
||||
import { EmbedBuilder } from "discord.js";
|
||||
import { DebugBuilder } from "../../modules/debugger.mjs";
|
||||
import { parse } from "node-html-parser";
|
||||
import { config } from 'dotenv';
|
||||
import { config } from "dotenv";
|
||||
|
||||
// Load environment variables
|
||||
config();
|
||||
|
||||
const log = new DebugBuilder("server", "discordBot.modules.rssWrappers");
|
||||
|
||||
const imageRegex = /(http(s?):)([/|.|\w|\s|-])*((\.(?:jpg|gif|png|webm))|(\/gallery\/(?:[/|.|\w|\s|-])*))/g;
|
||||
const youtubeVideoRegex = /((?:https?:)?\/\/)?((?:www|m)\.)?((?:youtube(-nocookie)?\.com|youtu.be))(\/(?:[\w\-]+\?v=|embed\/|v\/)?)([\w\-]+)/g;
|
||||
const imageRegex =
|
||||
/(http(s?):)([/|.|\w|\s|-])*((\.(?:jpg|gif|png|webm))|(\/gallery\/(?:[/|.|\w|\s|-])*))/g;
|
||||
const youtubeVideoRegex =
|
||||
/((?:https?:)?\/\/)?((?:www|m)\.)?((?:youtube(-nocookie)?\.com|youtu.be))(\/(?:[\w\-]+\?v=|embed\/|v\/)?)([\w\-]+)/g;
|
||||
|
||||
export class DRBEmbedBuilder extends EmbedBuilder {
|
||||
constructor() {
|
||||
super();
|
||||
this.setTimestamp();
|
||||
this.setFooter({ text: 'Brought to you by Emmelia.' });
|
||||
this.setFooter({ text: "Brought to you by Emmelia." });
|
||||
}
|
||||
}
|
||||
|
||||
export const sendPost = (post, source, channel) => {
|
||||
log.DEBUG("Sending post from source: ", post, source);
|
||||
|
||||
|
||||
const postTitle = String(post.title).substring(0, 150);
|
||||
const postLink = post.link;
|
||||
let postContent = `*This post has no content* [Direct Link](${post.link})`;
|
||||
|
||||
if (post.content || post['content:encoded']) {
|
||||
const content = post['content:encoded'] ?? post.content;
|
||||
|
||||
if (post.content || post["content:encoded"]) {
|
||||
const content = post["content:encoded"] ?? post.content;
|
||||
const parsedContent = parse(content);
|
||||
let postText = parsedContent.text.trim();
|
||||
|
||||
|
||||
if (postText.length >= 3800) {
|
||||
postText = `${postText.slice(0, 3800).substring(0, postText.lastIndexOf(" "))} [...](${post.link})`;
|
||||
} else if (postText.length === 0) {
|
||||
@@ -43,16 +45,18 @@ export const sendPost = (post, source, channel) => {
|
||||
const ytVideos = content.match(youtubeVideoRegex);
|
||||
if (ytVideos) {
|
||||
ytVideos.slice(0, 4).forEach((ytVideo) => {
|
||||
if (ytVideo.includes("embed")) ytVideo = ytVideo.replace("embed/", "watch?v=");
|
||||
if (ytVideo.includes("embed"))
|
||||
ytVideo = ytVideo.replace("embed/", "watch?v=");
|
||||
postContent += `\nEmbedded Video from Post: [YouTube](${ytVideo})`;
|
||||
});
|
||||
}
|
||||
|
||||
// Extract the first image link if available
|
||||
const imageLinks = parsedContent.querySelectorAll("a")
|
||||
.map(link => link.getAttribute("href"))
|
||||
.filter(href => href && href.match(imageRegex));
|
||||
|
||||
const imageLinks = parsedContent
|
||||
.querySelectorAll("a")
|
||||
.map((link) => link.getAttribute("href"))
|
||||
.filter((href) => href && href.match(imageRegex));
|
||||
|
||||
if (imageLinks.length > 0) {
|
||||
post.image = imageLinks[0];
|
||||
}
|
||||
@@ -67,11 +71,11 @@ export const sendPost = (post, source, channel) => {
|
||||
|
||||
try {
|
||||
const rssMessage = new DRBEmbedBuilder()
|
||||
.setColor(0x0099FF)
|
||||
.setColor(0x0099ff)
|
||||
.setTitle(postTitle)
|
||||
.setURL(postLink)
|
||||
.addFields({ name: 'Source', value: postSourceLink, inline: true })
|
||||
.addFields({ name: 'Published', value: postPubDate, inline: true });
|
||||
.addFields({ name: "Source", value: postSourceLink, inline: true })
|
||||
.addFields({ name: "Published", value: postPubDate, inline: true });
|
||||
|
||||
if (postImage) {
|
||||
log.DEBUG("Image from post:", postImage);
|
||||
@@ -87,7 +91,14 @@ export const sendPost = (post, source, channel) => {
|
||||
|
||||
return channelResponse;
|
||||
} catch (err) {
|
||||
log.ERROR("Error sending message: ", postTitle, postId, postContent, postPubDate, err);
|
||||
log.ERROR(
|
||||
"Error sending message: ",
|
||||
postTitle,
|
||||
postId,
|
||||
postContent,
|
||||
postPubDate,
|
||||
err,
|
||||
);
|
||||
return err;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,39 +1,49 @@
|
||||
import { DebugBuilder } from "../../modules/debugger.mjs";
|
||||
const log = new DebugBuilder("server", "discordBot.modules.wrappers");
|
||||
import { checkIfNodeIsConnectedToVC, getNodeDiscordID, getNodeDiscordUsername, checkIfNodeHasOpenDiscordClient, getNodeCurrentListeningSystem, requestNodeJoinSystem } from '../../modules/socketServerWrappers.mjs';
|
||||
import { getAllDiscordIDs } from '../../modules/mongo-wrappers/mongoDiscordIDWrappers.mjs'
|
||||
import { ActionRowBuilder, ButtonBuilder, ButtonStyle } from 'discord.js';
|
||||
|
||||
|
||||
import {
|
||||
checkIfNodeIsConnectedToVC,
|
||||
getNodeDiscordID,
|
||||
getNodeDiscordUsername,
|
||||
checkIfNodeHasOpenDiscordClient,
|
||||
getNodeCurrentListeningSystem,
|
||||
requestNodeJoinSystem,
|
||||
} from "../../modules/socketServerWrappers.mjs";
|
||||
import { getAllDiscordIDs } from "../../modules/mongo-wrappers/mongoDiscordIDWrappers.mjs";
|
||||
import { ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js";
|
||||
|
||||
export const checkOnlineBotsInGuild = async (nodeIo, guildId) => {
|
||||
let onlineBots = [];
|
||||
const openSockets = [...await nodeIo.allSockets()];
|
||||
await Promise.all(openSockets.map(async openSocket => {
|
||||
openSocket = await nodeIo.sockets.sockets.get(openSocket);
|
||||
const connected = await checkIfNodeIsConnectedToVC(nodeIo, guildId, openSocket.node.nuid);
|
||||
log.INFO("Connected:", connected);
|
||||
if (connected) {
|
||||
const username = await getNodeDiscordUsername(openSocket, guildId);
|
||||
const discordID = await getNodeDiscordID(openSocket);
|
||||
onlineBots.push({
|
||||
name: username,
|
||||
discord_id: discordID,
|
||||
nuid: openSocket.node.nuid
|
||||
});
|
||||
}
|
||||
}));
|
||||
const openSockets = [...(await nodeIo.allSockets())];
|
||||
await Promise.all(
|
||||
openSockets.map(async (openSocket) => {
|
||||
openSocket = await nodeIo.sockets.sockets.get(openSocket);
|
||||
const connected = await checkIfNodeIsConnectedToVC(
|
||||
nodeIo,
|
||||
guildId,
|
||||
openSocket.node.nuid,
|
||||
);
|
||||
log.INFO("Connected:", connected);
|
||||
if (connected) {
|
||||
const username = await getNodeDiscordUsername(openSocket, guildId);
|
||||
const discordID = await getNodeDiscordID(openSocket);
|
||||
onlineBots.push({
|
||||
name: username,
|
||||
discord_id: discordID,
|
||||
nuid: openSocket.node.nuid,
|
||||
});
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
return onlineBots;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
export const getAvailableTokensInGuild = async (nodeIo, guildId) => {
|
||||
try {
|
||||
// Execute both asynchronous functions concurrently
|
||||
const [discordIDs, onlineBots] = await Promise.all([
|
||||
getAllDiscordIDs(), // Fetch all Discord IDs
|
||||
checkOnlineBotsInGuild(nodeIo, guildId) // Check online bots in the guild
|
||||
checkOnlineBotsInGuild(nodeIo, guildId), // Check online bots in the guild
|
||||
]);
|
||||
|
||||
// Use the results of both promises here
|
||||
@@ -41,60 +51,76 @@ export const getAvailableTokensInGuild = async (nodeIo, guildId) => {
|
||||
log.INFO("Online bots in the guild:", onlineBots);
|
||||
|
||||
// Filter any discordIDs that are not active
|
||||
const availableDiscordIDs = discordIDs.filter(discordID => discordID.active == true).filter(discordID => !onlineBots.some(bot => Number(bot.discord_id) == discordID.discord_id));
|
||||
const availableDiscordIDs = discordIDs
|
||||
.filter((discordID) => discordID.active == true)
|
||||
.filter(
|
||||
(discordID) =>
|
||||
!onlineBots.some(
|
||||
(bot) => Number(bot.discord_id) == discordID.discord_id,
|
||||
),
|
||||
);
|
||||
|
||||
// Return the unavailable discordIDs
|
||||
return availableDiscordIDs;
|
||||
} catch (error) {
|
||||
console.error('Error getting available tokens in guild:', error);
|
||||
console.error("Error getting available tokens in guild:", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the nodes with given system that are available to be used within a given server
|
||||
* Get the nodes with given system that are available to be used within a given server
|
||||
* @param {any} nodeIo The nodeIO object contained in the discord server object
|
||||
* @param {any} guildId The guild ID to search in
|
||||
* @param {any} guildId The guild ID to search in
|
||||
* @param {any} system The system to filter the nodes by
|
||||
* @returns {any}
|
||||
*/
|
||||
export const getAvailableNodes = async (nodeIo, guildId, system) => {
|
||||
// Get all open socket nodes
|
||||
const openSockets = [...await nodeIo.allSockets()]; // TODO - Filter the returned nodes to only nodes that have the radio capability
|
||||
const openSockets = [...(await nodeIo.allSockets())]; // TODO - Filter the returned nodes to only nodes that have the radio capability
|
||||
log.DEBUG("All open sockets: ", openSockets);
|
||||
|
||||
var availableNodes = [];
|
||||
// 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);
|
||||
// Check if the node has an existing open client (meaning the radio is already being listened to)
|
||||
const hasOpenClient = await checkIfNodeHasOpenDiscordClient(openSocket);
|
||||
if (hasOpenClient) {
|
||||
let currentSystem = await getNodeCurrentListeningSystem(openSocket);
|
||||
if (currentSystem != system.name) {
|
||||
log.INFO("Node is listening to a different system than requested", openSocket.node.name);
|
||||
return;
|
||||
await Promise.all(
|
||||
openSockets.map(async (openSocket) => {
|
||||
openSocket = await nodeIo.sockets.sockets.get(openSocket);
|
||||
// Check if the node has an existing open client (meaning the radio is already being listened to)
|
||||
const hasOpenClient = await checkIfNodeHasOpenDiscordClient(openSocket);
|
||||
if (hasOpenClient) {
|
||||
let currentSystem = await getNodeCurrentListeningSystem(openSocket);
|
||||
if (currentSystem != system.name) {
|
||||
log.INFO(
|
||||
"Node is listening to a different system than requested",
|
||||
openSocket.node.name,
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the bot has an open voice connection in the requested server already
|
||||
const connected = await checkIfNodeIsConnectedToVC(nodeIo, guildId, openSocket.node.nuid);
|
||||
log.INFO("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);
|
||||
// Check if the bot has an open voice connection in the requested server already
|
||||
const connected = await checkIfNodeIsConnectedToVC(
|
||||
nodeIo,
|
||||
guildId,
|
||||
openSocket.node.nuid,
|
||||
);
|
||||
log.INFO("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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
}));
|
||||
|
||||
log.DEBUG("Availble nodes:", availableNodes.map(socket => socket.node.name));
|
||||
log.DEBUG(
|
||||
"Availble nodes:",
|
||||
availableNodes.map((socket) => socket.node.name),
|
||||
);
|
||||
|
||||
return availableNodes;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the voice channel the user is currently in.
|
||||
@@ -103,11 +129,14 @@ export const getAvailableNodes = async (nodeIo, guildId, system) => {
|
||||
*/
|
||||
export const getUserVoiceChannel = (interaction) => {
|
||||
if (!interaction.member.voice.channel) {
|
||||
interaction.editReply({ content: `<@${interaction.member.id}>, you need to enter a voice channel before using this command`, ephemeral: true });
|
||||
interaction.editReply({
|
||||
content: `<@${interaction.member.id}>, you need to enter a voice channel before using this command`,
|
||||
ephemeral: true,
|
||||
});
|
||||
return null;
|
||||
}
|
||||
return interaction.member.voice.channel;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Joins a node to a specified system and voice channel.
|
||||
@@ -117,25 +146,55 @@ export const getUserVoiceChannel = (interaction) => {
|
||||
* @param {any} system - The system object to join.
|
||||
* @param {any} channel - The voice channel to join.
|
||||
*/
|
||||
export const joinNode = async (nodeIo, interaction, nodeId, system, channel) => {
|
||||
export const joinNode = async (
|
||||
nodeIo,
|
||||
interaction,
|
||||
nodeId,
|
||||
system,
|
||||
channel,
|
||||
) => {
|
||||
try {
|
||||
const openSocket = await nodeIo.sockets.sockets.get(nodeId);
|
||||
const discordTokens = await getAvailableTokensInGuild(nodeIo, interaction.guild.id);
|
||||
const discordTokens = await getAvailableTokensInGuild(
|
||||
nodeIo,
|
||||
interaction.guild.id,
|
||||
);
|
||||
|
||||
if (discordTokens.length === 0) {
|
||||
await interaction.editReply({ content: `<@${interaction.member.id}>, there are no free bots available.`, ephemeral: true });
|
||||
await interaction.editReply({
|
||||
content: `<@${interaction.member.id}>, there are no free bots available.`,
|
||||
ephemeral: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
log.INFO("Joining node:", nodeId, system.name, channel.id, openSocket.node.name, discordTokens[0].token);
|
||||
await requestNodeJoinSystem(openSocket, system.name, channel.id, discordTokens[0].token);
|
||||
log.INFO(
|
||||
"Joining node:",
|
||||
nodeId,
|
||||
system.name,
|
||||
channel.id,
|
||||
openSocket.node.name,
|
||||
discordTokens[0].token,
|
||||
);
|
||||
await requestNodeJoinSystem(
|
||||
openSocket,
|
||||
system.name,
|
||||
channel.id,
|
||||
discordTokens[0].token,
|
||||
);
|
||||
|
||||
await interaction.editReply({ content: `<@${interaction.member.id}>, a bot will join your channel listening to '${system.name}' shortly.`, ephemeral: true });
|
||||
await interaction.editReply({
|
||||
content: `<@${interaction.member.id}>, a bot will join your channel listening to '${system.name}' shortly.`,
|
||||
ephemeral: true,
|
||||
});
|
||||
} catch (err) {
|
||||
log.ERROR("Failed to join node:", err);
|
||||
await interaction.editReply({ content: `<@${interaction.member.id}>, an error occurred while joining the node: ${err.message}`, ephemeral: true });
|
||||
await interaction.editReply({
|
||||
content: `<@${interaction.member.id}>, an error occurred while joining the node: ${err.message}`,
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Prompts the user to select a node from available nodes.
|
||||
@@ -143,9 +202,16 @@ export const joinNode = async (nodeIo, interaction, nodeId, system, channel) =>
|
||||
* @param {Array} availableNodes - The list of available nodes.
|
||||
* @param {Function} onNodeSelected - Callback function to handle the selected node.
|
||||
*/
|
||||
export const promptNodeSelection = async (interaction, availableNodes, onNodeSelected) => {
|
||||
const nodeSelectionButtons = availableNodes.map(node =>
|
||||
new ButtonBuilder().setCustomId(node.id).setLabel(node.node.name).setStyle(ButtonStyle.Primary)
|
||||
export const promptNodeSelection = async (
|
||||
interaction,
|
||||
availableNodes,
|
||||
onNodeSelected,
|
||||
) => {
|
||||
const nodeSelectionButtons = availableNodes.map((node) =>
|
||||
new ButtonBuilder()
|
||||
.setCustomId(node.id)
|
||||
.setLabel(node.node.name)
|
||||
.setStyle(ButtonStyle.Primary),
|
||||
);
|
||||
|
||||
const actionRow = new ActionRowBuilder().addComponents(nodeSelectionButtons);
|
||||
@@ -153,15 +219,21 @@ export const promptNodeSelection = async (interaction, availableNodes, onNodeSel
|
||||
const response = await interaction.editReply({
|
||||
content: `<@${interaction.member.id}>, please select the Node you would like to join with this system:`,
|
||||
components: [actionRow],
|
||||
ephemeral: true
|
||||
ephemeral: true,
|
||||
});
|
||||
|
||||
const collectorFilter = i => i.user.id === interaction.user.id;
|
||||
const collectorFilter = (i) => i.user.id === interaction.user.id;
|
||||
try {
|
||||
const selectedNode = await response.awaitMessageComponent({ filter: collectorFilter, time: 60_000 });
|
||||
const selectedNode = await response.awaitMessageComponent({
|
||||
filter: collectorFilter,
|
||||
time: 60_000,
|
||||
});
|
||||
await onNodeSelected(selectedNode.customId);
|
||||
} catch (e) {
|
||||
log.ERROR("Node selection timeout:", e);
|
||||
await interaction.editReply({ content: 'Confirmation not received within 1 minute, cancelling.', components: [] });
|
||||
await interaction.editReply({
|
||||
content: "Confirmation not received within 1 minute, cancelling.",
|
||||
components: [],
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,30 +2,28 @@ import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
import { FlatCompat } from "@eslint/eslintrc";
|
||||
import mjs from "@eslint/js";
|
||||
import prettierConfig from 'eslint-config-prettier';
|
||||
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
|
||||
import prettierConfig from "eslint-config-prettier";
|
||||
import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const compat = new FlatCompat({
|
||||
baseDirectory: __dirname,
|
||||
recommendedConfig: mjs.configs.recommended
|
||||
recommendedConfig: mjs.configs.recommended,
|
||||
});
|
||||
|
||||
export default [
|
||||
...compat.extends().map(
|
||||
config => ({
|
||||
...config,
|
||||
files: ["**/*.mjs", "**/*.js", "**/*.cjs"],
|
||||
rules: {
|
||||
...config.rules,
|
||||
// ...other your custom rules
|
||||
"no-console": "warn",
|
||||
"no-unused-vars": "warn",
|
||||
"unused-imports/no-unused-imports": "error",
|
||||
}
|
||||
})
|
||||
),
|
||||
...compat.extends().map((config) => ({
|
||||
...config,
|
||||
files: ["**/*.mjs", "**/*.js", "**/*.cjs"],
|
||||
rules: {
|
||||
...config.rules,
|
||||
// ...other your custom rules
|
||||
"no-console": "warn",
|
||||
"no-unused-vars": "warn",
|
||||
"unused-imports/no-unused-imports": "error",
|
||||
},
|
||||
})),
|
||||
prettierConfig, // Turns off all ESLint rules that have the potential to interfere with Prettier rules.
|
||||
eslintPluginPrettierRecommended
|
||||
];
|
||||
eslintPluginPrettierRecommended,
|
||||
];
|
||||
|
||||
@@ -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.`);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "eslint --fix .",
|
||||
"test": "mocha --timeout 5000",
|
||||
"start": "node server.js"
|
||||
},
|
||||
|
||||
@@ -1,28 +1,36 @@
|
||||
import { getAllFeeds, deleteFeedByLink, createPost, getPostByPostId } from '../modules/mongo-wrappers/mongoFeedsWrappers.mjs';
|
||||
import crypto from 'crypto';
|
||||
import { sendPost } from '../discordBot/modules/rssWrappers.mjs';
|
||||
import {
|
||||
getAllFeeds,
|
||||
deleteFeedByLink,
|
||||
createPost,
|
||||
getPostByPostId,
|
||||
} from "../modules/mongo-wrappers/mongoFeedsWrappers.mjs";
|
||||
import crypto from "crypto";
|
||||
import { sendPost } from "../discordBot/modules/rssWrappers.mjs";
|
||||
import { DebugBuilder } from "../modules/debugger.mjs";
|
||||
import { removeSource } from './sourceManager.mjs'
|
||||
import { removeSource } from "./sourceManager.mjs";
|
||||
import UserAgent from "user-agents";
|
||||
import Parser from 'rss-parser';
|
||||
import Parser from "rss-parser";
|
||||
|
||||
import dotenv from 'dotenv';
|
||||
dotenv.config()
|
||||
import dotenv from "dotenv";
|
||||
dotenv.config();
|
||||
|
||||
// Initialize the User-Agent string
|
||||
process.env.USER_AGENT_STRING = new UserAgent({ platform: 'Win32' }).toString();
|
||||
process.env.USER_AGENT_STRING = new UserAgent({ platform: "Win32" }).toString();
|
||||
|
||||
const parser = new Parser({
|
||||
headers: {
|
||||
'User-Agent': process.env.USER_AGENT_STRING,
|
||||
"Accept": "application/rss+xml,application/xhtml+xml,application/xml"
|
||||
}
|
||||
"User-Agent": process.env.USER_AGENT_STRING,
|
||||
Accept: "application/rss+xml,application/xhtml+xml,application/xml",
|
||||
},
|
||||
});
|
||||
|
||||
const log = new DebugBuilder("server", "feedHandler");
|
||||
|
||||
export const returnHash = (...stringsIncluded) => {
|
||||
return crypto.createHash('sha1').update(stringsIncluded.join("-<<??//\\\\??>>-")).digest("base64");
|
||||
return crypto
|
||||
.createHash("sha1")
|
||||
.update(stringsIncluded.join("-<<??//\\\\??>>-"))
|
||||
.digest("base64");
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -37,43 +45,55 @@ export const updateFeeds = async (client) => {
|
||||
const records = await getAllFeeds();
|
||||
|
||||
const sourcePromiseArray = records.map(async (source) => {
|
||||
log.DEBUG('Processing source:', source.title);
|
||||
log.DEBUG("Processing source:", source.title);
|
||||
|
||||
try {
|
||||
const parsedFeed = await parser.parseURL(source.link);
|
||||
|
||||
if (parsedFeed?.items) {
|
||||
await Promise.all(parsedFeed.items.reverse().map(async (post) => {
|
||||
log.DEBUG("Processing post:", post.title);
|
||||
await Promise.all(
|
||||
parsedFeed.items.reverse().map(async (post) => {
|
||||
log.DEBUG("Processing post:", post.title);
|
||||
|
||||
if (!post.title || !post.link) throw new Error("Missing title or link in the post");
|
||||
if (!post.content && !post['content:encoded']) log.WARN("No content for post:", post.title);
|
||||
if (!post.title || !post.link)
|
||||
throw new Error("Missing title or link in the post");
|
||||
if (!post.content && !post["content:encoded"])
|
||||
log.WARN("No content for post:", post.title);
|
||||
|
||||
post.postId = post.postId ?? post.guid ?? post.id ?? returnHash(post.title, post.link, post.pubDate ?? Date.now());
|
||||
post.postId =
|
||||
post.postId ??
|
||||
post.guid ??
|
||||
post.id ??
|
||||
returnHash(post.title, post.link, post.pubDate ?? Date.now());
|
||||
|
||||
const existingRecord = await getPostByPostId(post.postId);
|
||||
if (!existingRecord) {
|
||||
const channel = client.channels.cache.get(source.channel_id);
|
||||
const sendResults = await sendPost(post, source, channel);
|
||||
if (!sendResults) throw new Error("Failed to send post");
|
||||
const existingRecord = await getPostByPostId(post.postId);
|
||||
if (!existingRecord) {
|
||||
const channel = client.channels.cache.get(source.channel_id);
|
||||
const sendResults = await sendPost(post, source, channel);
|
||||
if (!sendResults) throw new Error("Failed to send post");
|
||||
|
||||
log.DEBUG("Saving post to database:", post.title, source.channel_id);
|
||||
log.DEBUG(
|
||||
"Saving post to database:",
|
||||
post.title,
|
||||
source.channel_id,
|
||||
);
|
||||
|
||||
const postToSave = {
|
||||
title: post.title,
|
||||
link: post.link,
|
||||
pubDate: post.pubDate,
|
||||
author: post.author,
|
||||
contentSnippet: post.contentSnippet,
|
||||
id: post.id,
|
||||
isoDate: post.isoDate,
|
||||
postId: post.postId
|
||||
};
|
||||
const postToSave = {
|
||||
title: post.title,
|
||||
link: post.link,
|
||||
pubDate: post.pubDate,
|
||||
author: post.author,
|
||||
contentSnippet: post.contentSnippet,
|
||||
id: post.id,
|
||||
isoDate: post.isoDate,
|
||||
postId: post.postId,
|
||||
};
|
||||
|
||||
await createPost(postToSave);
|
||||
log.DEBUG("Post saved:", postToSave);
|
||||
}
|
||||
}));
|
||||
await createPost(postToSave);
|
||||
log.DEBUG("Post saved:", postToSave);
|
||||
}
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
await deleteFeedByLink(source.link);
|
||||
}
|
||||
@@ -90,4 +110,4 @@ export const updateFeeds = async (client) => {
|
||||
log.ERROR("Error updating feeds:", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { DebugBuilder } from "../modules/debugger.mjs";
|
||||
import { updateFeeds } from "./feedHandler.mjs";
|
||||
import dotenv from 'dotenv';
|
||||
import dotenv from "dotenv";
|
||||
dotenv.config();
|
||||
|
||||
const log = new DebugBuilder("server", "rssController");
|
||||
@@ -10,40 +10,39 @@ const log = new DebugBuilder("server", "rssController");
|
||||
const refreshInterval = parseInt(process.env.RSS_REFRESH_INTERVAL) || 300000;
|
||||
|
||||
export class RSSController {
|
||||
constructor(client) {
|
||||
this.client = client;
|
||||
this.intervalId = null;
|
||||
constructor(client) {
|
||||
this.client = client;
|
||||
this.intervalId = null;
|
||||
}
|
||||
|
||||
async start() {
|
||||
try {
|
||||
log.INFO("Starting RSS Controller");
|
||||
// Get initial feeds before starting the interval loop
|
||||
await this.collectLatestPosts();
|
||||
|
||||
// Start the interval loop for updating feeds
|
||||
this.intervalId = setInterval(async () => {
|
||||
await this.collectLatestPosts();
|
||||
}, refreshInterval);
|
||||
} catch (error) {
|
||||
log.ERROR(`Failed to start RSS Controller: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async start() {
|
||||
try {
|
||||
log.INFO("Starting RSS Controller");
|
||||
// Get initial feeds before starting the interval loop
|
||||
await this.collectLatestPosts();
|
||||
|
||||
// Start the interval loop for updating feeds
|
||||
this.intervalId = setInterval(async () => {
|
||||
await this.collectLatestPosts();
|
||||
}, refreshInterval);
|
||||
|
||||
} catch (error) {
|
||||
log.ERROR(`Failed to start RSS Controller: ${error.message}`);
|
||||
}
|
||||
async stop() {
|
||||
if (this.intervalId) {
|
||||
clearInterval(this.intervalId);
|
||||
log.INFO("RSS Controller stopped");
|
||||
}
|
||||
}
|
||||
|
||||
async stop() {
|
||||
if (this.intervalId) {
|
||||
clearInterval(this.intervalId);
|
||||
log.INFO("RSS Controller stopped");
|
||||
}
|
||||
}
|
||||
|
||||
async collectLatestPosts() {
|
||||
try {
|
||||
log.INFO("Updating sources");
|
||||
await updateFeeds(this.client);
|
||||
} catch (error) {
|
||||
log.ERROR(`Error updating feeds: ${error.message}`);
|
||||
}
|
||||
async collectLatestPosts() {
|
||||
try {
|
||||
log.INFO("Updating sources");
|
||||
await updateFeeds(this.client);
|
||||
} catch (error) {
|
||||
log.ERROR(`Error updating feeds: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,77 +1,92 @@
|
||||
import { DebugBuilder } from "../modules/debugger.mjs";
|
||||
const log = new DebugBuilder("server", "sourceManager");
|
||||
import { createFeed, getFeedByLink, deleteFeedByLink } from '../modules/mongo-wrappers/mongoFeedsWrappers.mjs';
|
||||
import {
|
||||
createFeed,
|
||||
getFeedByLink,
|
||||
deleteFeedByLink,
|
||||
} from "../modules/mongo-wrappers/mongoFeedsWrappers.mjs";
|
||||
|
||||
class SourceManager {
|
||||
constructor(sourceFailureLimit) {
|
||||
this.sourceFailureLimit = sourceFailureLimit;
|
||||
this.runningSourcesToRemove = {};
|
||||
}
|
||||
|
||||
async removeSource(sourceURL) {
|
||||
log.INFO(`Removing source: ${sourceURL}`);
|
||||
constructor(sourceFailureLimit) {
|
||||
this.sourceFailureLimit = sourceFailureLimit;
|
||||
this.runningSourcesToRemove = {};
|
||||
}
|
||||
|
||||
const currentTime = Date.now();
|
||||
const sourceData = this.runningSourcesToRemove[sourceURL];
|
||||
async removeSource(sourceURL) {
|
||||
log.INFO(`Removing source: ${sourceURL}`);
|
||||
|
||||
if (!sourceData) {
|
||||
this.runningSourcesToRemove[sourceURL] = { count: 1, timestamp: currentTime, ignoredAttempts: 0 };
|
||||
return;
|
||||
}
|
||||
const currentTime = Date.now();
|
||||
const sourceData = this.runningSourcesToRemove[sourceURL];
|
||||
|
||||
const elapsedTimeSinceLastAttempt = currentTime - sourceData.timestamp;
|
||||
const waitTime = sourceData.count * 30000;
|
||||
|
||||
if (elapsedTimeSinceLastAttempt <= waitTime) {
|
||||
sourceData.ignoredAttempts += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (sourceData.count < this.sourceFailureLimit) {
|
||||
sourceData.count += 1;
|
||||
sourceData.timestamp = currentTime;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const record = await getFeedByLink(sourceURL);
|
||||
if (!record) {
|
||||
log.ERROR(`Source not found in storage: ${sourceURL}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const results = await deleteFeedByLink(sourceURL);
|
||||
if (!results) {
|
||||
log.WARN(`Failed to remove source: ${sourceURL}`);
|
||||
return;
|
||||
}
|
||||
|
||||
log.DEBUG(`Source removed after exceeding failure limit: ${sourceURL}`);
|
||||
// Optionally, clean up the entry from runningSourcesToRemove
|
||||
delete this.runningSourcesToRemove[sourceURL];
|
||||
} catch (err) {
|
||||
log.ERROR(`Error removing source from storage: ${sourceURL}`, err);
|
||||
}
|
||||
if (!sourceData) {
|
||||
this.runningSourcesToRemove[sourceURL] = {
|
||||
count: 1,
|
||||
timestamp: currentTime,
|
||||
ignoredAttempts: 0,
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
async addSource(title, link, category, guildId, channelId, callback) {
|
||||
try {
|
||||
const feed = { title, link, category, guild_id: guildId, channel_id: channelId };
|
||||
const record = await createFeed(feed);
|
||||
log.DEBUG("Source added:", record);
|
||||
if (callback) callback(null, record);
|
||||
} catch (err) {
|
||||
log.ERROR("Error adding source:", err);
|
||||
if (callback) callback(err, null);
|
||||
}
|
||||
const elapsedTimeSinceLastAttempt = currentTime - sourceData.timestamp;
|
||||
const waitTime = sourceData.count * 30000;
|
||||
|
||||
if (elapsedTimeSinceLastAttempt <= waitTime) {
|
||||
sourceData.ignoredAttempts += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (sourceData.count < this.sourceFailureLimit) {
|
||||
sourceData.count += 1;
|
||||
sourceData.timestamp = currentTime;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const record = await getFeedByLink(sourceURL);
|
||||
if (!record) {
|
||||
log.ERROR(`Source not found in storage: ${sourceURL}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const results = await deleteFeedByLink(sourceURL);
|
||||
if (!results) {
|
||||
log.WARN(`Failed to remove source: ${sourceURL}`);
|
||||
return;
|
||||
}
|
||||
|
||||
log.DEBUG(`Source removed after exceeding failure limit: ${sourceURL}`);
|
||||
// Optionally, clean up the entry from runningSourcesToRemove
|
||||
delete this.runningSourcesToRemove[sourceURL];
|
||||
} catch (err) {
|
||||
log.ERROR(`Error removing source from storage: ${sourceURL}`, err);
|
||||
}
|
||||
}
|
||||
|
||||
async addSource(title, link, category, guildId, channelId, callback) {
|
||||
try {
|
||||
const feed = {
|
||||
title,
|
||||
link,
|
||||
category,
|
||||
guild_id: guildId,
|
||||
channel_id: channelId,
|
||||
};
|
||||
const record = await createFeed(feed);
|
||||
log.DEBUG("Source added:", record);
|
||||
if (callback) callback(null, record);
|
||||
} catch (err) {
|
||||
log.ERROR("Error adding source:", err);
|
||||
if (callback) callback(err, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Create a default instance of SourceManager
|
||||
const defaultSourceManager = new SourceManager();
|
||||
|
||||
// Export the class and default instance methods
|
||||
export { SourceManager };
|
||||
export const addSource = defaultSourceManager.addSource.bind(defaultSourceManager);
|
||||
export const removeSource = defaultSourceManager.removeSource.bind(defaultSourceManager);
|
||||
export const addSource =
|
||||
defaultSourceManager.addSource.bind(defaultSourceManager);
|
||||
export const removeSource =
|
||||
defaultSourceManager.removeSource.bind(defaultSourceManager);
|
||||
|
||||
17
server.js
17
server.js
@@ -1,15 +1,18 @@
|
||||
import { DebugBuilder } from "./modules/debugger.mjs";
|
||||
const log = new DebugBuilder("server", "server");
|
||||
import { nodeIo, app, server } from './modules/socketServer.mjs';
|
||||
import { loadAddons } from './modules/addonManager.mjs';
|
||||
import { serverClient, addEnabledEventListeners } from './discordBot/discordBot.mjs';
|
||||
import { nodeIo, app, server } from "./modules/socketServer.mjs";
|
||||
import { loadAddons } from "./modules/addonManager.mjs";
|
||||
import {
|
||||
serverClient,
|
||||
addEnabledEventListeners,
|
||||
} from "./discordBot/discordBot.mjs";
|
||||
|
||||
import dotenv from 'dotenv';
|
||||
dotenv.config()
|
||||
import dotenv from "dotenv";
|
||||
dotenv.config();
|
||||
|
||||
// Startup the node server
|
||||
server.listen(process.env.SERVER_PORT || 3000, () => {
|
||||
log.INFO(`server running at http://localhost:${process.env.SERVER_PORT}`);
|
||||
log.INFO(`server running at http://localhost:${process.env.SERVER_PORT}`);
|
||||
});
|
||||
|
||||
// Add objects to the others
|
||||
@@ -17,4 +20,4 @@ serverClient.nodeIo = nodeIo;
|
||||
nodeIo.serverClient = serverClient;
|
||||
|
||||
// Load the addons
|
||||
loadAddons(nodeIo);
|
||||
loadAddons(nodeIo);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user