Skip to content
This repository was archived by the owner on May 31, 2021. It is now read-only.

Commit 1732d13

Browse files
committedMay 6, 2020
Made adding commands insertable through a registry
1 parent f97f956 commit 1732d13

19 files changed

+502
-13
lines changed
 

‎.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,6 @@ pids
1919

2020
# TypeScript cache
2121
*.tsbuildinfo
22+
23+
# Vscode
24+
.vscode/

‎src/Rice.ts

+10-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import { Client, ClientOptions } from "discord.js";
2-
import EventRegistry from "./core/Registry/EventRegistry";
3-
import CommandRegistry from "./core/Registry/CommandRegistry";
4-
import MonitorRegistry from "./core/Registry/MonitorRegistry";
2+
import EventRegistry from "./core/registry/EventRegistry";
3+
import CommandRegistry from "./core/registry/CommandRegistry";
4+
import MonitorRegistry from "./core/registry/MonitorRegistry";
55
import mongoose from "mongoose";
6+
import ALogger from "./util/Logger";
7+
68
class Rice extends Client {
9+
public logger: ALogger = new ALogger();
710
public eventRegistry: EventRegistry = new EventRegistry(this);
811
public commandRegistry: CommandRegistry = new CommandRegistry();
912
public monitorRegistry: MonitorRegistry = new MonitorRegistry(this);
@@ -16,13 +19,16 @@ class Rice extends Client {
1619
})
1720
.then(
1821
() => {
19-
console.log("Logged into Mongo!");
22+
this.logger.log("Logged into Mongo!", this.logger.levels.INFO);
2023
},
2124
(err: any) => {
2225
throw err;
2326
}
2427
);
2528
}
29+
get getLogger() {
30+
return this.logger;
31+
}
2632
static get client() {
2733
return this;
2834
}

‎src/api/index.ts

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import GSController from "./controller/GuildSettingController";
2+
import IGuildSettings from "./controller/IGuildSettingsController";
3+
4+
export { GSController, IGuildSettings };

‎src/commands/Fun/test.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import Command from "../../core/models/Command";
2+
import { Message } from "discord.js";
3+
import Rice from "../../Rice";
24

35
export default class extends Command {
46
constructor() {
@@ -13,7 +15,11 @@ export default class extends Command {
1315
aliases: [],
1416
});
1517
}
16-
public async run(): Promise<void> {
17-
console.log("RAN TEST CMD");
18+
public async run(
19+
_client: Rice,
20+
message: Message,
21+
[..._args]
22+
): Promise<Message | void> {
23+
message.channel.send("hola como estas " + _args);
1824
}
1925
}

