mirror of
https://github.com/sasjs/server.git
synced 2025-12-10 19:34:34 +00:00
165 lines
4.3 KiB
TypeScript
165 lines
4.3 KiB
TypeScript
import express from 'express'
|
|
import { Request, Security, Route, Tags, Post, Body } from 'tsoa'
|
|
import { ExecutionController, getSessionController } from './internal'
|
|
import {
|
|
getPreProgramVariables,
|
|
getUserAutoExec,
|
|
ModeType,
|
|
RunTimeType
|
|
} from '../utils'
|
|
|
|
interface ExecuteCodePayload {
|
|
/**
|
|
* The code to be executed
|
|
* @example "* Your Code HERE;"
|
|
*/
|
|
code: string
|
|
/**
|
|
* The runtime for the code - eg SAS, JS, PY or R
|
|
* @example "js"
|
|
*/
|
|
runTime: RunTimeType
|
|
}
|
|
|
|
interface TriggerCodePayload {
|
|
/**
|
|
* The code to be executed
|
|
* @example "* Your Code HERE;"
|
|
*/
|
|
code: string
|
|
/**
|
|
* The runtime for the code - eg SAS, JS, PY or R
|
|
* @example "sas"
|
|
*/
|
|
runTime: RunTimeType
|
|
/**
|
|
* Amount of minutes after the completion of the job when the session must be
|
|
* destroyed.
|
|
* @example 15
|
|
*/
|
|
expiresAfterMins?: number
|
|
}
|
|
|
|
interface TriggerCodeResponse {
|
|
/**
|
|
* The SessionId is the name of the temporary folder used to store the outputs.
|
|
* For SAS, this would be the SASWORK folder. Can be used to poll job status.
|
|
* This session ID should be used to poll job status.
|
|
* @example "{ sessionId: '20241028074744-54132-1730101664824' }"
|
|
*/
|
|
sessionId: string
|
|
}
|
|
|
|
@Security('bearerAuth')
|
|
@Route('SASjsApi/code')
|
|
@Tags('Code')
|
|
export class CodeController {
|
|
/**
|
|
* Execute Code on the Specified Runtime
|
|
* @summary Run Code and Return Webout Content, Log and Print output
|
|
* The order of returned parts of the payload is:
|
|
* 1. Webout (if present)
|
|
* 2. Logs UUID (used as separator)
|
|
* 3. Log
|
|
* 4. Logs UUID (used as separator)
|
|
* 5. Print (if present and if the runtime is SAS)
|
|
* Please see @sasjs/server/api/src/controllers/internal/Execution.ts for more information
|
|
*/
|
|
@Post('/execute')
|
|
public async executeCode(
|
|
@Request() request: express.Request,
|
|
@Body() body: ExecuteCodePayload
|
|
): Promise<string | Buffer> {
|
|
return executeCode(request, body)
|
|
}
|
|
|
|
/**
|
|
* Trigger Code on the Specified Runtime
|
|
* @summary Triggers code and returns SessionId immediately - does not wait for job completion
|
|
*/
|
|
@Post('/trigger')
|
|
public async triggerCode(
|
|
@Request() request: express.Request,
|
|
@Body() body: TriggerCodePayload
|
|
): Promise<TriggerCodeResponse> {
|
|
return triggerCode(request, body)
|
|
}
|
|
}
|
|
|
|
const executeCode = async (
|
|
req: express.Request,
|
|
{ code, runTime }: ExecuteCodePayload
|
|
) => {
|
|
const { user } = req
|
|
const userAutoExec =
|
|
process.env.MODE === ModeType.Server
|
|
? user?.autoExec
|
|
: await getUserAutoExec()
|
|
|
|
try {
|
|
const { result } = await new ExecutionController().executeProgram({
|
|
program: code,
|
|
preProgramVariables: getPreProgramVariables(req),
|
|
vars: { ...req.query, _debug: 131 },
|
|
otherArgs: { userAutoExec },
|
|
runTime: runTime,
|
|
includePrintOutput: true
|
|
})
|
|
|
|
return result
|
|
} catch (err: any) {
|
|
throw {
|
|
code: 400,
|
|
status: 'failure',
|
|
message: 'Job execution failed.',
|
|
error: typeof err === 'object' ? err.toString() : err
|
|
}
|
|
}
|
|
}
|
|
|
|
const triggerCode = async (
|
|
req: express.Request,
|
|
{ code, runTime, expiresAfterMins }: TriggerCodePayload
|
|
): Promise<{ sessionId: string }> => {
|
|
const { user } = req
|
|
const userAutoExec =
|
|
process.env.MODE === ModeType.Server
|
|
? user?.autoExec
|
|
: await getUserAutoExec()
|
|
|
|
// get session controller based on runTime
|
|
const sessionController = getSessionController(runTime)
|
|
|
|
// get session
|
|
const session = await sessionController.getSession()
|
|
|
|
// add expiresAfterMins to session if provided
|
|
if (expiresAfterMins) {
|
|
// expiresAfterMins.used is set initially to false
|
|
session.expiresAfterMins = { mins: expiresAfterMins, used: false }
|
|
}
|
|
|
|
try {
|
|
// call executeProgram method of ExecutionController without awaiting
|
|
new ExecutionController().executeProgram({
|
|
program: code,
|
|
preProgramVariables: getPreProgramVariables(req),
|
|
vars: { ...req.query, _debug: 131 },
|
|
otherArgs: { userAutoExec },
|
|
runTime: runTime,
|
|
includePrintOutput: true,
|
|
session // session is provided
|
|
})
|
|
|
|
// return session id
|
|
return { sessionId: session.id }
|
|
} catch (err: any) {
|
|
throw {
|
|
code: 400,
|
|
status: 'failure',
|
|
message: 'Job execution failed.',
|
|
error: typeof err === 'object' ? err.toString() : err
|
|
}
|
|
}
|
|
}
|