feat: added events and commands

This commit is contained in:
Rauf 2020-01-13 17:38:12 -05:00
parent 2fb4842994
commit bf24b9f46b
15 changed files with 324 additions and 42 deletions

126
package-lock.json generated
View file

@ -76,6 +76,11 @@
}
}
},
"@discordjs/collection": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.3.tgz",
"integrity": "sha512-4ek19SmNcPI92942RkuBrZrBK8hg7nG+ae/skkNNDeOaUG+XvxTPkv/jPZVgXwVPDkU5EFsewsI+0n4dTwFvgA=="
},
"@sindresorhus/is": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz",
@ -100,8 +105,23 @@
"@types/node": {
"version": "10.17.13",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.13.tgz",
"integrity": "sha512-pMCcqU2zT4TjqYFrWtYHKal7Sl30Ims6ulZ4UFXxI4xbtQqK/qqKwkDoBFCfooRqqmRu9vY3xaJRwxSh673aYg==",
"dev": true
"integrity": "sha512-pMCcqU2zT4TjqYFrWtYHKal7Sl30Ims6ulZ4UFXxI4xbtQqK/qqKwkDoBFCfooRqqmRu9vY3xaJRwxSh673aYg=="
},
"@types/ws": {
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-6.0.4.tgz",
"integrity": "sha512-PpPrX7SZW9re6+Ha8ojZG4Se8AZXgf0GK6zmfqEuCsY49LFDNXO3SByp44X3dFEqtB73lkCDAdUazhAjVPiNwg==",
"requires": {
"@types/node": "*"
}
},
"abort-controller": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
"requires": {
"event-target-shim": "^5.0.0"
}
},
"ansi-align": {
"version": "3.0.0",
@ -183,10 +203,10 @@
"integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=",
"dev": true
},
"async-limiter": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
"integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
},
"balanced-match": {
"version": "1.0.0",
@ -429,6 +449,14 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"requires": {
"delayed-stream": "~1.0.0"
}
},
"commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
@ -539,6 +567,11 @@
"integrity": "sha512-J7thop4u3mRTkYRQ+Vpfwy2G5Ehoy82I14+14W4YMDLKdWloI9gSzRbV30s/NckQGVJtPkWNcW4oMAUigTdqiQ==",
"dev": true
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
},
"diff": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz",
@ -546,15 +579,17 @@
"dev": true
},
"discord.js": {
"version": "11.5.1",
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-11.5.1.tgz",
"integrity": "sha512-tGhV5xaZXE3Z+4uXJb3hYM6gQ1NmnSxp9PClcsSAYFVRzH6AJH74040mO3afPDMWEAlj8XsoPXXTJHTxesqcGw==",
"version": "github:discordjs/discord.js#ee0b7c155a1767ed42e2756e53d56368e8b69929",
"from": "github:discordjs/discord.js",
"requires": {
"long": "^4.0.0",
"prism-media": "^0.0.3",
"snekfetch": "^3.6.4",
"tweetnacl": "^1.0.0",
"ws": "^6.0.0"
"@discordjs/collection": "^0.1.1",
"abort-controller": "^3.0.0",
"form-data": "^2.3.3",
"node-fetch": "^2.3.0",
"prism-media": "^1.0.0",
"setimmediate": "^1.0.5",
"tweetnacl": "^1.0.1",
"ws": "^7.2.0"
}
},
"dot-prop": {
@ -614,6 +649,11 @@
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true
},
"event-target-shim": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="
},
"execa": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz",
@ -658,6 +698,16 @@
"locate-path": "^2.0.0"
}
},
"form-data": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
"integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.6",
"mime-types": "^2.1.12"
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@ -1056,11 +1106,6 @@
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
"dev": true
},
"long": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="
},
"loud-rejection": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
@ -1119,6 +1164,19 @@
"yargs-parser": "^10.0.0"
}
},
"mime-db": {
"version": "1.43.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz",
"integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ=="
},
"mime-types": {
"version": "2.1.26",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz",
"integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==",
"requires": {
"mime-db": "1.43.0"
}
},
"mimic-fn": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
@ -1177,6 +1235,11 @@
"integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=",
"dev": true
},
"node-fetch": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
"integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA=="
},
"normalize-package-data": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
@ -1352,9 +1415,9 @@
"dev": true
},
"prism-media": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/prism-media/-/prism-media-0.0.3.tgz",
"integrity": "sha512-c9KkNifSMU/iXT8FFTaBwBMr+rdVcN+H/uNv1o+CuFeTThNZNTOrQ+RgXA1yL/DeLk098duAeRPP3QNPNbhxYQ=="
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.1.0.tgz",
"integrity": "sha512-W+oxjRyjtd7hw3pefNZuc7YEZ6VICORJvVNfCPs0+7CsJ43CqMjGAYGjPL3hQ82vw03EVra+CiX4zisqOBUUGw=="
},
"pseudomap": {
"version": "1.0.2",
@ -1530,6 +1593,11 @@
"semver": "^5.0.3"
}
},
"setimmediate": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
"integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU="
},
"shebang-command": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
@ -1551,11 +1619,6 @@
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
"dev": true
},
"snekfetch": {
"version": "3.6.4",
"resolved": "https://registry.npmjs.org/snekfetch/-/snekfetch-3.6.4.tgz",
"integrity": "sha512-NjxjITIj04Ffqid5lqr7XdgwM7X61c/Dns073Ly170bPQHLm6jkmelye/eglS++1nfTWktpP6Y2bFXjdPlQqdw=="
},
"spdx-correct": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
@ -1992,12 +2055,9 @@
}
},
"ws": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz",
"integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==",
"requires": {
"async-limiter": "~1.0.0"
}
"version": "7.2.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.2.1.tgz",
"integrity": "sha512-sucePNSafamSKoOqoNfBd8V0StlkzJKL2ZAhGQinCfNQ+oacw+Pk7lcdAElecBF2VkLNZRiIb5Oi1Q5lVUVt2A=="
},
"xdg-basedir": {
"version": "3.0.0",

View file

@ -9,7 +9,8 @@
"devDependencies": {
"gts": "^1.1.2",
"typescript": "~3.7.0",
"@types/node": "^10.0.3"
"@types/node": "^10.0.3",
"@types/ws": "^6.0.4"
},
"scripts": {
"check": "gts check",
@ -22,6 +23,6 @@
"posttest": "npm.cmd run check"
},
"dependencies": {
"discord.js": "^11.5.1"
"discord.js": "github:discordjs/discord.js"
}
}

