Skip to content

Commit

Permalink
Merge pull request #84 from en3sis/feat/guildsPluginCache
Browse files Browse the repository at this point in the history
feat: guild plugin cache, deps update, prepares messageReaction
  • Loading branch information
en3sis authored Feb 13, 2024
2 parents f60469d + da0b734 commit 8431d54
Show file tree
Hide file tree
Showing 11 changed files with 136 additions and 70 deletions.
1 change: 1 addition & 0 deletions .env.template
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ DISCORD_TOKEN=
DISCORD_CLIENT_ID=

SUPABASE_URL=
SUPABASE_ANON_KEY=
SUPABASE_SERVICE_ROL=

#=========== 👾 BOT CONFIGURATION ===========#
Expand Down
Empty file removed config.json
Empty file.
20 changes: 10 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "hans",
"version": "v2.0.4",
"version": "v2.1.1",
"description": "An open-source Discord bot built with Discord.JS & TypeScript",
"author": "en3sis",
"repository": {
Expand All @@ -11,7 +11,7 @@
"main": "src/index.ts",
"scripts": {
"start": "node build/utils/deploy-commands.js && node build/index.js",
"dev": "docker-compose -f docker-compose.dev.yaml up -d &&ISDEV=true nodemon hans",
"dev": "docker-compose -f docker-compose.dev.yaml up -d && ISDEV=true nodemon hans",
"build": "tsc --project ./",
"types:local": "supabase gen types typescript --local --schema public > src/types/database.types.ts",
"build_dev": "rm -rf ./build && tsc --project ./",
Expand All @@ -25,21 +25,21 @@
"devDependencies": {
"@discordjs/rest": "^2.0.1",
"@jest/globals": "^29.7.0",
"@types/jest": "^29.5.4",
"@types/lodash": "^4.14.184",
"@types/node": "^20.5.9",
"@types/node-cron": "^3.0.4",
"@types/sentiment": "^5.0.1",
"@types/ws": "^8.5.3",
"@types/jest": "^29.5.12",
"@types/lodash": "^4.14.202",
"@types/node": "^20.11.17",
"@types/node-cron": "^3.0.11",
"@types/sentiment": "^5.0.4",
"@types/ws": "^8.5.10",
"@typescript-eslint/eslint-plugin": "^6.5.0",
"@typescript-eslint/parser": "^6.5.0",
"eslint": "^8.48.0",
"eslint-config-prettier": "^9.0.0",
"husky": "^8.0.1",
"jest": "^29.7.0",
"nodemon": "^3.0.1",
"nodemon": "^3.0.3",
"prettier": "^3.0.3",
"ts-node": "^10.9.1",
"ts-node": "^10.9.2",
"tslib": "^2.6.2",
"typescript": "^5.2.2"
},
Expand Down
4 changes: 3 additions & 1 deletion src/controllers/bot/guilds.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export const insertAllGuilds = async (Hans: Client) => {
})
.select()

// Set the guild plugins to the default values.
if (data)
guilds.forEach(async (guild) => {
try {
Expand All @@ -59,7 +60,8 @@ export const insertAllGuilds = async (Hans: Client) => {
throw error
}

console.log(`🪯 Initial ${data.length} guilds inserted/updated`)
console.info(`🪯 Initial ${data.length} guilds inserted/updated`)

return data
} catch (error) {
console.error('❌ ERROR: insertAllGuilds(): ', error)
Expand Down
26 changes: 18 additions & 8 deletions src/controllers/bot/plugins.controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { CommandInteraction } from 'discord.js'
import { getFromCache, setToCache } from '../../libs/node-cache'
import supabase from '../../libs/supabase'
import { initialGuildPluginState, pluginsList } from '../../models/plugins.model'
import {
Expand Down Expand Up @@ -82,6 +83,13 @@ export const resolveGuildPlugins = async (
pluginName: string,
): Promise<GuildPluginData> => {
try {
// Return the cached data if it exists
const cachedData = getFromCache(`guilds_plugins:${guild_id}:${pluginName}`)

if (cachedData) {
return cachedData as GuildPluginData
}

const { data: guildPluginResult } = await supabase
.from('guilds')
.select('*, guilds_plugins(*, plugins(enabled, description, premium, name))')
Expand All @@ -93,15 +101,19 @@ export const resolveGuildPlugins = async (
const guildPlugin = guildPluginResult?.guilds_plugins.find(
(ele: GuildPlugin) => ele.name === pluginName,
)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const globalPluginSettings: Record<string, any> = guildPlugin?.plugins

const botPlugin: Record<string, any> = guildPlugin?.plugins

if (guildPlugin && guildPlugin.enabled && botPlugin.enabled) {
return {
if (guildPlugin && guildPlugin.enabled && globalPluginSettings.enabled) {
const pluginData = {
enabled: guildPlugin?.enabled || false,
metadata: JSON.parse(JSON.stringify(guildPlugin?.metadata)),
data: guildPlugin,
}

setToCache(`guilds_plugins:${guild_id}:${pluginName}`, pluginData, 60 * 5)

return pluginData
} else {
return {
enabled: false,
Expand Down Expand Up @@ -160,7 +172,7 @@ export const updateMetadataGuildPlugin = async (metadata: any, name: string, gui
* Returns an array of plugin names and values for use in a select menu.
* @returns {Array<{name: string, value: string}>} - An array of plugin names and values.
*/
export const pluginsListNames = () => {
export const pluginsListNames = (): Array<{ name: string; value: string }> => {
return Object.entries(pluginsList).reduce((acc, [key]) => {
return [...acc, { name: key, value: key }]
}, [])
Expand Down Expand Up @@ -210,11 +222,9 @@ export const pluginChatGPTSettings = async (

// =+=+=+ Threads Plugin =+=+=+

/**
* Updates the metadata for the "threads" plugin in the database for the current guild.
/** Updates the metadata for the "threads" plugin in the database for the current guild.
* @param {PluginsThreadsSettings} options - The options object containing the interaction and metadata.
*/

export const pluginThreadsSettings = async ({ interaction, metadata }: PluginsThreadsSettings) => {
try {
const { data: guildsPlugins, error } = await supabase
Expand Down
13 changes: 8 additions & 5 deletions src/events/messageCreate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ module.exports = {
async execute(Hans: Client, message: Message) {
try {
if (message.author.bot) return
// const args = message.content.slice(1).trim().split(/ +/g)
// const command = args.shift().toLowerCase()

// Server outage
if (!message.guild?.available) return
Expand All @@ -24,9 +22,14 @@ module.exports = {
// +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=+
// ==-=-=-=-=-=-=-=-= DEVELOPMENT =-=-=-=-=-=-=-= +
// +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=+
// Uncomment for development and do your tests/debug there, !!!DON'T COMMIT!!!
// TODO: Requires refactor, find a way to dynamically load the file if in development
// _messageCreate(Hans, message, command, args)
// INFO: This is a development feature that allows to run commands without the need of a bot slash command, it will only work in development mode and it will try to run the command from the messageCreate.ts file. Make sure you duplicate and rename messageCreate.template.ts file.
if (!!process.env.ISDEV) {
const args = message.content.slice(1).trim().split(/ +/g)
const command = args.shift().toLowerCase()

const module = await import('../controllers/_development/messageCreate')
module.default(Hans, message, command, args)
}
} catch (error) {
console.log('❌ messageCreate(): ', error)
}
Expand Down
6 changes: 4 additions & 2 deletions src/events/messageReactionAdd.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Client, GuildMember, MessageReaction } from 'discord.js'

module.exports = {
name: 'ready',
once: true,
name: 'messageReactionAdd',
once: false,
enabled: false,
async execute(Hans: Client, reaction: MessageReaction, member: GuildMember) {
if (reaction.partial) {
Expand All @@ -15,6 +15,8 @@ module.exports = {
return
}
}

// TODO @en3sis: Implement the messageReactionAdd event
console.log('', {
reaction,
member,
Expand Down
26 changes: 26 additions & 0 deletions src/events/messageReactionRemove.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Client, GuildMember, MessageReaction } from 'discord.js'

module.exports = {
name: 'messageReactionRemove',
once: false,
enabled: false,
async execute(Hans: Client, reaction: MessageReaction, member: GuildMember) {
if (reaction.partial) {
// If the message this reaction belongs to was removed, the fetching might result in an API error which should be handled
try {
await reaction.fetch()
} catch (error) {
console.error('Something went wrong when fetching the message:', error)
// Return as `reaction.message.author` may be undefined/null
return
}
}

// TODO @en3sis: Implement the messageReactionAdd event
console.log('💢', {
reaction,
foo: reaction.emoji.id,
member,
})
},
}
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ export const Hans = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.GuildMessageReactions,
GatewayIntentBits.GuildMembers,
GatewayIntentBits.MessageContent,
],
partials: [Partials.Message, Partials.Channel, Partials.Reaction],
})
Expand Down
20 changes: 19 additions & 1 deletion src/realtime/presence.realtime.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { setPresence } from '../controllers/bot/config.controller'
import { deleteFromCache } from '../libs/node-cache'
import supabase from '../libs/supabase'

export const configsRealtime = () => {
return supabase
// Listen for changes in the configs table
supabase
.channel('table-db-changes')
.on(
'postgres_changes',
Expand All @@ -16,4 +18,20 @@ export const configsRealtime = () => {
},
)
.subscribe()

// Listen for changes in the guilds plugins table and delete the cached data
supabase
.channel('table-db-changes')
.on(
'postgres_changes',
{
event: 'UPDATE',
schema: 'public',
table: 'guilds_plugins',
},
async (payload) => {
deleteFromCache(`guildPlugins:${payload.new.owner}:${payload.new.name}`)
},
)
.subscribe()
}
Loading

0 comments on commit 8431d54

Please sign in to comment.