UNPKG

@nestjs/microservices

Version:

Nest - modern, fast, powerful node.js web framework (@microservices)

139 lines (138 loc) 5.02 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ServerRedis = void 0; const shared_utils_1 = require("@nestjs/common/utils/shared.utils"); const constants_1 = require("../constants"); const ctx_host_1 = require("../ctx-host"); const enums_1 = require("../enums"); const server_1 = require("./server"); let redisPackage = {}; class ServerRedis extends server_1.Server { constructor(options) { super(); this.options = options; this.transportId = enums_1.Transport.REDIS; this.isExplicitlyTerminated = false; redisPackage = this.loadPackage('ioredis', ServerRedis.name, () => require('ioredis')); this.initializeSerializer(options); this.initializeDeserializer(options); } listen(callback) { try { this.subClient = this.createRedisClient(); this.pubClient = this.createRedisClient(); this.handleError(this.pubClient); this.handleError(this.subClient); this.start(callback); } catch (err) { callback(err); } } start(callback) { Promise.all([this.subClient.connect(), this.pubClient.connect()]) .then(() => { this.bindEvents(this.subClient, this.pubClient); callback(); }) .catch(callback); } bindEvents(subClient, pubClient) { subClient.on(this.options?.wildcards ? 'pmessage' : constants_1.MESSAGE_EVENT, this.getMessageHandler(pubClient).bind(this)); const subscribePatterns = [...this.messageHandlers.keys()]; subscribePatterns.forEach(pattern => { const { isEventHandler } = this.messageHandlers.get(pattern); const channel = isEventHandler ? pattern : this.getRequestPattern(pattern); if (this.options?.wildcards) { subClient.psubscribe(channel); } else { subClient.subscribe(channel); } }); } close() { this.isExplicitlyTerminated = true; this.pubClient && this.pubClient.quit(); this.subClient && this.subClient.quit(); } createRedisClient() { return new redisPackage({ port: constants_1.REDIS_DEFAULT_PORT, host: constants_1.REDIS_DEFAULT_HOST, ...this.getClientOptions(), lazyConnect: true, }); } getMessageHandler(pub) { return this.options?.wildcards ? (channel, pattern, buffer) => this.handleMessage(channel, buffer, pub, pattern) : (channel, buffer) => this.handleMessage(channel, buffer, pub, channel); } async handleMessage(channel, buffer, pub, pattern) { const rawMessage = this.parseMessage(buffer); const packet = await this.deserializer.deserialize(rawMessage, { channel }); const redisCtx = new ctx_host_1.RedisContext([pattern]); if ((0, shared_utils_1.isUndefined)(packet.id)) { return this.handleEvent(channel, packet, redisCtx); } const publish = this.getPublisher(pub, channel, packet.id); const handler = this.getHandlerByPattern(channel); if (!handler) { const status = 'error'; const noHandlerPacket = { id: packet.id, status, err: constants_1.NO_MESSAGE_HANDLER, }; return publish(noHandlerPacket); } const response$ = this.transformToObservable(await handler(packet.data, redisCtx)); response$ && this.send(response$, publish); } getPublisher(pub, pattern, id) { return (response) => { Object.assign(response, { id }); const outgoingResponse = this.serializer.serialize(response); return pub.publish(this.getReplyPattern(pattern), JSON.stringify(outgoingResponse)); }; } parseMessage(content) { try { return JSON.parse(content); } catch (e) { return content; } } getRequestPattern(pattern) { return pattern; } getReplyPattern(pattern) { return `${pattern}.reply`; } handleError(stream) { stream.on(constants_1.ERROR_EVENT, (err) => this.logger.error(err)); } getClientOptions() { const retryStrategy = (times) => this.createRetryStrategy(times); return { ...(this.options || {}), retryStrategy, }; } createRetryStrategy(times) { if (this.isExplicitlyTerminated) { return undefined; } if (!this.getOptionsProp(this.options, 'retryAttempts') || times > this.getOptionsProp(this.options, 'retryAttempts')) { this.logger.error(`Retry time exhausted`); return; } return this.getOptionsProp(this.options, 'retryDelay') || 0; } } exports.ServerRedis = ServerRedis;