Skip to content

Commit

Permalink
[FIXBUG]: set redis attempts to 0
Browse files Browse the repository at this point in the history
  • Loading branch information
Behzad-rabiei committed Oct 23, 2023
1 parent 0f7d921 commit c5cf4d2
Show file tree
Hide file tree
Showing 40 changed files with 2,360 additions and 197 deletions.
60 changes: 60 additions & 0 deletions lib/config/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const joi_1 = __importDefault(require("joi"));
const envVarsSchema = joi_1.default.object()
.keys({
NODE_ENV: joi_1.default.string().valid('production', 'development', 'test').required(),
DB_HOST: joi_1.default.string().required().description('Mongo DB url'),
DB_PORT: joi_1.default.string().required().description('Mongo DB port'),
DB_USER: joi_1.default.string().required().description('Mongo DB username'),
DB_PASSWORD: joi_1.default.string().required().description('Mongo DB password'),
DB_NAME: joi_1.default.string().required().description('Mongo DB name'),
RABBIT_HOST: joi_1.default.string().required().description('RabbitMQ url'),
RABBIT_PORT: joi_1.default.string().required().description('RabbitMQ port'),
RABBIT_USER: joi_1.default.string().required().description('RabbitMQ username'),
RABBIT_PASSWORD: joi_1.default.string().required().description('RabbitMQ password'),
DISCROD_CLIENT_ID: joi_1.default.string().required().description('Discord clinet id'),
DISCORD_CLIENT_SECRET: joi_1.default.string().required().description('Discord clinet secret'),
DISCORD_BOT_TOKEN: joi_1.default.string().required().description('Discord bot token'),
SENTRY_DSN: joi_1.default.string().required().description('Sentry DSN'),
SENTRY_ENV: joi_1.default.string().valid('production', 'development', 'local', 'test').required(),
REDIS_HOST: joi_1.default.string().required().description('Reids host'),
REDIS_PORT: joi_1.default.string().required().description('Reids port'),
REDIS_PASSWORD: joi_1.default.string().required().description('Reids password').allow(''),
LOG_LEVEL: joi_1.default.string().required().description('Min allowed log level'),
})
.unknown();
const { value: envVars, error } = envVarsSchema.prefs({ errors: { label: 'key' } }).validate(process.env);
if (error) {
throw new Error(`Config validation error: ${error.message}`);
}
exports.default = {
env: envVars.NODE_ENV,
mongoose: {
serverURL: `mongodb://${envVars.DB_USER}:${envVars.DB_PASSWORD}@${envVars.DB_HOST}:${envVars.DB_PORT}/${envVars.DB_NAME}`,
dbURL: `mongodb://${envVars.DB_USER}:${envVars.DB_PASSWORD}@${envVars.DB_HOST}:${envVars.DB_PORT}`,
},
redis: {
host: envVars.REDIS_HOST,
port: envVars.REDIS_PORT,
password: envVars.REDIS_PASSWORD,
},
rabbitMQ: {
url: `amqp://${envVars.RABBIT_USER}:${envVars.RABBIT_PASSWORD}@${envVars.RABBIT_HOST}:${envVars.RABBIT_PORT}`,
},
discord: {
clientId: envVars.DISCROD_CLIENT_ID,
clientSecret: envVars.DISCORD_CLIENT_SECRET,
botToken: envVars.DISCORD_BOT_TOKEN,
},
sentry: {
dsn: envVars.SENTRY_DSN,
env: envVars.SENTRY_ENV,
},
logger: {
level: envVars.LOG_LEVEL,
},
};
22 changes: 22 additions & 0 deletions lib/config/logger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const pino_1 = __importDefault(require("pino"));
const index_1 = __importDefault(require("./index"));
exports.default = (0, pino_1.default)({
level: index_1.default.logger.level,
formatters: {
level: label => {
return { level: label.toUpperCase() };
},
},
timestamp: () => `,"timestamp":"${new Date(Date.now()).toISOString()}"`,
bindings: (bindings) => {
return {
pid: bindings.pid,
host: bindings.hostname,
};
},
});
24 changes: 24 additions & 0 deletions lib/database/connection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.closeConnection = void 0;
const logger_1 = __importDefault(require("../config/logger"));
const logger = logger_1.default.child({ module: 'Connection' });
/**
* Closes a given Mongoose connection.
* @param {Connection} connection - The Mongoose connection object to be closed.
* @returns {Promise<void>} - A promise that resolves when the connection has been successfully closed.
* @throws {MongooseError} - If there is an error closing the connection, it is logged to the console and the error is thrown.
*/
async function closeConnection(connection) {
try {
await connection.close();
logger.info({ database: connection.name }, 'The connection to database has been successfully closed');
}
catch (error) {
logger.fatal({ database: connection.name, error }, 'Failed to close the connection to the database');
}
}
exports.closeConnection = closeConnection;
19 changes: 19 additions & 0 deletions lib/database/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.connectDB = void 0;
const mongoose_1 = __importDefault(require("mongoose"));
const config_1 = __importDefault(require("../config"));
const logger_1 = __importDefault(require("../config/logger"));
async function connectDB() {
mongoose_1.default.set('strictQuery', false);
mongoose_1.default
.connect(config_1.default.mongoose.serverURL)
.then(() => {
logger_1.default.info({ url: config_1.default.mongoose.serverURL }, 'Connected to MongoDB!');
})
.catch(error => logger_1.default.error({ url: config_1.default.mongoose.serverURL, error }, 'Failed to connect to MongoDB!'));
}
exports.connectDB = connectDB;
150 changes: 150 additions & 0 deletions lib/database/services/channel.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const logger_1 = __importDefault(require("../../config/logger"));
const logger = logger_1.default.child({ module: 'ChannelService' });
/**
* Create a channel in the database.
* @param {Connection} connection - Mongoose connection object for the database.
* @param {IChannel} channel - The channel object to be created.
* @returns {Promise<IChannel|null>} - A promise that resolves to the created channel object.
*/
async function createChannel(connection, channel) {
try {
return await connection.models.Channel.create(channel);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}
catch (error) {
if (error.code == 11000) {
logger.warn({ database: connection.name, channel_id: channel.channelId }, 'Failed to create duplicate channel');
return null;
}
logger.error({ database: connection.name, channel_id: channel.channelId, error }, 'Failed to create channel');
return null;
}
}
/**
* Create channels in the database.
* @param {Connection} connection - Mongoose connection object for the database.
* @param {IChannel[]} channels - An array of channel objects to be created.
* @returns {Promise<IChannel[] | []>} - A promise that resolves to an array of the created channel objects.
*/
async function createChannels(connection, channels) {
try {
return await connection.models.Channel.insertMany(channels, { ordered: false });
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}
catch (error) {
if (error.code == 11000) {
logger.warn({ database: connection.name }, 'Failed to create duplicate channels');
return [];
}
logger.error({ database: connection.name, error }, 'Failed to create channels');
return [];
}
}
/**
* Get a channel from the database based on the filter criteria.
* @param {Connection} connection - Mongoose connection object for the database.
* @param {object} filter - An object specifying the filter criteria to match the desired channel entry.
* @returns {Promise<IChannel | null>} - A promise that resolves to the matching channel object or null if not found.
*/
async function getChannel(connection, filter) {
return await connection.models.Channel.findOne(filter);
}
/**
* Get channels from the database based on the filter criteria.
* @param {Connection} connection - Mongoose connection object for the database.
* @param {object} filter - An object specifying the filter criteria to match the desired channel entries.
* @returns {Promise<IChannel[] | []>} - A promise that resolves to an array of the matching channel objects.
*/
async function getChannels(connection, filter) {
return await connection.models.Channel.find(filter);
}
/**
* Update a channel in the database based on the filter criteria.
* @param {Connection} connection - Mongoose connection object for the database.
* @param {object} filter - An object specifying the filter criteria to match the desired channel entry.
* @param {IChannelUpdateBody} updateBody - An object containing the updated channel data.
* @returns {Promise<IChannel | null>} - A promise that resolves to the updated channel object or null if not found.
*/
async function updateChannel(connection, filter, updateBody) {
try {
const channel = await connection.models.Channel.findOne(filter);
if (!channel) {
return null;
}
Object.assign(channel, updateBody);
return await channel.save();
}
catch (error) {
logger.error({ database: connection.name, filter, updateBody, error }, 'Failed to update channel');
return null;
}
}
/**
* Update multiple channels in the database based on the filter criteria.
* @param {Connection} connection - Mongoose connection object for the database.
* @param {object} filter - An object specifying the filter criteria to match multiple channel entries.
* @param {IChannelUpdateBody} updateBody - An object containing the updated channel data.
* @returns {Promise<number>} - A promise that resolves to the number of updated channel entries.
*/
async function updateChannels(connection, filter, updateBody) {
try {
const updateResult = await connection.models.Channel.updateMany(filter, updateBody);
return updateResult.modifiedCount || 0;
}
catch (error) {
logger.error({ database: connection.name, filter, updateBody, error }, 'Failed to update channels');
return 0;
}
}
/**
* Handle the logic for creating or updating channels in the database.
* @param {Connection} connection - Mongoose connection object for the specific guild database.
* @param {TextChannel | VoiceChannel | CategoryChannel} channel - The Discord.js Channel object containing the full channel details.
* @returns {Promise<void>} - A promise that resolves when the create or update operation is complete.
*
*/
async function handelChannelChanges(connection, channel) {
const commonFields = getNeededDateFromChannel(channel);
try {
const channelDoc = await updateChannel(connection, { channelId: channel.id }, commonFields);
if (!channelDoc) {
await createChannel(connection, commonFields);
}
}
catch (error) {
logger.error({ guild_id: connection.name, channel_id: channel.id, error }, 'Failed to handle channel changes');
}
}
/**
* Extracts necessary fields from a Discord.js GuildMember object to form an IGuildMember object.
* @param {TextChannel | VoiceChannel | CategoryChannel} channel - The Discord.js Channel object containing the full channel details.
* @returns {IChannel} - The extracted data in the form of an IChannel object.
*/
function getNeededDateFromChannel(channel) {
return {
channelId: channel.id,
name: channel.name,
parentId: channel.parentId,
permissionOverwrites: Array.from(channel.permissionOverwrites.cache.values()).map(overwrite => ({
id: overwrite.id,
type: overwrite.type,
allow: overwrite.allow.bitfield.toString(),
deny: overwrite.deny.bitfield.toString(),
})),
};
}
exports.default = {
createChannel,
createChannels,
updateChannel,
getChannel,
getChannels,
updateChannels,
handelChannelChanges,
getNeededDateFromChannel,
};
75 changes: 75 additions & 0 deletions lib/database/services/guild.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const db_1 = require("@togethercrew.dev/db");
const logger_1 = __importDefault(require("../../config/logger"));
const logger = logger_1.default.child({ module: 'GuildService' });
/**
* get guild by query
* @param {Object} filter
* @returns {Promise<IGuild | null>}
*/
async function getGuild(filter) {
return db_1.Guild.findOne(filter);
}
/**
* Retrieve and return multiple guild entries that match the provided filter.
* @param {object} filter - Filter criteria to match the desired guild entries.
* @returns {Promise<object[]>} - A promise that resolves to an array of matching guild entries.
*/
async function getGuilds(filter) {
return await db_1.Guild.find(filter);
}
/**
* Update the guild entry that matches the provided filter with the provided data.
* @param {object} filter - Filter criteria to match the desired guild entry for update.
* @param {IGuildUpdateBody} updateBody - Updated information for the guild entry.
* @returns {Promise<object|null>} - A promise that resolves to the updated guild entry, or null if not found.
*/
async function updateGuild(filter, updateBody) {
try {
const guild = await db_1.Guild.findOne(filter);
if (!guild) {
return null;
}
Object.assign(guild, updateBody);
return await guild.save();
}
catch (error) {
logger.error({ database: 'RnDAO', filter, updateBody, error }, 'Failed to update guild');
return null;
}
}
/**
* Update multiple guild entries that match the provided filter with the provided data.
* @param {object} filter - Filter criteria to match the desired guild entries for update.
* @param {IGuildUpdateBody} updateBody - Updated information for the guild entry.
* @returns {Promise<number>} - A promise that resolves to the number of guild entries updated.
*/
async function updateManyGuilds(filter, updateBody) {
try {
const updateResult = await db_1.Guild.updateMany(filter, updateBody);
const modifiedCount = updateResult.modifiedCount;
return modifiedCount;
}
catch (error) {
logger.error({ database: 'RnDAO', filter, updateBody, error }, 'Failed to update guilds');
return 0;
}
}
async function checkBotAccessToGuild(client, guildId) {
if (!client.guilds.cache.has(guildId)) {
await updateGuild({ guildId }, { isDisconnected: false });
return false;
}
return true;
}
exports.default = {
getGuild,
getGuilds,
updateGuild,
updateManyGuilds,
checkBotAccessToGuild,
};
Loading

0 comments on commit c5cf4d2

Please sign in to comment.