2022-04-11 09:58:40 +00:00
|
|
|
/* eslint no-console: "off" */
|
|
|
|
const path = require('path');
|
|
|
|
const fs = require('fs-extra');
|
|
|
|
|
|
|
|
module.exports = Self => {
|
|
|
|
Self.remoteMethodCtx('updateData', {
|
|
|
|
description: 'Updates schema data from external provider',
|
|
|
|
accessType: 'WRITE',
|
|
|
|
returns: {
|
|
|
|
type: 'object',
|
|
|
|
root: true
|
|
|
|
},
|
|
|
|
http: {
|
|
|
|
path: `/updateData`,
|
|
|
|
verb: 'GET'
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
Self.updateData = async() => {
|
|
|
|
const models = Self.app.models;
|
|
|
|
|
2022-06-07 11:06:42 +00:00
|
|
|
// Get files checksum
|
|
|
|
const files = await Self.rawSql('SELECT name, checksum, keyValue FROM edi.fileConfig');
|
2022-04-11 09:58:40 +00:00
|
|
|
|
2022-06-07 11:06:42 +00:00
|
|
|
const updatableFiles = [];
|
|
|
|
for (const file of files) {
|
|
|
|
const fileChecksum = await getChecksum(file);
|
2022-06-03 11:54:58 +00:00
|
|
|
|
2022-06-07 11:06:42 +00:00
|
|
|
if (file.checksum != fileChecksum) {
|
|
|
|
updatableFiles.push({
|
|
|
|
name: file.name,
|
|
|
|
checksum: fileChecksum
|
|
|
|
});
|
|
|
|
} else
|
|
|
|
console.debug(`File already updated, skipping...`);
|
|
|
|
}
|
2022-04-11 09:58:40 +00:00
|
|
|
|
2022-06-07 11:06:42 +00:00
|
|
|
if (updatableFiles.length === 0)
|
|
|
|
return false;
|
2022-04-11 09:58:40 +00:00
|
|
|
|
2022-06-07 11:06:42 +00:00
|
|
|
// Download files
|
|
|
|
const container = await models.TempContainer.container('edi');
|
|
|
|
const tempPath = path.join(container.client.root, container.name);
|
2022-04-11 09:58:40 +00:00
|
|
|
|
|
|
|
let remoteFile;
|
|
|
|
let tempDir;
|
|
|
|
let tempFile;
|
|
|
|
|
2022-06-07 11:06:42 +00:00
|
|
|
const fileNames = updatableFiles.map(file => file.name);
|
2022-04-11 09:58:40 +00:00
|
|
|
|
2022-06-07 11:06:42 +00:00
|
|
|
const tables = await Self.rawSql(`
|
|
|
|
SELECT fileName, toTable, file
|
|
|
|
FROM edi.tableConfig
|
|
|
|
WHERE file IN (?)`, [fileNames]);
|
2022-04-11 09:58:40 +00:00
|
|
|
|
2022-06-07 11:06:42 +00:00
|
|
|
for (const table of tables) {
|
|
|
|
const fileName = table.file;
|
2022-06-03 11:22:32 +00:00
|
|
|
|
2022-06-07 11:06:42 +00:00
|
|
|
console.debug(`Downloading file ${fileName}...`);
|
2022-06-03 11:22:32 +00:00
|
|
|
|
2022-06-07 11:06:42 +00:00
|
|
|
remoteFile = `codes/${fileName}.ZIP`;
|
|
|
|
tempDir = `${tempPath}/${fileName}`;
|
|
|
|
tempFile = `${tempPath}/${fileName}.zip`;
|
2022-04-11 09:58:40 +00:00
|
|
|
|
2022-06-09 08:13:45 +00:00
|
|
|
try {
|
|
|
|
await fs.readFile(tempFile);
|
|
|
|
} catch (error) {
|
|
|
|
if (error.code === 'ENOENT') {
|
|
|
|
const downloadOutput = await downloadFile(remoteFile, tempFile);
|
|
|
|
if (downloadOutput.error)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2022-06-07 11:06:42 +00:00
|
|
|
|
|
|
|
console.debug(`Extracting file ${fileName}...`);
|
|
|
|
await extractFile(tempFile, tempDir);
|
|
|
|
|
|
|
|
console.debug(`Updating table ${table.toTable}...`);
|
|
|
|
await dumpData(tempDir, table);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update files checksum
|
|
|
|
for (const file of updatableFiles) {
|
|
|
|
await Self.rawSql(`
|
|
|
|
UPDATE edi.fileConfig
|
|
|
|
SET checksum = ?
|
|
|
|
WHERE name = ?`,
|
|
|
|
[file.checksum, file.name]);
|
2022-04-11 09:58:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-07 11:06:42 +00:00
|
|
|
// Clean files
|
2022-06-09 08:13:45 +00:00
|
|
|
try {
|
|
|
|
await fs.remove(tempPath);
|
|
|
|
} catch (error) {
|
|
|
|
if (error.code !== 'ENOENT')
|
|
|
|
throw e;
|
|
|
|
}
|
2022-06-07 11:06:42 +00:00
|
|
|
|
2022-04-11 09:58:40 +00:00
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
2022-06-07 11:06:42 +00:00
|
|
|
let ftpClient;
|
|
|
|
async function getFtpClient() {
|
|
|
|
if (!ftpClient) {
|
|
|
|
const [ftpConfig] = await Self.rawSql('SELECT host, user, password FROM edi.ftpConfig');
|
|
|
|
console.debug(`Openning FTP connection to ${ftpConfig.host}...\n`);
|
2022-04-11 09:58:40 +00:00
|
|
|
|
2022-06-07 11:06:42 +00:00
|
|
|
const FtpClient = require('ftps');
|
2022-04-11 09:58:40 +00:00
|
|
|
|
2022-06-07 11:06:42 +00:00
|
|
|
ftpClient = new FtpClient({
|
|
|
|
host: ftpConfig.host,
|
|
|
|
username: ftpConfig.user,
|
|
|
|
password: ftpConfig.password,
|
|
|
|
procotol: 'ftp'
|
|
|
|
});
|
|
|
|
}
|
2022-04-11 09:58:40 +00:00
|
|
|
|
2022-06-07 11:06:42 +00:00
|
|
|
return ftpClient;
|
|
|
|
}
|
2022-04-11 09:58:40 +00:00
|
|
|
|
2022-06-07 11:06:42 +00:00
|
|
|
async function getChecksum(file) {
|
|
|
|
const ftpClient = await getFtpClient();
|
|
|
|
console.debug(`Checking checksum for file ${file.name}...`);
|
2022-04-11 09:58:40 +00:00
|
|
|
|
2022-06-07 11:06:42 +00:00
|
|
|
ftpClient.cat(`codes/${file.name}.txt`);
|
|
|
|
|
|
|
|
const response = await new Promise((resolve, reject) => {
|
|
|
|
ftpClient.exec((err, response) => {
|
|
|
|
if (response.error) {
|
|
|
|
console.debug(`Error downloading checksum file... ${response.error}`);
|
|
|
|
reject(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
resolve(response);
|
|
|
|
});
|
2022-04-11 09:58:40 +00:00
|
|
|
});
|
2022-06-07 11:06:42 +00:00
|
|
|
|
|
|
|
if (response && response.data) {
|
|
|
|
const fileContents = response.data;
|
|
|
|
const rows = fileContents.split('\n');
|
|
|
|
const row = rows[4];
|
|
|
|
const columns = row.split(/\s+/);
|
|
|
|
|
|
|
|
let fileChecksum;
|
|
|
|
if (file.keyValue)
|
|
|
|
fileChecksum = columns[1];
|
|
|
|
|
|
|
|
if (!file.keyValue)
|
|
|
|
fileChecksum = columns[0];
|
|
|
|
|
|
|
|
return fileChecksum;
|
|
|
|
}
|
2022-04-11 09:58:40 +00:00
|
|
|
}
|
|
|
|
|
2022-06-07 11:06:42 +00:00
|
|
|
async function downloadFile(remoteFile, tempFile) {
|
|
|
|
const ftpClient = await getFtpClient();
|
|
|
|
|
|
|
|
ftpClient.get(remoteFile, tempFile);
|
|
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
ftpClient.exec((err, response) => {
|
|
|
|
if (response.error) {
|
|
|
|
console.debug(`Error downloading file... ${response.error}`);
|
|
|
|
reject(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
resolve(response);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
async function extractFile(tempFile, tempDir) {
|
|
|
|
const JSZip = require('jszip');
|
|
|
|
|
2022-06-09 08:13:45 +00:00
|
|
|
try {
|
|
|
|
await fs.mkdir(tempDir);
|
|
|
|
} catch (error) {
|
|
|
|
if (error.code !== 'EEXIST')
|
|
|
|
throw e;
|
|
|
|
}
|
2022-06-07 11:06:42 +00:00
|
|
|
|
|
|
|
const fileStream = await fs.readFile(tempFile);
|
|
|
|
if (fileStream) {
|
|
|
|
const zip = new JSZip();
|
|
|
|
const zipContents = await zip.loadAsync(fileStream);
|
|
|
|
|
|
|
|
if (!zipContents) return;
|
|
|
|
|
|
|
|
const fileNames = Object.keys(zipContents.files);
|
|
|
|
|
|
|
|
for (const fileName of fileNames) {
|
|
|
|
const fileContent = await zip.file(fileName).async('nodebuffer');
|
|
|
|
const dest = path.join(tempDir, fileName);
|
2022-06-09 08:13:45 +00:00
|
|
|
await fs.writeFile(dest, fileContent);
|
2022-06-07 11:06:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async function dumpData(tempDir, table) {
|
|
|
|
const toTable = table.toTable;
|
|
|
|
const baseName = table.fileName;
|
2022-04-11 09:58:40 +00:00
|
|
|
|
2022-06-04 10:45:02 +00:00
|
|
|
const firstEntry = entries[0];
|
|
|
|
const entryName = firstEntry.entryName;
|
|
|
|
const startIndex = (entryName.length - 10);
|
|
|
|
const endIndex = (entryName.length - 4);
|
|
|
|
const dateString = entryName.substring(startIndex, endIndex);
|
|
|
|
|
|
|
|
const lastUpdated = new Date();
|
|
|
|
|
|
|
|
let updated = null;
|
|
|
|
if (file.updated) {
|
|
|
|
updated = new Date(file.updated);
|
|
|
|
updated.setHours(0, 0, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Format string date to a date object
|
|
|
|
lastUpdated.setFullYear(`20${dateString.substring(4, 6)}`);
|
|
|
|
lastUpdated.setMonth(parseInt(dateString.substring(2, 4)) - 1);
|
|
|
|
lastUpdated.setDate(dateString.substring(0, 2));
|
|
|
|
lastUpdated.setHours(0, 0, 0, 0);
|
|
|
|
|
|
|
|
if (updated && lastUpdated <= updated) {
|
|
|
|
console.debug(`Table ${toTable} already updated, skipping...`);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-06-03 10:52:41 +00:00
|
|
|
const tx = await Self.beginTransaction({});
|
2022-06-03 10:57:39 +00:00
|
|
|
|
2022-06-03 10:52:41 +00:00
|
|
|
try {
|
|
|
|
const options = {transaction: tx};
|
2022-04-11 09:58:40 +00:00
|
|
|
|
2022-06-03 10:57:39 +00:00
|
|
|
const tableName = `edi.${toTable}`;
|
|
|
|
await Self.rawSql(`DELETE FROM ??`, [tableName], options);
|
|
|
|
|
2022-06-09 08:13:45 +00:00
|
|
|
const dirFiles = await fs.readdir(tempDir);
|
|
|
|
const files = dirFiles.filter(file => file.startsWith(baseName));
|
2022-04-11 09:58:40 +00:00
|
|
|
|
2022-06-07 11:06:42 +00:00
|
|
|
for (const file of files) {
|
|
|
|
console.log(`Dumping data from file ${file}...`);
|
2022-04-11 09:58:40 +00:00
|
|
|
|
2022-06-03 10:52:41 +00:00
|
|
|
const templatePath = path.join(__dirname, `./sql/${toTable}.sql`);
|
2022-06-09 08:13:45 +00:00
|
|
|
const sqlTemplate = await fs.readFile(templatePath, 'utf8');
|
2022-06-07 11:06:42 +00:00
|
|
|
const filePath = path.join(tempDir, file);
|
2022-06-03 10:52:41 +00:00
|
|
|
|
2022-06-07 11:06:42 +00:00
|
|
|
await Self.rawSql(sqlTemplate, [filePath], options);
|
2022-04-11 09:58:40 +00:00
|
|
|
await Self.rawSql(`
|
2022-06-07 11:06:42 +00:00
|
|
|
UPDATE edi.tableConfig
|
|
|
|
SET updated = ?
|
|
|
|
WHERE fileName = ?
|
|
|
|
`, [new Date(), baseName], options);
|
2022-04-11 09:58:40 +00:00
|
|
|
}
|
2022-06-03 11:01:39 +00:00
|
|
|
|
|
|
|
tx.commit();
|
2022-06-03 10:52:41 +00:00
|
|
|
} catch (error) {
|
|
|
|
tx.rollback();
|
|
|
|
throw error;
|
2022-04-11 09:58:40 +00:00
|
|
|
}
|
2022-06-03 10:52:41 +00:00
|
|
|
console.log(`Updated table ${toTable}\n`);
|
2022-04-11 09:58:40 +00:00
|
|
|
}
|
|
|
|
};
|