mirror of
https://github.com/Maks1mS/nestjs-telegraf.git
synced 2024-12-25 07:24:39 +03:00
feat(): wip
This commit is contained in:
parent
320ee3077e
commit
75ff810c34
@ -1,17 +1,19 @@
|
|||||||
import { Inject, Injectable, OnModuleInit } from '@nestjs/common';
|
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 { 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 { isFunction, isNil } from '@nestjs/common/utils/shared.utils';
|
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 { 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 { ExternalContextCreator } from '@nestjs/core/helpers/external-context-creator';
|
|
||||||
import { TelegrafParamsFactory } from '../factories/telegraf-params-factory';
|
import { TelegrafParamsFactory } from '../factories/telegraf-params-factory';
|
||||||
|
|
||||||
|
// TODO: DELETE THIS CLASS
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TelegrafUpdateExplorer implements OnModuleInit {
|
export class TelegrafUpdateExplorer implements OnModuleInit {
|
||||||
private readonly telegrafParamsFactory = new TelegrafParamsFactory();
|
private readonly telegrafParamsFactory = new TelegrafParamsFactory();
|
||||||
@ -37,7 +39,7 @@ export class TelegrafUpdateExplorer implements OnModuleInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private exploreProviders(
|
private exploreProviders(
|
||||||
providers: Map<string, InstanceWrapper<IInjectable>>,
|
providers: Map<string, InstanceWrapper<unknown>>,
|
||||||
moduleName: string,
|
moduleName: string,
|
||||||
): void {
|
): void {
|
||||||
[...providers.values()]
|
[...providers.values()]
|
||||||
|
@ -1,15 +1,18 @@
|
|||||||
|
import { ParamsFactory } from '@nestjs/core/helpers/external-context-creator';
|
||||||
|
import { Context } from 'telegraf';
|
||||||
import { TelegrafParamtype } from '../enums/telegraf-paramtype.enum';
|
import { TelegrafParamtype } from '../enums/telegraf-paramtype.enum';
|
||||||
|
|
||||||
export class TelegrafParamsFactory {
|
export class TelegrafParamsFactory implements ParamsFactory {
|
||||||
exchangeKeyForValue<
|
exchangeKeyForValue(
|
||||||
TContext extends Record<string, any> = any,
|
type: TelegrafParamtype,
|
||||||
TResult = any
|
ctx: Context,
|
||||||
>(type: number, ctx: TContext, next: Function): TResult {
|
next: Function,
|
||||||
switch (type as TelegrafParamtype) {
|
): unknown {
|
||||||
|
switch (type) {
|
||||||
case TelegrafParamtype.CONTEXT:
|
case TelegrafParamtype.CONTEXT:
|
||||||
return ctx as any;
|
return ctx;
|
||||||
case TelegrafParamtype.NEXT:
|
case TelegrafParamtype.NEXT:
|
||||||
return next as any;
|
return next;
|
||||||
case TelegrafParamtype.SENDER:
|
case TelegrafParamtype.SENDER:
|
||||||
return ctx.from;
|
return ctx.from;
|
||||||
case TelegrafParamtype.MESSAGE:
|
case TelegrafParamtype.MESSAGE:
|
||||||
|
@ -6,17 +6,30 @@ import { Module } from '@nestjs/core/injector/module';
|
|||||||
import { BaseScene, Composer, Stage, Telegraf } from 'telegraf';
|
import { BaseScene, Composer, Stage, Telegraf } from 'telegraf';
|
||||||
|
|
||||||
import { MetadataAccessorService } from './metadata-accessor.service';
|
import { MetadataAccessorService } from './metadata-accessor.service';
|
||||||
import { TELEGRAF_MODULE_OPTIONS } from '../telegraf.constants';
|
import {
|
||||||
import { TelegrafModuleOptions } from '../interfaces';
|
PARAM_ARGS_METADATA,
|
||||||
|
TELEGRAF_MODULE_OPTIONS,
|
||||||
|
} from '../telegraf.constants';
|
||||||
|
import { ListenerMetadata, TelegrafModuleOptions } from '../interfaces';
|
||||||
import { BaseExplorerService } from './base-explorer.service';
|
import { BaseExplorerService } from './base-explorer.service';
|
||||||
import { getBotToken } from '../utils';
|
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()
|
@Injectable()
|
||||||
export class ListenersExplorerService
|
export class ListenersExplorerService
|
||||||
extends BaseExplorerService
|
extends BaseExplorerService
|
||||||
implements OnModuleInit {
|
implements OnModuleInit {
|
||||||
|
private readonly telegrafParamsFactory = new TelegrafParamsFactory();
|
||||||
private readonly stage = new Stage([]);
|
private readonly stage = new Stage([]);
|
||||||
private bot: Telegraf<any>;
|
private bot: Telegraf<never>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(TELEGRAF_MODULE_OPTIONS)
|
@Inject(TELEGRAF_MODULE_OPTIONS)
|
||||||
@ -26,6 +39,7 @@ export class ListenersExplorerService
|
|||||||
private readonly metadataAccessor: MetadataAccessorService,
|
private readonly metadataAccessor: MetadataAccessorService,
|
||||||
private readonly metadataScanner: MetadataScanner,
|
private readonly metadataScanner: MetadataScanner,
|
||||||
private readonly modulesContainer: ModulesContainer,
|
private readonly modulesContainer: ModulesContainer,
|
||||||
|
private readonly externalContextCreator: ExternalContextCreator,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
@ -58,17 +72,18 @@ export class ListenersExplorerService
|
|||||||
}
|
}
|
||||||
|
|
||||||
private registerScenes(modules: Module[]): void {
|
private registerScenes(modules: Module[]): void {
|
||||||
const scenes = this.flatMap<InstanceWrapper>(modules, (instance) =>
|
const scenes = this.flatMap<InstanceWrapper>(
|
||||||
this.filterScenes(instance),
|
modules,
|
||||||
|
(instance, moduleRef) => this.filterScenes(instance),
|
||||||
);
|
);
|
||||||
scenes.forEach(({ instance }) => {
|
scenes.forEach((wrapper) => {
|
||||||
const sceneId = this.metadataAccessor.getSceneMetadata(
|
const sceneId = this.metadataAccessor.getSceneMetadata(
|
||||||
instance.constructor,
|
instance.constructor,
|
||||||
);
|
);
|
||||||
const scene = new BaseScene(sceneId);
|
const scene = new BaseScene(sceneId);
|
||||||
this.stage.register(scene);
|
this.stage.register(scene);
|
||||||
|
|
||||||
this.registerInstanceMethodListeners(scene, instance);
|
this.registerInstanceMethodListeners(scene, wrapper);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,18 +109,63 @@ export class ListenersExplorerService
|
|||||||
|
|
||||||
private registerInstanceMethodListeners(
|
private registerInstanceMethodListeners(
|
||||||
composer: Composer<never>,
|
composer: Composer<never>,
|
||||||
instance: Record<string, Function>,
|
wrapper: InstanceWrapper<unknown>,
|
||||||
): void {
|
): void {
|
||||||
|
const { instance } = wrapper;
|
||||||
const prototype = Object.getPrototypeOf(instance);
|
const prototype = Object.getPrototypeOf(instance);
|
||||||
this.metadataScanner.scanFromPrototype(instance, prototype, (name) => {
|
const listenersMetadata = this.metadataScanner.scanFromPrototype(
|
||||||
const methodRef = instance[name];
|
instance,
|
||||||
|
prototype,
|
||||||
|
(name): ListenerCallbackMetadata =>
|
||||||
|
this.extractListenerCallbackMetadata(prototype, name),
|
||||||
|
);
|
||||||
|
|
||||||
const metadata = this.metadataAccessor.getListenerMetadata(methodRef);
|
const contextCallbackFn = this.createContextCallback(
|
||||||
if (!metadata) return;
|
instance,
|
||||||
|
prototype,
|
||||||
|
wrapper,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const middlewareFn = methodRef.bind(instance);
|
private extractListenerCallbackMetadata(
|
||||||
const { method, args } = metadata;
|
prototype: any,
|
||||||
composer[method](...args, middlewareFn);
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
|
|||||||
import { Reflector } from '@nestjs/core';
|
import { Reflector } from '@nestjs/core';
|
||||||
import {
|
import {
|
||||||
SCENE_METADATA,
|
SCENE_METADATA,
|
||||||
UPDATE_LISTENER_METADATA,
|
LISTENER_METADATA,
|
||||||
UPDATE_METADATA,
|
UPDATE_METADATA,
|
||||||
} from '../telegraf.constants';
|
} from '../telegraf.constants';
|
||||||
import { ListenerMetadata } from '../interfaces';
|
import { ListenerMetadata } from '../interfaces';
|
||||||
@ -27,7 +27,7 @@ export class MetadataAccessorService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getListenerMetadata(target: Function): ListenerMetadata | undefined {
|
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 {
|
getSceneMetadata(target: Function): string | undefined {
|
||||||
|
@ -4,8 +4,7 @@ export const TELEGRAF_MODULE_OPTIONS = 'TELEGRAF_MODULE_OPTIONS';
|
|||||||
export const DEFAULT_BOT_NAME = 'DEFAULT_BOT_NAME';
|
export const DEFAULT_BOT_NAME = 'DEFAULT_BOT_NAME';
|
||||||
|
|
||||||
export const UPDATE_METADATA = 'UPDATE_METADATA';
|
export const UPDATE_METADATA = 'UPDATE_METADATA';
|
||||||
export const UPDATE_LISTENER_METADATA = 'UPDATE_LISTENER_METADATA';
|
|
||||||
|
|
||||||
export const SCENE_METADATA = 'SCENE_METADATA';
|
export const SCENE_METADATA = 'SCENE_METADATA';
|
||||||
|
export const LISTENER_METADATA = 'LISTENER_METADATA';
|
||||||
|
|
||||||
export const PARAM_ARGS_METADATA = ROUTE_ARGS_METADATA;
|
export const PARAM_ARGS_METADATA = ROUTE_ARGS_METADATA;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { SetMetadata } from '@nestjs/common';
|
import { SetMetadata } from '@nestjs/common';
|
||||||
import { BaseScene as Scene } from 'telegraf';
|
import { BaseScene as Scene } from 'telegraf';
|
||||||
import { ComposerMethodArgs, SceneMethods } from '../types';
|
import { ComposerMethodArgs, SceneMethods } from '../types';
|
||||||
import { UPDATE_LISTENER_METADATA } from '../telegraf.constants';
|
import { LISTENER_METADATA } from '../telegraf.constants';
|
||||||
import { ListenerMetadata } from '../interfaces';
|
import { ListenerMetadata } from '../interfaces';
|
||||||
|
|
||||||
export function createListenerDecorator<TMethod extends SceneMethods>(
|
export function createListenerDecorator<TMethod extends SceneMethods>(
|
||||||
@ -10,7 +10,7 @@ export function createListenerDecorator<TMethod extends SceneMethods>(
|
|||||||
return (
|
return (
|
||||||
...args: ComposerMethodArgs<Scene<never>, TMethod>
|
...args: ComposerMethodArgs<Scene<never>, TMethod>
|
||||||
): MethodDecorator => {
|
): MethodDecorator => {
|
||||||
return SetMetadata(UPDATE_LISTENER_METADATA, {
|
return SetMetadata(LISTENER_METADATA, {
|
||||||
method,
|
method,
|
||||||
args,
|
args,
|
||||||
} as ListenerMetadata);
|
} as ListenerMetadata);
|
||||||
@ -21,7 +21,7 @@ export function createMissedListenerDecorator<TArgs extends any[]>(
|
|||||||
method: string,
|
method: string,
|
||||||
) {
|
) {
|
||||||
return (...args: TArgs): MethodDecorator => {
|
return (...args: TArgs): MethodDecorator => {
|
||||||
return SetMetadata(UPDATE_LISTENER_METADATA, {
|
return SetMetadata(LISTENER_METADATA, {
|
||||||
method,
|
method,
|
||||||
args,
|
args,
|
||||||
} as ListenerMetadata);
|
} as ListenerMetadata);
|
||||||
|
@ -48,39 +48,3 @@ export const addPipesMetadata = (
|
|||||||
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