chipmunkbot3/commands/logquery.js

115 lines
3 KiB
JavaScript
Raw Permalink Normal View History

2024-05-30 22:47:41 -04:00
const { literal, argument, greedyString, SimpleCommandExceptionType } = require('brigadier-commands')
const TextMessage = require('../util/command/text_message')
const fs = require('fs')
const path = require('path')
const zlib = require('zlib')
2024-06-02 17:26:17 -04:00
const stream = require('stream/promises')
2024-05-30 22:47:41 -04:00
const LOG_QUERY_ALREADY_RUNNING_ERROR = new SimpleCommandExceptionType(new TextMessage('Another log query is already running!'))
module.exports = {
running: false,
stream: null,
2024-05-30 23:07:52 -04:00
create () {
return Object.create(this)
},
2024-05-30 22:47:41 -04:00
register (dispatcher) {
const node = dispatcher.register(
literal('logquery')
.then(
literal('count')
.then(
argument('string', greedyString())
.executes(c => this.countCommand(c))
2024-05-30 22:47:41 -04:00
)
)
.then(
literal('abort')
.executes(c => this.abortCommand(c))
2024-05-30 22:47:41 -04:00
)
)
node.description = 'Searches for text in log files'
node.permissionLevel = 0
},
2024-05-30 23:07:52 -04:00
cleanup () {
this.abort()
},
2024-05-30 22:47:41 -04:00
async countCommand (context) {
const source = context.source
const bot = source.bot
const string = context.getArgument('string')
source.sendFeedback([{ text: 'Searching for instances of ', ...bot.styles.primary }, { text: string, ...bot.styles.secondary }, ' in logs...'], false)
let count = 0
2024-05-30 23:10:28 -04:00
const ran = await this.queryLogs(source, line => line.includes(string) && count++)
2024-05-30 22:47:41 -04:00
2024-05-30 23:10:28 -04:00
if (ran) source.sendFeedback([{ text: 'Found ', ...bot.styles.primary }, { text: count + '', ...bot.styles.secondary }, ' instances of ', { text: string, ...bot.styles.secondary }], true)
2024-05-30 22:47:41 -04:00
},
abortCommand (context) {
const source = context.source
const bot = source.bot
this.abort()
source.sendFeedback({ text: 'Stopped the running log query', ...bot.styles.primary })
},
abort () {
this.running = false
this.stream?.close()
this.stream = null
},
async queryLogs (source, handler) {
if (this.running) throw LOG_QUERY_ALREADY_RUNNING_ERROR.create()
const bot = source.bot
const logsDir = bot.paths.logs
this.running = true
2024-06-02 17:26:17 -04:00
const filenames = await fs.promises.readdir(logsDir)
for (let i = 0; i < filenames.length; i++) {
const filename = filenames[i]
2024-05-30 22:47:41 -04:00
const readStream = fs.createReadStream(path.join(logsDir, filename))
this.stream = readStream
if (filename.endsWith('.gz')) {
const gunzip = zlib.createGunzip()
readStream.pipe(gunzip)
this.stream = gunzip
}
let queue = ''
this.stream.on('data', chunk => {
queue += chunk // * This should convert it to a string
const lastNewlineIdx = queue.lastIndexOf('\n')
const lines = queue.substring(0, lastNewlineIdx)
queue = queue.substring(lastNewlineIdx + 1)
for (const line of lines.split('\n')) handler(line)
})
2024-06-02 17:26:17 -04:00
try {
await stream.finished(this.stream)
} catch {
}
2024-05-30 22:47:41 -04:00
2024-05-30 23:10:28 -04:00
if (!this.running) return false // if this was aborted
2024-05-30 22:47:41 -04:00
}
this.running = false
this.stream = null
2024-05-30 23:10:28 -04:00
return true
2024-05-30 22:47:41 -04:00
}
}