diff --git a/README.md b/README.md index bf7eb85..b979823 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ SYNC_SEQUENCE = true SYNC_SUPPLIER = true SYNC_CONN = true SYNC_TRADEITEM = true +MAX_REQUEST_RETRIES = 3 ``` ## Guidelines diff --git a/utils.js b/utils.js index 85f6e43..f8d5a33 100644 --- a/utils.js +++ b/utils.js @@ -34,25 +34,22 @@ export async function requestToken() { clientSecret = env.CLIENT_SECRET }; - const data = { + let data = { grant_type: 'client_credentials', client_id: clientId, client_secret: clientSecret, scope: 'role:app catalog:read supply:read organization:read network:write network:read' }; - const response = await axios.post(env.API_ENDPOINT, - Object.keys(data) - .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`) - .join('&'), - { - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - } - } - ); + data = Object.keys(data) + .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`) + .join('&') - const responseData = response.data; + const headers = { + 'Content-Type': 'application/x-www-form-urlencoded', + } + + const response = (await vnRequest('GET', env.API_ENDPOINT, data, headers)).data; if (response.statusText = 'OK') spinner.succeed(); @@ -61,13 +58,13 @@ export async function requestToken() { criticalError(new Error(`Token request failed with status: ${response.status} - ${response.statusText}`)); } let tokenExpirationDate = moment() - .add(responseData.expires_in, 's') + .add(response.expires_in, 's') .format('YYYY-MM-DD HH:mm:ss'); await updateClientConfig( clientId, clientSecret, - responseData.access_token, + response.access_token, tokenExpirationDate ); @@ -278,19 +275,12 @@ export async function syncSuppliers(){ 'X-Api-Key': process.env.API_KEY, }; - const response = await axios.get(`${env.API_URL}/organizations/current-max-sequence`, { headers }); - - if (!response.ok) { - spinner.fail(); - criticalError(new Error(`Max sequence request failed with status: ${response.status} - ${response.statusText}`)); - } - const maxSequenceNumber = response.data; + const maxSequenceNumber = (await vnRequest('GET', `${env.API_URL}/organizations/current-max-sequence`, null, headers)).data; let timeFinish, timeToGoSec, timeToGoMin, timeLeft; for (let curSequenceNumber = 0; curSequenceNumber <= maxSequenceNumber; curSequenceNumber++) { let timeStart = new moment(); - let response = await axios.get(`${env.API_URL}/organizations/sync/${curSequenceNumber}?organizationType=SUPPLIER`, { headers }); - let data = response.data; + let data = (await vnRequest('GET', `${env.API_URL}/organizations/sync/${curSequenceNumber}?organizationType=SUPPLIER`, null, headers)).data; let suppliers = data.results; for (let supplier of suppliers) { @@ -343,15 +333,16 @@ export async function syncConn(){ 'X-Api-Key': process.env.API_KEY }; - const remoteConnections = await axios.get(`${env.API_URL}/connections`, { headers }); + const remoteConnections = (await vnRequest('GET', `${env.API_URL}/connections`, null, headers)).data; let i = 1; for (let connection of connections){ spinner.text = `Creating ${i++} connections...` - let remoteConnection = remoteConnections.data.find(remoteConnection => remoteConnection == connection.supplierOrganizationId); + let remoteConnection = remoteConnections.find(remoteConnection => remoteConnection == connection.supplierOrganizationId); if (!remoteConnection){ - await axios.put(`${env.API_URL}/connections/${connection.supplierOrganizationId}`, null, { headers }); + await vnRequest('PUT', `${env.API_URL}/connections/${connection.supplierOrganizationId}`, null, headers); + await models.connection.update({ isConnected: true }, { where: { supplierOrganizationId: connection.supplierOrganizationId @@ -387,7 +378,8 @@ export async function syncTradeItems(){ const suppliers = await models.supplier.findAll({ where: { isConnected: true } }); - let i = 1; + let i = 0; + let x = 0; for (let supplier of suppliers) { let headers = { 'Content-Type': 'application/json', @@ -395,16 +387,14 @@ export async function syncTradeItems(){ 'X-Api-Key': process.env.API_KEY }; try { - let request = await axios.get(`${env.API_URL}/trade-items?supplierOrganizationId=${supplier.supplierOrganizationId}`, { headers }) - - let tradeItems = request.data; - - if (!tradeItems.length) - continue; + let tradeItems = (await vnRequest('GET', `${env.API_URL}/trade-items?supplierOrganizationId=${supplier.supplierOrganizationId}`, null, headers)).data + + spinner.text = `Syncing ${i} trade items of [${x++}|${suppliers.length}] suppliers...` + if (!tradeItems.length) continue; for (let tradeItem of tradeItems) { await insertItem(tradeItem); - spinner.text = `Syncing ${i++} trade items...` + spinner.text = `Syncing ${i++} trade items of [${x++}|${suppliers.length}] suppliers...` }; } catch (err) { spinner.fail(); @@ -452,14 +442,7 @@ export async function syncSupplyLines(){ tradeItemId: tradeItem.tradeItemId, postFilterSelectedTradeItems: false }).toString(); - let request = await axios.get(`${`${env.API_URL}/supply-lines`}?${params}`, { headers }); - - if (request.status == 429) { // Too many request - resolve([]); - return; - } - - let supplyLines = request.data; + let supplyLines = (await vnRequest('GET', `${`${env.API_URL}/supply-lines`}?${params}`, null, headers)).data; if (!supplyLines.results.length) { resolve([]); @@ -497,11 +480,9 @@ export async function syncSupplyLines(){ console.log('Trade item not found for supply line: ', line.supplyLineId); console.log('Requesting data for trade item id: ', line.tradeItemId); - let queryTradeItem = await axios.get(`${env.API_URL}/trade-items?tradeItemIds=${line.tradeItemId}`, { headers }); + let tradeItem = (await vnRequest('GET', `${env.API_URL}/trade-items?tradeItemIds=${line.tradeItemId}`, null, headers)).data; - let tradeItem = queryTradeItem.data; - - if (tradeItem.length == 0) { + if (!tradeItem.length) { console.log('Trade item not found for supply line: ', line.supplyLineId); console.log('Trade item id: ', line.tradeItemId); continue; @@ -569,6 +550,7 @@ export async function syncSupplyLines(){ } export async function newSyncSupplyLines() { + const spinner = ora(`(NEW) Syncing supply lines...`).start(); try { let headers = { 'Content-Type': 'application/json', @@ -592,24 +574,22 @@ export async function newSyncSupplyLines() { }); }).map(supplier => supplier.supplierOrganizationId); + let i = 1; for (let supplier of suppliers) { + spinner.text = `(NEW) Syncing ${i++} supply lines...` const params = new URLSearchParams({ supplierOrganizationId: supplier, }).toString(); - let request = await axios.get(`${`${env.API_URL}/supply-lines`}?${params}`, { headers }); + let supplyLines = (await vnRequest('GET',`${env.API_URL}/supply-lines?${params}`, null, headers)).data; + if (!supplyLines.length) continue - if (!request.data.length) - continue - - let supplyLines = request.data; - - for (let supplyLine of supplyLines) { + for (let supplyLine of supplyLines) console.log(supplyLine) - } } - console.log('Finalizado') + spinner.succeed(); } catch (err) { + spinner.fail(); throw err; } } @@ -718,9 +698,9 @@ export async function deleteConnections() { 'Authorization': `Bearer ${await getCurrentToken()}`, 'X-Api-Key': process.env.API_KEY }; - let connections = (await axios.get(`${env.API_URL}/connections`, { headers })).data; + let connections = (await vnRequest('GET', `${env.API_URL}/connections`, null, headers)).data; for (let connection of connections) { - await axios.delete(`${env.API_URL}/connections/${connection}`, { headers }); + await vnRequest('DELETE', `${env.API_URL}/connections/${connection}`, null, headers); spinner.text = `Deleting ${i++} connections...` } spinner.succeed(); @@ -730,6 +710,36 @@ export async function deleteConnections() { } } +/** + * Perform a REST request + * + * @param {string} url + * @param {string} method + * @param {array} body + * @param {array} header + * + * @return {array} + **/ +export async function vnRequest(method = 'GET', url, data = null, headers = {}) { + let response; + for(let i = 0; i < env.MAX_REQUEST_RETRIES; i++) { + try { + if (['GET', 'DELETE'].includes(method)) + response = await axios({method, url, headers}); + else + response = await axios({method, url, data, headers}); + break; + } catch (err) { + if (err.code == 'ECONNRESET') + warning(err) + else + criticalError(err) + await sleep(1000) + } + } + return response; +} + /** * Critical error *