@nestjs/microservices
Version:
Nest - modern, fast, powerful node.js web framework (@microservices)
105 lines (104 loc) • 4.6 kB
JavaScript
import { PATTERN_EXTRAS_METADATA, PATTERN_HANDLER_METADATA, PATTERN_METADATA, TRANSPORT_METADATA, } from '../constants.js';
import { Transport } from '../enums/index.js';
import { PatternHandler } from '../enums/pattern-handler.enum.js';
import { InvalidGrpcDecoratorException, } from '../errors/invalid-grpc-message-decorator.exception.js';
import { isNil, isNumber, isObject, isSymbol } from '@nestjs/common/internal';
export var GrpcMethodStreamingType;
(function (GrpcMethodStreamingType) {
GrpcMethodStreamingType["NO_STREAMING"] = "no_stream";
GrpcMethodStreamingType["RX_STREAMING"] = "rx_stream";
GrpcMethodStreamingType["PT_STREAMING"] = "pt_stream";
})(GrpcMethodStreamingType || (GrpcMethodStreamingType = {}));
/**
* Subscribes to incoming messages which fulfils chosen pattern.
*
* @publicApi
*/
export const MessagePattern = (metadata, transportOrExtras, maybeExtras) => {
let transport;
let extras;
if ((isNumber(transportOrExtras) || isSymbol(transportOrExtras)) &&
isNil(maybeExtras)) {
transport = transportOrExtras;
}
else if (isObject(transportOrExtras) && isNil(maybeExtras)) {
extras = transportOrExtras;
}
else {
transport = transportOrExtras;
extras = maybeExtras;
}
return (target, key, descriptor) => {
try {
Reflect.defineMetadata(PATTERN_METADATA, [].concat(metadata), descriptor.value);
Reflect.defineMetadata(PATTERN_HANDLER_METADATA, PatternHandler.MESSAGE, descriptor.value);
Reflect.defineMetadata(TRANSPORT_METADATA, transport, descriptor.value);
Reflect.defineMetadata(PATTERN_EXTRAS_METADATA, {
...Reflect.getMetadata(PATTERN_EXTRAS_METADATA, descriptor.value),
...extras,
}, descriptor.value);
return descriptor;
}
catch (err) {
throw new InvalidGrpcDecoratorException(metadata);
}
};
};
export function GrpcMethod(service, method) {
return (target, key, descriptor) => {
const metadata = createGrpcMethodMetadata(target, key, service, method);
return MessagePattern(metadata, Transport.GRPC)(target, key, descriptor);
};
}
export function GrpcStreamMethod(service, method) {
return (target, key, descriptor) => {
const metadata = createGrpcMethodMetadata(target, key, service, method, GrpcMethodStreamingType.RX_STREAMING);
MessagePattern(metadata, Transport.GRPC)(target, key, descriptor);
const originalMethod = descriptor.value;
// Override original method to call the "drainBuffer" method on the first parameter
// This is required to avoid premature message emission
descriptor.value = function (observable, ...args) {
const result = originalMethod.apply(this, [observable, ...args]);
const isPromise = result && typeof result.then === 'function';
if (isPromise) {
return result.then((data) => {
if (observable && observable.drainBuffer) {
observable.drainBuffer();
}
return data;
});
}
if (observable && observable.drainBuffer) {
observable.drainBuffer();
}
return result;
};
// Copy all metadata from the original method to the new one
const metadataKeys = Reflect.getMetadataKeys(originalMethod);
metadataKeys.forEach(metadataKey => {
const metadataValue = Reflect.getMetadata(metadataKey, originalMethod);
Reflect.defineMetadata(metadataKey, metadataValue, descriptor.value);
});
};
}
export function GrpcStreamCall(service, method) {
return (target, key, descriptor) => {
const metadata = createGrpcMethodMetadata(target, key, service, method, GrpcMethodStreamingType.PT_STREAMING);
return MessagePattern(metadata, Transport.GRPC)(target, key, descriptor);
};
}
export function createGrpcMethodMetadata(target, key, service, method, streaming = GrpcMethodStreamingType.NO_STREAMING) {
const capitalizeFirstLetter = (str) => str.charAt(0).toUpperCase() + str.slice(1);
if (!service) {
const { name } = target.constructor;
return {
service: name,
rpc: capitalizeFirstLetter(key),
streaming,
};
}
if (service && !method) {
return { service, rpc: capitalizeFirstLetter(key), streaming };
}
return { service, rpc: method, streaming };
}