UNPKG

@goparrot/pubsub-event-bus

Version:
141 lines 6.74 kB
"use strict"; var PubSubEventBinder_1; Object.defineProperty(exports, "__esModule", { value: true }); exports.PubSubEventBinder = void 0; const tslib_1 = require("tslib"); const common_1 = require("@nestjs/common"); const lodash_1 = require("lodash"); const decorator_1 = require("../decorator"); const provider_1 = require("../provider"); const utils_1 = require("../utils"); const configuration_1 = require("../utils/configuration"); const Consumer_1 = require("./Consumer"); const EventBus_1 = require("./EventBus"); const PubSubReflector_1 = require("./PubSubReflector"); let PubSubEventBinder = PubSubEventBinder_1 = class PubSubEventBinder { constructor(consumer, eventBus, reflector, consumerOptions) { this.consumer = consumer; this.eventBus = eventBus; this.reflector = reflector; this.consumerOptions = consumerOptions; } async registerPubSubEvents(handlers) { if (!handlers.length) { this.logger().log('No pub-sub event handlers found'); return; } const handlersWithEvents = this.filterValidHandlersWithEvents(handlers); for (const mappedHandler of handlersWithEvents) { this.consumer.configureAutoAck(mappedHandler); this.consumer.addHandleCatch(mappedHandler); await this.bindPubSubConsumer(mappedHandler); } await this.consumer.configureRetryInfrastructure(handlersWithEvents); } async bindPubSubConsumer(handlerWrapper) { await this.consumer.consume(handlerWrapper, (message) => { if (message) { this.emitPubSubEvent(handlerWrapper, message); } }); } emitPubSubEvent(handlerWrapper, message) { const { handler, eventWrappers } = handlerWrapper; const typeProperty = message.properties.type; const baseContext = { handler: handler.name, type: typeProperty }; if (typeof typeProperty !== 'string') { this.logger().warn(JSON.stringify({ ...baseContext, message: 'Message with invalid property "type" consumed', })); this.consumer.ack(message); return; } const messageExchange = (0, utils_1.getMessageExchange)(message); let matchedEventWrappers = eventWrappers.filter(({ event, options }) => options.exchange === messageExchange && (0, utils_1.toEventName)(event.name) === typeProperty); if (!matchedEventWrappers.length) { matchedEventWrappers = eventWrappers.filter((eventWrapper) => { const bindingPattern = this.consumer.extractBindingPattern(eventWrapper); return (eventWrapper.options.exchange === messageExchange && (bindingPattern === configuration_1.FAN_OUT_BINDING || PubSubEventBinder_1.checkTypeAgainstBinding(typeProperty, bindingPattern))); }); } if (!matchedEventWrappers.length) { this.logger().warn(JSON.stringify({ ...baseContext, events: matchedEventWrappers.map((eventWrapper) => { return { name: eventWrapper.event.name, bindingPattern: this.consumer.extractBindingPattern(eventWrapper), }; }), message: 'No event class matched. Possible reason: handler no longer listens for this type of message, so queue should be unbound', })); this.consumer.ack(message); return; } const eventClasses = matchedEventWrappers.map((eventWrapper) => eventWrapper.event); const [firstEventClass, ...unused] = eventClasses; if (unused.length) { this.logger().warn(JSON.stringify({ ...baseContext, used: firstEventClass.name, unused: unused.map((event) => event.name), message: "Handler's event intersection detected", })); } const pubSubEvent = new firstEventClass(JSON.parse(message.content.toString())).withMessage(message); this.eventBus.publisher.publishLocally(pubSubEvent); } filterValidHandlersWithEvents(handlers) { var _a; const prefix = (_a = this.consumerOptions.queueNamePrefix) !== null && _a !== void 0 ? _a : (0, utils_1.generateQueuePrefixFromPackageName)(); if (!prefix) { throw new Error('"config.consumer.queueNamePrefix" CQRS Module options parameter should be set or the application should be started using npm scripts.'); } const validHandlersWithEvents = []; handlers.forEach((handler) => { var _a; const metadata = this.reflector.reflectHandlerMetadata(handler); if (!metadata) { this.logger().error(`Event handler "${handler.name}" should be decorated with "${decorator_1.PubsubEventHandler.name}"`); return; } const eventWrappers = []; metadata.events.forEach((event) => { const metadata = this.reflector.reflectEventMetadata(event); if (!metadata) { this.logger().error(`Event "${event.name}" should be decorated with "${decorator_1.PubsubEvent.name}"`); return; } eventWrappers.push({ event, options: metadata }); }); if (!eventWrappers.length) { this.logger().error(`Handler "${handler.name}" has no valid events"`); return; } validHandlersWithEvents.push({ handler, eventWrappers, options: (0, lodash_1.omit)(metadata, 'events'), queue: (_a = metadata.queue) !== null && _a !== void 0 ? _a : [prefix, (0, utils_1.toSnakeCase)(handler.name)].join(':'), }); }); return validHandlersWithEvents; } logger() { return provider_1.LoggerProvider.logger; } static checkTypeAgainstBinding(typeProperty, bindingPattern) { return new RegExp(`^${(0, lodash_1.escapeRegExp)(bindingPattern).replace(/\\\*/g, '\\w*')}$`).test(typeProperty); } }; exports.PubSubEventBinder = PubSubEventBinder; exports.PubSubEventBinder = PubSubEventBinder = PubSubEventBinder_1 = tslib_1.__decorate([ (0, common_1.Injectable)(), tslib_1.__param(3, (0, common_1.Inject)(configuration_1.CQRS_MODULE_CONSUMER_OPTIONS)), tslib_1.__metadata("design:paramtypes", [Consumer_1.Consumer, EventBus_1.EventBus, PubSubReflector_1.PubSubReflector, Object]) ], PubSubEventBinder); //# sourceMappingURL=PubSubEventBinder.js.map