mirror of
https://github.com/nestjs/nest.git
synced 2026-02-21 23:11:44 +00:00
feature(websockets) extract web sockets drivers
This commit is contained in:
@@ -18,6 +18,10 @@ const packages = {
|
|||||||
'platform-fastify': ts.createProject(
|
'platform-fastify': ts.createProject(
|
||||||
'packages/platform-fastify/tsconfig.json',
|
'packages/platform-fastify/tsconfig.json',
|
||||||
),
|
),
|
||||||
|
'platform-socket.io': ts.createProject(
|
||||||
|
'packages/platform-socket.io/tsconfig.json',
|
||||||
|
),
|
||||||
|
'platform-ws': ts.createProject('packages/platform-ws/tsconfig.json'),
|
||||||
};
|
};
|
||||||
const modules = Object.keys(packages);
|
const modules = Object.keys(packages);
|
||||||
const source = 'packages';
|
const source = 'packages';
|
||||||
@@ -42,7 +46,9 @@ gulp.task('copy-misc', function() {
|
|||||||
.pipe(gulp.dest(`${source}/websockets`))
|
.pipe(gulp.dest(`${source}/websockets`))
|
||||||
.pipe(gulp.dest(`${source}/testing`))
|
.pipe(gulp.dest(`${source}/testing`))
|
||||||
.pipe(gulp.dest(`${source}/platform-fastify`))
|
.pipe(gulp.dest(`${source}/platform-fastify`))
|
||||||
.pipe(gulp.dest(`${source}/platform-express`));
|
.pipe(gulp.dest(`${source}/platform-express`))
|
||||||
|
.pipe(gulp.dest(`${source}/platform-ws`))
|
||||||
|
.pipe(gulp.dest(`${source}/platform-socket.io`));
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('clean:output', function() {
|
gulp.task('clean:output', function() {
|
||||||
|
|||||||
@@ -1,19 +1,22 @@
|
|||||||
import { INestApplication } from '@nestjs/common';
|
import {
|
||||||
import { INestFastifyApplication } from '@nestjs/common/interfaces/nest-fastify-application.interface';
|
FastifyAdapter,
|
||||||
import { FastifyAdapter } from '@nestjs/platform-fastify';
|
INestFastifyApplication,
|
||||||
|
} from '@nestjs/platform-fastify';
|
||||||
import { Test } from '@nestjs/testing';
|
import { Test } from '@nestjs/testing';
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { ApplicationModule } from '../src/app.module';
|
import { ApplicationModule } from '../src/app.module';
|
||||||
|
|
||||||
describe('Hello world (fastify adapter)', () => {
|
describe('Hello world (fastify adapter)', () => {
|
||||||
let app: INestApplication & INestFastifyApplication;
|
let app: INestFastifyApplication;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const module = await Test.createTestingModule({
|
const module = await Test.createTestingModule({
|
||||||
imports: [ApplicationModule],
|
imports: [ApplicationModule],
|
||||||
}).compile();
|
}).compile();
|
||||||
|
|
||||||
app = module.createNestApplication(new FastifyAdapter());
|
app = module.createNestApplication<INestFastifyApplication>(
|
||||||
|
new FastifyAdapter(),
|
||||||
|
);
|
||||||
await app.init();
|
await app.init();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +1,30 @@
|
|||||||
import * as request from 'supertest';
|
import {
|
||||||
import { Test } from '@nestjs/testing';
|
CallHandler,
|
||||||
import { INestApplication, Injectable } from '@nestjs/common';
|
ExecutionContext,
|
||||||
import { ApplicationModule } from '../src/app.module';
|
INestApplication,
|
||||||
|
Injectable,
|
||||||
|
NestInterceptor,
|
||||||
|
} from '@nestjs/common';
|
||||||
import { APP_INTERCEPTOR } from '@nestjs/core';
|
import { APP_INTERCEPTOR } from '@nestjs/core';
|
||||||
|
import { Test } from '@nestjs/testing';
|
||||||
import { of } from 'rxjs';
|
import { of } from 'rxjs';
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
|
import * as request from 'supertest';
|
||||||
|
import { ApplicationModule } from '../src/app.module';
|
||||||
|
|
||||||
const RETURN_VALUE = 'test';
|
const RETURN_VALUE = 'test';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class OverrideInterceptor {
|
export class OverrideInterceptor implements NestInterceptor {
|
||||||
intercept(context, stream) {
|
intercept(context: ExecutionContext, next: CallHandler) {
|
||||||
return of(RETURN_VALUE);
|
return of(RETURN_VALUE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TransformInterceptor {
|
export class TransformInterceptor {
|
||||||
intercept(context, stream) {
|
intercept(context: ExecutionContext, next: CallHandler) {
|
||||||
return stream.pipe(map(data => ({ data })));
|
return next.handle().pipe(map(data => ({ data })));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,7 +47,7 @@ describe('Interceptors', () => {
|
|||||||
app = (await createTestModule(
|
app = (await createTestModule(
|
||||||
new OverrideInterceptor(),
|
new OverrideInterceptor(),
|
||||||
)).createNestApplication();
|
)).createNestApplication();
|
||||||
|
|
||||||
await app.init();
|
await app.init();
|
||||||
return request(app.getHttpServer())
|
return request(app.getHttpServer())
|
||||||
.get('/hello')
|
.get('/hello')
|
||||||
@@ -52,7 +58,7 @@ describe('Interceptors', () => {
|
|||||||
app = (await createTestModule(
|
app = (await createTestModule(
|
||||||
new TransformInterceptor(),
|
new TransformInterceptor(),
|
||||||
)).createNestApplication();
|
)).createNestApplication();
|
||||||
|
|
||||||
await app.init();
|
await app.init();
|
||||||
return request(app.getHttpServer())
|
return request(app.getHttpServer())
|
||||||
.get('/hello')
|
.get('/hello')
|
||||||
@@ -63,7 +69,7 @@ describe('Interceptors', () => {
|
|||||||
app = (await createTestModule(
|
app = (await createTestModule(
|
||||||
new TransformInterceptor(),
|
new TransformInterceptor(),
|
||||||
)).createNestApplication();
|
)).createNestApplication();
|
||||||
|
|
||||||
await app.init();
|
await app.init();
|
||||||
return request(app.getHttpServer())
|
return request(app.getHttpServer())
|
||||||
.get('/hello/stream')
|
.get('/hello/stream')
|
||||||
@@ -74,7 +80,7 @@ describe('Interceptors', () => {
|
|||||||
app = (await createTestModule(
|
app = (await createTestModule(
|
||||||
new TransformInterceptor(),
|
new TransformInterceptor(),
|
||||||
)).createNestApplication();
|
)).createNestApplication();
|
||||||
|
|
||||||
await app.init();
|
await app.init();
|
||||||
return request(app.getHttpServer())
|
return request(app.getHttpServer())
|
||||||
.get('/hello/async')
|
.get('/hello/async')
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ async function createNestApp(...gateways): Promise<INestApplication> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe('WebSocketGateway', () => {
|
describe('WebSocketGateway', () => {
|
||||||
const event = 'push';
|
|
||||||
let ws, app;
|
let ws, app;
|
||||||
|
|
||||||
it(`should handle message (2nd port)`, async () => {
|
it(`should handle message (2nd port)`, async () => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { INestApplication } from '@nestjs/common';
|
import { INestApplication } from '@nestjs/common';
|
||||||
|
import { WsAdapter } from '@nestjs/platform-ws';
|
||||||
import { Test } from '@nestjs/testing';
|
import { Test } from '@nestjs/testing';
|
||||||
import { WsAdapter } from '@nestjs/websockets/adapters/ws-adapter';
|
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import * as WebSocket from 'ws';
|
import * as WebSocket from 'ws';
|
||||||
import { ApplicationGateway } from '../src/app.gateway';
|
import { ApplicationGateway } from '../src/app.gateway';
|
||||||
|
|||||||
63
package-lock.json
generated
63
package-lock.json
generated
@@ -1686,9 +1686,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"buffer-from": {
|
"buffer-from": {
|
||||||
"version": "1.0.0",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
|
||||||
"integrity": "sha512-83apNb8KK0Se60UE1+4Ukbe3HbfELJ6UlI4ldtOGs7So4KD26orJM8hIY9lxdzP+UpItH1Yh/Y8GUvNFWFFRxA==",
|
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"buffer-more-ints": {
|
"buffer-more-ints": {
|
||||||
@@ -10492,9 +10492,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"make-error": {
|
"make-error": {
|
||||||
"version": "1.3.4",
|
"version": "1.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz",
|
||||||
"integrity": "sha512-0Dab5btKVPhibSalc9QGXb559ED7G7iLjFXBaj9Wq8O3vorueR5K5jaE3hkG6ZQINyhA/JgG6Qk4qdFQjsYV6g==",
|
"integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"make-iterator": {
|
"make-iterator": {
|
||||||
@@ -15448,47 +15448,21 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ts-node": {
|
"ts-node": {
|
||||||
"version": "6.0.1",
|
"version": "7.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz",
|
||||||
"integrity": "sha512-LDS8WJRTEztvQEXbRK/0l/apWE0BNR/USGUhVcJDe2/hbNiB/v/lCqk6YJzgwKjScgdWOAhPQsfur7hmQ1Y1jA==",
|
"integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"arrify": "^1.0.0",
|
"arrify": "^1.0.0",
|
||||||
"chalk": "^2.3.0",
|
"buffer-from": "^1.1.0",
|
||||||
"diff": "^3.1.0",
|
"diff": "^3.1.0",
|
||||||
"make-error": "^1.1.1",
|
"make-error": "^1.1.1",
|
||||||
"minimist": "^1.2.0",
|
"minimist": "^1.2.0",
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
"source-map-support": "^0.5.3",
|
"source-map-support": "^0.5.6",
|
||||||
"yn": "^2.0.0"
|
"yn": "^2.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ansi-styles": {
|
|
||||||
"version": "3.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
|
||||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"color-convert": "^1.9.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"chalk": {
|
|
||||||
"version": "2.4.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
|
|
||||||
"integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"ansi-styles": "^3.2.1",
|
|
||||||
"escape-string-regexp": "^1.0.5",
|
|
||||||
"supports-color": "^5.3.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"has-flag": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
|
||||||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"source-map": {
|
"source-map": {
|
||||||
"version": "0.6.1",
|
"version": "0.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||||
@@ -15496,23 +15470,14 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"source-map-support": {
|
"source-map-support": {
|
||||||
"version": "0.5.5",
|
"version": "0.5.9",
|
||||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.5.tgz",
|
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.9.tgz",
|
||||||
"integrity": "sha512-mR7/Nd5l1z6g99010shcXJiNEaf3fEtmLhRB/sBcQVJGodcHCULPp2y4Sfa43Kv2zq7T+Izmfp/WHCR6dYkQCA==",
|
"integrity": "sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"buffer-from": "^1.0.0",
|
"buffer-from": "^1.0.0",
|
||||||
"source-map": "^0.6.0"
|
"source-map": "^0.6.0"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"supports-color": {
|
|
||||||
"version": "5.4.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz",
|
|
||||||
"integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"has-flag": "^3.0.0"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -121,7 +121,7 @@
|
|||||||
"sinon-chai": "^2.8.0",
|
"sinon-chai": "^2.8.0",
|
||||||
"socket.io-client": "^2.0.4",
|
"socket.io-client": "^2.0.4",
|
||||||
"supertest": "^3.0.0",
|
"supertest": "^3.0.0",
|
||||||
"ts-node": "^6.0.0",
|
"ts-node": "^7.0.1",
|
||||||
"tslint": "^5.11.0",
|
"tslint": "^5.11.0",
|
||||||
"typescript": "^3.2.2"
|
"typescript": "^3.2.2"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ export {
|
|||||||
ValidationError,
|
ValidationError,
|
||||||
WebSocketAdapter,
|
WebSocketAdapter,
|
||||||
WsExceptionFilter,
|
WsExceptionFilter,
|
||||||
|
WsMessageHandler,
|
||||||
} from './interfaces';
|
} from './interfaces';
|
||||||
export * from './pipes';
|
export * from './pipes';
|
||||||
export * from './serializer';
|
export * from './serializer';
|
||||||
|
|||||||
@@ -1,16 +1,21 @@
|
|||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
export interface WebSocketAdapter<T = any> {
|
export interface WsMessageHandler<T = string> {
|
||||||
create(port: number, options?: T): any;
|
message: T;
|
||||||
bindClientConnect(server: any, callback: (...args: any[]) => void): any;
|
callback: (...args: any[]) => Observable<any> | Promise<any>;
|
||||||
bindClientDisconnect?(client: any, callback: (...args: any[]) => void): any;
|
}
|
||||||
|
export interface WebSocketAdapter<
|
||||||
|
TServer = any,
|
||||||
|
TClient = any,
|
||||||
|
TOptions = any
|
||||||
|
> {
|
||||||
|
create(port: number, options?: TOptions): TServer;
|
||||||
|
bindClientConnect(server: TServer, callback: Function): any;
|
||||||
|
bindClientDisconnect?(client: TClient, callback: Function): any;
|
||||||
bindMessageHandlers(
|
bindMessageHandlers(
|
||||||
client: any,
|
client: TClient,
|
||||||
handlers: Array<{
|
handlers: WsMessageHandler[],
|
||||||
message: any;
|
|
||||||
callback: (...args: any[]) => Observable<any> | Promise<any> | any;
|
|
||||||
}>,
|
|
||||||
transform: (data: any) => Observable<any>,
|
transform: (data: any) => Observable<any>,
|
||||||
): any;
|
): any;
|
||||||
close(server: any): any;
|
close(server: TServer): any;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,12 @@ import { RequestHandler } from '@nestjs/common/interfaces';
|
|||||||
import { CorsOptions } from '@nestjs/common/interfaces/external/cors-options.interface';
|
import { CorsOptions } from '@nestjs/common/interfaces/external/cors-options.interface';
|
||||||
import { NestApplicationOptions } from '@nestjs/common/interfaces/nest-application-options.interface';
|
import { NestApplicationOptions } from '@nestjs/common/interfaces/nest-application-options.interface';
|
||||||
|
|
||||||
export abstract class AbstractHttpAdapter<T = any> implements HttpServer {
|
export abstract class AbstractHttpAdapter<
|
||||||
protected httpServer: T;
|
TServer = any,
|
||||||
|
TRequest = any,
|
||||||
|
TResponse = any
|
||||||
|
> implements HttpServer<TRequest, TResponse> {
|
||||||
|
protected httpServer: TServer;
|
||||||
|
|
||||||
constructor(protected readonly instance: any) {}
|
constructor(protected readonly instance: any) {}
|
||||||
|
|
||||||
@@ -60,11 +64,11 @@ export abstract class AbstractHttpAdapter<T = any> implements HttpServer {
|
|||||||
return this.instance.listen(port, hostname, callback);
|
return this.instance.listen(port, hostname, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getHttpServer(): T {
|
public getHttpServer(): TServer {
|
||||||
return this.httpServer as T;
|
return this.httpServer as TServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public setHttpServer(httpServer: T) {
|
public setHttpServer(httpServer: TServer) {
|
||||||
this.httpServer = httpServer;
|
this.httpServer = httpServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,12 +29,12 @@ export class ExceptionsHandler extends BaseExceptionFilter {
|
|||||||
if (isEmpty(this.filters)) return false;
|
if (isEmpty(this.filters)) return false;
|
||||||
|
|
||||||
const filter = this.filters.find(({ exceptionMetatypes }) => {
|
const filter = this.filters.find(({ exceptionMetatypes }) => {
|
||||||
const hasMetatype =
|
const typeExists =
|
||||||
!exceptionMetatypes.length ||
|
!exceptionMetatypes.length ||
|
||||||
exceptionMetatypes.some(
|
exceptionMetatypes.some(
|
||||||
ExceptionMetatype => exception instanceof ExceptionMetatype,
|
ExceptionMetatype => exception instanceof ExceptionMetatype,
|
||||||
);
|
);
|
||||||
return hasMetatype;
|
return typeExists;
|
||||||
});
|
});
|
||||||
filter && filter.func(exception, ctx);
|
filter && filter.func(exception, ctx);
|
||||||
return !!filter;
|
return !!filter;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { CanActivate } from '@nestjs/common';
|
|||||||
import { Controller } from '@nestjs/common/interfaces';
|
import { Controller } from '@nestjs/common/interfaces';
|
||||||
import { isEmpty } from '@nestjs/common/utils/shared.utils';
|
import { isEmpty } from '@nestjs/common/utils/shared.utils';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { ExecutionContextHost } from '../helpers/execution-context.host';
|
import { ExecutionContextHost } from '../helpers/execution-context-host';
|
||||||
|
|
||||||
export class GuardsConsumer {
|
export class GuardsConsumer {
|
||||||
public async tryActivate(
|
public async tryActivate(
|
||||||
|
|||||||
18
packages/core/helpers/load-adapter.ts
Normal file
18
packages/core/helpers/load-adapter.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { Logger } from '@nestjs/common';
|
||||||
|
|
||||||
|
const MISSING_REQUIRED_DEPENDENCY = (
|
||||||
|
defaultPlatform: string,
|
||||||
|
transport: string,
|
||||||
|
) =>
|
||||||
|
`No driver (${transport}) has been selected. In order to take advantage of the default driver, please, ensure to install the "${defaultPlatform}" package ($ npm install ${defaultPlatform}).`;
|
||||||
|
|
||||||
|
const logger = new Logger('PackageLoader');
|
||||||
|
|
||||||
|
export function loadAdapter(defaultPlatform: string, transport: string) {
|
||||||
|
try {
|
||||||
|
return require(defaultPlatform);
|
||||||
|
} catch (e) {
|
||||||
|
logger.error(MISSING_REQUIRED_DEPENDENCY(defaultPlatform, transport));
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ import { CallHandler, Controller } from '@nestjs/common/interfaces';
|
|||||||
import { isEmpty } from '@nestjs/common/utils/shared.utils';
|
import { isEmpty } from '@nestjs/common/utils/shared.utils';
|
||||||
import { defer, from as fromPromise, Observable } from 'rxjs';
|
import { defer, from as fromPromise, Observable } from 'rxjs';
|
||||||
import { mergeAll, switchMap } from 'rxjs/operators';
|
import { mergeAll, switchMap } from 'rxjs/operators';
|
||||||
import { ExecutionContextHost } from '../helpers/execution-context.host';
|
import { ExecutionContextHost } from '../helpers/execution-context-host';
|
||||||
|
|
||||||
export class InterceptorsConsumer {
|
export class InterceptorsConsumer {
|
||||||
public async intercept(
|
public async intercept(
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import iterate from 'iterare';
|
|||||||
import * as optional from 'optional';
|
import * as optional from 'optional';
|
||||||
import { ApplicationConfig } from './application-config';
|
import { ApplicationConfig } from './application-config';
|
||||||
import { MESSAGES } from './constants';
|
import { MESSAGES } from './constants';
|
||||||
|
import { loadAdapter } from './helpers/load-adapter';
|
||||||
import { NestContainer } from './injector/container';
|
import { NestContainer } from './injector/container';
|
||||||
import { MiddlewareContainer } from './middleware/container';
|
import { MiddlewareContainer } from './middleware/container';
|
||||||
import { MiddlewareModule } from './middleware/middleware-module';
|
import { MiddlewareModule } from './middleware/middleware-module';
|
||||||
@@ -29,8 +30,6 @@ const { SocketModule } =
|
|||||||
optional('@nestjs/websockets/socket-module') || ({} as any);
|
optional('@nestjs/websockets/socket-module') || ({} as any);
|
||||||
const { MicroservicesModule } =
|
const { MicroservicesModule } =
|
||||||
optional('@nestjs/microservices/microservices-module') || ({} as any);
|
optional('@nestjs/microservices/microservices-module') || ({} as any);
|
||||||
const { IoAdapter } =
|
|
||||||
optional('@nestjs/websockets/adapters/io-adapter') || ({} as any);
|
|
||||||
|
|
||||||
export class NestApplication extends NestApplicationContext
|
export class NestApplication extends NestApplicationContext
|
||||||
implements INestApplication {
|
implements INestApplication {
|
||||||
@@ -68,6 +67,7 @@ export class NestApplication extends NestApplicationContext
|
|||||||
public registerHttpServer() {
|
public registerHttpServer() {
|
||||||
this.httpServer = this.createServer();
|
this.httpServer = this.createServer();
|
||||||
|
|
||||||
|
const { IoAdapter } = optional('@nestjs/platform-socket.io') || ({} as any);
|
||||||
const ioAdapter = IoAdapter ? new IoAdapter(this.httpServer) : null;
|
const ioAdapter = IoAdapter ? new IoAdapter(this.httpServer) : null;
|
||||||
this.config.setIoAdapter(ioAdapter);
|
this.config.setIoAdapter(ioAdapter);
|
||||||
}
|
}
|
||||||
@@ -93,8 +93,7 @@ export class NestApplication extends NestApplicationContext
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async registerModules() {
|
public async registerModules() {
|
||||||
this.socketModule &&
|
this.registerWsModule();
|
||||||
this.socketModule.register(this.container, this.config);
|
|
||||||
|
|
||||||
if (this.microservicesModule) {
|
if (this.microservicesModule) {
|
||||||
this.microservicesModule.register(this.container, this.config);
|
this.microservicesModule.register(this.container, this.config);
|
||||||
@@ -107,6 +106,17 @@ export class NestApplication extends NestApplicationContext
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public registerWsModule() {
|
||||||
|
if (!this.socketModule) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const adapter = this.config.getIoAdapter();
|
||||||
|
if (!adapter) {
|
||||||
|
return loadAdapter('@nestjs/platform-socket.io', 'WebSockets');
|
||||||
|
}
|
||||||
|
this.socketModule.register(this.container, this.config);
|
||||||
|
}
|
||||||
|
|
||||||
public async init(): Promise<this> {
|
public async init(): Promise<this> {
|
||||||
const useBodyParser =
|
const useBodyParser =
|
||||||
this.appOptions && this.appOptions.bodyParser !== false;
|
this.appOptions && this.appOptions.bodyParser !== false;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { isFunction, isNil } from '@nestjs/common/utils/shared.utils';
|
|||||||
import { ApplicationConfig } from './application-config';
|
import { ApplicationConfig } from './application-config';
|
||||||
import { MESSAGES } from './constants';
|
import { MESSAGES } from './constants';
|
||||||
import { ExceptionsZone } from './errors/exceptions-zone';
|
import { ExceptionsZone } from './errors/exceptions-zone';
|
||||||
|
import { loadAdapter } from './helpers/load-adapter';
|
||||||
import { NestContainer } from './injector/container';
|
import { NestContainer } from './injector/container';
|
||||||
import { InstanceLoader } from './injector/instance-loader';
|
import { InstanceLoader } from './injector/instance-loader';
|
||||||
import { MetadataScanner } from './metadata-scanner';
|
import { MetadataScanner } from './metadata-scanner';
|
||||||
@@ -58,8 +59,8 @@ export class NestFactoryStatic {
|
|||||||
applicationConfig,
|
applicationConfig,
|
||||||
appOptions,
|
appOptions,
|
||||||
);
|
);
|
||||||
const target = this.createAdapterProxy<T>(instance, httpServer);
|
const target = this.createNestInstance(instance);
|
||||||
return this.createNestInstance<T>(target);
|
return this.createAdapterProxy<T>(target, httpServer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -155,18 +156,25 @@ export class NestFactoryStatic {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isFunction(receiver[prop])) {
|
if (isFunction(receiver[prop])) {
|
||||||
return (...args: any[]) => {
|
return this.createExceptionZone(receiver, prop);
|
||||||
let result;
|
|
||||||
ExceptionsZone.run(() => {
|
|
||||||
result = receiver[prop](...args);
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
return receiver[prop];
|
return receiver[prop];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private createExceptionZone(
|
||||||
|
receiver: Record<string, any>,
|
||||||
|
prop: string,
|
||||||
|
): Function {
|
||||||
|
return (...args: unknown[]) => {
|
||||||
|
let result;
|
||||||
|
ExceptionsZone.run(() => {
|
||||||
|
result = receiver[prop](...args);
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private applyLogger(options: NestApplicationContextOptions | undefined) {
|
private applyLogger(options: NestApplicationContextOptions | undefined) {
|
||||||
if (!options) {
|
if (!options) {
|
||||||
return;
|
return;
|
||||||
@@ -175,10 +183,7 @@ export class NestFactoryStatic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private createHttpAdapter<T = any>(httpServer?: T): HttpServer {
|
private createHttpAdapter<T = any>(httpServer?: T): HttpServer {
|
||||||
const { ExpressAdapter } = loadPackage(
|
const { ExpressAdapter } = loadAdapter('@nestjs/platform-express', 'HTTP');
|
||||||
'@nestjs/platform-express',
|
|
||||||
'NestFactory',
|
|
||||||
);
|
|
||||||
return new ExpressAdapter(httpServer);
|
return new ExpressAdapter(httpServer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,11 +197,11 @@ export class NestFactoryStatic {
|
|||||||
return (new Proxy(app, {
|
return (new Proxy(app, {
|
||||||
get: (receiver: Record<string, any>, prop: string) => {
|
get: (receiver: Record<string, any>, prop: string) => {
|
||||||
if (!(prop in receiver) && prop in adapter) {
|
if (!(prop in receiver) && prop in adapter) {
|
||||||
return adapter[prop];
|
return this.createExceptionZone(receiver, prop);
|
||||||
}
|
}
|
||||||
return receiver[prop];
|
return receiver[prop];
|
||||||
},
|
},
|
||||||
}) as any) as T;
|
}) as unknown) as T;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ExceptionsHandler } from '../exceptions/exceptions-handler';
|
import { ExceptionsHandler } from '../exceptions/exceptions-handler';
|
||||||
import { ExecutionContextHost } from '../helpers/execution-context.host';
|
import { ExecutionContextHost } from '../helpers/execution-context-host';
|
||||||
|
|
||||||
export type RouterProxyCallback = <TRequest, TResponse>(
|
export type RouterProxyCallback = <TRequest, TResponse>(
|
||||||
req?: TRequest,
|
req?: TRequest,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { Logger } from '../../../common/services/logger.service';
|
|||||||
import { AbstractHttpAdapter } from '../../adapters';
|
import { AbstractHttpAdapter } from '../../adapters';
|
||||||
import { InvalidExceptionFilterException } from '../../errors/exceptions/invalid-exception-filter.exception';
|
import { InvalidExceptionFilterException } from '../../errors/exceptions/invalid-exception-filter.exception';
|
||||||
import { ExceptionsHandler } from '../../exceptions/exceptions-handler';
|
import { ExceptionsHandler } from '../../exceptions/exceptions-handler';
|
||||||
import { ExecutionContextHost } from '../../helpers/execution-context.host';
|
import { ExecutionContextHost } from '../../helpers/execution-context-host';
|
||||||
import { NoopHttpAdapter } from './../utils/noop-adapter';
|
import { NoopHttpAdapter } from './../utils/noop-adapter';
|
||||||
|
|
||||||
describe('ExceptionsHandler', () => {
|
describe('ExceptionsHandler', () => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as sinon from 'sinon';
|
import * as sinon from 'sinon';
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { ExecutionContextHost } from '../../helpers/execution-context.host';
|
import { ExecutionContextHost } from '../../helpers/execution-context-host';
|
||||||
|
|
||||||
describe('ExecutionContextHost', () => {
|
describe('ExecutionContextHost', () => {
|
||||||
let contextHost: ExecutionContextHost;
|
let contextHost: ExecutionContextHost;
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ describe('ExternalContextCreator', () => {
|
|||||||
describe('when can not activate', () => {
|
describe('when can not activate', () => {
|
||||||
it('should throw exception when "tryActivate" returns false', () => {
|
it('should throw exception when "tryActivate" returns false', () => {
|
||||||
sinon.stub(guardsConsumer, 'tryActivate', () => false);
|
sinon.stub(guardsConsumer, 'tryActivate', () => false);
|
||||||
expect(proxyContext(1, 2, 3)).to.eventually.throw;
|
proxyContext(1, 2, 3).catch(err => expect(err).to.not.be.undefined);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('when can activate', () => {
|
describe('when can activate', () => {
|
||||||
|
|||||||
@@ -127,7 +127,9 @@ describe('RouterExecutionContext', () => {
|
|||||||
});
|
});
|
||||||
it('should throw exception when "tryActivate" returns false', () => {
|
it('should throw exception when "tryActivate" returns false', () => {
|
||||||
sinon.stub(guardsConsumer, 'tryActivate').callsFake(() => false);
|
sinon.stub(guardsConsumer, 'tryActivate').callsFake(() => false);
|
||||||
expect(proxyContext(request, response, next)).to.eventually.throw();
|
proxyContext(request, response, next).catch(
|
||||||
|
error => expect(error).to.not.be.undefined,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -257,7 +259,7 @@ describe('RouterExecutionContext', () => {
|
|||||||
it('should throw exception when "tryActivate" returns false', () => {
|
it('should throw exception when "tryActivate" returns false', () => {
|
||||||
const guardsFn = contextCreator.createGuardsFn([null], null, null);
|
const guardsFn = contextCreator.createGuardsFn([null], null, null);
|
||||||
sinon.stub(guardsConsumer, 'tryActivate').callsFake(() => false);
|
sinon.stub(guardsConsumer, 'tryActivate').callsFake(() => false);
|
||||||
expect(guardsFn([])).to.eventually.throw();
|
guardsFn([]).catch(err => expect(err).to.not.be.undefined);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('createHandleResponseFn', () => {
|
describe('createHandleResponseFn', () => {
|
||||||
|
|||||||
@@ -165,9 +165,9 @@ describe('DependenciesScanner', () => {
|
|||||||
});
|
});
|
||||||
describe('when "related" is nil', () => {
|
describe('when "related" is nil', () => {
|
||||||
it('should throw exception', () => {
|
it('should throw exception', () => {
|
||||||
expect(
|
scanner
|
||||||
scanner.insertRelatedModule(undefined, [] as any, 'test'),
|
.insertRelatedModule(undefined, [] as any, 'test')
|
||||||
).to.eventually.throws();
|
.catch(err => expect(err).to.not.be.undefined);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { isFunction } from '@nestjs/common/utils/shared.utils';
|
import { isFunction } from '@nestjs/common/utils/shared.utils';
|
||||||
import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context.host';
|
import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context-host';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { catchError } from 'rxjs/operators';
|
import { catchError } from 'rxjs/operators';
|
||||||
import { RpcExceptionsHandler } from '../exceptions/rpc-exceptions-handler';
|
import { RpcExceptionsHandler } from '../exceptions/rpc-exceptions-handler';
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ import { ServerFactory } from './server/server-factory';
|
|||||||
|
|
||||||
const { SocketModule } =
|
const { SocketModule } =
|
||||||
optional('@nestjs/websockets/socket-module') || ({} as any);
|
optional('@nestjs/websockets/socket-module') || ({} as any);
|
||||||
const { IoAdapter } =
|
|
||||||
optional('@nestjs/websockets/adapters/io-adapter') || ({} as any);
|
|
||||||
|
|
||||||
export class NestMicroservice extends NestApplicationContext
|
export class NestMicroservice extends NestApplicationContext
|
||||||
implements INestMicroservice {
|
implements INestMicroservice {
|
||||||
@@ -49,6 +47,7 @@ export class NestMicroservice extends NestApplicationContext
|
|||||||
}
|
}
|
||||||
|
|
||||||
public registerWsAdapter() {
|
public registerWsAdapter() {
|
||||||
|
const { IoAdapter } = optional('@nestjs/platform-socket.io') || ({} as any);
|
||||||
const ioAdapter = IoAdapter ? new IoAdapter() : null;
|
const ioAdapter = IoAdapter ? new IoAdapter() : null;
|
||||||
this.applicationConfig.setIoAdapter(ioAdapter);
|
this.applicationConfig.setIoAdapter(ioAdapter);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { Logger } from '@nestjs/common';
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
@@ -7,6 +8,11 @@ import { InvalidGrpcPackageException } from '../../errors/invalid-grpc-package.e
|
|||||||
import { InvalidGrpcServiceException } from '../../errors/invalid-grpc-service.exception';
|
import { InvalidGrpcServiceException } from '../../errors/invalid-grpc-service.exception';
|
||||||
import { InvalidProtoDefinitionException } from '../../errors/invalid-proto-definition.exception';
|
import { InvalidProtoDefinitionException } from '../../errors/invalid-proto-definition.exception';
|
||||||
// tslint:disable:no-string-literal
|
// tslint:disable:no-string-literal
|
||||||
|
class NoopLogger extends Logger {
|
||||||
|
log(message: any, context?: string): void {}
|
||||||
|
error(message: any, trace?: string, context?: string): void {}
|
||||||
|
warn(message: any, context?: string): void {}
|
||||||
|
}
|
||||||
|
|
||||||
class GrpcService {
|
class GrpcService {
|
||||||
test = null;
|
test = null;
|
||||||
@@ -188,9 +194,13 @@ describe('ClientGrpcProxy', () => {
|
|||||||
describe('when package does not exist', () => {
|
describe('when package does not exist', () => {
|
||||||
it('should throw "InvalidGrpcPackageException"', () => {
|
it('should throw "InvalidGrpcPackageException"', () => {
|
||||||
sinon.stub(client, 'lookupPackage').callsFake(() => null);
|
sinon.stub(client, 'lookupPackage').callsFake(() => null);
|
||||||
expect(() => client.createClient()).to.throw(
|
(client as any).logger = new NoopLogger();
|
||||||
InvalidGrpcPackageException,
|
|
||||||
);
|
try {
|
||||||
|
client.createClient();
|
||||||
|
} catch (err) {
|
||||||
|
expect(err).to.be.instanceof(InvalidGrpcPackageException);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -201,6 +211,7 @@ describe('ClientGrpcProxy', () => {
|
|||||||
sinon.stub(client, 'getOptionsProp').callsFake(() => {
|
sinon.stub(client, 'getOptionsProp').callsFake(() => {
|
||||||
throw new Error();
|
throw new Error();
|
||||||
});
|
});
|
||||||
|
(client as any).logger = new NoopLogger();
|
||||||
expect(() => client.loadProto()).to.throws(
|
expect(() => client.loadProto()).to.throws(
|
||||||
InvalidProtoDefinitionException,
|
InvalidProtoDefinitionException,
|
||||||
);
|
);
|
||||||
@@ -231,7 +242,7 @@ describe('ClientGrpcProxy', () => {
|
|||||||
|
|
||||||
describe('connect', () => {
|
describe('connect', () => {
|
||||||
it('should throw exception', () => {
|
it('should throw exception', () => {
|
||||||
expect(client.connect()).to.eventually.throws(Error);
|
client.connect().catch(error => expect(error).to.be.instanceof(Error));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -133,7 +133,9 @@ describe('RpcContextCreator', () => {
|
|||||||
);
|
);
|
||||||
const data = 'test';
|
const data = 'test';
|
||||||
|
|
||||||
expect(proxy(data)).to.eventually.rejectedWith(RpcException);
|
proxy(null, data).catch(err =>
|
||||||
|
expect(err).to.be.instanceOf(RpcException),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -167,7 +169,7 @@ describe('RpcContextCreator', () => {
|
|||||||
it('should throw exception when "tryActivate" returns false', () => {
|
it('should throw exception when "tryActivate" returns false', () => {
|
||||||
const guardsFn = contextCreator.createGuardsFn([null], null, null);
|
const guardsFn = contextCreator.createGuardsFn([null], null, null);
|
||||||
sinon.stub(guardsConsumer, 'tryActivate').callsFake(() => false);
|
sinon.stub(guardsConsumer, 'tryActivate').callsFake(() => false);
|
||||||
expect(guardsFn([])).to.eventually.throw();
|
guardsFn([]).catch(err => expect(err).to.not.be.undefined);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { Logger } from '@nestjs/common';
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { of } from 'rxjs';
|
import { of } from 'rxjs';
|
||||||
@@ -5,6 +6,12 @@ import * as sinon from 'sinon';
|
|||||||
import { InvalidGrpcPackageException } from '../../errors/invalid-grpc-package.exception';
|
import { InvalidGrpcPackageException } from '../../errors/invalid-grpc-package.exception';
|
||||||
import { ServerGrpc } from '../../server/server-grpc';
|
import { ServerGrpc } from '../../server/server-grpc';
|
||||||
|
|
||||||
|
class NoopLogger extends Logger {
|
||||||
|
log(message: any, context?: string): void {}
|
||||||
|
error(message: any, trace?: string, context?: string): void {}
|
||||||
|
warn(message: any, context?: string): void {}
|
||||||
|
}
|
||||||
|
|
||||||
describe('ServerGrpc', () => {
|
describe('ServerGrpc', () => {
|
||||||
let server: ServerGrpc;
|
let server: ServerGrpc;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@@ -42,11 +49,14 @@ describe('ServerGrpc', () => {
|
|||||||
|
|
||||||
describe('bindEvents', () => {
|
describe('bindEvents', () => {
|
||||||
describe('when package does not exist', () => {
|
describe('when package does not exist', () => {
|
||||||
it('should throw "InvalidGrpcPackageException"', () => {
|
it('should throw "InvalidGrpcPackageException"', async () => {
|
||||||
sinon.stub(server, 'lookupPackage').callsFake(() => null);
|
sinon.stub(server, 'lookupPackage').callsFake(() => null);
|
||||||
expect(server.bindEvents()).to.eventually.throws(
|
(server as any).logger = new NoopLogger();
|
||||||
InvalidGrpcPackageException,
|
try {
|
||||||
);
|
await server.bindEvents();
|
||||||
|
} catch (err) {
|
||||||
|
expect(err).to.be.instanceof(InvalidGrpcPackageException);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('when package exist', () => {
|
describe('when package exist', () => {
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
"url": "https://github.com/nestjs/nest"
|
"url": "https://github.com/nestjs/nest"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/express": "^4.0.39",
|
|
||||||
"body-parser": "1.18.3",
|
"body-parser": "1.18.3",
|
||||||
"cors": "2.8.4",
|
"cors": "2.8.4",
|
||||||
"express": "4.16.3",
|
"express": "4.16.3",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { CallHandler } from '@nestjs/common';
|
import { CallHandler } from '@nestjs/common';
|
||||||
import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context.host';
|
import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context-host';
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { of } from 'rxjs';
|
import { of } from 'rxjs';
|
||||||
import * as sinon from 'sinon';
|
import * as sinon from 'sinon';
|
||||||
@@ -57,9 +57,9 @@ describe('FileFieldsInterceptor', () => {
|
|||||||
(target as any).fields = {
|
(target as any).fields = {
|
||||||
array: () => callback,
|
array: () => callback,
|
||||||
};
|
};
|
||||||
expect(
|
(target.intercept(new ExecutionContextHost([]), handler) as any).catch(
|
||||||
target.intercept(new ExecutionContextHost([]), handler),
|
error => expect(error).to.not.be.undefined,
|
||||||
).to.eventually.throw();
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { CallHandler } from '@nestjs/common';
|
import { CallHandler } from '@nestjs/common';
|
||||||
import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context.host';
|
import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context-host';
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { of } from 'rxjs';
|
import { of } from 'rxjs';
|
||||||
import * as sinon from 'sinon';
|
import * as sinon from 'sinon';
|
||||||
@@ -39,9 +39,9 @@ describe('FileInterceptor', () => {
|
|||||||
(target as any).multer = {
|
(target as any).multer = {
|
||||||
single: () => callback,
|
single: () => callback,
|
||||||
};
|
};
|
||||||
expect(
|
(target.intercept(new ExecutionContextHost([]), handler) as any).catch(
|
||||||
target.intercept(new ExecutionContextHost([]), handler),
|
error => expect(error).to.not.be.undefined,
|
||||||
).to.eventually.throw();
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { CallHandler } from '@nestjs/common';
|
import { CallHandler } from '@nestjs/common';
|
||||||
import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context.host';
|
import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context-host';
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { of } from 'rxjs';
|
import { of } from 'rxjs';
|
||||||
import * as sinon from 'sinon';
|
import * as sinon from 'sinon';
|
||||||
@@ -41,9 +41,9 @@ describe('FilesInterceptor', () => {
|
|||||||
(target as any).multer = {
|
(target as any).multer = {
|
||||||
array: () => callback,
|
array: () => callback,
|
||||||
};
|
};
|
||||||
expect(
|
(target.intercept(new ExecutionContextHost([]), handler) as any).catch(
|
||||||
target.intercept(new ExecutionContextHost([]), handler),
|
error => expect(error).to.not.be.undefined,
|
||||||
).to.eventually.throw();
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { RequestMethod } from '@nestjs/common';
|
import { RequestMethod } from '@nestjs/common';
|
||||||
import { ErrorHandler, RequestHandler } from '@nestjs/common/interfaces';
|
|
||||||
import { CorsOptions } from '@nestjs/common/interfaces/external/cors-options.interface';
|
import { CorsOptions } from '@nestjs/common/interfaces/external/cors-options.interface';
|
||||||
import { NestApplicationOptions } from '@nestjs/common/interfaces/nest-application-options.interface';
|
import { NestApplicationOptions } from '@nestjs/common/interfaces/nest-application-options.interface';
|
||||||
import { loadPackage } from '@nestjs/common/utils/load-package.util';
|
import { loadPackage } from '@nestjs/common/utils/load-package.util';
|
||||||
@@ -24,54 +23,6 @@ export class FastifyAdapter extends AbstractHttpAdapter {
|
|||||||
super(instance);
|
super(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
public use(handler: RequestHandler | ErrorHandler);
|
|
||||||
public use(path: any, handler: RequestHandler | ErrorHandler);
|
|
||||||
public use(...args: any[]) {
|
|
||||||
return this.instance.use(...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
public get(handler: RequestHandler);
|
|
||||||
public get(path: any, handler: RequestHandler);
|
|
||||||
public get(...args: any[]) {
|
|
||||||
return this.instance.get(...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
public post(handler: RequestHandler);
|
|
||||||
public post(path: any, handler: RequestHandler);
|
|
||||||
public post(...args: any[]) {
|
|
||||||
return this.instance.post(...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
public head(handler: RequestHandler);
|
|
||||||
public head(path: any, handler: RequestHandler);
|
|
||||||
public head(...args: any[]) {
|
|
||||||
return this.instance.head(...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
public delete(handler: RequestHandler);
|
|
||||||
public delete(path: any, handler: RequestHandler);
|
|
||||||
public delete(...args: any[]) {
|
|
||||||
return this.instance.delete(...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
public put(handler: RequestHandler);
|
|
||||||
public put(path: any, handler: RequestHandler);
|
|
||||||
public put(...args: any[]) {
|
|
||||||
return this.instance.put(...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
public patch(handler: RequestHandler);
|
|
||||||
public patch(path: any, handler: RequestHandler);
|
|
||||||
public patch(...args: any[]) {
|
|
||||||
return this.instance.patch(...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
public options(handler: RequestHandler);
|
|
||||||
public options(path: any, handler: RequestHandler);
|
|
||||||
public options(...args: any[]) {
|
|
||||||
return this.instance.options(...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
public listen(port: string | number, callback?: () => void);
|
public listen(port: string | number, callback?: () => void);
|
||||||
public listen(port: string | number, hostname: string, callback?: () => void);
|
public listen(port: string | number, hostname: string, callback?: () => void);
|
||||||
public listen(port: any, hostname?: any, callback?: any) {
|
public listen(port: any, hostname?: any, callback?: any) {
|
||||||
|
|||||||
76
packages/platform-socket.io/Readme.md
Normal file
76
packages/platform-socket.io/Readme.md
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
<p align="center">
|
||||||
|
<a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo_text.svg" width="320" alt="Nest Logo" /></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
[travis-image]: https://api.travis-ci.org/nestjs/nest.svg?branch=master
|
||||||
|
[travis-url]: https://travis-ci.org/nestjs/nest
|
||||||
|
[linux-image]: https://img.shields.io/travis/nestjs/nest/master.svg?label=linux
|
||||||
|
[linux-url]: https://travis-ci.org/nestjs/nest
|
||||||
|
|
||||||
|
<p align="center">A progressive <a href="http://nodejs.org" target="blank">Node.js</a> framework for building efficient and scalable server-side applications, heavily inspired by <a href="https://angular.io" target="blank">Angular</a>.</p>
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://www.npmjs.com/~nestjscore"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
|
||||||
|
<a href="https://www.npmjs.com/~nestjscore"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
|
||||||
|
<a href="https://www.npmjs.com/~nestjscore"><img src="https://img.shields.io/npm/dm/@nestjs/core.svg" alt="NPM Downloads" /></a>
|
||||||
|
<a href="https://travis-ci.org/nestjs/nest"><img src="https://api.travis-ci.org/nestjs/nest.svg?branch=master" alt="Travis" /></a>
|
||||||
|
<a href="https://travis-ci.org/nestjs/nest"><img src="https://img.shields.io/travis/nestjs/nest/master.svg?label=linux" alt="Linux" /></a>
|
||||||
|
<a href="https://coveralls.io/github/nestjs/nest?branch=master"><img src="https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#8" alt="Coverage" /></a>
|
||||||
|
<a href="https://gitter.im/nestjs/nestjs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge"><img src="https://badges.gitter.im/nestjs/nestjs.svg" alt="Gitter" /></a>
|
||||||
|
<a href="https://opencollective.com/nest#backer"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a>
|
||||||
|
<a href="https://opencollective.com/nest#sponsor"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
|
||||||
|
<a href="https://paypal.me/kamilmysliwiec"><img src="https://img.shields.io/badge/Donate-PayPal-ff3f59.svg"/></a>
|
||||||
|
<a href="https://twitter.com/nestframework"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow"></a>
|
||||||
|
</p>
|
||||||
|
<!--[](https://opencollective.com/nest#backer)
|
||||||
|
[](https://opencollective.com/nest#sponsor)-->
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<p>Nest is a framework for building efficient, scalable <a href="http://nodejs.org" target="_blank">Node.js</a> server-side applications. It uses modern JavaScript, is built with <a href="http://www.typescriptlang.org" target="_blank">TypeScript</a> (preserves compatibility with pure JavaScript) and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Reactive Programming).</p>
|
||||||
|
|
||||||
|
<p>Under the hood, Nest makes use of <a href="https://expressjs.com/" target="_blank">Express</a>, but also, provides compatibility with a wide range of other libraries, like e.g. <a href="https://github.com/fastify/fastify" target="blank">Fastify</a>, allowing for easy use of the myriad third-party plugins which are available.</p>
|
||||||
|
|
||||||
|
## Philosophy
|
||||||
|
|
||||||
|
<p>In recent years, thanks to Node.js, JavaScript has become the “lingua franca” of the web for both front and backend applications, giving rise to awesome projects like <a href="https://angular.io/" target="_blank">Angular</a>, <a href="https://github.com/facebook/react" target="_blank">React</a> and <a href="https://github.com/vuejs/vue" target="_blank">Vue</a> which improve developer productivity and enable the construction of fast, testable, extensible frontend applications. However, on the server-side, while there are a lot of superb libraries, helpers and tools for Node, none of them effectively solve the main problem - the architecture.</p>
|
||||||
|
<p>Nest aims to provide an application architecture out of the box which allows for effortless creation of highly testable, scalable, loosely coupled and easily maintainable applications.</p>
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
* To check out the [guide](https://docs.nestjs.com), visit [docs.nestjs.com](https://docs.nestjs.com). :books:
|
||||||
|
* 要查看中文 [指南](readme_zh.md), 请访问 [docs.nestjs.cn](https://docs.nestjs.cn). :books:
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
|
||||||
|
|
||||||
|
#### Principal Sponsor
|
||||||
|
|
||||||
|
<a href="https://valor-software.com/"><img src="https://docs.nestjs.com/assets/sponsors/valor-software.png" width="320" /></a>
|
||||||
|
|
||||||
|
#### Gold Sponsors
|
||||||
|
|
||||||
|
<a href="http://xtremis.com/"><img src="https://nestjs.com/img/logo-xtremis.svg" width="220" /></a>
|
||||||
|
|
||||||
|
#### Silver Sponsors
|
||||||
|
<a href="https://neoteric.eu/"><img src="https://nestjs.com/img/neoteric-cut.png" width="120" /></a>
|
||||||
|
<a href="http://gojob.com"><img src="http://nestjs.com/img/gojob-logo.png" valign="bottom" height="95" /></a> <a href="https://www.swingdev.io"><img src="https://nestjs.com/img/swingdev-logo.svg#1" width="150" /> </a>
|
||||||
|
|
||||||
|
#### Sponsors
|
||||||
|
|
||||||
|
<a href="https://scal.io"><img src="https://nestjs.com/img/scalio-logo.svg" width="110" /></a> <a href="http://angularity.io"><img src="http://angularity.io/media/logo.svg" height="30" /></a> <!--<a href="https://keycdn.com"><img src="https://nestjs.com/img/keycdn.svg" height="30" /></a> --> <a href="https://hostpresto.com"><img src="https://nestjs.com/img/hostpresto.png" height="30" /></a> <a href="https://genuinebee.com/"><img src="https://nestjs.com/img/genuinebee.svg" height="38" /></a> <a href="http://architectnow.net/"><img src="https://nestjs.com/img/architectnow.png" height="24" /></a> <a href="https://quander.io/"><img src="https://nestjs.com/img/quander.png" height="28" /></a>
|
||||||
|
|
||||||
|
|
||||||
|
## Backers
|
||||||
|
|
||||||
|
<a href="https://opencollective.com/nest"><img src="https://opencollective.com/nest/backers.svg?width=890"></a>
|
||||||
|
|
||||||
|
## Stay in touch
|
||||||
|
|
||||||
|
* Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)
|
||||||
|
* Website - [https://nestjs.com](https://nestjs.com/)
|
||||||
|
* Twitter - [@nestframework](https://twitter.com/nestframework)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Nest is [MIT licensed](LICENSE).
|
||||||
1
packages/platform-socket.io/adapters/index.ts
Normal file
1
packages/platform-socket.io/adapters/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './io-adapter';
|
||||||
@@ -1,26 +1,14 @@
|
|||||||
import { INestApplicationContext, WebSocketAdapter } from '@nestjs/common';
|
|
||||||
import { isFunction, isNil } from '@nestjs/common/utils/shared.utils';
|
import { isFunction, isNil } from '@nestjs/common/utils/shared.utils';
|
||||||
import { NestApplication } from '@nestjs/core';
|
import {
|
||||||
import { Server } from 'http';
|
AbstractWsAdapter,
|
||||||
|
MessageMappingProperties,
|
||||||
|
} from '@nestjs/websockets';
|
||||||
|
import { DISCONNECT_EVENT } from '@nestjs/websockets/constants';
|
||||||
import { fromEvent, Observable } from 'rxjs';
|
import { fromEvent, Observable } from 'rxjs';
|
||||||
import { filter, first, map, mergeMap, share, takeUntil } from 'rxjs/operators';
|
import { filter, first, map, mergeMap, share, takeUntil } from 'rxjs/operators';
|
||||||
import * as io from 'socket.io';
|
import * as io from 'socket.io';
|
||||||
import { CONNECTION_EVENT, DISCONNECT_EVENT } from '../constants';
|
|
||||||
import { MessageMappingProperties } from '../gateway-metadata-explorer';
|
|
||||||
import { BaseWsExceptionFilter } from './../exceptions/base-ws-exception-filter';
|
|
||||||
|
|
||||||
export class IoAdapter implements WebSocketAdapter {
|
|
||||||
protected readonly baseExceptionFilter = new BaseWsExceptionFilter();
|
|
||||||
protected readonly httpServer: Server;
|
|
||||||
|
|
||||||
constructor(appOrHttpServer?: INestApplicationContext | Server) {
|
|
||||||
if (appOrHttpServer && appOrHttpServer instanceof NestApplication) {
|
|
||||||
this.httpServer = appOrHttpServer.getUnderlyingHttpServer();
|
|
||||||
} else {
|
|
||||||
this.httpServer = appOrHttpServer as Server;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
export class IoAdapter extends AbstractWsAdapter {
|
||||||
public create(
|
public create(
|
||||||
port: number,
|
port: number,
|
||||||
options?: any & { namespace?: string; server?: any },
|
options?: any & { namespace?: string; server?: any },
|
||||||
@@ -32,8 +20,8 @@ export class IoAdapter implements WebSocketAdapter {
|
|||||||
return server && isFunction(server.of)
|
return server && isFunction(server.of)
|
||||||
? server.of(namespace)
|
? server.of(namespace)
|
||||||
: namespace
|
: namespace
|
||||||
? this.createIOServer(port, opt).of(namespace)
|
? this.createIOServer(port, opt).of(namespace)
|
||||||
: this.createIOServer(port, opt);
|
: this.createIOServer(port, opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
public createIOServer(port: number, options?: any): any {
|
public createIOServer(port: number, options?: any): any {
|
||||||
@@ -43,14 +31,6 @@ export class IoAdapter implements WebSocketAdapter {
|
|||||||
return io(port, options);
|
return io(port, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bindClientConnect(server: any, callback: (...args: any[]) => void) {
|
|
||||||
server.on(CONNECTION_EVENT, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bindClientDisconnect(client: any, callback: (...args: any[]) => void) {
|
|
||||||
client.on(DISCONNECT_EVENT, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bindMessageHandlers(
|
public bindMessageHandlers(
|
||||||
client: any,
|
client: any,
|
||||||
handlers: MessageMappingProperties[],
|
handlers: MessageMappingProperties[],
|
||||||
@@ -72,15 +52,12 @@ export class IoAdapter implements WebSocketAdapter {
|
|||||||
}),
|
}),
|
||||||
takeUntil(disconnect$),
|
takeUntil(disconnect$),
|
||||||
);
|
);
|
||||||
const onMessage = ([response, ack]) => {
|
source$.subscribe(([response, ack]) => {
|
||||||
if (response.event) {
|
if (response.event) {
|
||||||
return client.emit(response.event, response.data);
|
return client.emit(response.event, response.data);
|
||||||
}
|
}
|
||||||
isFunction(ack) && ack(response);
|
isFunction(ack) && ack(response);
|
||||||
};
|
});
|
||||||
const onError = (err: any) =>
|
|
||||||
this.baseExceptionFilter.handleError(client, err);
|
|
||||||
source$.subscribe(onMessage as any, onError);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,12 +76,4 @@ export class IoAdapter implements WebSocketAdapter {
|
|||||||
}
|
}
|
||||||
return { data: payload };
|
return { data: payload };
|
||||||
}
|
}
|
||||||
|
|
||||||
public bindMiddleware(server, middleware: (socket, next) => void) {
|
|
||||||
server.use(middleware);
|
|
||||||
}
|
|
||||||
|
|
||||||
public close(server: any) {
|
|
||||||
isFunction(server.close) && server.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
8
packages/platform-socket.io/index.ts
Normal file
8
packages/platform-socket.io/index.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
* Nest @platform-socket.io
|
||||||
|
* Copyright(c) 2017 - 2018 Kamil Mysliwiec
|
||||||
|
* https://nestjs.com
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './adapters';
|
||||||
19
packages/platform-socket.io/package.json
Normal file
19
packages/platform-socket.io/package.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "@nestjs/platform-socket.io",
|
||||||
|
"version": "5.4.1",
|
||||||
|
"description": "Nest - modern, fast, powerful node.js web framework (@platform-socket.io)",
|
||||||
|
"author": "Kamil Mysliwiec",
|
||||||
|
"license": "MIT",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/nestjs/nest"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@types/express": "^4.0.39",
|
||||||
|
"body-parser": "1.18.3",
|
||||||
|
"cors": "2.8.4",
|
||||||
|
"express": "4.16.3",
|
||||||
|
"multer": "1.3.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {}
|
||||||
|
}
|
||||||
7
packages/platform-socket.io/tsconfig.json
Normal file
7
packages/platform-socket.io/tsconfig.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"extends": "./../tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": "./"
|
||||||
|
},
|
||||||
|
"include": ["*.ts", "**/*.ts"]
|
||||||
|
}
|
||||||
76
packages/platform-ws/Readme.md
Normal file
76
packages/platform-ws/Readme.md
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
<p align="center">
|
||||||
|
<a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo_text.svg" width="320" alt="Nest Logo" /></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
[travis-image]: https://api.travis-ci.org/nestjs/nest.svg?branch=master
|
||||||
|
[travis-url]: https://travis-ci.org/nestjs/nest
|
||||||
|
[linux-image]: https://img.shields.io/travis/nestjs/nest/master.svg?label=linux
|
||||||
|
[linux-url]: https://travis-ci.org/nestjs/nest
|
||||||
|
|
||||||
|
<p align="center">A progressive <a href="http://nodejs.org" target="blank">Node.js</a> framework for building efficient and scalable server-side applications, heavily inspired by <a href="https://angular.io" target="blank">Angular</a>.</p>
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://www.npmjs.com/~nestjscore"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
|
||||||
|
<a href="https://www.npmjs.com/~nestjscore"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
|
||||||
|
<a href="https://www.npmjs.com/~nestjscore"><img src="https://img.shields.io/npm/dm/@nestjs/core.svg" alt="NPM Downloads" /></a>
|
||||||
|
<a href="https://travis-ci.org/nestjs/nest"><img src="https://api.travis-ci.org/nestjs/nest.svg?branch=master" alt="Travis" /></a>
|
||||||
|
<a href="https://travis-ci.org/nestjs/nest"><img src="https://img.shields.io/travis/nestjs/nest/master.svg?label=linux" alt="Linux" /></a>
|
||||||
|
<a href="https://coveralls.io/github/nestjs/nest?branch=master"><img src="https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#8" alt="Coverage" /></a>
|
||||||
|
<a href="https://gitter.im/nestjs/nestjs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge"><img src="https://badges.gitter.im/nestjs/nestjs.svg" alt="Gitter" /></a>
|
||||||
|
<a href="https://opencollective.com/nest#backer"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a>
|
||||||
|
<a href="https://opencollective.com/nest#sponsor"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
|
||||||
|
<a href="https://paypal.me/kamilmysliwiec"><img src="https://img.shields.io/badge/Donate-PayPal-ff3f59.svg"/></a>
|
||||||
|
<a href="https://twitter.com/nestframework"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow"></a>
|
||||||
|
</p>
|
||||||
|
<!--[](https://opencollective.com/nest#backer)
|
||||||
|
[](https://opencollective.com/nest#sponsor)-->
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<p>Nest is a framework for building efficient, scalable <a href="http://nodejs.org" target="_blank">Node.js</a> server-side applications. It uses modern JavaScript, is built with <a href="http://www.typescriptlang.org" target="_blank">TypeScript</a> (preserves compatibility with pure JavaScript) and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Reactive Programming).</p>
|
||||||
|
|
||||||
|
<p>Under the hood, Nest makes use of <a href="https://expressjs.com/" target="_blank">Express</a>, but also, provides compatibility with a wide range of other libraries, like e.g. <a href="https://github.com/fastify/fastify" target="blank">Fastify</a>, allowing for easy use of the myriad third-party plugins which are available.</p>
|
||||||
|
|
||||||
|
## Philosophy
|
||||||
|
|
||||||
|
<p>In recent years, thanks to Node.js, JavaScript has become the “lingua franca” of the web for both front and backend applications, giving rise to awesome projects like <a href="https://angular.io/" target="_blank">Angular</a>, <a href="https://github.com/facebook/react" target="_blank">React</a> and <a href="https://github.com/vuejs/vue" target="_blank">Vue</a> which improve developer productivity and enable the construction of fast, testable, extensible frontend applications. However, on the server-side, while there are a lot of superb libraries, helpers and tools for Node, none of them effectively solve the main problem - the architecture.</p>
|
||||||
|
<p>Nest aims to provide an application architecture out of the box which allows for effortless creation of highly testable, scalable, loosely coupled and easily maintainable applications.</p>
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
* To check out the [guide](https://docs.nestjs.com), visit [docs.nestjs.com](https://docs.nestjs.com). :books:
|
||||||
|
* 要查看中文 [指南](readme_zh.md), 请访问 [docs.nestjs.cn](https://docs.nestjs.cn). :books:
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
|
||||||
|
|
||||||
|
#### Principal Sponsor
|
||||||
|
|
||||||
|
<a href="https://valor-software.com/"><img src="https://docs.nestjs.com/assets/sponsors/valor-software.png" width="320" /></a>
|
||||||
|
|
||||||
|
#### Gold Sponsors
|
||||||
|
|
||||||
|
<a href="http://xtremis.com/"><img src="https://nestjs.com/img/logo-xtremis.svg" width="220" /></a>
|
||||||
|
|
||||||
|
#### Silver Sponsors
|
||||||
|
<a href="https://neoteric.eu/"><img src="https://nestjs.com/img/neoteric-cut.png" width="120" /></a>
|
||||||
|
<a href="http://gojob.com"><img src="http://nestjs.com/img/gojob-logo.png" valign="bottom" height="95" /></a> <a href="https://www.swingdev.io"><img src="https://nestjs.com/img/swingdev-logo.svg#1" width="150" /> </a>
|
||||||
|
|
||||||
|
#### Sponsors
|
||||||
|
|
||||||
|
<a href="https://scal.io"><img src="https://nestjs.com/img/scalio-logo.svg" width="110" /></a> <a href="http://angularity.io"><img src="http://angularity.io/media/logo.svg" height="30" /></a> <!--<a href="https://keycdn.com"><img src="https://nestjs.com/img/keycdn.svg" height="30" /></a> --> <a href="https://hostpresto.com"><img src="https://nestjs.com/img/hostpresto.png" height="30" /></a> <a href="https://genuinebee.com/"><img src="https://nestjs.com/img/genuinebee.svg" height="38" /></a> <a href="http://architectnow.net/"><img src="https://nestjs.com/img/architectnow.png" height="24" /></a> <a href="https://quander.io/"><img src="https://nestjs.com/img/quander.png" height="28" /></a>
|
||||||
|
|
||||||
|
|
||||||
|
## Backers
|
||||||
|
|
||||||
|
<a href="https://opencollective.com/nest"><img src="https://opencollective.com/nest/backers.svg?width=890"></a>
|
||||||
|
|
||||||
|
## Stay in touch
|
||||||
|
|
||||||
|
* Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)
|
||||||
|
* Website - [https://nestjs.com](https://nestjs.com/)
|
||||||
|
* Twitter - [@nestframework](https://twitter.com/nestframework)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Nest is [MIT licensed](LICENSE).
|
||||||
1
packages/platform-ws/adapters/index.ts
Normal file
1
packages/platform-ws/adapters/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './ws-adapter';
|
||||||
103
packages/platform-ws/adapters/ws-adapter.ts
Normal file
103
packages/platform-ws/adapters/ws-adapter.ts
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
import { INestApplicationContext, Logger } from '@nestjs/common';
|
||||||
|
import { loadPackage } from '@nestjs/common/utils/load-package.util';
|
||||||
|
import { AbstractWsAdapter } from '@nestjs/websockets';
|
||||||
|
import {
|
||||||
|
CLOSE_EVENT,
|
||||||
|
CONNECTION_EVENT,
|
||||||
|
ERROR_EVENT,
|
||||||
|
} from '@nestjs/websockets/constants';
|
||||||
|
import { MessageMappingProperties } from '@nestjs/websockets/gateway-metadata-explorer';
|
||||||
|
import { EMPTY as empty, fromEvent, Observable } from 'rxjs';
|
||||||
|
import { filter, first, mergeMap, share, takeUntil } from 'rxjs/operators';
|
||||||
|
|
||||||
|
let wsPackage: any = {};
|
||||||
|
|
||||||
|
enum READY_STATE {
|
||||||
|
CONNECTING_STATE = 0,
|
||||||
|
OPEN_STATE = 1,
|
||||||
|
CLOSING_STATE = 2,
|
||||||
|
CLOSED_STATE = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
export class WsAdapter extends AbstractWsAdapter {
|
||||||
|
protected readonly logger = new Logger(WsAdapter.name);
|
||||||
|
|
||||||
|
constructor(appOrHttpServer?: INestApplicationContext | any) {
|
||||||
|
super(appOrHttpServer);
|
||||||
|
wsPackage = loadPackage('ws', 'WsAdapter');
|
||||||
|
}
|
||||||
|
|
||||||
|
public create(
|
||||||
|
port: number,
|
||||||
|
options?: any & { namespace?: string; server?: any },
|
||||||
|
): any {
|
||||||
|
const { server, ...wsOptions } = options;
|
||||||
|
if (port === 0 && this.httpServer) {
|
||||||
|
return this.bindErrorHandler(
|
||||||
|
new wsPackage.Server({
|
||||||
|
server: this.httpServer,
|
||||||
|
...wsOptions,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return server
|
||||||
|
? server
|
||||||
|
: this.bindErrorHandler(
|
||||||
|
new wsPackage.Server({
|
||||||
|
port,
|
||||||
|
...wsOptions,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bindMessageHandlers(
|
||||||
|
client: any,
|
||||||
|
handlers: MessageMappingProperties[],
|
||||||
|
transform: (data: any) => Observable<any>,
|
||||||
|
) {
|
||||||
|
const close$ = fromEvent(client, CLOSE_EVENT).pipe(
|
||||||
|
share(),
|
||||||
|
first(),
|
||||||
|
);
|
||||||
|
const source$ = fromEvent(client, 'message').pipe(
|
||||||
|
mergeMap(data =>
|
||||||
|
this.bindMessageHandler(data, handlers, transform).pipe(
|
||||||
|
filter(result => result),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
takeUntil(close$),
|
||||||
|
);
|
||||||
|
const onMessage = (response: any) => {
|
||||||
|
if (client.readyState !== READY_STATE.OPEN_STATE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
client.send(JSON.stringify(response));
|
||||||
|
};
|
||||||
|
source$.subscribe(onMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bindMessageHandler(
|
||||||
|
buffer: any,
|
||||||
|
handlers: MessageMappingProperties[],
|
||||||
|
transform: (data: any) => Observable<any>,
|
||||||
|
): Observable<any> {
|
||||||
|
try {
|
||||||
|
const message = JSON.parse(buffer.data);
|
||||||
|
const messageHandler = handlers.find(
|
||||||
|
handler => handler.message === message.event,
|
||||||
|
);
|
||||||
|
const { callback } = messageHandler;
|
||||||
|
return transform(callback(message.data));
|
||||||
|
} catch {
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bindErrorHandler(server: any) {
|
||||||
|
server.on(CONNECTION_EVENT, ws =>
|
||||||
|
ws.on(ERROR_EVENT, (err: any) => this.logger.error(err)),
|
||||||
|
);
|
||||||
|
server.on(ERROR_EVENT, (err: any) => this.logger.error(err));
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
}
|
||||||
8
packages/platform-ws/index.ts
Normal file
8
packages/platform-ws/index.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
* Nest @platform-ws
|
||||||
|
* Copyright(c) 2017 - 2018 Kamil Mysliwiec
|
||||||
|
* https://nestjs.com
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './adapters';
|
||||||
19
packages/platform-ws/package.json
Normal file
19
packages/platform-ws/package.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "@nestjs/platform-ws",
|
||||||
|
"version": "5.4.1",
|
||||||
|
"description": "Nest - modern, fast, powerful node.js web framework (@platform-ws)",
|
||||||
|
"author": "Kamil Mysliwiec",
|
||||||
|
"license": "MIT",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/nestjs/nest"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@types/express": "^4.0.39",
|
||||||
|
"body-parser": "1.18.3",
|
||||||
|
"cors": "2.8.4",
|
||||||
|
"express": "4.16.3",
|
||||||
|
"multer": "1.3.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {}
|
||||||
|
}
|
||||||
7
packages/platform-ws/tsconfig.json
Normal file
7
packages/platform-ws/tsconfig.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"extends": "./../tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": "./"
|
||||||
|
},
|
||||||
|
"include": ["*.ts", "**/*.ts"]
|
||||||
|
}
|
||||||
@@ -1 +1 @@
|
|||||||
export * from './ws-adapter';
|
export * from './ws-adapter';
|
||||||
|
|||||||
@@ -1,123 +1,47 @@
|
|||||||
import {
|
import { INestApplicationContext, WebSocketAdapter } from '@nestjs/common';
|
||||||
INestApplicationContext,
|
import { WsMessageHandler } from '@nestjs/common/interfaces';
|
||||||
Logger,
|
|
||||||
WebSocketAdapter,
|
|
||||||
} from '@nestjs/common';
|
|
||||||
import { loadPackage } from '@nestjs/common/utils/load-package.util';
|
|
||||||
import { isFunction } from '@nestjs/common/utils/shared.utils';
|
import { isFunction } from '@nestjs/common/utils/shared.utils';
|
||||||
import { NestApplication } from '@nestjs/core';
|
import { NestApplication } from '@nestjs/core';
|
||||||
import { Server } from 'http';
|
import { Observable } from 'rxjs';
|
||||||
import { EMPTY as empty, fromEvent, Observable } from 'rxjs';
|
import { CONNECTION_EVENT, DISCONNECT_EVENT } from '../constants';
|
||||||
import { filter, first, mergeMap, share, takeUntil } from 'rxjs/operators';
|
|
||||||
import { CLOSE_EVENT, CONNECTION_EVENT, ERROR_EVENT } from '../constants';
|
|
||||||
import { MessageMappingProperties } from '../gateway-metadata-explorer';
|
|
||||||
import { BaseWsExceptionFilter } from './../exceptions/base-ws-exception-filter';
|
|
||||||
|
|
||||||
let wsPackage: any = {};
|
export interface BaseWsInstance {
|
||||||
|
on: (event: string, callback: Function) => void;
|
||||||
enum READY_STATE {
|
close: Function;
|
||||||
CONNECTING_STATE = 0,
|
|
||||||
OPEN_STATE = 1,
|
|
||||||
CLOSING_STATE = 2,
|
|
||||||
CLOSED_STATE = 3,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WsAdapter implements WebSocketAdapter {
|
export abstract class AbstractWsAdapter<
|
||||||
protected readonly baseExceptionFilter = new BaseWsExceptionFilter();
|
TServer extends BaseWsInstance = any,
|
||||||
protected readonly logger = new Logger(WsAdapter.name);
|
TClient extends BaseWsInstance = any,
|
||||||
protected readonly httpServer: Server;
|
TOptions = any
|
||||||
|
> implements WebSocketAdapter<TServer, TClient, TOptions> {
|
||||||
|
protected readonly httpServer: any;
|
||||||
|
|
||||||
constructor(appOrHttpServer?: INestApplicationContext | Server) {
|
constructor(appOrHttpServer?: INestApplicationContext | any) {
|
||||||
wsPackage = loadPackage('ws', 'WsAdapter');
|
|
||||||
if (appOrHttpServer && appOrHttpServer instanceof NestApplication) {
|
if (appOrHttpServer && appOrHttpServer instanceof NestApplication) {
|
||||||
this.httpServer = appOrHttpServer.getUnderlyingHttpServer();
|
this.httpServer = appOrHttpServer.getUnderlyingHttpServer();
|
||||||
} else {
|
} else {
|
||||||
this.httpServer = appOrHttpServer as Server;
|
this.httpServer = appOrHttpServer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public create(
|
public bindClientConnect(server: TServer, callback: Function) {
|
||||||
port: number,
|
|
||||||
options?: any & { namespace?: string; server?: any },
|
|
||||||
): any {
|
|
||||||
const { server, ...wsOptions } = options;
|
|
||||||
if (port === 0 && this.httpServer) {
|
|
||||||
return this.bindErrorHandler(
|
|
||||||
new wsPackage.Server({
|
|
||||||
server: this.httpServer,
|
|
||||||
...wsOptions,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return server
|
|
||||||
? server
|
|
||||||
: this.bindErrorHandler(
|
|
||||||
new wsPackage.Server({
|
|
||||||
port,
|
|
||||||
...wsOptions,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bindClientConnect(server, callback: (...args: any[]) => void) {
|
|
||||||
server.on(CONNECTION_EVENT, callback);
|
server.on(CONNECTION_EVENT, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bindClientDisconnect(client, callback: (...args: any[]) => void) {
|
public bindClientDisconnect(client: TClient, callback: Function) {
|
||||||
client.on(CLOSE_EVENT, callback);
|
client.on(DISCONNECT_EVENT, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bindMessageHandlers(
|
public close(server: TServer) {
|
||||||
client: any,
|
const isCallable = server && isFunction(server.close);
|
||||||
handlers: MessageMappingProperties[],
|
isCallable && server.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract create(port: number, options?: TOptions): TServer;
|
||||||
|
public abstract bindMessageHandlers(
|
||||||
|
client: TClient,
|
||||||
|
handlers: WsMessageHandler[],
|
||||||
transform: (data: any) => Observable<any>,
|
transform: (data: any) => Observable<any>,
|
||||||
) {
|
);
|
||||||
const close$ = fromEvent(client, CLOSE_EVENT).pipe(share(), first());
|
|
||||||
const source$ = fromEvent(client, 'message').pipe(
|
|
||||||
mergeMap(data =>
|
|
||||||
this.bindMessageHandler(data, handlers, transform).pipe(
|
|
||||||
filter(result => result),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
takeUntil(close$),
|
|
||||||
);
|
|
||||||
const onMessage = (response: any) => {
|
|
||||||
if (client.readyState !== READY_STATE.OPEN_STATE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
client.send(JSON.stringify(response));
|
|
||||||
};
|
|
||||||
const onError = (err: any) =>
|
|
||||||
this.baseExceptionFilter.handleError(client, err);
|
|
||||||
source$.subscribe(onMessage, onError);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bindMessageHandler(
|
|
||||||
buffer: any,
|
|
||||||
handlers: MessageMappingProperties[],
|
|
||||||
transform: (data: any) => Observable<any>,
|
|
||||||
): Observable<any> {
|
|
||||||
try {
|
|
||||||
const message = JSON.parse(buffer.data);
|
|
||||||
const messageHandler = handlers.find(
|
|
||||||
handler => handler.message === message.event,
|
|
||||||
);
|
|
||||||
const { callback } = messageHandler;
|
|
||||||
return transform(callback(message.data));
|
|
||||||
} catch {
|
|
||||||
return empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public close(server: any) {
|
|
||||||
server && isFunction(server.close) && server.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bindErrorHandler(server: any) {
|
|
||||||
server.on(CONNECTION_EVENT, ws =>
|
|
||||||
ws.on(ERROR_EVENT, (err: any) => this.logger.error(err)),
|
|
||||||
);
|
|
||||||
server.on(ERROR_EVENT, (err: any) => this.logger.error(err));
|
|
||||||
return server;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { isFunction } from '@nestjs/common/utils/shared.utils';
|
import { isFunction } from '@nestjs/common/utils/shared.utils';
|
||||||
import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context.host';
|
import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context-host';
|
||||||
import { empty } from 'rxjs';
|
import { empty } from 'rxjs';
|
||||||
import { catchError } from 'rxjs/operators';
|
import { catchError } from 'rxjs/operators';
|
||||||
import { WsExceptionsHandler } from '../exceptions/ws-exceptions-handler';
|
import { WsExceptionsHandler } from '../exceptions/ws-exceptions-handler';
|
||||||
|
|||||||
@@ -2,6 +2,6 @@ import { RuntimeException } from '@nestjs/core/errors/exceptions/runtime.excepti
|
|||||||
|
|
||||||
export class InvalidSocketPortException extends RuntimeException {
|
export class InvalidSocketPortException extends RuntimeException {
|
||||||
constructor(port: number | string, type: any) {
|
constructor(port: number | string, type: any) {
|
||||||
super(`Invalid port (${port}) in gateway ${type}!`);
|
super(`Invalid port (${port}) in gateway ${type}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
import 'reflect-metadata';
|
import 'reflect-metadata';
|
||||||
|
|
||||||
export * from './adapters/io-adapter';
|
export * from './adapters';
|
||||||
export * from './adapters/ws-adapter';
|
|
||||||
export * from './errors';
|
export * from './errors';
|
||||||
export * from './exceptions';
|
export * from './exceptions';
|
||||||
export { MessageMappingProperties } from './gateway-metadata-explorer';
|
export { MessageMappingProperties } from './gateway-metadata-explorer';
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "@nestjs/websockets",
|
"name": "@nestjs/websockets",
|
||||||
"version": "5.5.0",
|
"version": "5.5.0",
|
||||||
"description": "Nest - modern, fast, powerful node.js web framework (@websockets)",
|
"description":
|
||||||
|
"Nest - modern, fast, powerful node.js web framework (@websockets)",
|
||||||
"author": "Kamil Mysliwiec",
|
"author": "Kamil Mysliwiec",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
@@ -9,8 +10,7 @@
|
|||||||
"url": "https://github.com/nestjs/nest"
|
"url": "https://github.com/nestjs/nest"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"iterare": "0.0.8",
|
"iterare": "0.0.8"
|
||||||
"socket.io": "^2.1.1"
|
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@nestjs/common": "^5.0.0",
|
"@nestjs/common": "^5.0.0",
|
||||||
|
|||||||
@@ -27,27 +27,32 @@ export class SocketModule {
|
|||||||
|
|
||||||
public register(container: NestContainer, config: ApplicationConfig) {
|
public register(container: NestContainer, config: ApplicationConfig) {
|
||||||
this.applicationConfig = config;
|
this.applicationConfig = config;
|
||||||
this.webSocketsController = new WebSocketsController(
|
const serverProvider = new SocketServerProvider(
|
||||||
new SocketServerProvider(this.socketsContainer, config),
|
this.socketsContainer,
|
||||||
config,
|
config,
|
||||||
this.getContextCreator(container),
|
);
|
||||||
|
const contextCreator = this.getContextCreator(container);
|
||||||
|
this.webSocketsController = new WebSocketsController(
|
||||||
|
serverProvider,
|
||||||
|
config,
|
||||||
|
contextCreator,
|
||||||
);
|
);
|
||||||
const modules = container.getModules();
|
const modules = container.getModules();
|
||||||
modules.forEach(({ providers }, moduleName: string) =>
|
modules.forEach(({ providers }, moduleName: string) =>
|
||||||
this.hookGatewaysIntoServers(providers, moduleName),
|
this.mergeAllGateways(providers, moduleName),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public hookGatewaysIntoServers(
|
public mergeAllGateways(
|
||||||
providers: Map<string, InstanceWrapper<Injectable>>,
|
providers: Map<string, InstanceWrapper<Injectable>>,
|
||||||
moduleName: string,
|
moduleName: string,
|
||||||
) {
|
) {
|
||||||
providers.forEach(wrapper =>
|
providers.forEach(wrapper =>
|
||||||
this.hookGatewayIntoServer(wrapper, moduleName),
|
this.mergeGatewayAndServer(wrapper, moduleName),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public hookGatewayIntoServer(
|
public mergeGatewayAndServer(
|
||||||
wrapper: InstanceWrapper<Injectable>,
|
wrapper: InstanceWrapper<Injectable>,
|
||||||
moduleName: string,
|
moduleName: string,
|
||||||
) {
|
) {
|
||||||
@@ -59,7 +64,7 @@ export class SocketModule {
|
|||||||
if (!metadataKeys.includes(GATEWAY_METADATA)) {
|
if (!metadataKeys.includes(GATEWAY_METADATA)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.webSocketsController.hookGatewayIntoServer(
|
this.webSocketsController.mergeGatewayAndServer(
|
||||||
instance as NestGateway,
|
instance as NestGateway,
|
||||||
metatype,
|
metatype,
|
||||||
moduleName,
|
moduleName,
|
||||||
|
|||||||
@@ -129,8 +129,9 @@ describe('WsContextCreator', () => {
|
|||||||
module,
|
module,
|
||||||
);
|
);
|
||||||
const data = 'test';
|
const data = 'test';
|
||||||
|
proxy(null, data).catch(err =>
|
||||||
expect(proxy(null, data)).to.eventually.rejectedWith(WsException);
|
expect(err).to.be.instanceOf(WsException),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -164,7 +165,7 @@ describe('WsContextCreator', () => {
|
|||||||
it('should throw exception when "tryActivate" returns false', () => {
|
it('should throw exception when "tryActivate" returns false', () => {
|
||||||
const guardsFn = contextCreator.createGuardsFn([null], null, null);
|
const guardsFn = contextCreator.createGuardsFn([null], null, null);
|
||||||
sinon.stub(guardsConsumer, 'tryActivate').callsFake(() => false);
|
sinon.stub(guardsConsumer, 'tryActivate').callsFake(() => false);
|
||||||
expect(guardsFn([])).to.eventually.throw();
|
guardsFn([]).catch(err => expect(err).to.not.be.undefined);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import * as sinon from 'sinon';
|
|||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { WsExceptionsHandler } from '../../exceptions/ws-exceptions-handler';
|
import { WsExceptionsHandler } from '../../exceptions/ws-exceptions-handler';
|
||||||
import { WsException } from '../../errors/ws-exception';
|
import { WsException } from '../../errors/ws-exception';
|
||||||
import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context.host';
|
import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context-host';
|
||||||
|
|
||||||
describe('WsExceptionsHandler', () => {
|
describe('WsExceptionsHandler', () => {
|
||||||
let handler: WsExceptionsHandler;
|
let handler: WsExceptionsHandler;
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
import * as sinon from 'sinon';
|
|
||||||
import { expect } from 'chai';
|
|
||||||
import { SocketServerProvider } from '../socket-server-provider';
|
|
||||||
import { SocketsContainer } from '../container';
|
|
||||||
import { ApplicationConfig } from '@nestjs/core/application-config';
|
import { ApplicationConfig } from '@nestjs/core/application-config';
|
||||||
import { IoAdapter } from '@nestjs/websockets/adapters/io-adapter';
|
import { expect } from 'chai';
|
||||||
|
import * as sinon from 'sinon';
|
||||||
|
import { SocketsContainer } from '../container';
|
||||||
|
import { SocketServerProvider } from '../socket-server-provider';
|
||||||
|
import { AbstractWsAdapter } from './../adapters/ws-adapter';
|
||||||
|
|
||||||
|
class NoopAdapter extends AbstractWsAdapter {
|
||||||
|
public create(port: number, options?: any) {}
|
||||||
|
public bindMessageHandlers(client: any, handlers) {}
|
||||||
|
}
|
||||||
|
|
||||||
describe('SocketServerProvider', () => {
|
describe('SocketServerProvider', () => {
|
||||||
let instance: SocketServerProvider;
|
let instance: SocketServerProvider;
|
||||||
@@ -14,7 +19,7 @@ describe('SocketServerProvider', () => {
|
|||||||
mockContainer = sinon.mock(socketsContainer);
|
mockContainer = sinon.mock(socketsContainer);
|
||||||
instance = new SocketServerProvider(
|
instance = new SocketServerProvider(
|
||||||
socketsContainer,
|
socketsContainer,
|
||||||
new ApplicationConfig(new IoAdapter()),
|
new ApplicationConfig(new NoopAdapter()),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
describe('scanForSocketServer', () => {
|
describe('scanForSocketServer', () => {
|
||||||
|
|||||||
@@ -1,17 +1,31 @@
|
|||||||
import { ApplicationConfig } from '@nestjs/core/application-config';
|
import { ApplicationConfig } from '@nestjs/core/application-config';
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { of } from 'rxjs';
|
import { fromEvent, Observable, of } from 'rxjs';
|
||||||
import * as sinon from 'sinon';
|
import * as sinon from 'sinon';
|
||||||
import { MetadataScanner } from '../../core/metadata-scanner';
|
import { MetadataScanner } from '../../core/metadata-scanner';
|
||||||
|
import { AbstractWsAdapter } from '../adapters/ws-adapter';
|
||||||
import { PORT_METADATA } from '../constants';
|
import { PORT_METADATA } from '../constants';
|
||||||
import { WsContextCreator } from '../context/ws-context-creator';
|
import { WsContextCreator } from '../context/ws-context-creator';
|
||||||
import { InvalidSocketPortException } from '../errors/invalid-socket-port.exception';
|
import { InvalidSocketPortException } from '../errors/invalid-socket-port.exception';
|
||||||
import { GatewayMetadataExplorer } from '../gateway-metadata-explorer';
|
import { GatewayMetadataExplorer } from '../gateway-metadata-explorer';
|
||||||
import { IoAdapter } from '../index';
|
|
||||||
import { SocketServerProvider } from '../socket-server-provider';
|
import { SocketServerProvider } from '../socket-server-provider';
|
||||||
import { WebSocketGateway } from '../utils/socket-gateway.decorator';
|
import { WebSocketGateway } from '../utils/socket-gateway.decorator';
|
||||||
import { WebSocketsController } from '../web-sockets-controller';
|
import { WebSocketsController } from '../web-sockets-controller';
|
||||||
|
|
||||||
|
class NoopAdapter extends AbstractWsAdapter {
|
||||||
|
public create(port: number, options?: any) {}
|
||||||
|
public bindMessageHandlers(
|
||||||
|
client: any,
|
||||||
|
handlers,
|
||||||
|
transform: (data: any) => Observable<any>,
|
||||||
|
) {
|
||||||
|
handlers.forEach(({ message, callback }) => {
|
||||||
|
const source$ = fromEvent(client, message);
|
||||||
|
source$.subscribe(data => null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
describe('WebSocketsController', () => {
|
describe('WebSocketsController', () => {
|
||||||
let instance: WebSocketsController;
|
let instance: WebSocketsController;
|
||||||
let provider: SocketServerProvider,
|
let provider: SocketServerProvider,
|
||||||
@@ -24,7 +38,7 @@ describe('WebSocketsController', () => {
|
|||||||
class Test {}
|
class Test {}
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
config = new ApplicationConfig(new IoAdapter());
|
config = new ApplicationConfig(new NoopAdapter());
|
||||||
provider = new SocketServerProvider(null, config);
|
provider = new SocketServerProvider(null, config);
|
||||||
mockProvider = sinon.mock(provider);
|
mockProvider = sinon.mock(provider);
|
||||||
instance = new WebSocketsController(
|
instance = new WebSocketsController(
|
||||||
@@ -33,7 +47,7 @@ describe('WebSocketsController', () => {
|
|||||||
sinon.createStubInstance(WsContextCreator),
|
sinon.createStubInstance(WsContextCreator),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
describe('hookGatewayIntoServer', () => {
|
describe('mergeGatewayAndServer', () => {
|
||||||
let subscribeObservableServer: sinon.SinonSpy;
|
let subscribeObservableServer: sinon.SinonSpy;
|
||||||
|
|
||||||
@WebSocketGateway('test' as any)
|
@WebSocketGateway('test' as any)
|
||||||
@@ -49,7 +63,7 @@ describe('WebSocketsController', () => {
|
|||||||
it('should throws "InvalidSocketPortException" when port is not a number', () => {
|
it('should throws "InvalidSocketPortException" when port is not a number', () => {
|
||||||
Reflect.defineMetadata(PORT_METADATA, 'test', InvalidGateway);
|
Reflect.defineMetadata(PORT_METADATA, 'test', InvalidGateway);
|
||||||
expect(() =>
|
expect(() =>
|
||||||
instance.hookGatewayIntoServer(
|
instance.mergeGatewayAndServer(
|
||||||
new InvalidGateway(),
|
new InvalidGateway(),
|
||||||
InvalidGateway,
|
InvalidGateway,
|
||||||
'',
|
'',
|
||||||
@@ -58,13 +72,13 @@ describe('WebSocketsController', () => {
|
|||||||
});
|
});
|
||||||
it('should call "subscribeObservableServer" with default values when metadata is empty', () => {
|
it('should call "subscribeObservableServer" with default values when metadata is empty', () => {
|
||||||
const gateway = new DefaultGateway();
|
const gateway = new DefaultGateway();
|
||||||
instance.hookGatewayIntoServer(gateway, DefaultGateway, '');
|
instance.mergeGatewayAndServer(gateway, DefaultGateway, '');
|
||||||
expect(subscribeObservableServer.calledWith(gateway, {}, 0, '')).to.be
|
expect(subscribeObservableServer.calledWith(gateway, {}, 0, '')).to.be
|
||||||
.true;
|
.true;
|
||||||
});
|
});
|
||||||
it('should call "subscribeObservableServer" when metadata is valid', () => {
|
it('should call "subscribeObservableServer" when metadata is valid', () => {
|
||||||
const gateway = new Test();
|
const gateway = new Test();
|
||||||
instance.hookGatewayIntoServer(gateway, Test, '');
|
instance.mergeGatewayAndServer(gateway, Test, '');
|
||||||
expect(
|
expect(
|
||||||
subscribeObservableServer.calledWith(gateway, { namespace }, port, ''),
|
subscribeObservableServer.calledWith(gateway, { namespace }, port, ''),
|
||||||
).to.be.true;
|
).to.be.true;
|
||||||
@@ -303,7 +317,7 @@ describe('WebSocketsController', () => {
|
|||||||
});
|
});
|
||||||
it('should bind each handler to client', () => {
|
it('should bind each handler to client', () => {
|
||||||
instance.subscribeMessages(handlers, client, gateway);
|
instance.subscribeMessages(handlers, client, gateway);
|
||||||
expect(onSpy.calledThrice).to.be.true;
|
expect(onSpy.calledTwice).to.be.true;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('pickResult', () => {
|
describe('pickResult', () => {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export class WebSocketsController {
|
|||||||
private readonly contextCreator: WsContextCreator,
|
private readonly contextCreator: WsContextCreator,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public hookGatewayIntoServer(
|
public mergeGatewayAndServer(
|
||||||
instance: NestGateway,
|
instance: NestGateway,
|
||||||
metatype: Type<any>,
|
metatype: Type<any>,
|
||||||
module: string,
|
module: string,
|
||||||
|
|||||||
@@ -1,10 +1,17 @@
|
|||||||
import { NestFactory, FastifyAdapter } from '@nestjs/core';
|
|
||||||
import { ValidationPipe } from '@nestjs/common';
|
import { ValidationPipe } from '@nestjs/common';
|
||||||
|
import { NestFactory } from '@nestjs/core';
|
||||||
|
import {
|
||||||
|
FastifyAdapter,
|
||||||
|
INestFastifyApplication,
|
||||||
|
} from '@nestjs/platform-fastify';
|
||||||
import { ApplicationModule } from './app.module';
|
import { ApplicationModule } from './app.module';
|
||||||
|
|
||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
const app = await NestFactory.create(ApplicationModule, new FastifyAdapter());
|
const app = await NestFactory.create<INestFastifyApplication>(
|
||||||
|
ApplicationModule,
|
||||||
|
new FastifyAdapter(),
|
||||||
|
);
|
||||||
app.useGlobalPipes(new ValidationPipe());
|
app.useGlobalPipes(new ValidationPipe());
|
||||||
await app.listen(3000);
|
await app.listen(3000);
|
||||||
}
|
}
|
||||||
bootstrap();
|
bootstrap();
|
||||||
|
|||||||
Reference in New Issue
Block a user