Continued work on heatmap

This commit is contained in:
Ean Milligan (Bastion) 2022-06-26 20:18:41 -04:00
parent e8464cf7bb
commit 8e6467fd17
10 changed files with 170 additions and 126 deletions

View File

@ -50,6 +50,8 @@ The Artificer comes with a few supplemental commands to the main rolling command
* If bot is given the permission `Manage Messages`, the bot will remove the message requesting the emote.
* `[[stats` or `[[s`
* Prints out how many users, channels, and servers the bot is currently serving.
* `[[heatmap` or `[[hm`
* Heatmap of when the roll command is run the most.
* `[[report` or `[[r [command that failed]`
* People aren't perfect, but this bot is trying to be.
* If you encounter a command that errors out or returns something unexpected, please use this command to alert the developers of the problem.

View File

@ -12,6 +12,7 @@ export const config = {
},
"api": { // Setting for the built-in API
"enable": false, // Leave this off if you have no intention of using this/supporting it
"publicDomain": 'http://example.com/', // Public domain that the API is behind, should end with a /
"port": 8080, // Port for the API to listen on
"supportURL": "your_support_url_for_api_abuse", // Fill this in with the way you wish to be contacted when somebody needs to report API key abuse
"rateLimitTime": 10000, // Time range for how often the API rate limits will be lifted (time in ms)

View File

@ -91,114 +91,121 @@ const start = async (): Promise<void> => {
});
}
if (authenticated) {
// Handle the authenticated request
switch (request.method) {
case 'GET':
switch (path.toLowerCase()) {
case '/key':
case '/key/':
endpoints.get.apiKeyAdmin(requestEvent, query, apiUserid);
break;
case '/channel':
case '/channel/':
endpoints.get.apiChannel(requestEvent, query, apiUserid);
break;
case '/roll':
case '/roll/':
endpoints.get.apiRoll(requestEvent, query, apiUserid);
break;
default:
// Alert API user that they messed up
requestEvent.respondWith(stdResp.NotFound('Auth Get'));
break;
}
break;
case 'POST':
switch (path.toLowerCase()) {
case '/channel/add':
case '/channel/add/':
endpoints.post.apiChannelAdd(requestEvent, query, apiUserid);
break;
default:
// Alert API user that they messed up
requestEvent.respondWith(stdResp.NotFound('Auth Post'));
break;
}
break;
case 'PUT':
switch (path.toLowerCase()) {
case '/key/ban':
case '/key/ban/':
case '/key/unban':
case '/key/unban/':
case '/key/activate':
case '/key/activate/':
case '/key/deactivate':
case '/key/deactivate/':
endpoints.put.apiKeyManage(requestEvent, query, apiUserid, path);
break;
case '/channel/ban':
case '/channel/ban/':
case '/channel/unban':
case '/channel/unban/':
endpoints.put.apiChannelManageBan(requestEvent, query, apiUserid, path);
break;
case '/channel/activate':
case '/channel/activate/':
case '/channel/deactivate':
case '/channel/deactivate/':
endpoints.put.apiChannelManageActive(requestEvent, query, apiUserid, path);
break;
default:
// Alert API user that they messed up
requestEvent.respondWith(stdResp.NotFound('Auth Put'));
break;
}
break;
case 'DELETE':
switch (path.toLowerCase()) {
case '/key/delete':
case '/key/delete/':
endpoints.delete.apiKeyDelete(requestEvent, query, apiUserid, apiUserEmail, apiUserDelCode);
break;
default:
// Alert API user that they messed up
requestEvent.respondWith(stdResp.NotFound('Auth Del'));
break;
}
break;
default:
// Alert API user that they messed up
requestEvent.respondWith(stdResp.MethodNotAllowed('Auth'));
break;
}
if (path) {
if (authenticated) {
// Handle the authenticated request
switch (request.method) {
case 'GET':
switch (path.toLowerCase()) {
case '/key':
case '/key/':
endpoints.get.apiKeyAdmin(requestEvent, query, apiUserid);
break;
case '/channel':
case '/channel/':
endpoints.get.apiChannel(requestEvent, query, apiUserid);
break;
case '/roll':
case '/roll/':
endpoints.get.apiRoll(requestEvent, query, apiUserid);
break;
default:
// Alert API user that they messed up
requestEvent.respondWith(stdResp.NotFound('Auth Get'));
break;
}
break;
case 'POST':
switch (path.toLowerCase()) {
case '/channel/add':
case '/channel/add/':
endpoints.post.apiChannelAdd(requestEvent, query, apiUserid);
break;
default:
// Alert API user that they messed up
requestEvent.respondWith(stdResp.NotFound('Auth Post'));
break;
}
break;
case 'PUT':
switch (path.toLowerCase()) {
case '/key/ban':
case '/key/ban/':
case '/key/unban':
case '/key/unban/':
case '/key/activate':
case '/key/activate/':
case '/key/deactivate':
case '/key/deactivate/':
endpoints.put.apiKeyManage(requestEvent, query, apiUserid, path);
break;
case '/channel/ban':
case '/channel/ban/':
case '/channel/unban':
case '/channel/unban/':
endpoints.put.apiChannelManageBan(requestEvent, query, apiUserid, path);
break;
case '/channel/activate':
case '/channel/activate/':
case '/channel/deactivate':
case '/channel/deactivate/':
endpoints.put.apiChannelManageActive(requestEvent, query, apiUserid, path);
break;
default:
// Alert API user that they messed up
requestEvent.respondWith(stdResp.NotFound('Auth Put'));
break;
}
break;
case 'DELETE':
switch (path.toLowerCase()) {
case '/key/delete':
case '/key/delete/':
endpoints.delete.apiKeyDelete(requestEvent, query, apiUserid, apiUserEmail, apiUserDelCode);
break;
default:
// Alert API user that they messed up
requestEvent.respondWith(stdResp.NotFound('Auth Del'));
break;
}
break;
default:
// Alert API user that they messed up
requestEvent.respondWith(stdResp.MethodNotAllowed('Auth'));
break;
}
// Update rate limit details
if (updateRateLimitTime) {
const apiTimeNow = new Date().getTime();
rateLimitTime.set(apiUseridStr, apiTimeNow);
}
} else if (!authenticated) {
// Handle the unathenticated request
switch (request.method) {
case 'GET':
switch (path.toLowerCase()) {
case '/key':
case '/key/':
endpoints.get.apiKey(requestEvent, query);
break;
default:
// Alert API user that they messed up
requestEvent.respondWith(stdResp.NotFound('NoAuth Get'));
break;
}
break;
default:
// Alert API user that they messed up
requestEvent.respondWith(stdResp.MethodNotAllowed('NoAuth'));
break;
// Update rate limit details
if (updateRateLimitTime) {
const apiTimeNow = new Date().getTime();
rateLimitTime.set(apiUseridStr, apiTimeNow);
}
} else if (!authenticated) {
// Handle the unathenticated request
switch (request.method) {
case 'GET':
switch (path.toLowerCase()) {
case '/key':
case '/key/':
endpoints.get.apiKey(requestEvent, query);
break;
case '/heatmap.png':
endpoints.get.heatmapPng(requestEvent);
break;
default:
// Alert API user that they messed up
requestEvent.respondWith(stdResp.NotFound('NoAuth Get'));
break;
}
break;
default:
// Alert API user that they messed up
requestEvent.respondWith(stdResp.MethodNotAllowed('NoAuth'));
break;
}
}
} else {
requestEvent.respondWith(stdResp.Forbidden('What are you trying to do?'));
}
} else if (authenticated && rateLimited) {
// Alert API user that they are doing this too often

View File

@ -3,25 +3,34 @@ import {
// Discordeno deps
DiscordenoMessage,
} from '../../deps.ts';
import { } from '../commandUtils.ts';
import { compilingStats } from '../commonEmbeds.ts';
import config from '../../config.ts';
import { LOCALMODE } from '../../flags.ts';
import { failColor, infoColor2 } from '../commandUtils.ts';
import utils from '../utils.ts';
export const heatmap = async (message: DiscordenoMessage) => {
// Light telemetry to see how many times a command is being run
dbClient.execute(queries.callIncCnt('heatmap')).catch((e) => utils.commonLoggers.dbError('heatmap.ts:14', 'call sproc INC_CNT on', e));
try {
const m = await message.send(compilingStats);
if (config.api.enable) {
const m = await message.send({
embeds: [{
title: 'Roll Heatmap',
color: infoColor2,
image: {
url: `${config.api.publicDomain}api/heatmap.png`,
},
}],
}).catch((e) => utils.commonLoggers.messageSendError('heatmap.ts:21', message, e));
// Calculate how many times commands have been run
const hmQuery = await dbClient.query(`SELECT * FROM roll_time_heatmap`).catch((e) => utils.commonLoggers.dbError('heatmap.ts:20', 'query', e));
console.log(hmQuery);
m.edit('').catch((e: Error) =>
utils.commonLoggers.messageEditError('heatmap.ts:21', m, e)
);
} catch (e) {
utils.commonLoggers.messageSendError('heatmap.ts:24', message, e);
console.log(m);
} else {
message.send({
embeds: [{
title: 'Roll Heatmap Disabled',
description: 'This command requires the bot\'s API to be enabled. If you are the host of this bot, check your `config.ts` file to enable it.',
color: failColor,
}],
}).catch((e) => utils.commonLoggers.messageSendError('heatmap.ts:21', message, e));
}
};

View File

@ -66,6 +66,11 @@ export const help = (message: DiscordenoMessage) => {
value: 'Statistics on the bot',
inline: true,
},
{
name: `\`${config.prefix}heatmap\``,
value: 'Heatmap of when the roll command is run the most',
inline: true,
},
{
name: `\`${config.prefix}xdydzracsq!${config.postfix}\` ...`,
value:

View File

@ -27,9 +27,9 @@ export const stats = async (message: DiscordenoMessage) => {
const cachedGuilds = await cacheHandlers.size('guilds');
const cachedChannels = await cacheHandlers.size('channels');
const cachedMembers = await cacheHandlers.size('members');
m.edit(generateStats(cachedGuilds + cache.dispatchedGuildIds.size, cachedChannels + cache.dispatchedChannelIds.size, cachedMembers, rolls, (total - rolls), rollRate, (totalRate - rollRate))).catch((e: Error) =>
utils.commonLoggers.messageEditError('stats.ts:38', m, e)
);
m.edit(generateStats(cachedGuilds + cache.dispatchedGuildIds.size, cachedChannels + cache.dispatchedChannelIds.size, cachedMembers, rolls, total - rolls, rollRate, totalRate - rollRate)).catch((
e: Error,
) => utils.commonLoggers.messageEditError('stats.ts:38', m, e));
} catch (e) {
utils.commonLoggers.messageSendError('stats.ts:41', message, e);
}

View File

@ -3,6 +3,7 @@ import { apiKey } from './gets/apiKey.ts';
import { apiRoll } from './gets/apiRoll.ts';
import { apiKeyAdmin } from './gets/apiKeyAdmin.ts';
import { apiChannel } from './gets/apiChannel.ts';
import { heatmapPng } from './gets/heatmapPng.ts';
import { apiChannelAdd } from './posts/apiChannelAdd.ts';
import { apiKeyManage } from './puts/apiKeyManage.ts';
import { apiChannelManageBan } from './puts/apiChannelManageBan.ts';
@ -17,6 +18,7 @@ export default {
apiRoll,
apiKeyAdmin,
apiChannel,
heatmapPng,
},
post: {
apiChannelAdd,

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

View File

@ -0,0 +1,16 @@
import {
// httpd deps
Status,
STATUS_TEXT,
} from '../../../deps.ts';
export const heatmapPng = async (requestEvent: Deno.RequestEvent) => {
const file = Deno.readFileSync('./src/endpoints/gets/heatmap.png');
// Send basic OK to indicate key has been sent
requestEvent.respondWith(
new Response(file, {
status: Status.OK,
statusText: STATUS_TEXT.get(Status.OK),
}),
);
};

View File

@ -63,7 +63,7 @@ const updateListStatistics = (botID: bigint, serverCount: number): void => {
// Keep one week of data
const hoursToKeep = 7 * 24;
const previousHours: Array<Array<PastCommandCount>> = []
const previousHours: Array<Array<PastCommandCount>> = [];
// updateHourlyRates() returns nothing
// Updates the hourlyRate for command usage
const updateHourlyRates = async () => {
@ -73,7 +73,7 @@ const updateHourlyRates = async () => {
if (previousHours.length > 1) {
const oldestHour = previousHours[0];
const computedDiff: Array<PastCommandCount> = []
const computedDiff: Array<PastCommandCount> = [];
for (let i = 0; i < newestHour.length; i++) {
computedDiff.push({
command: newestHour[i].command,
@ -85,7 +85,9 @@ const updateHourlyRates = async () => {
// Update DB
computedDiff.forEach(async (cmd) => {
log(LT.LOG, `Updating hourlyRate | Storing to DB: ${JSON.stringify(cmd)}`);
await dbClient.execute(`UPDATE command_cnt SET hourlyRate = ? WHERE command = ?`, [(cmd.count / previousHours.length), cmd.command]).catch((e) => utils.commonLoggers.dbError('intervals.ts:88', 'update', e));
await dbClient.execute(`UPDATE command_cnt SET hourlyRate = ? WHERE command = ?`, [cmd.count / previousHours.length, cmd.command]).catch((e) =>
utils.commonLoggers.dbError('intervals.ts:88', 'update', e)
);
});
}
@ -93,7 +95,7 @@ const updateHourlyRates = async () => {
previousHours.unshift();
}
} catch (e) {
log(LT.ERROR, `Something went wrong in previousHours interval | Error: ${e.name} - ${e.message}`)
log(LT.ERROR, `Something went wrong in previousHours interval | Error: ${e.name} - ${e.message}`);
}
};