@message-queue-toolkit/core
Version:
Useful utilities, interfaces and base classes for message queue handling. Supports AMQP and SQS with a common abstraction on top currently
110 lines • 4.26 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.HandlerSpy = void 0;
exports.isHandlerSpy = isHandlerSpy;
exports.resolveHandlerSpy = resolveHandlerSpy;
const node_crypto_1 = require("node:crypto");
const node_core_1 = require("@lokalise/node-core");
const toad_cache_1 = require("toad-cache");
const matchUtils_1 = require("../utils/matchUtils");
function isHandlerSpy(value) {
return ((0, node_core_1.isObject)(value) &&
(value instanceof HandlerSpy || value.name === 'HandlerSpy'));
}
class HandlerSpy {
name = 'HandlerSpy';
// biome-ignore lint/suspicious/noExplicitAny: This is expected
messageBuffer;
messageIdField;
messageTypeField;
spyPromises;
constructor(params = {}) {
this.messageBuffer = new toad_cache_1.Fifo(params.bufferSize ?? 100);
// @ts-ignore
this.messageIdField = params.messageIdField ?? 'id';
// @ts-ignore
this.messageTypeField = params.messageTypeField ?? 'type';
this.spyPromises = [];
}
messageMatchesFilter(spyResult, fields, status) {
return ((0, matchUtils_1.objectMatches)(fields, spyResult.message) &&
(!status || spyResult.processingResult.status === status));
}
waitForMessageWithId(id, status) {
return this.waitForMessage(
// @ts-expect-error
{ [this.messageIdField]: id }, status);
}
checkForMessage(expectedFields, status) {
return Object.values(this.messageBuffer.items).find((spyResult) => {
return this.messageMatchesFilter(spyResult.value, expectedFields, status);
})?.value;
}
waitForMessage(expectedFields, status) {
const processedMessageEntry = this.checkForMessage(expectedFields, status);
if (processedMessageEntry) {
return Promise.resolve(processedMessageEntry);
}
let resolve;
const spyPromise = new Promise((_resolve) => {
resolve = _resolve;
});
this.spyPromises.push({
promise: spyPromise,
status,
fields: expectedFields,
// @ts-ignore
resolve,
});
// @ts-ignore
return spyPromise;
}
clear() {
this.messageBuffer.clear();
}
addProcessedMessage(processingResult, messageId) {
const resolvedMessageId = processingResult.message?.[this.messageIdField] ?? messageId ?? (0, node_crypto_1.randomUUID)();
const resolvedMessageType = processingResult.message?.[this.messageTypeField] ?? 'FAILED_TO_RESOLVE';
// If we failed to parse message, let's store id and type at least
const resolvedProcessingResult = processingResult.message
? processingResult
: {
...processingResult,
message: {
[this.messageIdField]: messageId,
[this.messageTypeField]: resolvedMessageType,
},
};
// @ts-ignore
const cacheId = `${resolvedMessageId}-${Date.now()}-${(Math.random() + 1)
.toString(36)
.substring(7)}`;
this.messageBuffer.set(cacheId, resolvedProcessingResult);
const foundPromise = this.spyPromises.find((spyPromise) => {
return this.messageMatchesFilter(resolvedProcessingResult, spyPromise.fields, spyPromise.status);
});
if (foundPromise) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
foundPromise.resolve(processingResult);
const index = this.spyPromises.indexOf(foundPromise);
if (index > -1) {
// only splice array when item is found
this.spyPromises.splice(index, 1); // 2nd parameter means remove one item only
}
}
}
}
exports.HandlerSpy = HandlerSpy;
function resolveHandlerSpy(queueOptions) {
if (isHandlerSpy(queueOptions.handlerSpy)) {
return queueOptions.handlerSpy;
}
if (!queueOptions.handlerSpy) {
return undefined;
}
if (queueOptions.handlerSpy === true) {
return new HandlerSpy();
}
return new HandlerSpy(queueOptions.handlerSpy);
}
//# sourceMappingURL=HandlerSpy.js.map
;