From 9cf02b25d03acee9df3052f5b4a4850395ad3823 Mon Sep 17 00:00:00 2001 From: Yury Shkoda Date: Thu, 14 Oct 2021 07:34:08 +0000 Subject: [PATCH] refactor: improve types and imports --- src/controllers/deploy.ts | 1 + src/controllers/executor.ts | 68 --------------- src/controllers/index.ts | 4 +- src/controllers/sas.ts | 107 ------------------------ src/controllers/session.ts | 109 ------------------------- src/types/{sas.ts => Execution.ts} | 0 src/types/{fileTree.ts => FileTree.ts} | 0 src/types/Process.d.ts | 2 +- src/types/{request.ts => Request.ts} | 1 + src/types/Session.ts | 3 +- src/types/index.ts | 6 +- 11 files changed, 10 insertions(+), 291 deletions(-) delete mode 100644 src/controllers/executor.ts delete mode 100644 src/controllers/sas.ts delete mode 100644 src/controllers/session.ts rename src/types/{sas.ts => Execution.ts} (100%) rename src/types/{fileTree.ts => FileTree.ts} (100%) rename src/types/{request.ts => Request.ts} (99%) diff --git a/src/controllers/deploy.ts b/src/controllers/deploy.ts index 3df7c43..2c1f1db 100644 --- a/src/controllers/deploy.ts +++ b/src/controllers/deploy.ts @@ -3,6 +3,7 @@ import { getTmpFilesFolderPath } from '../utils/file' import { createFolder, createFile, asyncForEach } from '@sasjs/utils' import path from 'path' +// REFACTOR: export FileTreeCpntroller export const createFileTree = async ( members: [FolderMember, ServiceMember], parentFolders: string[] = [] diff --git a/src/controllers/executor.ts b/src/controllers/executor.ts deleted file mode 100644 index db00297..0000000 --- a/src/controllers/executor.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { getSessionController } from './session' -import { readFile, deleteFile, fileExists, createFile } from '@sasjs/utils' -import path from 'path' -import { configuration } from '../../package.json' -import { promisify } from 'util' -import { execFile } from 'child_process' -const execFilePromise = promisify(execFile) - -export class ExecutionController { - async execute(program = '', autoExec?: string, debug?: number) { - console.log(`[ExecutionController]program: `, program) - console.log(`[ExecutionController]autoExec: `, autoExec) - - if (program) { - if (!(await fileExists(program))) { - throw 'SASjsServer/Executor: SAS file does not exist.' - } - - program = await readFile(program) - } - - const sessionController = getSessionController() - const session = await sessionController.getSession() - - console.log(`[ExecutionController]session: `, session) - - let log = path.join(session.path, 'log.log') - await createFile(log, '') - - let webout = path.join(session.path, 'webout.txt') - await createFile(webout, '') - - const code = path.join(session.path, 'code') - await createFile(code, program) - - let additionalArgs: string[] = [] - if (autoExec) additionalArgs = ['-AUTOEXEC', autoExec] - - const { stdout, stderr } = await execFilePromise(configuration.sasPath, [ - '-SYSIN', - code, - '-LOG', - log, - '-WORK', - ...additionalArgs, - session.path, - process.platform === 'win32' ? '-nosplash' : '' - ]).catch((err) => ({ stderr: err, stdout: '' })) - - log = await readFile(log) - - if (stderr) return Promise.reject({ error: stderr, log: log }) - - webout = await readFile(webout) - - if (debug && debug >= 131) { - webout = ` -${webout} -
-

SAS Log

