socketio / socket.io

Realtime application framework (Node.JS server)
https://socket.io
MIT License
60.88k stars 10.09k forks source link

uWebSockets.js not working with msgpack parser #4660

Open eudaimos opened 1 year ago

eudaimos commented 1 year ago

Describe the bug Combining a uWebSockets.js app using the io.attachApp() with the msgpack parser (socket.io-msgpack-parser) does not work. Under the following conditions I'm experiencing different behavior:

  1. When connecting the client and not specifying the transports option, the upgrade will work to connect but the messages are only base64 encoded rather than binary
  2. When connecting the client and specifying transports: ['websocket'] only, the connection handshake cannot complete and continuous reconnections are attempted by the client. The messages do appear to be binary however.

To Reproduce

Please fill the following code example:

Socket.IO server version: 4.6.1 Socket.IO msgpack Parser version: 3.0.2 uWebSockets.js version: uWebSockets.js@uNetworking/uWebSockets.js#v20.20.0

Server

import { Server } from "socket.io";
import { App } from "uWebSockets.js";
import customParser from 'socket.io-msgpack-parser';

const io = new Server();

const app = new App();
io.attachApp(app, {
  serveClient: false,
  parser: customParser,
  cors: environment.cors,
  maxHttpBufferSize: 3.2e8,
});

io.on("connection", (socket) => {
  console.log('connected:', socket.id);
  setTimeout(() =>
    socket.emit('hello', { say: 'hello world!'}),
    2000,
  );
  socket.on('error', err => console.error('socket:', err));
  socket.on('disconnecting', (reason, desc) => console.log({ reason, desc }));
  socket.on('disconnect', (reason, desc) => console.log('disconnect:', { reason, desc }));
});
io.on('error', console.error);

app.listen(3000, (token) => {
  if (!token) {
    console.warn("port already in use");
  } else {
    console.log('open for business!! :rocket:');
  }
});

Socket.IO client version: 4.6.1 Socket.IO msgpack Parser version: 3.0.2

Client

import { io } from "socket.io-client";
import customParser from 'socket.io-msgpack-parser';

const socket = io("ws://localhost:3000/", {
  withCredentials: true,
  parser: customParser,
  // transports: ["websocket"] // uncomment for websocket-only transport
});

socket.on("connect", () => {
  console.log(`connect ${socket.id}`);
});

socket.on('disconnect', (reason, desc) => console.log({ reason, desc }));

Expected behavior Whether specifying transports option or not on the client, the socket will connect, perform the handshake successfully and messages will be passed back and forth in binary encoding.

Platform:

Additional context The Client will repeatedly print transport close disconnect logs but the Server logs nothing. When I close the browser tab the client is executing in, then I will see the disconnect log on the Server.

The parser works with plain socket.io.Server and when wrapping the built-in Node.js HttpServer in my testing.

darrachequesne commented 1 year ago

Hi! I think that's because the parser option is ignored when calling attachApp(). Could you please try with:

import { Server } from "socket.io";
import { App } from "uWebSockets.js";
import customParser from 'socket.io-msgpack-parser';

- const io = new Server();
+ const io = new Server({
+   serveClient: false,
+   parser: customParser,
+   cors: environment.cors,
+   maxHttpBufferSize: 3.2e8,
+ });

const app = App();

- io.attachApp(app, {
-   serveClient: false,
-   parser: customParser,
-   cors: environment.cors,
-   maxHttpBufferSize: 3.2e8,
- });
+ io.attachApp(app);

Something is wrong with the types though, let me check.

eudaimos commented 1 year ago

thanks @darrachequesne - how did you figure out the parser option is ignored when calling attachApp()? Is it getting lost in the initialization of the engine.io engine?

Before submitting the issue, I saw these lines in index.ts:450-458 and concluded it doesn't matter which way I pass the options, either via Server constructor or the attachApp() function.

Also to ensure it wasn't a difference, I tested both ways of initializing the Server and only posted the code sample that was the last one I tried.

eudaimos commented 1 year ago

@darrachequesne I was able to get it to work with a different parser using the suggestion in this issue https://github.com/skgdev/socket.io-msgpack-javascript/issues/15

but only when using websocket only (no upgrade) does it encode binary from the server

darrachequesne commented 1 year ago

It seems there is an issue in the parser here: https://github.com/skgdev/socket.io-msgpack-javascript/issues/15

The client sends { type: 0, data: undefined, nsp: '/' } but the server decodes { type: 0, data: null, nsp: '/' } and closes the connection because data should either be undefined or an object.

Related: https://github.com/socketio/socket.io/pull/4675