fix: allow for filters to be aware of the pattern for websockets

This commit is contained in:
Jay McDoniel
2023-09-12 10:56:42 -07:00
parent 67951ff2e9
commit 6f43a8b26e
5 changed files with 58 additions and 15 deletions

View File

@@ -82,5 +82,21 @@ describe('WebSocketGateway', () => {
);
});
it(`should be able to get the pattern in a filter (when the error comes from a known handler)`, async () => {
app = await createNestApp(ApplicationGateway);
await app.listen(3000);
ws = io('http://localhost:8080');
ws.emit('getClientWithError', {
test: 'test',
});
await new Promise<void>(resolve =>
ws.on('exception', data => {
expect(data.pattern).to.be.eql('getClientWithError');
resolve();
}),
);
});
afterEach(() => app.close());
});

View File

@@ -1,10 +1,13 @@
import { UseInterceptors } from '@nestjs/common';
import { UseFilters, UseInterceptors } from '@nestjs/common';
import {
MessageBody,
SubscribeMessage,
WebSocketGateway,
WsException,
} from '@nestjs/websockets';
import { RequestInterceptor } from './request.interceptor';
import { throwError } from 'rxjs';
import { RequestFilter } from './request.filter';
@WebSocketGateway(8080)
export class ApplicationGateway {
@@ -24,4 +27,10 @@ export class ApplicationGateway {
data: { ...data, path: client.pattern },
};
}
@UseFilters(RequestFilter)
@SubscribeMessage('getClientWithError')
getPathCalledWithError() {
return throwError(() => new WsException('This is an error'));
}
}

View File

@@ -0,0 +1,12 @@
import { ArgumentsHost, Catch, ExceptionFilter } from '@nestjs/common';
import { WsException } from '@nestjs/websockets';
@Catch(WsException)
export class RequestFilter implements ExceptionFilter {
catch(exception: WsException, host: ArgumentsHost) {
const wsCtx = host.switchToWs();
const pattern = wsCtx.getPattern();
const client = wsCtx.getClient();
client.emit('exception', { pattern, message: exception.message });
}
}

View File

@@ -107,22 +107,26 @@ export class WsContextCreator {
}
return callback.apply(instance, args);
};
const targetPattern = this.reflectCallbackPattern(callback);
return this.wsProxy.create(
async (...args: unknown[]) => {
args.push(targetPattern);
return this.wsProxy.create(async (...args: unknown[]) => {
args.push(this.reflectCallbackPattern(callback));
const initialArgs = this.contextUtils.createNullArray(argsLength);
fnCanActivate && (await fnCanActivate(args));
const initialArgs = this.contextUtils.createNullArray(argsLength);
fnCanActivate && (await fnCanActivate(args));
return this.interceptorsConsumer.intercept(
interceptors,
args,
instance,
callback,
handler(initialArgs, args),
contextType,
);
}, exceptionHandler);
return this.interceptorsConsumer.intercept(
interceptors,
args,
instance,
callback,
handler(initialArgs, args),
contextType,
);
},
exceptionHandler,
targetPattern,
);
}
public reflectCallbackParamtypes(

View File

@@ -7,8 +7,10 @@ export class WsProxy {
public create(
targetCallback: (...args: unknown[]) => Promise<any>,
exceptionsHandler: WsExceptionsHandler,
targetPattern?: string,
): (...args: unknown[]) => Promise<any> {
return async (...args: unknown[]) => {
args = [...args, targetPattern ?? 'unknown'];
try {
const result = await targetCallback(...args);
return !isObservable(result)