quarkus-quinoa icon indicating copy to clipboard operation
quarkus-quinoa copied to clipboard

Handle websocket in dev-mode or document that it is not forwarded (HMR)

Open ia3andy opened this issue 3 years ago • 5 comments

Some NodeJS dev-server don't allow to set the websocket port for for hot reload. Currently those websocket connection are not forwarded by Quinoa.

Some other dev-server like Vite allow to change the HMR port, then http is sent and forwarded by Quinoa and HMR is sent to the frontend dev-server (which works great).

ia3andy avatar May 30 '22 11:05 ia3andy

When stopping the dev mode, it might end up with an exception:

022-05-30 13:52:08,679 INFO  [io.qua.qui.dep.PackageManager] (Thread-40) Stopping Quinoa package manager live coding as a dev service.
2022-05-30 13:52:08,698 ERROR [io.ver.cor.net.imp.ConnectionBase] (vert.x-eventloop-thread-2) Connection reset
2022-05-30 13:52:08,699 ERROR [io.qua.qui.QuinoaDevProxyHandler] (vert.x-eventloop-thread-2) Quinoa failed to forward request, see logs.: java.net.SocketException: Connection reset
	at java.base/sun.nio.ch.SocketChannelImpl.throwConnectionReset(SocketChannelImpl.java:394)
	at java.base/sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:426)
	at io.netty.buffer.PooledByteBuf.setBytes(PooledByteBuf.java:258)
	at io.netty.buffer.AbstractByteBuf.writeBytes(AbstractByteBuf.java:1132)
	at io.netty.channel.socket.nio.NioSocketChannel.doReadBytes(NioSocketChannel.java:350)
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:151)
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:722)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:658)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:584)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:496)
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986)
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:833)

ia3andy avatar May 30 '22 12:05 ia3andy

@cescoffier any idea on how we could listen/forward websocket events?

ia3andy avatar May 30 '22 13:05 ia3andy

Did you look at https://vertx.io/docs/vertx-core/java/#_websockets?

cescoffier avatar May 30 '22 14:05 cescoffier

Did you look at vertx.io/docs/vertx-core/java/#_websockets?

@cescoffier yes I did. But here are my issues:

  • How to know if I should handle a given event or not (what if there is a Quarkus Websocket server also)
  • How to send event the npm server from Vertx (client in the doc is JS)
  • The Quarkus Vertx http server is not accessible from an extension and there is no BuildItem for it. I am not sure it's a good idea to create another one?

ia3andy avatar May 30 '22 14:05 ia3andy

I don't understand your first point. Web sockets are not a publish/subscribe thing, it's end to end. I believe you can receive the request and upgrade to a web socket.

About the second point, do you have a channel of communication? A web socket maybe?

About the third point, yes, but a simple route upgrading the connection to a web socket is generally much better.

cescoffier avatar May 30 '22 18:05 cescoffier

@cescoffier maybe you can help here. We receive a WebSocket request on 8080 but we need to forward it to 3000 (NextJS).

        if (headers.get("Connection").contains("Upgrade")) {
            LOG.infof("Quinoa is forwarding web socket: '%s'", request.uri());
            Future<ServerWebSocket> fut = request.toWebSocket();
            fut.onSuccess(serverWs -> {
                LOG.infof("Quinoa is forwarded web socket: '%s'", request.uri());
                WebSocketConnectOptions options = new WebSocketConnectOptions()
                        .setHost(request.localAddress().host())
                        .setPort(port)
                        .setURI(uri)
                        .setAllowOriginHeader(false);
                httpClient.webSocket(options, res -> {
                    WebSocket clientWs = res.result();
                    clientWs.pipeTo(serverWs);
                    serverWs.pipeTo(clientWs);
                    LOG.infof("Connected! ");
                });
            });

But essentially the goal is we are trying to forward and 8080 WebSocket to 3000 and keep it open for two way communication.

I can see the Next ping-pong but something still isn't working.

image

melloware avatar Mar 10 '23 22:03 melloware

OK I think I found the issue. when running raw Next the event.data is a JSON string.

image

When receiving it from VertX it is a Blob not a string and its breaking Next.

image

So I am wondering how to have VertX send strings back instead of Blobs?

melloware avatar Mar 10 '23 23:03 melloware

I got it all working for both NextJS and Vite. PR on the way...

melloware avatar Mar 11 '23 14:03 melloware