mirror of
https://github.com/basicswap/basicswap.git
synced 2025-05-05 20:32:15 +00:00
JS: Fix HTTP Error 429
This commit is contained in:
parent
fe02441619
commit
765ef9571a
2 changed files with 177 additions and 122 deletions
basicswap/static/js
|
@ -74,7 +74,7 @@ let filterTimeout = null;
|
||||||
// CONFIGURATION CONSTANTS
|
// CONFIGURATION CONSTANTS
|
||||||
|
|
||||||
// Time Constants
|
// Time Constants
|
||||||
const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
|
const CACHE_DURATION = 10 * 60 * 1000;
|
||||||
|
|
||||||
// Application Constants
|
// Application Constants
|
||||||
const itemsPerPage = 50;
|
const itemsPerPage = 50;
|
||||||
|
@ -1106,7 +1106,20 @@ function getEmptyPriceData() {
|
||||||
|
|
||||||
async function fetchLatestPrices() {
|
async function fetchLatestPrices() {
|
||||||
const PRICES_CACHE_KEY = 'prices_coingecko';
|
const PRICES_CACHE_KEY = 'prices_coingecko';
|
||||||
|
const minRequestInterval = 15000;
|
||||||
|
const currentTime = Date.now();
|
||||||
|
|
||||||
|
if (!window.isManualRefresh) {
|
||||||
|
const lastRequestTime = window.lastPriceRequest || 0;
|
||||||
|
if (currentTime - lastRequestTime < minRequestInterval) {
|
||||||
|
console.log('Request too soon, using cache');
|
||||||
|
const cachedData = CacheManager.get(PRICES_CACHE_KEY);
|
||||||
|
if (cachedData) {
|
||||||
|
return cachedData.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
window.lastPriceRequest = currentTime;
|
||||||
if (!window.isManualRefresh) {
|
if (!window.isManualRefresh) {
|
||||||
const cachedData = CacheManager.get(PRICES_CACHE_KEY);
|
const cachedData = CacheManager.get(PRICES_CACHE_KEY);
|
||||||
if (cachedData && cachedData.remainingTime > 60000) {
|
if (cachedData && cachedData.remainingTime > 60000) {
|
||||||
|
@ -1120,10 +1133,11 @@ async function fetchLatestPrices() {
|
||||||
return cachedData.value;
|
return cachedData.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const url = `${offersConfig.apiEndpoints.coinGecko}/simple/price?ids=bitcoin,bitcoin-cash,dash,dogecoin,decred,litecoin,particl,pivx,monero,zano,wownero,zcoin&vs_currencies=USD,BTC&api_key=${offersConfig.apiKeys.coinGecko}`;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log('Initiating fresh price data fetch...');
|
console.log('Initiating fresh price data fetch...');
|
||||||
|
const existingCache = CacheManager.get(PRICES_CACHE_KEY, true);
|
||||||
|
let fallbackData = existingCache ? existingCache.value : null;
|
||||||
|
const url = `${offersConfig.apiEndpoints.coinGecko}/simple/price?ids=bitcoin,bitcoin-cash,dash,dogecoin,decred,litecoin,particl,pivx,monero,zano,wownero,zcoin&vs_currencies=USD,BTC&api_key=${offersConfig.apiKeys.coinGecko}`;
|
||||||
const response = await fetch('/json/readurl', {
|
const response = await fetch('/json/readurl', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
|
@ -1131,23 +1145,26 @@ async function fetchLatestPrices() {
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
url: url,
|
url: url,
|
||||||
headers: {}
|
headers: {
|
||||||
|
'User-Agent': 'Mozilla/5.0',
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Accept-Language': 'en-US,en;q=0.5'
|
||||||
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`HTTP Error: ${response.status} ${response.statusText}`);
|
throw new Error(`HTTP Error: ${response.status} ${response.statusText}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
if (data.Error) {
|
if (data.Error) {
|
||||||
console.error('API Error:', data.Error);
|
if (fallbackData) {
|
||||||
|
console.log('Using fallback data due to API error');
|
||||||
|
return fallbackData;
|
||||||
|
}
|
||||||
throw new Error(data.Error);
|
throw new Error(data.Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data && Object.keys(data).length > 0) {
|
if (data && Object.keys(data).length > 0) {
|
||||||
console.log('Processing fresh price data...');
|
console.log('Processing fresh price data');
|
||||||
latestPrices = data;
|
latestPrices = data;
|
||||||
CacheManager.set(PRICES_CACHE_KEY, data, CACHE_DURATION);
|
CacheManager.set(PRICES_CACHE_KEY, data, CACHE_DURATION);
|
||||||
|
|
||||||
|
@ -1156,14 +1173,27 @@ async function fetchLatestPrices() {
|
||||||
tableRateModule.setFallbackValue(coin, prices.usd);
|
tableRateModule.setFallbackValue(coin, prices.usd);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
} else {
|
|
||||||
console.warn('No price data received');
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
if (fallbackData) {
|
||||||
|
console.log('Using fallback data due to empty response');
|
||||||
|
return fallbackData;
|
||||||
|
}
|
||||||
|
const fallbackPrices = {};
|
||||||
|
Object.keys(getEmptyPriceData()).forEach(coin => {
|
||||||
|
const fallbackValue = tableRateModule.getFallbackValue(coin);
|
||||||
|
if (fallbackValue !== null) {
|
||||||
|
fallbackPrices[coin] = { usd: fallbackValue, btc: null };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (Object.keys(fallbackPrices).length > 0) {
|
||||||
|
return fallbackPrices;
|
||||||
|
}
|
||||||
|
console.warn('No price data received');
|
||||||
|
return null;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Price Fetch Error:', error);
|
console.error('Price Fetch Error:', error);
|
||||||
|
|
||||||
const fallbackPrices = {};
|
const fallbackPrices = {};
|
||||||
Object.keys(getEmptyPriceData()).forEach(coin => {
|
Object.keys(getEmptyPriceData()).forEach(coin => {
|
||||||
const fallbackValue = tableRateModule.getFallbackValue(coin);
|
const fallbackValue = tableRateModule.getFallbackValue(coin);
|
||||||
|
@ -2523,21 +2553,20 @@ function initializeTableEvents() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const refreshButton = document.getElementById('refreshOffers');
|
const refreshButton = document.getElementById('refreshOffers');
|
||||||
if (refreshButton) {
|
if (refreshButton) {
|
||||||
EventManager.add(refreshButton, 'click', async () => {
|
EventManager.add(refreshButton, 'click', async () => {
|
||||||
console.log('Manual refresh initiated');
|
console.log('Manual refresh initiated');
|
||||||
const refreshIcon = document.getElementById('refreshIcon');
|
const refreshIcon = document.getElementById('refreshIcon');
|
||||||
const refreshText = document.getElementById('refreshText');
|
const refreshText = document.getElementById('refreshText');
|
||||||
|
|
||||||
refreshButton.disabled = true;
|
refreshButton.disabled = true;
|
||||||
refreshIcon.classList.add('animate-spin');
|
refreshIcon.classList.add('animate-spin');
|
||||||
refreshText.textContent = 'Refreshing...';
|
refreshText.textContent = 'Refreshing...';
|
||||||
refreshButton.classList.add('opacity-75', 'cursor-wait');
|
refreshButton.classList.add('opacity-75', 'cursor-wait');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const PRICES_CACHE_KEY = 'prices_coingecko';
|
const cachedPrices = CacheManager.get('prices_coingecko');
|
||||||
localStorage.removeItem(PRICES_CACHE_KEY);
|
let previousPrices = cachedPrices ? cachedPrices.value : null;
|
||||||
CacheManager.clear();
|
CacheManager.clear();
|
||||||
window.isManualRefresh = true;
|
window.isManualRefresh = true;
|
||||||
const endpoint = isSentOffers ? '/json/sentoffers' : '/json/offers';
|
const endpoint = isSentOffers ? '/json/sentoffers' : '/json/offers';
|
||||||
|
@ -2547,43 +2576,32 @@ if (refreshButton) {
|
||||||
}
|
}
|
||||||
const newData = await response.json();
|
const newData = await response.json();
|
||||||
const processedNewData = Array.isArray(newData) ? newData : Object.values(newData);
|
const processedNewData = Array.isArray(newData) ? newData : Object.values(newData);
|
||||||
console.log('Fetched offers:', processedNewData.length);
|
|
||||||
|
|
||||||
jsonData = formatInitialData(processedNewData);
|
jsonData = formatInitialData(processedNewData);
|
||||||
originalJsonData = [...jsonData];
|
originalJsonData = [...jsonData];
|
||||||
|
const priceData = await fetchLatestPrices();
|
||||||
const url = `${offersConfig.apiEndpoints.coinGecko}/simple/price?ids=bitcoin,bitcoin-cash,dash,dogecoin,decred,litecoin,particl,pivx,monero,zano,wownero,zcoin&vs_currencies=USD,BTC&api_key=${offersConfig.apiKeys.coinGecko}`;
|
if (!priceData && previousPrices) {
|
||||||
console.log('Fetching fresh prices...');
|
console.log('Using previous price data after failed refresh');
|
||||||
const priceResponse = await fetch('/json/readurl', {
|
latestPrices = previousPrices;
|
||||||
method: 'POST',
|
await updateOffersTable();
|
||||||
headers: { 'Content-Type': 'application/json' },
|
} else if (priceData) {
|
||||||
body: JSON.stringify({ url: url, headers: {} })
|
latestPrices = priceData;
|
||||||
});
|
await updateOffersTable();
|
||||||
|
} else {
|
||||||
if (priceResponse.ok) {
|
throw new Error('Unable to fetch price data');
|
||||||
const priceData = await priceResponse.json();
|
|
||||||
if (priceData && Object.keys(priceData).length > 0) {
|
|
||||||
console.log('Updating with fresh price data');
|
|
||||||
latestPrices = priceData;
|
|
||||||
CacheManager.set(PRICES_CACHE_KEY, priceData, CACHE_DURATION);
|
|
||||||
Object.entries(priceData).forEach(([coin, prices]) => {
|
|
||||||
if (prices.usd) {
|
|
||||||
tableRateModule.setFallbackValue(coin, prices.usd);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await updateOffersTable();
|
|
||||||
updateJsonView();
|
updateJsonView();
|
||||||
updatePaginationInfo();
|
updatePaginationInfo();
|
||||||
lastRefreshTime = Date.now();
|
lastRefreshTime = Date.now();
|
||||||
updateLastRefreshTime();
|
updateLastRefreshTime();
|
||||||
|
|
||||||
console.log('Manual refresh completed successfully');
|
console.log('Manual refresh completed successfully');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error during manual refresh:', error);
|
console.error('Error during manual refresh:', error);
|
||||||
ui.displayErrorMessage('Failed to refresh offers. Please try again later.');
|
ui.displayErrorMessage('Unable to refresh data. Previous data will be preserved.');
|
||||||
|
const cachedData = CacheManager.get('prices_coingecko');
|
||||||
|
if (cachedData?.value) {
|
||||||
|
latestPrices = cachedData.value;
|
||||||
|
await updateOffersTable();
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
window.isManualRefresh = false;
|
window.isManualRefresh = false;
|
||||||
refreshButton.disabled = false;
|
refreshButton.disabled = false;
|
||||||
|
|
|
@ -28,7 +28,7 @@ const config = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
showVolume: false,
|
showVolume: false,
|
||||||
cacheTTL: 5 * 60 * 1000, // 5 minutes
|
cacheTTL: 10 * 60 * 1000,
|
||||||
specialCoins: [''],
|
specialCoins: [''],
|
||||||
resolutions: {
|
resolutions: {
|
||||||
year: { days: 365, interval: 'month' },
|
year: { days: 365, interval: 'month' },
|
||||||
|
@ -124,106 +124,143 @@ const api = {
|
||||||
error: error.message
|
error: error.message
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
fetchCoinGeckoDataXHR: async () => {
|
fetchCoinGeckoDataXHR: async () => {
|
||||||
const cacheKey = 'coinGeckoOneLiner';
|
const cacheKey = 'coinGeckoOneLiner';
|
||||||
|
const minRequestInterval = 15000;
|
||||||
|
const currentTime = Date.now();
|
||||||
|
const lastRequestTime = window.lastGeckoRequest || 0;
|
||||||
|
if (currentTime - lastRequestTime < minRequestInterval) {
|
||||||
|
console.log('Request too soon, using cache');
|
||||||
const cachedData = cache.get(cacheKey);
|
const cachedData = cache.get(cacheKey);
|
||||||
|
|
||||||
if (cachedData) {
|
if (cachedData) {
|
||||||
console.log('Using cached CoinGecko data');
|
|
||||||
return cachedData.value;
|
return cachedData.value;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
window.lastGeckoRequest = currentTime;
|
||||||
|
const cachedData = cache.get(cacheKey);
|
||||||
|
if (cachedData) {
|
||||||
|
console.log('Using cached CoinGecko data');
|
||||||
|
return cachedData.value;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const existingCache = localStorage.getItem(cacheKey);
|
||||||
|
let fallbackData = null;
|
||||||
|
if (existingCache) {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(existingCache);
|
||||||
|
fallbackData = parsed.value;
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Failed to parse existing cache:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
const coinIds = config.coins
|
const coinIds = config.coins
|
||||||
.filter(coin => coin.usesCoinGecko)
|
.filter(coin => coin.usesCoinGecko)
|
||||||
.map(coin => coin.name)
|
.map(coin => coin.name)
|
||||||
.join(',');
|
.join(',');
|
||||||
const url = `${config.apiEndpoints.coinGecko}/simple/price?ids=${coinIds}&vs_currencies=usd,btc&include_24hr_vol=true&include_24hr_change=true&api_key=${config.apiKeys.coinGecko}`;
|
const url = `${config.apiEndpoints.coinGecko}/simple/price?ids=${coinIds}&vs_currencies=usd,btc&include_24hr_vol=true&include_24hr_change=true&api_key=${config.apiKeys.coinGecko}`;
|
||||||
//console.log(`Fetching data for multiple coins from CoinGecko: ${url}`);
|
const response = await api.makePostRequest(url, {
|
||||||
try {
|
'User-Agent': 'Mozilla/5.0',
|
||||||
const data = await api.makePostRequest(url);
|
'Accept': 'application/json',
|
||||||
//console.log(`Raw CoinGecko data:`, data);
|
'Accept-Language': 'en-US,en;q=0.5'
|
||||||
if (typeof data !== 'object' || data === null) {
|
});
|
||||||
throw new AppError(`Invalid data structure received from CoinGecko`);
|
if (typeof response !== 'object' || response === null) {
|
||||||
|
if (fallbackData) {
|
||||||
|
console.log('Using fallback data due to invalid response');
|
||||||
|
return fallbackData;
|
||||||
}
|
}
|
||||||
const transformedData = {};
|
throw new AppError(`Invalid data structure received from CoinGecko`);
|
||||||
Object.entries(data).forEach(([id, values]) => {
|
|
||||||
const coinConfig = config.coins.find(coin => coin.name === id);
|
|
||||||
const symbol = coinConfig?.symbol.toLowerCase() || id;
|
|
||||||
transformedData[symbol] = {
|
|
||||||
current_price: values.usd,
|
|
||||||
price_btc: values.btc,
|
|
||||||
total_volume: values.usd_24h_vol,
|
|
||||||
price_change_percentage_24h: values.usd_24h_change,
|
|
||||||
displayName: coinConfig?.displayName || coinConfig?.symbol || id
|
|
||||||
};
|
|
||||||
});
|
|
||||||
//console.log(`Transformed CoinGecko data:`, transformedData);
|
|
||||||
cache.set(cacheKey, transformedData);
|
|
||||||
return transformedData;
|
|
||||||
} catch (error) {
|
|
||||||
//console.error(`Error fetching CoinGecko data:`, error);
|
|
||||||
return { error: error.message };
|
|
||||||
}
|
}
|
||||||
},
|
if (response.error || response.Error) {
|
||||||
|
if (fallbackData) {
|
||||||
|
console.log('Using fallback data due to API error');
|
||||||
|
return fallbackData;
|
||||||
|
}
|
||||||
|
throw new AppError(response.error || response.Error);
|
||||||
|
}
|
||||||
|
const transformedData = {};
|
||||||
|
Object.entries(response).forEach(([id, values]) => {
|
||||||
|
const coinConfig = config.coins.find(coin => coin.name === id);
|
||||||
|
const symbol = coinConfig?.symbol.toLowerCase() || id;
|
||||||
|
transformedData[symbol] = {
|
||||||
|
current_price: values.usd,
|
||||||
|
price_btc: values.btc,
|
||||||
|
total_volume: values.usd_24h_vol,
|
||||||
|
price_change_percentage_24h: values.usd_24h_change,
|
||||||
|
displayName: coinConfig?.displayName || coinConfig?.symbol || id
|
||||||
|
};
|
||||||
|
});
|
||||||
|
cache.set(cacheKey, transformedData);
|
||||||
|
return transformedData;
|
||||||
|
|
||||||
fetchHistoricalDataXHR: async (coinSymbols) => {
|
} catch (error) {
|
||||||
if (!Array.isArray(coinSymbols)) {
|
console.error(`Error fetching CoinGecko data:`, error);
|
||||||
coinSymbols = [coinSymbols];
|
if (cachedData) {
|
||||||
|
console.log('Using expired cache data due to error');
|
||||||
|
return cachedData.value;
|
||||||
|
}
|
||||||
|
return { error: error.message };
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
//console.log(`Fetching historical data for coins: ${coinSymbols.join(', ')}`);
|
fetchHistoricalDataXHR: async (coinSymbols) => {
|
||||||
|
if (!Array.isArray(coinSymbols)) {
|
||||||
|
coinSymbols = [coinSymbols];
|
||||||
|
}
|
||||||
const results = {};
|
const results = {};
|
||||||
|
|
||||||
const fetchPromises = coinSymbols.map(async coin => {
|
const fetchPromises = coinSymbols.map(async coin => {
|
||||||
const coinConfig = config.coins.find(c => c.symbol === coin);
|
const coinConfig = config.coins.find(c => c.symbol === coin);
|
||||||
if (!coinConfig) {
|
if (!coinConfig) return;
|
||||||
//console.error(`Coin configuration not found for ${coin}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (coin === 'WOW') {
|
const cacheKey = `historical_${coin}_${config.currentResolution}`;
|
||||||
const url = `${config.apiEndpoints.coinGecko}/coins/wownero/market_chart?vs_currency=usd&days=1&api_key=${config.apiKeys.coinGecko}`;
|
const cachedData = cache.get(cacheKey);
|
||||||
//console.log(`CoinGecko URL for WOW: ${url}`);
|
if (cachedData) {
|
||||||
|
results[coin] = cachedData.value;
|
||||||
try {
|
return;
|
||||||
const response = await api.makePostRequest(url);
|
|
||||||
if (response && response.prices) {
|
|
||||||
results[coin] = response.prices;
|
|
||||||
} else {
|
|
||||||
//console.error(`Unexpected data structure for WOW:`, response);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`Error fetching CoinGecko data for WOW:`, error);
|
|
||||||
}
|
}
|
||||||
} else {
|
if (coin === 'WOW') {
|
||||||
const resolution = config.resolutions[config.currentResolution];
|
const url = `${config.apiEndpoints.coinGecko}/coins/wownero/market_chart?vs_currency=usd&days=1&api_key=${config.apiKeys.coinGecko}`;
|
||||||
let url;
|
try {
|
||||||
if (resolution.interval === 'hourly') {
|
const response = await api.makePostRequest(url);
|
||||||
url = `https://min-api.cryptocompare.com/data/v2/histohour?fsym=${coin}&tsym=USD&limit=${resolution.days * 24}&api_key=${config.apiKeys.cryptoCompare}`;
|
if (response && response.prices) {
|
||||||
|
results[coin] = response.prices;
|
||||||
|
cache.set(cacheKey, response.prices);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error fetching CoinGecko data for WOW:`, error);
|
||||||
|
if (cachedData) {
|
||||||
|
results[coin] = cachedData.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
url = `${config.apiEndpoints.cryptoCompareHistorical}?fsym=${coin}&tsym=USD&limit=${resolution.days}&api_key=${config.apiKeys.cryptoCompare}`;
|
const resolution = config.resolutions[config.currentResolution];
|
||||||
|
let url;
|
||||||
|
if (resolution.interval === 'hourly') {
|
||||||
|
url = `https://min-api.cryptocompare.com/data/v2/histohour?fsym=${coin}&tsym=USD&limit=${resolution.days * 24}&api_key=${config.apiKeys.cryptoCompare}`;
|
||||||
|
} else {
|
||||||
|
url = `${config.apiEndpoints.cryptoCompareHistorical}?fsym=${coin}&tsym=USD&limit=${resolution.days}&api_key=${config.apiKeys.cryptoCompare}`;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const response = await api.makePostRequest(url);
|
||||||
|
if (response.Response === "Error") {
|
||||||
|
console.error(`API Error for ${coin}:`, response.Message);
|
||||||
|
if (cachedData) {
|
||||||
|
results[coin] = cachedData.value;
|
||||||
|
}
|
||||||
|
} else if (response.Data && response.Data.Data) {
|
||||||
|
results[coin] = response.Data;
|
||||||
|
cache.set(cacheKey, response.Data);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error fetching CryptoCompare data for ${coin}:`, error);
|
||||||
|
if (cachedData) {
|
||||||
|
results[coin] = cachedData.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//console.log(`CryptoCompare URL for ${coin}: ${url}`);
|
|
||||||
try {
|
|
||||||
const response = await api.makePostRequest(url);
|
|
||||||
if (response.Response === "Error") {
|
|
||||||
//console.error(`API Error for ${coin}:`, response.Message);
|
|
||||||
} else if (response.Data && response.Data.Data) {
|
|
||||||
results[coin] = response.Data;
|
|
||||||
} else {
|
|
||||||
//console.error(`Unexpected data structure for ${coin}:`, response);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`Error fetching CryptoCompare data for ${coin}:`, error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
await Promise.all(fetchPromises);
|
await Promise.all(fetchPromises);
|
||||||
//console.log('Final results object:', JSON.stringify(results, null, 2));
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// CACHE
|
// CACHE
|
||||||
|
|
Loading…
Reference in a new issue