n8n-nodes-message-buffer
Version:
n8n community node for message buffering
159 lines (158 loc) • 6.34 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MessageBuffer = void 0;
const ioredis_1 = __importDefault(require("ioredis"));
const POLLING_SIGNAL_KEY = '__isPollingSignal__';
function setupRedisClient(credentials) {
return new ioredis_1.default({
host: credentials.host,
port: credentials.port,
tls: credentials.ssl ? {} : undefined,
db: credentials.database,
username: credentials.user || undefined,
password: credentials.password || undefined,
showFriendlyErrorStack: true,
});
}
class MessageBuffer {
constructor() {
this.description = {
displayName: 'Message Buffer',
name: 'messageBuffer',
icon: 'file:icon.svg',
group: ['transform'],
version: 1,
description: 'Buffers messages for a set time to consolidate them into one. Uses a polling loop. ⚠️ Do not connect anything to the "Discarded" output — it is for internal use only⚠️ .',
defaults: {
name: 'Message Buffer',
},
inputs: ['main'],
outputs: ['main', 'main', 'main'],
outputNames: ['Message Ready', 'Wait', 'Discarded'],
credentials: [
{
name: 'redis',
required: true,
},
],
properties: [
{
displayName: 'Conversation Key',
name: 'conversationKey',
type: 'string',
required: true,
default: '',
description: 'A unique key for the conversation (e.g., userId, chatId). This is crucial to keep conversations separate.',
},
{
displayName: 'Message Field',
name: 'messageField',
type: 'string',
required: true,
default: '',
description: 'The field in the incoming JSON that contains the message text to buffer.',
},
{
displayName: 'Output Field Name',
name: 'outputFieldName',
type: 'string',
default: 'consolidatedMessage',
description: 'The name of the new field for the consolidated message.',
},
{
displayName: 'Wait Time (seconds)',
name: 'waitTime',
type: 'number',
typeOptions: {
minValue: 1,
},
default: 5,
description: 'Time to wait after the last message before consolidating. This value resets with each new message.',
},
],
};
}
async execute() {
const conversationKey = this.getNodeParameter('conversationKey', 0);
const messageField = this.getNodeParameter('messageField', 0);
const waitTime = this.getNodeParameter('waitTime', 0);
const outputFieldName = this.getNodeParameter('outputFieldName', 0, 'consolidatedMessage');
const credentials = await this.getCredentials('redis');
if (!credentials) {
throw new Error('Redis credentials are not configured for this node.');
}
const redis = setupRedisClient(credentials);
const items = this.getInputData();
const returnDataWait = [];
const returnDataMessageReady = [];
const returnDataDiscarded = [];
const dataKey = `msg:${conversationKey}`;
const timerKey = `timer:${conversationKey}`;
const item = items[0];
try {
if (item.json[POLLING_SIGNAL_KEY]) {
const timerExists = await redis.exists(timerKey);
if (timerExists) {
returnDataWait.push(item);
}
else {
const messages = await redis.lrange(dataKey, 0, -1);
if (messages.length > 0) {
const consolidatedMessage = messages.join(' ');
const newJson = { ...item.json };
delete newJson[POLLING_SIGNAL_KEY];
newJson[outputFieldName] = consolidatedMessage;
newJson.allMessages = messages;
const newItem = {
json: newJson,
binary: item.binary,
};
returnDataMessageReady.push(newItem);
await redis.del(dataKey);
}
else {
returnDataDiscarded.push(item);
}
}
}
else {
if (messageField.trim() !== '') {
await redis.rpush(dataKey, messageField);
await redis.set(timerKey, '1', 'EX', waitTime);
const pollingItem = {
json: {
...item.json,
[POLLING_SIGNAL_KEY]: true,
},
binary: item.binary,
};
returnDataWait.push(pollingItem);
}
else {
returnDataDiscarded.push(item);
}
}
}
catch (error) {
if (this.continueOnFail()) {
return this.prepareOutputData(items);
}
else {
const nodeError = error instanceof Error ? error.message : 'Unknown error';
throw nodeError;
}
}
finally {
await redis.quit();
}
return [
this.helpers.returnJsonArray(returnDataMessageReady),
this.helpers.returnJsonArray(returnDataWait),
this.helpers.returnJsonArray(returnDataDiscarded),
];
}
}
exports.MessageBuffer = MessageBuffer;