UNPKG

@nestjs/microservices

Version:

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

116 lines (115 loc) 4.27 kB
import { throwError as _throw, connectable, defer, fromEvent, merge, Observable, ReplaySubject, Subject, } from 'rxjs'; import { distinctUntilChanged, map, mergeMap, take } from 'rxjs/operators'; import { IncomingResponseDeserializer } from '../deserializers/incoming-response.deserializer.js'; import { InvalidMessageException } from '../errors/invalid-message.exception.js'; import { IdentitySerializer } from '../serializers/identity.serializer.js'; import { transformPatternToRoute } from '../utils/index.js'; import { randomStringGenerator, isNil } from '@nestjs/common/internal'; /** * @publicApi */ export class ClientProxy { routingMap = new Map(); serializer; deserializer; _status$ = new ReplaySubject(1); /** * Returns an observable that emits status changes. */ get status() { return this._status$.asObservable().pipe(distinctUntilChanged()); } /** * Registers an event listener for the given event. * @param event Event name * @param callback Callback to be executed when the event is emitted */ on(event, callback) { throw new Error('Method not implemented.'); } /** * Send a message to the server/broker. * Used for message-driven communication style between microservices. * @param pattern Pattern to identify the message * @param data Data to be sent * @returns Observable with the result */ send(pattern, data) { if (isNil(pattern) || isNil(data)) { return _throw(() => new InvalidMessageException()); } return defer(async () => this.connect()).pipe(mergeMap(() => new Observable((observer) => { const callback = this.createObserver(observer); return this.publish({ pattern, data }, callback); }))); } /** * Emits an event to the server/broker. * Used for event-driven communication style between microservices. * @param pattern Pattern to identify the event * @param data Data to be sent * @returns Observable that completes when the event is successfully emitted */ emit(pattern, data) { if (isNil(pattern) || isNil(data)) { return _throw(() => new InvalidMessageException()); } const source = defer(async () => this.connect()).pipe(mergeMap(() => this.dispatchEvent({ pattern, data }))); const connectableSource = connectable(source, { connector: () => new Subject(), resetOnDisconnect: false, }); connectableSource.connect(); return connectableSource; } createObserver(observer) { return ({ err, response, isDisposed }) => { if (err) { return observer.error(this.serializeError(err)); } else if (response !== undefined && isDisposed) { observer.next(this.serializeResponse(response)); return observer.complete(); } else if (isDisposed) { return observer.complete(); } observer.next(this.serializeResponse(response)); }; } serializeError(err) { return err; } serializeResponse(response) { return response; } assignPacketId(packet) { const id = randomStringGenerator(); return Object.assign(packet, { id }); } connect$(instance, errorEvent = 'error', connectEvent = 'connect') { const error$ = fromEvent(instance, errorEvent).pipe(map((err) => { throw err; })); const connect$ = fromEvent(instance, connectEvent); return merge(error$, connect$).pipe(take(1)); } getOptionsProp(obj, prop, defaultValue = undefined) { return obj && prop in obj ? obj[prop] : defaultValue; } normalizePattern(pattern) { return transformPatternToRoute(pattern); } initializeSerializer(options) { this.serializer = (options && options.serializer) || new IdentitySerializer(); } initializeDeserializer(options) { this.deserializer = (options && options.deserializer) || new IncomingResponseDeserializer(); } }