mirror of
https://github.com/TheNetsky/Microsoft-Rewards-Script.git
synced 2026-01-17 21:43:59 +00:00
190 lines
6.2 KiB
TypeScript
190 lines
6.2 KiB
TypeScript
import chalk from 'chalk'
|
|
import cluster from 'cluster'
|
|
import { sendDiscord } from './Discord'
|
|
import { sendNtfy } from './Ntfy'
|
|
import type { MicrosoftRewardsBot } from '../index'
|
|
import { errorDiagnostic } from '../util/ErrorDiagnostic'
|
|
import type { LogFilter } from '../interface/Config'
|
|
|
|
export type Platform = boolean | 'main'
|
|
export type LogLevel = 'info' | 'warn' | 'error' | 'debug'
|
|
export type ColorKey = keyof typeof chalk
|
|
export interface IpcLog {
|
|
content: string
|
|
level: LogLevel
|
|
}
|
|
|
|
type ChalkFn = (msg: string) => string
|
|
|
|
function platformText(platform: Platform): string {
|
|
return platform === 'main' ? 'MAIN' : platform ? 'MOBILE' : 'DESKTOP'
|
|
}
|
|
|
|
function platformBadge(platform: Platform): string {
|
|
return platform === 'main' ? chalk.bgCyan('MAIN') : platform ? chalk.bgBlue('MOBILE') : chalk.bgMagenta('DESKTOP')
|
|
}
|
|
|
|
function getColorFn(color?: ColorKey): ChalkFn | null {
|
|
return color && typeof chalk[color] === 'function' ? (chalk[color] as ChalkFn) : null
|
|
}
|
|
|
|
function consoleOut(level: LogLevel, msg: string, chalkFn: ChalkFn | null): void {
|
|
const out = chalkFn ? chalkFn(msg) : msg
|
|
switch (level) {
|
|
case 'warn':
|
|
return console.warn(out)
|
|
case 'error':
|
|
return console.error(out)
|
|
default:
|
|
return console.log(out)
|
|
}
|
|
}
|
|
|
|
function formatMessage(message: string | Error): string {
|
|
return message instanceof Error ? `${message.message}\n${message.stack || ''}` : message
|
|
}
|
|
|
|
export class Logger {
|
|
constructor(private bot: MicrosoftRewardsBot) {}
|
|
|
|
info(isMobile: Platform, title: string, message: string, color?: ColorKey) {
|
|
return this.baseLog('info', isMobile, title, message, color)
|
|
}
|
|
|
|
warn(isMobile: Platform, title: string, message: string | Error, color?: ColorKey) {
|
|
return this.baseLog('warn', isMobile, title, message, color)
|
|
}
|
|
|
|
error(isMobile: Platform, title: string, message: string | Error, color?: ColorKey) {
|
|
return this.baseLog('error', isMobile, title, message, color)
|
|
}
|
|
|
|
debug(isMobile: Platform, title: string, message: string | Error, color?: ColorKey) {
|
|
return this.baseLog('debug', isMobile, title, message, color)
|
|
}
|
|
|
|
private baseLog(
|
|
level: LogLevel,
|
|
isMobile: Platform,
|
|
title: string,
|
|
message: string | Error,
|
|
color?: ColorKey
|
|
): void {
|
|
const now = new Date().toLocaleString()
|
|
const formatted = formatMessage(message)
|
|
|
|
const userName = this.bot.userData.userName ? this.bot.userData.userName : 'MAIN'
|
|
|
|
const levelTag = level.toUpperCase()
|
|
const cleanMsg = `[${now}] [${userName}] [${levelTag}] ${platformText(isMobile)} [${title}] ${formatted}`
|
|
|
|
const config = this.bot.config
|
|
|
|
if (level === 'debug' && !config.debugLogs && !process.argv.includes('-dev')) {
|
|
return
|
|
}
|
|
|
|
const badge = platformBadge(isMobile)
|
|
const consoleStr = `[${now}] [${userName}] [${levelTag}] ${badge} [${title}] ${formatted}`
|
|
|
|
let logColor: ColorKey | undefined = color
|
|
|
|
if (!logColor) {
|
|
switch (level) {
|
|
case 'error':
|
|
logColor = 'red'
|
|
break
|
|
case 'warn':
|
|
logColor = 'yellow'
|
|
break
|
|
case 'debug':
|
|
logColor = 'magenta'
|
|
break
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
|
|
if (level === 'error' && config.errorDiagnostics) {
|
|
const page = this.bot.isMobile ? this.bot.mainMobilePage : this.bot.mainDesktopPage
|
|
const error = message instanceof Error ? message : new Error(String(message))
|
|
errorDiagnostic(page, error)
|
|
}
|
|
|
|
const consoleAllowed = this.shouldPassFilter(config.consoleLogFilter, level, cleanMsg)
|
|
const webhookAllowed = this.shouldPassFilter(config.webhook.webhookLogFilter, level, cleanMsg)
|
|
|
|
if (consoleAllowed) {
|
|
consoleOut(level, consoleStr, getColorFn(logColor))
|
|
}
|
|
|
|
if (!webhookAllowed) {
|
|
return
|
|
}
|
|
|
|
if (cluster.isPrimary) {
|
|
if (config.webhook.discord?.enabled && config.webhook.discord.url) {
|
|
if (level === 'debug') return
|
|
sendDiscord(config.webhook.discord.url, cleanMsg, level)
|
|
}
|
|
|
|
if (config.webhook.ntfy?.enabled && config.webhook.ntfy.url) {
|
|
if (level === 'debug') return
|
|
sendNtfy(config.webhook.ntfy, cleanMsg, level)
|
|
}
|
|
} else {
|
|
process.send?.({ __ipcLog: { content: cleanMsg, level } })
|
|
}
|
|
}
|
|
|
|
private shouldPassFilter(filter: LogFilter | undefined, level: LogLevel, message: string): boolean {
|
|
// If disabled or not, let all logs pass
|
|
if (!filter || !filter.enabled) {
|
|
return true
|
|
}
|
|
|
|
// Always log error levelo logs, remove these lines to disable this!
|
|
if (level === 'error') {
|
|
return true
|
|
}
|
|
|
|
const { mode, levels, keywords, regexPatterns } = filter
|
|
|
|
const hasLevelRule = Array.isArray(levels) && levels.length > 0
|
|
const hasKeywordRule = Array.isArray(keywords) && keywords.length > 0
|
|
const hasPatternRule = Array.isArray(regexPatterns) && regexPatterns.length > 0
|
|
|
|
if (!hasLevelRule && !hasKeywordRule && !hasPatternRule) {
|
|
return mode === 'blacklist'
|
|
}
|
|
|
|
const lowerMessage = message.toLowerCase()
|
|
let isMatch = false
|
|
|
|
if (hasLevelRule && levels!.includes(level)) {
|
|
isMatch = true
|
|
}
|
|
|
|
if (!isMatch && hasKeywordRule) {
|
|
if (keywords!.some(k => lowerMessage.includes(k.toLowerCase()))) {
|
|
isMatch = true
|
|
}
|
|
}
|
|
|
|
// Fancy regex filtering if set!
|
|
if (!isMatch && hasPatternRule) {
|
|
for (const pattern of regexPatterns!) {
|
|
try {
|
|
const regex = new RegExp(pattern, 'i')
|
|
if (regex.test(message)) {
|
|
isMatch = true
|
|
break
|
|
}
|
|
} catch {}
|
|
}
|
|
}
|
|
|
|
return mode === 'whitelist' ? isMatch : !isMatch
|
|
}
|
|
}
|