9
src/PluginClient.ts Normal file
View file

@ -0,0 +1,9 @@
import { Client, ClientOptions, Collection } from 'discord.js';
import { Plugin } from './plugins/Plugin';
export class PluginClient extends Client {
plugins!: Collection<string, Plugin>;
constructor(options?: ClientOptions) {
super(options);
}
}

8
src/events/Event.ts Normal file
View file

@ -0,0 +1,8 @@
import { PluginClient } from '../PluginClient';
// tslint:disable-next-line: no-any
type EventFunc = (lifeguard: PluginClient, ...args: any[]) => void;
export class Event {
constructor(public name: string, public func: EventFunc) {}
}

21
src/events/eventLoader.ts Normal file
View file

@ -0,0 +1,21 @@
import { Client } from 'discord.js';
import { readdir } from 'fs';
import { promisify } from 'util';
import { Event } from './Event';
const readDir = promisify(readdir);
export async function EventLoader(lifeguard: Client) {
const eventFiles = await readDir('./build/src/events');
for await (const file of eventFiles) {
if (file.endsWith('js') && file !== 'Event.js') {
const { event } = require(`./${file}`);
if (event instanceof Event) {
lifeguard.on(event.name, (...args: []) => {
event.func(lifeguard, ...args);
});
}
}
}
}

13
src/events/guildCreate.ts Normal file
View file

@ -0,0 +1,13 @@
import { Event } from './Event';
export const event = new Event('guildCreate', lifeguard => {
if (lifeguard.user) {
lifeguard.user.setPresence({
activity: {
name: `${lifeguard.users.size} people in the pool`,
type: 'WATCHING',
},
status: 'online',
});
}
});

View file

@ -0,0 +1,26 @@
import { Event } from './Event';
import { Message } from 'discord.js';
import { prefix } from '../config/bot';
import { PluginClient } from '../PluginClient';
function parseContent(content: string) {
const split = content.split(' ');
const cmdName = split[0].slice(prefix.length);
split.shift();
return [cmdName, ...split];
}
function getCommandFromPlugin(lifeguard: PluginClient, cmdName: string) {
const plugin = lifeguard.plugins.find(p => p.has(cmdName));
const command = plugin?.get(cmdName);
return command;
}
export const event = new Event(
'lifeguardCommandUsed',
async (lifeguard, msg: Message) => {
const [cmdName, ...args] = parseContent(msg.content);
const cmd = getCommandFromPlugin(lifeguard, cmdName);
cmd?.func(lifeguard, msg, args);
}
);

9
src/events/message.ts Normal file
View file

