diff --git a/api/.env.example b/api/.env.example index ab6de3e..a21c209 100644 --- a/api/.env.example +++ b/api/.env.example @@ -6,6 +6,8 @@ PROTOCOL=[http|https] default considered as http PRIVATE_KEY=privkey.pem FULL_CHAIN=fullchain.pem +RUN_TIMES=[sas|js|sas,js|js,sas] default considered as sas + PORT=[5000] default value is 5000 HELMET_CSP_CONFIG_PATH=./csp.config.json if omitted HELMET default will be used diff --git a/api/src/controllers/internal/FileUploadController.ts b/api/src/controllers/internal/FileUploadController.ts index d267d43..7c6737c 100644 --- a/api/src/controllers/internal/FileUploadController.ts +++ b/api/src/controllers/internal/FileUploadController.ts @@ -32,7 +32,17 @@ export class FileUploadController { const programPath = (query?._program ?? body?._program) as string - const { runTime } = await getRunTimeAndFilePath(programPath) + let runTime + + try { + ;({ runTime } = await getRunTimeAndFilePath(programPath)) + } catch (err: any) { + res.status(400).send({ + status: 'failure', + message: 'Job execution failed', + error: typeof err === 'object' ? err.toString() : err + }) + } const sessionController = runTime === RunTimeType.SAS diff --git a/api/src/controllers/stp.ts b/api/src/controllers/stp.ts index 624762c..37e3dad 100644 --- a/api/src/controllers/stp.ts +++ b/api/src/controllers/stp.ts @@ -131,9 +131,9 @@ const executeReturnRaw = async ( ): Promise => { const query = req.query as ExecutionVars - const { codePath, runTime } = await getRunTimeAndFilePath(_program) - try { + const { codePath, runTime } = await getRunTimeAndFilePath(_program) + const { result, httpHeaders } = (await new ExecutionController().executeFile({ programPath: codePath, @@ -169,13 +169,13 @@ const executeReturnJson = async ( req: express.Request, _program: string ): Promise => { - const { codePath, runTime } = await getRunTimeAndFilePath(_program) - const filesNamesMap = req.files?.length ? makeFilesNamesMap(req.files as MulterFile[]) : null try { + const { codePath, runTime } = await getRunTimeAndFilePath(_program) + const { webout, log, httpHeaders } = (await new ExecutionController().executeFile({ programPath: codePath, diff --git a/api/src/utils/getRunTimeAndFilePath.ts b/api/src/utils/getRunTimeAndFilePath.ts index f25edf6..e36c931 100644 --- a/api/src/utils/getRunTimeAndFilePath.ts +++ b/api/src/utils/getRunTimeAndFilePath.ts @@ -1,18 +1,37 @@ import path from 'path' import { fileExists } from '@sasjs/utils' import { getFilesFolder } from './file' +import { RunTimeType } from '.' export const getRunTimeAndFilePath = async (programPath: string) => { - for (const runTime of process.runTimes) { - const codePath = - path - .join(getFilesFolder(), programPath) - .replace(new RegExp('/', 'g'), path.sep) + - '.' + - runTime + const ext = path.extname(programPath) + // if program path is provided with extension we should split that into code path and ext as run time + if (ext) { + const runTime = ext.slice(1) + const runTimeTypes = Object.values(RunTimeType) - if (await fileExists(codePath)) return { codePath, runTime } + if (!runTimeTypes.includes(runTime as RunTimeType)) { + throw `The '${runTime}' runtime is not supported.` + } + + const codePath = path + .join(getFilesFolder(), programPath) + .replace(new RegExp('/', 'g'), path.sep) + + if (await fileExists(codePath)) { + return { codePath, runTime: runTime as RunTimeType } + } + } else { + for (const runTime of process.runTimes) { + const codePath = + path + .join(getFilesFolder(), programPath) + .replace(new RegExp('/', 'g'), path.sep) + + '.' + + runTime + + if (await fileExists(codePath)) return { codePath, runTime } + } } - throw `The Program at (${programPath}) does not exist.` }