You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2b-bot-v2/src/Bot.ts

118 lines
4.4 KiB
TypeScript

import {Client, Guild} from "discord.js";
import {Config} from "./lib/utils/Config";
import {DefaultConfig} from "./lib/utils/DefaultConfig";
import * as path from "path";
import * as fsx from "fs-extra";
import * as yaml from "js-yaml";
import {BotLogger} from "./lib/utils/BotLogger";
import {DataHandler} from "./lib/DataHandler";
import {GuildHandler} from "./lib/GuildHandler";
import {CommandCollection} from "./lib/CommandCollection";
import {Command} from "./lib/Command";
import {globalCommands} from "./commands/global";
import {privateCommands} from "./commands/private";
import {parseMessage} from "./lib/utils";
import {CommandPermission} from "./lib/CommandPermission";
import {Help} from "./commands/global/utility/Help";
import {ExtendedMessage} from "./lib/ExtendedMessage";
const configFile = "config.yaml";
/**
* The main class of the bot.
*/
export class Bot {
public readonly client: Client;
public readonly config: Config;
public readonly logger: BotLogger;
public readonly dataHandler: DataHandler;
private commandCollection: CommandCollection<Command>;
private guildHandlers: any = {};
/**
* constructor
*/
constructor() {
globalCommands.add(Help);
this.config = Bot.loadConfig();
this.logger = new BotLogger(this.config.logging.directory, this.config.logging.level);
this.client = new Client();
this.dataHandler = new DataHandler(this);
this.commandCollection = new CommandCollection<Command>();
this.commandCollection.include(globalCommands);
this.commandCollection.include(privateCommands);
}
/**
* Starts the bot.
*/
public async start(): Promise<void> {
await this.dataHandler.init();
this.logger.debug(`Config is ${JSON.stringify(this.config)}`);
await this.client.login(this.config.botToken);
this.logger.info(`Logged in as ${this.client.user.tag}`);
this.registerEvents();
}
/**
* Loads the config file or creates one if none exists.
*/
private static loadConfig(): Config {
const configPath: string = path.join(__dirname, "../", configFile);
if (!fsx.existsSync(configPath)) {
const configString: string = yaml.safeDump(new DefaultConfig());
fsx.writeFileSync(configPath, configString);
// tslint:disable-next-line:no-console
console.log("-----------------");
// tslint:disable-next-line:no-console
console.log("Please edit the config before starting the bot.");
process.exit(0);
} else {
const configString = fsx.readFileSync(configPath, "utf-8");
return Object.assign(new DefaultConfig(), yaml.safeLoad(configString));
}
}
/**
* Registers all events the bot needs.
*/
private registerEvents(): void {
this.client.on("message", async (message) => {
if (message.author !== this.client.user) {
if (message.guild) {
const handler = await this.getGuildHandler(message.guild);
await handler.onMessage(message);
} else {
this.logger.debug(`<PM: ${message.author.tag}> ${message.content}`);
const userPermission = this.config.owners.includes(message.author.tag) ?
CommandPermission.OWNER : CommandPermission.REGULAR;
const CommandClass = parseMessage(message, this.commandCollection,
this.config.prefix, userPermission);
if (CommandClass) {
const command = new CommandClass(this);
try {
await command.invoke(message, new ExtendedMessage(message));
} catch (err) {
this.logger.errorReport(err);
}
}
}
}
});
}
/**
* Returns the guild handler for a guild and creates one if it doesn't exist.
* @param guild
*/
private async getGuildHandler(guild: Guild): Promise<GuildHandler> {
let handler = this.guildHandlers[guild.id];
if (!handler) {
handler = new GuildHandler(this, guild) as GuildHandler;
await handler.init();
this.guildHandlers[guild.id] = handler;
}
return handler;
}
}