Commit 0aefcf6e authored by nanahira's avatar nanahira

move

parent c7aec622
......@@ -85,7 +85,7 @@ Koishi-Nest 的配置项和 Koishi 配置项一致,参照 [Koishi 文档](http
* `options` Koishi 插件配置。等同于 `ctx.plugin(plugin, options)`
* `select` 插件选择器,定义插件的作用上下文。定义参照 [Koishi 文档](https://koishi.js.org/v4/guide/plugin/context.html#%E5%9C%A8%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E4%B8%AD%E4%BD%BF%E7%94%A8%E9%80%89%E6%8B%A9%E5%99%A8) 的写法。
* `isGlobal`: `boolean` 默认 `false` 。指示 Koishi-Nest 模块是否应被注册为全局模块。 **异步配置该项应写入异步配置项中。** 关于全局模块请参考 [Nest.js 文档](https://docs.nestjs.cn/8/modules?id=%e5%85%a8%e5%b1%80%e6%a8%a1%e5%9d%97)
* `isGlobal`: `boolean` 默认 `false` 。指示 Koishi-Nest 模块是否应被注册为全局模块。当 Koishi-Nest 需要被其他模块引用的情况下,需要使用该选项。 **异步配置该项应写入异步配置项中。** 关于全局模块请参考 [Nest.js 文档](https://docs.nestjs.cn/8/modules?id=%e5%85%a8%e5%b1%80%e6%a8%a1%e5%9d%97)
插件的使用可以参考 [Koishi 文档](https://koishi.js.org/v4/guide/plugin/plugin.html)
......@@ -301,6 +301,7 @@ Koishi-Nest 使用一组装饰器进行描述指令的行为。这些装饰器
* `PluginDef(plugin: Plugin, options?: PluginConfig, select?: Selection)` 生成指令注册定义。用于 Koishi-Nest 启动参数和 `@UsePlugin()` 返回值。指令注册定义成员参数如下。
* `plugin` Koishi 插件。
* `options` Koishi 插件配置。等同于 `ctx.plugin(plugin, options)`
* `select` 插件选择器,定义插件的作用上下文。定义参照 [Koishi 文档](https://koishi.js.org/v4/guide/plugin/context.html#%E5%9C%A8%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E4%B8%AD%E4%BD%BF%E7%94%A8%E9%80%89%E6%8B%A9%E5%99%A8) 的写法。
* `plugin`: Koishi 插件。
* `options`: Koishi 插件配置。等同于 `ctx.plugin(plugin, options)`
* `select`: 插件选择器,定义插件的作用上下文。定义参照 [Koishi 文档](https://koishi.js.org/v4/guide/plugin/context.html#%E5%9C%A8%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E4%B8%AD%E4%BD%BF%E7%94%A8%E9%80%89%E6%8B%A9%E5%99%A8) 的写法。
* `useSelector`: `(ctx: Context) => Context` 使用函数进行选择。该函数接受1个 Context 参数,同时也需要返回1个 Context 对象。
import { Context } from 'koishi';
import { Provider, Scope } from '@nestjs/common';
import { KOISHI_CONTEXT } from './koishi.constants';
import { KOISHI_CONTEXT } from './utility/koishi.constants';
export type ContextScopeTypes =
| 'guild'
......@@ -26,7 +26,7 @@ function createContextProvider(
return {
provide: constructProvideToken(scopeType, values),
inject: [KOISHI_CONTEXT],
// scope: Scope.TRANSIENT,
scope: Scope.TRANSIENT,
useFactory: (ctx: Context) => ctx[scopeType](...values),
};
}
......
......@@ -4,7 +4,7 @@ import {
KoishiCommandDefinition,
KoishiDoRegister,
KoishiOnContextScope,
} from './koishi.constants';
} from './utility/koishi.constants';
import {
CommandDefinitionFun,
ContextFunction,
......
......@@ -20,10 +20,14 @@ export interface Selection extends BaseSelection {
$not?: Selection;
}
export interface KoishiModulePlugin<T extends Plugin> {
export interface ContextSelector {
select?: Selection;
useSelector?: OnContextFunction;
}
export interface KoishiModulePlugin<T extends Plugin> extends ContextSelector {
plugin: T;
options?: boolean | Plugin.Config<T>;
select?: Selection;
}
export function PluginDef<T extends Plugin>(
......@@ -34,6 +38,10 @@ export function PluginDef<T extends Plugin>(
return { plugin, options, select };
}
export interface KoishiModuleSelection extends ContextSelector {
module: Type<any>;
}
export interface WhetherGlobalOption {
isGlobal?: boolean;
}
......@@ -42,6 +50,7 @@ export interface KoishiModuleOptions extends App.Config, WhetherGlobalOption {
usePlugins?: KoishiModulePlugin<Plugin>[];
loggerPrefix?: string;
loggerColor?: number;
moduleSelection?: KoishiModuleSelection[];
}
export interface KoishiModuleOptionsFactory {
......
......@@ -4,6 +4,7 @@ import {
Module,
NestModule,
Provider,
Scope,
} from '@nestjs/common';
import {
KoishiModuleAsyncOptions,
......@@ -11,20 +12,27 @@ import {
KoishiModuleOptionsFactory,
} from './koishi.interfaces';
import { KoishiService } from './koishi.service';
import { KOISHI_CONTEXT, KOISHI_MODULE_OPTIONS } from './koishi.constants';
import { KoishiMiddleware } from './koishi.middleware';
import {
KOISHI_CONTEXT,
KOISHI_MODULE_OPTIONS,
} from './utility/koishi.constants';
import { KoishiMiddleware } from './providers/koishi.middleware';
import { createServer } from 'http';
import { AddressInfo } from 'net';
import { KoishiLoggerService } from './koishi-logger.service';
import { KoishiMetascanService } from './koishi-metascan.service';
import { DiscoveryModule } from '@nestjs/core';
import { KoishiLoggerService } from './providers/koishi-logger.service';
import { KoishiMetascanService } from './providers/koishi-metascan.service';
import { DiscoveryModule, INQUIRER } from '@nestjs/core';
import { Context } from 'koishi';
import { contextsToProvide } from './koishi-context.factory';
import { KoishiInjectionService } from './providers/koishi-injection.service';
import { KoishiContextService } from './providers/koishi-context.service';
const koishiContextProvider: Provider<Context> = {
provide: KOISHI_CONTEXT,
inject: [KoishiService],
useFactory: (koishiApp: KoishiService) => koishiApp.any(),
inject: [KoishiInjectionService, INQUIRER],
scope: Scope.TRANSIENT,
useFactory: (injectionService: KoishiInjectionService, inquirer: any) =>
injectionService.getInjectContext(inquirer),
};
@Module({
......@@ -55,6 +63,8 @@ const koishiContextProvider: Provider<Context> = {
KoishiLoggerService,
KoishiMetascanService,
koishiContextProvider,
KoishiContextService,
KoishiInjectionService,
KoishiMiddleware,
],
exports: [KoishiService, koishiContextProvider],
......
......@@ -10,7 +10,8 @@ import { Server } from 'http';
import Koa from 'koa';
import KoaRouter from '@koa/router';
import KoaBodyParser from 'koa-bodyparser';
import { KoishiMetascanService } from './koishi-metascan.service';
import { KoishiMetascanService } from './providers/koishi-metascan.service';
import { applySelector } from './utility/koishi.utility';
@Injectable()
export class KoishiService
......@@ -51,9 +52,7 @@ export class KoishiService
await this.setHttpServer();
if (this.koishiModuleOptions.usePlugins) {
for (const pluginDesc of this.koishiModuleOptions.usePlugins) {
const ctx = pluginDesc.select
? this.select(pluginDesc.select)
: this.any();
const ctx = applySelector(this, pluginDesc);
ctx.plugin(pluginDesc.plugin, pluginDesc.options);
}
}
......
import { Inject, Injectable, Type } from '@nestjs/common';
import { KOISHI_MODULE_OPTIONS } from '../utility/koishi.constants';
import {
KoishiModuleOptions,
KoishiModuleSelection,
} from '../koishi.interfaces';
import { applySelector } from '../utility/koishi.utility';
import { Context } from 'koishi';
import { Module } from '@nestjs/core/injector/module';
@Injectable()
export class KoishiContextService {
moduleSelections = new Map<Type<any>, KoishiModuleSelection>();
constructor(@Inject(KOISHI_MODULE_OPTIONS) options: KoishiModuleOptions) {
if (options.moduleSelection) {
for (const selection of options.moduleSelection) {
this.moduleSelections.set(selection.module, selection);
}
}
}
getModuleCtx(ctx: Context, module: Module) {
const moduleSelection = this.moduleSelections.get(module.metatype);
if (moduleSelection) {
return applySelector(ctx, moduleSelection);
} else {
return ctx;
}
}
}
import { Injectable } from '@nestjs/common';
import { KoishiService } from '../koishi.service';
import { KoishiContextService } from './koishi-context.service';
import { ModulesContainer } from '@nestjs/core';
@Injectable()
export class KoishiInjectionService {
constructor(
private readonly koishi: KoishiService,
private readonly ctxService: KoishiContextService,
private moduleContainer: ModulesContainer,
) {}
getInjectContext(inquerier: string | any) {
let ctx = this.koishi.any();
const token =
typeof inquerier === 'string' ? inquerier : inquerier.constructor;
for (const module of this.moduleContainer.values()) {
const targetProvider = module.getProviderByKey(token);
if (targetProvider) {
ctx = this.ctxService.getModuleCtx(ctx, module);
}
}
return ctx;
}
}
import { ConsoleLogger, Inject, Injectable } from '@nestjs/common';
import { Logger } from 'koishi';
import { KOISHI_MODULE_OPTIONS } from './koishi.constants';
import { KoishiModuleOptions } from './koishi.interfaces';
import { KOISHI_MODULE_OPTIONS } from '../utility/koishi.constants';
import { KoishiModuleOptions } from '../koishi.interfaces';
@Injectable()
export class KoishiLoggerService extends ConsoleLogger {
......
import { Injectable } from '@nestjs/common';
import {
AbstractHttpAdapter,
DiscoveryService,
HttpAdapterHost,
MetadataScanner,
ModuleRef,
ModulesContainer,
Reflector,
} from '@nestjs/core';
import { Argv, Command, Context } from 'koishi';
......@@ -13,7 +13,7 @@ import {
KoishiCommandDefinition,
KoishiDoRegister,
KoishiOnContextScope,
} from './koishi.constants';
} from '../utility/koishi.constants';
import {
CommandDefinitionFun,
ContextFunction,
......@@ -21,15 +21,19 @@ import {
EventNameAndPrepend,
KoishiModulePlugin,
OnContextFunction,
} from './koishi.interfaces';
} from '../koishi.interfaces';
import { applySelector } from '../utility/koishi.utility';
import _ from 'lodash';
import { KoishiContextService } from './koishi-context.service';
@Injectable()
export class KoishiMetascanService {
constructor(
private readonly discoveryService: DiscoveryService,
private readonly metadataScanner: MetadataScanner,
private readonly reflector: Reflector,
private readonly moduleRef: ModuleRef,
private readonly moduleContainer: ModulesContainer,
private readonly ctxService: KoishiContextService,
) {}
getHttpAdapter(): AbstractHttpAdapter {
......@@ -95,9 +99,7 @@ export class KoishiMetascanService {
if (!pluginDesc || !pluginDesc.plugin) {
throw new Error(`Invalid plugin from method ${methodKey}.`);
}
const pluginCtx = pluginDesc.select
? baseContext.select(pluginDesc.select)
: baseContext.any();
const pluginCtx = applySelector(baseContext, pluginDesc);
pluginCtx.plugin(pluginDesc.plugin, pluginDesc.options);
break;
case 'command':
......@@ -124,22 +126,29 @@ export class KoishiMetascanService {
}
async registerContext(ctx: Context) {
const providers = this.discoveryService.getProviders();
const controllers = this.discoveryService.getControllers();
const modules = Array.from(this.moduleContainer.values());
await Promise.all(
[...providers, ...controllers]
.filter((wrapper) => wrapper.isDependencyTreeStatic())
.filter((wrapper) => wrapper.instance)
.map((wrapper: InstanceWrapper) => {
const { instance } = wrapper;
const prototype = Object.getPrototypeOf(instance);
return this.metadataScanner.scanFromPrototype(
instance,
prototype,
(methodKey: string) =>
this.handleInstance(ctx, instance, methodKey),
);
_.flatten(
modules.map((module) => {
const moduleCtx = this.ctxService.getModuleCtx(ctx, module);
return [
...Array.from(module.routes.values()),
...Array.from(module.providers.values()),
]
.filter((wrapper) => wrapper.isDependencyTreeStatic())
.filter((wrapper) => wrapper.instance)
.map((wrapper: InstanceWrapper) => {
const { instance } = wrapper;
const prototype = Object.getPrototypeOf(instance);
return this.metadataScanner.scanFromPrototype(
instance,
prototype,
(methodKey: string) =>
this.handleInstance(moduleCtx, instance, methodKey),
);
});
}),
),
);
}
}
import { Injectable, NestMiddleware, OnModuleInit } from '@nestjs/common';
import { NextFunction, Request, Response } from 'express';
import { KoishiService } from './koishi.service';
import { KoishiService } from '../koishi.service';
import { createProxyMiddleware, RequestHandler } from 'http-proxy-middleware';
@Injectable()
......
import { Context } from 'koishi';
import { ContextSelector } from '../koishi.interfaces';
export function applySelector(
ctx: Context,
selector: ContextSelector,
): Context {
if (!selector) {
return ctx;
}
let targetCtx = ctx;
if (selector.select) {
targetCtx = targetCtx.select(selector.select);
}
if (selector.useSelector) {
targetCtx = selector.useSelector(targetCtx) || targetCtx;
}
return targetCtx;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment