diff --git a/api/package-lock.json b/api/package-lock.json index c047631..ecbd640 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@sasjs/utils": "^2.33.1", "bcryptjs": "^2.4.3", + "cors": "^2.8.5", "express": "^4.17.1", "joi": "^17.4.2", "jsonwebtoken": "^8.5.1", @@ -3904,6 +3905,18 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/cosmiconfig": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", @@ -18036,6 +18049,15 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, "cosmiconfig": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", diff --git a/api/package.json b/api/package.json index 6c00d35..e60b350 100644 --- a/api/package.json +++ b/api/package.json @@ -43,6 +43,7 @@ "dependencies": { "@sasjs/utils": "^2.33.1", "bcryptjs": "^2.4.3", + "cors": "^2.8.5", "express": "^4.17.1", "joi": "^17.4.2", "jsonwebtoken": "^8.5.1", diff --git a/api/public/swagger.yaml b/api/public/swagger.yaml index 3d814f4..c4d4018 100644 --- a/api/public/swagger.yaml +++ b/api/public/swagger.yaml @@ -981,7 +981,7 @@ paths: application/json: schema: type: string - description: "Trigger a SAS program using it's location in the _program parameter.\nEnable debugging using the _debug parameter.\nAdditional URL parameters are turned into SAS macro variables.\nAny files provided are placed into the session and\ncorresponding _WEBIN_XXX variables are created." + description: "Trigger a SAS program using it's location in the _program parameter.\r\nEnable debugging using the _debug parameter.\r\nAdditional URL parameters are turned into SAS macro variables.\r\nAny files provided are placed into the session and\r\ncorresponding _WEBIN_XXX variables are created." summary: 'Execute Stored Program, return raw content' tags: - STP @@ -1005,7 +1005,7 @@ paths: application/json: schema: $ref: '#/components/schemas/ExecuteReturnJsonResponse' - description: "Trigger a SAS program using it's location in the _program parameter.\nEnable debugging using the _debug parameter.\nAdditional URL parameters are turned into SAS macro variables.\nAny files provided are placed into the session and\ncorresponding _WEBIN_XXX variables are created." + description: "Trigger a SAS program using it's location in the _program parameter.\r\nEnable debugging using the _debug parameter.\r\nAdditional URL parameters are turned into SAS macro variables.\r\nAny files provided are placed into the session and\r\ncorresponding _WEBIN_XXX variables are created." summary: 'Execute Stored Program, return JSON' tags: - STP diff --git a/api/src/app.ts b/api/src/app.ts index 0874ad0..f4c4b01 100644 --- a/api/src/app.ts +++ b/api/src/app.ts @@ -2,7 +2,6 @@ import path from 'path' import express from 'express' import morgan from 'morgan' import dotenv from 'dotenv' - import webRouter from './routes/web' import apiRouter from './routes/api' import { getWebBuildFolderPath } from './utils' @@ -10,6 +9,9 @@ import { connectDB } from './routes/api/auth' const app = express() +const cors=require('cors') +app.use(cors()) + app.use(express.json({ limit: '50mb' })) app.use(morgan('tiny')) app.use(express.static(path.join(__dirname, '../public'))) diff --git a/api/src/controllers/internal/Execution.ts b/api/src/controllers/internal/Execution.ts index 2aaf4de..1f1d6f3 100644 --- a/api/src/controllers/internal/Execution.ts +++ b/api/src/controllers/internal/Execution.ts @@ -2,13 +2,10 @@ import path from 'path' import fs from 'fs' import { getSessionController } from './' import { readFile, fileExists, createFile } from '@sasjs/utils' -import { configuration } from '../../../package.json' -import { promisify } from 'util' -import { execFile } from 'child_process' import { PreProgramVars, Session, TreeNode } from '../../types' import { generateFileUploadSasCode, getTmpFilesFolderPath } from '../../utils' - -const execFilePromise = promisify(execFile) +export const delay = (ms: number) => +new Promise((resolve) => setTimeout(resolve, ms)) export class ExecutionController { async execute( @@ -76,25 +73,25 @@ ${program}` } } - const code = path.join(session.path, 'code.sas') - if (!(await fileExists(code))) { - await createFile(code, program) + const codePath = path.join(session.path, 'code.sas') + + // Creating this file in a RUNNING session will break out + // the autoexec loop and actually execute the program + // but - given it will take several milliseconds to create + // (which can mean SAS trying to run a partial program, or + // failing due to file lock) we first create the file THEN + // we rename it. + await createFile(codePath + '.bkp', program) + fs.renameSync(codePath + '.bkp',codePath) + + // we now need to poll the session array + while ( + !session.completed + ) { + await delay(50) } - let additionalArgs: string[] = [] - if (autoExec) additionalArgs = ['-AUTOEXEC', autoExec] - const sasLoc = process.sasLoc ?? configuration.sasPath - const { stdout, stderr } = await execFilePromise(sasLoc, [ - '-SYSIN', - code, - '-LOG', - log, - '-WORK', - session.path, - ...additionalArgs, - process.platform === 'win32' ? '-nosplash' : '' - ]).catch((err) => ({ stderr: err, stdout: '' })) if (await fileExists(log)) log = await readFile(log) else log = '' @@ -107,7 +104,7 @@ ${program}` ) let jsonResult - if ((debug && vars[debug] >= 131) || stderr) { + if ((debug && vars[debug] >= 131)) { webout = `
${webout}