diff --git a/api/src/controllers/code.ts b/api/src/controllers/code.ts index 1e09c4d..b164396 100644 --- a/api/src/controllers/code.ts +++ b/api/src/controllers/code.ts @@ -1,7 +1,6 @@ import express from 'express' import { Request, Security, Route, Tags, Post, Body } from 'tsoa' -import { ExecuteReturnJson, ExecutionController } from './internal' -import { ExecuteReturnJsonResponse } from '.' +import { ExecutionController } from './internal' import { getPreProgramVariables, getUserAutoExec, @@ -35,7 +34,7 @@ export class CodeController { public async executeCode( @Request() request: express.Request, @Body() body: ExecuteCodePayload - ): Promise { + ): Promise { return executeCode(request, body) } } @@ -51,22 +50,15 @@ const executeCode = async ( : await getUserAutoExec() try { - const { webout, log, httpHeaders } = - (await new ExecutionController().executeProgram({ - program: code, - preProgramVariables: getPreProgramVariables(req), - vars: { ...req.query, _debug: 131 }, - otherArgs: { userAutoExec }, - returnJson: true, - runTime: runTime - })) as ExecuteReturnJson + const { result } = await new ExecutionController().executeProgram({ + program: code, + preProgramVariables: getPreProgramVariables(req), + vars: { ...req.query, _debug: 131 }, + otherArgs: { userAutoExec }, + runTime: runTime + }) - return { - status: 'success', - _webout: webout as string, - log: parseLogToArray(log), - httpHeaders - } + return result } catch (err: any) { throw { code: 400, diff --git a/api/src/controllers/internal/Execution.ts b/api/src/controllers/internal/Execution.ts index b5594a6..e96e7c4 100644 --- a/api/src/controllers/internal/Execution.ts +++ b/api/src/controllers/internal/Execution.ts @@ -20,12 +20,6 @@ export interface ExecuteReturnRaw { result: string | Buffer } -export interface ExecuteReturnJson { - httpHeaders: HTTPHeaders - webout: string | Buffer - log?: string -} - interface ExecuteFileParams { programPath: string preProgramVariables: PreProgramVars @@ -68,10 +62,9 @@ export class ExecutionController { preProgramVariables, vars, otherArgs, - returnJson, session: sessionByFileUpload, runTime - }: ExecuteProgramParams): Promise { + }: ExecuteProgramParams): Promise { const sessionController = getSessionController(runTime) const session = @@ -89,8 +82,6 @@ export class ExecutionController { tokenFile, preProgramVariables?.httpHeaders.join('\n') ?? '' ) - if (returnJson) - await createFile(headersPath, 'Content-type: application/json') await processProgram( program, @@ -110,10 +101,7 @@ export class ExecutionController { ? await readFile(headersPath) : '' const httpHeaders: HTTPHeaders = extractHeaders(headersContent) - const fileResponse: boolean = - httpHeaders.hasOwnProperty('content-type') && - !returnJson && // not a POST Request - !isDebugOn(vars) // Debug is not enabled + const fileResponse: boolean = httpHeaders.hasOwnProperty('content-type') const webout = (await fileExists(weboutPath)) ? fileResponse @@ -124,19 +112,11 @@ export class ExecutionController { // it should be deleted by scheduleSessionDestroy session.inUse = false - if (returnJson) { - return { - httpHeaders, - webout, - log: isDebugOn(vars) || session.crashed ? log : undefined - } - } - return { httpHeaders, result: isDebugOn(vars) || session.crashed - ? `${webout}

SAS Log

${log}
` + ? `${webout}\n${process.logsUUID}\n${log}` : webout } } diff --git a/api/src/controllers/stp.ts b/api/src/controllers/stp.ts index a32c706..aab271a 100644 --- a/api/src/controllers/stp.ts +++ b/api/src/controllers/stp.ts @@ -1,33 +1,16 @@ import express from 'express' -import { - Request, - Security, - Route, - Tags, - Post, - Body, - Get, - Query, - Example -} from 'tsoa' -import { - ExecuteReturnJson, - ExecuteReturnRaw, - ExecutionController, - ExecutionVars -} from './internal' +import { Request, Security, Route, Tags, Post, Body, Get, Query } from 'tsoa' +import { ExecutionController, ExecutionVars } from './internal' import { getPreProgramVariables, HTTPHeaders, - isDebugOn, LogLine, makeFilesNamesMap, - parseLogToArray, getRunTimeAndFilePath } from '../utils' import { MulterFile } from '../types/Upload' -interface ExecuteReturnJsonPayload { +interface ExecutePostRequestPayload { /** * Location of SAS program * @example "/Public/somefolder/some.file" @@ -35,17 +18,6 @@ interface ExecuteReturnJsonPayload { _program?: string } -interface IRecordOfAny { - [key: string]: any -} -export interface ExecuteReturnJsonResponse { - status: string - _webout: string | IRecordOfAny - log: LogLine[] - message?: string - httpHeaders: HTTPHeaders -} - @Security('bearerAuth') @Route('SASjsApi/stp') @Tags('STP') @@ -62,11 +34,12 @@ export class STPController { * @example _program "/Projects/myApp/some/program" */ @Get('/execute') - public async executeReturnRaw( + public async executeGetRequest( @Request() request: express.Request, @Query() _program: string ): Promise { - return executeReturnRaw(request, _program) + const vars = request.query as ExecutionVars + return execute(request, _program, vars) } /** @@ -87,50 +60,42 @@ export class STPController { * @param _program Location of SAS or JS code * @example _program "/Projects/myApp/some/program" */ - @Example({ - status: 'success', - _webout: 'webout content', - log: [], - httpHeaders: { - 'Content-type': 'application/zip', - 'Cache-Control': 'public, max-age=1000' - } - }) @Post('/execute') - public async executeReturnJson( + public async executePostRequest( @Request() request: express.Request, - @Body() body?: ExecuteReturnJsonPayload, + @Body() body?: ExecutePostRequestPayload, @Query() _program?: string - ): Promise { + ): Promise { const program = _program ?? body?._program - return executeReturnJson(request, program!) + const vars = { ...request.query, ...request.body } + const filesNamesMap = request.files?.length + ? makeFilesNamesMap(request.files as MulterFile[]) + : null + const otherArgs = { filesNamesMap: filesNamesMap } + + return execute(request, program!, vars, otherArgs) } } -const executeReturnRaw = async ( +const execute = async ( req: express.Request, - _program: string + _program: string, + vars: ExecutionVars, + otherArgs?: any ): Promise => { - const query = req.query as ExecutionVars - try { const { codePath, runTime } = await getRunTimeAndFilePath(_program) - const { result, httpHeaders } = - (await new ExecutionController().executeFile({ + const { result, httpHeaders } = await new ExecutionController().executeFile( + { programPath: codePath, + runTime, preProgramVariables: getPreProgramVariables(req), - vars: query, - runTime - })) as ExecuteReturnRaw - - // Should over-ride response header for debug - // on GET request to see entire log rendering on browser. - if (isDebugOn(query)) { - httpHeaders['content-type'] = 'text/plain' - } - - req.res?.set(httpHeaders) + vars, + otherArgs, + session: req.sasjsSession + } + ) if (result instanceof Buffer) { ;(req as any).sasHeaders = httpHeaders @@ -146,48 +111,3 @@ const executeReturnRaw = async ( } } } - -const executeReturnJson = async ( - req: express.Request, - _program: string -): Promise => { - 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, - preProgramVariables: getPreProgramVariables(req), - vars: { ...req.query, ...req.body }, - otherArgs: { filesNamesMap: filesNamesMap }, - returnJson: true, - session: req.sasjsSession, - runTime - })) as ExecuteReturnJson - - let weboutRes: string | IRecordOfAny = webout - if (httpHeaders['content-type']?.toLowerCase() === 'application/json') { - try { - weboutRes = JSON.parse(webout as string) - } catch (_) {} - } - - return { - status: 'success', - _webout: weboutRes, - log: parseLogToArray(log), - httpHeaders - } - } catch (err: any) { - throw { - code: 400, - status: 'failure', - message: 'Job execution failed.', - error: typeof err === 'object' ? err.toString() : err - } - } -} diff --git a/api/src/routes/api/stp.ts b/api/src/routes/api/stp.ts index 858feb5..cb1adce 100644 --- a/api/src/routes/api/stp.ts +++ b/api/src/routes/api/stp.ts @@ -13,7 +13,7 @@ stpRouter.get('/execute', async (req, res) => { if (error) return res.status(400).send(error.details[0].message) try { - const response = await controller.executeReturnRaw(req, query._program) + const response = await controller.executeGetRequest(req, query._program) if (response instanceof Buffer) { res.writeHead(200, (req as any).sasHeaders) @@ -42,7 +42,7 @@ stpRouter.post( // if (errQ && errB) return res.status(400).send(errB.details[0].message) try { - const response = await controller.executeReturnJson( + const response = await controller.executePostRequest( req, req.body, req.query?._program as string diff --git a/api/src/types/system/process.d.ts b/api/src/types/system/process.d.ts index f635d46..75a16c9 100644 --- a/api/src/types/system/process.d.ts +++ b/api/src/types/system/process.d.ts @@ -5,6 +5,7 @@ declare namespace NodeJS { pythonLoc?: string driveLoc: string logsLoc: string + logsUUID: string sasSessionController?: import('../../controllers/internal').SASSessionController jsSessionController?: import('../../controllers/internal').JSSessionController pythonSessionController?: import('../../controllers/internal').PythonSessionController diff --git a/api/src/utils/setProcessVariables.ts b/api/src/utils/setProcessVariables.ts index 07c03e2..00382b9 100644 --- a/api/src/utils/setProcessVariables.ts +++ b/api/src/utils/setProcessVariables.ts @@ -50,6 +50,8 @@ export const setProcessVariables = async () => { await createFolder(absLogsPath) process.logsLoc = getRealPath(absLogsPath) + process.logsUUID = 'SASJS_LOGS_SEPARATOR_163ee17b6ff24f028928972d80a26784' + console.log('sasLoc: ', process.sasLoc) console.log('sasDrive: ', process.driveLoc) console.log('sasLogs: ', process.logsLoc) diff --git a/web/src/containers/Studio/editor.tsx b/web/src/containers/Studio/editor.tsx index f90217d..d424760 100644 --- a/web/src/containers/Studio/editor.tsx +++ b/web/src/containers/Studio/editor.tsx @@ -70,6 +70,8 @@ type SASjsEditorProps = { } const baseUrl = window.location.origin +const SASJS_LOGS_SEPARATOR = + 'SASJS_LOGS_SEPARATOR_163ee17b6ff24f028928972d80a26784' const SASjsEditor = ({ selectedFilePath, @@ -203,13 +205,8 @@ const SASjsEditor = ({ axios .post(`/SASjsApi/code/execute`, { code, runTime: selectedRunTime }) .then((res: any) => { - const parsedLog = res?.data?.log - .map((logLine: any) => logLine.line) - .join('\n') - - setLog(parsedLog) - - setWebout(`${res.data?._webout}`) + setWebout(res.data.split(SASJS_LOGS_SEPARATOR)[0] ?? '') + setLog(res.data.split(SASJS_LOGS_SEPARATOR)[1] ?? '') setTab('log') // Scroll to bottom of log