import log4js from 'log4js'; import { loadConfig } from '../config.js'; import { natsServer } from '../database/nats.js'; import { generateEtcId } from '../utils.js'; const config = loadConfig(); // Setup logger const logger = log4js.getLogger('Action Manager'); logger.level = config.server.logLevel; /** * ActionManager handles tracking object updates using NATS and broadcasts update events via websockets. */ export class ActionManager { constructor(socketClient) { this.socketClient = socketClient; this.callbacks = new Map(); } async subscribeToObjectActions(id, objectType) { logger.debug('Subscribing to object actions...', id, objectType); const subject = `${objectType}s.${id}.actions`; await natsServer.subscribe( subject, this.socketClient.id, (subject, value) => { if (!value?.result) { logger.trace('Object action:', id); this.socketClient.socket.emit( 'objectAction', { _id: id, objectType: objectType, action: { ...value } }, result => { logger.trace('Got action result:', subject); const actionId = value.actionId || generateEtcId(); natsServer.publish(`${subject}.${actionId}`, { ...value, result: { ...result } }); } ); } } ); return { success: true }; } async removeObjectActionsListener(id, objectType) { const subject = `${objectType}s.${id}.actions`; await natsServer.removeSubscription(subject, this.socketClient.id); return { success: true }; } async sendObjectAction(id, objectType, action, callback) { const actionId = generateEtcId(); const subject = `${objectType}s.${id}.actions.${actionId}`; try { this.callbacks.set(actionId, callback); logger.trace( `Calling action id: ${actionId}, object id: ${id}, object type: ${objectType} Action:`, action ); // Subscribe to the response subject await natsServer.subscribe( subject, this.socketClient.socketId, async (subject, value) => { if (value.result) { logger.trace('Calling result callback...'); const storedCallback = this.callbacks.get(actionId); await natsServer.removeSubscription( subject, this.socketClient.socketId ); storedCallback(value.result); } } ); // Publish the action await natsServer.publish(`${objectType}s.${id}.actions`, { ...action, actionId: actionId }); return true; } catch (error) { logger.error( `Failed to send action for ${objectType}s.${id}.actions.${actionId}:`, error ); return false; } } }