-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit fb98df3
Showing
15 changed files
with
2,771 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
name: main | ||
|
||
on: | ||
push: | ||
branches: | ||
- main | ||
|
||
jobs: | ||
check: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v2 | ||
|
||
- name: Set Node.js to 16.x | ||
uses: actions/setup-node@v2.5.1 | ||
with: | ||
node-version: 16.x | ||
|
||
- name: Install dependencies | ||
run: | | ||
npm install | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
node_modules/ | ||
.env |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# MMS-Commission |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
const { Client, GatewayIntentBits, Partials, Collection } = require("discord.js"); | ||
const { config } = require('dotenv'); | ||
config(); | ||
|
||
const client = new Client({ | ||
intents: Object.values(GatewayIntentBits), | ||
partials: Object.values(Partials), | ||
shards: "auto", | ||
allowedMentions: { | ||
parse: ["roles", "users", "everyone"], | ||
repliedUser: false, | ||
}, | ||
}); | ||
|
||
client.slashData = []; | ||
client.commands = new Collection(); | ||
client.token = process.env.TOKEN; | ||
|
||
const ResourceManager = new (require('./managers/ResourceManager'))(client); | ||
const DatabaseManager = new (require('./managers/DatabaseManager'))(); | ||
const CacheManager = new (require('./managers/CacheManager'))(); | ||
|
||
client.login(client.token).finally(async () => { | ||
|
||
await ResourceManager.loadCmdData('../src'); | ||
console.log( | ||
`${ResourceManager.prefix} Loaded ${(ResourceManager.totalSize / 1024).toFixed(2)}MB of resources` | ||
); | ||
|
||
DatabaseManager.connect(process.env.DATABASE); | ||
CacheManager.connect(process.env.REDIS_CACHE); | ||
|
||
client.database = DatabaseManager; | ||
client.cache = CacheManager; | ||
|
||
console.log(`[DISCORD] Logged in as ${client.user.tag}`); | ||
}); | ||
|
||
const handleErrors = (type, err, origin) => { | ||
console.log(`\n\n\n\n\n=== ${type.toUpperCase()} ===`); | ||
console.log(type === 'unhandledRejection' ? `Reason: ${err.stack ? String(err.stack) : String(err)}` : `Exception: ${err.stack ? err.stack : err}`); | ||
console.log(`=== ${type.toUpperCase()} ===\n\n\n\n\n`); | ||
}; | ||
|
||
process.on('unhandledRejection', (reason, p) => handleErrors('unhandledRejection', reason)); | ||
process.on('uncaughtException', (err, origin) => handleErrors('uncaughtException', err)); | ||
process.on('uncaughtExceptionMonitor', (err, origin) => console.log('=== uncaught Exception Monitor ==='.toUpperCase())); | ||
process.on('beforeExit', code => { | ||
console.log('\n\n\n\n\n=== before Exit ==='.toUpperCase()); | ||
console.log(`Code: ${code}`); | ||
console.log('=== before Exit ===\n\n\n\n\n'); | ||
}); | ||
process.on('exit', code => { | ||
console.log('\n\n\n\n\n=== exit ==='.toUpperCase()); | ||
console.log(`Code: ${code}`); | ||
console.log('=== exit ===\n\n\n\n\n'); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
const { ShardingManager } = require('discord.js'); | ||
require('dotenv').config(); | ||
|
||
const shard = new ShardingManager('./bot.js', { | ||
totalShards: 'auto', | ||
token: process.env.TOKEN | ||
}); | ||
|
||
shard.on("shardCreate", async (shard) => { | ||
console.log(`[SHARDING] Launched shard #${shard.id}`) | ||
}) | ||
|
||
shard.spawn({timeout: -1}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
const { createClient } = require('redis'); | ||
|
||
class CacheManager { | ||
|
||
constructor() { | ||
this.prefix = '[CACHE]'; | ||
this.redisClient; | ||
} | ||
|
||
async connect(redisURI) { | ||
this.redisClient = await createClient({ | ||
url: redisURI | ||
}) | ||
.on('connect', () => { | ||
console.log(`${this.prefix} Established connection with Cache`); | ||
}) | ||
.connect(); | ||
} | ||
|
||
async setGuildData(guildID, data) { | ||
const key = `bot_${guildID}`; | ||
const value = JSON.stringify(data); | ||
await this.redisClient.set(key, value); | ||
} | ||
|
||
async getGuildData(guildID) { | ||
const key = `bot_${guildID}`; | ||
const data = await this.redisClient.get(key); | ||
return data ? JSON.parse(data) : false; | ||
} | ||
|
||
async invalidate(client, keys) { | ||
const Messages = client.database.messageSchema; | ||
|
||
for (const key of keys) { | ||
|
||
const startTime = Date.now(); | ||
const guildId = key.split('_')[1]; | ||
let data = await this.redisClient.get(key); | ||
data = JSON.parse(data); | ||
const filter = { guildId }; | ||
|
||
const bulkOperations = Object.entries(data.channels) | ||
.flatMap(([channelID, channelDataForDates]) => | ||
Object.entries(channelDataForDates) | ||
.flatMap(([date, userData]) => | ||
Object.entries(userData) | ||
.map(([userId, count]) => ({ | ||
updateOne: { | ||
filter, | ||
update: { | ||
$inc: { | ||
[`channels.${channelID}.${date}.${userId}`]: count, | ||
}, | ||
}, | ||
upsert: true, | ||
}, | ||
})) | ||
) | ||
); | ||
|
||
try { | ||
await Messages.bulkWrite(bulkOperations); | ||
} catch (err) { | ||
console.error(`${this.prefix} Error Bulk Writing Operations:`, err); | ||
} | ||
|
||
try { | ||
await this.redisClient.del(key); | ||
} catch (err) { | ||
console.error(`${this.prefix} Error deleting Redis key:`, err); | ||
} | ||
|
||
console.log(`${this.prefix} Redis cache invalidated successfully for: ${guildId} - ${Date.now() - startTime}ms.`); | ||
} | ||
} | ||
|
||
async startInvalidationInterval(client) { | ||
setInterval(async () => { | ||
const keys = await this.redisClient.keys('bot_*'); | ||
if (keys.length) { | ||
console.log(`${this.prefix} Redis cache beginning to invalidate & store.`); | ||
await this.invalidate(client, keys); | ||
} else { | ||
console.log(`${this.prefix} No Queued Guilds for Cache Invalidation.`); | ||
} | ||
}, 10000); | ||
} | ||
|
||
} | ||
|
||
module.exports = CacheManager; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
const mongoose = require('mongoose'); | ||
const messageSchema = require('../models/Messages') | ||
|
||
class DatabaseManager { | ||
constructor() { | ||
this.prefix = '[DATABASE]'; | ||
this.messageSchema = messageSchema; | ||
this.localCache = { | ||
guildId: String, | ||
channels: { | ||
[String]: { | ||
[String]: { | ||
[String]: Number, | ||
}, | ||
}, | ||
}, | ||
} | ||
} | ||
async connect(mongoURI) { | ||
mongoose.connect(mongoURI) | ||
mongoose.connection.once('error', console.error); | ||
mongoose.connection.on('open', () => { | ||
console.log(`${this.prefix} Established connection with database`); | ||
}); | ||
} | ||
|
||
} | ||
|
||
module.exports = DatabaseManager; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
const { REST } = require("@discordjs/rest"); | ||
const { Routes } = require("discord-api-types/v10"); | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
const Command = require('../structures/Command.js'); | ||
const Event = require('../structures/Event.js'); | ||
|
||
function formatBytes(x) { | ||
const units = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; | ||
let l = 0, n = parseInt(x, 10) || 0; | ||
while (n >= 1024 && ++l) { | ||
n = n / 1024; | ||
} | ||
return n.toFixed(n < 10 && l > 0 ? 1 : 0) + ' ' + units[l]; | ||
} | ||
|
||
class ResourceManager { | ||
constructor(client = null) { | ||
this.client = client; | ||
this.prefix = '[RESOURCE]'; | ||
this.totalSize = 0; | ||
} | ||
|
||
async loadCmdData(dir = '') { | ||
const SlashCommands = []; | ||
const rest = new REST({ version: "10" }).setToken(this.client.token); | ||
const _path = path.join(__dirname, dir); | ||
const files = fs.readdirSync(_path); | ||
|
||
for (const file of files) { | ||
const fullPath = path.join(_path, file); | ||
const stat = fs.lstatSync(fullPath); | ||
this.totalSize += parseFloat(stat.size); | ||
|
||
if (stat.isDirectory()) { | ||
await this.loadCmdData(path.join(dir, file)); | ||
} | ||
|
||
if (file.endsWith('.js')) { | ||
let _file = require(fullPath); | ||
|
||
if (_file.prototype instanceof Command) { | ||
let command = new _file(); | ||
if (!command.name || !command.description) { | ||
console.log(`${this.prefix} Invalid command : ❌ ${file}`); | ||
continue; | ||
} | ||
|
||
this.client.commands.set(command.name, command); | ||
try { | ||
SlashCommands.push(command); | ||
await rest.put(Routes.applicationCommands(this.client.user.id), { body: SlashCommands }); | ||
} catch (err) { | ||
console.error(err); | ||
} | ||
|
||
this.client.commands.categories = command => { | ||
let cats = command ? '' : []; | ||
const dir = '../src/modules/'; | ||
const _path = path.join(__dirname, dir); | ||
const categories = fs.readdirSync(_path); | ||
|
||
categories.forEach((module, key) => { | ||
const cmdDir = `${dir}/${module}`; | ||
const cmdPath = path.join(__dirname, cmdDir); | ||
command ? cats : (cats[module] = []); | ||
const files = fs.readdirSync(cmdPath).filter(g => g.endsWith('js')); | ||
|
||
for (const file of files) { | ||
const Command = require(path.join(cmdPath, file)); | ||
const cmd = new Command(); | ||
if (!command) cats[module].push(cmd); | ||
if (command && command.name == cmd.name) { | ||
return (cats = module); | ||
} | ||
} | ||
}); | ||
return cats; | ||
}; | ||
|
||
console.log(`${this.prefix} Registered Slash : ✔️ ${command.name} (${formatBytes(stat.size)})`); | ||
} | ||
|
||
if (_file.prototype instanceof Event) { | ||
let event = new _file(); | ||
if (!event.name || event.once === undefined) { | ||
console.log(`${this.prefix} Invalid event : ❌ ${file}`); | ||
continue; | ||
} | ||
|
||
if (event.once) { | ||
this.client.once(event.name, event.execute.bind(event, this.client)); | ||
} else { | ||
this.client.on(event.name, event.execute.bind(event, this.client)); | ||
} | ||
|
||
console.log(`${this.prefix} Loaded event : ✔️ ${file} (${formatBytes(stat.size)})`); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
module.exports = ResourceManager; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
const mongoose = require('mongoose'); | ||
|
||
const messageSchema = new mongoose.Schema({ | ||
guildId: String, | ||
channels: Object, | ||
}, { versionKey: false }); | ||
|
||
module.exports = mongoose.model('Message', messageSchema); |
Oops, something went wrong.