farmcontrol-ws/src/actions/actionmanager.js
Tom Butcher 8ccdc81de1 Refactor ActionManager and introduce EventManager for NATS-based event handling
- Replaced Etcd with NATS in ActionManager for tracking object actions and broadcasting updates.
- Implemented EventManager to handle object events using NATS, including subscription and publishing functionalities.
- Enhanced logging for better traceability of actions and events.
2025-09-05 23:29:47 +01:00

103 lines
2.8 KiB
JavaScript

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;
}
}
}