1
0
mirror of https://github.com/sasjs/adapter.git synced 2025-12-10 17:04:36 +00:00
Files
adapter/src/job-execution/Sas9JobExecutor.ts

138 lines
4.1 KiB
TypeScript

import * as https from 'https'
import { ServerType } from '@sasjs/utils/types'
import NodeFormData from 'form-data'
import { ErrorResponse } from '../types/errors'
import { convertToCSV, isRelativePath } from '../utils'
import { BaseJobExecutor } from './JobExecutor'
import { Sas9RequestClient } from '../request/Sas9RequestClient'
import { RequestClient } from '../request/RequestClient'
/**
* Job executor for SAS9 servers for use in Node.js environments.
* Initiates login with the provided username and password from the config
* The cookies are stored in the request client and used in subsequent
* job execution requests.
*/
export class Sas9JobExecutor extends BaseJobExecutor {
private sas9RequestClient: Sas9RequestClient
constructor(
serverUrl: string,
serverType: ServerType,
private jobsPath: string,
private requestClient: RequestClient,
httpsAgentOptions?: https.AgentOptions
) {
super(serverUrl, serverType)
this.sas9RequestClient = new Sas9RequestClient(serverUrl, httpsAgentOptions)
}
async execute(sasJob: string, data: any, config: any) {
const program = isRelativePath(sasJob)
? config.appLoc
? config.appLoc.replace(/\/?$/, '/') + sasJob.replace(/^\//, '')
: sasJob
: sasJob
let apiUrl = `${config.serverUrl}${this.jobsPath}?${'_program=' + program}`
apiUrl = `${apiUrl}${
config.username && config.password
? '&_username=' + config.username + '&_password=' + config.password
: ''
}`
apiUrl = `${apiUrl}${config.debug ? '&_debug=131' : ''}`
let requestParams = {
...this.getRequestParams(config)
}
let formData = new NodeFormData()
if (data) {
try {
formData = generateFileUploadForm(formData, data)
} catch (e: any) {
return Promise.reject(new ErrorResponse(e?.message, e))
}
} else {
data = ''
}
for (const key in requestParams) {
if (requestParams.hasOwnProperty(key)) {
formData.append(key, requestParams[key])
}
}
await this.sas9RequestClient.login(
config.username,
config.password,
this.jobsPath
)
const contentType =
data && Object.keys(data).length
? 'multipart/form-data; boundary=' + (formData as any)._boundary
: 'text/plain'
const requestPromise = new Promise((resolve, reject) =>
this.sas9RequestClient!.post(apiUrl, formData, undefined, contentType, {
Accept: '*/*',
Connection: 'Keep-Alive'
})
.then((res: any) => {
// appending response to requests array that will be used for requests history reference
this.requestClient!.appendRequest(res, sasJob, config.debug)
resolve(res)
})
.catch((err: any) => {
// by default error string is equal to actual error object
let errString = err
// if error object contains non empty result attribute, set result to errString
if (err.result && err.result !== '') errString = err.result
// if there's no result but error message, set error message to errString
else if (err.message) errString = err.message
// appending error to requests array that will be used for requests history reference
this.requestClient!.appendRequest(errString, sasJob, config.debug)
reject(new ErrorResponse(err?.message, err))
})
)
return requestPromise
}
protected getRequestParams(config: any): any {
const requestParams: any = {}
if (config.debug) {
requestParams['_debug'] = 131
}
return requestParams
}
}
const generateFileUploadForm = (
formData: NodeFormData,
data: any
): NodeFormData => {
for (const tableName in data) {
const name = tableName
const csv = convertToCSV(data, tableName)
if (csv === 'ERROR: LARGE STRING LENGTH') {
throw new Error(
'The max length of a string value in SASjs is 32765 characters.'
)
}
formData.append(name, csv, {
filename: `${name}.csv`,
contentType: 'application/csv'
})
}
return formData
}