mirror of
https://github.com/sasjs/adapter.git
synced 2026-01-07 20:40:05 +00:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2cffc57209 | ||
|
|
4e43687de2 | ||
|
|
f8dab83e37 | ||
|
|
655af03cf3 | ||
|
|
0a4dd00edb | ||
|
|
55b4929c54 | ||
|
|
8eb73a6b3c | ||
|
|
0aeb201625 | ||
|
|
e0140a23c2 | ||
|
|
ff6698a9d1 | ||
|
|
843d498b72 | ||
|
|
349612a065 | ||
|
|
e48b22128d | ||
|
|
14dfe4ec51 | ||
|
|
f679b17cbe | ||
|
|
36a0f0e743 | ||
|
|
ad563b9bc8 | ||
|
|
e0051bf276 | ||
|
|
7b72998e1c | ||
|
|
893cce7f21 | ||
|
|
bf7e8fd0e6 | ||
|
|
66d02cf1d1 | ||
|
|
f2c8e40430 | ||
|
|
4b28ee8e73 | ||
|
|
c7e54cfe9f |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -3,4 +3,6 @@ build
|
|||||||
|
|
||||||
.env
|
.env
|
||||||
|
|
||||||
/coverage
|
/coverage
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -21,6 +21,7 @@ import { isAuthorizeFormRequired } from './auth/isAuthorizeFormRequired'
|
|||||||
import { RequestClient } from './request/RequestClient'
|
import { RequestClient } from './request/RequestClient'
|
||||||
import { NotFoundError } from './types/NotFoundError'
|
import { NotFoundError } from './types/NotFoundError'
|
||||||
import { SasAuthResponse } from '@sasjs/utils/types'
|
import { SasAuthResponse } from '@sasjs/utils/types'
|
||||||
|
import { prefixMessage } from '@sasjs/utils/error'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A client for interfacing with the SAS Viya REST API.
|
* A client for interfacing with the SAS Viya REST API.
|
||||||
@@ -280,25 +281,24 @@ export class SASViyaApiClient {
|
|||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
}
|
}
|
||||||
|
|
||||||
if (accessToken) {
|
if (accessToken) headers.Authorization = `Bearer ${accessToken}`
|
||||||
headers.Authorization = `Bearer ${accessToken}`
|
|
||||||
}
|
|
||||||
|
|
||||||
let executionSessionId: string
|
let executionSessionId: string
|
||||||
|
|
||||||
const session = await this.sessionManager
|
const session = await this.sessionManager
|
||||||
.getSession(accessToken)
|
.getSession(accessToken)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
throw err
|
throw prefixMessage(err, 'Error while getting session. ')
|
||||||
})
|
})
|
||||||
|
|
||||||
executionSessionId = session!.id
|
executionSessionId = session!.id
|
||||||
|
|
||||||
if (printPid) {
|
if (printPid) {
|
||||||
const { result: jobIdVariable } = await this.sessionManager.getVariable(
|
const { result: jobIdVariable } = await this.sessionManager
|
||||||
executionSessionId,
|
.getVariable(executionSessionId, 'SYSJOBID', accessToken)
|
||||||
'SYSJOBID',
|
.catch((err) => {
|
||||||
accessToken
|
throw prefixMessage(err, 'Error while getting session variable. ')
|
||||||
)
|
})
|
||||||
|
|
||||||
if (jobIdVariable && jobIdVariable.value) {
|
if (jobIdVariable && jobIdVariable.value) {
|
||||||
const relativeJobPath = this.rootFolderName
|
const relativeJobPath = this.rootFolderName
|
||||||
@@ -331,6 +331,7 @@ export class SASViyaApiClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let fileName
|
let fileName
|
||||||
|
|
||||||
if (isRelativePath(jobPath)) {
|
if (isRelativePath(jobPath)) {
|
||||||
fileName = `exec-${
|
fileName = `exec-${
|
||||||
jobPath.includes('/') ? jobPath.split('/')[1] : jobPath
|
jobPath.includes('/') ? jobPath.split('/')[1] : jobPath
|
||||||
@@ -352,7 +353,7 @@ export class SASViyaApiClient {
|
|||||||
if (data) {
|
if (data) {
|
||||||
if (JSON.stringify(data).includes(';')) {
|
if (JSON.stringify(data).includes(';')) {
|
||||||
files = await this.uploadTables(data, accessToken).catch((err) => {
|
files = await this.uploadTables(data, accessToken).catch((err) => {
|
||||||
throw err
|
throw prefixMessage(err, 'Error while uploading tables. ')
|
||||||
})
|
})
|
||||||
|
|
||||||
jobVariables['_webin_file_count'] = files.length
|
jobVariables['_webin_file_count'] = files.length
|
||||||
@@ -376,19 +377,18 @@ export class SASViyaApiClient {
|
|||||||
variables: jobVariables,
|
variables: jobVariables,
|
||||||
arguments: jobArguments
|
arguments: jobArguments
|
||||||
}
|
}
|
||||||
|
|
||||||
const { result: postedJob, etag } = await this.requestClient
|
const { result: postedJob, etag } = await this.requestClient
|
||||||
.post<Job>(
|
.post<Job>(
|
||||||
`/compute/sessions/${executionSessionId}/jobs`,
|
`/compute/sessions/${executionSessionId}/jobs`,
|
||||||
jobRequestBody,
|
jobRequestBody,
|
||||||
accessToken
|
accessToken
|
||||||
)
|
)
|
||||||
.catch((err: any) => {
|
.catch((err) => {
|
||||||
throw err
|
throw prefixMessage(err, 'Error while posting job. ')
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!waitForResult) {
|
if (!waitForResult) return session
|
||||||
return session
|
|
||||||
}
|
|
||||||
|
|
||||||
if (debug) {
|
if (debug) {
|
||||||
console.log(`Job has been submitted for '${fileName}'.`)
|
console.log(`Job has been submitted for '${fileName}'.`)
|
||||||
@@ -404,7 +404,9 @@ export class SASViyaApiClient {
|
|||||||
etag,
|
etag,
|
||||||
accessToken,
|
accessToken,
|
||||||
pollOptions
|
pollOptions
|
||||||
)
|
).catch((err) => {
|
||||||
|
throw prefixMessage(err, 'Error while polling job status. ')
|
||||||
|
})
|
||||||
|
|
||||||
const { result: currentJob } = await this.requestClient
|
const { result: currentJob } = await this.requestClient
|
||||||
.get<Job>(
|
.get<Job>(
|
||||||
@@ -412,7 +414,7 @@ export class SASViyaApiClient {
|
|||||||
accessToken
|
accessToken
|
||||||
)
|
)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
throw err
|
throw prefixMessage(err, 'Error while getting job. ')
|
||||||
})
|
})
|
||||||
|
|
||||||
let jobResult
|
let jobResult
|
||||||
@@ -427,7 +429,7 @@ export class SASViyaApiClient {
|
|||||||
res.result.items.map((i: any) => i.line).join('\n')
|
res.result.items.map((i: any) => i.line).join('\n')
|
||||||
)
|
)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
throw err
|
throw prefixMessage(err, 'Error while getting log. ')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -455,7 +457,7 @@ export class SASViyaApiClient {
|
|||||||
res.result.items.map((i: any) => i.line).join('\n')
|
res.result.items.map((i: any) => i.line).join('\n')
|
||||||
)
|
)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
throw err
|
throw prefixMessage(err, 'Error while getting log. ')
|
||||||
})
|
})
|
||||||
|
|
||||||
return Promise.reject({
|
return Promise.reject({
|
||||||
@@ -464,6 +466,7 @@ export class SASViyaApiClient {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
result: JSON.stringify(e)
|
result: JSON.stringify(e)
|
||||||
}
|
}
|
||||||
@@ -473,7 +476,7 @@ export class SASViyaApiClient {
|
|||||||
await this.sessionManager
|
await this.sessionManager
|
||||||
.clearSession(executionSessionId, accessToken)
|
.clearSession(executionSessionId, accessToken)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
throw err
|
throw prefixMessage(err, 'Error while clearing session. ')
|
||||||
})
|
})
|
||||||
|
|
||||||
return { result: jobResult?.result, log }
|
return { result: jobResult?.result, log }
|
||||||
@@ -490,7 +493,7 @@ export class SASViyaApiClient {
|
|||||||
true
|
true
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
throw e
|
throw prefixMessage(e, 'Error while executing script. ')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -814,9 +817,12 @@ export class SASViyaApiClient {
|
|||||||
? `${this.rootFolderName}/${folderPath}`
|
? `${this.rootFolderName}/${folderPath}`
|
||||||
: folderPath
|
: folderPath
|
||||||
|
|
||||||
await this.populateFolderMap(fullFolderPath, accessToken)
|
await this.populateFolderMap(fullFolderPath, accessToken).catch((err) => {
|
||||||
|
throw prefixMessage(err, 'Error while populating folder map. ')
|
||||||
|
})
|
||||||
|
|
||||||
const jobFolder = this.folderMap.get(fullFolderPath)
|
const jobFolder = this.folderMap.get(fullFolderPath)
|
||||||
|
|
||||||
if (!jobFolder) {
|
if (!jobFolder) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`The folder '${fullFolderPath}' was not found on '${this.serverUrl}'`
|
`The folder '${fullFolderPath}' was not found on '${this.serverUrl}'`
|
||||||
@@ -824,6 +830,7 @@ export class SASViyaApiClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const headers: any = { 'Content-Type': 'application/json' }
|
const headers: any = { 'Content-Type': 'application/json' }
|
||||||
|
|
||||||
if (!!accessToken) {
|
if (!!accessToken) {
|
||||||
headers.Authorization = `Bearer ${accessToken}`
|
headers.Authorization = `Bearer ${accessToken}`
|
||||||
}
|
}
|
||||||
@@ -847,10 +854,14 @@ export class SASViyaApiClient {
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
result: jobDefinition
|
result: jobDefinition
|
||||||
} = await this.requestClient.get<JobDefinition>(
|
} = await this.requestClient
|
||||||
`${this.serverUrl}${jobDefinitionLink.href}`,
|
.get<JobDefinition>(
|
||||||
accessToken
|
`${this.serverUrl}${jobDefinitionLink.href}`,
|
||||||
)
|
accessToken
|
||||||
|
)
|
||||||
|
.catch((err) => {
|
||||||
|
throw prefixMessage(err, 'Error while getting job definition. ')
|
||||||
|
})
|
||||||
|
|
||||||
code = jobDefinition.code
|
code = jobDefinition.code
|
||||||
|
|
||||||
@@ -861,6 +872,7 @@ export class SASViyaApiClient {
|
|||||||
if (!code) code = ''
|
if (!code) code = ''
|
||||||
|
|
||||||
const linesToExecute = code.replace(/\r\n/g, '\n').split('\n')
|
const linesToExecute = code.replace(/\r\n/g, '\n').split('\n')
|
||||||
|
|
||||||
return await this.executeScript(
|
return await this.executeScript(
|
||||||
sasJob,
|
sasJob,
|
||||||
linesToExecute,
|
linesToExecute,
|
||||||
@@ -1007,19 +1019,27 @@ export class SASViyaApiClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const url = '/folders/folders/@item?path=' + path
|
const url = '/folders/folders/@item?path=' + path
|
||||||
const { result: folder } = await this.requestClient.get<Folder>(
|
const { result: folder } = await this.requestClient
|
||||||
`${url}`,
|
.get<Folder>(`${url}`, accessToken)
|
||||||
accessToken
|
.catch((err) => {
|
||||||
)
|
throw prefixMessage(err, 'Error while getting folder. ')
|
||||||
|
})
|
||||||
|
|
||||||
if (!folder) {
|
if (!folder) {
|
||||||
throw new Error(`The path ${path} does not exist on ${this.serverUrl}`)
|
throw new Error(`The path ${path} does not exist on ${this.serverUrl}`)
|
||||||
}
|
}
|
||||||
const { result: members } = await this.requestClient.get<{ items: any[] }>(
|
|
||||||
`/folders/folders/${folder.id}/members?limit=${folder.memberCount}`,
|
const { result: members } = await this.requestClient
|
||||||
accessToken
|
.get<{ items: any[] }>(
|
||||||
)
|
`/folders/folders/${folder.id}/members?limit=${folder.memberCount}`,
|
||||||
|
accessToken
|
||||||
|
)
|
||||||
|
.catch((err) => {
|
||||||
|
throw prefixMessage(err, 'Error while getting members. ')
|
||||||
|
})
|
||||||
|
|
||||||
const itemsAtRoot = members.items
|
const itemsAtRoot = members.items
|
||||||
|
|
||||||
this.folderMap.set(path, itemsAtRoot)
|
this.folderMap.set(path, itemsAtRoot)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1052,11 +1072,15 @@ export class SASViyaApiClient {
|
|||||||
Promise.reject(`Job state link was not found.`)
|
Promise.reject(`Job state link was not found.`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const { result: state } = await this.requestClient.get<string>(
|
const { result: state } = await this.requestClient
|
||||||
`${this.serverUrl}${stateLink.href}?_action=wait&wait=30`,
|
.get<string>(
|
||||||
accessToken,
|
`${this.serverUrl}${stateLink.href}?_action=wait&wait=30`,
|
||||||
'text/plain'
|
accessToken,
|
||||||
)
|
'text/plain'
|
||||||
|
)
|
||||||
|
.catch((err) => {
|
||||||
|
throw prefixMessage(err, 'Error while getting job state. ')
|
||||||
|
})
|
||||||
|
|
||||||
const currentState = state.trim()
|
const currentState = state.trim()
|
||||||
if (currentState === 'completed') {
|
if (currentState === 'completed') {
|
||||||
@@ -1073,11 +1097,15 @@ export class SASViyaApiClient {
|
|||||||
postedJobState === 'pending'
|
postedJobState === 'pending'
|
||||||
) {
|
) {
|
||||||
if (stateLink) {
|
if (stateLink) {
|
||||||
const { result: jobState } = await this.requestClient.get<string>(
|
const { result: jobState } = await this.requestClient
|
||||||
`${this.serverUrl}${stateLink.href}?_action=wait&wait=30`,
|
.get<string>(
|
||||||
accessToken,
|
`${this.serverUrl}${stateLink.href}?_action=wait&wait=30`,
|
||||||
'text/plain'
|
accessToken,
|
||||||
)
|
'text/plain'
|
||||||
|
)
|
||||||
|
.catch((err) => {
|
||||||
|
throw prefixMessage(err, 'Error while getting job state. ')
|
||||||
|
})
|
||||||
|
|
||||||
postedJobState = jobState.trim()
|
postedJobState = jobState.trim()
|
||||||
|
|
||||||
@@ -1119,11 +1147,11 @@ export class SASViyaApiClient {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const uploadResponse = await this.requestClient.uploadFile(
|
const uploadResponse = await this.requestClient
|
||||||
`${this.serverUrl}/files/files#rawUpload`,
|
.uploadFile(`${this.serverUrl}/files/files#rawUpload`, csv, accessToken)
|
||||||
csv,
|
.catch((err) => {
|
||||||
accessToken
|
throw prefixMessage(err, 'Error while uploading file. ')
|
||||||
)
|
})
|
||||||
|
|
||||||
uploadedFiles.push({ tableName, file: uploadResponse.result })
|
uploadedFiles.push({ tableName, file: uploadResponse.result })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ export class SessionManager {
|
|||||||
this.sessions = this.sessions.filter((s) => s.id !== id)
|
this.sessions = this.sessions.filter((s) => s.id !== id)
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
throw err
|
throw prefixMessage(err, 'Error while deleting session. ')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,35 +20,52 @@ export class ComputeJobExecutor extends BaseJobExecutor {
|
|||||||
const waitForResult = true
|
const waitForResult = true
|
||||||
const expectWebout = true
|
const expectWebout = true
|
||||||
|
|
||||||
return this.sasViyaApiClient
|
const requestPromise = new Promise((resolve, reject) => {
|
||||||
?.executeComputeJob(
|
this.sasViyaApiClient
|
||||||
sasJob,
|
?.executeComputeJob(
|
||||||
config.contextName,
|
sasJob,
|
||||||
config.debug,
|
config.contextName,
|
||||||
data,
|
config.debug,
|
||||||
accessToken,
|
data,
|
||||||
waitForResult,
|
accessToken,
|
||||||
expectWebout
|
waitForResult,
|
||||||
)
|
expectWebout
|
||||||
.then((response) => {
|
)
|
||||||
this.appendRequest(response, sasJob, config.debug)
|
.then((response) => {
|
||||||
let responseJson
|
this.appendRequest(response, sasJob, config.debug)
|
||||||
|
|
||||||
return response.result
|
resolve(response.result)
|
||||||
|
})
|
||||||
|
.catch(async (e: Error) => {
|
||||||
|
if (e instanceof ComputeJobExecutionError) {
|
||||||
|
this.appendRequest(e, sasJob, config.debug)
|
||||||
|
|
||||||
return responseJson
|
reject(new ErrorResponse(e?.message, e))
|
||||||
})
|
}
|
||||||
.catch(async (e: Error) => {
|
|
||||||
if (e instanceof ComputeJobExecutionError) {
|
if (e instanceof LoginRequiredError) {
|
||||||
this.appendRequest(e, sasJob, config.debug)
|
await loginCallback()
|
||||||
}
|
this.appendWaitingRequest(() => {
|
||||||
if (e instanceof LoginRequiredError) {
|
return this.execute(
|
||||||
await loginCallback()
|
sasJob,
|
||||||
this.appendWaitingRequest(() =>
|
data,
|
||||||
this.execute(sasJob, data, config, loginRequiredCallback)
|
config,
|
||||||
)
|
loginRequiredCallback
|
||||||
}
|
).then(
|
||||||
return Promise.reject(new ErrorResponse(e?.message, e))
|
(res: any) => {
|
||||||
})
|
resolve(res)
|
||||||
|
},
|
||||||
|
(err: any) => {
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
reject(new ErrorResponse(e?.message, e))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return requestPromise
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,24 +17,52 @@ export class JesJobExecutor extends BaseJobExecutor {
|
|||||||
accessToken?: string
|
accessToken?: string
|
||||||
) {
|
) {
|
||||||
const loginCallback = loginRequiredCallback || (() => Promise.resolve())
|
const loginCallback = loginRequiredCallback || (() => Promise.resolve())
|
||||||
return await this.sasViyaApiClient
|
|
||||||
?.executeJob(sasJob, config.contextName, config.debug, data, accessToken)
|
|
||||||
.then((response) => {
|
|
||||||
this.appendRequest(response, sasJob, config.debug)
|
|
||||||
|
|
||||||
return response.result
|
const requestPromise = new Promise((resolve, reject) => {
|
||||||
})
|
this.sasViyaApiClient
|
||||||
.catch(async (e: Error) => {
|
?.executeJob(
|
||||||
if (e instanceof JobExecutionError) {
|
sasJob,
|
||||||
this.appendRequest(e, sasJob, config.debug)
|
config.contextName,
|
||||||
}
|
config.debug,
|
||||||
if (e instanceof LoginRequiredError) {
|
data,
|
||||||
await loginCallback()
|
accessToken
|
||||||
this.appendWaitingRequest(() =>
|
)
|
||||||
this.execute(sasJob, data, config, loginRequiredCallback)
|
.then((response) => {
|
||||||
)
|
this.appendRequest(response, sasJob, config.debug)
|
||||||
}
|
|
||||||
return Promise.reject(new ErrorResponse(e?.message, e))
|
resolve(response.result)
|
||||||
})
|
})
|
||||||
|
.catch(async (e: Error) => {
|
||||||
|
if (e instanceof JobExecutionError) {
|
||||||
|
this.appendRequest(e, sasJob, config.debug)
|
||||||
|
|
||||||
|
reject(new ErrorResponse(e?.message, e))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e instanceof LoginRequiredError) {
|
||||||
|
await loginCallback()
|
||||||
|
|
||||||
|
this.appendWaitingRequest(() => {
|
||||||
|
return this.execute(
|
||||||
|
sasJob,
|
||||||
|
data,
|
||||||
|
config,
|
||||||
|
loginRequiredCallback
|
||||||
|
).then(
|
||||||
|
(res: any) => {
|
||||||
|
resolve(res)
|
||||||
|
},
|
||||||
|
(err: any) => {
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
reject(new ErrorResponse(e?.message, e))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return requestPromise
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,11 @@ import { SASViyaApiClient } from '../SASViyaApiClient'
|
|||||||
import { isRelativePath } from '../utils'
|
import { isRelativePath } from '../utils'
|
||||||
import { BaseJobExecutor } from './JobExecutor'
|
import { BaseJobExecutor } from './JobExecutor'
|
||||||
|
|
||||||
|
export interface WaitingRequstPromise {
|
||||||
|
promise: Promise<any> | null
|
||||||
|
resolve: any
|
||||||
|
reject: any
|
||||||
|
}
|
||||||
export class WebJobExecutor extends BaseJobExecutor {
|
export class WebJobExecutor extends BaseJobExecutor {
|
||||||
constructor(
|
constructor(
|
||||||
serverUrl: string,
|
serverUrl: string,
|
||||||
@@ -80,30 +85,51 @@ export class WebJobExecutor extends BaseJobExecutor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.requestClient!.post(apiUrl, formData, undefined)
|
const requestPromise = new Promise((resolve, reject) => {
|
||||||
.then(async (res) => {
|
this.requestClient!.post(apiUrl, formData, undefined)
|
||||||
if (this.serverType === ServerType.SasViya && config.debug) {
|
.then(async (res) => {
|
||||||
const jsonResponse = await this.parseSasViyaDebugResponse(
|
if (this.serverType === ServerType.SasViya && config.debug) {
|
||||||
res.result as string
|
const jsonResponse = await this.parseSasViyaDebugResponse(
|
||||||
)
|
res.result as string
|
||||||
|
)
|
||||||
|
this.appendRequest(res, sasJob, config.debug)
|
||||||
|
resolve(jsonResponse)
|
||||||
|
}
|
||||||
this.appendRequest(res, sasJob, config.debug)
|
this.appendRequest(res, sasJob, config.debug)
|
||||||
return jsonResponse
|
resolve(res.result)
|
||||||
}
|
})
|
||||||
this.appendRequest(res, sasJob, config.debug)
|
.catch(async (e: Error) => {
|
||||||
return res.result
|
if (e instanceof JobExecutionError) {
|
||||||
})
|
this.appendRequest(e, sasJob, config.debug)
|
||||||
.catch(async (e: Error) => {
|
|
||||||
if (e instanceof JobExecutionError) {
|
reject(new ErrorResponse(e?.message, e))
|
||||||
this.appendRequest(e, sasJob, config.debug)
|
}
|
||||||
}
|
|
||||||
if (e instanceof LoginRequiredError) {
|
if (e instanceof LoginRequiredError) {
|
||||||
await loginCallback()
|
await loginCallback()
|
||||||
this.appendWaitingRequest(() =>
|
|
||||||
this.execute(sasJob, data, config, loginRequiredCallback)
|
this.appendWaitingRequest(() => {
|
||||||
)
|
return this.execute(
|
||||||
}
|
sasJob,
|
||||||
return Promise.reject(new ErrorResponse(e?.message, e))
|
data,
|
||||||
})
|
config,
|
||||||
|
loginRequiredCallback
|
||||||
|
).then(
|
||||||
|
(res: any) => {
|
||||||
|
resolve(res)
|
||||||
|
},
|
||||||
|
(err: any) => {
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
reject(new ErrorResponse(e?.message, e))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return requestPromise
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseSasViyaDebugResponse = async (response: string) => {
|
private parseSasViyaDebugResponse = async (response: string) => {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { LoginRequiredError } from '../types'
|
|||||||
import { AuthorizeError } from '../types/AuthorizeError'
|
import { AuthorizeError } from '../types/AuthorizeError'
|
||||||
import { NotFoundError } from '../types/NotFoundError'
|
import { NotFoundError } from '../types/NotFoundError'
|
||||||
import { parseWeboutResponse } from '../utils/parseWeboutResponse'
|
import { parseWeboutResponse } from '../utils/parseWeboutResponse'
|
||||||
|
import { prefixMessage } from '@sasjs/utils/error'
|
||||||
|
|
||||||
export interface HttpClient {
|
export interface HttpClient {
|
||||||
get<T>(
|
get<T>(
|
||||||
@@ -97,7 +98,9 @@ export class RequestClient implements HttpClient {
|
|||||||
.catch(async (e) => {
|
.catch(async (e) => {
|
||||||
return await this.handleError(e, () =>
|
return await this.handleError(e, () =>
|
||||||
this.get<T>(url, accessToken, contentType, overrideHeaders)
|
this.get<T>(url, accessToken, contentType, overrideHeaders)
|
||||||
)
|
).catch((err) => {
|
||||||
|
throw prefixMessage(err, 'Error while handling error. ')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,35 +334,59 @@ export class RequestClient implements HttpClient {
|
|||||||
|
|
||||||
private handleError = async (e: any, callback: any) => {
|
private handleError = async (e: any, callback: any) => {
|
||||||
const response = e.response as AxiosResponse
|
const response = e.response as AxiosResponse
|
||||||
|
|
||||||
if (e instanceof AuthorizeError) {
|
if (e instanceof AuthorizeError) {
|
||||||
const res = await this.httpClient.get(e.confirmUrl, {
|
const res = await this.httpClient
|
||||||
responseType: 'text',
|
.get(e.confirmUrl, {
|
||||||
headers: { 'Content-Type': 'text/plain', Accept: '*/*' }
|
responseType: 'text',
|
||||||
})
|
headers: { 'Content-Type': 'text/plain', Accept: '*/*' }
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
throw prefixMessage(err, 'Error while getting error confirmUrl. ')
|
||||||
|
})
|
||||||
|
|
||||||
if (isAuthorizeFormRequired(res?.data as string)) {
|
if (isAuthorizeFormRequired(res?.data as string)) {
|
||||||
await this.authorize(res.data as string)
|
await this.authorize(res.data as string).catch((err) => {
|
||||||
|
throw prefixMessage(err, 'Error while authorizing request. ')
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return await callback()
|
|
||||||
|
return await callback().catch((err: any) => {
|
||||||
|
throw prefixMessage(
|
||||||
|
err,
|
||||||
|
'Error while executing callback in handleError. '
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e instanceof LoginRequiredError) {
|
if (e instanceof LoginRequiredError) {
|
||||||
this.clearCsrfTokens()
|
this.clearCsrfTokens()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response?.status === 403 || response?.status === 449) {
|
if (response?.status === 403 || response?.status === 449) {
|
||||||
this.parseAndSetCsrfToken(response)
|
this.parseAndSetCsrfToken(response)
|
||||||
|
|
||||||
if (this.csrfToken.headerName && this.csrfToken.value) {
|
if (this.csrfToken.headerName && this.csrfToken.value) {
|
||||||
return await callback()
|
return await callback().catch((err: any) => {
|
||||||
|
throw prefixMessage(
|
||||||
|
err,
|
||||||
|
'Error while executing callback in handleError. '
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
throw e
|
throw e
|
||||||
} else if (response?.status === 404) {
|
} else if (response?.status === 404) {
|
||||||
throw new NotFoundError(response.config.url!)
|
throw new NotFoundError(response.config.url!)
|
||||||
}
|
}
|
||||||
|
|
||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
|
|
||||||
private async parseResponse<T>(response: AxiosResponse<any>) {
|
private parseResponse<T>(response: AxiosResponse<any>) {
|
||||||
const etag = response?.headers ? response.headers['etag'] : ''
|
const etag = response?.headers ? response.headers['etag'] : ''
|
||||||
let parsedResponse
|
let parsedResponse
|
||||||
|
let includeSAS9Log: boolean = false
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (typeof response.data === 'string') {
|
if (typeof response.data === 'string') {
|
||||||
@@ -373,11 +400,20 @@ export class RequestClient implements HttpClient {
|
|||||||
} catch {
|
} catch {
|
||||||
parsedResponse = response.data
|
parsedResponse = response.data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
includeSAS9Log = true
|
||||||
}
|
}
|
||||||
return {
|
|
||||||
|
let responseToReturn: { result: T; etag: any; log?: string } = {
|
||||||
result: parsedResponse as T,
|
result: parsedResponse as T,
|
||||||
etag
|
etag
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (includeSAS9Log) {
|
||||||
|
responseToReturn.log = response.data
|
||||||
|
}
|
||||||
|
|
||||||
|
return responseToReturn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,10 @@ describe('SessionManager', () => {
|
|||||||
Promise.resolve({ data: sampleResponse })
|
Promise.resolve({ data: sampleResponse })
|
||||||
)
|
)
|
||||||
|
|
||||||
const expectedResponse = { etag: '', result: sampleResponse }
|
const expectedResponse = {
|
||||||
|
etag: '',
|
||||||
|
result: sampleResponse
|
||||||
|
}
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
sessionManager.getVariable(
|
sessionManager.getVariable(
|
||||||
|
|||||||
Reference in New Issue
Block a user