2023-04-21 07:55:10 -05:00
|
|
|
import express from 'express'
|
|
|
|
import { body, param } from 'express-validator'
|
|
|
|
import { isUUIDValid } from '@server/helpers/custom-validators/misc'
|
|
|
|
import {
|
|
|
|
isRunnerJobAbortReasonValid,
|
|
|
|
isRunnerJobErrorMessageValid,
|
|
|
|
isRunnerJobProgressValid,
|
|
|
|
isRunnerJobSuccessPayloadValid,
|
|
|
|
isRunnerJobTokenValid,
|
|
|
|
isRunnerJobUpdatePayloadValid
|
|
|
|
} from '@server/helpers/custom-validators/runners/jobs'
|
|
|
|
import { isRunnerTokenValid } from '@server/helpers/custom-validators/runners/runners'
|
|
|
|
import { cleanUpReqFiles } from '@server/helpers/express-utils'
|
2023-05-22 06:44:22 -05:00
|
|
|
import { LiveManager } from '@server/lib/live'
|
2023-04-21 07:55:10 -05:00
|
|
|
import { RunnerJobModel } from '@server/models/runner/runner-job'
|
2023-05-22 06:44:22 -05:00
|
|
|
import {
|
|
|
|
HttpStatusCode,
|
|
|
|
RunnerJobLiveRTMPHLSTranscodingPrivatePayload,
|
|
|
|
RunnerJobState,
|
|
|
|
RunnerJobSuccessBody,
|
|
|
|
RunnerJobUpdateBody,
|
|
|
|
ServerErrorCode
|
|
|
|
} from '@shared/models'
|
2023-04-21 07:55:10 -05:00
|
|
|
import { areValidationErrors } from '../shared'
|
|
|
|
|
|
|
|
const tags = [ 'runner' ]
|
|
|
|
|
|
|
|
export const acceptRunnerJobValidator = [
|
|
|
|
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
|
|
|
if (res.locals.runnerJob.state !== RunnerJobState.PENDING) {
|
|
|
|
return res.fail({
|
|
|
|
status: HttpStatusCode.BAD_REQUEST_400,
|
|
|
|
message: 'This runner job is not in pending state',
|
|
|
|
tags
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
return next()
|
|
|
|
}
|
|
|
|
]
|
|
|
|
|
|
|
|
export const abortRunnerJobValidator = [
|
|
|
|
body('reason').custom(isRunnerJobAbortReasonValid),
|
|
|
|
|
|
|
|
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
|
|
|
if (areValidationErrors(req, res, { tags })) return
|
|
|
|
|
|
|
|
return next()
|
|
|
|
}
|
|
|
|
]
|
|
|
|
|
|
|
|
export const updateRunnerJobValidator = [
|
|
|
|
body('progress').optional().custom(isRunnerJobProgressValid),
|
|
|
|
|
|
|
|
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
|
|
|
if (areValidationErrors(req, res, { tags })) return cleanUpReqFiles(req)
|
|
|
|
|
|
|
|
const body = req.body as RunnerJobUpdateBody
|
2023-05-22 06:44:22 -05:00
|
|
|
const job = res.locals.runnerJob
|
2023-04-21 07:55:10 -05:00
|
|
|
|
2023-05-22 06:44:22 -05:00
|
|
|
if (isRunnerJobUpdatePayloadValid(body.payload, job.type, req.files) !== true) {
|
2023-04-21 07:55:10 -05:00
|
|
|
cleanUpReqFiles(req)
|
|
|
|
|
|
|
|
return res.fail({
|
|
|
|
status: HttpStatusCode.BAD_REQUEST_400,
|
|
|
|
message: 'Payload is invalid',
|
|
|
|
tags
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-05-22 06:44:22 -05:00
|
|
|
if (res.locals.runnerJob.type === 'live-rtmp-hls-transcoding') {
|
|
|
|
const privatePayload = job.privatePayload as RunnerJobLiveRTMPHLSTranscodingPrivatePayload
|
|
|
|
|
|
|
|
if (!LiveManager.Instance.hasSession(privatePayload.sessionId)) {
|
|
|
|
cleanUpReqFiles(req)
|
|
|
|
|
|
|
|
return res.fail({
|
|
|
|
status: HttpStatusCode.BAD_REQUEST_400,
|
2023-05-22 07:10:59 -05:00
|
|
|
type: ServerErrorCode.RUNNER_JOB_NOT_IN_PROCESSING_STATE,
|
2023-05-22 06:44:22 -05:00
|
|
|
message: 'Session of this live ended',
|
|
|
|
tags
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-21 07:55:10 -05:00
|
|
|
return next()
|
|
|
|
}
|
|
|
|
]
|
|
|
|
|
|
|
|
export const errorRunnerJobValidator = [
|
|
|
|
body('message').custom(isRunnerJobErrorMessageValid),
|
|
|
|
|
|
|
|
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
|
|
|
if (areValidationErrors(req, res, { tags })) return
|
|
|
|
|
|
|
|
return next()
|
|
|
|
}
|
|
|
|
]
|
|
|
|
|
|
|
|
export const successRunnerJobValidator = [
|
|
|
|
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
|
|
|
const body = req.body as RunnerJobSuccessBody
|
|
|
|
|
|
|
|
if (isRunnerJobSuccessPayloadValid(body.payload, res.locals.runnerJob.type, req.files) !== true) {
|
|
|
|
cleanUpReqFiles(req)
|
|
|
|
|
|
|
|
return res.fail({
|
|
|
|
status: HttpStatusCode.BAD_REQUEST_400,
|
|
|
|
message: 'Payload is invalid',
|
|
|
|
tags
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
return next()
|
|
|
|
}
|
|
|
|
]
|
|
|
|
|
2023-05-04 08:29:34 -05:00
|
|
|
export const cancelRunnerJobValidator = [
|
|
|
|
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
|
|
|
const runnerJob = res.locals.runnerJob
|
|
|
|
|
|
|
|
const allowedStates = new Set<RunnerJobState>([
|
|
|
|
RunnerJobState.PENDING,
|
|
|
|
RunnerJobState.PROCESSING,
|
|
|
|
RunnerJobState.WAITING_FOR_PARENT_JOB
|
|
|
|
])
|
|
|
|
|
|
|
|
if (allowedStates.has(runnerJob.state) !== true) {
|
|
|
|
return res.fail({
|
|
|
|
status: HttpStatusCode.BAD_REQUEST_400,
|
|
|
|
message: 'Cannot cancel this job that is not in "pending", "processing" or "waiting for parent job" state',
|
|
|
|
tags
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
return next()
|
|
|
|
}
|
|
|
|
]
|
|
|
|
|
2023-04-21 07:55:10 -05:00
|
|
|
export const runnerJobGetValidator = [
|
|
|
|
param('jobUUID').custom(isUUIDValid),
|
|
|
|
|
|
|
|
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
|
|
|
if (areValidationErrors(req, res, { tags })) return
|
|
|
|
|
|
|
|
const runnerJob = await RunnerJobModel.loadWithRunner(req.params.jobUUID)
|
|
|
|
|
|
|
|
if (!runnerJob) {
|
|
|
|
return res.fail({
|
|
|
|
status: HttpStatusCode.NOT_FOUND_404,
|
|
|
|
message: 'Unknown runner job',
|
|
|
|
tags
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
res.locals.runnerJob = runnerJob
|
|
|
|
|
|
|
|
return next()
|
|
|
|
}
|
|
|
|
]
|
|
|
|
|
|
|
|
export const jobOfRunnerGetValidator = [
|
|
|
|
param('jobUUID').custom(isUUIDValid),
|
|
|
|
|
|
|
|
body('runnerToken').custom(isRunnerTokenValid),
|
|
|
|
body('jobToken').custom(isRunnerJobTokenValid),
|
|
|
|
|
|
|
|
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
|
|
|
if (areValidationErrors(req, res, { tags })) return cleanUpReqFiles(req)
|
|
|
|
|
|
|
|
const runnerJob = await RunnerJobModel.loadByRunnerAndJobTokensWithRunner({
|
|
|
|
uuid: req.params.jobUUID,
|
|
|
|
runnerToken: req.body.runnerToken,
|
|
|
|
jobToken: req.body.jobToken
|
|
|
|
})
|
|
|
|
|
|
|
|
if (!runnerJob) {
|
|
|
|
cleanUpReqFiles(req)
|
|
|
|
|
|
|
|
return res.fail({
|
|
|
|
status: HttpStatusCode.NOT_FOUND_404,
|
|
|
|
message: 'Unknown runner job',
|
|
|
|
tags
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
if (runnerJob.state !== RunnerJobState.PROCESSING) {
|
|
|
|
cleanUpReqFiles(req)
|
|
|
|
|
|
|
|
return res.fail({
|
|
|
|
status: HttpStatusCode.BAD_REQUEST_400,
|
|
|
|
type: ServerErrorCode.RUNNER_JOB_NOT_IN_PROCESSING_STATE,
|
|
|
|
message: 'Job is not in "processing" state',
|
|
|
|
tags
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
res.locals.runnerJob = runnerJob
|
|
|
|
|
|
|
|
return next()
|
|
|
|
}
|
|
|
|
]
|