This repository has been archived by the owner on Dec 19, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 8
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
Matthew Ray
committed
Nov 11, 2018
1 parent
0ac41a3
commit bea6cb5
Showing
9 changed files
with
360 additions
and
11 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
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
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
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,117 @@ | ||
if (Number(process.version.slice(1).split('.')[0]) < 8) throw new RangeError('Node 8.0.0 or higher is required. Update Node on your system.'); | ||
|
||
const Discord = require('discord.js'); | ||
//const sentryconfig = require('./sentry.json'); | ||
//const Raven = require('raven'); | ||
//Raven.config(sentryconfig.link).install(); | ||
const { promisify } = require('util'); | ||
const readdir = promisify(require('fs').readdir); | ||
const Enmap = require('enmap'); | ||
const EnmapLevel = require('enmap-sqlite'); //eslint-disable-line no-unused-vars | ||
|
||
const client = new Discord.Client({ | ||
fetchAllMembers: true, | ||
disableEveryone: true, | ||
//shardId: process.argv[1], | ||
//shardCount: process.argv0[2], | ||
}); | ||
|
||
|
||
client.config = require('./config.js'); | ||
// client.config.token contains the bot's token | ||
// client.config.prefix contains the message prefix | ||
//k | ||
|
||
client.logger = require('./modules/Logger.ts'); | ||
|
||
require('./modules/functions.ts')(client); | ||
|
||
client.commands = new Enmap(); | ||
client.aliases = new Enmap(); | ||
|
||
|
||
client.settings = new Enmap({ | ||
name: 'settings', | ||
autoFetch: true}); | ||
|
||
client.blackList = new Enmap({ | ||
name: 'blackList', | ||
autofetch: true, | ||
fetchAll:true | ||
}); | ||
|
||
client.alerts = new Enmap({ | ||
name: 'alerts', | ||
autofetch: true, | ||
fetchAll: true | ||
}); | ||
|
||
client.stats = new Enmap({ | ||
name: 'stats', | ||
autoFetch: true, | ||
fetchAll: true}); | ||
|
||
client.activatedServers = new Enmap({ | ||
name: 'activatedServers', | ||
autofetch: true, | ||
fetchAll: true}); | ||
|
||
client.credits = new Enmap({ | ||
name: 'credits', | ||
autoFetch: true, | ||
fetchAll: true | ||
}); | ||
|
||
client.repPoints = new Enmap({ | ||
name: 'reputation', | ||
autoFetch: true, | ||
fetchAll: true | ||
}); | ||
|
||
client.userTitle = new Enmap({ | ||
name: 'title', | ||
autoFetch: true, | ||
fetchAll: true | ||
}); | ||
|
||
client.userBio = new Enmap({ | ||
name: 'bio', | ||
autoFetch: true, | ||
fetchAll: true | ||
}); | ||
|
||
const init = async () => { | ||
|
||
const { join } = require('path'); | ||
const commands = await readdir(join(__dirname, './commands/')); | ||
client.logger.log(`Loading a total of ${commands.length} commands.`); | ||
commands.forEach(f => { | ||
if (!f.endsWith('.js' || '.ts')) return; | ||
const response = client.loadCommand(f); | ||
if (response) console.log(response); | ||
}); | ||
|
||
|
||
|
||
const evtFiles = await readdir(join(__dirname, './events/')); | ||
client.logger.log(`Loading a total of ${evtFiles.length} events.`); | ||
evtFiles.forEach(file => { | ||
const eventName = file.split('.')[0]; | ||
client.logger.log(`Loading Event: ${eventName}`); | ||
const event = require(`./events/${file}`); | ||
client.on(eventName, event.bind(null, client)); | ||
}); | ||
|
||
// Generate a cache of client permissions for pretty perm names in commands. | ||
client.levelCache = {}; | ||
for (let i = 0; i < client.config.permLevels.length; i++) { | ||
const thisLevel = client.config.permLevels[i]; | ||
client.levelCache[thisLevel.name] = thisLevel.level; | ||
} | ||
|
||
// Here we login the client. | ||
client.login(client.config.token); | ||
|
||
}; | ||
|
||
init(); |
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,38 @@ | ||
/* | ||
Logger class for easy and aesthetically pleasing console logging | ||
*/ | ||
const moment = require('moment'); | ||
const chalk = require('chalk'); | ||
|
||
exports.log = (content : string, type = 'log') => { | ||
const timestamp = `[${moment().format('YYYY-MM-DD HH:mm:ss')}]:`; | ||
switch (type) { | ||
case 'log': { | ||
return console.log(`${timestamp} ${chalk.bgBlue(type.toUpperCase())} ${content} `); | ||
} | ||
case 'warn': { | ||
return console.log(`${timestamp} ${chalk.black.bgYellow(type.toUpperCase())} ${content} `); | ||
} | ||
case 'error': { | ||
return console.log(`${timestamp} ${chalk.bgRed(type.toUpperCase())} ${content} `); | ||
} | ||
case 'debug': { | ||
return console.log(`${timestamp} ${chalk.green(type.toUpperCase())} ${content} `); | ||
} | ||
case 'cmd': { | ||
return console.log(`${timestamp} ${chalk.black.bgWhite(type.toUpperCase())} ${content}`); | ||
} | ||
case 'ready': { | ||
return console.log(`${timestamp} ${chalk.black.bgGreen(type.toUpperCase())} ${content}`); | ||
} | ||
default: throw new TypeError('Logger type must be either warn, debug, log, ready, cmd or error.'); | ||
} | ||
}; | ||
|
||
exports.error = (...args) => this.log(...args, 'error'); | ||
|
||
exports.warn = (...args) => this.log(...args, 'warn'); | ||
|
||
exports.debug = (...args) => this.log(...args, 'debug'); | ||
|
||
exports.cmd = (...args) => this.log(...args, 'cmd'); |
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,178 @@ | ||
const sentryconfig = require('../sentry.json') | ||
const Raven = require('raven'); | ||
Raven.config(sentryconfig.link).install(); | ||
module.exports = (client: any) => { | ||
|
||
/* | ||
PERMISSION LEVEL FUNCTION | ||
This is a very basic permission system for commands which uses "levels" | ||
"spaces" are intentionally left black so you can add them if you want. | ||
NEVER GIVE ANYONE BUT OWNER THE LEVEL 10! By default this can run any | ||
command including the VERY DANGEROUS `eval` and `exec` commands! | ||
*/ | ||
client.permlevel = message => { | ||
let permlvl = 0; | ||
|
||
const permOrder = client.config.permLevels.slice(0).sort((p, c) => p.level < c.level ? 1 : -1); | ||
|
||
while (permOrder.length) { | ||
const currentLevel = permOrder.shift(); | ||
if (message.guild && currentLevel.guildOnly) continue; | ||
if (currentLevel.check(message)) { | ||
permlvl = currentLevel.level; | ||
break; | ||
} | ||
} | ||
return permlvl; | ||
}; | ||
|
||
/* | ||
GUILD SETTINGS FUNCTION | ||
This function merges the default settings (from config.defaultSettings) with any | ||
guild override you might have for particular guild. If no overrides are present, | ||
the default settings are used. | ||
*/ | ||
client.getGuildSettings = (guild: any) => { | ||
const def = client.config.defaultSettings; | ||
if (!guild) return def; | ||
const returns = {}; | ||
const overrides = client.settings.get(guild.id) || {}; | ||
for (const key in def) { | ||
returns[key] = overrides[key] || def[key]; | ||
} | ||
return returns; | ||
}; | ||
|
||
/* | ||
SINGLE-LINE AWAITMESSAGE | ||
A simple way to grab a single reply, from the user that initiated | ||
the command. Useful to get "precisions" on certain things... | ||
USAGE | ||
const response = await client.awaitReply(msg, "Favourite Color?"); | ||
msg.reply(`Oh, I really love ${response} too!`); | ||
*/ | ||
client.awaitReply = async (msg: any, question: string[], limit = 60000) => { | ||
const filter = m => m.author.id === msg.author.id; | ||
await msg.channel.send(question); | ||
try { | ||
const collected = await msg.channel.awaitMessages(filter, { max: 1, time: limit, errors: ['time'] }); | ||
return collected.first().content; | ||
} catch (e) { | ||
return false; | ||
} | ||
}; | ||
|
||
|
||
/* | ||
MESSAGE CLEAN FUNCTION | ||
"Clean" removes @everyone pings, as well as tokens, and makes code blocks | ||
escaped so they're shown more easily. As a bonus it resolves promises | ||
and stringifies objects! | ||
This is mostly only used by the Eval and Exec commands. | ||
*/ | ||
client.clean = async (client, text) => { | ||
if (text && text.constructor.name == 'Promise') | ||
text = await text; | ||
if (typeof evaled !== 'string') | ||
text = require('util').inspect(text, {depth: 1}); | ||
|
||
text = text | ||
.replace(/`/g, '`' + String.fromCharCode(8203)) | ||
.replace(/@/g, '@' + String.fromCharCode(8203)) | ||
.replace(client.token, '[TOKEN]'); | ||
|
||
return text; | ||
}; | ||
interface ClientCommands { | ||
command: string, | ||
shutdown: any, | ||
commands?: string[] | ||
} | ||
client.loadCommand = (commandName) => { | ||
try { | ||
client.logger.log(`Loading Command: ${commandName}`); | ||
const props = require(`../commands/${commandName}`); | ||
if (props.init) { | ||
props.init(client); | ||
} | ||
client.commands.set(props.help.name, props); | ||
props.conf.aliases.forEach(alias => { | ||
client.aliases.set(alias, props.help.name); | ||
}); | ||
return false; | ||
} catch (e) { | ||
return `Unable to load command ${commandName}: ${e}`; | ||
} | ||
}; | ||
|
||
client.unloadCommand = async (commandName: string) => { | ||
|
||
let command : ClientCommands | ||
if (client.commands.has(commandName)) { | ||
command = client.commands.get(commandName); | ||
} else if (client.aliases.has(commandName)) { | ||
command = client.commands.get(client.aliases.get(commandName)); | ||
} | ||
if (!command) return `The command \`${commandName}\` doesn't seem to exist, nor is it an alias. Try again!`; | ||
|
||
if (command.shutdown) { | ||
await command.shutdown(client); | ||
} | ||
const mod = require.cache[require.resolve(`../commands/${commandName}`)]; | ||
delete require.cache[require.resolve(`../commands/${commandName}.js`)]; | ||
for (let i = 0; i < mod.parent.children.length; i++) { | ||
if (mod.parent.children[i] === mod) { | ||
mod.parent.children.splice(i, 1); | ||
break; | ||
} | ||
} | ||
return false; | ||
}; | ||
|
||
/* MISCELANEOUS NON-CRITICAL FUNCTIONS */ | ||
|
||
// EXTENDING NATIVE TYPES IS BAD PRACTICE. Why? Because if JavaScript adds this | ||
// later, this conflicts with native code. Also, if some other lib you use does | ||
// this, a conflict also occurs. KNOWING THIS however, the following 2 methods | ||
// are, we feel, very useful in code. | ||
|
||
// <String>.toPropercase() returns a proper-cased string such as: | ||
// "Mary had a little lamb".toProperCase() returns "Mary Had A Little Lamb" | ||
/*String.prototype.toProperCase = function() { | ||
return this.replace(/([^\W_]+[^\s-]*) *///g, function(txt) {return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();}); | ||
//}; | ||
|
||
// <Array>.random() returns a single random element from an array | ||
// [1, 2, 3, 4, 5].random() can return 1, 2, 3, 4 or 5. | ||
/*Array.prototype.random= function() { | ||
return this[Math.floor(Math.random() * this.length)]; | ||
};*/ | ||
|
||
// `await client.wait(1000);` to "pause" for 1 second. | ||
client.wait = require('util').promisify(setTimeout); | ||
|
||
// These 2 process methods will catch exceptions and give *more details* about the error and stack trace. | ||
process.on('uncaughtException', (err) => { | ||
const errorMsg = err.stack.replace(new RegExp(`${__dirname}/`, 'g'), './'); | ||
client.logger.error(`Uncaught Exception Error: ${errorMsg}`); | ||
//Raven.captureException(err); | ||
// Always best practice to let the code crash on uncaught exceptions. | ||
// Because you should be catching them anyway. | ||
process.exit(1); | ||
}); | ||
|
||
process.on('unhandledRejection', err => { | ||
client.logger.error(`Unhandled Rejection Error: ${err}`); | ||
//client.channels.get('503374059044601872').send(err); | ||
Raven.captureException(err); | ||
}); | ||
}; |
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,7 @@ | ||
const { ShardingManager } = require('discord.js'); | ||
const manager = new ShardingManager('./index.js', { totalShards: 1 }); | ||
|
||
manager.spawn(); | ||
manager.on('launch', shard => console.log(`Launched shard ${shard.id}`)); | ||
|
||
|
Oops, something went wrong.