@nestjs/websockets
Version:
Nest - modern, fast, powerful node.js web framework (@websockets)
92 lines (91 loc) • 3.45 kB
JavaScript
import { IntrinsicException, Logger, } from '@nestjs/common';
import { WsException } from '../errors/ws-exception.js';
import { isFunction, isNumber, isObject } from '@nestjs/common/internal';
import { MESSAGES } from '@nestjs/core/internal';
/**
* @publicApi
*/
export class BaseWsExceptionFilter {
options;
static logger = new Logger('WsExceptionsHandler');
constructor(options = {}) {
this.options = options;
this.options.includeCause = this.options.includeCause ?? true;
this.options.causeFactory =
this.options.causeFactory ?? ((pattern, data) => ({ pattern, data }));
}
catch(exception, host) {
const client = host.switchToWs().getClient();
const pattern = host.switchToWs().getPattern();
const data = host.switchToWs().getData();
this.handleError(client, exception, {
pattern,
data,
});
}
handleError(client, exception, cause) {
if (!(exception instanceof WsException)) {
return this.handleUnknownError(exception, client, cause);
}
const status = 'error';
const result = exception.getError();
if (isObject(result)) {
return this.emitMessage(client, 'exception', result);
}
const payload = {
status,
message: result,
};
if (this.options?.includeCause && cause) {
payload.cause = this.options.causeFactory(cause.pattern, cause.data);
}
this.emitMessage(client, 'exception', payload);
}
handleUnknownError(exception, client, data) {
const status = 'error';
const payload = {
status,
message: MESSAGES.UNKNOWN_EXCEPTION_MESSAGE,
};
if (this.options?.includeCause && data) {
payload.cause = this.options.causeFactory(data.pattern, data.data);
}
this.emitMessage(client, 'exception', payload);
if (!(exception instanceof IntrinsicException)) {
const logger = BaseWsExceptionFilter.logger;
logger.error(exception);
}
}
isExceptionObject(err) {
return isObject(err) && !!err.message;
}
/**
* Sends an error message to the client. Supports both Socket.IO clients
* (which use `emit`) and native WebSocket clients (which use `send`).
*
* Native WebSocket clients (e.g. from the `ws` package) inherit from
* EventEmitter and therefore also have an `emit` method, but that method
* only dispatches events locally. To distinguish native WebSocket clients
* from Socket.IO clients, we check for a numeric `readyState` property
* (part of the WebSocket specification) before falling back to `emit`.
*/
emitMessage(client, event, payload) {
if (this.isNativeWebSocket(client)) {
client.send(JSON.stringify({
event,
data: payload,
}));
}
else if (isFunction(client.emit)) {
client.emit(event, payload);
}
}
/**
* Determines whether the given client is a native WebSocket (e.g. from the
* `ws` package) as opposed to a Socket.IO socket. Native WebSocket objects
* expose a numeric `readyState` property per the WebSocket specification.
*/
isNativeWebSocket(client) {
return isNumber(client.readyState) && isFunction(client.send);
}
}