‎src/commands/Moderation/kick.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import Command from "../../core/models/Command";
33
export default class extends Command {
44
constructor() {
55
super({
6-
name: "true",
6+
name: "kick",
77
enable: true,
88
cooldown: 0,
99
runIn: ["text"],

‎src/commands/System/help.ts

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import Command from "../../core/models/Command";
2+
import Rice from "../../Rice";
3+
import { Message } from "discord.js";
4+
export default class extends Command {
5+
constructor() {
6+
super({
7+
name: "help",
8+
enable: true,
9+
cooldown: 0,
10+
runIn: ["text"],
11+
permLevel: 0,
12+
usage: "",
13+
description: "bruh",
14+
aliases: [],
15+
});
16+
}
17+
public async run(client: Rice, message: Message): Promise<Message | void> {
18+
const help: any = await this.buildHelp(client);
19+
const categories = Object.keys(help);
20+
const helpMessage = [];
21+
for (let cat = 0; cat < categories.length; cat++) {
22+
helpMessage.push(`**${categories[cat]} Commands**: \`\`\`asciidoc`, "");
23+
helpMessage.push(`${help[categories[cat]].join("\n")}\n`);
24+
helpMessage.push("```\n\u200b");
25+
}
26+
27+
return message.channel.send(helpMessage, { split: { char: "\u200b" } });
28+
}
29+
async buildHelp(client: Rice) {
30+
const help: any = {};
31+
const commandNames = Array.from(
32+
client.commandRegistry.getCommandStore.getStore.keys()
33+
);
34+
const longest = commandNames.reduce(
35+
(long, str) => Math.max(long, str.length),
36+
0
37+
);
38+
await Promise.all(
39+
client.commandRegistry.getCommandStore.getStore.map((command) => {
40+
if (!help.hasOwnProperty(command.category)) help[command.category] = [];
41+
help[command.category].push(
42+
`+${command.name.padEnd(longest)} :: ${command.description}`
43+
);
44+
return command.category;
45+
})
46+
);
47+
48+
return help;
49+
}
50+
}

‎src/commands/System/info.ts

+141
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import Command from "../../core/models/Command";
2+
import Rice from "../../Rice";
3+
import { Message } from "discord.js";
4+
import PageEmbed from "../../core/tools/PageEmbed";
5+
import Discord from "discord.js";
6+
import Page from "../../core/models/Page";
7+
export default class extends Command {
8+
constructor() {
9+
super({
10+
name: "info",
11+
enable: true,
12+
cooldown: 0,
13+
runIn: ["text"],
14+
permLevel: 0,
15+
usage: "",
16+
description: "bruh",
17+
aliases: [],
18+
});
19+
}
20+
public async run(client: Rice, message: Message): Promise<Message | void> {
21+
const embed = new PageEmbed(client, message);
22+
embed.addPages([
23+
new Page({
24+
title: "Rice Market Stats:",
25+
author: {
26+
name: client.user?.username,
27+
iconURL: client.user?.displayAvatarURL(),
28+
},
29+
thumbnail: {
30+
url: client.user!.displayAvatarURL(),
31+
},
32+
fields: [
33+
{
34+
name: "CPU:",
35+
value: (process.cpuUsage().user / 1000 / 1000).toFixed(2) + "%",
36+
inline: true,
37+
},
38+
{
39+
name: "Memory Usage:",
40+
value: `${(process.memoryUsage().heapUsed / 1024 / 1024).toFixed(
41+
2
42+
)} / ${(process.memoryUsage().heapTotal / 1024 / 1024).toFixed(
43+
2
44+
)} MB`,
45+
inline: true,
46+
},
47+
{
48+
name: "Uptime:",
49+
value: `${client.uptime}`,
50+
inline: true,
51+
},
52+
{
53+
name: "Discord JS:",
54+
value: `v${Discord.version}`,
55+
inline: true,
56+
},
57+
{
58+
name: "Node.JS:",
59+
value: `${process.version}`,
60+
inline: true,
61+
},
62+
],
63+
}),
64+
new Page({
65+
title: `${message.guild?.name}'s Stats`,
66+
author: {
67+
name: client.user?.username,
68+
iconURL: message.guild?.iconURL() || client.user?.defaultAvatarURL,
69+
},
70+
thumbnail: {
71+
url: message.guild!.iconURL() || client.user!.defaultAvatarURL,
72+
},
73+
fields: [
74+
{
75+
name: "Member Count",
76+
value: `${message.guild?.memberCount}`,
77+
inline: true,
78+
},
79+
{
80+
name: "Shard ID",
81+
value: `${message.guild!.shardID}`,
82+
inline: true,
83+
},
84+
{
85+
name: "Join Date",
86+
value: `${message.guild!.joinedAt}`,
87+
inline: true,
88+
},
89+
{
90+
name: "Created on",
91+
value: `${message.guild!.createdAt}`,
92+
inline: true,
93+
},
94+
{
95+
name: "Owner",
96+
value: `${message.guild!.owner!.user.username}`,
97+
inline: true,
98+
},
99+
],
100+
}),
101+
new Page({
102+
title: `Rice's Stats`,
103+
author: {
104+
name: "Global Stats",
105+
iconURL: client.user?.displayAvatarURL(),
106+
},
107+
thumbnail: {
108+
url: client.user!.displayAvatarURL(),
109+
},
110+
fields: [
111+
{
112+
name: "Guild Count",
113+
value: `${client.guilds.cache.size}`,
114+
inline: true,
115+
},
116+
{
117+
name: "Member Count",
118+
value: `${client.users.cache.size}`,
119+
inline: true,
120+
},
121+
{
122+
name: "Join Date",
123+
value: `${message.guild!.joinedAt}`,
124+
inline: true,
125+
},
126+
{
127+
name: "Version",
128+
value: `Pre Alpha Stage`,
129+
inline: true,
130+
},
131+
{
132+
name: "Contributors",
133+
value: `AndyIsCool5463`,
134+
inline: true,
135+
},
136+
],
137+
}),
138+
]);
139+
return embed.sendEmbed();
140+
}
141+
}

‎src/commands/index.ts

+9
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,20 @@ import test from "./Fun/test";
1313

1414
import kick from "./Moderation/kick";
1515

16+
/**
17+
* System Module
18+
*/
19+
import help from "./System/help";
20+
import info from "./System/info";
1621
export default {
1722
fun: {
1823
test,
1924
},
2025
moderation: {
2126
kick,
2227
},
28+
system: {
29+
help,
30+
info,
31+
},
2332
};

‎src/core/models/Command.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ class Command {
3232
this.description = description || "Unspecified.";
3333
}
3434
public async run(
35+
_client: Rice,
3536
_message: Message,
36-
[..._args],
37-
_client: Rice
37+
..._args: any
3838
): Promise<Message | void> {}
3939
get getRunIn() {
4040
return this.runIn;

‎src/core/models/Monitor.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class Monitor {
2929
if (ignoreSelf) this.ignoreSelf = ignoreSelf;
3030
if (allowedTypes) this.allowedTypes = allowedTypes;
3131
}
32-
public async run(_message: Message, _client: Rice): Promise<void> {}
32+
public async run(_message: Message, _client: Rice): Promise<Message | void> {}
3333
shouldRun(message: Message, client: Rice) {
3434
return (
3535
this.enabled &&

‎src/core/models/Page.ts

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import {
2+
ColorResolvable,
3+
MessageEmbedThumbnail,
4+
MessageEmbedImage,
5+
MessageEmbedVideo,
6+
MessageEmbedAuthor,
7+
MessageEmbedProvider,
8+
} from "discord.js";
9+
10+
interface EmbedField {
11+
name: string;
12+
value: string;
13+
inline: boolean | false;
14+
}
15+
interface IPage {
16+
title?: string;
17+
description?: string;
18+
fields?: Array<EmbedField>;
19+
url?: string; // TODO: change maybe?
20+
color?: ColorResolvable;
21+
timestamp?: Date | null;
22+
thumbnail?: MessageEmbedThumbnail;
23+
image?: MessageEmbedImage;
24+
video?: MessageEmbedVideo;
25+
author?: MessageEmbedAuthor;
26+
provider?: MessageEmbedProvider;
27+
}
28+
class Page {
29+
// HACK: I mean, is this really a hack? All fields are optional
30+
public title?: string;
31+
public description?: string;
32+
public fields?: Array<EmbedField>;
33+
public url?: string; // TODO: change maybe?
34+
public color?: ColorResolvable;
35+
public timestamp?: Date | null;
36+
public thumbnail?: MessageEmbedThumbnail;
37+
public image?: MessageEmbedImage;
38+
public video?: MessageEmbedVideo;
39+
public author?: MessageEmbedAuthor;
40+
public provider?: MessageEmbedProvider;
41+
42+
constructor({
43+
title,
44+
description,
45+
fields,
46+
url,
47+
author,
48+
color,
49+
image,
50+
provider,
51+
thumbnail,
52+
timestamp,
53+
video,
54+
}: IPage) {
55+
if (title) this.title = title;
56+
if (description) this.description = description;
57+
if (fields) this.fields = fields;
58+
if (url) this.url = url;
59+
if (author) this.author = author;
60+
if (color) this.color = color;
61+
if (image) this.image = image;
62+
63+
if (provider) this.provider = provider;
64+
if (thumbnail) this.thumbnail = thumbnail;
65+
if (timestamp) this.timestamp = timestamp;
66+
if (video) this.video = video;
67+
}
68+
public addFields(field: EmbedField) {
69+
this.fields?.push(field);
70+
}
71+
}
72+
73+
export default Page;

‎src/core/Registry/CommandRegistry.ts ‎src/core/registry/CommandRegistry.ts

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class CommandRegistry {
1313
private async init(): Promise<void> {
1414
this.registerModule(Commands.fun, "Fun");
1515
this.registerModule(Commands.moderation, "Moderation");
16+
this.registerModule(Commands.system, "System");
1617
}
1718
public registerModule(module: Object, moduleName: string) {
1819
for (let [, command] of Object.entries(module)) {

‎src/core/Registry/EventRegistry.ts ‎src/core/registry/EventRegistry.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class EventRegistry {
1010
this.init();
1111
}
1212
private init(): void {
13-
this.registerAll(new Events.message());
13+
this.registerAll(new Events.message(), new Events.ready());
1414
}
1515
public registerAll(...events: Event[]) {
1616
events.forEach((event) => {
File renamed without changes.

‎src/core/tools/PageEmbed.ts

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import Page from "../models/Page";
2+
import Rice from "../../Rice";
3+
import { Message, MessageEmbed, MessageReaction, User } from "discord.js";
4+
5+
class PageEmbed {
6+
private pages: Array<Page> = new Array<Page>();
7+
protected client: Rice;
8+
private message: Message;
9+
private pageNumber: number = 0;
10+
constructor(client: Rice, message: Message) {
11+
this.client = client;
12+
this.message = message;
13+
}
14+
15+
public addPages([...pages]: Page[]) {
16+
for (let page of pages) {
17+
this.pages.push(page);
18+
}
19+
return this;
20+
}
21+
public removePage(index: number): void {
22+
this.pages.splice(index, 1);
23+
}
24+
public sendEmbed(): Promise<Message> {
25+
const message = this.message.channel.send(this.constructEmbed());
26+
message.then(async (message) => {
27+
await message.react("◀");
28+
await message.react("▶");
29+
const reactionManager = message.createReactionCollector(
30+
this.embedFilter,
31+
{
32+
time: 30000, // 30 seconds
33+
maxEmojis: 20, // can be clicked 100 times.
34+
}
35+
);
36+
reactionManager.on("collect", (reaction) => {
37+
this.handleReaction(reaction);
38+
});
39+
reactionManager.on("end", () => {
40+
message.reactions.removeAll();
41+
});
42+
});
43+
return message;
44+
}
45+
private handleReaction(reaction: MessageReaction) {
46+
if (reaction.emoji.name == "◀") {
47+
if (this.pageNumber === 0) return;
48+
this.pageNumber--;
49+
this.changePage(reaction);
50+
} else if (reaction.emoji.name == "▶") {
51+
if (this.pageNumber >= this.pages.length - 1) return;
52+
this.pageNumber++;
53+
this.changePage(reaction);
54+
}
55+
}
56+
private changePage(reaction: MessageReaction) {
57+
reaction.message.edit(this.constructEmbed(this.pageNumber));
58+
}
59+
private constructEmbed(pageNumber = 0): MessageEmbed {
60+
if (!this.pages[pageNumber])
61+
throw new Error("are you stupid? there isnt a starting page.");
62+
const embed = new MessageEmbed();
63+
const page = this.pages[pageNumber];
64+
page.author
65+
? embed.setAuthor(page.author.name, page.author.iconURL, page.author.url)
66+
: null;
67+
page.color ? embed.setColor(page.color) : null;
68+
page.description ? embed.setDescription(page.description) : null;
69+
page.image ? embed.setImage(page.image.url) : null;
70+
page.thumbnail ? embed.setThumbnail(page.thumbnail.url) : null;
71+
page.title ? embed.setTitle(page.title) : null;
72+
page.thumbnail ? embed.setThumbnail(page.thumbnail.url) : null;
73+
if (page.fields) {
74+
for (let field of page.fields) {
75+
embed.addField(field.name, field.value, field.inline);
76+
}
77+
}
78+
embed.setFooter(`Page: ${pageNumber + 1}/${this.pages.length}`);
79+
80+
return embed;
81+
}
82+
private embedFilter(reaction: MessageReaction, user: User): boolean {
83+
return (
84+
(reaction.emoji.name === "◀" || reaction.emoji.name === "▶") && !user.bot
85+
);
86+
}
87+
}
88+
89+
export default PageEmbed;

‎src/events/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import message from "./message";
2+
import ready from "./ready";
23
export default {
4+
ready,
35
message,
46
};

‎src/events/ready.ts

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import Event from "../core/models/Event";
2+
import Rice from "../Rice";
3+
class Ready extends Event {
4+
constructor() {
5+
super("ready");
6+
}
7+
public run(client: Rice) {
8+
client.logger.log(
9+
`${client.user!.username}#${client.user?.discriminator} is serving ${
10+
client.guilds.cache.size
11+
} fields!`
12+
);
13+
client.user!.setPresence({
14+
status: "idle",
15+
activity: {
16+
type: "WATCHING",
17+
name: `${client.guilds.cache.size} fields.`,
18+
},
19+
});
20+
}
21+
}
22+
export default Ready;

‎src/monitors/CommandMonitor.ts

+33-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,42 @@
11
import Monitor from "../core/models/Monitor";
2-
2+
import { Message } from "discord.js";
3+
import Rice from "../Rice";
4+
import { GSController } from "../api";
35
export default class extends Monitor {
46
constructor() {
57
super({
68
enabled: true,
79
name: "Command Monitor",
810
});
911
}
10-
public async run() {}
12+
public async run(message: Message, client: Rice): Promise<Message | void> {
13+
if (!message.guild) return;
14+
let prefix = "+";
15+
const guildSettings = await GSController.ensureGuild(message.guild);
16+
for (const pfx of guildSettings.config.prefix) {
17+
if (message.content.startsWith(pfx)) prefix = pfx;
18+
}
19+
if (!message.content.startsWith(prefix)) return; // this is to ensure that if the user did not use +, they wont get fucked dong
20+
21+
const command = message.content.slice(prefix.length).trim().split(/ +/g);
22+
const args = message.content
23+
.slice(prefix.length)
24+
.trim()
25+
.split(/ +/g)
26+
.reverse();
27+
args.pop();
28+
args.reverse();
29+
30+
const commandRunnable =
31+
client.commandRegistry.getCommandStore.get(command[0].toLowerCase()) ||
32+
client.commandRegistry.getCommandStore.aliasStore.get(
33+
command[0].toLowerCase()
34+
);
35+
if (!commandRunnable) return;
36+
commandRunnable.run(client, message, args).catch((e: Error) => {
37+
message.channel.send(
38+
`There was an error executing your command. \n \`\`\`${e.message}\`\`\``
39+
);
40+
});
41+
}
1142
}

‎src/util/Logger.ts

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* File: Logger.js
3+
* Project: ricebot
4+
* File Created: Thursday, 16th April 2020 12:07:46 am
5+
* Author: andyl5463 (andyl5463@gmail.com)
6+
* -----
7+
* Last Modified: Thursday, 16th April 2020 12:07:46 am
8+
* Modified By: andyl5463 (andyl5463@gmail.com>)
9+
* -----
10+
* Copyright 2020 - 2020 Longshot Development, Longshot Development
11+
*/
12+
import moment from "moment";
13+
import chalk from "chalk";
14+
enum levels {
15+
LOG,
16+
DEBUG,
17+
WARN,
18+
ERROR,
19+
INFO,
20+
}
21+
export default class {
22+
public levels = levels;
23+
24+
public log(text: string, type: levels = levels.INFO): void {
25+
process.env.NODE_ENV !== "test"
26+
? console.log(
27+
`${chalk.black.bgYellow(
28+
`[${moment().format("LTS")}]`
29+
)} [${this.getType(type)}]: ${text}`
30+
)
31+
: null;
32+
}
33+
public getType(type: levels): string {
34+
switch (type) {
35+
case levels.DEBUG:
36+
return "DEBUG";
37+
break;
38+
case levels.ERROR:
39+
return "ERROR";
40+
break;
41+
case levels.INFO:
42+
return "INFO";
43+
break;
44+
case levels.LOG:
45+
return "LOG";
46+
break;
47+
case levels.WARN:
48+
return "WARN";
49+
break;
50+
}
51+
}
52+
}

0 commit comments

Comments
 (0)
This repository has been archived.