52 lines
1.6 KiB
TypeScript
52 lines
1.6 KiB
TypeScript
import type { HttpContext } from '@adonisjs/core/http'
|
|
import AuditLog from '#models/audit_log'
|
|
import UserError from '#exceptions/user_error'
|
|
import jobRunner, { type JobLine } from '#services/job_runner'
|
|
import { openSse } from '#services/sse'
|
|
|
|
export default class JobsController {
|
|
/**
|
|
* Replays the output of a job, then follows it until the end. Jobs
|
|
* finished a while ago are read from the action log.
|
|
*/
|
|
async stream(ctx: HttpContext) {
|
|
const id = Number(ctx.params.id)
|
|
const job = jobRunner.get(id)
|
|
const entry = job ? null : await AuditLog.find(id)
|
|
if (!job && !entry) throw new UserError('Action introuvable.', 404)
|
|
|
|
const channel = openSse(ctx)
|
|
|
|
if (!job) {
|
|
const lines = (entry!.output ?? '')
|
|
.split('\n')
|
|
.map((text) => ({ ts: 0, stream: 'out', text }))
|
|
channel.send('meta', { id, action: entry!.action, target: entry!.target })
|
|
channel.send('lines', lines)
|
|
channel.send('end', { status: entry!.status })
|
|
channel.close()
|
|
return
|
|
}
|
|
|
|
channel.send('meta', { id, action: job.meta.action, target: job.meta.target })
|
|
channel.send('lines', job.lines)
|
|
if (job.status !== 'running') {
|
|
channel.send('end', { status: job.status })
|
|
channel.close()
|
|
return
|
|
}
|
|
|
|
const onLine = (line: JobLine) => channel.send('lines', [line])
|
|
const onEnd = (status: string) => {
|
|
channel.send('end', { status })
|
|
channel.close()
|
|
}
|
|
job.on('line', onLine)
|
|
job.once('end', onEnd)
|
|
channel.onClose(() => {
|
|
job.off('line', onLine)
|
|
job.off('end', onEnd)
|
|
})
|
|
}
|
|
}
|