diff --git a/server/bot/client.ts b/server/bot/client.ts index 6eded74..bfca66c 100644 --- a/server/bot/client.ts +++ b/server/bot/client.ts @@ -113,12 +113,15 @@ export default class CommandParser { tempDB: DB // eslint-disable-line no-undef db: Db // eslint-disable-line no-undef evaluatedMessages: string[] // eslint-disable-line no-undef + // eslint-disable-next-line no-undef + analytics: { name: string, totalUse: number, averageExecTime: number[] }[] constructor (client: Client, tempDB: DB, db: Db) { this.commands = {} this.client = client this.tempDB = tempDB this.db = db + this.analytics = [] this.evaluatedMessages = [] this.onMessage = this.onMessage.bind(this) this.onMessageUpdate = this.onMessageUpdate.bind(this) @@ -165,6 +168,23 @@ export default class CommandParser { if (command.postGenerator) command.postGenerator(message, args, sent, context) } + async saveAnalytics (timeTaken: [number, number], name: string) { + // Get the local command info. + let commandInfo = this.analytics.find(i => i.name === name) + // If there is no info for the command then insert an object for it. + if (!commandInfo) { + this.analytics.push({ name, averageExecTime: [0, 0], totalUse: 0 }) + commandInfo = this.analytics.find(i => i.name === name) + } + // Calculate the average time of execution taken. + const averageExecTime = commandInfo.averageExecTime.map((i: number, index: number) => ( + ((i * commandInfo.totalUse) + timeTaken[index]) / (commandInfo.totalUse + 1) + )) + // Update local cache with analytics. + this.analytics[this.analytics.indexOf(commandInfo)].totalUse += 1 + this.analytics[this.analytics.indexOf(commandInfo)].averageExecTime = averageExecTime + } + async onMessage (message: Message) { if (message.content && !message.content.startsWith('/')) { botCallback(message, this.client, this.tempDB, this.db) @@ -185,6 +205,11 @@ export default class CommandParser { this.evaluatedMessages.splice(this.evaluatedMessages.findIndex(i => i === message.id), 1) }, 30000) // Execute command. + try { + const executeFirst = process.hrtime() // Initial high-precision time. + await this.executeCommand(this.commands[keys[i]], message) + const executeSecond = process.hrtime(executeFirst) // Time difference. + this.saveAnalytics(executeSecond, keys[i]) // Send analytics. try { await this.executeCommand(this.commands[keys[i]], message) } catch (e) { // On error, we tell the user of an unknown error and log it for our reference. message.channel.createMessage(this.commands[keys[i]].errorMessage) @@ -219,7 +244,12 @@ export default class CommandParser { this.evaluatedMessages.splice(this.evaluatedMessages.findIndex(i => i === message.id), 1) }, 30000) // Execute command. - try { await this.executeCommand(this.commands[keys[i]], message) } catch (e) { + try { + const executeFirst = process.hrtime() // Initial high precision time. + await this.executeCommand(this.commands[keys[i]], message) + const executeSecond = process.hrtime(executeFirst) // Time difference. + this.saveAnalytics(executeSecond, keys[i]) // Send analytics. + } catch (e) { // On error, we tell the user of an unknown error and log it for our reference. message.channel.createMessage(this.commands[keys[i]].errorMessage) console.error(e) diff --git a/server/bot/commands/admin/index.ts b/server/bot/commands/admin/index.ts index 834ffa3..b8a6a38 100644 --- a/server/bot/commands/admin/index.ts +++ b/server/bot/commands/admin/index.ts @@ -4,8 +4,8 @@ import { checkRolePosition } from '../../imports/permissions' import { Message } from 'eris' export { handleAddemoji, handleDeleteemoji, handleEditemoji, handleEmojiimage } from './emoji' export { handleWarn, handleWarnings, handleClearwarns, handleRemovewarn } from './warn' +export { handleGiverole, handleTakerole, handleNotify } from './roles' export { handleDeletechannel, handleEditchannel } from './channels' -export { handleGiverole, handleTakerole } from './roles' export { handleMute, handleUnmute } from './mute' export { handleBan, handleUnban } from './ban' @@ -86,8 +86,8 @@ export const handleKick: Command = { if (!f.silent) { client.createMessage((await client.getDMChannel(user.id)).id, f.args.length !== 0 ? `You have been kicked from ${message.member.guild.name} for ${f.args.join(' ')}.` - : `You have been kicked from ${message.member.guild.name}.` - ) + : `You have been kicked from ${message.member.guild.name}.` + ) } // WeChill if (message.member.guild.id === '402423671551164416') { diff --git a/server/bot/commands/admin/roles.ts b/server/bot/commands/admin/roles.ts index d1adf39..b98666b 100644 --- a/server/bot/commands/admin/roles.ts +++ b/server/bot/commands/admin/roles.ts @@ -103,3 +103,32 @@ export const handleTakerole: Command = { ? `Took the role **${role.name}** from you.` : `Took role **${role.name}** from ${user.mention}.` } } + +export const handleNotify: Command = { + name: 'notify', + opts: { + description: 'Ping a role which cannot be mentioned.', + fullDescription: 'Ping a role which cannot be mentioned.', + usage: '/notify (message)', + example: '/notify Helper testing', + guildOnly: true, + deleteCommand: true, + requirements: { permissions: { 'manageRoles': true } } + }, + generator: async (message, args) => { + // Find the role. + const arg = args.shift() + const role = message.member.guild.roles.find( + a => arg === a.id || a.name.toLowerCase() === arg.toLowerCase() || arg === a.mention + ) + if (!role) return `You have provided an invalid role name/ID, you ${getInsult()}.` + // Can the user manage this role? + if (role.position >= checkRolePosition(message.member) && !role.mentionable + ) return `You cannot notify this role, you ${getInsult()}.` + // Edit the role. + const wasMentionable = role.mentionable + if (!wasMentionable) await role.edit({ mentionable: true }) + await message.channel.createMessage(`${role.mention} ${args.join(' ')}`) + if (!wasMentionable) await role.edit({ mentionable: false }) + } +} diff --git a/server/bot/commands/help.ts b/server/bot/commands/help.ts index 5fb1adf..4d22433 100644 --- a/server/bot/commands/help.ts +++ b/server/bot/commands/help.ts @@ -37,6 +37,7 @@ let generalHelp = `**Jony Ive can do many commands 📡** \`/about\`, \`/ping\`, \`/uptime\` and \`/version\` - About the running instance of IveBot. \`/emojiImage\` - Image of an emoji. \`/giverole\` and \`/takerole\` - Edit roles. + \`/notify\` - Ping a role that cannot be pinged. **Administrative commands.** \`/ban\`, \`/unban\`, \`/kick\`, \`/mute\` and \`/unmute\` \`/addEmoji\`, \`/deleteEmoji\` and \`/editEmoji\`