-
${log}
-
-` - } - - return Promise.resolve(webout) - } -} diff --git a/src/controllers/index.ts b/src/controllers/index.ts index 4df137d..2990104 100644 --- a/src/controllers/index.ts +++ b/src/controllers/index.ts @@ -1,3 +1,3 @@ -export * from './sas' export * from './deploy' -export * from './session' +export * from './Session' +export * from './Execution' diff --git a/src/controllers/sas.ts b/src/controllers/sas.ts deleted file mode 100644 index e30e382..0000000 --- a/src/controllers/sas.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { readFile, deleteFile, fileExists, createFile } from '@sasjs/utils' -import path from 'path' -import { ExecutionResult, ExecutionQuery } from '../types' -import { - getTmpFilesFolderPath, - getTmpLogFolderPath, - getTmpWeboutFolderPath, - generateUniqueFileName -} from '../utils' -import { configuration } from '../../package.json' -import { SessionController } from './session' -import { promisify } from 'util' -import { execFile } from 'child_process' -const execFilePromise = promisify(execFile) - -export const processSas = async (query: ExecutionQuery): Promise => { - const sasCodePath = path - .join(getTmpFilesFolderPath(), query._program) - .replace(new RegExp('/', 'g'), path.sep) - - if (!(await fileExists(sasCodePath))) { - return Promise.reject({ error: 'SAS file does not exist.' }) - } - - // FIXME - const sessionController = new SessionController() - - sessionController.getSession() - - return Promise.resolve('success') - - // const sasFile: string = sasCodePath.split(path.sep).pop() || 'default' - - // const sasLogPath = path.join( - // getTmpLogFolderPath(), - // generateUniqueFileName(sasFile.replace(/\.sas/g, ''), '.log') - // ) - - // await createFile(sasLogPath, '') - - // const sasWeboutPath = path.join( - // getTmpWeboutFolderPath(), - // generateUniqueFileName(sasFile.replace(/\.sas/g, ''), '.txt') - // ) - - // await createFile(sasWeboutPath, '') - - // let sasCode = await readFile(sasCodePath) - - // const vars: any = query - // Object.keys(query).forEach( - // (key: string) => (sasCode = `%let ${key}=${vars[key]};\n${sasCode}`) - // ) - - // sasCode = `filename _webout "${sasWeboutPath}";\n${sasCode}` - - // const tmpSasCodePath = sasCodePath.replace( - // sasFile, - // generateUniqueFileName(sasFile) - // ) - - // await createFile(tmpSasCodePath, sasCode) - - // const { stdout, stderr } = await execFilePromise(configuration.sasPath, [ - // '-SYSIN', - // tmpSasCodePath, - // '-log', - // sasLogPath, - // process.platform === 'win32' ? '-nosplash' : '' - // ]).catch((err) => ({ stderr: err, stdout: '' })) - - // let log = '' - // if (sasLogPath && (await fileExists(sasLogPath))) { - // log = await readFile(sasLogPath) - // } - - // await deleteFile(sasLogPath) - // await deleteFile(tmpSasCodePath) - - // if (stderr) return Promise.reject({ error: stderr, log: log }) - - // if (await fileExists(sasWeboutPath)) { - // let webout = await readFile(sasWeboutPath) - - // await deleteFile(sasWeboutPath) - - // const debug = Object.keys(query).find( - // (key: string) => key.toLowerCase() === '_debug' - // ) - - // if (debug && (query as any)[debug] >= 131) { - // webout = ` - // ${webout} - //
- //

SAS Log

