3
0
Fork 0
mirror of https://github.com/ZeppelinBot/Zeppelin.git synced 2025-03-15 05:41:51 +00:00
zeppelin/src/index.ts

212 lines
7 KiB
TypeScript
Raw Normal View History

import path from "path";
import yaml from "js-yaml";
2019-01-15 01:07:02 +02:00
import fs from "fs";
const fsp = fs.promises;
import { Knub, logger, PluginError, Plugin } from "knub";
2018-12-14 06:27:41 +02:00
import { SimpleError } from "./SimpleError";
import DiscordRESTError from "eris/lib/errors/DiscordRESTError"; // tslint:disable-line
import DiscordHTTPError from "eris/lib/errors/DiscordHTTPError"; // tslint:disable-line
2018-07-01 03:35:51 +03:00
require("dotenv").config();
let recentPluginErrors = 0;
const RECENT_PLUGIN_ERROR_EXIT_THRESHOLD = 5;
let recentDiscordErrors = 0;
const RECENT_DISCORD_ERROR_EXIT_THRESHOLD = 5;
setInterval(() => (recentPluginErrors = Math.max(0, recentPluginErrors - 1)), 2500);
setInterval(() => (recentDiscordErrors = Math.max(0, recentDiscordErrors - 1)), 2500);
2018-07-01 03:35:51 +03:00
function errorHandler(err) {
console.error(err);
if (err instanceof PluginError) {
// Tolerate a few recent plugin errors before crashing
if (++recentPluginErrors >= RECENT_PLUGIN_ERROR_EXIT_THRESHOLD) {
console.error(`Exiting after ${RECENT_PLUGIN_ERROR_EXIT_THRESHOLD} plugin errors`);
process.exit(1);
}
} else if (err instanceof DiscordRESTError || err instanceof DiscordHTTPError) {
// Discord API errors, usually safe to continue (rate limits etc. are handled elsewhere)
// We still bail if we get a ton of them in a short amount of time
if (++recentDiscordErrors >= RECENT_DISCORD_ERROR_EXIT_THRESHOLD) {
console.error(`Exiting after ${RECENT_DISCORD_ERROR_EXIT_THRESHOLD} API errors`);
process.exit(1);
}
} else {
// On other errors, crash immediately
process.exit(1);
}
}
process.on("unhandledRejection", errorHandler);
process.on("uncaughtException", errorHandler);
2018-08-03 19:25:00 +03:00
2018-12-14 06:27:41 +02:00
// Verify required Node.js version
const REQUIRED_NODE_VERSION = "10.14.2";
const requiredParts = REQUIRED_NODE_VERSION.split(".").map(v => parseInt(v, 10));
const actualVersionParts = process.versions.node.split(".").map(v => parseInt(v, 10));
for (const [i, part] of actualVersionParts.entries()) {
2019-01-03 03:47:52 +02:00
if (part > requiredParts[i]) break;
if (part === requiredParts[i]) continue;
throw new SimpleError(`Unsupported Node.js version! Must be at least ${REQUIRED_NODE_VERSION}`);
2018-12-14 06:27:41 +02:00
}
// Always use UTC
import moment from "moment-timezone";
moment.tz.setDefault("UTC");
2018-07-01 03:35:51 +03:00
import { Client } from "eris";
import { connect } from "./data/db";
2018-08-05 01:32:59 +03:00
// Global plugins
2018-07-01 03:35:51 +03:00
import { BotControlPlugin } from "./plugins/BotControl";
2018-08-05 01:32:59 +03:00
import { LogServerPlugin } from "./plugins/LogServer";
// Guild plugins
2018-07-01 03:35:51 +03:00
import { ModActionsPlugin } from "./plugins/ModActions";
import { UtilityPlugin } from "./plugins/Utility";
import { LogsPlugin } from "./plugins/Logs";
import { PostPlugin } from "./plugins/Post";
2018-07-29 15:18:26 +03:00
import { ReactionRolesPlugin } from "./plugins/ReactionRoles";
import { CensorPlugin } from "./plugins/Censor";
2018-07-30 23:35:44 +03:00
import { PersistPlugin } from "./plugins/Persist";
import { SpamPlugin } from "./plugins/Spam";
2018-08-05 01:32:59 +03:00
import { TagsPlugin } from "./plugins/Tags";
import { MessageSaverPlugin } from "./plugins/MessageSaver";
import { CasesPlugin } from "./plugins/Cases";
import { MutesPlugin } from "./plugins/Mutes";
2018-12-15 17:04:04 +02:00
import { SlowmodePlugin } from "./plugins/Slowmode";
2018-12-15 23:01:45 +02:00
import { StarboardPlugin } from "./plugins/Starboard";
2019-01-06 15:27:51 +02:00
import { NameHistoryPlugin } from "./plugins/NameHistory";
2019-02-20 00:01:14 +02:00
import { AutoReactionsPlugin } from "./plugins/AutoReactionsPlugin";
import { PingableRolesPlugin } from "./plugins/PingableRolesPlugin";
import { SelfGrantableRolesPlugin } from "./plugins/SelfGrantableRolesPlugin";
import { RemindersPlugin } from "./plugins/Reminders";
import { errorMessage, successMessage } from "./utils";
import { ZeppelinPlugin } from "./plugins/ZeppelinPlugin";
import { customArgumentTypes } from "./customArgumentTypes";
2019-04-23 05:58:50 +03:00
import { startUptimeCounter } from "./uptime";
import { UsernameSaver } from "./plugins/UsernameSaver";
2019-05-03 23:56:38 +03:00
import { WelcomeMessagePlugin } from "./plugins/WelcomeMessage";
2018-07-01 03:35:51 +03:00
// Run latest database migrations
2018-07-01 04:31:24 +03:00
logger.info("Running database migrations");
connect().then(async conn => {
await conn.runMigrations();
const client = new Client(`Bot ${process.env.TOKEN}`, {
getAllUsers: true,
restMode: true,
2018-07-31 20:58:48 +03:00
});
client.setMaxListeners(100);
2018-07-01 03:35:51 +03:00
2019-02-07 20:44:26 +02:00
client.on("debug", message => {
if (message.includes(" 429 ")) {
logger.info(`[RATELIMITED] ${message}`);
}
});
2019-01-06 15:27:51 +02:00
const basePlugins = ["message_saver", "name_history", "cases", "mutes"];
2018-07-01 03:35:51 +03:00
const bot = new Knub(client, {
plugins: [
// Base plugins (always enabled)
MessageSaverPlugin,
2019-01-06 15:27:51 +02:00
NameHistoryPlugin,
CasesPlugin,
MutesPlugin,
// Regular plugins
UtilityPlugin,
ModActionsPlugin,
LogsPlugin,
PostPlugin,
ReactionRolesPlugin,
CensorPlugin,
PersistPlugin,
SpamPlugin,
TagsPlugin,
SlowmodePlugin,
2019-01-12 13:42:11 +02:00
StarboardPlugin,
2019-02-20 00:01:14 +02:00
AutoReactionsPlugin,
PingableRolesPlugin,
SelfGrantableRolesPlugin,
RemindersPlugin,
2019-05-03 23:56:38 +03:00
WelcomeMessagePlugin,
],
globalPlugins: [BotControlPlugin, LogServerPlugin, UsernameSaver],
options: {
getEnabledPlugins(guildId, guildConfig): string[] {
const configuredPlugins = guildConfig.plugins || {};
const pluginNames: string[] = Array.from(this.plugins.keys());
const plugins: Array<typeof Plugin> = Array.from(this.plugins.values());
const zeppelinPlugins: Array<typeof ZeppelinPlugin> = plugins.filter(
p => p.prototype instanceof ZeppelinPlugin,
) as Array<typeof ZeppelinPlugin>;
const enabledBasePlugins = pluginNames.filter(n => basePlugins.includes(n));
const explicitlyEnabledPlugins = pluginNames.filter(pluginName => {
return configuredPlugins[pluginName] && configuredPlugins[pluginName].enabled !== false;
});
const enabledPlugins = new Set([...enabledBasePlugins, ...explicitlyEnabledPlugins]);
const pluginsEnabledAsDependencies = zeppelinPlugins.reduce((arr, pluginClass) => {
if (!enabledPlugins.has(pluginClass.pluginName)) return arr;
return arr.concat(pluginClass.dependencies);
}, []);
const finalEnabledPlugins = new Set([
...basePlugins,
...pluginsEnabledAsDependencies,
...explicitlyEnabledPlugins,
]);
return Array.from(finalEnabledPlugins.values());
},
async getConfig(id) {
const configFile = id ? `${id}.yml` : "global.yml";
const configPath = path.join("config", configFile);
try {
2019-01-15 01:07:02 +02:00
await fsp.access(configPath);
} catch (e) {
return {};
}
2019-01-15 01:07:02 +02:00
const yamlString = await fsp.readFile(configPath, { encoding: "utf8" });
return yaml.safeLoad(yamlString);
},
2019-02-08 21:04:04 +02:00
performanceDebug: {
2019-05-04 10:52:59 +03:00
enabled: false,
2019-02-08 21:04:04 +02:00
size: 30,
2019-02-19 00:02:46 +02:00
threshold: 200,
},
customArgumentTypes,
sendSuccessMessageFn(channel, body) {
channel.createMessage(successMessage(body));
},
sendErrorMessageFn(channel, body) {
channel.createMessage(errorMessage(body));
},
2019-02-19 00:02:46 +02:00
},
2018-07-01 03:35:51 +03:00
});
2019-04-23 05:58:50 +03:00
client.once("ready", () => {
startUptimeCounter();
});
2018-07-01 04:31:24 +03:00
logger.info("Starting the bot");
2018-07-01 03:35:51 +03:00
bot.run();
});