Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Binary Messages over Websocket from default nestjs ws adapter doesnt work, doesnt connect. #13779

Closed
4 of 15 tasks
Eyalm321 opened this issue Jul 11, 2024 · 1 comment
Closed
4 of 15 tasks
Labels
needs triage This issue has not been looked into

Comments

@Eyalm321
Copy link

Is there an existing issue for this?

  • I have searched the existing issues

Current behavior

In main.ts
I define adapter from @nestjs/platform-socket.io and pass it httpsOptions(pem files)
Upon connection from postman it seems to work and make a connection but if connection is made for binary streaming like audio, client will disconnect.
Using WsAdapter from @nestjs/platform-ws solves it and messages come through securely using the same httpsServer BUT it doesnt support namespace so I can see how server dev becomes complex as I add more gateways , having all clients route to the same path.

Minimum reproduction code

https://github.com

Steps to reproduce

I'm not able to reproduce in a simple app, im using freeSwitch for my sip server, when I get a phone call it route RTP to WSS using mod_audio_stream.
I can paste my main.ts and gateway

main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as cookieParser from 'cookie-parser';
import * as dotenv from 'dotenv';
import * as fs from 'fs';
import * as https from 'https';
import { AllExceptionsFilter } from './shared/filters/http-exception.filter';
import { LoggingMiddleware } from './shared/middleware/logging.middleware';
import { WebSocketAdapter } from '@nestjs/common';
import { WsAdapter } from '@nestjs/platform-ws';

