Add heatmap.png generator
This commit is contained in:
		
							parent
							
								
									42cb268a58
								
							
						
					
					
						commit
						a7cdd91969
					
				| 
						 | 
					@ -1,3 +1,4 @@
 | 
				
			||||||
config.ts
 | 
					config.ts
 | 
				
			||||||
**/**/Thumbs.db
 | 
					**/**/Thumbs.db
 | 
				
			||||||
logs
 | 
					logs
 | 
				
			||||||
 | 
					src/endpoints/gets/heatmap.png
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										2
									
								
								deps.ts
								
								
								
								
							
							
						
						
									
										2
									
								
								deps.ts
								
								
								
								
							| 
						 | 
					@ -18,3 +18,5 @@ export { Status, STATUS_TEXT } from "https://deno.land/std@0.137.0/http/http_sta
 | 
				
			||||||
export { nanoid } from "https://deno.land/x/nanoid@v3.0.0/mod.ts";
 | 
					export { nanoid } from "https://deno.land/x/nanoid@v3.0.0/mod.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export { LogTypes as LT, initLog, log } from "https://raw.githubusercontent.com/Burn-E99/Log4Deno/V1.1.1/mod.ts";
 | 
					export { LogTypes as LT, initLog, log } from "https://raw.githubusercontent.com/Burn-E99/Log4Deno/V1.1.1/mod.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export * as is from "https://deno.land/x/imagescript@v1.2.13/mod.ts";
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										7
									
								
								mod.ts
								
								
								
								
							
							
						
						
									
										7
									
								
								mod.ts
								
								
								
								
							| 
						 | 
					@ -79,11 +79,18 @@ startBot({
 | 
				
			||||||
				intervals.updateHourlyRates();
 | 
									intervals.updateHourlyRates();
 | 
				
			||||||
			}, 3600000);
 | 
								}, 3600000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Interval to update heatmap.png every hour
 | 
				
			||||||
 | 
								setInterval(() => {
 | 
				
			||||||
 | 
									log(LT.LOG, 'Updating heatmap.png');
 | 
				
			||||||
 | 
									intervals.updateHeatmapPng();
 | 
				
			||||||
 | 
								}, 3600000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// setTimeout added to make sure the startup message does not error out
 | 
								// setTimeout added to make sure the startup message does not error out
 | 
				
			||||||
			setTimeout(() => {
 | 
								setTimeout(() => {
 | 
				
			||||||
				LOCALMODE && editBotNickname(config.devServer, `LOCAL - ${config.name}`);
 | 
									LOCALMODE && editBotNickname(config.devServer, `LOCAL - ${config.name}`);
 | 
				
			||||||
				LOCALMODE ? log(LT.INFO, 'updateListStatistics not running') : intervals.updateListStatistics(botId, cache.guilds.size);
 | 
									LOCALMODE ? log(LT.INFO, 'updateListStatistics not running') : intervals.updateListStatistics(botId, cache.guilds.size);
 | 
				
			||||||
				intervals.updateHourlyRates();
 | 
									intervals.updateHourlyRates();
 | 
				
			||||||
 | 
									intervals.updateHeatmapPng();
 | 
				
			||||||
				editBotStatus({
 | 
									editBotStatus({
 | 
				
			||||||
					activities: [{
 | 
										activities: [{
 | 
				
			||||||
						name: 'Booting Complete',
 | 
											name: 'Booting Complete',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,7 +10,7 @@ export const dbClient = await new Client().connect({
 | 
				
			||||||
	password: config.db.password,
 | 
						password: config.db.password,
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const weekDays = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];
 | 
					export const weekDays = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const queries = {
 | 
					export const queries = {
 | 
				
			||||||
	insertRollLogCmd: (api: number, error: number) => `INSERT INTO roll_log(input,result,resultid,api,error) values(?,?,?,${api},${error})`,
 | 
						insertRollLogCmd: (api: number, error: number) => `INSERT INTO roll_log(input,result,resultid,api,error) values(?,?,?,${api},${error})`,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										112
									
								
								src/intervals.ts
								
								
								
								
							
							
						
						
									
										112
									
								
								src/intervals.ts
								
								
								
								
							| 
						 | 
					@ -8,12 +8,14 @@ import {
 | 
				
			||||||
	// Discordeno deps
 | 
						// Discordeno deps
 | 
				
			||||||
	cache,
 | 
						cache,
 | 
				
			||||||
	cacheHandlers,
 | 
						cacheHandlers,
 | 
				
			||||||
 | 
						// imagescript
 | 
				
			||||||
 | 
						is,
 | 
				
			||||||
	// Log4Deno deps
 | 
						// Log4Deno deps
 | 
				
			||||||
	log,
 | 
						log,
 | 
				
			||||||
	LT,
 | 
						LT,
 | 
				
			||||||
} from '../deps.ts';
 | 
					} from '../deps.ts';
 | 
				
			||||||
import { PastCommandCount } from './mod.d.ts';
 | 
					import { PastCommandCount } from './mod.d.ts';
 | 
				
			||||||
import { dbClient } from './db.ts';
 | 
					import { dbClient, weekDays } from './db.ts';
 | 
				
			||||||
import utils from './utils.ts';
 | 
					import utils from './utils.ts';
 | 
				
			||||||
import config from '../config.ts';
 | 
					import config from '../config.ts';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -41,7 +43,7 @@ const getRandomStatus = async (): Promise<string> => {
 | 
				
			||||||
	return status;
 | 
						return status;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// updateListStatistics(bot ID, current guild count) returns nothing
 | 
					// 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
 | 
					// Sends the current server count to all bot list sites we are listed on
 | 
				
			||||||
const updateListStatistics = (botID: bigint, serverCount: number): void => {
 | 
					const updateListStatistics = (botID: bigint, serverCount: number): void => {
 | 
				
			||||||
	config.botLists.forEach(async (e) => {
 | 
						config.botLists.forEach(async (e) => {
 | 
				
			||||||
| 
						 | 
					@ -64,11 +66,11 @@ 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 DB directly
 | 
				
			||||||
// Updates the hourlyRate for command usage
 | 
					// Updates the hourlyRate for command usage
 | 
				
			||||||
const updateHourlyRates = async () => {
 | 
					const updateHourlyRates = async () => {
 | 
				
			||||||
	try {
 | 
						try {
 | 
				
			||||||
		const newestHour = await dbClient.query(`SELECT command, count FROM command_cnt ORDER BY command;`).catch((e) => utils.commonLoggers.dbError('intervals.ts:71', 'query', e));
 | 
							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);
 | 
							previousHours.push(newestHour);
 | 
				
			||||||
		if (previousHours.length > 1) {
 | 
							if (previousHours.length > 1) {
 | 
				
			||||||
			const oldestHour = previousHours[0];
 | 
								const oldestHour = previousHours[0];
 | 
				
			||||||
| 
						 | 
					@ -99,4 +101,104 @@ const updateHourlyRates = async () => {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default { getRandomStatus, updateListStatistics, updateHourlyRates };
 | 
					// 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,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1 +1 @@
 | 
				
			||||||
deno run --allow-write=./logs/ --allow-read=./src/solver/ --allow-net .\mod.ts
 | 
					deno run --allow-write=./logs/,./src/endpoints/gets/heatmap.png --allow-read=./src/solver/,./src/endpoints/gets/heatmap-base.png --allow-net .\mod.ts
 | 
				
			||||||
		Loading…
	
		Reference in New Issue