diff --git a/package-lock.json b/package-lock.json index e081bbdf..536ab0df 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2456,6 +2456,14 @@ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-4.0.0.tgz", "integrity": "sha1-hk7xN5rO1Vzm+V3r7NzhefegzR0=" }, + "dotgitconfig": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dotgitconfig/-/dotgitconfig-1.0.1.tgz", + "integrity": "sha512-a6RPc5Cco7ogiKLVExcGBMEEP6jHkzJFYbS/HYGFvQSZrm3EkC876YIqqrj92N8SZYGLqPz6pU522/LlNAaedQ==", + "requires": { + "ini": "^1.3.5" + } + }, "duplexer": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", @@ -3965,8 +3973,7 @@ "ini": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", - "dev": true + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, "invariant": { "version": "2.2.4", @@ -5385,6 +5392,14 @@ "ts-essentials": "^2.0.3" } }, + "last-commit-log": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/last-commit-log/-/last-commit-log-2.1.0.tgz", + "integrity": "sha512-vvZNAaiPSQ/PtyfDP2UrIRwKx0xttliGSwEfd/4tU1B/2iD/g4e3nWbttYb6YLarpULpM6s5OW5JWl97ogB6jA==", + "requires": { + "dotgitconfig": "^1.0.1" + } + }, "latest-version": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", diff --git a/package.json b/package.json index 4c870526..9e244f4b 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "humanize-duration": "^3.15.0", "js-yaml": "^3.13.1", "knub": "^20.0.0", + "last-commit-log": "^2.1.0", "lodash.at": "^4.6.0", "lodash.chunk": "^4.2.0", "lodash.difference": "^4.5.0", diff --git a/src/index.ts b/src/index.ts index 66bbe763..64a9180d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -90,6 +90,7 @@ import { RemindersPlugin } from "./plugins/Reminders"; import { errorMessage, successMessage } from "./utils"; import { ZeppelinPlugin } from "./plugins/ZeppelinPlugin"; import { customArgumentTypes } from "./customArgumentTypes"; +import { startUptimeCounter } from "./uptime"; // Run latest database migrations logger.info("Running database migrations"); @@ -204,6 +205,10 @@ connect().then(async conn => { }, }); + client.once("ready", () => { + startUptimeCounter(); + }); + logger.info("Starting the bot"); bot.run(); }); diff --git a/src/plugins/Utility.ts b/src/plugins/Utility.ts index 82103e77..70e45970 100644 --- a/src/plugins/Utility.ts +++ b/src/plugins/Utility.ts @@ -1,5 +1,17 @@ import { decorators as d, getCommandSignature, IPluginOptions, ICommandDefinition } from "knub"; -import { CategoryChannel, Channel, EmbedOptions, Member, Message, Role, TextChannel, User, VoiceChannel } from "eris"; +import { + CategoryChannel, + Channel, + EmbedOptions, + GuildChannel, + Member, + Message, + MessageContent, + Role, + TextChannel, + User, + VoiceChannel, +} from "eris"; import { channelMentionRegex, chunkArray, @@ -9,7 +21,9 @@ import { isSnowflake, multiSorter, noop, + resolveMember, simpleClosestStringMatch, + sleep, sorter, stripObjectToScalars, successMessage, @@ -26,6 +40,9 @@ import { SavedMessage } from "../data/entities/SavedMessage"; import { GuildSavedMessages } from "../data/GuildSavedMessages"; import { GuildArchives } from "../data/GuildArchives"; import { ZeppelinPlugin } from "./ZeppelinPlugin"; +import { getCurrentUptime } from "../uptime"; + +import LCL from "last-commit-log"; const { performance } = require("perf_hooks"); @@ -48,6 +65,7 @@ interface IUtilityPluginConfig { can_source: boolean; can_vcmove: boolean; can_help: boolean; + can_about: boolean; } export class UtilityPlugin extends ZeppelinPlugin { @@ -73,6 +91,7 @@ export class UtilityPlugin extends ZeppelinPlugin { can_source: false, can_vcmove: false, can_help: false, + can_about: false, }, overrides: [ { @@ -95,6 +114,7 @@ export class UtilityPlugin extends ZeppelinPlugin { can_reload_guild: true, can_ping: true, can_source: true, + can_about: true, }, }, ], @@ -792,6 +812,65 @@ export class UtilityPlugin extends ZeppelinPlugin { createChunkedMessage(msg.channel, message); } + @d.command("about") + @d.permission("can_about") + async aboutCmd(msg: Message) { + const uptime = getCurrentUptime(); + const prettyUptime = humanizeDuration(uptime, { largest: 2, round: true }); + + const lcl = new LCL(); + const lastCommit = await lcl.getLastCommit(); + + const shard = this.bot.shards.get(this.bot.guildShardMap[this.guildId]); + + const basicInfoRows = [ + ["Uptime", prettyUptime], + ["Last update", moment(lastCommit.committer.date, "X").format("LL [at] H:mm [(UTC)]")], + ["Version", lastCommit.shortHash], + ["API latency", `${shard.latency}ms`], + ]; + + const loadedPlugins = Object.keys(this.guildConfig.plugins); + + const aboutContent: MessageContent = { + embed: { + title: `About ${this.bot.user.username}`, + fields: [ + { + name: "Basic info", + value: + basicInfoRows + .map(([label, value]) => { + return `${label}: **${value}**`; + }) + .join("\n") + embedPadding, + }, + { + name: "Loaded plugins on this server", + value: loadedPlugins.join(", "), + }, + ], + }, + }; + + // For the embed color, find the highest colored role the bot has - this is their color on the server as well + const botMember = await resolveMember(this.bot, this.guild, this.bot.user.id); + let botRoles = botMember.roles.map(r => (msg.channel as GuildChannel).guild.roles.get(r)); + botRoles = botRoles.filter(r => !!r); // Drop any unknown roles + botRoles = botRoles.filter(r => r.color); // Filter to those with a color + botRoles.sort(sorter("position", "DESC")); // Sort by position (highest first) + if (botRoles.length) { + aboutContent.embed.color = botRoles[0].color; + } + + // Use the bot avatar as the embed image + if (this.bot.user.avatarURL) { + aboutContent.embed.thumbnail = { url: this.bot.user.avatarURL }; + } + + msg.channel.createMessage(aboutContent); + } + @d.command("reload_guild") @d.permission("can_reload_guild") reloadGuildCmd(msg: Message) { diff --git a/src/uptime.ts b/src/uptime.ts new file mode 100644 index 00000000..c47dbcfd --- /dev/null +++ b/src/uptime.ts @@ -0,0 +1,9 @@ +let start = 0; + +export function startUptimeCounter() { + start = Date.now(); +} + +export function getCurrentUptime() { + return Date.now() - start; +}