bulltrackers-module 1.0.351 → 1.0.352

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,132 @@
1
+ /**
2
+ * @fileoverview Logic for fetching and storing Popular Investor rankings.
3
+ * Integrates IntelligentProxyManager for IP rotation and IntelligentHeaderManager for
4
+ * user-agent/header rotation and performance tracking.
5
+ */
6
+ const { IntelligentProxyManager } = require('../../core/utils/intelligent_proxy_manager');
7
+ const { IntelligentHeaderManager } = require('../../core/utils/intelligent_header_manager');
8
+
9
+ /**
10
+ * Fetches the top Popular Investors and stores the raw result in Firestore.
11
+ * @param {object} dependencies - Contains db, logger.
12
+ * @param {object} config - Configuration object.
13
+ * @param {string} config.rankingsApiUrl - The eToro Rankings API URL.
14
+ * @param {string} config.rankingsCollectionName - e.g., 'popular_investor_rankings'.
15
+ * @param {object} config.proxyConfig - Configuration for the IntelligentProxyManager.
16
+ * @param {object} config.headerConfig - Configuration for the IntelligentHeaderManager.
17
+ */
18
+ async function fetchAndStorePopularInvestors(dependencies, config) {
19
+ const { db, logger } = dependencies;
20
+ const { rankingsApiUrl, rankingsCollectionName, proxyConfig, headerConfig } = config;
21
+
22
+ if (!rankingsApiUrl || !rankingsCollectionName || !proxyConfig || !headerConfig) {
23
+ throw new Error("[PopularInvestorFetch] Missing required config (rankingsApiUrl, rankingsCollectionName, proxyConfig, headerConfig).");
24
+ }
25
+
26
+ const today = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
27
+ logger.log('INFO', `[PopularInvestorFetch] Starting fetch for date: ${today}`);
28
+
29
+ // 1. Initialize Managers
30
+ const headerManager = new IntelligentHeaderManager(db, logger, headerConfig);
31
+ const proxyManager = new IntelligentProxyManager(db, logger, proxyConfig);
32
+
33
+ let data = null;
34
+ let fetchSuccess = false;
35
+ let selectedHeaderId = 'fallback';
36
+
37
+ try {
38
+ // 2. Select the best performing header
39
+ const { id, header } = await headerManager.selectHeader();
40
+ selectedHeaderId = id;
41
+
42
+ logger.log('INFO', `[PopularInvestorFetch] Selected header configuration: ${id}`);
43
+
44
+ // Merge selected headers with specific API requirements
45
+ // We prioritize the dynamic headers but ensure critical fields like Accept exist
46
+ const requestHeaders = {
47
+ 'Accept': 'application/json',
48
+ 'Referer': 'https://www.etoro.com/',
49
+ ...header
50
+ };
51
+
52
+ // 3. Attempt Fetch via Proxy Manager
53
+ try {
54
+ logger.log('INFO', '[PopularInvestorFetch] Attempting fetch via Proxy Manager...');
55
+
56
+ const response = await proxyManager.fetch(rankingsApiUrl, {
57
+ method: 'GET',
58
+ headers: requestHeaders
59
+ });
60
+
61
+ if (response.ok) {
62
+ data = await response.json();
63
+ fetchSuccess = true;
64
+ logger.log('SUCCESS', '[PopularInvestorFetch] Successfully fetched data via Proxy.');
65
+ } else {
66
+ logger.log('WARN', `[PopularInvestorFetch] Proxy fetch failed with status ${response.status}.`);
67
+ }
68
+ } catch (proxyError) {
69
+ logger.log('ERROR', '[PopularInvestorFetch] Error during Proxy Manager execution.', { errorMessage: proxyError.message });
70
+ }
71
+
72
+ // 4. Fallback: Direct Fetch (if Proxy failed)
73
+ if (!data) {
74
+ logger.log('WARN', '[PopularInvestorFetch] Falling back to Direct Node Fetch...');
75
+ try {
76
+ const directResponse = await fetch(rankingsApiUrl, {
77
+ method: 'GET',
78
+ headers: requestHeaders
79
+ });
80
+
81
+ if (directResponse.ok) {
82
+ data = await directResponse.json();
83
+ fetchSuccess = true;
84
+ logger.log('SUCCESS', '[PopularInvestorFetch] Successfully fetched data via Direct Fetch.');
85
+ } else {
86
+ throw new Error(`Direct fetch failed with status: ${directResponse.status}`);
87
+ }
88
+ } catch (directError) {
89
+ logger.log('ERROR', '[PopularInvestorFetch] Direct fetch failed.', { errorMessage: directError.message });
90
+ }
91
+ }
92
+
93
+ } catch (error) {
94
+ logger.log('ERROR', '[PopularInvestorFetch] Critical error in fetch orchestration.', { errorMessage: error.message });
95
+ } finally {
96
+ // 5. Update Header Performance (Reinforcement Learning)
97
+ // This ensures the system "learns" which headers are getting blocked vs accepted
98
+ logger.log('INFO', `[PopularInvestorFetch] Updating header performance for ${selectedHeaderId}: Success=${fetchSuccess}`);
99
+ headerManager.updatePerformance(selectedHeaderId, fetchSuccess);
100
+ await headerManager.flushPerformanceUpdates();
101
+ }
102
+
103
+ // 6. Final Validation & Storage
104
+ if (data && data.Items && Array.isArray(data.Items)) {
105
+ try {
106
+ const docRef = db.collection(rankingsCollectionName).doc(today);
107
+
108
+ await docRef.set({
109
+ fetchedAt: new Date(),
110
+ totalRows: data.TotalRows,
111
+ itemsCount: data.Items.length,
112
+ ...data
113
+ });
114
+
115
+ logger.log('SUCCESS', `[PopularInvestorFetch] Stored ${data.TotalRows} rankings into ${rankingsCollectionName}/${today}`);
116
+ return { success: true, count: data.TotalRows };
117
+
118
+ } catch (dbError) {
119
+ logger.log('ERROR', '[PopularInvestorFetch] Failed to write to Firestore.', { errorMessage: dbError.message });
120
+ throw dbError;
121
+ }
122
+ } else {
123
+ const errorMsg = fetchSuccess
124
+ ? '[PopularInvestorFetch] Fetched data format is invalid (missing Items array).'
125
+ : '[PopularInvestorFetch] Failed to fetch data from all sources.';
126
+
127
+ logger.log('ERROR', errorMsg);
128
+ throw new Error(errorMsg);
129
+ }
130
+ }
131
+
132
+ module.exports = { fetchAndStorePopularInvestors };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @fileoverview Entry point for the Popular Investor Fetcher module.
3
+ */
4
+ const { fetchAndStorePopularInvestors } = require('./helpers/fetch_helpers');
5
+
6
+ module.exports = {
7
+ runPopularInvestorFetch: fetchAndStorePopularInvestors
8
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bulltrackers-module",
3
- "version": "1.0.351",
3
+ "version": "1.0.352",
4
4
  "description": "Helper Functions for Bulltrackers.",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -19,7 +19,8 @@
19
19
  "functions/social-orchestrator/",
20
20
  "functions/social-task-handler/",
21
21
  "functions/price-backfill/",
22
- "functions/root-data-indexer/"
22
+ "functions/root-data-indexer/",
23
+ "functions/fetch-popular-investors"
23
24
  ],
24
25
  "keywords": [
25
26
  "bulltrackers",