feat(): wip

This commit is contained in:
Morb0 2021-01-05 12:37:04 +03:00
parent 320ee3077e
commit 75ff810c34
7 changed files with 98 additions and 70 deletions

View File

@ -1,17 +1,19 @@
import { Inject, Injectable, OnModuleInit } from '@nestjs/common';
import { Injectable as IInjectable } from '@nestjs/common/interfaces/injectable.interface';
import { DiscoveryService, ModuleRef, ModulesContainer } from '@nestjs/core';
import { MetadataScanner } from '@nestjs/core/metadata-scanner';
import { InstanceWrapper } from '@nestjs/core/injector/instance-wrapper';
import { isFunction, isNil } from '@nestjs/common/utils/shared.utils';
import { ExternalContextCreator } from '@nestjs/core/helpers/external-context-creator';
import { fromPromise } from 'rxjs/internal-compatibility';
import { filter, mergeAll } from 'rxjs/operators';
import { Observable, of } from 'rxjs';
import { Context, Telegraf } from 'telegraf';
import { TelegrafMetadataAccessor } from '../telegraf.metadata-accessor';
import { ExternalContextCreator } from '@nestjs/core/helpers/external-context-creator';
import { TelegrafParamsFactory } from '../factories/telegraf-params-factory';
// TODO: DELETE THIS CLASS
@Injectable()
export class TelegrafUpdateExplorer implements OnModuleInit {
private readonly telegrafParamsFactory = new TelegrafParamsFactory();
@ -37,7 +39,7 @@ export class TelegrafUpdateExplorer implements OnModuleInit {
}
private exploreProviders(
providers: Map<string, InstanceWrapper<IInjectable>>,
providers: Map<string, InstanceWrapper<unknown>>,
moduleName: string,
): void {
[...providers.values()]

View File

@ -1,15 +1,18 @@
import { ParamsFactory } from '@nestjs/core/helpers/external-context-creator';
import { Context } from 'telegraf';
import { TelegrafParamtype } from '../enums/telegraf-paramtype.enum';
export class TelegrafParamsFactory {
exchangeKeyForValue<
TContext extends Record<string, any> = any,
TResult = any
>(type: number, ctx: TContext, next: Function): TResult {
switch (type as TelegrafParamtype) {
export class TelegrafParamsFactory implements ParamsFactory {
exchangeKeyForValue(
type: TelegrafParamtype,
ctx: Context,
next: Function,
): unknown {
switch (type) {
case TelegrafParamtype.CONTEXT:
return ctx as any;
return ctx;
case TelegrafParamtype.NEXT:
return next as any;
return next;
case TelegrafParamtype.SENDER:
return ctx.from;
case TelegrafParamtype.MESSAGE:

View File

@ -6,17 +6,30 @@ import { Module } from '@nestjs/core/injector/module';
import { BaseScene, Composer, Stage, Telegraf } from 'telegraf';
import { MetadataAccessorService } from './metadata-accessor.service';
import { TELEGRAF_MODULE_OPTIONS } from '../telegraf.constants';
import { TelegrafModuleOptions } from '../interfaces';
import {
PARAM_ARGS_METADATA,
TELEGRAF_MODULE_OPTIONS,
} from '../telegraf.constants';
import { ListenerMetadata, TelegrafModuleOptions } from '../interfaces';
import { BaseExplorerService } from './base-explorer.service';
import { getBotToken } from '../utils';
import { ExternalContextCreator } from '@nestjs/core/helpers/external-context-creator';
import { TelegrafParamsFactory } from '../factories/telegraf-params-factory';
import { TelegrafContextType } from '../execution-context/telegraf-execution-context';
import { ParamMetadata } from '@nestjs/core/helpers/interfaces';
interface ListenerCallbackMetadata {
methodName: string;
metadata: ListenerMetadata;
}
@Injectable()
export class ListenersExplorerService
extends BaseExplorerService
implements OnModuleInit {
private readonly telegrafParamsFactory = new TelegrafParamsFactory();
private readonly stage = new Stage([]);
private bot: Telegraf<any>;
private bot: Telegraf<never>;
constructor(
@Inject(TELEGRAF_MODULE_OPTIONS)
@ -26,6 +39,7 @@ export class ListenersExplorerService
private readonly metadataAccessor: MetadataAccessorService,
private readonly metadataScanner: MetadataScanner,
private readonly modulesContainer: ModulesContainer,
private readonly externalContextCreator: ExternalContextCreator,
) {
super();
}
@ -58,17 +72,18 @@ export class ListenersExplorerService
}
private registerScenes(modules: Module[]): void {
const scenes = this.flatMap<InstanceWrapper>(modules, (instance) =>
this.filterScenes(instance),
const scenes = this.flatMap<InstanceWrapper>(
modules,
(instance, moduleRef) => this.filterScenes(instance),
);
scenes.forEach(({ instance }) => {
scenes.forEach((wrapper) => {
const sceneId = this.metadataAccessor.getSceneMetadata(
instance.constructor,
);
const scene = new BaseScene(sceneId);
this.stage.register(scene);
this.registerInstanceMethodListeners(scene, instance);
this.registerInstanceMethodListeners(scene, wrapper);
});
}
@ -94,18 +109,63 @@ export class ListenersExplorerService
private registerInstanceMethodListeners(
composer: Composer<never>,
instance: Record<string, Function>,
wrapper: InstanceWrapper<unknown>,
): void {
const { instance } = wrapper;
const prototype = Object.getPrototypeOf(instance);
this.metadataScanner.scanFromPrototype(instance, prototype, (name) => {
const methodRef = instance[name];
const listenersMetadata = this.metadataScanner.scanFromPrototype(
instance,
prototype,
(name): ListenerCallbackMetadata =>
this.extractListenerCallbackMetadata(prototype, name),
);
const metadata = this.metadataAccessor.getListenerMetadata(methodRef);
if (!metadata) return;
const contextCallbackFn = this.createContextCallback(
instance,
prototype,
wrapper,
);
}
const middlewareFn = methodRef.bind(instance);
const { method, args } = metadata;
composer[method](...args, middlewareFn);
});
private extractListenerCallbackMetadata(
prototype: any,
methodName: string,
): ListenerCallbackMetadata {
const callback = prototype[methodName];
const metadata = this.metadataAccessor.getListenerMetadata(callback);
if (!metadata) {
return undefined;
}
return {
methodName,
metadata: metadata,
};
}
createContextCallback<T extends Record<string, unknown>>(
instance: T,
prototype: unknown,
wrapper: InstanceWrapper,
moduleRef: Module,
listener: ListenerMetadata,
) {
const paramsFactory = this.telegrafParamsFactory;
const resolverCallback = this.externalContextCreator.create<
Record<number, ParamMetadata>,
TelegrafContextType
>(
instance,
prototype[listener.methodName],
listener.methodName,
PARAM_ARGS_METADATA,
paramsFactory,
undefined,
undefined,
undefined,
'telegraf',
);
return resolverCallback;
}
}

View File

@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import {
SCENE_METADATA,
UPDATE_LISTENER_METADATA,
LISTENER_METADATA,
UPDATE_METADATA,
} from '../telegraf.constants';
import { ListenerMetadata } from '../interfaces';
@ -27,7 +27,7 @@ export class MetadataAccessorService {
}
getListenerMetadata(target: Function): ListenerMetadata | undefined {
return this.reflector.get(UPDATE_LISTENER_METADATA, target);
return this.reflector.get(LISTENER_METADATA, target);
}
getSceneMetadata(target: Function): string | undefined {

View File

@ -4,8 +4,7 @@ export const TELEGRAF_MODULE_OPTIONS = 'TELEGRAF_MODULE_OPTIONS';
export const DEFAULT_BOT_NAME = 'DEFAULT_BOT_NAME';
export const UPDATE_METADATA = 'UPDATE_METADATA';
export const UPDATE_LISTENER_METADATA = 'UPDATE_LISTENER_METADATA';
export const SCENE_METADATA = 'SCENE_METADATA';
export const LISTENER_METADATA = 'LISTENER_METADATA';
export const PARAM_ARGS_METADATA = ROUTE_ARGS_METADATA;

View File

@ -1,7 +1,7 @@
import { SetMetadata } from '@nestjs/common';
import { BaseScene as Scene } from 'telegraf';
import { ComposerMethodArgs, SceneMethods } from '../types';
import { UPDATE_LISTENER_METADATA } from '../telegraf.constants';
import { LISTENER_METADATA } from '../telegraf.constants';
import { ListenerMetadata } from '../interfaces';
export function createListenerDecorator<TMethod extends SceneMethods>(
@ -10,7 +10,7 @@ export function createListenerDecorator<TMethod extends SceneMethods>(
return (
...args: ComposerMethodArgs<Scene<never>, TMethod>
): MethodDecorator => {
return SetMetadata(UPDATE_LISTENER_METADATA, {
return SetMetadata(LISTENER_METADATA, {
method,
args,
} as ListenerMetadata);
@ -21,7 +21,7 @@ export function createMissedListenerDecorator<TArgs extends any[]>(
method: string,
) {
return (...args: TArgs): MethodDecorator => {
return SetMetadata(UPDATE_LISTENER_METADATA, {
return SetMetadata(LISTENER_METADATA, {
method,
args,
} as ListenerMetadata);

View File

@ -48,39 +48,3 @@ export const addPipesMetadata = (
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,
// );
// };