This commit is contained in:
nolan 2020-08-16 00:27:59 -07:00
commit 566c73e35a
12 changed files with 2667 additions and 55 deletions

View File

@ -136,6 +136,10 @@ class DiscordClient extends Client {
return this._options.prefix;
}
get storage() {
return this.storageManager;
}
}
module.exports = DiscordClient;

View File

@ -1,15 +1,14 @@
const { Command } = require('../../../../interfaces/');
const os = require('os');
class StatsCommand extends Command {
constructor(client) {
super(client, {
name: 'about',
name: 'stats',
module: 'developer',
aliases: [
'stats',
'info'
],
usage: '',
restricted: true,
@ -27,14 +26,15 @@ class StatsCommand extends Command {
}
async execute(message, { params, args }) {
async execute(message) {
// TODO:
// Add some stuff that only shows when a dev runs the command, for instance amount of cached messages etc
const { guild } = message;
const { guild, author } = message;
const { shard } = this.client;
//Shards eval
const evalFunc = (thisArg) => {
return {
users: thisArg.users.cache.size,
@ -45,6 +45,7 @@ class StatsCommand extends Command {
};
};
//Manager eval
const mEvalFunc = (thisArg) => {
return {
memory: Math.floor(process.memoryUsage().heapUsed / 1024 / 1024),
@ -55,23 +56,24 @@ class StatsCommand extends Command {
const shardResults = await shard.broadcastEval(evalFunc).catch((error) => this.client.logger.error(error));
const managerResult = await this.client.managerEval(`(${mEvalFunc})(this)`).catch((error) => this.client.logger.error(error));
const descValues = {
devs: await this.client.resolveUsers(this.client._options.bot.owners).then((owners) => {
return owners.map((o) => o.tag).join(', ');
}),
uptime: this.client.resolver.timeAgo(Math.floor(managerResult.uptime/1000)),
//Current shard
const mainValues = {
uptime: this.client.resolver.timeAgo(Math.floor(managerResult.uptime / 1000), true, true, true),
memory: managerResult.memory,
shards: shard.count
shards: shard.count,
library: require('discord.js').version
};
//All shards combined
const shardValues = {
cachedUsers: this.client.users.cache.size,
guilds: this.client.guilds.cache.size,
channels: this.client.channels.cache.size,
uptime: this.client.resolver.timeAgo(Math.floor(this.client.uptime/1000)),
uptime: this.client.resolver.timeAgo(Math.floor(this.client.uptime / 1000), true, true, true),
memory: Math.floor(process.memoryUsage().heapUsed / 1024 / 1024)
};
//Compile shard data
const totalValues = shardResults.reduce((acc, curr) => {
Object.entries(curr).forEach(([key, val]) => {
if (!acc[key]) acc[key] = 0;
@ -79,28 +81,119 @@ class StatsCommand extends Command {
});
return acc;
}, {});
totalValues.uptime = this.client.resolver.timeAgo(Math.floor(totalValues.uptime / 1000));
totalValues.uptime = this.client.resolver.timeAgo(Math.floor(totalValues.uptime / 1000), true, true, true);
//System information
const CPU = os.cpus();
const memoryFree = (os.freemem() / 1024 / 1024 / 1024).toFixed(1);
const memoryTotal = (os.totalmem() / 1024 / 1024 / 1024).toFixed(1);
const sysInfo = {
devs: await this.client.resolveUsers(this.client._options.bot.owners).then((owners) => {
return owners.map((o) => o.tag).join(', ');
}),
cpu: CPU[0].model,
cores: CPU.length,
memoryUsed: memoryTotal - memoryFree,
memoryTotal,
osType: os.type(),
uptime: this.client.resolver.timeAgo(os.uptime(), true, true, true),
hostname: os.hostname()
};
//Command statistics - probably expand this further
const commands = this.client.registry.components.filter((comp) => comp.type === 'command');
const commandValues = {
invokes: commands.reduce((acc, cmd) => acc + cmd._invokes.success + cmd._invokes.fail, 0),
success: commands.reduce((acc, cmd) => acc + cmd._invokes.success, 0),
fail: commands.reduce((acc, cmd) => acc + cmd._invokes.fail, 0)
};
const embed = {
title: message.format('C_STATS_TITLE', {
client: this.client.user.tag,
version: require('../../../../../package.json').version
}),
description: message.format('C_STATS_DESC', descValues),
description: message.format('C_STATS_SYSTEM_VALUE', sysInfo),
fields: [
{
name: message.format('C_STATS_MAIN'),
value: message.format('C_STATS_MAIN_VALUE', mainValues),
inline: true
},
{
name: message.format('C_STATS_CURRENT_SHARD', { shard: guild.shardID }),
value: message.format('C_STATS_CURRENT_SHARDS_VALUE', shardValues),
inline: true
},
{
name: message.format('C_STATS_TOTAL', { shards: shard.count }),
name: message.format('C_STATS_TOTAL'),
value: message.format('C_STATS_TOTAL_VALUE', totalValues),
inline: true
},
{
name: message.format('C_STATS_COMMANDS'),
value: message.format('C_STATS_COMMANDS_VALUE', commandValues),
inline: true
}
]
};
if (author.developer) {
//Mongo DB
const stats = await this.client.storage.mongodb.stats();
const dbStats = {
db: stats.db,
collections: stats.collections,
objects: stats.objects,
avgObjSize: (stats.avgObjSize / 1024 / 1024).toFixed(1),
totalSize: (stats.dataSize / 1024 / 1024 / 1024).toFixed(2)
};
embed.fields.push({
name: message.format('C_STATS_MONGODB'),
value: message.format('C_STATS_MONGODB_VALUE', dbStats),
inline: true
});
//Other
const evalFunc2 = () => {
let msg = 0,
mem = 0;
// eslint-disable-next-line no-return-assign
this.channels.cache.forEach((c) => {
msg += c.messages?.cache.size || 0
});
this.guilds.cache.forEach((g) => {
mem += g.members.cache.size
})
return {
cachedMessages: msg,
cachedMembers: mem
};
};
const result = await shard.broadcastEval(evalFunc2).catch((error) => this.client.logger.error(error.stack));
console.log(result);
const other = result.reduce((acc, curr) => {
Object.entries(curr).forEach(([key, val]) => {
if (!acc[key]) acc[key] = 0;
acc[key] += val;
});
return acc;
}, {});
other['memberAvg'] = Math.floor(other.cachedMembers / shard.count);
other['messageAvg'] = Math.floor(other.cachedMessages / shard.count);
embed.fields.push({
name: message.format('C_STATS_CACHE'),
value: message.format('C_STATS_CACHE_VALUE', other),
inline: true
});
}
message.embed(embed);
}

View File

@ -92,6 +92,9 @@ class GuildCommand extends Command {
],
thumbnail: {
url: guild.iconURL()
},
footer: {
text: `• Server ID: ${guild.id} • Shard ID: ${guild.shardID}`
}
};

View File

@ -110,8 +110,8 @@ class UserCommand extends Command {
response = {
author: {
name: Util.escapeMarkdown(user.tag),
icon_url: user.displayAvatarURL() //eslint-disable-line camelcase
name: Util.escapeMarkdown(user.tag)
// icon_url: user.displayAvatarURL() //eslint-disable-line camelcase
},
description: response,
thumbnail: {

View File

@ -41,7 +41,7 @@ class AvatarCommand extends Command {
if (!user) user = message.author;
let avatar = null;
try {
avatar = user.displayAvatarURL({ format: args.format?.value || 'webp', size: args.size?.value || 128, dynamic: true });
avatar = user.displayAvatarURL({ format: args.format?.value || 'webp', size: args.size?.value || 256, dynamic: true });
} catch(error) {
message.respond(message.format('C_AVATAR_FORMATERROR'), { emoji: 'failure' });
return undefined;

View File

@ -70,9 +70,11 @@ const Message = Structures.extend('Message', (Message) => {
params: this.parameters,
args: this.arguments
});
this.command._invokes.success++;
if(resolved instanceof Promise) await resolved;
return { error: false };
} catch(error) {
} catch (error) {
this.command._invokes.fail++;
return { error: true, message: error };
}

View File

@ -43,6 +43,10 @@ class Command extends Component {
};
this._throttles = new Map();
this._invokes = {
success: 0,
fail: 0
};
}

View File

@ -7,8 +7,21 @@ Reloads components and language files.
[C_STATS_TITLE]
Statistics for {client} ({version})
[C_STATS_DESC]
[C_STATS_MAIN]
__**Main Process**__
[C_STATS_SYSTEM_VALUE]
**Developers:** {devs}
**Hostname:** {hostname}
**CPU:** {cpu}
**Threads:** {cores}
**Memory:** {memoryUsed}/{memoryTotal}GB
**OS Type:** {osType}
**System Uptime:** {uptime}
[C_STATS_MAIN_VALUE]
**Library:** Discord.js
**Library Version:** {library}
**Manager Uptime:** {uptime}
**Managed Shards:** {shards}
**Manager Memory Consumption:** {memory}MB
@ -32,3 +45,30 @@ __**All shards**__
**Channels:** {channels}
**Average Uptime:** {uptime}
**Total Memory Consumption:** {memory}MB
[C_STATS_COMMANDS]
__**Command usage since start**__
[C_STATS_COMMANDS_VALUE]
**Invokes:** {invokes}
**Succeeds:** {success}
**Fails:** {fail}
[C_STATS_MONGODB]
__**MongoDB**__
[C_STATS_MONGODB_VALUE]
**Database:** {db}
**Collections:** {collections}
**Entries:** {objects}
**Average Entry Size:** {avgObjSize}MB
**Total DB Size:** {totalSize}GB
[C_STATS_CACHE]
__**Cache**__
[C_STATS_CACHE_VALUE]
**Messages:** {cachedMessages}
**Average caches messages per shard:** {messageAvg}
**Members:** {cachedMembers}
**Average cached members per shard:** {memberAvg}

View File

@ -117,14 +117,12 @@ __Server information for **{name}**__
{emoji_booster3} **Boosters:** {boosters}
{emoji_calendar} **Date created:** {createdAt}
{emoji_region} **Voice region:** {region}
{emoji_id} **Server ID:** {id}
{emoji_id} **Shard ID:** {shard}
[C_GUILD_MEMBERS_NAME]
__Members__
[C_GUILD_MEMBERS]
{emoji_member} **Count:**
{emoji_members} **Count:**
{memberCount}/{maxMembers}
{emoji_online} **Online:**
{approxPresences}/{maxPresences}

View File

@ -124,7 +124,7 @@ class MongodbTable {
}
//Statistics
statistics(options = {}) {
stats(options = {}) {
return new Promise((resolve, reject) => {
if(!this.provider._initialized) return reject(new Error('MongoDB is not connected.'));
this.collection.stats(options, (error, statistics) => {

View File

@ -25,6 +25,20 @@ class MongoDBProvider extends Provider {
}
stats(options = {}) {
return new Promise((resolve, reject) => {
if (!this._initialized) return reject(new Error('MongoDB is not connected.'));
this.db.stats(options, (error, result) => {
if (error) reject(error);
resolve(result);
});
});
}
get guilds() {
return this.tables.guilds;
}

2516
yarn.lock

File diff suppressed because it is too large Load Diff