mirror of
https://gitlab.com/wgp/dougal/software.git
synced 2025-12-06 08:37:07 +00:00
102 lines
3.3 KiB
JavaScript
102 lines
3.3 KiB
JavaScript
const nodeAsync = require('async'); // npm install async
|
|
const { listen } = require('../lib/db/notify');
|
|
const db = require('../lib/db'); // Adjust paths; include all needed DB utils
|
|
const { schema2pid } = require('../lib/db/connection');
|
|
const unique = require('../lib/utils/unique'); // If needed by handlers
|
|
const withinValidity = require('../lib/utils/ranges').withinValidity; // If needed
|
|
const { ALERT, ERROR, DEBUG } = require('DOUGAL_ROOT/debug')(__filename);
|
|
|
|
// List of handler classes (add more as needed)
|
|
const handlerClasses = require('./handlers').Handlers;
|
|
|
|
// Channels to listen to (hardcoded for simplicity; could scan handlers for mentions)
|
|
const channels = require('../lib/db/channels');
|
|
|
|
// Queue config: Process one at a time for order; max retries=3
|
|
const eventQueue = nodeAsync.queue(async (task, callback) => {
|
|
const { data, ctx } = task;
|
|
DEBUG(`Processing event on channel ${data.channel} with timestamp ${data._received ?? 'unknown'}`);
|
|
|
|
for (const handler of ctx.handlers) {
|
|
try {
|
|
await handler.run(data, ctx);
|
|
} catch (err) {
|
|
ERROR(`Error in handler ${handler.constructor.name}:`, err);
|
|
// Retry logic: Could add task.retries++, re-enqueue if < max
|
|
}
|
|
}
|
|
|
|
if (typeof callback === 'function') {
|
|
// async v3.2.6+ does not use callsbacks with AsyncFunctions, but anyway
|
|
callback();
|
|
}
|
|
}, 1); // Concurrency=1 for strict order
|
|
|
|
eventQueue.error((err, task) => {
|
|
ALERT(`Queue error processing task:`, err, task);
|
|
});
|
|
|
|
// Main setup function (call from server init)
|
|
async function setupEventHandlers(projectsConfig) {
|
|
// Shared context
|
|
const ctx = {
|
|
dryRun: Boolean(process.env.DOUGAL_HANDLERS_DRY_RUN) ?? false, // If true, don't commit changes
|
|
projects: { configuration: projectsConfig }, // From user config
|
|
handlers: handlerClasses.map(Cls => new Cls()), // Instances
|
|
// DB utils (add more as needed)
|
|
db,
|
|
schema2pid,
|
|
unique,
|
|
withinValidity
|
|
// Add other utils, e.g., ctx.logger = DEBUG;
|
|
};
|
|
|
|
// Optional: Replay recent events on startup to rebuild state
|
|
// await replayRecentEvents(ctx);
|
|
|
|
// Setup listener
|
|
const subscriber = await listen(channels, (rawData) => {
|
|
const data = {
|
|
...rawData,
|
|
enqueuedAt: new Date() // For monitoring
|
|
};
|
|
eventQueue.push({ data, ctx });
|
|
});
|
|
|
|
DEBUG('Event handler system initialized with channels:', channels);
|
|
if (ctx.dryRun) {
|
|
DEBUG('DRY RUNNING');
|
|
}
|
|
|
|
// Return for cleanup if needed
|
|
return {
|
|
close: () => {
|
|
subscriber.events.removeAllListeners();
|
|
subscriber.close();
|
|
eventQueue.kill();
|
|
}
|
|
};
|
|
}
|
|
|
|
// Optional: Replay last N events to rebuild handler state (e.g., this.prev)
|
|
// async function replayRecentEvents(ctx) {
|
|
// try {
|
|
// // Example: Fetch last 10 realtime events, sorted by tstamp
|
|
// const recentRealtime = await event.listAllProjects({ channel: 'realtime', limit: 10, sort: 'tstamp DESC' });
|
|
// // Assume event.listAllProjects is a custom DB method; implement if needed
|
|
//
|
|
// // Enqueue in original order (reverse sort)
|
|
// recentRealtime.reverse().forEach((evt) => {
|
|
// const data = { channel: 'realtime', payload: { new: evt } };
|
|
// eventQueue.push({ data, ctx });
|
|
// });
|
|
//
|
|
// // Similarly for 'event' channel if needed
|
|
// DEBUG('Replayed recent events for state rebuild');
|
|
// } catch (err) {
|
|
// ERROR('Error replaying events:', err);
|
|
// }
|
|
// }
|
|
|
|
module.exports = { setupEventHandlers };
|