TheArtificer/src/intervals.ts

205 lines
6.2 KiB
TypeScript
Raw Normal View History

/* The Artificer was built in memory of Babka
* With love, Ean
*
* December 21, 2020
*/
import {
// Discordeno deps
cache,
cacheHandlers,
2022-06-26 19:53:25 -07:00
// imagescript
is,
2022-05-04 23:49:06 -07:00
// Log4Deno deps
2022-05-27 21:48:34 -07:00
log,
LT,
} from '../deps.ts';
import { PastCommandCount } from './mod.d.ts';
2022-06-26 19:53:25 -07:00
import { dbClient, weekDays } from './db.ts';
import utils from './utils.ts';
import config from '../config.ts';
// getRandomStatus() returns status as string
// Gets a new random status for the bot
const getRandomStatus = async (): Promise<string> => {
let status = '';
switch (Math.floor((Math.random() * 4) + 1)) {
case 1:
status = `${config.prefix}help for commands`;
break;
case 2:
status = `Running V${config.version}`;
break;
case 3:
status = `${config.prefix}info to learn more`;
break;
default: {
const cachedCount = await cacheHandlers.size('guilds');
status = `Rolling dice for ${cachedCount + cache.dispatchedGuildIds.size} servers`;
break;
}
}
return status;
};
2022-06-26 19:53:25 -07:00
// updateListStatistics(bot ID, current guild count) returns nothing, posts to botlists
// Sends the current server count to all bot list sites we are listed on
const updateListStatistics = (botID: bigint, serverCount: number): void => {
config.botLists.forEach(async (e) => {
log(LT.LOG, `Updating statistics for ${JSON.stringify(e)}`);
if (e.enabled) {
const tempHeaders = new Headers();
tempHeaders.append(e.headers[0].header, e.headers[0].value);
tempHeaders.append('Content-Type', 'application/json');
// ?{} is a template used in config, just need to replace it with the real value
const response = await fetch(e.apiUrl.replace('?{bot_id}', botID.toString()), {
'method': 'POST',
'headers': tempHeaders,
'body': JSON.stringify(e.body).replace('"?{server_count}"', serverCount.toString()), // ?{server_count} needs the "" removed from around it aswell to make sure its sent as a number
});
2022-05-04 23:49:06 -07:00
log(LT.INFO, `Posted server count to ${e.name}. Results: ${JSON.stringify(response)}`);
}
});
};
// Keep one week of data
const hoursToKeep = 7 * 24;
2022-06-26 17:18:41 -07:00
const previousHours: Array<Array<PastCommandCount>> = [];
2022-06-26 19:53:25 -07:00
// updateHourlyRates() returns nothing, updates DB directly
// Updates the hourlyRate for command usage
const updateHourlyRates = async () => {
try {
2022-06-26 19:53:25 -07:00
const newestHour = await dbClient.query('SELECT command, count FROM command_cnt ORDER BY command;').catch((e) => utils.commonLoggers.dbError('intervals.ts:71', 'query', e));
previousHours.push(newestHour);
if (previousHours.length > 1) {
const oldestHour = previousHours[0];
2022-06-26 17:18:41 -07:00
const computedDiff: Array<PastCommandCount> = [];
for (let i = 0; i < newestHour.length; i++) {
computedDiff.push({
command: newestHour[i].command,
count: (newestHour[i].count - oldestHour[i].count),
});
log(LT.LOG, `Updating hourlyRate | Computing diffs: ${JSON.stringify(computedDiff)}`);
}
// Update DB
computedDiff.forEach(async (cmd) => {
log(LT.LOG, `Updating hourlyRate | Storing to DB: ${JSON.stringify(cmd)}`);
2022-06-26 17:18:41 -07:00
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)
);
});
}
if (previousHours.length > hoursToKeep) {
previousHours.unshift();
}
} catch (e) {
2022-06-26 17:18:41 -07:00
log(LT.ERROR, `Something went wrong in previousHours interval | Error: ${e.name} - ${e.message}`);
}
};
2022-06-26 19:53:25 -07:00
// getPercentOfRange(min, max, val) returns number
// Gets a percent value of where val lies in the min-max range
const getPercentOfRange = (minVal: number, maxVal: number, val: number): number => {
const localMax = maxVal - minVal;
const localVal = val - minVal;
return localVal / localMax;
};
// Pixel locations in heatmap-base.png, pixel locations are 0 based
// dayPixels holds the left and right (AKA X Coord) pixel locations for each col (ex: [leftPX, rightPX])
const dayPixels: Array<Array<number>> = [
[72, 159],
[163, 260],
[264, 359],
[363, 497],
[501, 608],
[612, 686],
[690, 800],
];
// hourPixels holds the top and bottom (AKA Y Coord) pixel locations for each row (ex: [topPX, botPX])
const hourPixels: Array<Array<number>> = [
[29, 49],
[51, 72],
[74, 95],
[97, 118],
[120, 141],
[143, 164],
[166, 187],
[189, 209],
[211, 232],
[234, 254],
[256, 277],
[279, 299],
[301, 322],
[324, 345],
[347, 368],
[370, 391],
[393, 413],
[415, 436],
[438, 459],
[461, 482],
[484, 505],
[507, 528],
[530, 550],
[552, 572],
];
// updateHeatmap() returns nothing, creates new heatmap.png
// Updates the heatmap image with latest data from the db
const updateHeatmapPng = async () => {
const baseHeatmap = Deno.readFileSync('./src/endpoints/gets/heatmap-base.png');
const heatmap = await is.decode(baseHeatmap);
if (heatmap instanceof is.Image) {
// Get latest data from DB
const heatmapData = await dbClient.query('SELECT * FROM roll_time_heatmap ORDER BY hour;').catch((e) => utils.commonLoggers.dbError('intervals.ts:148', 'query', e));
let minRollCnt = Infinity;
let maxRollCnt = 0;
// determine min and max values
for (let hour = 0; hour < heatmapData.length; hour++) {
for (let day = 0; day < weekDays.length; day++) {
const rollCnt = heatmapData[hour][weekDays[day]];
log(LT.LOG, `updateHeatmapPng | finding min/max | min: ${minRollCnt} max: ${maxRollCnt} curr: ${rollCnt}`);
if (rollCnt > maxRollCnt) {
maxRollCnt = rollCnt;
}
if (rollCnt < minRollCnt) {
minRollCnt = rollCnt;
}
}
}
// Apply values to image
for (let hour = 0; hour < heatmapData.length; hour++) {
for (let day = 0; day < weekDays.length; day++) {
log(LT.LOG, `updateHeatmapPng | putting ${weekDays[day]} ${hour}:00 into image`);
const percent = getPercentOfRange(minRollCnt, maxRollCnt, heatmapData[hour][weekDays[day]]);
heatmap.drawBox(
dayPixels[day][0] + 1,
hourPixels[hour][0] + 1,
dayPixels[day][1] - dayPixels[day][0] + 1,
hourPixels[hour][1] - hourPixels[hour][0] + 1,
is.Image.rgbToColor(
255 * (1 - percent),
255 * percent,
0,
),
);
}
}
Deno.writeFileSync('./src/endpoints/gets/heatmap.png', await heatmap.encode());
}
};
export default {
getRandomStatus,
updateListStatistics,
updateHourlyRates,
updateHeatmapPng,
};