From 0aaa6166af6ff17f9b643997fccb44de1b57b1e5 Mon Sep 17 00:00:00 2001 From: IRONM00N <64110067+IRONM00N@users.noreply.github.com> Date: Sat, 6 Aug 2022 21:07:39 -0400 Subject: track the number of guilds the bot is in so I can make a graph --- src/lib/extensions/discord-akairo/BushClient.ts | 81 ++++++++++++++----------- src/lib/models/shared/GuildCount.ts | 39 ++++++++++++ src/lib/models/shared/MemberCount.ts | 2 +- src/tasks/feature/memberCount.ts | 28 --------- src/tasks/stats/guildCount.ts | 24 ++++++++ src/tasks/stats/memberCount.ts | 28 +++++++++ 6 files changed, 138 insertions(+), 64 deletions(-) create mode 100644 src/lib/models/shared/GuildCount.ts delete mode 100644 src/tasks/feature/memberCount.ts create mode 100644 src/tasks/stats/guildCount.ts create mode 100644 src/tasks/stats/memberCount.ts (limited to 'src') diff --git a/src/lib/extensions/discord-akairo/BushClient.ts b/src/lib/extensions/discord-akairo/BushClient.ts index 286d9cf..44c995a 100644 --- a/src/lib/extensions/discord-akairo/BushClient.ts +++ b/src/lib/extensions/discord-akairo/BushClient.ts @@ -58,6 +58,7 @@ import { ModLog } from '../../models/instance/ModLog.js'; import { Reminder } from '../../models/instance/Reminder.js'; import { StickyRole } from '../../models/instance/StickyRole.js'; import { Global } from '../../models/shared/Global.js'; +import { GuildCount } from '../../models/shared/GuildCount.js'; import { MemberCount } from '../../models/shared/MemberCount.js'; import { Shared } from '../../models/shared/Shared.js'; import { Stat } from '../../models/shared/Stat.js'; @@ -78,41 +79,41 @@ const { Sequelize } = (await import('sequelize')).default; declare module 'discord.js' { export interface Client extends EventEmitter { /** The ID of the owner(s). */ - ownerID: Snowflake | Snowflake[]; + readonly ownerID: Snowflake | Snowflake[]; /** The ID of the superUser(s). */ - superUserID: Snowflake | Snowflake[]; + readonly superUserID: Snowflake | Snowflake[]; /** Whether or not the client is ready. */ - customReady: boolean; + readonly customReady: boolean; /** The configuration for the client. */ - config: Config; + readonly config: Config; /** Stats for the client. */ - stats: BushStats; + readonly stats: BushStats; /** The handler for the bot's listeners. */ - listenerHandler: BushListenerHandler; + readonly listenerHandler: BushListenerHandler; /** The handler for the bot's command inhibitors. */ - inhibitorHandler: BushInhibitorHandler; + readonly inhibitorHandler: BushInhibitorHandler; /** The handler for the bot's commands. */ - commandHandler: BushCommandHandler; + readonly commandHandler: BushCommandHandler; /** The handler for the bot's tasks. */ - taskHandler: BushTaskHandler; + readonly taskHandler: BushTaskHandler; /** The handler for the bot's context menu commands. */ - contextMenuCommandHandler: ContextMenuCommandHandler; + readonly contextMenuCommandHandler: ContextMenuCommandHandler; /** The database connection for this instance of the bot (production, beta, or development). */ - instanceDB: SequelizeType; + readonly instanceDB: SequelizeType; /** The database connection that is shared between all instances of the bot. */ - sharedDB: SequelizeType; + readonly sharedDB: SequelizeType; /** A custom logging system for the bot. */ - logger: BushLogger; + readonly logger: BushLogger; /** Cached global and guild database data. */ - cache: BushCache; + readonly cache: BushCache; /** Sentry error reporting for the bot. */ - sentry: typeof Sentry; + readonly sentry: typeof Sentry; /** Manages most aspects of the highlight command */ - highlightManager: HighlightManager; + readonly highlightManager: HighlightManager; /** The perspective api */ perspective: any; /** Client utilities. */ - utils: BushClientUtils; + readonly utils: BushClientUtils; /** A custom logging system for the bot. */ get console(): BushLogger; on(event: K, listener: (...args: BushClientEvents[K]) => Awaitable): this; @@ -151,8 +152,8 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url)); * The main hub for interacting with the Discord API. */ export class BushClient extends AkairoClient { - public declare ownerID: Snowflake[]; - public declare superUserID: Snowflake[]; + public declare readonly ownerID: Snowflake[]; + public declare readonly superUserID: Snowflake[]; /** * Whether or not the client is ready. @@ -162,62 +163,62 @@ export class BushClient extends AkairoClient extends AkairoClient extends AkairoClient extends AkairoClient extends AkairoClient>.`, false); } catch (e) { @@ -542,6 +550,9 @@ export interface BushClient extends EventEmitte removeAllListeners(event?: K): this; } +/** + * Various statistics + */ export interface BushStats { /** * The average cpu usage of the bot from the past 60 seconds. diff --git a/src/lib/models/shared/GuildCount.ts b/src/lib/models/shared/GuildCount.ts new file mode 100644 index 0000000..51e571a --- /dev/null +++ b/src/lib/models/shared/GuildCount.ts @@ -0,0 +1,39 @@ +import { type Sequelize } from 'sequelize'; +import { Environment } from '../../../../config/Config.js'; +const { DataTypes, Model } = (await import('sequelize')).default; + +export interface GuildCountModel { + timestamp: Date; + environment: Environment; + guildCount: number; +} + +export interface GuildCountCreationAttributes { + timestamp?: Date; + environment: Environment; + guildCount: number; +} + +/** + * The number of guilds that the bot is in for each environment. + */ +export class GuildCount extends Model implements GuildCountModel { + public declare timestamp: Date; + public declare environment: Environment; + public declare guildCount: number; + + /** + * Initializes the model. + * @param sequelize The sequelize instance. + */ + public static initModel(sequelize: Sequelize): void { + GuildCount.init( + { + timestamp: { type: DataTypes.DATE, allowNull: false, defaultValue: DataTypes.NOW }, + environment: { type: DataTypes.STRING, allowNull: false }, + guildCount: { type: DataTypes.BIGINT, allowNull: false } + }, + { sequelize, timestamps: false } + ); + } +} diff --git a/src/lib/models/shared/MemberCount.ts b/src/lib/models/shared/MemberCount.ts index 409d1ac..ea8795c 100644 --- a/src/lib/models/shared/MemberCount.ts +++ b/src/lib/models/shared/MemberCount.ts @@ -14,7 +14,7 @@ export interface MemberCountCreationAttributes { } /** - * Data specific to a certain instance of the bot. + * The member count of each guild that the bot is in that have over 100 members. */ export class MemberCount extends Model implements MemberCountModel { public declare timestamp: Date; diff --git a/src/tasks/feature/memberCount.ts b/src/tasks/feature/memberCount.ts deleted file mode 100644 index 9c31c5b..0000000 --- a/src/tasks/feature/memberCount.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { BushTask, MemberCount, Time } from '#lib'; -import assert from 'assert/strict'; - -export default class MemberCountTask extends BushTask { - public constructor() { - super('memberCount', { - delay: Time.Minute, - runOnStart: true - }); - } - - public override async exec() { - if (!this.client.config.isProduction) return; - - const res = await Promise.allSettled( - this.client.guilds.cache - .filter((g) => g.memberCount >= 100) - .map((g) => MemberCount.create({ guildId: g.id, memberCount: g.memberCount })) - ); - - res - .filter((r) => r.status === 'rejected') - .forEach((r) => { - assert(r.status === 'rejected'); - void this.client.console.error('memberCount', r.status); - }); - } -} diff --git a/src/tasks/stats/guildCount.ts b/src/tasks/stats/guildCount.ts new file mode 100644 index 0000000..262f00c --- /dev/null +++ b/src/tasks/stats/guildCount.ts @@ -0,0 +1,24 @@ +import { BushTask, Time } from '#lib'; +import { GuildCount } from '../../lib/models/shared/GuildCount.js'; + +export default class GuildCountTask extends BushTask { + public constructor() { + super('guildCount', { + delay: 15 * Time.Minute, + runOnStart: true + }); + } + + public override async exec() { + if (!this.client.config.isProduction) return; + + try { + await GuildCount.create({ + environment: this.client.config.environment, + guildCount: this.client.guilds.cache.size + }); + } catch (err) { + void this.client.console.error('guildCount', err); + } + } +} diff --git a/src/tasks/stats/memberCount.ts b/src/tasks/stats/memberCount.ts new file mode 100644 index 0000000..9c31c5b --- /dev/null +++ b/src/tasks/stats/memberCount.ts @@ -0,0 +1,28 @@ +import { BushTask, MemberCount, Time } from '#lib'; +import assert from 'assert/strict'; + +export default class MemberCountTask extends BushTask { + public constructor() { + super('memberCount', { + delay: Time.Minute, + runOnStart: true + }); + } + + public override async exec() { + if (!this.client.config.isProduction) return; + + const res = await Promise.allSettled( + this.client.guilds.cache + .filter((g) => g.memberCount >= 100) + .map((g) => MemberCount.create({ guildId: g.id, memberCount: g.memberCount })) + ); + + res + .filter((r) => r.status === 'rejected') + .forEach((r) => { + assert(r.status === 'rejected'); + void this.client.console.error('memberCount', r.status); + }); + } +} -- cgit