Skip to content

Instantly share code, notes, and snippets.

@xkisu
Created April 16, 2018 06:46
Show Gist options
  • Save xkisu/f0490a8e6e10a35a8cede4d956feba73 to your computer and use it in GitHub Desktop.
Save xkisu/f0490a8e6e10a35a8cede4d956feba73 to your computer and use it in GitHub Desktop.
MongoProvider for discord.js Commando
const SettingProvider = require('discord.js-commando/src/providers/base')
const mongoose = require('mongoose')
const Settings = mongoose.model('Setting', new mongoose.Schema({
guild: {
type: String,
required: true,
unique: true,
index: true
},
settings: {
type: Object,
default: {}
}
}))
/**
* Uses a Mongo database to store settings with guilds
* @extends {SettingProvider}
*/
class MongoProvider extends SettingProvider {
/**
* @param {String} url - Mongodb URL
*/
constructor (url) {
super()
/**
* Database url that will be used by mongoose
* @type {String}
*/
this.url = url
/**
* Client that the provider is for (set once the client is ready, after using {@link CommandoClient#setProvider})
* @name MongoProvider#client
* @type {CommandoClient}
* @readonly
*/
Object.defineProperty(this, 'client', { value: null, writable: true })
/**
* Listeners on the Client, mapped by the event name
* @type {Map}
* @private
*/
this.listeners = new Map()
}
async init(client) {
this.client = client
console.log('init')
const settings = await Settings.find({}).exec()
console.log(settings)
console.log(client.guilds)
for(let i = 0; i < settings.length; ++i) {
const guildid = settings[i].guild
const guildSettings = settings[i].settings || {}
console.log(`${guildid} !== 'global' = ` + (guildid !== 'global'))
console.log(`!client.guilds.has(${guildid}) = ` + (!client.guilds.has(''+guildid)))
if(guildid !== 'global' && !client.guilds.has(''+guildid)) continue
console.log('setting up guild ' + guildid)
console.log(guildSettings)
this.setupGuild(guildid, guildSettings)
}
this.listeners
.set('commandPrefixChange', (guild, prefix) => this.set(guild, 'prefix', prefix))
.set('commandStatusChange', (guild, command, enabled) => this.set(guild, `cmd-${command.name}`, enabled))
.set('groupStatusChange', (guild, group, enabled) => this.set(guild, `grp-${group.id}`, enabled))
.set('guildCreate', async (guild) => {
const settingsDocument = await Settings.findOne({ guild: guild }).exec()
if(!settingsDocument) return
this.setupGuild(guild.id, settingsDocument.settings)
})
.set('commandRegister', async (command) => {
const settings = await Settings.find({}).exec()
for(let i = 0; i < settings.length; ++i) {
const guild = settings[i].guild
const guildSettings = settings[i].settings || {}
if(guild !== 'global' && !client.guilds.has(guild)) continue
this.setupGuildCommand(client.guilds.get(guild), command, guildSettings)
}
})
.set('groupRegister', async (group) => {
const settings = await Settings.find({}).exec()
for(let i = 0; i < settings.length; ++i) {
const guild = settings[i].guild
const guildSettings = settings[i].settings || {}
if(guild !== 'global' && !client.guilds.has(guild)) continue;
this.setupGuildGroup(client.guilds.get(guild), group, guildSettings)
}
})
for(const [event, listener] of this.listeners) client.on(event, listener)
}
destroy () {
for(const [event, listener] of this.listeners) this.client.removeListener(event, listener);
this.listeners.clear()
}
async get (guild, key, defaultVal) {
const guildid = this.constructor.getGuildID(guild)
const settingsDocument = await Settings.findOne({ guild: guildid }).exec()
if(!settingsDocument.settings)
settingsDocument.settings = {}
return settingsDocument ? typeof settingsDocument.settings[key] !== 'undefined' ? settingsDocument.settings[key] : defVal : defVal
}
async set (guild, key, val) {
console.log(`${guild} ${key} ${val}`)
const guildid = this.constructor.getGuildID(guild)
const settingsDocument = await this.getOrCreateGuild(guildid)
if(settingsDocument.settings == undefined)
settingsDocument.settings = {}
settingsDocument.set('settings.'+key, val)
await settingsDocument.save()
console.log(settingsDocument)
if(guildid === 'global') this.updateOtherShards(key, val)
return val
}
async remove (guild, key) {
const guildid = this.constructor.getGuildID(guild)
const settingsDocument = await Settings.findOne({ guild: guildid }).exec()
if(!settingsDocument || typeof settingsDocument.settings[key] === 'undefined') return undefined
const val = settingsDocument[key]
settingsDocument[key] = undefined
await settingsDocument.save()
if(guildid === 'global') this.updateOtherShards(key, undefined)
return val
}
async clear (guild) {
const guildid = this.constructor.getGuildID(guild)
const settingsDocument = await Settings.findOne({ guild: guildid }).exec()
if(!settingsDocument) return
await settingsDocument.remove()
}
async getOrCreateGuild (guildid) {
const settingsDocument = await Settings.findOne({ guild: guildid }).exec()
if(!settingsDocument) {
const guildSettings = new Settings()
guildSettings.guild = guildid
guildSettings.settings = {}
await guildSettings.save()
return guildSettings
} else {
return settingsDocument
}
}
/**
* Loads all settings for a guild
* @param {string} guild - Guild ID to load the settings of (or 'global')
* @param {Object} settings - Settings to load
* @private
*/
setupGuild(guild, settings) {
if(typeof guild !== 'string') throw new TypeError('The guild must be a guild ID or "global".');
guild = this.client.guilds.get(guild) || null;
// Load the command prefix
if(typeof settings.prefix !== 'undefined') {
if(guild) guild._commandPrefix = settings.prefix;
else this.client._commandPrefix = settings.prefix;
}
// Load all command/group statuses
for(const command of this.client.registry.commands.values()) this.setupGuildCommand(guild, command, settings);
for(const group of this.client.registry.groups.values()) this.setupGuildGroup(guild, group, settings);
}
/**
* Sets up a command's status in a guild from the guild's settings
* @param {?CommandoGuild} guild - Guild to set the status in
* @param {Command} command - Command to set the status of
* @param {Object} settings - Settings of the guild
* @private
*/
setupGuildCommand(guild, command, settings) {
if(typeof settings[`cmd-${command.name}`] === 'undefined') return;
if(guild) {
if(!guild._commandsEnabled) guild._commandsEnabled = {};
guild._commandsEnabled[command.name] = settings[`cmd-${command.name}`];
} else {
command._globalEnabled = settings[`cmd-${command.name}`];
}
}
/**
* Sets up a command group's status in a guild from the guild's settings
* @param {?CommandoGuild} guild - Guild to set the status in
* @param {CommandGroup} group - Group to set the status of
* @param {Object} settings - Settings of the guild
* @private
*/
setupGuildGroup(guild, group, settings) {
if(typeof settings[`grp-${group.id}`] === 'undefined') return;
if(guild) {
if(!guild._groupsEnabled) guild._groupsEnabled = {};
guild._groupsEnabled[group.id] = settings[`grp-${group.id}`];
} else {
group._globalEnabled = settings[`grp-${group.id}`];
}
}
/**
* Updates a global setting on all other shards if using the {@link ShardingManager}.
* @param {string} key - Key of the setting to update
* @param {*} val - Value of the setting
* @private
*/
updateOtherShards(key, val) {
if(!this.client.shard) return;
key = JSON.stringify(key);
val = typeof val !== 'undefined' ? JSON.stringify(val) : 'undefined';
this.client.shard.broadcastEval(`
if(this.shard.id !== ${this.client.shard.id} && this.provider && this.provider.settings) {
let global = this.provider.settings.get('global');
if(!global) {
global = {};
this.provider.settings.set('global', global);
}
global[${key}] = ${val};
}
`);
}
}
module.exports = MongoProvider
@xkisu
Copy link
Author

xkisu commented Apr 16, 2018

This assumes that you have made the mongoose connection before initializing Commando and creating the provider

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment