bulltrackers-module 1.0.18 → 1.0.19

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,95 @@
1
+ /**
2
+ * @fileoverview Core logic for fetching eToro instrument insights.
3
+ */
4
+
5
+ const { FieldValue } = require('@google-cloud/firestore');
6
+
7
+ /**
8
+ * Fetches insights data using header and proxy managers and stores it in Firestore.
9
+ *
10
+ * @param {object} firestore - An initialized Firestore client instance.
11
+ * @param {object} logger - A logger instance.
12
+ * @param {object} headerManager - An initialized IntelligentHeaderManager instance.
13
+ * @param {object} proxyManager - An initialized IntelligentProxyManager instance.
14
+ * @param {object} config - Configuration object.
15
+ * @param {string} config.etoroInsightsUrl - The URL for the eToro insights API.
16
+ * @param {string} config.insightsCollectionName - Firestore collection name for results.
17
+ * @returns {Promise<{success: boolean, message: string, instrumentCount?: number}>}
18
+ */
19
+ exports.fetchAndStoreInsights = async (firestore, logger, headerManager, proxyManager, config) => {
20
+ logger.log('INFO', '[FetchInsightsHelpers] Starting eToro insights data fetch...');
21
+ let selectedHeader = null;
22
+ let wasSuccessful = false;
23
+
24
+ try {
25
+ // Validate config
26
+ if (!config.etoroInsightsUrl || !config.insightsCollectionName) {
27
+ throw new Error("Missing required configuration: etoroInsightsUrl or insightsCollectionName.");
28
+ }
29
+
30
+ selectedHeader = await headerManager.selectHeader();
31
+ if (!selectedHeader) {
32
+ throw new Error("Could not select a header for the request.");
33
+ }
34
+
35
+ logger.log('INFO', `[FetchInsightsHelpers] Using header ID: ${selectedHeader.id}`, {
36
+ userAgent: selectedHeader.header['User-Agent'] // Access header data correctly
37
+ });
38
+
39
+ // Make the API request via the proxy manager
40
+ // Pass only the necessary parts of the selected header object
41
+ const fetchOptions = {
42
+ headers: selectedHeader.header, // Pass the actual header object
43
+ timeout: 30000 // 30 second timeout - Note: Proxy manager might have its own timeout logic
44
+ };
45
+ const { response } = await proxyManager.fetch(config.etoroInsightsUrl, fetchOptions);
46
+
47
+ if (!response.ok) {
48
+ const errorText = await response.text();
49
+ // No need to update header performance here, proxy manager handles failures implicitly if needed
50
+ throw new Error(`API request failed via proxy with status ${response.status}: ${errorText}`);
51
+ }
52
+
53
+ // If fetch succeeded via proxy, mark header as successful
54
+ wasSuccessful = true; // Mark success for header update
55
+
56
+ const insightsData = await response.json();
57
+
58
+ if (!Array.isArray(insightsData) || insightsData.length === 0) {
59
+ throw new Error('API returned empty or invalid data.');
60
+ }
61
+
62
+ // Store in Firestore
63
+ const today = new Date().toISOString().slice(0, 10);
64
+ const docRef = firestore.collection(config.insightsCollectionName).doc(today);
65
+
66
+ const firestorePayload = {
67
+ fetchedAt: FieldValue.serverTimestamp(),
68
+ instrumentCount: insightsData.length,
69
+ insights: insightsData
70
+ };
71
+
72
+ await docRef.set(firestorePayload);
73
+
74
+ const successMsg = `Successfully fetched and stored ${insightsData.length} instrument insights for ${today}.`;
75
+ logger.log('SUCCESS', `[FetchInsightsHelpers] ${successMsg}`, {
76
+ documentId: today,
77
+ instrumentCount: insightsData.length
78
+ });
79
+ return { success: true, message: successMsg, instrumentCount: insightsData.length };
80
+
81
+ } catch (error) {
82
+ logger.log('ERROR', '[FetchInsightsHelpers] Error fetching eToro insights', {
83
+ errorMessage: error.message,
84
+ errorStack: error.stack,
85
+ headerId: selectedHeader ? selectedHeader.id : 'not-selected'
86
+ });
87
+ // Let the calling function handle header update on failure
88
+ throw error; // Re-throw the error to be caught by the handler
89
+ } finally {
90
+ // Update header performance based on the success *of the target API call*
91
+ if (selectedHeader) {
92
+ await headerManager.updatePerformance(selectedHeader.id, wasSuccessful);
93
+ }
94
+ }
95
+ };
@@ -0,0 +1,57 @@
1
+ /**
2
+ * @fileoverview Exports the FetchInsights handler creator.
3
+ */
4
+
5
+ const { Firestore } = require('@google-cloud/firestore');
6
+ const { logger } = require("sharedsetup")(__filename);
7
+ const { IntelligentHeaderManager, IntelligentProxyManager } = require('../core/utils');
8
+ const { fetchAndStoreInsights } = require('./helpers/handler_helpers');
9
+
10
+ /**
11
+ * Creates the Cloud Function handler for fetching eToro insights.
12
+ * @param {object} config - The configuration object loaded from the calling function's context.
13
+ * @returns {Function} The async Cloud Function handler (Express middleware format).
14
+ */
15
+ function createFetchInsightsHandler(config) {
16
+ // Initialize clients once when the function instance starts
17
+ const firestore = new Firestore();
18
+ const headerManager = new IntelligentHeaderManager(firestore, logger, config); // Pass dependencies
19
+ const proxyManager = new IntelligentProxyManager(firestore, logger, config); // Pass dependencies
20
+
21
+ return async (req, res) => {
22
+ logger.log('INFO', '🚀 Fetch eToro Insights triggered via module...');
23
+ try {
24
+ // Delegate all logic to the helper
25
+ const result = await fetchAndStoreInsights(firestore, logger, headerManager, proxyManager, config);
26
+
27
+ // Send success response
28
+ res.status(200).send(result.message);
29
+
30
+ } catch (error) {
31
+ logger.log('ERROR', 'FATAL Error in Fetch eToro Insights (Module)', { errorMessage: error.message, errorStack: error.stack });
32
+ // Header performance update on failure is handled within the helper's finally block if header was selected
33
+
34
+ // Ensure header performance flush happens even on fatal error before responding
35
+ try {
36
+ await headerManager.flushPerformanceUpdates();
37
+ } catch (flushError) {
38
+ logger.log('ERROR', 'Error flushing header performance during error handling', { flushError: flushError.message });
39
+ }
40
+
41
+ // Send error response
42
+ res.status(500).send(`An internal error occurred: ${error.message}`);
43
+ } finally {
44
+ // Always attempt to flush performance updates at the end of the function execution
45
+ try {
46
+ await headerManager.flushPerformanceUpdates();
47
+ } catch (flushError) {
48
+ logger.log('ERROR', 'Error flushing header performance in final finally block', { flushError: flushError.message });
49
+ }
50
+ }
51
+ };
52
+ }
53
+
54
+ module.exports = {
55
+ createFetchInsightsHandler,
56
+ helpers: { fetchAndStoreInsights } // Export helpers if needed directly
57
+ };
package/index.js CHANGED
@@ -12,6 +12,7 @@ const GenericAPI = require('./functions/generic-api'); // <-- ADD THIS
12
12
  const Dispatcher = require('./functions/dispatcher'); // <-- ADD THIS
