114 lines
3 KiB
JavaScript
114 lines
3 KiB
JavaScript
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')
|
|
const stream = require('stream/promises')
|
|
|
|
const LOG_QUERY_ALREADY_RUNNING_ERROR = new SimpleCommandExceptionType(new TextMessage('Another log query is already running!'))
|
|
|
|
module.exports = {
|
|
running: false,
|
|
stream: null,
|
|
|
|
create () {
|
|
return Object.create(this)
|
|
},
|
|
|
|
register (dispatcher) {
|
|
const node = dispatcher.register(
|
|
literal('logquery')
|
|
.then(
|
|
literal('count')
|
|
.then(
|
|
argument('string', greedyString())
|
|
.executes(c => this.countCommand(c))
|
|
)
|
|
)
|
|
.then(
|
|
literal('abort')
|
|
.executes(c => this.abortCommand(c))
|
|
)
|
|
)
|
|
|
|
node.description = 'Searches for text in log files'
|
|
node.permissionLevel = 0
|
|
},
|
|
|
|
cleanup () {
|
|
this.abort()
|
|
},
|
|
|
|
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
|
|
const ran = await this.queryLogs(source, line => line.includes(string) && count++)
|
|
|
|
if (ran) source.sendFeedback([{ text: 'Found ', ...bot.styles.primary }, { text: count + '', ...bot.styles.secondary }, ' instances of ', { text: string, ...bot.styles.secondary }], true)
|
|
},
|
|
|
|
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
|
|
|
|
const filenames = await fs.promises.readdir(logsDir)
|
|
for (let i = 0; i < filenames.length; i++) {
|
|
const filename = filenames[i]
|
|
|
|
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)
|
|
})
|
|
|
|
try {
|
|
await stream.finished(this.stream)
|
|
} catch {
|
|
}
|
|
|
|
if (!this.running) return false // if this was aborted
|
|
}
|
|
|
|
this.running = false
|
|
this.stream = null
|
|
return true
|
|
}
|
|
}
|