152 lines
4.6 KiB
JavaScript
152 lines
4.6 KiB
JavaScript
const { reset, IS_PM2 } = require('./banners/utils/helper.js');
|
|
const { axiosWebhook } = require('./services/axios.js');
|
|
const repoInfo = require('./repo.js');
|
|
const { SERVER_ID, DISCORD_WEBHOOK_ENABLED, DISCORD_WEBHOOK_URL, DISCORD_WEBHOOK_USERNAME, DISCORD_USER_ID } = require('../config.js').MAIN;
|
|
|
|
const LEVELS = Object.freeze({
|
|
0: { method: 'log', label: '[i]', color: '\x1b[38;5;38m', hex: 0x00AEEF, name: 'INFO' },
|
|
1: { method: 'log', label: '[✓]', color: '\x1b[38;5;77m', hex: 0x3CB371, name: 'SUCCESS' },
|
|
2: { method: 'warn', label: '[!]', color: '\x1b[38;5;208m', hex: 0xFF8C00, name: 'WARNING' },
|
|
3: { method: 'error', label: '[X]', color: '\x1b[38;5;160m', hex: 0xD32F2F, name: 'ERROR' },
|
|
});
|
|
|
|
const WEBHOOK_BURST_LIMIT = 3, WEBHOOK_COOLDOWN = 3000;
|
|
const webhookQueue = [];
|
|
let webhookBurstCount = 0, webhookLastSent = 0;
|
|
|
|
class Logger {
|
|
static #getLevel(level) {
|
|
return LEVELS[level] ?? LEVELS[0];
|
|
}
|
|
|
|
static #normalizeOptions(options, defaultDiscord, defaultPing) {
|
|
if (typeof options === 'boolean') return { discord: defaultDiscord, ping: options };
|
|
return {
|
|
discord: options.discord ?? defaultDiscord,
|
|
ping: options.ping ?? defaultPing,
|
|
};
|
|
}
|
|
|
|
static print(msg, level = 0) {
|
|
const { method, label, color: lvlColor } = this.#getLevel(level);
|
|
const fn = console[method] || console.log;
|
|
|
|
if (IS_PM2) {
|
|
fn(`${label} ${msg}`);
|
|
} else {
|
|
fn(`${lvlColor}${label} ${msg}${reset}`);
|
|
}
|
|
}
|
|
|
|
static async #sendToDiscord(msg, hex, ping) {
|
|
if (!msg || !DISCORD_WEBHOOK_ENABLED || !DISCORD_WEBHOOK_URL) return;
|
|
|
|
if (typeof msg !== 'string') msg = msg.toString();
|
|
|
|
try {
|
|
const res = await axiosWebhook.post(DISCORD_WEBHOOK_URL, {
|
|
username: DISCORD_WEBHOOK_USERNAME === 'SERVER_ID' ? SERVER_ID : DISCORD_WEBHOOK_USERNAME || null,
|
|
content: (ping && DISCORD_USER_ID) ? `**[<@${DISCORD_USER_ID}>]**` : undefined,
|
|
embeds: [{
|
|
description: msg
|
|
.replace(/(\b\w+=)/g, '**$1**')
|
|
.replace(/'/g, '`')
|
|
.trim(),
|
|
color: hex ?? 0x008FD1,
|
|
footer: {
|
|
text: `${SERVER_ID ? `${SERVER_ID} • ` : ''}${repoInfo.repoSlug} [v${repoInfo.version}]`,
|
|
},
|
|
timestamp: new Date().toISOString(),
|
|
}],
|
|
});
|
|
|
|
if (res.status !== 204) {
|
|
this.print(`Failed to deliver Discord Webhook (unexpected status code: ${res.status})`, 2);
|
|
}
|
|
} catch (err) {
|
|
this.print(`Discord Webhook Error: ${err.message}`, 3);
|
|
}
|
|
}
|
|
|
|
static async webhook(msg, levelOrHex = 0, ping = false) {
|
|
const isLevel = typeof levelOrHex === 'number' && levelOrHex >= 0 && levelOrHex <= 3;
|
|
const hex = isLevel ? this.#getLevel(levelOrHex).hex : levelOrHex;
|
|
|
|
const now = Date.now();
|
|
if (now - webhookLastSent > WEBHOOK_COOLDOWN) webhookBurstCount = 0;
|
|
|
|
if (webhookBurstCount >= WEBHOOK_BURST_LIMIT) {
|
|
webhookQueue.push({ msg, hex, ping });
|
|
if (webhookQueue.length === 1) {
|
|
this.print('Discord webhook rate limit reached. Some messages were scheduled for later delivery.', 2);
|
|
setTimeout(() => this.#processWebhookQueue(), WEBHOOK_COOLDOWN);
|
|
}
|
|
return;
|
|
}
|
|
|
|
try {
|
|
await this.#sendToDiscord(msg, hex, ping);
|
|
webhookLastSent = now;
|
|
webhookBurstCount++;
|
|
|
|
if (webhookQueue.length > 0) setTimeout(() => this.#processWebhookQueue(), WEBHOOK_COOLDOWN);
|
|
} catch (err) {
|
|
this.print(`Discord webhook delivery failed: ${err.message}`, 3);
|
|
}
|
|
}
|
|
|
|
static async #processWebhookQueue() {
|
|
if (webhookQueue.length === 0) return;
|
|
|
|
if (Date.now() - webhookLastSent > WEBHOOK_COOLDOWN) webhookBurstCount = 0;
|
|
|
|
const { msg, hex, ping } = webhookQueue.shift();
|
|
this.print(`Processing queued webhook (${webhookQueue.length} remaining)`, 0);
|
|
|
|
try {
|
|
await this.#sendToDiscord(msg, hex, ping);
|
|
webhookLastSent = Date.now();
|
|
webhookBurstCount = 1;
|
|
} catch (err) {
|
|
this.print(`Queued webhook failed: ${err.message}`, 3);
|
|
}
|
|
|
|
if (webhookQueue.length > 0) setTimeout(() => this.#processWebhookQueue(), WEBHOOK_COOLDOWN);
|
|
}
|
|
|
|
static log(msg, level = 0, options = {}) {
|
|
this.print(msg, level);
|
|
|
|
if (options.discord) {
|
|
this.webhook(msg, level, options.ping)
|
|
.catch(err => console.error('[Logger] Webhook error:', err.message));
|
|
}
|
|
}
|
|
|
|
static info(msg, options = {}) {
|
|
const opts = this.#normalizeOptions(options, false, false);
|
|
this.log(msg, 0, opts);
|
|
}
|
|
|
|
static success(msg, options = {}) {
|
|
const opts = this.#normalizeOptions(options, false, false);
|
|
this.log(msg, 1, opts);
|
|
}
|
|
|
|
static warn(msg, options = {}) {
|
|
const opts = this.#normalizeOptions(options, true, false);
|
|
this.log(msg, 2, opts);
|
|
}
|
|
|
|
static error(msg, options = {}) {
|
|
const opts = this.#normalizeOptions(options, true, false);
|
|
this.log(msg, 3, opts);
|
|
}
|
|
|
|
static getWebhookQueueSize() {
|
|
return webhookQueue.length;
|
|
}
|
|
}
|
|
|
|
module.exports = Logger;
|