UNPKG

nestjs-google-pubsub-microservice

Version:
171 lines 7.04 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.GCPubSubServer = void 0; const pubsub_1 = require("@google-cloud/pubsub"); const microservices_1 = require("@nestjs/microservices"); const common_1 = require("@nestjs/common"); const shared_utils_1 = require("@nestjs/common/utils/shared.utils"); const gc_pubsub_constants_1 = require("./gc-pubsub.constants"); const gc_pubsub_context_1 = require("./gc-pubsub.context"); const gc_pubsub_utils_1 = require("./gc-pubsub.utils"); const constants_1 = require("@nestjs/microservices/constants"); class GCPubSubServer extends microservices_1.Server { constructor(options) { super(); this.options = options; this.logger = new common_1.Logger(GCPubSubServer.name); this.pendingEventListeners = []; this.client = null; this.subscription = null; this.clientConfig = this.options.client || gc_pubsub_constants_1.GC_PUBSUB_DEFAULT_CLIENT_CONFIG; this.scopedEnvKey = this.options.scopedEnvKey ?? ''; this.topicName = this.options.topic || gc_pubsub_constants_1.GC_PUBSUB_DEFAULT_TOPIC; this.topicName = `${this.scopedEnvKey}${this.topicName}`; this.subscriptionName = this.options.subscription || gc_pubsub_constants_1.GC_PUBSUB_DEFAULT_SUBSCRIPTION; this.subscriptionName = `${this.scopedEnvKey}${this.subscriptionName}`; this.subscriberConfig = this.options.subscriber || gc_pubsub_constants_1.GC_PUBSUB_DEFAULT_SUBSCRIBER_CONFIG; this.publisherConfig = this.options.publisher || gc_pubsub_constants_1.GC_PUBSUB_DEFAULT_PUBLISHER_CONFIG; this.noAck = this.options.noAck ?? gc_pubsub_constants_1.GC_PUBSUB_DEFAULT_NO_ACK; this.init = this.options.init ?? gc_pubsub_constants_1.GC_PUBSUB_DEFAULT_INIT; this.checkExistence = this.options.checkExistence ?? gc_pubsub_constants_1.GC_PUBSUB_DEFAULT_CHECK_EXISTENCE; this.replyTopics = new Set(); this.initializeSerializer(options); this.initializeDeserializer(options); } async listen(callback) { this.client = this.createClient(); const topic = this.client.topic(this.topicName); if (this.init) { await this.createIfNotExists(topic.create.bind(topic)); } else if (this.checkExistence) { const [exists] = await topic.exists(); if (!exists) { const message = `PubSub server is not started: topic ${this.topicName} does not exist`; this.logger.error(message); throw new Error(message); } } this.subscription = topic.subscription(this.subscriptionName, this.subscriberConfig); if (this.init) { await this.createIfNotExists(this.subscription.create.bind(this.subscription)); } else if (this.checkExistence) { const [exists] = await this.subscription.exists(); if (!exists) { const message = `PubSub server is not started: subscription ${this.subscriptionName} does not exist`; this.logger.error(message); throw new Error(message); } } this.pendingEventListeners.forEach(({ event, callback }) => { this.subscription.on(event, callback); }); this.pendingEventListeners = []; this.subscription .on('message', async (message) => { await this.handleMessage(message); if (this.noAck) { message.ack(); } }) .on('error', (err) => this.logger.error(err)); callback(); } async close() { await (0, gc_pubsub_utils_1.closeSubscription)(this.subscription); await Promise.all(Array.from(this.replyTopics.values()).map((replyTopic) => { return (0, gc_pubsub_utils_1.flushTopic)(this.client.topic(replyTopic)); })); this.replyTopics.clear(); await (0, gc_pubsub_utils_1.closePubSub)(this.client); this.pendingEventListeners = []; } async handleMessage(message) { const { data, attributes } = message; let rawMessage; try { rawMessage = JSON.parse(data.toString()); } catch (error) { this.logger.error(`Unsupported JSON message data format for message '${message.id}'`); return; } let packet; if (attributes.pattern) { packet = this.deserializer.deserialize({ data: rawMessage, id: attributes.id, pattern: attributes.pattern, }); } else { packet = this.deserializer.deserialize(rawMessage); } const pattern = (0, shared_utils_1.isString)(packet.pattern) ? packet.pattern : JSON.stringify(packet.pattern); const correlationId = packet.id; const context = new gc_pubsub_context_1.GCPubSubContext([message, pattern]); if ((0, shared_utils_1.isUndefined)(correlationId)) { return this.handleEvent(pattern, packet, context); } const handler = this.getHandlerByPattern(pattern); if (!handler) { if (!attributes.replyTo) { return; } const status = 'error'; const noHandlerPacket = { id: correlationId, status, err: constants_1.NO_MESSAGE_HANDLER, }; return this.sendMessage(noHandlerPacket, attributes.replyTo, correlationId); } const response$ = this.transformToObservable(await handler(packet.data, context)); const publish = (data) => this.sendMessage(data, attributes.replyTo, correlationId); response$ && this.send(response$, publish); } async sendMessage(message, replyTo, id) { Object.assign(message, { id }); const outgoingResponse = this.serializer.serialize(message); this.replyTopics.add(replyTo); await this.client .topic(replyTo, this.publisherConfig) .publishMessage({ json: outgoingResponse, attributes: { id } }); } async createIfNotExists(create) { try { await create(); } catch (error) { if (error.code !== gc_pubsub_constants_1.ALREADY_EXISTS) { throw error; } } } createClient() { return new pubsub_1.PubSub(this.clientConfig); } on(event, callback) { if (this.subscription) { this.subscription.on(event, callback); } else { this.pendingEventListeners.push({ event, callback }); } } unwrap() { if (!this.client) { throw new Error('Client is not initialized.'); } return this.client; } } exports.GCPubSubServer = GCPubSubServer; //# sourceMappingURL=gc-pubsub.server.js.map