Continued work on heatmap
This commit is contained in:
parent
e8464cf7bb
commit
8e6467fd17
|
@ -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.
|
* If bot is given the permission `Manage Messages`, the bot will remove the message requesting the emote.
|
||||||
* `[[stats` or `[[s`
|
* `[[stats` or `[[s`
|
||||||
* Prints out how many users, channels, and servers the bot is currently serving.
|
* 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]`
|
* `[[report` or `[[r [command that failed]`
|
||||||
* People aren't perfect, but this bot is trying to be.
|
* 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.
|
* If you encounter a command that errors out or returns something unexpected, please use this command to alert the developers of the problem.
|
||||||
|
|
|
@ -12,6 +12,7 @@ export const config = {
|
||||||
},
|
},
|
||||||
"api": { // Setting for the built-in API
|
"api": { // Setting for the built-in API
|
||||||
"enable": false, // Leave this off if you have no intention of using this/supporting it
|
"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
|
"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
|
"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)
|
"rateLimitTime": 10000, // Time range for how often the API rate limits will be lifted (time in ms)
|
||||||
|
|
219
src/api.ts
219
src/api.ts
|
@ -91,114 +91,121 @@ const start = async (): Promise<void> => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (authenticated) {
|
if (path) {
|
||||||
// Handle the authenticated request
|
if (authenticated) {
|
||||||
switch (request.method) {
|
// Handle the authenticated request
|
||||||
case 'GET':
|
switch (request.method) {
|
||||||
switch (path.toLowerCase()) {
|
case 'GET':
|
||||||
case '/key':
|
switch (path.toLowerCase()) {
|
||||||
case '/key/':
|
case '/key':
|
||||||
endpoints.get.apiKeyAdmin(requestEvent, query, apiUserid);
|
case '/key/':
|
||||||
break;
|
endpoints.get.apiKeyAdmin(requestEvent, query, apiUserid);
|
||||||
case '/channel':
|
break;
|
||||||
case '/channel/':
|
case '/channel':
|
||||||
endpoints.get.apiChannel(requestEvent, query, apiUserid);
|
case '/channel/':
|
||||||
break;
|
endpoints.get.apiChannel(requestEvent, query, apiUserid);
|
||||||
case '/roll':
|
break;
|
||||||
case '/roll/':
|
case '/roll':
|
||||||
endpoints.get.apiRoll(requestEvent, query, apiUserid);
|
case '/roll/':
|
||||||
break;
|
endpoints.get.apiRoll(requestEvent, query, apiUserid);
|
||||||
default:
|
break;
|
||||||
// Alert API user that they messed up
|
default:
|
||||||
requestEvent.respondWith(stdResp.NotFound('Auth Get'));
|
// Alert API user that they messed up
|
||||||
break;
|
requestEvent.respondWith(stdResp.NotFound('Auth Get'));
|
||||||
}
|
break;
|
||||||
break;
|
}
|
||||||
case 'POST':
|
break;
|
||||||
switch (path.toLowerCase()) {
|
case 'POST':
|
||||||
case '/channel/add':
|
switch (path.toLowerCase()) {
|
||||||
case '/channel/add/':
|
case '/channel/add':
|
||||||
endpoints.post.apiChannelAdd(requestEvent, query, apiUserid);
|
case '/channel/add/':
|
||||||
break;
|
endpoints.post.apiChannelAdd(requestEvent, query, apiUserid);
|
||||||
default:
|
break;
|
||||||
// Alert API user that they messed up
|
default:
|
||||||
requestEvent.respondWith(stdResp.NotFound('Auth Post'));
|
// Alert API user that they messed up
|
||||||
break;
|
requestEvent.respondWith(stdResp.NotFound('Auth Post'));
|
||||||
}
|
break;
|
||||||
break;
|
}
|
||||||
case 'PUT':
|
break;
|
||||||
switch (path.toLowerCase()) {
|
case 'PUT':
|
||||||
case '/key/ban':
|
switch (path.toLowerCase()) {
|
||||||
case '/key/ban/':
|
case '/key/ban':
|
||||||
case '/key/unban':
|
case '/key/ban/':
|
||||||
case '/key/unban/':
|
case '/key/unban':
|
||||||
case '/key/activate':
|
case '/key/unban/':
|
||||||
case '/key/activate/':
|
case '/key/activate':
|
||||||
case '/key/deactivate':
|
case '/key/activate/':
|
||||||
case '/key/deactivate/':
|
case '/key/deactivate':
|
||||||
endpoints.put.apiKeyManage(requestEvent, query, apiUserid, path);
|
case '/key/deactivate/':
|
||||||
break;
|
endpoints.put.apiKeyManage(requestEvent, query, apiUserid, path);
|
||||||
case '/channel/ban':
|
break;
|
||||||
case '/channel/ban/':
|
case '/channel/ban':
|
||||||
case '/channel/unban':
|
case '/channel/ban/':
|
||||||
case '/channel/unban/':
|
case '/channel/unban':
|
||||||
endpoints.put.apiChannelManageBan(requestEvent, query, apiUserid, path);
|
case '/channel/unban/':
|
||||||
break;
|
endpoints.put.apiChannelManageBan(requestEvent, query, apiUserid, path);
|
||||||
case '/channel/activate':
|
break;
|
||||||
case '/channel/activate/':
|
case '/channel/activate':
|
||||||
case '/channel/deactivate':
|
case '/channel/activate/':
|
||||||
case '/channel/deactivate/':
|
case '/channel/deactivate':
|
||||||
endpoints.put.apiChannelManageActive(requestEvent, query, apiUserid, path);
|
case '/channel/deactivate/':
|
||||||
break;
|
endpoints.put.apiChannelManageActive(requestEvent, query, apiUserid, path);
|
||||||
default:
|
break;
|
||||||
// Alert API user that they messed up
|
default:
|
||||||
requestEvent.respondWith(stdResp.NotFound('Auth Put'));
|
// Alert API user that they messed up
|
||||||
break;
|
requestEvent.respondWith(stdResp.NotFound('Auth Put'));
|
||||||
}
|
break;
|
||||||
break;
|
}
|
||||||
case 'DELETE':
|
break;
|
||||||
switch (path.toLowerCase()) {
|
case 'DELETE':
|
||||||
case '/key/delete':
|
switch (path.toLowerCase()) {
|
||||||
case '/key/delete/':
|
case '/key/delete':
|
||||||
endpoints.delete.apiKeyDelete(requestEvent, query, apiUserid, apiUserEmail, apiUserDelCode);
|
case '/key/delete/':
|
||||||
break;
|
endpoints.delete.apiKeyDelete(requestEvent, query, apiUserid, apiUserEmail, apiUserDelCode);
|
||||||
default:
|
break;
|
||||||
// Alert API user that they messed up
|
default:
|
||||||
requestEvent.respondWith(stdResp.NotFound('Auth Del'));
|
// Alert API user that they messed up
|
||||||
break;
|
requestEvent.respondWith(stdResp.NotFound('Auth Del'));
|
||||||
}
|
break;
|
||||||
break;
|
}
|
||||||
default:
|
break;
|
||||||
// Alert API user that they messed up
|
default:
|
||||||
requestEvent.respondWith(stdResp.MethodNotAllowed('Auth'));
|
// Alert API user that they messed up
|
||||||
break;
|
requestEvent.respondWith(stdResp.MethodNotAllowed('Auth'));
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Update rate limit details
|
// Update rate limit details
|
||||||
if (updateRateLimitTime) {
|
if (updateRateLimitTime) {
|
||||||
const apiTimeNow = new Date().getTime();
|
const apiTimeNow = new Date().getTime();
|
||||||
rateLimitTime.set(apiUseridStr, apiTimeNow);
|
rateLimitTime.set(apiUseridStr, apiTimeNow);
|
||||||
}
|
}
|
||||||
} else if (!authenticated) {
|
} else if (!authenticated) {
|
||||||
// Handle the unathenticated request
|
// Handle the unathenticated request
|
||||||
switch (request.method) {
|
switch (request.method) {
|
||||||
case 'GET':
|
case 'GET':
|
||||||
switch (path.toLowerCase()) {
|
switch (path.toLowerCase()) {
|
||||||
case '/key':
|
case '/key':
|
||||||
case '/key/':
|
case '/key/':
|
||||||
endpoints.get.apiKey(requestEvent, query);
|
endpoints.get.apiKey(requestEvent, query);
|
||||||
break;
|
break;
|
||||||
default:
|
case '/heatmap.png':
|
||||||
// Alert API user that they messed up
|
endpoints.get.heatmapPng(requestEvent);
|
||||||
requestEvent.respondWith(stdResp.NotFound('NoAuth Get'));
|
break;
|
||||||
break;
|
default:
|
||||||
}
|
// Alert API user that they messed up
|
||||||
break;
|
requestEvent.respondWith(stdResp.NotFound('NoAuth Get'));
|
||||||
default:
|
break;
|
||||||
// Alert API user that they messed up
|
}
|
||||||
requestEvent.respondWith(stdResp.MethodNotAllowed('NoAuth'));
|
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) {
|
} else if (authenticated && rateLimited) {
|
||||||
// Alert API user that they are doing this too often
|
// Alert API user that they are doing this too often
|
||||||
|
|
|
@ -3,25 +3,34 @@ import {
|
||||||
// Discordeno deps
|
// Discordeno deps
|
||||||
DiscordenoMessage,
|
DiscordenoMessage,
|
||||||
} from '../../deps.ts';
|
} from '../../deps.ts';
|
||||||
import { } from '../commandUtils.ts';
|
import config from '../../config.ts';
|
||||||
import { compilingStats } from '../commonEmbeds.ts';
|
import { LOCALMODE } from '../../flags.ts';
|
||||||
|
import { failColor, infoColor2 } from '../commandUtils.ts';
|
||||||
import utils from '../utils.ts';
|
import utils from '../utils.ts';
|
||||||
|
|
||||||
export const heatmap = async (message: DiscordenoMessage) => {
|
export const heatmap = async (message: DiscordenoMessage) => {
|
||||||
// Light telemetry to see how many times a command is being run
|
// 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));
|
dbClient.execute(queries.callIncCnt('heatmap')).catch((e) => utils.commonLoggers.dbError('heatmap.ts:14', 'call sproc INC_CNT on', e));
|
||||||
|
|
||||||
try {
|
if (config.api.enable) {
|
||||||
const m = await message.send(compilingStats);
|
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
|
console.log(m);
|
||||||
const hmQuery = await dbClient.query(`SELECT * FROM roll_time_heatmap`).catch((e) => utils.commonLoggers.dbError('heatmap.ts:20', 'query', e));
|
} else {
|
||||||
console.log(hmQuery);
|
message.send({
|
||||||
|
embeds: [{
|
||||||
m.edit('').catch((e: Error) =>
|
title: 'Roll Heatmap Disabled',
|
||||||
utils.commonLoggers.messageEditError('heatmap.ts:21', m, e)
|
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:24', message, e);
|
}).catch((e) => utils.commonLoggers.messageSendError('heatmap.ts:21', message, e));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -66,6 +66,11 @@ export const help = (message: DiscordenoMessage) => {
|
||||||
value: 'Statistics on the bot',
|
value: 'Statistics on the bot',
|
||||||
inline: true,
|
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}\` ...`,
|
name: `\`${config.prefix}xdydzracsq!${config.postfix}\` ...`,
|
||||||
value:
|
value:
|
||||||
|
|
|
@ -27,9 +27,9 @@ export const stats = async (message: DiscordenoMessage) => {
|
||||||
const cachedGuilds = await cacheHandlers.size('guilds');
|
const cachedGuilds = await cacheHandlers.size('guilds');
|
||||||
const cachedChannels = await cacheHandlers.size('channels');
|
const cachedChannels = await cacheHandlers.size('channels');
|
||||||
const cachedMembers = await cacheHandlers.size('members');
|
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) =>
|
m.edit(generateStats(cachedGuilds + cache.dispatchedGuildIds.size, cachedChannels + cache.dispatchedChannelIds.size, cachedMembers, rolls, total - rolls, rollRate, totalRate - rollRate)).catch((
|
||||||
utils.commonLoggers.messageEditError('stats.ts:38', m, e)
|
e: Error,
|
||||||
);
|
) => utils.commonLoggers.messageEditError('stats.ts:38', m, e));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
utils.commonLoggers.messageSendError('stats.ts:41', message, e);
|
utils.commonLoggers.messageSendError('stats.ts:41', message, e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { apiKey } from './gets/apiKey.ts';
|
||||||
import { apiRoll } from './gets/apiRoll.ts';
|
import { apiRoll } from './gets/apiRoll.ts';
|
||||||
import { apiKeyAdmin } from './gets/apiKeyAdmin.ts';
|
import { apiKeyAdmin } from './gets/apiKeyAdmin.ts';
|
||||||
import { apiChannel } from './gets/apiChannel.ts';
|
import { apiChannel } from './gets/apiChannel.ts';
|
||||||
|
import { heatmapPng } from './gets/heatmapPng.ts';
|
||||||
import { apiChannelAdd } from './posts/apiChannelAdd.ts';
|
import { apiChannelAdd } from './posts/apiChannelAdd.ts';
|
||||||
import { apiKeyManage } from './puts/apiKeyManage.ts';
|
import { apiKeyManage } from './puts/apiKeyManage.ts';
|
||||||
import { apiChannelManageBan } from './puts/apiChannelManageBan.ts';
|
import { apiChannelManageBan } from './puts/apiChannelManageBan.ts';
|
||||||
|
@ -17,6 +18,7 @@ export default {
|
||||||
apiRoll,
|
apiRoll,
|
||||||
apiKeyAdmin,
|
apiKeyAdmin,
|
||||||
apiChannel,
|
apiChannel,
|
||||||
|
heatmapPng,
|
||||||
},
|
},
|
||||||
post: {
|
post: {
|
||||||
apiChannelAdd,
|
apiChannelAdd,
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 57 KiB |
|
@ -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),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
};
|
|
@ -63,7 +63,7 @@ const updateListStatistics = (botID: bigint, serverCount: number): void => {
|
||||||
|
|
||||||
// Keep one week of data
|
// Keep one week of data
|
||||||
const hoursToKeep = 7 * 24;
|
const hoursToKeep = 7 * 24;
|
||||||
const previousHours: Array<Array<PastCommandCount>> = []
|
const previousHours: Array<Array<PastCommandCount>> = [];
|
||||||
// updateHourlyRates() returns nothing
|
// updateHourlyRates() returns nothing
|
||||||
// Updates the hourlyRate for command usage
|
// Updates the hourlyRate for command usage
|
||||||
const updateHourlyRates = async () => {
|
const updateHourlyRates = async () => {
|
||||||
|
@ -73,7 +73,7 @@ const updateHourlyRates = async () => {
|
||||||
if (previousHours.length > 1) {
|
if (previousHours.length > 1) {
|
||||||
const oldestHour = previousHours[0];
|
const oldestHour = previousHours[0];
|
||||||
|
|
||||||
const computedDiff: Array<PastCommandCount> = []
|
const computedDiff: Array<PastCommandCount> = [];
|
||||||
for (let i = 0; i < newestHour.length; i++) {
|
for (let i = 0; i < newestHour.length; i++) {
|
||||||
computedDiff.push({
|
computedDiff.push({
|
||||||
command: newestHour[i].command,
|
command: newestHour[i].command,
|
||||||
|
@ -85,7 +85,9 @@ const updateHourlyRates = async () => {
|
||||||
// Update DB
|
// Update DB
|
||||||
computedDiff.forEach(async (cmd) => {
|
computedDiff.forEach(async (cmd) => {
|
||||||
log(LT.LOG, `Updating hourlyRate | Storing to DB: ${JSON.stringify(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();
|
previousHours.unshift();
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} 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}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue