Skip to content

Commit

Permalink
Merge pull request #261 from sasjs/issue-258
Browse files Browse the repository at this point in the history
fix: update response of /SASjsApi/stp/execute and /SASjsApi/code/execute
  • Loading branch information
sabhas authored Aug 24, 2022
2 parents e94c56b + 98ea2ac commit 65de1bb
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 158 deletions.
28 changes: 10 additions & 18 deletions api/src/controllers/code.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -35,7 +34,7 @@ export class CodeController {
public async executeCode(
@Request() request: express.Request,
@Body() body: ExecuteCodePayload
): Promise<ExecuteReturnJsonResponse> {
): Promise<string | Buffer> {
return executeCode(request, body)
}
}
Expand All @@ -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,
Expand Down
26 changes: 3 additions & 23 deletions api/src/controllers/internal/Execution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -68,10 +62,9 @@ export class ExecutionController {
preProgramVariables,
vars,
otherArgs,
returnJson,
session: sessionByFileUpload,
runTime
}: ExecuteProgramParams): Promise<ExecuteReturnRaw | ExecuteReturnJson> {
}: ExecuteProgramParams): Promise<ExecuteReturnRaw> {
const sessionController = getSessionController(runTime)

const session =
Expand All @@ -89,8 +82,6 @@ export class ExecutionController {
tokenFile,
preProgramVariables?.httpHeaders.join('\n') ?? ''
)
if (returnJson)
await createFile(headersPath, 'Content-type: application/json')

await processProgram(
program,
Expand All @@ -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
Expand All @@ -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
? `<html><body>${webout}<div style="text-align:left"><hr /><h2>SAS Log</h2><pre>${log}</pre></div></body></html>`
? `${webout}\n${process.logsUUID}\n${log}`
: webout
}
}
Expand Down
136 changes: 28 additions & 108 deletions api/src/controllers/stp.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,23 @@
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"
*/
_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')
Expand All @@ -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<string | Buffer> {
return executeReturnRaw(request, _program)
const vars = request.query as ExecutionVars
return execute(request, _program, vars)
}

/**
Expand All @@ -87,50 +60,42 @@ export class STPController {
* @param _program Location of SAS or JS code
* @example _program "/Projects/myApp/some/program"
*/
@Example<ExecuteReturnJsonResponse>({
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<ExecuteReturnJsonResponse> {
): Promise<string | Buffer> {
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<string | Buffer> => {
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
Expand All @@ -146,48 +111,3 @@ const executeReturnRaw = async (
}
}
}

const executeReturnJson = async (
req: express.Request,
_program: string
): Promise<ExecuteReturnJsonResponse> => {
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
}
}
}
4 changes: 2 additions & 2 deletions api/src/routes/api/stp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions api/src/types/system/process.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions api/src/utils/setProcessVariables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
11 changes: 4 additions & 7 deletions web/src/containers/Studio/editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ type SASjsEditorProps = {
}

const baseUrl = window.location.origin
const SASJS_LOGS_SEPARATOR =
'SASJS_LOGS_SEPARATOR_163ee17b6ff24f028928972d80a26784'

const SASjsEditor = ({
selectedFilePath,
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 65de1bb

Please sign in to comment.