13
13
  const InvalidSpeculatorHandler = require('./functions/invalid-speculator-handler'); // <-- ADD THIS
14
14
  const SpeculatorCleanupOrchestrator = require('./functions/speculator-cleanup-orchestrator'); // <-- ADD THIS
15
+ const FetchInsights = require('./functions/fetch-insights'); // <-- ADD THIS
15
16
 
16
17
  module.exports = {
17
18
  core,
@@ -21,5 +22,6 @@ module.exports = {
21
22
  GenericAPI, // <-- AND ADD THIS
22
23
  Dispatcher, // <-- AND ADD THIS
23
24
  InvalidSpeculatorHandler, // <-- AND ADD THIS
24
- SpeculatorCleanupOrchestrator // <-- AND ADD THIS
25
+ SpeculatorCleanupOrchestrator, // <-- AND ADD THIS
26
+ FetchInsights, // <-- AND ADD THIS
25
27
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bulltrackers-module",
3
- "version": "1.0.18",
3
+ "version": "1.0.19",
4
4
  "description": "Helper Functions for Bulltrackers.",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -12,7 +12,8 @@
12
12
  "functions/generic-api/",
13
13
  "functions/dispatcher/",
14
14
  "functions/invalid-speculator-handler/",
15
- "functions/speculator-cleanup-orchestrator/"
15
+ "functions/speculator-cleanup-orchestrator/",
16
+ "functions/fetch-insights/"
16
17
  ],
17
18
  "scripts": {
18
19
  "test": "echo \"Error: no test specified\" && exit 1"