Files
Superalgos/Integrations/FileStorage.js
T

234 lines
7.1 KiB
JavaScript

const axios = require('axios')
const Ecosystem = require('./Ecosystem')
let fs = require('fs')
const { promisify } = require('util')
const readFileAsync = promisify(fs.readFile)
const writeFileAsync = promisify(fs.writeFile)
const path = require('path')
exports.newFileStorage = function newFileStorage(logger) {
const MODULE_NAME = 'FileStorage'
const MAX_RETRY = 30
let currentRetryGetTextFile = 0
let currentRetryWriteTextFile = 0
const recoverableErrors = [
'SOCKETTIMEDOUT',
'TIMEDOUT',
'CONNRESET',
'CONNREFUSED',
'NOTFOUND',
'ENOTFOUND',
'ECONNREFUSED',
'CONNREFUSED',
'NOTFOUND',
'ESOCKETTIMEDOUT',
'ECONNRESET',
'ETIMEDOUT',
'EAI_AGAIN'
]
return {
getTextFile,
createTextFile
}
function logInfo(message) {
log('[INFO] ' + message)
}
function log(message) {
if (logger) {
logger.write(MODULE_NAME, message);
} else {
//console.log("['" + new Date().toISOString() + "', 0,'" + MODULE_NAME + "','" + message + "']")
}
}
function logError(message) {
log('[ERROR] ' + message)
}
async function getTextFile(container, filePath, callBackFunction) {
try {
let host = await getDevTeamHost(container)
if (host.url.indexOf('localhost') !== -1) {
let fileLocation
if (filePath.indexOf("/bots/") > 0) {
fileLocation = process.env.BOTS_PATH + '/' + container + '/' + filePath
} else {
fileLocation = process.env.STORAGE_PATH + '/' + container + '/' + filePath
}
logInfo('getTextFile: ' + fileLocation)
//console.log('getTextFile: ' + fileLocation)
let fileContent = await readFileAsync(fileLocation)
callBackFunction(global.DEFAULT_OK_RESPONSE, fileContent.toString())
} else {
let response = await axios({
url: host.url + 'graphql',
method: 'post',
data: {
query: `
query web_FileContent($file: web_FileInput){
web_FileContent(file: $file)
}
`,
variables: {
file: {
container: container.toLowerCase(),
filePath,
storage: host.storage,
accessKey: host.accessKey
}
}
}
})
if (response.data.errors) {
callBackFunction({ code: response.data.errors[0] })
return
}
if (response.data.data.web_FileContent) {
callBackFunction(global.DEFAULT_OK_RESPONSE, response.data.data.web_FileContent)
} else {
callBackFunction({ code: 'The specified key does not exist.' })
}
}
} catch (err) {
if (verifyRetry(err.code) && currentRetryGetTextFile < MAX_RETRY) {
currentRetryGetTextFile++
logInfo('getTextFile -> Retrying connection to the server because received error: ' + err.code + '. Retry #: ' + currentRetryGetTextFile)
getTextFile(container, filePath, callBackFunction)
} else if (err.code === 'ENOENT') {
callBackFunction({ code: 'The specified key does not exist.' })
} else {
currentRetryGetTextFile = 0
logError('getTextFile -> error = ' + err.message)
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
}
}
}
async function createTextFile(container, filePath, fileContent, callBackFunction) {
try {
let host = await getDevTeamHost(container)
if (host.url.indexOf('localhost') !== -1) {
let fileLocation
if (filePath.indexOf("/Logs/") > 0) {
fileLocation = process.env.LOG_PATH + '/' + container + '/' + filePath
} else {
fileLocation = process.env.STORAGE_PATH + '/' + container + '/' + filePath
}
logInfo('createTextFile: ' + fileLocation)
//console.log('createTextFile: ' + fileLocation)
let directoryPath = fileLocation.substring(0, fileLocation.lastIndexOf('/') + 1);
mkDirByPathSync(directoryPath)
await writeFileAsync(fileLocation, fileContent)
callBackFunction(global.DEFAULT_OK_RESPONSE)
} else {
let response = await axios({
url: process.env.GATEWAY_ENDPOINT_K8S,
method: 'post',
data: {
query: `
mutation web_CreateFile($file: web_FileInput){
web_CreateFile(file: $file)
}
`,
variables: {
file: {
container: container.toLowerCase(),
filePath,
storage: 'localStorage',
accessKey: host.ownerKey,
fileContent
}
}
}
})
if (!response || response.data.errors) {
let customErr = {
result: global.CUSTOM_FAIL_RESPONSE.result,
message: response.data.errors[0]
}
callBackFunction(customErr)
} else {
callBackFunction(global.DEFAULT_OK_RESPONSE)
}
}
} catch (err) {
if (verifyRetry(err.code) && currentRetryWriteTextFile < MAX_RETRY) {
currentRetryWriteTextFile++
logInfo('createTextFile -> Retrying connection to the server because received error: ' + err.code + '. Retry #: ' + currentRetryWriteTextFile)
createTextFile(container, filePath, fileContent, callBackFunction)
} else {
currentRetryWriteTextFile = 0
logError('createTextFile -> error = ' + err.message)
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
}
}
}
async function getDevTeamHost(devTeamName) {
let ecosystem = await Ecosystem.getEcosystem()
for (var i = 0; i < ecosystem.devTeams.length; i++) {
if (ecosystem.devTeams[i].codeName.toLowerCase() === devTeamName.toLowerCase()) {
return ecosystem.devTeams[i].host
}
}
}
function verifyRetry(errorCode) {
for (let i = 0; i < recoverableErrors.length; i++) {
const error = recoverableErrors[i];
if (error === errorCode) {
return true
}
}
return false
}
function mkDirByPathSync(targetDir, { isRelativeToScript = false } = {}) {
const sep = '/';
const initDir = path.isAbsolute(targetDir) ? sep : '';
const baseDir = isRelativeToScript ? __dirname : '.';
return targetDir.split(sep).reduce((parentDir, childDir) => {
const curDir = path.resolve(baseDir, parentDir, childDir);
try {
fs.mkdirSync(curDir);
} catch (err) {
if (err.code === 'EEXIST') { // curDir already exists!
return curDir;
}
// To avoid `EISDIR` error on Mac and `EACCES`-->`ENOENT` and `EPERM` on Windows.
if (err.code === 'ENOENT') { // Throw the original parentDir error on curDir `ENOENT` failure.
throw new Error(`EACCES: permission denied, mkdir '${parentDir}'`);
}
const caughtErr = ['EACCES', 'EPERM', 'EISDIR'].indexOf(err.code) > -1;
if (!caughtErr || caughtErr && curDir === path.resolve(targetDir)) {
throw err; // Throw if it's just the last created dir.
}
}
return curDir;
}, initDir);
}
}