bulltrackers-module 1.0.721 → 1.0.723
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.
- package/functions/computation-system/data/CachedDataLoader.js +101 -102
- package/functions/computation-system/data/DependencyFetcher.js +48 -8
- package/functions/computation-system/persistence/ResultCommitter.js +158 -573
- package/functions/computation-system/utils/data_loader.js +253 -1088
- package/functions/core/utils/bigquery_utils.js +248 -112
- package/functions/etoro-price-fetcher/helpers/handler_helpers.js +4 -1
- package/functions/fetch-insights/helpers/handler_helpers.js +63 -65
- package/functions/fetch-popular-investors/helpers/fetch_helpers.js +143 -458
- package/functions/orchestrator/index.js +108 -141
- package/functions/root-data-indexer/index.js +130 -437
- package/index.js +0 -2
- package/package.json +3 -4
- package/functions/invalid-speculator-handler/helpers/handler_helpers.js +0 -38
- package/functions/speculator-cleanup-orchestrator/helpers/cleanup_helpers.js +0 -101
package/index.js
CHANGED
|
@@ -51,8 +51,6 @@ const computationUtils = require('./functions
|
|
|
51
51
|
const { createApiV2App } = require('./functions/api-v2/index');
|
|
52
52
|
|
|
53
53
|
// Maintenance & Data Acquisition
|
|
54
|
-
const { runCleanup } = require('./functions/speculator-cleanup-orchestrator/helpers/cleanup_helpers');
|
|
55
|
-
const { handleInvalidSpeculator } = require('./functions/invalid-speculator-handler/helpers/handler_helpers');
|
|
56
54
|
const { fetchAndStoreInsights } = require('./functions/fetch-insights/helpers/handler_helpers');
|
|
57
55
|
const { fetchAndStorePrices } = require('./functions/etoro-price-fetcher/helpers/handler_helpers');
|
|
58
56
|
const { runSocialOrchestrator } = require('./functions/social-orchestrator/helpers/orchestrator_helpers');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bulltrackers-module",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.723",
|
|
4
4
|
"description": "Helper Functions for Bulltrackers.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
@@ -11,8 +11,6 @@
|
|
|
11
11
|
"functions/computation-system/",
|
|
12
12
|
"functions/api-v2/",
|
|
13
13
|
"functions/dispatcher/",
|
|
14
|
-
"functions/invalid-speculator-handler/",
|
|
15
|
-
"functions/speculator-cleanup-orchestrator/",
|
|
16
14
|
"functions/fetch-insights/",
|
|
17
15
|
"functions/etoro-price-fetcher/",
|
|
18
16
|
"functions/appscript-api/",
|
|
@@ -56,7 +54,8 @@
|
|
|
56
54
|
"sharedsetup": "latest",
|
|
57
55
|
"zod": "^4.3.5",
|
|
58
56
|
"@google-cloud/storage": "^7.18.0",
|
|
59
|
-
"@google-cloud/bigquery": "^7.3.0"
|
|
57
|
+
"@google-cloud/bigquery": "^7.3.0",
|
|
58
|
+
"@google-cloud/tasks": "^5.0.0"
|
|
60
59
|
},
|
|
61
60
|
"devDependencies": {
|
|
62
61
|
"bulltracker-deployer": "file:../bulltracker-deployer"
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Main pipe: pipe.maintenance.handleInvalidSpeculator
|
|
3
|
-
* REFACTORED: Now stateless and receives dependencies.
|
|
4
|
-
*/
|
|
5
|
-
const { FieldValue } = require('@google-cloud/firestore');
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Main pipe: pipe.maintenance.handleInvalidSpeculator
|
|
9
|
-
* @param {object} message The Pub/Sub message.
|
|
10
|
-
* @param {object} context The message context.
|
|
11
|
-
* @param {object} config The configuration object.
|
|
12
|
-
* @param {object} dependencies - Contains db, logger.
|
|
13
|
-
*/
|
|
14
|
-
exports.handleInvalidSpeculator = async (message, context, config, dependencies) => {
|
|
15
|
-
const { db, logger } = dependencies;
|
|
16
|
-
try {
|
|
17
|
-
const { invalidCids } = JSON.parse(Buffer.from(message.data, 'base64').toString());
|
|
18
|
-
if (!invalidCids || invalidCids.length === 0) { logger.log('WARN', 'Received message with no invalid CIDs. Nothing to do.'); return; }
|
|
19
|
-
const collectionRef = db.collection(config.invalidSpeculatorsCollectionName);
|
|
20
|
-
const maxPerDoc = config.maxInvalidUsersPerDoc;
|
|
21
|
-
const querySnapshot = await collectionRef .where('userCount', '<', maxPerDoc) .limit(10) .get();
|
|
22
|
-
let targetDocRef;
|
|
23
|
-
if (!querySnapshot.empty) { const randomIndex = Math.floor(Math.random() * querySnapshot.docs.length); targetDocRef = querySnapshot.docs[randomIndex].ref;
|
|
24
|
-
} else { targetDocRef = collectionRef.doc(); }
|
|
25
|
-
await db.runTransaction(async (transaction) => { const doc = await transaction.get(targetDocRef);
|
|
26
|
-
const updates = {};
|
|
27
|
-
let newUsersCount = 0;
|
|
28
|
-
if (!doc.exists) { updates.userCount = 0; }
|
|
29
|
-
for (const cid of invalidCids) {
|
|
30
|
-
const fieldPath = `users.${cid}`;
|
|
31
|
-
if (!doc.exists || !doc.data().users || !doc.data().users[cid]) {updates[fieldPath] = true; newUsersCount++; } }
|
|
32
|
-
if (newUsersCount > 0) { updates.userCount = FieldValue.increment(newUsersCount); transaction.set(targetDocRef, updates, { merge: true }); } });
|
|
33
|
-
logger.log('SUCCESS', `Successfully stored ${invalidCids.length} invalid speculator IDs in document ${targetDocRef.id}.`);
|
|
34
|
-
} catch (error) {
|
|
35
|
-
logger.log('ERROR', 'FATAL Error in Invalid Speculator Handler', { errorMessage: error.message, errorStack: error.stack });
|
|
36
|
-
throw error;
|
|
37
|
-
}
|
|
38
|
-
};
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Main pipe: pipe.maintenance.runSpeculatorCleanup
|
|
3
|
-
* REFACTORED: Now stateless and receives dependencies.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const { FieldValue } = require('@google-cloud/firestore');
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Main pipe: pipe.maintenance.runSpeculatorCleanup
|
|
10
|
-
* Orchestrates the cleanup process.
|
|
11
|
-
* @param {object} config - Configuration object.
|
|
12
|
-
* @param {object} dependencies - Contains db, logger.
|
|
13
|
-
*/
|
|
14
|
-
exports.runCleanup = async (config, dependencies) => {
|
|
15
|
-
const { logger } = dependencies;
|
|
16
|
-
logger.log('INFO', '[CleanupHelpers] Running cleanup orchestrator...');
|
|
17
|
-
try { const { batch: batchAfterPending, count: pendingRemoved } = await cleanupPendingSpeculators(config, dependencies);
|
|
18
|
-
const { batch: finalBatch, count: staleRemoved } = await cleanupStaleSpeculators(config, dependencies, batchAfterPending);
|
|
19
|
-
if (pendingRemoved > 0 || staleRemoved > 0) { await finalBatch.commit(); logger.log('SUCCESS', `[CleanupHelpers] Cleanup commit successful. Removed ${pendingRemoved} pending, ${staleRemoved} stale speculators.`); return { pendingRemoved, staleRemoved };
|
|
20
|
-
} else { logger.log('SUCCESS', '[CleanupHelpers] No stale users found in pending or blocks.'); return { pendingRemoved: 0, staleRemoved: 0 }; }
|
|
21
|
-
} catch (error) { logger.log('ERROR', '[CleanupHelpers] FATAL error during cleanup orchestration', { errorMessage: error.message, errorStack: error.stack }); throw error; }
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Internal sub-pipe for cleaning pending speculators.
|
|
26
|
-
*/
|
|
27
|
-
async function cleanupPendingSpeculators(config, dependencies) {
|
|
28
|
-
const { db, logger } = dependencies;
|
|
29
|
-
logger.log('INFO', '[CleanupHelpers] Starting pending speculator cleanup...');
|
|
30
|
-
|
|
31
|
-
const batch = db.batch();
|
|
32
|
-
let stalePendingUsersRemoved = 0;
|
|
33
|
-
const pendingCollectionRef = db.collection(config.pendingSpeculatorsCollectionName);
|
|
34
|
-
const staleThreshold = new Date();
|
|
35
|
-
staleThreshold.setHours(staleThreshold.getHours() - config.pendingGracePeriodHours);
|
|
36
|
-
|
|
37
|
-
try {
|
|
38
|
-
const pendingSnapshot = await pendingCollectionRef.get();
|
|
39
|
-
if (pendingSnapshot.empty) { logger.log('INFO', '[CleanupHelpers] Pending speculators collection is empty.'); return { batch, count: 0 }; }
|
|
40
|
-
|
|
41
|
-
for (const doc of pendingSnapshot.docs) {
|
|
42
|
-
const pendingData = doc.data().users || {};
|
|
43
|
-
const updates = {};
|
|
44
|
-
let updatesInDoc = 0;
|
|
45
|
-
|
|
46
|
-
for (const userId in pendingData) {
|
|
47
|
-
const timestamp = pendingData[userId]?.toDate ? pendingData[userId].toDate() : null;
|
|
48
|
-
if (timestamp && timestamp < staleThreshold) { updates[`users.${userId}`] = FieldValue.delete(); stalePendingUsersRemoved++; updatesInDoc++; } }
|
|
49
|
-
|
|
50
|
-
if (updatesInDoc > 0) { logger.log('TRACE', `[CleanupHelpers] Marking ${updatesInDoc} users for removal from pending doc ${doc.id}`); batch.update(doc.ref, updates); } }
|
|
51
|
-
logger.log('INFO', `[CleanupHelpers] Marked ${stalePendingUsersRemoved} total stale pending users for removal.`);
|
|
52
|
-
} catch (error) { logger.log('ERROR', '[CleanupHelpers] Error cleaning pending speculators', { errorMessage: error.message }); throw error; }
|
|
53
|
-
return { batch, count: stalePendingUsersRemoved };
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Internal sub-pipe for cleaning stale speculators.
|
|
58
|
-
*/
|
|
59
|
-
async function cleanupStaleSpeculators(config, dependencies, batch) {
|
|
60
|
-
const { db, logger } = dependencies;
|
|
61
|
-
logger.log('INFO', '[CleanupHelpers] Starting stale speculator cleanup from blocks...');
|
|
62
|
-
let totalUsersRemoved = 0;
|
|
63
|
-
const blocksCollectionRef = db.collection(config.speculatorBlocksCollectionName);
|
|
64
|
-
const gracePeriodDate = new Date();
|
|
65
|
-
gracePeriodDate.setDate(gracePeriodDate.getDate() - config.activityGracePeriodDays);
|
|
66
|
-
const blockCountsUpdate = {};
|
|
67
|
-
|
|
68
|
-
try {
|
|
69
|
-
const blocksSnapshot = await blocksCollectionRef.get();
|
|
70
|
-
if (blocksSnapshot.empty) { logger.log('INFO', '[CleanupHelpers] Speculator blocks collection is empty.'); return { batch, count: 0 }; }
|
|
71
|
-
|
|
72
|
-
for (const doc of blocksSnapshot.docs) {
|
|
73
|
-
const blockId = doc.id;
|
|
74
|
-
const blockData = doc.data();
|
|
75
|
-
const users = blockData.users || {};
|
|
76
|
-
let usersRemovedFromBlock = 0;
|
|
77
|
-
const updates = {};
|
|
78
|
-
|
|
79
|
-
for (const userKey in users) {
|
|
80
|
-
const userId = userKey.split('.')[1];
|
|
81
|
-
if (!userId) continue;
|
|
82
|
-
|
|
83
|
-
const userData = users[userKey];
|
|
84
|
-
const lastHeldTimestamp = userData.lastHeldSpeculatorAsset?.toDate ? userData.lastHeldSpeculatorAsset.toDate() : null;
|
|
85
|
-
|
|
86
|
-
if (lastHeldTimestamp && lastHeldTimestamp < gracePeriodDate) { updates[userKey] = FieldValue.delete(); usersRemovedFromBlock++;
|
|
87
|
-
|
|
88
|
-
if (userData.instruments && Array.isArray(userData.instruments)) {
|
|
89
|
-
userData.instruments.forEach(instrumentId => { const instrumentBlockKey = `${instrumentId}_${blockId}`; if (!blockCountsUpdate[instrumentBlockKey]) { blockCountsUpdate[instrumentBlockKey] = 0; } blockCountsUpdate[instrumentBlockKey]--; }); } } }
|
|
90
|
-
if (usersRemovedFromBlock > 0) { logger.log('TRACE', `[CleanupHelpers] Marking ${usersRemovedFromBlock} users for removal from block ${blockId}.`); batch.update(doc.ref, updates); totalUsersRemoved += usersRemovedFromBlock; } }
|
|
91
|
-
|
|
92
|
-
if (totalUsersRemoved > 0 && Object.keys(blockCountsUpdate).length > 0) {
|
|
93
|
-
const countsRef = db.doc(config.speculatorBlockCountsDocPath);
|
|
94
|
-
const finalCountUpdates = {};
|
|
95
|
-
for (const key in blockCountsUpdate) { finalCountUpdates[`counts.${key}`] = FieldValue.increment(blockCountsUpdate[key]); }
|
|
96
|
-
logger.log('TRACE', '[CleanupHelpers] Staging block count decrements.', { updates: finalCountUpdates });
|
|
97
|
-
batch.set(countsRef, finalCountUpdates, { merge: true }); }
|
|
98
|
-
logger.log('INFO', `[CleanupHelpers] Marked ${totalUsersRemoved} total stale speculators for removal from blocks.`);
|
|
99
|
-
} catch (error) { logger.log('ERROR', '[CleanupHelpers] Error cleaning stale speculators', { errorMessage: error.message }); throw error; }
|
|
100
|
-
return { batch, count: totalUsersRemoved };
|
|
101
|
-
}
|