All Downloads are FREE. Search and download functionalities are using the official Maven repository.

info.bitrich.xchangestream.okcoin.OkCoinStreamingService Maven / Gradle / Ivy

The newest version!
package info.bitrich.xchangestream.okcoin;

import com.fasterxml.jackson.databind.JsonNode;
import info.bitrich.xchangestream.okcoin.dto.WebSocketMessage;
import info.bitrich.xchangestream.service.netty.JsonNettyStreamingService;
import info.bitrich.xchangestream.service.netty.WebSocketClientHandler;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.reactivex.rxjava3.core.Completable;
import io.reactivex.rxjava3.core.CompletableSource;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.disposables.Disposable;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;
import java.util.zip.Inflater;
import org.knowm.xchange.exceptions.ExchangeException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class OkCoinStreamingService extends JsonNettyStreamingService {

  private final Observable pingPongSrc = Observable.interval(15, 15, TimeUnit.SECONDS);

  private Disposable pingPongSubscription;

  public OkCoinStreamingService(String apiUrl) {
    super(apiUrl);
  }

  @Override
  public Completable connect() {
    Completable conn = super.connect();
    return conn.andThen(
        (CompletableSource)
            (completable) -> {
              try {
                if (pingPongSubscription != null && !pingPongSubscription.isDisposed()) {
                  pingPongSubscription.dispose();
                }
                pingPongSubscription =
                    pingPongSrc.subscribe(o -> this.sendMessage("{\"event\":\"ping\"}"));
                completable.onComplete();
              } catch (Exception e) {
                completable.onError(e);
              }
            });
  }

  @Override
  protected String getChannelNameFromMessage(JsonNode message) throws IOException {
    return message.get("channel").asText();
  }

  @Override
  public String getSubscribeMessage(String channelName, Object... args) throws IOException {
    return objectMapper.writeValueAsString(new WebSocketMessage("addChannel", channelName));
  }

  @Override
  public String getUnsubscribeMessage(String channelName, Object... args) throws IOException {
    return objectMapper.writeValueAsString(new WebSocketMessage("removeChannel", channelName));
  }

  @Override
  protected void handleMessage(JsonNode message) {
    if (message.get("event") != null && "pong".equals(message.get("event").asText())) {
      // ignore pong message
      return;
    }
    if (message.get("data") != null) {
      if (message.get("data").has("result")) {
        boolean success = message.get("data").get("result").asBoolean();
        if (!success) {
          super.handleError(
              message,
              new ExchangeException(
                  "Error code: " + message.get("data").get("error_code").asText()));
        }
        return;
      }
    }
    super.handleMessage(message);
  }

  @Override
  protected WebSocketClientHandler getWebSocketClientHandler(
      WebSocketClientHandshaker handshaker,
      WebSocketClientHandler.WebSocketMessageHandler handler) {
    return new OkCoinNettyWebSocketClientHandler(handshaker, handler);
  }

  protected class OkCoinNettyWebSocketClientHandler extends NettyWebSocketClientHandler {

    private final Logger LOG = LoggerFactory.getLogger(OkCoinNettyWebSocketClientHandler.class);

    protected OkCoinNettyWebSocketClientHandler(
        WebSocketClientHandshaker handshaker, WebSocketMessageHandler handler) {
      super(handshaker, handler);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
      if (pingPongSubscription != null && !pingPongSubscription.isDisposed()) {
        pingPongSubscription.dispose();
      }
      super.channelInactive(ctx);
    }

    @Override
    public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {

      if (!handshaker.isHandshakeComplete()) {
        super.channelRead0(ctx, msg);
        return;
      }

      super.channelRead0(ctx, msg);

      WebSocketFrame frame = (WebSocketFrame) msg;
      if (frame instanceof BinaryWebSocketFrame) {
        BinaryWebSocketFrame binaryFrame = (BinaryWebSocketFrame) frame;
        ByteBuf byteBuf = binaryFrame.content();
        byte[] temp = new byte[byteBuf.readableBytes()];
        ByteBufInputStream bis = new ByteBufInputStream(byteBuf);
        StringBuilder appender = new StringBuilder();
        try {
          bis.read(temp);
          bis.close();
          Inflater infl = new Inflater(true);
          infl.setInput(temp, 0, temp.length);
          byte[] result = new byte[1024];
          while (!infl.finished()) {
            int length = infl.inflate(result);
            appender.append(new String(result, 0, length, StandardCharsets.UTF_8));
          }
          infl.end();
        } catch (Exception e) {
          LOG.trace("Error when inflate websocket binary message");
        }
        handler.onMessage(appender.toString());
      }
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy