UNPKG

@nestjs/websockets

Version:

Nest - modern, fast, powerful node.js web framework (@websockets)

92 lines (91 loc) 3.45 kB
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); } }