Commit b0b1f631 authored by nanahira's avatar nanahira

support fastify

parent e056bf1b
This diff is collapsed.
import { Injectable, NestMiddleware } from '@nestjs/common';
import { NextFunction, Request, Response } from 'express';
import { NextFunction } from 'express';
import { KoishiService } from '../koishi.service';
import { IncomingMessage, ServerResponse } from 'http';
import { Http2ServerRequest, Http2ServerResponse } from 'http2';
import { parse } from 'url';
export type RequestWithOriginalUrl = IncomingMessage & { originalUrl?: string };
@Injectable()
export class KoishiMiddleware implements NestMiddleware<Request, Response> {
export class KoishiMiddleware
implements NestMiddleware<RequestWithOriginalUrl, ServerResponse>
{
private readonly koaCallback: (
req: IncomingMessage | Http2ServerRequest,
res: ServerResponse | Http2ServerResponse,
......@@ -14,10 +19,10 @@ export class KoishiMiddleware implements NestMiddleware<Request, Response> {
this.koaCallback = this.koishi._nestKoaTmpInstance.callback();
}
use(req: Request, res: Response, next: NextFunction) {
const baseUrl = req.baseUrl || req.url;
const exactUrl = req.originalUrl || baseUrl;
const match = this.koishi.router.match(baseUrl, req.method);
use(req: RequestWithOriginalUrl, res: ServerResponse, next: NextFunction) {
const exactUrl = req.originalUrl || req.url;
const matchingUrl = parse(exactUrl).pathname || '';
const match = this.koishi.router.match(matchingUrl, req.method);
if (!match.route) {
return next();
}
......
import {
FastifyAdapter,
NestFastifyApplication,
} from '@nestjs/platform-fastify';
import { KoishiService } from '../src/koishi.service';
import { testingModule } from './utility/testing-module';
import { KoishiWsAdapter } from '../src/koishi.ws-adapter';
import http from 'http';
import request from 'supertest';
describe('Koishi module in Fastify adapter', () => {
let app: NestFastifyApplication;
let koishiApp: KoishiService;
beforeEach(async () => {
const moduleFixture = await testingModule();
app = moduleFixture.createNestApplication<NestFastifyApplication>(
new FastifyAdapter(),
);
app.useWebSocketAdapter(new KoishiWsAdapter(app));
await app.init();
koishiApp = app.get(KoishiService);
});
it('should define koishi', () => {
expect(koishiApp).toBeDefined();
});
it('should register http and ws server', () => {
expect(koishiApp._httpServer).toBeDefined();
expect(koishiApp._wsServer).toBeDefined();
});
it('should be nest http server', () => {
expect(koishiApp._httpServer).toBeInstanceOf(http.Server);
expect(app.getHttpServer()).toEqual(koishiApp._httpServer);
});
it('should response to koishi routes', () => {
koishiApp.router.get('/ping', (ctx) => {
ctx.status = 233;
ctx.body = 'pong';
});
return app.inject({ method: 'GET', url: '/ping/?test=1' }).then((res) => {
expect(res.statusCode).toBe(233);
expect(res.body).toBe('pong');
});
});
});
import { Test } from '@nestjs/testing';
import { KoishiModule } from '../src/koishi.module';
import { KoishiService } from '../src/koishi.service';
import {
INestApplication,
Injectable,
NotFoundException,
} from '@nestjs/common';
import { INestApplication } from '@nestjs/common';
import { KoishiWsAdapter } from '../src/koishi.ws-adapter';
import http from 'http';
import request from 'supertest';
import {
CommandUsage,
OnGuild,
OnPlatform,
PutOption,
UseCommand,
} from 'koishi-decorators';
import { Session } from 'koishi';
import { KoishiCommandInterceptor } from '../src/utility/koishi.interfaces';
import { Argv } from 'koishi';
import { CommandInterceptors } from '../src/utility/koishi.decorators';
@Injectable()
class MooInterceptor implements KoishiCommandInterceptor {
intercept(argv: Argv) {
return 'moo!';
}
}
@Injectable()
class PooInterceptor implements KoishiCommandInterceptor {
intercept(argv: Argv) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
if (argv.options?.content === 'poo') {
return 'poo!';
}
}
}
@Injectable()
class PeeInterceptor implements KoishiCommandInterceptor {
intercept(argv: Argv) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
if (argv.options?.content === 'pee') {
return 'pee!';
}
}
}
@OnPlatform('discord')
@Injectable()
@CommandInterceptors(PooInterceptor)
class KoishiTestService {
@OnGuild('1111111111')
@UseCommand('echo', 'hi')
@CommandUsage('foo')
async onEcho(@PutOption('content', '-c <content:string>') content: string) {
return `bot: ${content}`;
}
@UseCommand('boo')
async onBoo(@PutOption('content', '-c <content:string>') content: string) {
throw new NotFoundException(`boo: ${content}`);
}
@UseCommand('bow')
async onBow() {
throw new Error('bow!');
}
@UseCommand('moo')
@CommandInterceptors(MooInterceptor)
async onMoo() {
return 'zzzz';
}
}
import { testingModule } from './utility/testing-module';
describe('Koishi in Nest.js', () => {
let app: INestApplication;
let koishiApp: KoishiService;
beforeEach(async () => {
const moduleFixture = await Test.createTestingModule({
imports: [
KoishiModule.register({
useWs: true,
globalInterceptors: [PeeInterceptor],
}),
],
providers: [
KoishiTestService,
MooInterceptor,
PooInterceptor,
PeeInterceptor,
],
}).compile();
const moduleFixture = await testingModule();
app = moduleFixture.createNestApplication();
app.useWebSocketAdapter(new KoishiWsAdapter(app));
await app.init();
......@@ -122,7 +37,10 @@ describe('Koishi in Nest.js', () => {
ctx.status = 233;
ctx.body = 'pong';
});
return request(app.getHttpServer()).get('/ping').expect(233).expect('pong');
return request(app.getHttpServer())
.get('/ping/?test=1')
.expect(233)
.expect('pong');
});
it('should register command', () => {
......
import { Injectable, NotFoundException } from '@nestjs/common';
import { KoishiCommandInterceptor } from '../../src/utility/koishi.interfaces';
import { Argv } from 'koishi';
import {
CommandUsage,
OnGuild,
OnPlatform,
PutOption,
UseCommand,
} from 'koishi-decorators';
import { CommandInterceptors } from '../../src/utility/koishi.decorators';
import { Test } from '@nestjs/testing';
import { KoishiModule } from '../../src/koishi.module';
@Injectable()
class MooInterceptor implements KoishiCommandInterceptor {
intercept(argv: Argv) {
return 'moo!';
}
}
@Injectable()
class PooInterceptor implements KoishiCommandInterceptor {
intercept(argv: Argv) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
if (argv.options?.content === 'poo') {
return 'poo!';
}
}
}
@Injectable()
class PeeInterceptor implements KoishiCommandInterceptor {
intercept(argv: Argv) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
if (argv.options?.content === 'pee') {
return 'pee!';
}
}
}
@OnPlatform('discord')
@Injectable()
@CommandInterceptors(PooInterceptor)
class KoishiTestService {
@OnGuild('1111111111')
@UseCommand('echo', 'hi')
@CommandUsage('foo')
async onEcho(@PutOption('content', '-c <content:string>') content: string) {
return `bot: ${content}`;
}
@UseCommand('boo')
async onBoo(@PutOption('content', '-c <content:string>') content: string) {
throw new NotFoundException(`boo: ${content}`);
}
@UseCommand('bow')
async onBow() {
throw new Error('bow!');
}
@UseCommand('moo')
@CommandInterceptors(MooInterceptor)
async onMoo() {
return 'zzzz';
}
}
export function testingModule() {
return Test.createTestingModule({
imports: [
KoishiModule.register({
useWs: true,
globalInterceptors: [PeeInterceptor],
}),
],
providers: [
KoishiTestService,
MooInterceptor,
PooInterceptor,
PeeInterceptor,
],
}).compile();
}
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