UNPKG

@tawk.to/nestjs-google-pubsub-microservice

Version:
197 lines 8.66 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 constants_1 = require("@nestjs/microservices/constants"); 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 gc_pubsub_parser_1 = require("./gc-pubsub.parser"); const gc_message_serializer_1 = require("./gc-message.serializer"); class GCPubSubServer extends microservices_1.Server { constructor(options) { var _a, _b, _c, _d, _e; 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.topicName = this.options.topic || gc_pubsub_constants_1.GC_PUBSUB_DEFAULT_TOPIC; this.subscriptionName = this.options.subscription || gc_pubsub_constants_1.GC_PUBSUB_DEFAULT_SUBSCRIPTION; 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 = (_a = this.options.noAck) !== null && _a !== void 0 ? _a : gc_pubsub_constants_1.GC_PUBSUB_DEFAULT_NO_ACK; this.init = (_b = this.options.init) !== null && _b !== void 0 ? _b : gc_pubsub_constants_1.GC_PUBSUB_DEFAULT_INIT; this.checkExistence = (_c = this.options.checkExistence) !== null && _c !== void 0 ? _c : gc_pubsub_constants_1.GC_PUBSUB_DEFAULT_CHECK_EXISTENCE; this.createSubscriptionOptions = this.options.createSubscriptionOptions; this.replyTopics = new Set(); this.ackAfterResponse = (_d = this.options.ackAfterResponse) !== null && _d !== void 0 ? _d : gc_pubsub_constants_1.GC_PUBSUB_DEFAULT_ACK_AFTER_RESPONSE; this.initializeSerializer(options); this.initializeDeserializer(options); this.parser = (_e = options.parser) !== null && _e !== void 0 ? _e : new gc_pubsub_parser_1.GCPubSubParser(); } 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, this.createSubscriptionOptions)); } 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 { attributes, publishTime } = message; const rawMessage = await this.parser.parse(message); const now = new Date(); const packet = (await this.deserializer.deserialize({ data: rawMessage, id: attributes._id, pattern: attributes._pattern, }, { message })); const pattern = (0, shared_utils_1.isString)(packet.pattern) ? packet.pattern : JSON.stringify(packet.pattern); const correlationId = packet.id; const timeout = Number(attributes._timeout); if (timeout && timeout > 0) { if (now.getTime() - publishTime.getTime() >= timeout) { const timeoutPacket = { id: correlationId, status: 'error', err: 'Message Timeout', }; this.sendMessage(timeoutPacket, attributes._replyTo, correlationId, attributes); if (!this.noAck) message.ack(); return; } } 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, }; this.sendMessage(noHandlerPacket, attributes._replyTo, correlationId, attributes); if (this.noAck) message.ack(); return; } const response$ = this.transformToObservable(await handler(packet.data, context)); const publish = (data) => this.sendMessage(data, attributes._replyTo, correlationId, attributes); response$ && this.send(response$, publish); if (this.ackAfterResponse) { message.ack(); } } async sendMessage(message, replyTo, id, attributes) { Object.assign(message, { id }); const outgoingResponse = await this.serializer.serialize(message, { message: { data: message, attributes, }, }); this.replyTopics.add(replyTo); await this.client.topic(replyTo, this.publisherConfig).publishMessage({ data: outgoingResponse.data, attributes: Object.assign(Object.assign(Object.assign(Object.assign({ id }, attributes), (outgoingResponse.isDisposed ? { isDisposed: '1' } : {})), (outgoingResponse.err ? { err: JSON.stringify(outgoingResponse.err) } : {})), (outgoingResponse.status ? { status: outgoingResponse.status } : {})), }); } initializeSerializer(options) { var _a; this.serializer = (_a = options === null || options === void 0 ? void 0 : options.serializer) !== null && _a !== void 0 ? _a : new gc_message_serializer_1.GCPubSubResponseSerializer(); } 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