async function bootstrap() {
dotenv.config(); // Load environment variables from .env file

const port = process.env.MAIN_PORT || 3000;
const certPath = process.env.MILVUS_CERT_CHAIN_PATH;
const keyPath = process.env.MILVUS_PRIVATE_KEY_PATH;
const caPath = process.env.MILVUS_ROOT_CERT_PATH;
const wssCertPath = process.env.WSS_CERT_PATH;
const wssKeyPath = process.env.WSS_KEY_PATH;

// Check if the certificate files exist
if (!fs.existsSync(certPath)) {
throw new Error(Certificate file not found: ${certPath});
}

if (!fs.existsSync(keyPath)) {
throw new Error(Private key file not found: ${keyPath});
}

if (!fs.existsSync(caPath)) {
throw new Error(CA file not found: ${caPath});
}

const cert = fs.readFileSync(certPath, 'utf-8');
const key = fs.readFileSync(keyPath, 'utf-8');
const ca = fs.readFileSync(caPath, 'utf-8');
const wssCert = fs.readFileSync(wssCertPath, 'utf-8');
const wssKey = fs.readFileSync(wssKeyPath, 'utf-8');

const httpsOptions = {
key: Buffer.from(key, 'utf-8'),
cert: Buffer.from(cert, 'utf-8'),
ca: Buffer.from(ca, 'utf-8'),
};

const wssOptions = {
key: Buffer.from(wssKey, 'utf-8'),
cert: Buffer.from(wssCert, 'utf-8'),
ca: Buffer.from(ca, 'utf-8'),
};

// Create an Express server instance
const app = await NestFactory.create(AppModule, {
httpsOptions,
cors: {
origin: '*',
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
credentials: true,
}
});

// Apply global exception filter
app.useGlobalFilters(new AllExceptionsFilter());

// Apply global logging middleware
app.use(new LoggingMiddleware().use);

// Use middleware
app.use(cookieParser()); // Parse cookies

const wsServer = https.createServer(httpsOptions, app.getHttpAdapter().getInstance());
wsServer.listen(443);
app.useWebSocketAdapter(new WsAdapter(wsServer));
app.useWebSocketAdapter(new )

// Start the HTTP application
await app.listen(port, () => {
console.log(HTTP Application is running on: https://localhost:${port});
});

app.getHttpAdapter().getInstance().use((req, res, next) => {
console.log(Incoming Request: ${req.method} ${req.url});
next();
});
}

bootstrap();

gateway:

import { WebSocketGateway, WebSocketServer, OnGatewayConnection, OnGatewayDisconnect } from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';
import { stringify } from 'flatted';
import { Logger } from '@nestjs/common';
import * as fs from 'fs';
import * as minimist from 'minimist';

@WebSocketGateway({
transports: ['websocket'],
allowEIO3: true,
allowUpgrades: true,
allowRequests: true,
})
export class AudioGateway implements OnGatewayConnection, OnGatewayDisconnect {
@WebSocketServer() server: Server;
private logger: Logger = new Logger('AudioGateway');
private wstream: fs.WriteStream;
private recordingPath: string;

constructor() {
    const argv = minimist(process.argv.slice(2));
    this.recordingPath = argv._.length ? argv._[0] : '/tmp/audio.raw';
    this.logger.log(`Writing incoming raw audio to file ${this.recordingPath}`);
}

afterInit(server: Server) {
    this.logger.log('WebSocket server initialized');
}

handleConnection(client: Socket, ...args: any[]) {
    this.logger.log(`Client connected: ${client.request}`);
    this.wstream = fs.createWriteStream(this.recordingPath, { flags: 'a' });

    client.on('message', (message) => {
        if (typeof message === 'string') {
            this.logger.log(`Received message: ${message}`);
        } else if (Buffer.isBuffer(message)) {
            this.logger.log(`Received binary message of length ${message.length}`);
            this.wstream.write(message);
        }
    });

    client.on('disconnect', (reason) => {
        this.logger.log(`Client disconnected: ${reason}`);
        this.wstream.end();
    });

    client.on('error', (error) => {
        this.logger.error(`Socket error: ${error.message}`);
        this.wstream.end();
    });
}

handleDisconnect(client: Socket) {
    this.logger.log(`Client disconnected: ${client.request}`);
}

}

Expected behavior

I expected to use adapter from @nestjs/platform-socket.io and have it working. that way I can define namespace to audio gateway.

Package

  • I don't know. Or some 3rd-party package
  • @nestjs/common
  • @nestjs/core
  • @nestjs/microservices
  • @nestjs/platform-express
  • @nestjs/platform-fastify
  • @nestjs/platform-socket.io
  • @nestjs/platform-ws
  • @nestjs/testing
  • @nestjs/websockets
  • Other (see below)

Other package

No response

NestJS version

10.4.1

Packages versions


| \ | | | | |_ |/ |/ __ | | | |
| | | ___ ___ | |
| |\ --. | / \/| | | | | . | / _ / __|| __| | | `--. | | | | | |
| |\ || /_ | | /_
/ //_
/ /| _/| |_____| |
_| _/ _||/ _|_/ _/ _/__/___/

[System Information]
OS Version : Linux 5.14.0-467.el9.x86_64
NodeJS Version : v22.3.0
NPM Version : 10.8.1

[Nest CLI]
Nest CLI Version : 10.4.1

[Nest Platform Information]
platform-socket.io version : 10.3.10
platform-express version : 10.3.10
cache-manager version : 2.2.2
microservices version : 10.3.10
serve-static version : 4.0.2
platform-ws version : 10.3.10
websockets version : 10.3.10
mongoose version : 10.0.6
testing version : 10.3.10
common version : 10.3.10
config version : 3.2.3
axios version : 3.0.2
core version : 10.3.10
cli version : 10.4.1

Node.js version

22.3.0

In which operating systems have you tested?

  • macOS
  • Windows
  • Linux

Other

No response

@Eyalm321 Eyalm321 added the needs triage This issue has not been looked into label Jul 11, 2024
@kamilmysliwiec
Copy link
Member

Thank you for taking the time to submit your report! From the looks of it, this could be better discussed on our Discord. If you haven't already, please join here and send a new post in the #⁠ 🐈 nestjs-help forum. Make sure to include a link to this issue, so you don't need to write it all again. We have a large community of helpful members, who will assist you in getting this to work.

@nestjs nestjs locked and limited conversation to collaborators Jul 12, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
needs triage This issue has not been looked into
Projects
None yet
Development

No branches or pull requests

2 participants