mirror of
https://github.com/Maks1mS/nestjs-telegraf.git
synced 2025-01-11 22:51:06 +03:00
refactor(): use ExternalContextCreator
This commit is contained in:
parent
d7f397b375
commit
798494a5b2
@ -1,38 +0,0 @@
|
|||||||
import { NestContainer } from '@nestjs/core';
|
|
||||||
import { BaseExceptionFilterContext } from '@nestjs/core/exceptions/base-exception-filter-context';
|
|
||||||
import { EXCEPTION_FILTERS_METADATA } from '@nestjs/common/constants';
|
|
||||||
import { isEmpty } from '@nestjs/common/utils/shared.utils';
|
|
||||||
import { TelegrafExceptionsHandler } from '../exceptions/telegraf-exceptions-handler';
|
|
||||||
|
|
||||||
export class FiltersContextCreator extends BaseExceptionFilterContext {
|
|
||||||
constructor(container: NestContainer) {
|
|
||||||
super(container);
|
|
||||||
}
|
|
||||||
|
|
||||||
public create(
|
|
||||||
instance: object,
|
|
||||||
callback: (...args: any[]) => void,
|
|
||||||
moduleKey: string,
|
|
||||||
): TelegrafExceptionsHandler {
|
|
||||||
this.moduleContext = moduleKey;
|
|
||||||
|
|
||||||
const exceptionHandler = new TelegrafExceptionsHandler();
|
|
||||||
const filters = this.createContext(
|
|
||||||
instance,
|
|
||||||
callback,
|
|
||||||
EXCEPTION_FILTERS_METADATA,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isEmpty(filters)) {
|
|
||||||
return exceptionHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
exceptionHandler.setCustomFilters(filters.reverse());
|
|
||||||
|
|
||||||
return exceptionHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getGlobalMetadata<T extends any[]>(): T {
|
|
||||||
return [] as T;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,278 +0,0 @@
|
|||||||
import { Controller, PipeTransform } from '@nestjs/common/interfaces';
|
|
||||||
import { PipesContextCreator } from '@nestjs/core/pipes/pipes-context-creator';
|
|
||||||
import { PipesConsumer } from '@nestjs/core/pipes/pipes-consumer';
|
|
||||||
import { GuardsContextCreator } from '@nestjs/core/guards/guards-context-creator';
|
|
||||||
import { GuardsConsumer } from '@nestjs/core/guards/guards-consumer';
|
|
||||||
import { InterceptorsContextCreator } from '@nestjs/core/interceptors/interceptors-context-creator';
|
|
||||||
import { InterceptorsConsumer } from '@nestjs/core/interceptors/interceptors-consumer';
|
|
||||||
import {
|
|
||||||
ContextUtils,
|
|
||||||
ParamProperties,
|
|
||||||
} from '@nestjs/core/helpers/context-utils';
|
|
||||||
import { HandlerMetadataStorage } from '@nestjs/core/helpers/handler-metadata-storage';
|
|
||||||
import { FORBIDDEN_MESSAGE } from '@nestjs/core/guards/constants';
|
|
||||||
import { ParamsMetadata } from '@nestjs/core/helpers/interfaces';
|
|
||||||
import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context-host';
|
|
||||||
|
|
||||||
import { FiltersContextCreator } from './filters-context-creator';
|
|
||||||
import { TelegrafContextType } from '../execution-context/telegraf-execution-context';
|
|
||||||
import { TelegrafProxy } from './telegraf-proxy';
|
|
||||||
import { TelegrafException } from '../errors';
|
|
||||||
import {
|
|
||||||
CUSTOM_LISTENER_AGRS_METADATA,
|
|
||||||
LISTENER_ARGS_METADATA,
|
|
||||||
} from '../telegraf.constants';
|
|
||||||
import { TelegrafParamsFactory } from '../factories/telegraf-params-factory';
|
|
||||||
import { isEmpty } from '@nestjs/common/utils/shared.utils';
|
|
||||||
|
|
||||||
export type Update = Controller;
|
|
||||||
type TelegrafParamProperties = ParamProperties & { metatype?: any };
|
|
||||||
|
|
||||||
export interface TelegrafHandlerMetadata {
|
|
||||||
argsLength: number;
|
|
||||||
paramtypes: any[];
|
|
||||||
getParamsMetadata: (moduleKey: string) => TelegrafParamProperties[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export class TelegrafContextCreator {
|
|
||||||
private readonly contextUtils = new ContextUtils();
|
|
||||||
private readonly telegrafParamsFactory = new TelegrafParamsFactory();
|
|
||||||
private readonly handlerMetadataStorage = new HandlerMetadataStorage<TelegrafHandlerMetadata>();
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private readonly telegrafProxy: TelegrafProxy,
|
|
||||||
private readonly exceptionFiltersContext: FiltersContextCreator,
|
|
||||||
private readonly pipesContextCreator: PipesContextCreator,
|
|
||||||
private readonly pipesConsumer: PipesConsumer,
|
|
||||||
private readonly guardsContextCreator: GuardsContextCreator,
|
|
||||||
private readonly guardsConsumer: GuardsConsumer,
|
|
||||||
private readonly interceptorsContextCreator: InterceptorsContextCreator,
|
|
||||||
private readonly interceptorsConsumer: InterceptorsConsumer,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
public create<T extends ParamsMetadata = ParamsMetadata>(
|
|
||||||
instance: Update,
|
|
||||||
methodRef: (...args: unknown[]) => void,
|
|
||||||
moduleName: string,
|
|
||||||
methodKey: string,
|
|
||||||
): (...args: any[]) => Promise<void> {
|
|
||||||
const contextType: TelegrafContextType = 'telegraf';
|
|
||||||
const { argsLength, paramtypes, getParamsMetadata } = this.getMetadata<T>(
|
|
||||||
instance,
|
|
||||||
methodKey,
|
|
||||||
contextType,
|
|
||||||
);
|
|
||||||
|
|
||||||
const exceptionHandler = this.exceptionFiltersContext.create(
|
|
||||||
instance,
|
|
||||||
methodRef,
|
|
||||||
moduleName,
|
|
||||||
);
|
|
||||||
|
|
||||||
const pipes = this.pipesContextCreator.create(
|
|
||||||
instance,
|
|
||||||
methodRef,
|
|
||||||
moduleName,
|
|
||||||
);
|
|
||||||
|
|
||||||
const guards = this.guardsContextCreator.create(
|
|
||||||
instance,
|
|
||||||
methodRef,
|
|
||||||
moduleName,
|
|
||||||
);
|
|
||||||
|
|
||||||
const interceptors = this.interceptorsContextCreator.create(
|
|
||||||
instance,
|
|
||||||
methodRef,
|
|
||||||
moduleName,
|
|
||||||
);
|
|
||||||
|
|
||||||
const paramsMetadata = getParamsMetadata(moduleName);
|
|
||||||
const paramsOptions = paramsMetadata
|
|
||||||
? this.contextUtils.mergeParamsMetatypes(paramsMetadata, paramtypes)
|
|
||||||
: [];
|
|
||||||
const fnApplyPipes = this.createPipesFn(pipes, paramsOptions);
|
|
||||||
|
|
||||||
const fnCanActivate = this.createGuardsFn(
|
|
||||||
guards,
|
|
||||||
instance,
|
|
||||||
methodRef,
|
|
||||||
contextType,
|
|
||||||
);
|
|
||||||
|
|
||||||
const handler = <TContext>(
|
|
||||||
initialArgs: unknown[],
|
|
||||||
ctx: TContext,
|
|
||||||
next: Function,
|
|
||||||
) => async () => {
|
|
||||||
if (fnApplyPipes) {
|
|
||||||
await fnApplyPipes(initialArgs, ctx, next);
|
|
||||||
return methodRef.apply(instance, initialArgs);
|
|
||||||
}
|
|
||||||
return methodRef.apply(instance, [ctx, next]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const targetCallback = async <TContext>(ctx: TContext, next: Function) => {
|
|
||||||
const initialArgs = this.contextUtils.createNullArray(argsLength);
|
|
||||||
fnCanActivate && (await fnCanActivate([ctx, next]));
|
|
||||||
|
|
||||||
return this.interceptorsConsumer.intercept(
|
|
||||||
interceptors,
|
|
||||||
[ctx, next],
|
|
||||||
instance,
|
|
||||||
methodRef,
|
|
||||||
handler(initialArgs, ctx, next),
|
|
||||||
contextType,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return this.telegrafProxy.create(targetCallback, exceptionHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getMetadata<
|
|
||||||
TMetadata,
|
|
||||||
TContext extends TelegrafContextType = TelegrafContextType
|
|
||||||
>(
|
|
||||||
instance: Controller,
|
|
||||||
methodName: string,
|
|
||||||
contextType: TContext,
|
|
||||||
): TelegrafHandlerMetadata {
|
|
||||||
const cachedMetadata = this.handlerMetadataStorage.get(
|
|
||||||
instance,
|
|
||||||
methodName,
|
|
||||||
);
|
|
||||||
if (cachedMetadata) return cachedMetadata;
|
|
||||||
|
|
||||||
const metadata =
|
|
||||||
this.contextUtils.reflectCallbackMetadata<TMetadata>(
|
|
||||||
instance,
|
|
||||||
methodName,
|
|
||||||
LISTENER_ARGS_METADATA,
|
|
||||||
) || {};
|
|
||||||
|
|
||||||
const keys = Object.keys(metadata);
|
|
||||||
const argsLength = this.contextUtils.getArgumentsLength(keys, metadata);
|
|
||||||
const contextFactory = this.contextUtils.getContextFactory(
|
|
||||||
contextType,
|
|
||||||
instance,
|
|
||||||
instance[methodName],
|
|
||||||
);
|
|
||||||
const getParamsMetadata = (moduleKey: string) =>
|
|
||||||
this.exchangeKeysForValues(
|
|
||||||
keys,
|
|
||||||
metadata,
|
|
||||||
moduleKey,
|
|
||||||
this.telegrafParamsFactory,
|
|
||||||
contextFactory,
|
|
||||||
);
|
|
||||||
|
|
||||||
const paramtypes = this.contextUtils.reflectCallbackParamtypes(
|
|
||||||
instance,
|
|
||||||
methodName,
|
|
||||||
);
|
|
||||||
const handlerMetadata: TelegrafHandlerMetadata = {
|
|
||||||
argsLength,
|
|
||||||
paramtypes,
|
|
||||||
getParamsMetadata,
|
|
||||||
};
|
|
||||||
this.handlerMetadataStorage.set(instance, methodName, handlerMetadata);
|
|
||||||
return handlerMetadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
public exchangeKeysForValues<TMetadata = any>(
|
|
||||||
keys: string[],
|
|
||||||
metadata: TMetadata,
|
|
||||||
moduleContext: string,
|
|
||||||
paramsFactory: TelegrafParamsFactory,
|
|
||||||
contextFactory: (args: unknown[]) => ExecutionContextHost,
|
|
||||||
): ParamProperties[] {
|
|
||||||
this.pipesContextCreator.setModuleContext(moduleContext);
|
|
||||||
|
|
||||||
return keys.map((key) => {
|
|
||||||
const { index, data, pipes: pipesCollection } = metadata[key];
|
|
||||||
const pipes = this.pipesContextCreator.createConcreteContext(
|
|
||||||
pipesCollection,
|
|
||||||
);
|
|
||||||
const type = this.contextUtils.mapParamType(key);
|
|
||||||
|
|
||||||
if (key.includes(CUSTOM_LISTENER_AGRS_METADATA)) {
|
|
||||||
const { factory } = metadata[key];
|
|
||||||
const customExtractValue = this.contextUtils.getCustomFactory(
|
|
||||||
factory,
|
|
||||||
data,
|
|
||||||
contextFactory,
|
|
||||||
);
|
|
||||||
return { index, extractValue: customExtractValue, type, data, pipes };
|
|
||||||
}
|
|
||||||
const numericType = Number(type);
|
|
||||||
const extractValue = <TContext>(ctx: TContext, next: Function) =>
|
|
||||||
paramsFactory.exchangeKeyForValue(numericType, ctx, next);
|
|
||||||
|
|
||||||
return { index, extractValue, type: numericType, data, pipes };
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public createGuardsFn<TContext extends string = TelegrafContextType>(
|
|
||||||
guards: any[],
|
|
||||||
instance: Controller,
|
|
||||||
callback: (...args: unknown[]) => any,
|
|
||||||
contextType?: TContext,
|
|
||||||
): Function | null {
|
|
||||||
const canActivateFn = async (args: any[]) => {
|
|
||||||
const canActivate = await this.guardsConsumer.tryActivate<TContext>(
|
|
||||||
guards,
|
|
||||||
args,
|
|
||||||
instance,
|
|
||||||
callback,
|
|
||||||
contextType,
|
|
||||||
);
|
|
||||||
if (!canActivate) {
|
|
||||||
throw new TelegrafException(FORBIDDEN_MESSAGE);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return guards.length ? canActivateFn : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public createPipesFn(
|
|
||||||
pipes: PipeTransform[],
|
|
||||||
paramsOptions: (ParamProperties & { metatype?: unknown })[],
|
|
||||||
) {
|
|
||||||
const pipesFn = async <TContext>(
|
|
||||||
args: unknown[],
|
|
||||||
ctx: TContext,
|
|
||||||
next: Function,
|
|
||||||
) => {
|
|
||||||
const resolveParamValue = async (
|
|
||||||
param: ParamProperties & { metatype?: unknown },
|
|
||||||
) => {
|
|
||||||
const {
|
|
||||||
index,
|
|
||||||
extractValue,
|
|
||||||
type,
|
|
||||||
data,
|
|
||||||
metatype,
|
|
||||||
pipes: paramPipes,
|
|
||||||
} = param;
|
|
||||||
const value = extractValue(ctx, next);
|
|
||||||
|
|
||||||
args[index] = await this.getParamValue(
|
|
||||||
value,
|
|
||||||
{ metatype, type, data },
|
|
||||||
pipes.concat(paramPipes),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
await Promise.all(paramsOptions.map(resolveParamValue));
|
|
||||||
};
|
|
||||||
return paramsOptions.length ? pipesFn : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getParamValue<T>(
|
|
||||||
value: T,
|
|
||||||
{ metatype, type, data }: { metatype: any; type: any; data: any },
|
|
||||||
pipes: PipeTransform[],
|
|
||||||
): Promise<any> {
|
|
||||||
return isEmpty(pipes)
|
|
||||||
? value
|
|
||||||
: this.pipesConsumer.apply(value, { metatype, type, data }, pipes);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context-host';
|
|
||||||
import { catchError } from 'rxjs/operators';
|
|
||||||
import { EMPTY } from 'rxjs';
|
|
||||||
import { isObservable } from '../helpers/is-observable.helper';
|
|
||||||
import { TelegrafExceptionsHandler } from '../exceptions/telegraf-exceptions-handler';
|
|
||||||
|
|
||||||
export class TelegrafProxy {
|
|
||||||
public create(
|
|
||||||
targetCallback: <TContext>(ctx: TContext, next: Function) => Promise<any>,
|
|
||||||
exceptionsHandler: TelegrafExceptionsHandler,
|
|
||||||
): <TContext>(ctx: TContext, next: Function) => Promise<any> {
|
|
||||||
return async <TContext>(ctx: TContext, next: Function) => {
|
|
||||||
try {
|
|
||||||
const result = await targetCallback(ctx, next);
|
|
||||||
return !isObservable(result)
|
|
||||||
? result
|
|
||||||
: result.pipe(
|
|
||||||
catchError((error) => {
|
|
||||||
this.handleError(exceptionsHandler, [ctx, next], error);
|
|
||||||
return EMPTY;
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
this.handleError(exceptionsHandler, [ctx, next], error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
handleError<T>(
|
|
||||||
exceptionsHandler: TelegrafExceptionsHandler,
|
|
||||||
args: unknown[],
|
|
||||||
error: T,
|
|
||||||
): void {
|
|
||||||
const host = new ExecutionContextHost(args);
|
|
||||||
host.setType('telegraf');
|
|
||||||
exceptionsHandler.handle(error, host);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +1,10 @@
|
|||||||
import { PipeTransform, Type } from '@nestjs/common';
|
import { PipeTransform, Type } from '@nestjs/common';
|
||||||
import { createPipesTelegrafParamDecorator } from '../../utils/param-decorator.util';
|
import { createTelegrafPipesParamDecorator } from '../../utils/param-decorator.util';
|
||||||
import { TelegrafParamtype } from '../../enums/telegraf-paramtype.enum';
|
import { TelegrafParamtype } from '../../enums/telegraf-paramtype.enum';
|
||||||
|
|
||||||
export function MessageText(): ParameterDecorator;
|
export function MessageText(...pipes: (Type<PipeTransform> | PipeTransform)[]) {
|
||||||
export function MessageText(
|
return createTelegrafPipesParamDecorator(TelegrafParamtype.MESSAGE_TEXT)(
|
||||||
...pipes: (Type<PipeTransform> | PipeTransform)[]
|
undefined,
|
||||||
): ParameterDecorator;
|
|
||||||
export function MessageText(
|
|
||||||
...pipes: (Type<PipeTransform> | PipeTransform)[]
|
|
||||||
): ParameterDecorator {
|
|
||||||
return createPipesTelegrafParamDecorator(TelegrafParamtype.MESSAGE_TEXT)(
|
|
||||||
...pipes,
|
...pipes,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
import { ArgumentsHost, Logger } from '@nestjs/common';
|
|
||||||
import { MESSAGES } from '@nestjs/core/constants';
|
|
||||||
import { Context } from 'telegraf';
|
|
||||||
import { TelegrafExceptionFilter } from '../interfaces/telegraf-exception-filter.interface';
|
|
||||||
import { TelegrafException } from '../errors';
|
|
||||||
import { isErrorObject } from '../helpers/is-error-object.helper';
|
|
||||||
import { TelegrafArgumentsHost } from '../execution-context';
|
|
||||||
|
|
||||||
export class BaseTelegrafExceptionFilter<TError = any>
|
|
||||||
implements TelegrafExceptionFilter {
|
|
||||||
private static readonly logger = new Logger('TelegrafExceptionsHandler');
|
|
||||||
|
|
||||||
catch(exception: TError, host: ArgumentsHost): void {
|
|
||||||
const context = TelegrafArgumentsHost.create(host).getContext<Context>();
|
|
||||||
this.handleError(exception, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public handleError(exception: TError, context: Context): void {
|
|
||||||
if (!(exception instanceof TelegrafException)) {
|
|
||||||
return this.handleUnknownError(exception, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.reply(exception.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public handleUnknownError(exception: TError, context: Context): void {
|
|
||||||
context.reply(MESSAGES.UNKNOWN_EXCEPTION_MESSAGE);
|
|
||||||
|
|
||||||
const errorMessage = isErrorObject(exception)
|
|
||||||
? exception.message
|
|
||||||
: exception;
|
|
||||||
BaseTelegrafExceptionFilter.logger.error(errorMessage);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
export * from './base-telegraf-exception-filter';
|
|
@ -1,48 +0,0 @@
|
|||||||
import { ArgumentsHost } from '@nestjs/common';
|
|
||||||
import { ExceptionFilterMetadata } from '@nestjs/common/interfaces/exceptions';
|
|
||||||
import { BaseTelegrafExceptionFilter } from './base-telegraf-exception-filter';
|
|
||||||
import { TelegrafException } from '../errors';
|
|
||||||
import { InvalidExceptionFilterException } from '@nestjs/core/errors/exceptions/invalid-exception-filter.exception';
|
|
||||||
import { isEmpty } from '@nestjs/common/utils/shared.utils';
|
|
||||||
|
|
||||||
export class TelegrafExceptionsHandler extends BaseTelegrafExceptionFilter {
|
|
||||||
private filters: ExceptionFilterMetadata[] = [];
|
|
||||||
|
|
||||||
public handle(
|
|
||||||
exception: Error | TelegrafException | any,
|
|
||||||
host: ArgumentsHost,
|
|
||||||
): void {
|
|
||||||
const isFilterInvoked = this.invokeCustomFilters(exception, host);
|
|
||||||
if (!isFilterInvoked) {
|
|
||||||
super.catch(exception, host);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public invokeCustomFilters<T = any>(
|
|
||||||
exception: T,
|
|
||||||
args: ArgumentsHost,
|
|
||||||
): boolean {
|
|
||||||
if (isEmpty(this.filters)) return false;
|
|
||||||
|
|
||||||
const filter = this.filters.find(({ exceptionMetatypes }) => {
|
|
||||||
const hasMetatype =
|
|
||||||
!exceptionMetatypes.length ||
|
|
||||||
exceptionMetatypes.some(
|
|
||||||
(ExceptionMetatype) => exception instanceof ExceptionMetatype,
|
|
||||||
);
|
|
||||||
return hasMetatype;
|
|
||||||
});
|
|
||||||
|
|
||||||
filter && filter.func(exception, args);
|
|
||||||
|
|
||||||
return !!filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public setCustomFilters(filters: ExceptionFilterMetadata[]): void {
|
|
||||||
if (!Array.isArray(filters)) {
|
|
||||||
throw new InvalidExceptionFilterException();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.filters = filters;
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,25 +3,18 @@ import { Injectable as IInjectable } from '@nestjs/common/interfaces/injectable.
|
|||||||
import { DiscoveryService, ModuleRef, ModulesContainer } from '@nestjs/core';
|
import { DiscoveryService, ModuleRef, ModulesContainer } from '@nestjs/core';
|
||||||
import { MetadataScanner } from '@nestjs/core/metadata-scanner';
|
import { MetadataScanner } from '@nestjs/core/metadata-scanner';
|
||||||
import { InstanceWrapper } from '@nestjs/core/injector/instance-wrapper';
|
import { InstanceWrapper } from '@nestjs/core/injector/instance-wrapper';
|
||||||
import { PipesContextCreator } from '@nestjs/core/pipes/pipes-context-creator';
|
|
||||||
import { PipesConsumer } from '@nestjs/core/pipes/pipes-consumer';
|
|
||||||
import { GuardsContextCreator } from '@nestjs/core/guards/guards-context-creator';
|
|
||||||
import { GuardsConsumer } from '@nestjs/core/guards/guards-consumer';
|
|
||||||
import { InterceptorsContextCreator } from '@nestjs/core/interceptors/interceptors-context-creator';
|
|
||||||
import { InterceptorsConsumer } from '@nestjs/core/interceptors/interceptors-consumer';
|
|
||||||
import { isFunction, isNil } from '@nestjs/common/utils/shared.utils';
|
import { isFunction, isNil } from '@nestjs/common/utils/shared.utils';
|
||||||
import { fromPromise } from 'rxjs/internal-compatibility';
|
import { fromPromise } from 'rxjs/internal-compatibility';
|
||||||
import { filter, mergeAll } from 'rxjs/operators';
|
import { filter, mergeAll } from 'rxjs/operators';
|
||||||
import { Observable, of } from 'rxjs';
|
import { Observable, of } from 'rxjs';
|
||||||
import { Context, Telegraf } from 'telegraf';
|
import { Context, Telegraf } from 'telegraf';
|
||||||
import { TelegrafMetadataAccessor } from '../telegraf.metadata-accessor';
|
import { TelegrafMetadataAccessor } from '../telegraf.metadata-accessor';
|
||||||
import { TelegrafContextCreator } from '../context/telegraf-context-creator';
|
import { ExternalContextCreator } from '@nestjs/core/helpers/external-context-creator';
|
||||||
import { TelegrafProxy } from '../context/telegraf-proxy';
|
import { TelegrafParamsFactory } from '../factories/telegraf-params-factory';
|
||||||
import { FiltersContextCreator } from '../context/filters-context-creator';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TelegrafUpdateExplorer implements OnModuleInit {
|
export class TelegrafUpdateExplorer implements OnModuleInit {
|
||||||
private readonly contextCreator: TelegrafContextCreator;
|
private readonly telegrafParamsFactory = new TelegrafParamsFactory();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly moduleRef: ModuleRef,
|
private readonly moduleRef: ModuleRef,
|
||||||
@ -29,24 +22,9 @@ export class TelegrafUpdateExplorer implements OnModuleInit {
|
|||||||
private readonly discoveryService: DiscoveryService,
|
private readonly discoveryService: DiscoveryService,
|
||||||
private readonly metadataAccessor: TelegrafMetadataAccessor,
|
private readonly metadataAccessor: TelegrafMetadataAccessor,
|
||||||
private readonly metadataScanner: MetadataScanner,
|
private readonly metadataScanner: MetadataScanner,
|
||||||
|
private readonly externalContextCreator: ExternalContextCreator,
|
||||||
@Inject(Telegraf) private readonly telegraf: Telegraf<never>,
|
@Inject(Telegraf) private readonly telegraf: Telegraf<never>,
|
||||||
) {
|
) {}
|
||||||
this.contextCreator = this.getContextCreator();
|
|
||||||
}
|
|
||||||
|
|
||||||
private getContextCreator(): TelegrafContextCreator {
|
|
||||||
const { container } = this.moduleRef as any;
|
|
||||||
return new TelegrafContextCreator(
|
|
||||||
new TelegrafProxy(),
|
|
||||||
new FiltersContextCreator(container),
|
|
||||||
new PipesContextCreator(container),
|
|
||||||
new PipesConsumer(),
|
|
||||||
new GuardsContextCreator(container),
|
|
||||||
new GuardsConsumer(),
|
|
||||||
new InterceptorsContextCreator(container),
|
|
||||||
new InterceptorsConsumer(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
onModuleInit(): void {
|
onModuleInit(): void {
|
||||||
this.explore();
|
this.explore();
|
||||||
@ -87,11 +65,20 @@ export class TelegrafUpdateExplorer implements OnModuleInit {
|
|||||||
moduleName: string,
|
moduleName: string,
|
||||||
): void {
|
): void {
|
||||||
const methodRef = instance[methodKey] as (...args: unknown[]) => unknown;
|
const methodRef = instance[methodKey] as (...args: unknown[]) => unknown;
|
||||||
const contextHandlerFn = this.contextCreator.create(
|
const contextHandlerFn = this.externalContextCreator.create(
|
||||||
instance,
|
instance,
|
||||||
methodRef,
|
methodRef,
|
||||||
moduleName,
|
moduleName,
|
||||||
methodKey,
|
methodKey,
|
||||||
|
this.telegrafParamsFactory,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
{
|
||||||
|
interceptors: true,
|
||||||
|
filters: true,
|
||||||
|
guards: true,
|
||||||
|
},
|
||||||
|
'telegraf',
|
||||||
);
|
);
|
||||||
|
|
||||||
const listenerMetadata = this.metadataAccessor.getListenerMetadata(
|
const listenerMetadata = this.metadataAccessor.getListenerMetadata(
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
import { isObject } from '@nestjs/common/utils/shared.utils';
|
|
||||||
|
|
||||||
export function isErrorObject(err: any): err is Error {
|
|
||||||
return isObject(err) && !!(err as Error).message;
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
import { isFunction } from '@nestjs/common/utils/shared.utils';
|
|
||||||
|
|
||||||
export function isObservable(result: any): boolean {
|
|
||||||
return result && isFunction(result.subscribe);
|
|
||||||
}
|
|
@ -1,7 +1,4 @@
|
|||||||
import {
|
import { ROUTE_ARGS_METADATA } from '@nestjs/common/constants';
|
||||||
CUSTOM_ROUTE_AGRS_METADATA,
|
|
||||||
ROUTE_ARGS_METADATA,
|
|
||||||
} from '@nestjs/common/constants';
|
|
||||||
|
|
||||||
export const TELEGRAF_MODULE_OPTIONS = 'TELEGRAF_MODULE_OPTIONS';
|
export const TELEGRAF_MODULE_OPTIONS = 'TELEGRAF_MODULE_OPTIONS';
|
||||||
|
|
||||||
@ -10,5 +7,4 @@ export const UPDATE_LISTENER_METADATA = 'UPDATE_LISTENER_METADATA';
|
|||||||
|
|
||||||
export const SCENE_METADATA = 'SCENE_METADATA';
|
export const SCENE_METADATA = 'SCENE_METADATA';
|
||||||
|
|
||||||
export const LISTENER_ARGS_METADATA = ROUTE_ARGS_METADATA;
|
export const PARAM_ARGS_METADATA = ROUTE_ARGS_METADATA;
|
||||||
export const CUSTOM_LISTENER_AGRS_METADATA = CUSTOM_ROUTE_AGRS_METADATA;
|
|
||||||
|
@ -1,39 +1,86 @@
|
|||||||
import { assignMetadata, PipeTransform, Type } from '@nestjs/common';
|
import { assignMetadata, PipeTransform, Type } from '@nestjs/common';
|
||||||
|
import { isNil, isString } from '@nestjs/common/utils/shared.utils';
|
||||||
import { TelegrafParamtype } from '../enums/telegraf-paramtype.enum';
|
import { TelegrafParamtype } from '../enums/telegraf-paramtype.enum';
|
||||||
import { LISTENER_ARGS_METADATA } from '../telegraf.constants';
|
import { PARAM_ARGS_METADATA } from '../telegraf.constants';
|
||||||
|
|
||||||
export function createTelegrafParamDecorator(
|
export type ParamData = object | string | number;
|
||||||
paramtype: TelegrafParamtype,
|
|
||||||
): (...pipes: (Type<PipeTransform> | PipeTransform)[]) => ParameterDecorator {
|
export const createTelegrafParamDecorator = (paramtype: TelegrafParamtype) => {
|
||||||
return (...pipes: (Type<PipeTransform> | PipeTransform)[]) => (
|
return (data?: ParamData): ParameterDecorator => (target, key, index) => {
|
||||||
target,
|
|
||||||
key,
|
|
||||||
index,
|
|
||||||
) => {
|
|
||||||
const args =
|
const args =
|
||||||
Reflect.getMetadata(LISTENER_ARGS_METADATA, target.constructor, key) ||
|
Reflect.getMetadata(PARAM_ARGS_METADATA, target.constructor, key) || {};
|
||||||
{};
|
|
||||||
Reflect.defineMetadata(
|
Reflect.defineMetadata(
|
||||||
LISTENER_ARGS_METADATA,
|
PARAM_ARGS_METADATA,
|
||||||
assignMetadata(args, paramtype, index, undefined, ...pipes),
|
assignMetadata(args, paramtype, index, data),
|
||||||
target.constructor,
|
target.constructor,
|
||||||
key,
|
key,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export const createPipesTelegrafParamDecorator = (
|
export const createTelegrafPipesParamDecorator = (
|
||||||
paramtype: TelegrafParamtype,
|
paramtype: TelegrafParamtype,
|
||||||
) => (
|
) => (
|
||||||
|
data?: any,
|
||||||
...pipes: (Type<PipeTransform> | PipeTransform)[]
|
...pipes: (Type<PipeTransform> | PipeTransform)[]
|
||||||
): ParameterDecorator => (target, key, index) => {
|
): ParameterDecorator => (target, key, index) => {
|
||||||
|
addPipesMetadata(paramtype, data, pipes, target, key, index);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const addPipesMetadata = (
|
||||||
|
paramtype: TelegrafParamtype,
|
||||||
|
data: any,
|
||||||
|
pipes: (Type<PipeTransform> | PipeTransform)[],
|
||||||
|
target: Record<string, any>,
|
||||||
|
key: string | symbol,
|
||||||
|
index: number,
|
||||||
|
) => {
|
||||||
const args =
|
const args =
|
||||||
Reflect.getMetadata(LISTENER_ARGS_METADATA, target.constructor, key) || {};
|
Reflect.getMetadata(PARAM_ARGS_METADATA, target.constructor, key) || {};
|
||||||
|
const hasParamData = isNil(data) || isString(data);
|
||||||
|
const paramData = hasParamData ? data : undefined;
|
||||||
|
const paramPipes = hasParamData ? pipes : [data, ...pipes];
|
||||||
|
|
||||||
Reflect.defineMetadata(
|
Reflect.defineMetadata(
|
||||||
LISTENER_ARGS_METADATA,
|
PARAM_ARGS_METADATA,
|
||||||
assignMetadata(args, paramtype, index, undefined, ...pipes),
|
assignMetadata(args, paramtype, index, paramData, ...paramPipes),
|
||||||
target.constructor,
|
target.constructor,
|
||||||
key,
|
key,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// export function createTelegrafParamDecorator(
|
||||||
|
// paramtype: TelegrafParamtype,
|
||||||
|
// ): (...pipes: (Type<PipeTransform> | PipeTransform)[]) => ParameterDecorator {
|
||||||
|
// return (...pipes: (Type<PipeTransform> | PipeTransform)[]) => (
|
||||||
|
// target,
|
||||||
|
// key,
|
||||||
|
// index,
|
||||||
|
// ) => {
|
||||||
|
// const args =
|
||||||
|
// Reflect.getMetadata(LISTENER_ARGS_METADATA, target.constructor, key) ||
|
||||||
|
// {};
|
||||||
|
// Reflect.defineMetadata(
|
||||||
|
// LISTENER_ARGS_METADATA,
|
||||||
|
// assignMetadata(args, paramtype, index, undefined, ...pipes),
|
||||||
|
// target.constructor,
|
||||||
|
// key,
|
||||||
|
// );
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// export const createPipesTelegrafParamDecorator = (
|
||||||
|
// paramtype: TelegrafParamtype,
|
||||||
|
// ) => (
|
||||||
|
// ...pipes: (Type<PipeTransform> | PipeTransform)[]
|
||||||
|
// ): ParameterDecorator => (target, key, index) => {
|
||||||
|
// const args =
|
||||||
|
// Reflect.getMetadata(LISTENER_ARGS_METADATA, target.constructor, key) || {};
|
||||||
|
//
|
||||||
|
// Reflect.defineMetadata(
|
||||||
|
// LISTENER_ARGS_METADATA,
|
||||||
|
// assignMetadata(args, paramtype, index, undefined, ...pipes),
|
||||||
|
// target.constructor,
|
||||||
|
// key,
|
||||||
|
// );
|
||||||
|
// };
|
||||||
|
Loading…
Reference in New Issue
Block a user