- //
${log}
- //
- // ` - // } - - // return Promise.resolve(webout) - // } else { - // return Promise.resolve({ - // log: log - // }) - // } -} diff --git a/src/controllers/session.ts b/src/controllers/session.ts deleted file mode 100644 index 0b17c73..0000000 --- a/src/controllers/session.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { Session } from '../types' -import { getTmpSessionsFolderPath, generateUniqueFileName } from '../utils' -import { createFolder, createFile, generateTimestamp } from '@sasjs/utils' -import path from 'path' -import { ExecutionController } from './executor' - -// /opt/sas/sas9/SASHome/SASFoundation/9.4/sasexe/sas -// -LOG /tmp/mydir/demo.log -// -SYSIN /tmp/mydir/code.sas -// -AUTOEXEC /tmp/mydir/autoexec.sas -// -WORK /tmp/mydir - -// 1. req (_program) for execution -// 2. check available session -// 2.3 spawn one more session -// 2.3.1 create folder -// 2.3.2 create autoexec -// 2.3.3 create _program.sas (empty) -// 2.3.4 /opt/sas/sas9/SASHome/SASFoundation/9.4/sasexe/sas -LOG /tmp/sessionFolder/demo.log -SYSIN /tmp/sessionFolder/_program.sas -AUTOEXEC /tmp/sessionFolder/autoexec.sas -WORK /tmp/sessionFolder -// 2.3.5 wait for _program.sas to be deleted -// 2.3.6 add session to the session array -// --- -// 3.0 wait for session -// 3.1 create _program.sas in sessionFolder -// 3.2 poll session array - -export class SessionController { - private sessions: Session[] = [] - private executionController: ExecutionController - - constructor() { - this.executionController = new ExecutionController() - } - - public async getSession() { - if (this.sessions.length) { - const session: Session = this.sessions[0] - - // TODO: check if session is not expired - - return session - } - - return await this.createSession() - } - - private async createSession() { - if (!this.sessions.length) { - const sessionId = generateUniqueFileName(generateTimestamp()) - - const sessionFolder = path.join( - await getTmpSessionsFolderPath(), - sessionId - ) - - const autoExecContent = `data _null_; - /* remove the dummy SYSIN */ - length fname $8; - rc=filename(fname,getoption('SYSIN') ); - if rc = 0 and fexist(fname) then rc=fdelete(fname); - rc=filename(fname); - /* now wait for the real SYSIN */ - slept=0; - do until ( fileexist(getoption('SYSIN')) or slept>(60*15) ); - slept=slept+sleep(0.1,1); - end; -run; -EOL` - - const autoExec = path.join(sessionFolder, 'autoexec.sas') - - await createFile(autoExec, autoExecContent) - - console.log(`[SessionController about to create first session]`) - - this.executionController.execute('', autoExec) - - const creationTimeStamp = sessionId.split('-').pop() as string - - const session: Session = { - id: sessionId, - available: true, - creationTimeStamp: creationTimeStamp, - deathTimeStamp: ( - parseInt(creationTimeStamp) + - 15 * 60 * 1000 - - 1000 - ).toString(), - path: sessionFolder - } - - console.log(`[SessionController]session: `, session) - - this.sessions.push(session) - - return session - } else { - return this.sessions[0] - } - } -} - -export const getSessionController = () => { - if (process.sessionController) return process.sessionController - - process.sessionController = new SessionController() - - return process.sessionController -} diff --git a/src/types/sas.ts b/src/types/Execution.ts similarity index 100% rename from src/types/sas.ts rename to src/types/Execution.ts diff --git a/src/types/fileTree.ts b/src/types/FileTree.ts similarity index 100% rename from src/types/fileTree.ts rename to src/types/FileTree.ts diff --git a/src/types/Process.d.ts b/src/types/Process.d.ts index 501fd16..50313f7 100644 --- a/src/types/Process.d.ts +++ b/src/types/Process.d.ts @@ -1,5 +1,5 @@ declare namespace NodeJS { export interface Process { - sessionController?: import('../controllers/session').SessionController + sessionController?: import('../controllers/Session').SessionController } } diff --git a/src/types/request.ts b/src/types/Request.ts similarity index 99% rename from src/types/request.ts rename to src/types/Request.ts index 26c872f..6bc7e2b 100644 --- a/src/types/request.ts +++ b/src/types/Request.ts @@ -1,4 +1,5 @@ import { MacroVars } from '@sasjs/utils' + export interface ExecutionQuery { _program: string macroVars?: MacroVars diff --git a/src/types/Session.ts b/src/types/Session.ts index 9066363..5484311 100644 --- a/src/types/Session.ts +++ b/src/types/Session.ts @@ -1,7 +1,8 @@ export interface Session { id: string - available: boolean + ready: boolean creationTimeStamp: string deathTimeStamp: string path: string + inUse: boolean } diff --git a/src/types/index.ts b/src/types/index.ts index 1c326b2..2377b59 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,5 +1,5 @@ // TODO: uppercase types -export * from './sas' -export * from './request' -export * from './fileTree' +export * from './Execution' +export * from './Request' +export * from './FileTree' export * from './Session'