Skip to content

Commit

Permalink
Release 2.5.3
Browse files Browse the repository at this point in the history
  • Loading branch information
elijaholmos committed Feb 23, 2023
2 parents e0ac210 + c78fa65 commit 58e2fce
Show file tree
Hide file tree
Showing 14 changed files with 355 additions and 172 deletions.
13 changes: 13 additions & 0 deletions bot.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,19 @@ class DiscordHaloBot extends Client {
});
}

/**
* Sends a discord message on the bot's behalf to the health log channel
* @param {Object} args
* @param {EmbedBase} args.embed Singular embed object to be sent in message
* @returns {Promise<Message>} Promise which resolves to the sent message
*/
async logHealth({ embed, ...options }) {
return (await this.channels.fetch(this.config.channels.log_health)).send({
embeds: [embed],
...options,
});
}

/**
* Sends a discord message on the bot's behalf to a public log channel
* @param {Object} args
Expand Down
17 changes: 13 additions & 4 deletions classes/HaloWatcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,26 @@

import { EventEmitter } from 'node:events';
import { setIntervalAsync } from 'set-interval-async/fixed';
import { Firebase, Halo, handle401, Logger } from '.';
import { Firebase, Halo, handle401, HealthManager, Logger } from '.';
import { CLASS_ANNOUNCEMENTS, USER_GRADES, USER_INBOX } from '../caches';

export class HaloWatcher extends EventEmitter {
constructor() {
super();

//create intervals
setIntervalAsync(async () => await this.#watchForAnnouncements(), 20000);
setIntervalAsync(async () => await this.#watchForGrades(), 20000);
setIntervalAsync(async () => await this.#watchForInboxMessages(), 20000);
setIntervalAsync(async () => {
await this.#watchForAnnouncements();
HealthManager.record('ANNOUNCEMENTS');
}, 20000);
setIntervalAsync(async () => {
await this.#watchForGrades();
HealthManager.record('GRADES');
}, 20000);
setIntervalAsync(async () => {
await this.#watchForInboxMessages();
HealthManager.record('INBOX_MESSAGES');
}, 20000);
}

/**
Expand Down
58 changes: 58 additions & 0 deletions classes/HealthManager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright (C) 2023 Elijah Olmos
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import bot from '../bot';
import { Logger, EmbedBase } from '.';

export class HealthManager {
static #records = new Map();

static record(event) {
this.#records.set(event, Date.now());
Logger.health(`recorded event: ${event}`);
}

static publishLogs() {
const flags = [];
// find all records that are older than 2min
const fields = Array.from(this.#records).map(([event, date]) => {
if (date < Date.now() - 120000) flags.push(event);
return {
name: `\`${event}\``,
value: bot.formatTimestamp(date, 'R'),
inline: true,
};
});

const embed = new EmbedBase({
title: 'Health Report',
description: `Discord API Latency: ${bot.ws.ping}ms`,
fields: [
...(!!flags.length
? [
{
name: 'Flags',
value: flags.map((flag) => `\`${flag}\``).join('\n'),
},
]
: []),
...fields,
],
});
!!flags.length && embed.Error();
bot.logHealth({ embed, ...(!!flags.length && { content: '<@!139120967208271872> unhealthy status' }) });
}
}
66 changes: 44 additions & 22 deletions classes/Logger.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,17 @@ import { serializeError } from 'serialize-error';

export class Logger {
static async log(content, type = 'log') {
const timestamp = `[${chalk.white(moment().format('YYYY-MM-DD HH:mm:ss'))}]`;
const date = moment();
const timestamp = `[${chalk.white(date.format('YYYY-MM-DD HH:mm:ss'))}]`;
type !== 'error' && !!content && content.constructor === Object && (content = JSON.stringify(content));
switch (type) {
case 'log': {
//create file first, if it does not exist
await fs.mkdir('./' + path.relative(process.cwd(), 'log/'), { recursive: true });
//create dir first, if it does not exist
await fs.mkdir('./' + path.relative(process.cwd(), `log/${date.format('YYYY-MM-DD')}/`), {
recursive: true,
});
fs.appendFile(
'./' + path.relative(process.cwd(), 'log/log.log'),
'./' + path.relative(process.cwd(), `log/${date.format('YYYY-MM-DD')}/log.log`),
`[${moment().format('YYYY-MM-DD HH:mm:ss')}]: ${content}\n`
);
return console.log(`${timestamp} [${chalk.bgBlue(` ${type.toUpperCase()} `)}]: ${content}`);
Expand All @@ -38,19 +41,23 @@ export class Logger {
return console.log(`${timestamp} [${chalk.black.bgYellow(type.toUpperCase())}]: ${content}`);
}
case 'error': {
//create file first, if it does not exist
await fs.mkdir('./' + path.relative(process.cwd(), 'log/'), { recursive: true });
//create dir first, if it does not exist
await fs.mkdir('./' + path.relative(process.cwd(), `log/${date.format('YYYY-MM-DD')}/`), {
recursive: true,
});
fs.appendFile(
'./' + path.relative(process.cwd(), 'log/error.log'),
'./' + path.relative(process.cwd(), `log/${date.format('YYYY-MM-DD')}/error.log`),
`[${moment().format('YYYY-MM-DD HH:mm:ss')}]: ${JSON.stringify(serializeError(content))}\n`
);
return console.log(`${timestamp} [${chalk.bgRed(type.toUpperCase())}]: ${content}`);
}
case 'debug': {
//create file first, if it does not exist
await fs.mkdir('./' + path.relative(process.cwd(), 'log/'), { recursive: true });
//create dir first, if it does not exist
await fs.mkdir('./' + path.relative(process.cwd(), `log/${date.format('YYYY-MM-DD')}/`), {
recursive: true,
});
fs.appendFile(
'./' + path.relative(process.cwd(), 'log/debug.log'),
'./' + path.relative(process.cwd(), `log/${date.format('YYYY-MM-DD')}/debug.log`),
`[${moment().format('YYYY-MM-DD HH:mm:ss')}]: ${content}\n`
);
return console.log(`${timestamp} [${chalk.green(type.toUpperCase())}]: ${content}`);
Expand All @@ -65,41 +72,52 @@ export class Logger {
return console.log(`${timestamp} [${chalk.black.bgGreen(type.toUpperCase())}]: ${content}`);
}
case 'uninstall': {
//create file first, if it does not exist
await fs.mkdir('./' + path.relative(process.cwd(), 'log/'), { recursive: true });
//create dir first, if it does not exist
await fs.mkdir('./' + path.relative(process.cwd(), `log/${date.format('YYYY-MM-DD')}/`), {
recursive: true,
});
fs.appendFile(
'./' + path.relative(process.cwd(), 'log/uninstall.log'),
'./' + path.relative(process.cwd(), `log/${date.format('YYYY-MM-DD')}/uninstall.log`),
`[${moment().format('YYYY-MM-DD HH:mm:ss')}]: ${content}\n`
);
return console.log(`${timestamp} [${chalk.yellow(type.toUpperCase())}]: ${content}`);
}
case 'unauth': {
//create file first, if it does not exist
await fs.mkdir('./' + path.relative(process.cwd(), 'log/'), { recursive: true });
//create dir first, if it does not exist
await fs.mkdir('./' + path.relative(process.cwd(), `log/${date.format('YYYY-MM-DD')}/`), {
recursive: true,
});
fs.appendFile(
'./' + path.relative(process.cwd(), 'log/unauth.log'),
'./' + path.relative(process.cwd(), `log/${date.format('YYYY-MM-DD')}/unauth.log`),
`[${moment().format('YYYY-MM-DD HH:mm:ss')}]: ${content}\n`
);
return; //don't output to console
}
case 'cookie': {
//create file first, if it does not exist
await fs.mkdir('./' + path.relative(process.cwd(), 'log/'), { recursive: true });
//create dir first, if it does not exist
await fs.mkdir('./' + path.relative(process.cwd(), `log/${date.format('YYYY-MM-DD')}/`), {
recursive: true,
});
fs.appendFile(
'./' + path.relative(process.cwd(), 'log/cookie.log'),
'./' + path.relative(process.cwd(), `log/${date.format('YYYY-MM-DD')}/cookie.log`),
`[${moment().format('YYYY-MM-DD HH:mm:ss')}]: ${content}\n`
);
return console.log(`${timestamp} [${chalk.grey(type.toUpperCase())}]: ${content}`);
}
case 'cron': {
//create file first, if it does not exist
await fs.mkdir('./' + path.relative(process.cwd(), 'log/'), { recursive: true });
//create dir first, if it does not exist
await fs.mkdir('./' + path.relative(process.cwd(), `log/${date.format('YYYY-MM-DD')}/`), {
recursive: true,
});
fs.appendFile(
'./' + path.relative(process.cwd(), 'log/cron.log'),
'./' + path.relative(process.cwd(), `log/${date.format('YYYY-MM-DD')}/cron.log`),
`[${moment().format('YYYY-MM-DD HH:mm:ss')}]: ${content}\n`
);
return console.log(`${timestamp} [${chalk.bgYellow(type.toUpperCase())}]: ${content}`);
}
case 'health': {
return console.log(`${timestamp} [${chalk.black.bgGreen(type.toUpperCase())}]: ${content}`);
}
default:
throw new TypeError('Unknown log type');
}
Expand Down Expand Up @@ -144,4 +162,8 @@ export class Logger {
static cron(content) {
return this.log(content, 'cron');
}

static health(content) {
return this.log(content, 'health');
}
}
3 changes: 1 addition & 2 deletions classes/components/EmbedBase.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,7 @@ export class EmbedBase extends MessageEmbed {
this.description &&= truncate(this.description.trim(), { length: 4095, omission: '\u2026' });
// I'd like to split the embeds before slicing fields, if possible
this.fields = this.fields
.map((f) => this.splitField(f))
.flat()
.flatMap((f) => this.splitField(f))
.slice(0, 25)
.map((f) => ({
...f,
Expand Down
1 change: 1 addition & 0 deletions classes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ export * from './services/GradeService';
export * from './services/InboxMessageService';
export * from './services/401Service';
export * as Encrypt from './services/EncryptionService';
export * from './HealthManager';
14 changes: 10 additions & 4 deletions classes/services/AnnouncementService.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import { decode } from 'html-entities';
import { EmbedBase, Firebase, Logger } from '..';
import bot from '../../bot';

Expand Down Expand Up @@ -92,10 +93,15 @@ export class AnnouncementService {
fields: [
{
name: 'Message',
value: announcement.content
.replaceAll('<br>', '\n')
.replaceAll('</p><p>', '\n') //this is kinda hacky ngl
.replace(/<\/?[^>]+(>|$)/g, ''),
value: decode(
announcement.content
.replaceAll('<br>', '\n')
.replaceAll('</p><p>', '\n') //this is kinda hacky ngl
.replaceAll('<li>', '\n\t\u2022 ')
.replaceAll('</ol>', '\n')
.replaceAll('</ul>', '\n')
.replace(/<\/?[^>]+(>|$)/g, '')
),
},
//TODO: cleanup dry code
...(!!announcement.resources.filter(({ kind }) => kind !== 'URL').length
Expand Down
14 changes: 10 additions & 4 deletions classes/services/GradeService.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import { decode } from 'html-entities';
import { round } from 'lodash-es';
import { EmbedBase, Firebase, Logger } from '..';
import bot from '../../bot';
Expand Down Expand Up @@ -106,10 +107,15 @@ export class GradeService {
{
name: `Feedback:`,
value: !!finalComment?.comment
? finalComment.comment
.replaceAll('<br>', '\n')
.replaceAll('</p><p>', '\n') //this is kinda hacky ngl
.replace(/<\/?[^>]+(>|$)/g, '')
? decode(
finalComment.comment
.replaceAll('<br>', '\n')
.replaceAll('</p><p>', '\n') //this is kinda hacky ngl
.replaceAll('<li>', '\n\t\u2022 ')
.replaceAll('</ol>', '\n')
.replaceAll('</ul>', '\n')
.replace(/<\/?[^>]+(>|$)/g, '')
)
: 'None',
},
...(show_overall_grade
Expand Down
16 changes: 11 additions & 5 deletions classes/services/InboxMessageService.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import { EmbedBase, Firebase, Logger } from '..';
import { decode } from 'html-entities';
import { EmbedBase, Logger } from '..';
import bot from '../../bot';

export class InboxMessageService {
Expand Down Expand Up @@ -79,10 +80,15 @@ export class InboxMessageService {
content: `New message received from **${firstName} ${lastName}**:`,
embeds: [
new EmbedBase({
description: inbox_message.content
.replaceAll('<br>', '\n')
.replaceAll('</p><p>', '\n') //this is kinda hacky ngl
.replace(/<\/?[^>]+(>|$)/g, ''),
description: decode(
inbox_message.content
.replaceAll('<br>', '\n')
.replaceAll('</p><p>', '\n') //this is kinda hacky ngl
.replaceAll('<li>', '\n\t\u2022 ')
.replaceAll('</ol>', '\n')
.replaceAll('</ul>', '\n')
.replace(/<\/?[^>]+(>|$)/g, '')
),
fields: [
...(!!inbox_message.resources.filter(({ kind }) => kind !== 'URL').length
? [
Expand Down
5 changes: 2 additions & 3 deletions commands/development/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/

import bot from '../../bot';
import { Command, Firebase, Halo } from '../../classes';
import { Command, Firebase, Halo, HealthManager } from '../../classes';

class test extends Command {
constructor() {
Expand All @@ -28,8 +28,7 @@ class test extends Command {

async run({ intr }) {
try {
const cookie = await Firebase.getUserCookie(intr.user.id);

HealthManager.publishLogs();
// const feedback = await Halo.getGradeFeedback({
// cookie,
// assessment_id: '1454f632-ab98-4900-8858-452160a85b9c',
Expand Down
2 changes: 2 additions & 0 deletions config.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export default {
connection_log: '932058303779983470',
cron_log: '1029803136367476807',
log_401: '1036438412011507773',
log_health: '1077445943865131018',
},
events: {},
emoji: {},
Expand Down Expand Up @@ -98,6 +99,7 @@ export default {
connection_log: '932058303779983470',
cron_log: '1029803136367476807',
log_401: '1036438412011507773',
log_health: '1077445943865131018',
},
events: {},
emoji: {},
Expand Down
Loading

0 comments on commit 58e2fce

Please sign in to comment.