110 lines
4.8 KiB
JavaScript
110 lines
4.8 KiB
JavaScript
// proxy/collector.js
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
// Core data collection orchestrator for the BackOne Proxy Server
|
|
// All data is stored in MongoDB, tagged with agent_uuid + site_uuid.
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
const path = require('path');
|
|
require('dotenv').config({ path: path.join(__dirname, '..', '.env.local') });
|
|
|
|
const backone = require('./backoneClient');
|
|
const { AgentRegistry } = require('./models/Schemas');
|
|
const { pruneOldData } = require('./dataRetention');
|
|
const { collectForAgent, collectSiteSummary } = require('./collectorCore');
|
|
|
|
const SITE_UUIDS_STR = process.env.BACKONE_SITE_UUIDS || process.env.BACKONE_SITE_UUID;
|
|
const SITE_UUIDS = SITE_UUIDS_STR ? SITE_UUIDS_STR.split(',').map(s => s.trim()).filter(Boolean) : [];
|
|
|
|
async function collectAllAgents() {
|
|
const timestamp = new Date();
|
|
const timeString = timestamp.toLocaleString('id-ID', { timeZone: 'Asia/Jakarta' }) + ' WIB';
|
|
console.log(`[Collector] === MODE: ALL AGENTS === Started at ${timeString}`);
|
|
|
|
const results = [];
|
|
|
|
console.log(`[Collector] Fetching ALL agents globally...`);
|
|
const rawAgents = await backone.fetchAgents(null);
|
|
|
|
if (!rawAgents || rawAgents.length === 0) {
|
|
console.warn(`[Collector] No agents found globally.`);
|
|
return { success: false, mode: 'all', message: 'No agents found', results: [] };
|
|
}
|
|
|
|
const agents = rawAgents.filter(a => a && a.uuid);
|
|
const totalAgents = agents.length;
|
|
console.log(`[Collector] Processing ${totalAgents} unique agents globally`);
|
|
|
|
// Step 1: Upsert technical metadata only (NEVER touch label field during updates)
|
|
// This prevents ANY version of proxy from overwriting a custom label set by the UI.
|
|
await Promise.allSettled(agents.map(a =>
|
|
AgentRegistry.findOneAndUpdate(
|
|
{ uuid: a.uuid },
|
|
{
|
|
$set: {
|
|
uuid: a.uuid,
|
|
serial: a.serial || a.uuid,
|
|
site_uuid: 'global',
|
|
provisioned: a.provisioned ?? true,
|
|
activated: a.activated ?? false,
|
|
last_seen_at: a.last_seen_at ?? null,
|
|
},
|
|
},
|
|
{ upsert: true, new: true }
|
|
)
|
|
));
|
|
|
|
// Step 2: Set default label ONLY for agents that have no label yet (brand new agents).
|
|
// We NEVER overwrite an existing label — even if it was set by an older proxy version.
|
|
await Promise.allSettled(agents.map(a =>
|
|
AgentRegistry.updateOne(
|
|
{ uuid: a.uuid, $or: [{ label: { $exists: false } }, { label: null }, { label: '' }] },
|
|
{ $set: { label: a.label } }
|
|
)
|
|
));
|
|
console.log(`[Collector] ✓ ${agents.length} agents upserted into registry globally`);
|
|
|
|
for (const agent of agents) {
|
|
const result = await collectForAgent(agent.uuid, timestamp, 'global');
|
|
results.push({ ...result, agent_label: agent.label, site_uuid: 'global' });
|
|
}
|
|
|
|
const successful = results.filter(r => r.success).length;
|
|
console.log(`[Collector] === ALL AGENTS DONE === ${successful}/${totalAgents} successful across global scope`);
|
|
|
|
await pruneOldData().catch(err => console.error('[Collector] [Retention] error:', err.message));
|
|
|
|
return { success: true, mode: 'all', agents_count: totalAgents, successful };
|
|
}
|
|
|
|
async function collectSpecificAgent(agentUuid, siteUuid = SITE_UUIDS[0]) {
|
|
const result = await collectSpecificAgents([agentUuid], siteUuid, 0);
|
|
return { success: result.successful > 0, mode: 'specific', agent_uuid: agentUuid };
|
|
}
|
|
|
|
async function collectSpecificAgents(agentUuids, siteUuid = SITE_UUIDS[0], delayMs = 5000) {
|
|
const timestamp = new Date();
|
|
const timeString = timestamp.toLocaleString('id-ID', { timeZone: 'Asia/Jakarta' }) + ' WIB';
|
|
console.log(`[Collector] === MODE: SPECIFIC AGENTS [${agentUuids.join(', ')}] === Started at ${timeString}`);
|
|
const results = [];
|
|
for (let i = 0; i < agentUuids.length; i++) {
|
|
if (i > 0) {
|
|
console.log(`[Collector] Waiting ${delayMs}ms before next agent...`);
|
|
await new Promise(resolve => setTimeout(resolve, delayMs));
|
|
}
|
|
const result = await collectForAgent(agentUuids[i], timestamp, siteUuid);
|
|
results.push(result);
|
|
}
|
|
const successful = results.filter(r => r.success).length;
|
|
console.log(`[Collector] === SPECIFIC AGENTS DONE === ${successful}/${agentUuids.length} successful`);
|
|
|
|
await pruneOldData().catch(err => console.error('[Collector] [Retention] error:', err.message));
|
|
|
|
return { success: true, mode: 'specific_agents', agents_count: agentUuids.length, successful, results };
|
|
}
|
|
|
|
module.exports = {
|
|
collectAllAgents,
|
|
collectSpecificAgent,
|
|
collectSpecificAgents
|
|
};
|