Commit ecf63787 authored by nanahira's avatar nanahira

support all koa routes

parent 23d82194
Pipeline #6074 failed with stages
in 1 minute and 40 seconds
import { ModuleMetadata, Provider, Type } from '@nestjs/common'; import { ModuleMetadata, Provider, Type } from '@nestjs/common';
import { App, Plugin, MaybeArray } from 'koishi'; import { App, MaybeArray, Plugin } from 'koishi';
import { AbstractHttpAdapter } from '@nestjs/core'; import { AbstractHttpAdapter } from '@nestjs/core';
const selectors = [ const selectors = [
......
import { Injectable, NestMiddleware, OnModuleInit } from '@nestjs/common';
import { NextFunction, Request, Response } from 'express';
import { KoishiService } from './koishi.service';
import { createProxyMiddleware, RequestHandler } from 'http-proxy-middleware';
@Injectable()
export class KoishiMiddleware
implements NestMiddleware<Request, Response>, OnModuleInit {
constructor(private koishi: KoishiService) {}
private proxyMiddleware: RequestHandler;
async onModuleInit() {
this.proxyMiddleware = createProxyMiddleware({
target: `http://localhost:${this.koishi._nestKoaTmpServerPort}`,
ws: true,
logLevel: 'silent',
});
}
use(req: Request, res: Response, next: NextFunction) {
const match = this.koishi.router.match(req.baseUrl, req.method);
if (
!match.route &&
// ws-reverse onebot goes here
!req.header('x-self-id')
) {
return next();
}
return this.proxyMiddleware(req, res, next);
}
}
import { import {
DynamicModule, DynamicModule,
MiddlewareConsumer,
Module, Module,
OnApplicationShutdown, NestModule,
Provider, Provider,
} from '@nestjs/common'; } from '@nestjs/common';
import { ModuleRef } from '@nestjs/core';
import { import {
KoishiModuleAsyncOptions, KoishiModuleAsyncOptions,
KoishiModuleOptions, KoishiModuleOptions,
...@@ -17,6 +17,9 @@ import { ...@@ -17,6 +17,9 @@ import {
KOISHI_CONTEXT_PRIVATE, KOISHI_CONTEXT_PRIVATE,
KOISHI_MODULE_OPTIONS, KOISHI_MODULE_OPTIONS,
} from './koishi.constants'; } from './koishi.constants';
import { KoishiMiddleware } from './koishi.middleware';
import { createServer } from 'http';
import { AddressInfo } from 'net';
const koishiContextProvider: Provider = { const koishiContextProvider: Provider = {
provide: KOISHI_CONTEXT, provide: KOISHI_CONTEXT,
...@@ -38,10 +41,25 @@ const koishiContextProviderPrivate: Provider = { ...@@ -38,10 +41,25 @@ const koishiContextProviderPrivate: Provider = {
@Module({ @Module({
providers: [ providers: [
KoishiService, {
provide: KoishiService,
inject: [KOISHI_MODULE_OPTIONS],
useFactory: async (options: KoishiModuleOptions) => {
const koishi = new KoishiService(options);
koishi._nestKoaTmpServer = createServer(
koishi._nestKoaTmpInstance.callback(),
);
await new Promise<void>((resolve) => {
koishi._nestKoaTmpServer.listen(0, 'localhost', resolve);
});
koishi._nestKoaTmpServerPort = (koishi._nestKoaTmpServer.address() as AddressInfo).port;
return koishi;
},
},
koishiContextProvider, koishiContextProvider,
koishiContextProviderChannel, koishiContextProviderChannel,
koishiContextProviderPrivate, koishiContextProviderPrivate,
KoishiMiddleware,
], ],
exports: [ exports: [
KoishiService, KoishiService,
...@@ -50,8 +68,10 @@ const koishiContextProviderPrivate: Provider = { ...@@ -50,8 +68,10 @@ const koishiContextProviderPrivate: Provider = {
koishiContextProviderPrivate, koishiContextProviderPrivate,
], ],
}) })
export class KoishiModule implements OnApplicationShutdown { export class KoishiModule implements NestModule {
constructor(private readonly moduleRef: ModuleRef) {} configure(consumer: MiddlewareConsumer) {
consumer.apply(KoishiMiddleware).forRoutes('*');
}
static register(options: KoishiModuleOptions): DynamicModule { static register(options: KoishiModuleOptions): DynamicModule {
return { return {
...@@ -100,9 +120,4 @@ export class KoishiModule implements OnApplicationShutdown { ...@@ -100,9 +120,4 @@ export class KoishiModule implements OnApplicationShutdown {
inject: [options.useExisting || options.useClass], inject: [options.useExisting || options.useClass],
}; };
} }
async onApplicationShutdown() {
const koishiApp = this.moduleRef.get(KoishiService);
await koishiApp.stop();
}
} }
...@@ -3,38 +3,50 @@ import { ...@@ -3,38 +3,50 @@ import {
Inject, Inject,
Injectable, Injectable,
OnApplicationBootstrap, OnApplicationBootstrap,
OnModuleDestroy,
OnModuleInit, OnModuleInit,
} from '@nestjs/common'; } from '@nestjs/common';
import { KOISHI_MODULE_OPTIONS } from './koishi.constants'; import { KOISHI_MODULE_OPTIONS } from './koishi.constants';
import { KoishiModuleOptions } from './koishi.interfaces'; import { KoishiModuleOptions } from './koishi.interfaces';
import { Server } from 'http'; import { Server } from 'http';
import Koa from 'koa';
import KoaRouter from '@koa/router';
@Injectable() @Injectable()
export class KoishiService export class KoishiService
extends App extends App
implements OnModuleInit, OnApplicationBootstrap { implements OnModuleInit, OnApplicationBootstrap, OnModuleDestroy {
constructor( constructor(
@Inject(KOISHI_MODULE_OPTIONS) @Inject(KOISHI_MODULE_OPTIONS)
private readonly koishiModuleOptions: KoishiModuleOptions, private readonly koishiModuleOptions: KoishiModuleOptions,
) { ) {
super(koishiModuleOptions); super({
...koishiModuleOptions,
port: 0,
});
this.router = new KoaRouter();
this._nestKoaTmpInstance.use(this.router.routes());
this._nestKoaTmpInstance.use(this.router.allowedMethods());
} }
private setHttpServer() { _nestKoaTmpInstance = new Koa();
if ( _nestKoaTmpServer: Server;
this.koishiModuleOptions.httpAdapter && _nestKoaTmpServerPort: number;
!this.koishiModuleOptions.port
) { private async setHttpServer() {
if (this.koishiModuleOptions.httpAdapter) {
const httpServer: Server = this.koishiModuleOptions.httpAdapter.getHttpServer(); const httpServer: Server = this.koishiModuleOptions.httpAdapter.getHttpServer();
if (httpServer instanceof Server) { if (httpServer instanceof Server) {
this.logger('app').info('App using Nest HTTP Server.'); this.logger('app').info('App using Nest HTTP Server.');
this._httpServer = httpServer; this._httpServer = httpServer;
} }
} else {
this._httpServer = this._nestKoaTmpServer;
} }
} }
onModuleInit() { async onModuleInit() {
this.setHttpServer(); await this.setHttpServer();
if (this.koishiModuleOptions.usePlugins) { if (this.koishiModuleOptions.usePlugins) {
for (const pluginDesc of this.koishiModuleOptions.usePlugins) { for (const pluginDesc of this.koishiModuleOptions.usePlugins) {
const ctx = pluginDesc.select const ctx = pluginDesc.select
...@@ -48,4 +60,11 @@ export class KoishiService ...@@ -48,4 +60,11 @@ export class KoishiService
onApplicationBootstrap() { onApplicationBootstrap() {
return this.start(); return this.start();
} }
async onModuleDestroy() {
await this.stop();
if (this._nestKoaTmpServer) {
this._nestKoaTmpServer.close();
}
}
} }
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