@ -0,0 +1,9 @@
import { Event } from './Event';
import { Message } from 'discord.js';
import { prefix } from '../config/bot';
export const event = new Event('message', async (lifeguard, msg: Message) => {
if (msg.content.startsWith(prefix)) {
lifeguard.emit('lifeguardCommandUsed', msg);
}
});

14
src/events/ready.ts Normal file
View file

@ -0,0 +1,14 @@
import { Event } from './Event';
export const event = new Event('ready', lifeguard => {
console.log('Connected to Discord');
if (lifeguard.user) {
lifeguard.user.setPresence({
activity: {
name: `${lifeguard.users.size} people in the pool`,
type: 'WATCHING',
},
status: 'online',
});
}
});

View file

@ -1,12 +1,19 @@
import { Client } from 'discord.js';
import { token } from './config/bot';
import { EventLoader } from './events/eventLoader';
import { PluginLoader } from './plugins/pluginLoader';
import { PluginClient } from './PluginClient';
const lifeguard = new Client();
const lifeguard = new PluginClient();
lifeguard
.login(token)
.then(_ =>
EventLoader(lifeguard);
PluginLoader().then(plugins => {
lifeguard.plugins = plugins;
});
lifeguard.login(token).then(() => {
if (lifeguard.user) {
console.log(
`Logged in to ${lifeguard.user.username}#${lifeguard.user.discriminator}`
)
);
);
}
});

25
src/plugins/Command.ts Normal file
View file

@ -0,0 +1,25 @@
import { Message, PermissionString } from 'discord.js';
import { PluginClient } from '../PluginClient';
type CommandFunction = (
lifeguard: PluginClient,
msg: Message,
args: string[]
) => void;
interface CommandOptions {
alias?: string[];
guildOnly?: boolean;
hidden?: boolean;
level: number;
usage: string[];
permissions?: PermissionString[];
}
export class Command {
constructor(
public name: string,
public func: CommandFunction,
public options: CommandOptions
) {}
}

8
src/plugins/Plugin.ts Normal file
View file

@ -0,0 +1,8 @@
import { Collection } from 'discord.js';
import { Command } from './Command';
export class Plugin extends Collection<string, Command> {
constructor() {
super();
}
}

30
src/plugins/debug/ping.ts Normal file
View file

@ -0,0 +1,30 @@
import { Command } from '../Command';
import { MessageEmbed } from 'discord.js';
export const command = new Command(
'ping',
async (lifeguard, msg, args) => {
const m = await msg.channel.send('Ping?');
m.delete({ timeout: 100 });
const embed = new MessageEmbed()
.setTitle('Pong! :ping_pong:')
.addField('Bot Latency', `${Math.round(lifeguard.ws.ping)}ms`)
.addField(
'Message Latency',
`${m.createdTimestamp - msg.createdTimestamp}ms`
)
.setColor(0x7289da)
.setFooter(
`Executed By ${msg.author.tag}`,
msg.author.avatarURL() ?? msg.author.defaultAvatarURL
)
.setTimestamp();
msg.channel.send(embed);
},
{
level: 0,
usage: ['ping'],
}
);

17
src/plugins/info/help.ts Normal file
View file

@ -0,0 +1,17 @@
import { Command } from '../Command';
export const command = new Command(
'help',
(lifeguard, msg, args) => {
const cmds = Array.from(lifeguard.plugins.values())
.map(plugin => Array.from(plugin.values()))
.reduce((acc, val) => acc.concat(val), [])
.filter(cmd => !cmd.options.hidden)
.sort((a, b) => a.name.localeCompare(b.name));
msg.channel.send(cmds.map(c => c.name).join('\n'));
},
{
level: 0,
usage: ['help', 'help [name]'],
}
);

View file

@ -0,0 +1,34 @@
import { promisify } from 'util';
import { readdir, lstat } from 'fs';
import { Collection } from 'discord.js';
import { Plugin } from './Plugin';
import { Command } from './Command';
export async function PluginLoader() {
const readDir = promisify(readdir);
const stats = promisify(lstat);
const plugins = new Collection<string, Plugin>();
const pluginDir = './build/src/plugins';
const folders = await readDir(pluginDir);
for await (const folder of folders) {
const folderDir = `${pluginDir}/${folder}`;
const info = await stats(folderDir);
if (info.isDirectory()) {
const plugin = new Plugin();
const files = await readDir(`${folderDir}`);
for await (const file of files) {
if (file.endsWith('.js')) {
const command: Command = require(`./${folder}/${file}`).command;
plugin.set(command.name, command);
}
}
plugins.set(folder, plugin);
}
}
return plugins;
}