1. /**
  2. * Configures API endpoints with rate limiting.
  3. *
  4. * @param {object} config - Configuration object containing API endpoint definitions and rate limits.
  5. * @returns {object} - An object containing functions to access API endpoints with rate limiting.
  6. */
  7. function configureAPIs(config) {
  8. const apiEndpoints = {}; // Store API endpoints with rate limits
  9. // Validate config
  10. if (!config || typeof config !== 'object') {
  11. console.error("Invalid config provided. Must be an object.");
  12. return { };
  13. }
  14. for (const endpointName in config) {
  15. if (config.hasOwnProperty(endpointName)) {
  16. const endpoint = config[endpointName];
  17. if (typeof endpoint !== 'object' || !endpoint.url || !endpoint.rateLimit) {
  18. console.warn(`Invalid endpoint configuration for ${endpointName}. Skipping.`);
  19. continue;
  20. }
  21. apiEndpoints[endpointName] = {
  22. url: endpoint.url,
  23. rateLimit: endpoint.rateLimit,
  24. tokens: endpoint.rateLimit.max, // Initialize tokens
  25. resetTime: null,
  26. lock: false, // prevent concurrent requests
  27. acquire: async () => {
  28. // Wait until tokens are available
  29. while (apiEndpoints[endpointName].lock) {
  30. await new Promise(resolve => setTimeout(resolve, 10)); // Small delay
  31. }
  32. if (apiEndpoints[endpointName].tokens <= 0) {
  33. const now = Date.now();
  34. const nextAvailable = apiEndpoints[endpointName].resetTime || now + (1000 / apiEndpoints[endpointName].rateLimit.refetchInterval);
  35. if (nextAvailable > now) {
  36. // Wait until tokens are refilled
  37. await new Promise(resolve => setTimeout(resolve, nextAvailable - now));
  38. }
  39. }
  40. apiEndpoints[endpointName].tokens--;
  41. apiEndpoints[endpointName].lock = true;
  42. return;
  43. },
  44. release: () => {
  45. apiEndpoints[endpointName].tokens++;
  46. apiEndpoints[endpointName].lock = false;
  47. },
  48. fetch: async (data = {}) => {
  49. await apiEndpoints[endpointName].acquire(); // Acquire a token before fetching
  50. try {
  51. const response = await fetch(apiEndpoints[endpointName].url, {
  52. method: 'POST', // or GET, PUT, DELETE, etc.
  53. headers: {
  54. 'Content-Type': 'application/json',
  55. // Add other headers as needed
  56. },
  57. body: JSON.stringify(data), // or other data format
  58. });
  59. if (!response.ok) {
  60. throw new Error(`HTTP error! status: ${response.status}`);
  61. }
  62. const json = await response.json();
  63. return json;
  64. } catch (error) {
  65. console.error(`Error fetching from ${endpointName}:`, error);
  66. throw error; // Re-throw the error
  67. } finally {
  68. apiEndpoints[endpointName].release(); // Release the token after fetching
  69. }
  70. },
  71. resetTokens: () => {
  72. apiEndpoints[endpointName].tokens = apiEndpoints[endpointName].rateLimit.max;
  73. apiEndpoints[endpointName].resetTime = null;
  74. }
  75. };
  76. }
  77. }
  78. return { apiEndpoints };
  79. }
  80. export default configureAPIs;

Add your comment