@nestjs/microservices
Version:
Nest - modern, fast, powerful node.js web framework (@microservices)
116 lines (115 loc) • 4.27 kB
JavaScript
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();
}
}