Skip to content

Commit

Permalink
fix: refactor postBotStats.ts
Browse files Browse the repository at this point in the history
  • Loading branch information
mariusbegby committed Sep 14, 2023
1 parent 6beb29d commit f06f2ae
Showing 1 changed file with 99 additions and 96 deletions.
195 changes: 99 additions & 96 deletions src/utils/other/postBotStats.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Guild } from 'discord.js';
import { ClientRequest, ClientRequestArgs } from 'node:http';
import { Client } from 'discord.js';
import { ClientRequest, ClientRequestArgs, IncomingMessage } from 'node:http';
import https from 'node:https';
import { Logger } from 'pino';
import loggerModule from '../../services/logger';
import { PostBotStatsParams, PostBotStatsSite } from '../../types/utilTypes';
import { fetchTotalGuildStatistics } from '../shardUtils';

export const postBotStats = async ({ client, executionId }: PostBotStatsParams) => {
const logger: Logger = loggerModule.child({
Expand All @@ -13,41 +14,107 @@ export const postBotStats = async ({ client, executionId }: PostBotStatsParams)
shardId: client.shard?.ids[0]
});

if (client.shard?.ids[0] !== 0) {
const shardId: number = client.shard!.ids[0];

if (shardId !== 0) {
return;
}

if (process.env.NODE_ENV !== 'production') {
logger.debug('Not posting bot stats because NODE_ENV is not production.');
return;
}

let guildCount: number = 0;
let memberCount: number = 0;
const shardCount: number = client.shard.count;
const shardId: number = client.shard.ids[0];
const shardCount: number = client.shard!.count;
const { guildCount, memberCount } = await fetchGuildAndMemberCounts(client, logger);

const botSites: PostBotStatsSite[] = createSites(shardId, shardCount, guildCount, memberCount);

try {
const enabledSites = botSites.filter((site) => site.enabled);

if (enabledSites.length === 0) {
logger.debug('No sites are enabled. Not posting bot stats.');
return;
}

logger.info(
`Starting to post bot stats with guild count ${guildCount} and member count ${memberCount} for ${enabledSites.length} sites...`
);

await postStatsToSites(enabledSites, logger);
} catch (error) {
logger.error(error, 'Failed to post bot stats to sites.');
}
};

async function fetchGuildAndMemberCounts(client: Client, logger: Logger) {
let guildCount = 0;
let memberCount = 0;

try {
logger.debug('Gathering data about guild and member count from shards...');
await client!
.shard!.fetchClientValues('guilds.cache')
.then((results) => {
const guildCaches: Guild[][] = results as Guild[][];
guildCaches.map((guildCache: Guild[]) => {
if (guildCache) {
guildCount += guildCache.length;
memberCount += guildCache.reduce((acc: number, guild: Guild) => acc + guild.memberCount, 0);
}
});

logger.debug('Successfully fetched client values from shards.');
})
.catch((error) => {
logger.error(error, 'Failed to fetch client values from shards.');
});
const { totalGuildCount, totalMemberCount } = await fetchTotalGuildStatistics(client);
guildCount = totalGuildCount;
memberCount = totalMemberCount;
} catch (error) {
logger.error(error, 'Failed to gather data about guild and member count from shards.');
}

return { guildCount, memberCount };
}

async function postStatsToSites(enabledSites: PostBotStatsSite[], logger: Logger) {
const statusPromises = enabledSites.map((site) => {
return new Promise<number | null>((resolve, reject) => {
const options: ClientRequestArgs = {
protocol: 'https:',
hostname: site.hostname,
port: 443,
path: site.path,
method: site.method,
headers: {
'Content-Type': 'application/json',
Authorization: site.token
}
};

const request: ClientRequest = https.request(options, (res) => {
const statusCode = handleResponse(res, site, logger);
resolve(statusCode);
});

request.on('error', (error) => {
logger.error(error, `Request to ${site.hostname} failed.`);
reject(error);
});

request.write(JSON.stringify(site.body));
request.end();
});
});

const statusCodes = await Promise.all(statusPromises);
logger.info(`Successfully posted bot stats with status codes ${statusCodes.join(', ')}.`);
}

function handleResponse(res: IncomingMessage, site: PostBotStatsSite, logger: Logger): number | null {
if (typeof res.statusCode === 'number') {
res.statusCode === 200
? logger.debug(`Request to ${site.hostname}: statusCode: ${res.statusCode}`)
: logger.warn(`Request to ${site.hostname}: statusCode: ${res.statusCode}`);
return res.statusCode;
} else {
logger.error(`Request to ${site.hostname}: statusCode is undefined or not a number (${res.statusCode}).`);
return null;
}
}

function createSites(shardId: number, shardCount: number, guildCount: number, memberCount: number): PostBotStatsSite[] {
/* eslint-disable camelcase */
const sites: PostBotStatsSite[] = [
return [
{
enabled: process.env.NODE_ENV === 'production' && process.env.BOTLIST_TOP_GG_API_TOKEN ? true : false,
enabled: process.env.BOTLIST_TOP_GG_API_TOKEN ? true : false,
hostname: 'top.gg',
path: `/api/bots/${process.env.DISCORD_APPLICATION_ID}/stats`,
method: 'POST',
Expand All @@ -59,10 +126,7 @@ export const postBotStats = async ({ client, executionId }: PostBotStatsParams)
token: process.env.BOTLIST_TOP_GG_API_TOKEN ?? ''
},
{
enabled:
process.env.NODE_ENV === 'production' && process.env.BOTLIST_DISCORD_BOT_LIST_COM_API_TOKEN
? true
: false,
enabled: process.env.BOTLIST_DISCORD_BOT_LIST_COM_API_TOKEN ? true : false,
hostname: 'discordbotlist.com',
path: `/api/v1/bots/${process.env.DISCORD_APPLICATION_ID}/stats`,
method: 'POST',
Expand All @@ -74,7 +138,7 @@ export const postBotStats = async ({ client, executionId }: PostBotStatsParams)
token: process.env.BOTLIST_DISCORD_BOT_LIST_COM_API_TOKEN ?? ''
},
{
enabled: process.env.NODE_ENV === 'production' && process.env.BOTLIST_DISCORDS_COM_API_TOKEN ? true : false,
enabled: process.env.BOTLIST_DISCORDS_COM_API_TOKEN ? true : false,
hostname: 'discords.com',
path: `/bots/api/bot/${process.env.DISCORD_APPLICATION_ID}`,
method: 'POST',
Expand All @@ -84,8 +148,7 @@ export const postBotStats = async ({ client, executionId }: PostBotStatsParams)
token: process.env.BOTLIST_DISCORDS_COM_API_TOKEN ?? ''
},
{
enabled:
process.env.NODE_ENV === 'production' && process.env.BOTLIST_DISCORD_BOTS_GG_API_TOKEN ? true : false,
enabled: process.env.BOTLIST_DISCORD_BOTS_GG_API_TOKEN ? true : false,
hostname: 'discord.bots.gg',
path: `/api/v1/bots/${process.env.DISCORD_APPLICATION_ID}/stats`,
method: 'POST',
Expand All @@ -97,7 +160,7 @@ export const postBotStats = async ({ client, executionId }: PostBotStatsParams)
token: process.env.BOTLIST_DISCORD_BOTS_GG_API_TOKEN ?? ''
},
{
enabled: process.env.NODE_ENV === 'production' && process.env.BOTLIST_BOTLIST_ME_API_TOKEN ? true : false,
enabled: process.env.BOTLIST_BOTLIST_ME_API_TOKEN ? true : false,
hostname: 'api.botlist.me',
path: `/api/v1/bots/${process.env.DISCORD_APPLICATION_ID}/stats`,
method: 'POST',
Expand All @@ -108,8 +171,7 @@ export const postBotStats = async ({ client, executionId }: PostBotStatsParams)
token: process.env.BOTLIST_BOTLIST_ME_API_TOKEN ?? ''
},
{
enabled:
process.env.NODE_ENV === 'production' && process.env.BOTLIST_DISCORDLIST_GG_API_TOKEN ? true : false,
enabled: process.env.BOTLIST_DISCORDLIST_GG_API_TOKEN ? true : false,
hostname: 'api.discordlist.gg',
path: `/v0/bots/${process.env.DISCORD_APPLICATION_ID}/guilds`,
method: 'POST',
Expand All @@ -119,10 +181,7 @@ export const postBotStats = async ({ client, executionId }: PostBotStatsParams)
token: `Bearer ${process.env.BOTLIST_DISCORDLIST_GG_API_TOKEN}`
},
{
enabled:
process.env.NODE_ENV === 'production' && process.env.BOTLIST_DISCORD_BOTLIST_EU_API_TOKEN
? true
: false,
enabled: process.env.BOTLIST_DISCORD_BOTLIST_EU_API_TOKEN ? true : false,
hostname: 'api.discord-botlist.eu',
path: '/v1/update',
method: 'PATCH',
Expand All @@ -132,60 +191,4 @@ export const postBotStats = async ({ client, executionId }: PostBotStatsParams)
token: `Bearer ${process.env.BOTLIST_DISCORD_BOTLIST_EU_API_TOKEN}`
}
];

try {
const enabledSites = sites.filter((site) => site.enabled);

if (enabledSites.length === 0) {
logger.debug('No sites are enabled. Not posting bot stats.');
return;
}

logger.info(
`Starting to post bot stats with guild count ${guildCount} and member count ${memberCount} for ${enabledSites.length} sites...`
);

const statusPromises = enabledSites.map((site) => {
return new Promise<number | null>((resolve, reject) => {
const options: ClientRequestArgs = {
protocol: 'https:',
hostname: site.hostname,
port: 443,
path: site.path,
method: site.method,
headers: {
'Content-Type': 'application/json',
Authorization: site.token
}
};

const request: ClientRequest = https.request(options, (res) => {
if (typeof res.statusCode === 'number') {
res.statusCode === 200
? logger.debug(`Request to ${site.hostname}: statusCode: ${res.statusCode}`)
: logger.warn(`Request to ${site.hostname}: statusCode: ${res.statusCode}`);
resolve(res.statusCode);
} else {
logger.error(
`Request to ${site.hostname}: statusCode is undefined or not a number (${res.statusCode}).`
);
resolve(null);
}
});

request.on('error', (error) => {
logger.error(error, `Request to ${site.hostname} failed.`);
reject(error);
});

request.write(JSON.stringify(site.body));
request.end();
});
});

const statusCodes = await Promise.all(statusPromises);
logger.info(`Successfully posted bot stats with status codes ${statusCodes.join(', ')}.`);
} catch (error) {
logger.error(error, 'Failed to post bot stats to sites.');
}
};
}

0 comments on commit f06f2ae

Please sign in to comment.