From c0f38ba7c9639848fe79506be3c17eb92c48d6f5 Mon Sep 17 00:00:00 2001 From: Yury Shkoda Date: Fri, 28 Apr 2023 15:09:44 +0300 Subject: [PATCH 01/13] wip(print-output): added print output to response payload --- api/src/controllers/internal/Execution.ts | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/api/src/controllers/internal/Execution.ts b/api/src/controllers/internal/Execution.ts index 2ef6514..28e7424 100644 --- a/api/src/controllers/internal/Execution.ts +++ b/api/src/controllers/internal/Execution.ts @@ -77,6 +77,8 @@ export class ExecutionController { session.consumed = true const logPath = path.join(session.path, 'log.log') + const printOutputPath = path.join(session.path, 'output.lst') + console.log(`🤖[printOutputPath]🤖`, printOutputPath) const headersPath = path.join(session.path, 'stpsrv_header.txt') const weboutPath = path.join(session.path, 'webout.txt') @@ -102,6 +104,10 @@ export class ExecutionController { ) const log = (await fileExists(logPath)) ? await readFile(logPath) : '' + const printOutput = (await fileExists(printOutputPath)) + ? await readFile(printOutputPath) + : '' + console.log(`🤖[printOutput]🤖`, printOutput) const headersContent = (await fileExists(headersPath)) ? await readFile(headersPath) : '' @@ -122,12 +128,19 @@ export class ExecutionController { // it should be deleted by scheduleSessionDestroy session.inUse = false + const resultParts = [webout, process.logsUUID, log] + + if (printOutput) { + resultParts.push(process.logsUUID) + resultParts.push(printOutput) + } + + console.log(`🤖[resultParts]🤖`, resultParts) + return { httpHeaders, result: - isDebugOn(vars) || session.crashed - ? `${webout}\n${process.logsUUID}\n${log}` - : webout + isDebugOn(vars) || session.crashed ? resultParts.join(`\n`) : webout } } From 6dd2f4f87673336135bc7a6de0d2e143e192c025 Mon Sep 17 00:00:00 2001 From: Yury Shkoda Date: Fri, 28 Apr 2023 17:25:30 +0300 Subject: [PATCH 02/13] fix(execution): removed empty webout from response --- api/src/controllers/internal/Execution.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/api/src/controllers/internal/Execution.ts b/api/src/controllers/internal/Execution.ts index 28e7424..32611bd 100644 --- a/api/src/controllers/internal/Execution.ts +++ b/api/src/controllers/internal/Execution.ts @@ -78,7 +78,6 @@ export class ExecutionController { const logPath = path.join(session.path, 'log.log') const printOutputPath = path.join(session.path, 'output.lst') - console.log(`🤖[printOutputPath]🤖`, printOutputPath) const headersPath = path.join(session.path, 'stpsrv_header.txt') const weboutPath = path.join(session.path, 'webout.txt') @@ -107,7 +106,6 @@ export class ExecutionController { const printOutput = (await fileExists(printOutputPath)) ? await readFile(printOutputPath) : '' - console.log(`🤖[printOutput]🤖`, printOutput) const headersContent = (await fileExists(headersPath)) ? await readFile(headersPath) : '' @@ -128,15 +126,18 @@ export class ExecutionController { // it should be deleted by scheduleSessionDestroy session.inUse = false - const resultParts = [webout, process.logsUUID, log] + const resultParts = [] + + if (webout) resultParts.push(webout) + + resultParts.push(process.logsUUID) + resultParts.push(log) if (printOutput) { resultParts.push(process.logsUUID) resultParts.push(printOutput) } - console.log(`🤖[resultParts]🤖`, resultParts) - return { httpHeaders, result: From d2de9dc13ef2e980286dd03cca5e22cea443ed0c Mon Sep 17 00:00:00 2001 From: Yury Shkoda Date: Mon, 1 May 2023 07:28:23 +0300 Subject: [PATCH 03/13] fix(editor): fixed log/webout/print tabs --- web/src/containers/Studio/editor.tsx | 71 +++++++++++++++++----------- 1 file changed, 43 insertions(+), 28 deletions(-) diff --git a/web/src/containers/Studio/editor.tsx b/web/src/containers/Studio/editor.tsx index 02964c1..8dd84c9 100644 --- a/web/src/containers/Studio/editor.tsx +++ b/web/src/containers/Studio/editor.tsx @@ -62,6 +62,7 @@ const SASjsEditor = ({ selectedRunTime, showDiff, webout, + printOutput, Dialog, handleChangeRunTime, handleDiffEditorDidMount, @@ -153,30 +154,35 @@ const SASjsEditor = ({ > - - ) : ( - '' - ) - } - onClick={() => { - const logWrapper = document.querySelector(`#logWrapper`) + {log && ( + + ) : ( + '' + ) + } + onClick={() => { + const logWrapper = document.querySelector(`#logWrapper`) - if (logWrapper) logWrapper.scrollTop = 0 - }} - /> - - Webout - - } - value="webout" - /> + if (logWrapper) logWrapper.scrollTop = 0 + }} + /> + )} + {webout && ( + + Webout + + } + value="webout" + /> + )} + {printOutput && } @@ -222,11 +228,20 @@ const SASjsEditor = ({ )} - -
-
{webout}
-
-
+ {webout && ( + +
+
{webout}
+
+
+ )} + {printOutput && ( + +
+
{printOutput}
+
+
+ )} )} From eb42683fff701bd5b4d2b68760fe0c3ecad573dd Mon Sep 17 00:00:00 2001 From: Yury Shkoda Date: Mon, 1 May 2023 08:18:49 +0300 Subject: [PATCH 04/13] feat(editor): parse print output in response payload --- .../Studio/internal/hooks/useEditor.ts | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/web/src/containers/Studio/internal/hooks/useEditor.ts b/web/src/containers/Studio/internal/hooks/useEditor.ts index 5baba2d..7ff3333 100644 --- a/web/src/containers/Studio/internal/hooks/useEditor.ts +++ b/web/src/containers/Studio/internal/hooks/useEditor.ts @@ -39,14 +39,14 @@ const useEditor = ({ const { Snackbar, setOpenSnackbar, setSnackbarMessage, setSnackbarSeverity } = useSnackbar() const [isLoading, setIsLoading] = useState(false) - const [prevFileContent, setPrevFileContent] = useStateWithCallback('') const [fileContent, setFileContent] = useState('') const [log, setLog] = useState() - const [webout, setWebout] = useState('') + const [webout, setWebout] = useState() + const [printOutput, setPrintOutput] = useState() const [runTimes, setRunTimes] = useState([]) - const [selectedRunTime, setSelectedRunTime] = useState( - '' + const [selectedRunTime, setSelectedRunTime] = useState( + RunTimeType.SAS ) const [selectedFileExtension, setSelectedFileExtension] = useState('') const [openFilePathInputModal, setOpenFilePathInputModal] = useState(false) @@ -169,25 +169,29 @@ const useEditor = ({ ), runTime: selectedRunTime }) - .then((res: any) => { - if (selectedRunTime === RunTimeType.SAS) { - const { errors, warnings, logLines } = parseErrorsAndWarnings( - res.data.split(SASJS_LOGS_SEPARATOR)[1] - ) + .then((res: { data: string }) => { + const resDataSplitted = res.data.split(SASJS_LOGS_SEPARATOR) + const webout = resDataSplitted[0] + const log = resDataSplitted[1] + const printOutput = resDataSplitted[2] - const log: LogObject = { + if (selectedRunTime === RunTimeType.SAS) { + const { errors, warnings, logLines } = parseErrorsAndWarnings(log) + + const logObject: LogObject = { body: logLines.join(`\n`), errors, warnings, linesCount: logLines.length } - setLog(log) + setLog(logObject) } else { - setLog(res.data.split(SASJS_LOGS_SEPARATOR)[1] ?? '') + setLog(log) } - setWebout(res.data.split(SASJS_LOGS_SEPARATOR)[0] ?? '') + setWebout(webout) + setPrintOutput(printOutput) setTab('log') // Scroll to bottom of log @@ -335,6 +339,7 @@ const useEditor = ({ selectedRunTime, showDiff, webout, + printOutput, Dialog, handleChangeRunTime, handleDiffEditorDidMount, From 31df72ad88fe2c771d0ef8445d6db9dd147c40c9 Mon Sep 17 00:00:00 2001 From: Yury Shkoda Date: Tue, 2 May 2023 11:17:12 +0300 Subject: [PATCH 05/13] fix(webout): fixed adding empty webout to response payload --- api/src/controllers/internal/Execution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/controllers/internal/Execution.ts b/api/src/controllers/internal/Execution.ts index 32611bd..3e9f646 100644 --- a/api/src/controllers/internal/Execution.ts +++ b/api/src/controllers/internal/Execution.ts @@ -128,7 +128,7 @@ export class ExecutionController { const resultParts = [] - if (webout) resultParts.push(webout) + if (webout && webout.length !== 0) resultParts.push(webout) resultParts.push(process.logsUUID) resultParts.push(log) From 9f521634d9aec861dc9570f343bae7f561efd7aa Mon Sep 17 00:00:00 2001 From: Yury Shkoda Date: Tue, 2 May 2023 11:30:55 +0300 Subject: [PATCH 06/13] chore(webout): added comment --- api/src/controllers/internal/Execution.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/api/src/controllers/internal/Execution.ts b/api/src/controllers/internal/Execution.ts index 3e9f646..afa310e 100644 --- a/api/src/controllers/internal/Execution.ts +++ b/api/src/controllers/internal/Execution.ts @@ -128,6 +128,7 @@ export class ExecutionController { const resultParts = [] + // INFO: webout can be a Buffer, that is why it's length should be checked to determine if it is empty if (webout && webout.length !== 0) resultParts.push(webout) resultParts.push(process.logsUUID) From bd1b58086d970bd03959426265072f9f1cc813dc Mon Sep 17 00:00:00 2001 From: Yury Shkoda Date: Tue, 2 May 2023 12:10:17 +0300 Subject: [PATCH 07/13] docs: left a comment regarding payload parts --- api/src/controllers/code.ts | 9 ++++++++- web/src/containers/Studio/internal/hooks/useEditor.ts | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/api/src/controllers/code.ts b/api/src/controllers/code.ts index 67973d5..4fe69a3 100644 --- a/api/src/controllers/code.ts +++ b/api/src/controllers/code.ts @@ -28,7 +28,14 @@ interface ExecuteCodePayload { export class CodeController { /** * Execute Code on the Specified Runtime - * @summary Run Code and Return Webout Content and Log + * @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) + * Please see @sasjs/server/api/src/controllers/internal/Execution.ts for more information */ @Post('/execute') public async executeCode( diff --git a/web/src/containers/Studio/internal/hooks/useEditor.ts b/web/src/containers/Studio/internal/hooks/useEditor.ts index 7ff3333..f1e57cb 100644 --- a/web/src/containers/Studio/internal/hooks/useEditor.ts +++ b/web/src/containers/Studio/internal/hooks/useEditor.ts @@ -170,6 +170,7 @@ const useEditor = ({ runTime: selectedRunTime }) .then((res: { data: string }) => { + // INFO: the order of payload parts is set in @sasjs/server/api/src/controllers/internal/Execution.ts const resDataSplitted = res.data.split(SASJS_LOGS_SEPARATOR) const webout = resDataSplitted[0] const log = resDataSplitted[1] From e78f87f5c00038ea11261dffb525ac8f1024e40b Mon Sep 17 00:00:00 2001 From: Yury Shkoda Date: Tue, 2 May 2023 15:18:05 +0300 Subject: [PATCH 08/13] fix(execute): added atribute indicating stp api --- README.md | 2 +- api/src/controllers/internal/Execution.ts | 28 ++++++++++++++--------- api/src/controllers/stp.ts | 13 ++++++----- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 64a210b..14316f8 100644 --- a/README.md +++ b/README.md @@ -158,7 +158,7 @@ CORS= WHITELIST= # HELMET Cross Origin Embedder Policy -# Sets the Cross-Origin-Embedder-Policy header to require-corp when `true` +# Sets the Cross-Origin-Embedder-Policy header to require-corp when `true` # options: [true|false] default: true # Docs: https://helmetjs.github.io/#reference (`crossOriginEmbedderPolicy`) HELMET_COEP= diff --git a/api/src/controllers/internal/Execution.ts b/api/src/controllers/internal/Execution.ts index afa310e..d5fb25b 100644 --- a/api/src/controllers/internal/Execution.ts +++ b/api/src/controllers/internal/Execution.ts @@ -29,6 +29,7 @@ interface ExecuteFileParams { session?: Session runTime: RunTimeType forceStringResult?: boolean + isStp?: boolean } interface ExecuteProgramParams extends Omit { @@ -44,7 +45,8 @@ export class ExecutionController { returnJson, session, runTime, - forceStringResult + forceStringResult, + isStp }: ExecuteFileParams) { const program = await readFile(programPath) @@ -56,7 +58,8 @@ export class ExecutionController { returnJson, session, runTime, - forceStringResult + forceStringResult, + isStp }) } @@ -67,7 +70,8 @@ export class ExecutionController { otherArgs, session: sessionByFileUpload, runTime, - forceStringResult + forceStringResult, + isStp }: ExecuteProgramParams): Promise { const sessionController = getSessionController(runTime) @@ -77,9 +81,7 @@ export class ExecutionController { session.consumed = true const logPath = path.join(session.path, 'log.log') - const printOutputPath = path.join(session.path, 'output.lst') const headersPath = path.join(session.path, 'stpsrv_header.txt') - const weboutPath = path.join(session.path, 'webout.txt') const tokenFile = path.join(session.path, 'reqHeaders.txt') @@ -103,9 +105,6 @@ export class ExecutionController { ) const log = (await fileExists(logPath)) ? await readFile(logPath) : '' - const printOutput = (await fileExists(printOutputPath)) - ? await readFile(printOutputPath) - : '' const headersContent = (await fileExists(headersPath)) ? await readFile(headersPath) : '' @@ -134,9 +133,16 @@ export class ExecutionController { resultParts.push(process.logsUUID) resultParts.push(log) - if (printOutput) { - resultParts.push(process.logsUUID) - resultParts.push(printOutput) + if (!isStp) { + const printOutputPath = path.join(session.path, 'output.lst') + const printOutput = (await fileExists(printOutputPath)) + ? await readFile(printOutputPath) + : '' + + if (printOutput) { + resultParts.push(process.logsUUID) + resultParts.push(printOutput) + } } return { diff --git a/api/src/controllers/stp.ts b/api/src/controllers/stp.ts index b103688..58cfb99 100644 --- a/api/src/controllers/stp.ts +++ b/api/src/controllers/stp.ts @@ -3,8 +3,6 @@ import { Request, Security, Route, Tags, Post, Body, Get, Query } from 'tsoa' import { ExecutionController, ExecutionVars } from './internal' import { getPreProgramVariables, - HTTPHeaders, - LogLine, makeFilesNamesMap, getRunTimeAndFilePath } from '../utils' @@ -39,7 +37,8 @@ export class STPController { @Query() _program: string ): Promise { const vars = request.query as ExecutionVars - return execute(request, _program, vars) + + return execute(request, _program, vars, undefined, true) } /** @@ -67,7 +66,7 @@ export class STPController { : null const otherArgs = { filesNamesMap: filesNamesMap } - return execute(request, program!, vars, otherArgs) + return execute(request, program!, vars, otherArgs, true) } } @@ -75,7 +74,8 @@ const execute = async ( req: express.Request, _program: string, vars: ExecutionVars, - otherArgs?: any + otherArgs?: any, + isStp?: boolean ): Promise => { try { const { codePath, runTime } = await getRunTimeAndFilePath(_program) @@ -87,7 +87,8 @@ const execute = async ( preProgramVariables: getPreProgramVariables(req), vars, otherArgs, - session: req.sasjsSession + session: req.sasjsSession, + isStp } ) From 9aaffce82051d81bf39adb69942bb321e9795141 Mon Sep 17 00:00:00 2001 From: Yury Shkoda Date: Tue, 2 May 2023 15:49:44 +0300 Subject: [PATCH 09/13] fix(execute): fixed adding print output --- api/src/controllers/code.ts | 3 ++- api/src/controllers/internal/Execution.ts | 12 +++++------- api/src/controllers/stp.ts | 6 ++---- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/api/src/controllers/code.ts b/api/src/controllers/code.ts index 4fe69a3..204d359 100644 --- a/api/src/controllers/code.ts +++ b/api/src/controllers/code.ts @@ -62,7 +62,8 @@ const executeCode = async ( preProgramVariables: getPreProgramVariables(req), vars: { ...req.query, _debug: 131 }, otherArgs: { userAutoExec }, - runTime: runTime + runTime: runTime, + addPrintOutput: true }) return result diff --git a/api/src/controllers/internal/Execution.ts b/api/src/controllers/internal/Execution.ts index d5fb25b..5ca80db 100644 --- a/api/src/controllers/internal/Execution.ts +++ b/api/src/controllers/internal/Execution.ts @@ -29,7 +29,7 @@ interface ExecuteFileParams { session?: Session runTime: RunTimeType forceStringResult?: boolean - isStp?: boolean + addPrintOutput?: boolean } interface ExecuteProgramParams extends Omit { @@ -45,8 +45,7 @@ export class ExecutionController { returnJson, session, runTime, - forceStringResult, - isStp + forceStringResult }: ExecuteFileParams) { const program = await readFile(programPath) @@ -58,8 +57,7 @@ export class ExecutionController { returnJson, session, runTime, - forceStringResult, - isStp + forceStringResult }) } @@ -71,7 +69,7 @@ export class ExecutionController { session: sessionByFileUpload, runTime, forceStringResult, - isStp + addPrintOutput }: ExecuteProgramParams): Promise { const sessionController = getSessionController(runTime) @@ -133,7 +131,7 @@ export class ExecutionController { resultParts.push(process.logsUUID) resultParts.push(log) - if (!isStp) { + if (addPrintOutput && runTime === RunTimeType.SAS) { const printOutputPath = path.join(session.path, 'output.lst') const printOutput = (await fileExists(printOutputPath)) ? await readFile(printOutputPath) diff --git a/api/src/controllers/stp.ts b/api/src/controllers/stp.ts index 58cfb99..f839677 100644 --- a/api/src/controllers/stp.ts +++ b/api/src/controllers/stp.ts @@ -74,8 +74,7 @@ const execute = async ( req: express.Request, _program: string, vars: ExecutionVars, - otherArgs?: any, - isStp?: boolean + otherArgs?: any ): Promise => { try { const { codePath, runTime } = await getRunTimeAndFilePath(_program) @@ -87,8 +86,7 @@ const execute = async ( preProgramVariables: getPreProgramVariables(req), vars, otherArgs, - session: req.sasjsSession, - isStp + session: req.sasjsSession } ) From a17814fc90bd7dfffe893c1f3866225167b16b68 Mon Sep 17 00:00:00 2001 From: Yury Shkoda Date: Tue, 2 May 2023 15:53:13 +0300 Subject: [PATCH 10/13] chore(stp): removed redundant argument --- api/src/controllers/stp.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/src/controllers/stp.ts b/api/src/controllers/stp.ts index f839677..a41b31d 100644 --- a/api/src/controllers/stp.ts +++ b/api/src/controllers/stp.ts @@ -38,7 +38,7 @@ export class STPController { ): Promise { const vars = request.query as ExecutionVars - return execute(request, _program, vars, undefined, true) + return execute(request, _program, vars, undefined) } /** @@ -66,7 +66,7 @@ export class STPController { : null const otherArgs = { filesNamesMap: filesNamesMap } - return execute(request, program!, vars, otherArgs, true) + return execute(request, program!, vars, otherArgs) } } From 78ceed13e16a395c93c6e832935302ad5321782c Mon Sep 17 00:00:00 2001 From: Yury Shkoda Date: Tue, 2 May 2023 16:01:00 +0300 Subject: [PATCH 11/13] docs(code): updated execute endpoint info --- api/src/controllers/code.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/controllers/code.ts b/api/src/controllers/code.ts index 204d359..9c94240 100644 --- a/api/src/controllers/code.ts +++ b/api/src/controllers/code.ts @@ -34,7 +34,7 @@ export class CodeController { * 2. Logs UUID (used as separator) * 3. Log * 4. Logs UUID (used as separator) - * 5. Print (if present) + * 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') From 958ab9cad2a0694baca481a0cbce02970ce45953 Mon Sep 17 00:00:00 2001 From: Yury Shkoda Date: Wed, 3 May 2023 10:46:21 +0300 Subject: [PATCH 12/13] chore(execution): add includePrintOutput to ExecuteFileParams --- api/src/controllers/code.ts | 2 +- api/src/controllers/internal/Execution.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/src/controllers/code.ts b/api/src/controllers/code.ts index 9c94240..72fa376 100644 --- a/api/src/controllers/code.ts +++ b/api/src/controllers/code.ts @@ -63,7 +63,7 @@ const executeCode = async ( vars: { ...req.query, _debug: 131 }, otherArgs: { userAutoExec }, runTime: runTime, - addPrintOutput: true + includePrintOutput: true }) return result diff --git a/api/src/controllers/internal/Execution.ts b/api/src/controllers/internal/Execution.ts index 5ca80db..9196014 100644 --- a/api/src/controllers/internal/Execution.ts +++ b/api/src/controllers/internal/Execution.ts @@ -29,11 +29,11 @@ interface ExecuteFileParams { session?: Session runTime: RunTimeType forceStringResult?: boolean - addPrintOutput?: boolean } interface ExecuteProgramParams extends Omit { program: string + includePrintOutput?: boolean } export class ExecutionController { @@ -69,7 +69,7 @@ export class ExecutionController { session: sessionByFileUpload, runTime, forceStringResult, - addPrintOutput + includePrintOutput }: ExecuteProgramParams): Promise { const sessionController = getSessionController(runTime) @@ -131,7 +131,7 @@ export class ExecutionController { resultParts.push(process.logsUUID) resultParts.push(log) - if (addPrintOutput && runTime === RunTimeType.SAS) { + if (includePrintOutput && runTime === RunTimeType.SAS) { const printOutputPath = path.join(session.path, 'output.lst') const printOutput = (await fileExists(printOutputPath)) ? await readFile(printOutputPath) From d458b5bb81917d9f00bc05644d20940d80593085 Mon Sep 17 00:00:00 2001 From: Yury Shkoda Date: Wed, 3 May 2023 10:56:17 +0300 Subject: [PATCH 13/13] chore: cleanup --- api/src/controllers/stp.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/controllers/stp.ts b/api/src/controllers/stp.ts index a41b31d..c78d6ce 100644 --- a/api/src/controllers/stp.ts +++ b/api/src/controllers/stp.ts @@ -38,7 +38,7 @@ export class STPController { ): Promise { const vars = request.query as ExecutionVars - return execute(request, _program, vars, undefined) + return execute(request, _program, vars) } /**