mirror of
https://github.com/Maks1mS/nestjs-telegraf.git
synced 2025-03-15 22:43:45 +03:00
fix(sample-app): make possible to run app
This commit is contained in:
parent
334304a823
commit
e75415340b
@ -1,18 +0,0 @@
|
|||||||
import { SetMetadata } from '@nestjs/common';
|
|
||||||
import { Composer } from 'telegraf';
|
|
||||||
import { ComposerMethodArgs, UpdateMethods } from '../types';
|
|
||||||
import { UPDATE_LISTENER_METADATA } from '../telegraf.constants';
|
|
||||||
import { ListenerMetadata } from '../interfaces';
|
|
||||||
|
|
||||||
export function createUpdateListenerDecorator<Method extends UpdateMethods>(
|
|
||||||
method: unknown,
|
|
||||||
) {
|
|
||||||
return (
|
|
||||||
...args: ComposerMethodArgs<Composer<never>, Method>
|
|
||||||
): MethodDecorator => {
|
|
||||||
return SetMetadata(UPDATE_LISTENER_METADATA, {
|
|
||||||
method,
|
|
||||||
args,
|
|
||||||
} as ListenerMetadata);
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,2 +0,0 @@
|
|||||||
export * from './create-update-listener-decorator.helper';
|
|
||||||
export * from './create-scene-listener-decorator.helper';
|
|
@ -1,6 +0,0 @@
|
|||||||
export interface UpdateMetadata {
|
|
||||||
name: string;
|
|
||||||
type: string;
|
|
||||||
methodName: string;
|
|
||||||
callback?: Function | Record<string, any>;
|
|
||||||
}
|
|
111
lib/services/listeners-explorer.service.ts
Normal file
111
lib/services/listeners-explorer.service.ts
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
import { Inject, Injectable, OnModuleInit } from '@nestjs/common';
|
||||||
|
import { DiscoveryService, ModuleRef, ModulesContainer } from '@nestjs/core';
|
||||||
|
import { InstanceWrapper } from '@nestjs/core/injector/instance-wrapper';
|
||||||
|
import { MetadataScanner } from '@nestjs/core/metadata-scanner';
|
||||||
|
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 { BaseExplorerService } from './base-explorer.service';
|
||||||
|
import { getBotToken } from '../utils';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class TelegrafExplorerService
|
||||||
|
extends BaseExplorerService
|
||||||
|
implements OnModuleInit {
|
||||||
|
private readonly bot: Telegraf<any>;
|
||||||
|
private readonly stage = new Stage([]);
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@Inject(TELEGRAF_MODULE_OPTIONS)
|
||||||
|
private readonly telegrafOptions: TelegrafModuleOptions,
|
||||||
|
private readonly moduleRef: ModuleRef,
|
||||||
|
private readonly discoveryService: DiscoveryService,
|
||||||
|
private readonly metadataAccessor: MetadataAccessorService,
|
||||||
|
private readonly metadataScanner: MetadataScanner,
|
||||||
|
private readonly modulesContainer: ModulesContainer,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
const botToken = getBotToken(this.telegrafOptions.name);
|
||||||
|
this.bot = this.moduleRef.get<Telegraf<never>>(botToken);
|
||||||
|
this.bot.use(this.stage.middleware());
|
||||||
|
}
|
||||||
|
|
||||||
|
onModuleInit(): void {
|
||||||
|
this.explore();
|
||||||
|
}
|
||||||
|
|
||||||
|
explore(): void {
|
||||||
|
const modules = this.getModules(
|
||||||
|
this.modulesContainer,
|
||||||
|
this.telegrafOptions.include || [],
|
||||||
|
);
|
||||||
|
|
||||||
|
this.registerUpdates(modules);
|
||||||
|
this.registerScenes(modules);
|
||||||
|
}
|
||||||
|
|
||||||
|
private registerUpdates(modules: Module[]): void {
|
||||||
|
const updates = this.flatMap<InstanceWrapper>(modules, (instance) =>
|
||||||
|
this.filterUpdates(instance),
|
||||||
|
);
|
||||||
|
updates.forEach(({ instance }) =>
|
||||||
|
this.registerInstanceMethodListeners(this.bot, instance),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private registerScenes(modules: Module[]): void {
|
||||||
|
const scenes = this.flatMap<InstanceWrapper>(modules, (instance) =>
|
||||||
|
this.filterScenes(instance),
|
||||||
|
);
|
||||||
|
scenes.forEach(({ instance }) => {
|
||||||
|
const sceneId = this.metadataAccessor.getSceneMetadata(
|
||||||
|
instance.constructor,
|
||||||
|
);
|
||||||
|
const scene = new BaseScene(sceneId);
|
||||||
|
this.stage.register(scene);
|
||||||
|
|
||||||
|
this.registerInstanceMethodListeners(scene, instance);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private filterUpdates(wrapper: InstanceWrapper): InstanceWrapper<unknown> {
|
||||||
|
const { instance } = wrapper;
|
||||||
|
if (!instance) return undefined;
|
||||||
|
|
||||||
|
const isUpdate = this.metadataAccessor.isUpdate(wrapper.metatype);
|
||||||
|
if (!isUpdate) return undefined;
|
||||||
|
|
||||||
|
return wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
private filterScenes(wrapper: InstanceWrapper): InstanceWrapper<unknown> {
|
||||||
|
const { instance } = wrapper;
|
||||||
|
if (!instance) return undefined;
|
||||||
|
|
||||||
|
const isScene = this.metadataAccessor.isScene(wrapper.metatype);
|
||||||
|
if (!isScene) return undefined;
|
||||||
|
|
||||||
|
return wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
private registerInstanceMethodListeners(
|
||||||
|
composer: Composer<never>,
|
||||||
|
instance: Record<string, Function>,
|
||||||
|
): void {
|
||||||
|
const prototype = Object.getPrototypeOf(instance);
|
||||||
|
this.metadataScanner.scanFromPrototype(instance, prototype, (name) => {
|
||||||
|
const methodRef = instance[name];
|
||||||
|
|
||||||
|
const metadata = this.metadataAccessor.getListenerMetadata(methodRef);
|
||||||
|
if (!metadata) return;
|
||||||
|
|
||||||
|
const middlewareFn = methodRef.bind(instance);
|
||||||
|
const { method, args } = metadata;
|
||||||
|
composer[method](...args, middlewareFn);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,98 +0,0 @@
|
|||||||
import { Inject, Injectable, OnModuleInit } from '@nestjs/common';
|
|
||||||
import { DiscoveryService, ModuleRef, ModulesContainer } from '@nestjs/core';
|
|
||||||
import { MetadataScanner } from '@nestjs/core/metadata-scanner';
|
|
||||||
import { InstanceWrapper } from '@nestjs/core/injector/instance-wrapper';
|
|
||||||
import { BaseScene as Scene, Stage, Telegraf } from 'telegraf';
|
|
||||||
import { MetadataAccessorService } from './metadata-accessor.service';
|
|
||||||
import { BaseExplorerService } from './base-explorer.service';
|
|
||||||
import {
|
|
||||||
TELEGRAF_BOT_NAME,
|
|
||||||
TELEGRAF_MODULE_OPTIONS,
|
|
||||||
} from '../telegraf.constants';
|
|
||||||
import { TelegrafModuleOptions } from '../interfaces';
|
|
||||||
import { Module } from '@nestjs/core/injector/module';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class ScenesExplorerService
|
|
||||||
extends BaseExplorerService
|
|
||||||
implements OnModuleInit {
|
|
||||||
private readonly stage = new Stage([]);
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
@Inject(TELEGRAF_BOT_NAME)
|
|
||||||
private readonly botName: string,
|
|
||||||
@Inject(TELEGRAF_MODULE_OPTIONS)
|
|
||||||
private readonly telegrafModuleOptions: TelegrafModuleOptions,
|
|
||||||
private readonly moduleRef: ModuleRef,
|
|
||||||
private readonly discoveryService: DiscoveryService,
|
|
||||||
private readonly metadataAccessor: MetadataAccessorService,
|
|
||||||
private readonly metadataScanner: MetadataScanner,
|
|
||||||
private readonly modulesContainer: ModulesContainer,
|
|
||||||
) {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
private bot: Telegraf<any>;
|
|
||||||
|
|
||||||
onModuleInit(): void {
|
|
||||||
this.bot = this.moduleRef.get<Telegraf<any>>(this.botName, {
|
|
||||||
strict: false,
|
|
||||||
});
|
|
||||||
this.bot.use(this.stage.middleware());
|
|
||||||
this.explore();
|
|
||||||
}
|
|
||||||
|
|
||||||
private explore(): void {
|
|
||||||
const modules = this.getModules(
|
|
||||||
this.modulesContainer,
|
|
||||||
this.telegrafModuleOptions.include || [],
|
|
||||||
);
|
|
||||||
const scenes = this.flatMap(modules, (instance, moduleRef) =>
|
|
||||||
this.applyScenes(instance, moduleRef),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private applyScenes(wrapper: InstanceWrapper, moduleRef: Module) {
|
|
||||||
const { instance } = wrapper;
|
|
||||||
if (!instance) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
const prototype = Object.getPrototypeOf(instance);
|
|
||||||
|
|
||||||
const providers: InstanceWrapper[] = this.discoveryService.getProviders();
|
|
||||||
const sceneProviders: InstanceWrapper[] = providers.filter(
|
|
||||||
(wrapper: InstanceWrapper) =>
|
|
||||||
this.metadataAccessor.isScene(wrapper.metatype),
|
|
||||||
);
|
|
||||||
|
|
||||||
sceneProviders.forEach((wrapper) => {
|
|
||||||
const { instance } = wrapper;
|
|
||||||
if (!instance) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const sceneId = this.metadataAccessor.getSceneMetadata(
|
|
||||||
instance.constructor,
|
|
||||||
);
|
|
||||||
|
|
||||||
const scene = new Scene(sceneId);
|
|
||||||
this.stage.register(scene);
|
|
||||||
|
|
||||||
this.metadataScanner.scanFromPrototype(
|
|
||||||
instance,
|
|
||||||
prototype,
|
|
||||||
(methodKey: string) => {
|
|
||||||
const methodRef = instance[methodKey];
|
|
||||||
if (this.metadataAccessor.isUpdateListener(methodRef)) {
|
|
||||||
const metadata = this.metadataAccessor.getListenerMetadata(
|
|
||||||
methodRef,
|
|
||||||
);
|
|
||||||
const middlewareFn = methodRef.bind(instance);
|
|
||||||
const { method, args } = metadata;
|
|
||||||
(scene[method] as any)(...args, middlewareFn);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,83 +0,0 @@
|
|||||||
import { Inject, Injectable, OnModuleInit } from '@nestjs/common';
|
|
||||||
import { DiscoveryService, ModuleRef, ModulesContainer } from '@nestjs/core';
|
|
||||||
import { InstanceWrapper } from '@nestjs/core/injector/instance-wrapper';
|
|
||||||
import { MetadataScanner } from '@nestjs/core/metadata-scanner';
|
|
||||||
import { MetadataAccessorService } from './metadata-accessor.service';
|
|
||||||
import {
|
|
||||||
TELEGRAF_BOT_NAME,
|
|
||||||
TELEGRAF_MODULE_OPTIONS,
|
|
||||||
} from '../telegraf.constants';
|
|
||||||
import { Telegraf } from 'telegraf';
|
|
||||||
import { TelegrafModuleOptions } from '../interfaces';
|
|
||||||
import { BaseExplorerService } from './base-explorer.service';
|
|
||||||
import { Module } from '@nestjs/core/injector/module';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class UpdatesExplorerService
|
|
||||||
extends BaseExplorerService
|
|
||||||
implements OnModuleInit {
|
|
||||||
constructor(
|
|
||||||
@Inject(TELEGRAF_BOT_NAME)
|
|
||||||
private readonly botName: string,
|
|
||||||
@Inject(TELEGRAF_MODULE_OPTIONS)
|
|
||||||
private readonly telegrafModuleOptions: TelegrafModuleOptions,
|
|
||||||
private readonly moduleRef: ModuleRef,
|
|
||||||
private readonly discoveryService: DiscoveryService,
|
|
||||||
private readonly metadataAccessor: MetadataAccessorService,
|
|
||||||
private readonly metadataScanner: MetadataScanner,
|
|
||||||
private readonly modulesContainer: ModulesContainer,
|
|
||||||
) {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
private bot: Telegraf<any>;
|
|
||||||
|
|
||||||
onModuleInit(): void {
|
|
||||||
this.bot = this.moduleRef.get<Telegraf<any>>(this.botName, {
|
|
||||||
strict: false,
|
|
||||||
});
|
|
||||||
this.explore();
|
|
||||||
}
|
|
||||||
|
|
||||||
explore() {
|
|
||||||
const modules = this.getModules(
|
|
||||||
this.modulesContainer,
|
|
||||||
this.telegrafModuleOptions.include || [],
|
|
||||||
);
|
|
||||||
const updates = this.flatMap(modules, (instance, moduleRef) =>
|
|
||||||
this.applyUpdates(instance, moduleRef),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private applyUpdates(wrapper: InstanceWrapper, moduleRef: Module) {
|
|
||||||
const { instance } = wrapper;
|
|
||||||
if (!instance) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
const prototype = Object.getPrototypeOf(instance);
|
|
||||||
|
|
||||||
const providers: InstanceWrapper[] = this.discoveryService.getProviders();
|
|
||||||
const updateProviders: InstanceWrapper[] = providers.filter(
|
|
||||||
(wrapper: InstanceWrapper) =>
|
|
||||||
this.metadataAccessor.isUpdate(wrapper.metatype),
|
|
||||||
);
|
|
||||||
|
|
||||||
updateProviders.forEach((wrapper: InstanceWrapper) => {
|
|
||||||
const { instance } = wrapper;
|
|
||||||
if (!instance) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
this.metadataScanner.scanFromPrototype(instance, prototype, (name) => {
|
|
||||||
const methodRef = instance[name];
|
|
||||||
if (this.metadataAccessor.isUpdateListener(methodRef)) {
|
|
||||||
const metadata = this.metadataAccessor.getListenerMetadata(methodRef);
|
|
||||||
const middlewareFn = methodRef.bind(instance);
|
|
||||||
const { method, args } = metadata;
|
|
||||||
// NOTE: Use "any" to disable "Expected at least 1 arguments, but got 1 or more." error.
|
|
||||||
// Use telegraf instance for non-scene listeners
|
|
||||||
(this.bot[method] as any)(...args, middlewareFn);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,7 +4,7 @@ import { ComposerMethodArgs, SceneMethods } from '../types';
|
|||||||
import { UPDATE_LISTENER_METADATA } from '../telegraf.constants';
|
import { UPDATE_LISTENER_METADATA } from '../telegraf.constants';
|
||||||
import { ListenerMetadata } from '../interfaces';
|
import { ListenerMetadata } from '../interfaces';
|
||||||
|
|
||||||
export function createSceneListenerDecorator<Method extends SceneMethods>(
|
export function createListenerDecorator<Method extends SceneMethods>(
|
||||||
method: Method,
|
method: Method,
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
@ -30,7 +30,8 @@
|
|||||||
"prepublish:npm": "npm run build",
|
"prepublish:npm": "npm run build",
|
||||||
"publish:npm": "npm publish --access public",
|
"publish:npm": "npm publish --access public",
|
||||||
"test": "",
|
"test": "",
|
||||||
"typedoc:build": "typedoc --tsconfig ./tsconfig.typedoc.json"
|
"typedoc:build": "typedoc --tsconfig ./tsconfig.typedoc.json",
|
||||||
|
"sample-app": "ts-node --transpile-only -r tsconfig-paths/register sample/main.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"telegraf": "3.38.0"
|
"telegraf": "3.38.0"
|
||||||
@ -50,6 +51,7 @@
|
|||||||
"prettier": "2.2.1",
|
"prettier": "2.2.1",
|
||||||
"reflect-metadata": "0.1.13",
|
"reflect-metadata": "0.1.13",
|
||||||
"rxjs": "6.6.3",
|
"rxjs": "6.6.3",
|
||||||
|
"tsconfig-paths": "3.9.0",
|
||||||
"typedoc": "0.20.9",
|
"typedoc": "0.20.9",
|
||||||
"typescript": "4.1.3"
|
"typescript": "4.1.3"
|
||||||
},
|
},
|
||||||
|
@ -7,8 +7,9 @@
|
|||||||
"noLib": false,
|
"noLib": false,
|
||||||
"emitDecoratorMetadata": true,
|
"emitDecoratorMetadata": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"target": "es6",
|
"target": "es2017",
|
||||||
"sourceMap": false,
|
"sourceMap": false,
|
||||||
|
"baseUrl": "./",
|
||||||
"outDir": "./dist",
|
"outDir": "./dist",
|
||||||
"skipLibCheck": true
|
"skipLibCheck": true
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user