0

I'm trying to connect to the Kucoin API using Secure WebSockets (WSS). I'm using JDK 17 and Vert.x 4.3.8 (the latest version at this time). I followed the instructions here.

So currently I have a basic app with two verticles: the first one uses a WebClient to connect to the /api/v1/bullet-public URI to get the WSS endpoint and the token. Once I get an answer, I save these to a local map and publish an event to the bus to connect to the WebSocket feed. This part works fine.

The second verticle consumes the event published by the first one and creates a websocket using the settings saved on the local map. This doesn't work. I tried two slightly different approaches and I get different errors on each.

The first approach is to set the host to ws-api-spot.kucoin.com and the relative URI. The code for this is on this Github gist.

In this case I get the following error:

io.netty.handler.codec.http.websocketx.WebSocketHandshakeException: Connection closed while handshake in process
at io.vertx.core.http.impl.WebSocketHandshakeInboundHandler.channelInactive(WebSocketHandshakeInboundHandler.java:81)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:305)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:281)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:274)
at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelInactive(CombinedChannelDuplexHandler.java:418)
at io.netty.handler.codec.ByteToMessageDecoder.channelInputClosed(ByteToMessageDecoder.java:411)
at io.netty.handler.codec.ByteToMessageDecoder.channelInactive(ByteToMessageDecoder.java:376)
at io.netty.handler.codec.http.HttpClientCodec$Decoder.channelInactive(HttpClientCodec.java:329)
at io.netty.channel.CombinedChannelDuplexHandler.channelInactive(CombinedChannelDuplexHandler.java:221)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:303)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:281)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:274)
at io.netty.handler.logging.LoggingHandler.channelInactive(LoggingHandler.java:206)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:303)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:281)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:274)
at io.netty.handler.codec.ByteToMessageDecoder.channelInputClosed(ByteToMessageDecoder.java:411)
at io.netty.handler.codec.ByteToMessageDecoder.channelInactive(ByteToMessageDecoder.java:376)
at io.netty.handler.ssl.SslHandler.channelInactive(SslHandler.java:1075)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:305)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:281)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:274)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelInactive(DefaultChannelPipeline.java:1405)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:301)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:281)
at io.netty.channel.DefaultChannelPipeline.fireChannelInactive(DefaultChannelPipeline.java:901)
at io.netty.channel.AbstractChannel$AbstractUnsafe$7.run(AbstractChannel.java:813)
at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:174)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:167)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:470)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:566)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
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)

The second approach is to set the absolute URI to something like this:

wss://ws-api-spot.kucoin.com/endpoint/?token=<token_value>&topic=/market/ticker:btc&response=true

To do this, I slightly modified the getOptions method like this:

private static WebSocketConnectOptions getOptions(LocalMap<String, String> serverDetails) {
  WebSocketConnectOptions options = new WebSocketConnectOptions();
  options.setMethod(HttpMethod.GET);
  options.setAllowOriginHeader(false);
  options.setPort(443);
  options.setSsl(true);
  options.setAbsoluteURI(serverDetails.get("endpoint") + "endpoint/?token=" + serverDetails.get("token") + "&topic=/market/ticker:btc&response=true");
  return options;
}

In this case, I get this other error:

io.vertx.core.VertxException: Invalid url: wss://ws-api-spot.kucoin.com/endpoint/?token=<token_value>&topic=/market/ticker:btc&response=true
at io.vertx.core.http.RequestOptions.parseUrl(RequestOptions.java:357)
at io.vertx.core.http.RequestOptions.setAbsoluteURI(RequestOptions.java:370)
at org.phase5.goyena.SymbolSnapshotVerticle.getOptions(SymbolSnapshotVerticle.java:52)
at org.phase5.goyena.SymbolSnapshotVerticle.lambda$start$3(SymbolSnapshotVerticle.java:32)
at io.vertx.core.impl.ContextInternal.dispatch(ContextInternal.java:264)
at io.vertx.core.eventbus.impl.MessageConsumerImpl.dispatch(MessageConsumerImpl.java:177)
at io.vertx.core.eventbus.impl.HandlerRegistration$InboundDeliveryContext.execute(HandlerRegistration.java:137)
at io.vertx.core.eventbus.impl.DeliveryContextBase.next(DeliveryContextBase.java:72)
at io.vertx.core.eventbus.impl.DeliveryContextBase.dispatch(DeliveryContextBase.java:43)
at io.vertx.core.eventbus.impl.HandlerRegistration.dispatch(HandlerRegistration.java:98)
at io.vertx.core.eventbus.impl.MessageConsumerImpl.deliver(MessageConsumerImpl.java:183)
at io.vertx.core.eventbus.impl.MessageConsumerImpl.doReceive(MessageConsumerImpl.java:168)
at io.vertx.core.eventbus.impl.HandlerRegistration.lambda$receive$0(HandlerRegistration.java:49)
at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:174)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:167)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:470)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:569)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
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)
Caused by: java.net.MalformedURLException: unknown protocol: wss
at java.base/java.net.URL.<init>(URL.java:681)
at java.base/java.net.URL.<init>(URL.java:569)
at java.base/java.net.URL.<init>(URL.java:516)
at io.vertx.core.http.RequestOptions.parseUrl(RequestOptions.java:355)
... 20 common frames omitted

When I manually run a request from Postman following the same instructions, I successfully get a connection. Any ideas of what's wrong? Do I need to change the options for either the HTTP client or the Websocket?

Thanks in advance.

foundationer
  • 85
  • 2
  • 9

0 Answers0