From f1aaf8419763ffda2ee9899240ac90e7ba7e8964 Mon Sep 17 00:00:00 2001 From: Benoit Lavenier <benoit.lavenier@e-is.pro> Date: Mon, 14 Aug 2023 08:08:04 +0200 Subject: [PATCH] fix(bma): Apply the workaround of Duniter request limit per IP only on some requests --- www/js/services/bma-services.js | 115 +++++++++++++++----------------- 1 file changed, 54 insertions(+), 61 deletions(-) diff --git a/www/js/services/bma-services.js b/www/js/services/bma-services.js index 982a0565..61e63d8c 100644 --- a/www/js/services/bma-services.js +++ b/www/js/services/bma-services.js @@ -204,7 +204,42 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. return wrappedRequest; } - function incrementGetPathCount(path, limitRequestCount) { + function get(path, cacheTime, forcedTimeout) { + var request = getCacheable(path, cacheTime, forcedTimeout); + + var execCount = 1; + var wrappedRequest = function(params) { + return request(params) + .then(function(res) { + execCount--; + return res; + }) + .catch(function(err){ + // If node return too many requests error + if (err && err.ucode === exports.errorCodes.HTTP_LIMITATION) { + // If max number of retry not reach + if (execCount <= exports.constants.LIMIT_REQUEST_COUNT) { + if (execCount === 1) { + console.warn("[BMA] Too many HTTP requests: Will wait then retry..."); + // Update the loading message (if exists) + UIUtils.loading.update({template: "COMMON.LOADING_WAIT"}); + } + // Wait 1s then retry + return $timeout(function() { + execCount++; + return wrappedRequest(params); // Loop + }, exports.constants.LIMIT_REQUEST_DELAY); + } + } + throw err; + }); + } + return wrappedRequest; + } + + + + function incrementGetUsageCount(path, limitRequestCount) { limitRequestCount = limitRequestCount || constants.LIMIT_REQUEST_COUNT; // Wait if too many requests on this path if (that.raw.getCountByPath[path] >= limitRequestCount) { @@ -213,7 +248,7 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. //console.debug("[BMA] Delaying request '{0}' to avoid a quota error...".format(path)); return $timeout(function() { - return incrementGetPathCount(path, limitRequestCount); + return incrementGetUsageCount(path, limitRequestCount); }, constants.LIMIT_REQUEST_DELAY); } @@ -232,7 +267,16 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. } } - function get(path, cacheTime, forcedTimeout, limitRequestCount) { + /** + * Allow to call GET requests, with a limited rate (in Duniter node). Parallel execution will be done, + * until the max limitRequestCount, then BMA will wait few times, and continue. + * @param path + * @param cacheTime + * @param forcedTimeout + * @param limitRequestCount + * @returns {function(*): *} + */ + function getHighUsage(path, cacheTime, forcedTimeout, limitRequestCount) { limitRequestCount = limitRequestCount || constants.LIMIT_REQUEST_COUNT; that.raw.getCountByPath[path] = that.raw.getCountByPath[path] || 0; @@ -241,7 +285,7 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. var wrappedRequest = function(params) { var start = Date.now(); - return incrementGetPathCount(path, limitRequestCount) + return incrementGetUsageCount(path, limitRequestCount) .then(function() { return request(params); }) @@ -336,7 +380,7 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. } return isCompatible; }) - .catch(function(err) { + .catch(function() { return false; // Unreachable }); }; @@ -538,7 +582,7 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. network: { peering: { self: get('/network/peering'), - peers: get('/network/peering/peers', null, null, 10) + peers: getHighUsage('/network/peering/peers', null, null, 10) }, peers: get('/network/peers'), ws2p: { @@ -581,7 +625,7 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. } }, tx: { - sources: get('/tx/sources/:pubkey', csCache.constants.SHORT, constants.TIMEOUT.VERY_LONG), + sources: get('/tx/sources/:pubkey', csCache.constants.SHORT), process: post('/tx/process'), history: { all: function(params) { @@ -632,8 +676,8 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. }, tx: { history: { - timesWithCache: get('/tx/history/:pubkey/times/:from/:to', csCache.constants.LONG), - times: get('/tx/history/:pubkey/times/:from/:to'), + timesWithCache: getHighUsage('/tx/history/:pubkey/times/:from/:to', csCache.constants.LONG), + times: getHighUsage('/tx/history/:pubkey/times/:from/:to'), all: get('/tx/history/:pubkey') } }, @@ -938,7 +982,7 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. /** * Return all expected blocks - * @param blockNumbers a rray of block number + * @param leaves */ exports.network.peering.peersByLeaves = function(leaves){ return $q.all(leaves.map(function(leaf) { @@ -946,57 +990,6 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. })); }; - exports.raw.getHttpRecursive = function(httpGetRequest, paramName, paramValues, offset, size) { - offset = angular.isDefined(offset) ? offset : 0; - size = size || exports.constants.LIMIT_REQUEST_COUNT; - return $q(function(resolve, reject) { - var result = []; - var jobs = []; - var chunk = paramValues.slice(offset, offset+size); - _.each(chunk, function(paramValue) { - var requestParams = {}; - requestParams[paramName] = paramValue; - jobs.push( - httpGetRequest(requestParams) - .then(function(res){ - if (!res) return; - result.push(res); - }) - ); - }); - - $q.all(jobs) - .then(function() { - if (offset < paramValues.length - 1) { - $timeout(function() { - exports.raw.getHttpRecursive(httpGetRequest, paramName, paramValues, offset+size, size) - .then(function(res) { - if (!res || !res.length) { - resolve(result); - return; - } - - resolve(result.concat(res)); - }) - .catch(function(err) { - reject(err); - }); - }, exports.constants.LIMIT_REQUEST_DELAY); - } - else { - resolve(result); - } - }) - .catch(function(err){ - if (err && err.ucode === exports.errorCodes.HTTP_LIMITATION) { - resolve(result); - } - else { - reject(err); - } - }); - }); - }; exports.blockchain.lastUd = function() { return exports.blockchain.stats.ud() -- GitLab