info.bitrich.xchangestream.poloniex2.PoloniexStreamingService Maven / Gradle / Ivy
package info.bitrich.xchangestream.poloniex2;
import com.fasterxml.jackson.databind.JsonNode;
import info.bitrich.xchangestream.poloniex2.dto.PoloniexWebSocketEvent;
import info.bitrich.xchangestream.poloniex2.dto.PoloniexWebSocketEventsTransaction;
import info.bitrich.xchangestream.poloniex2.dto.PoloniexWebSocketOrderbookModifiedEvent;
import info.bitrich.xchangestream.poloniex2.dto.PoloniexWebSocketSubscriptionMessage;
import info.bitrich.xchangestream.service.netty.JsonNettyStreamingService;
import io.reactivex.rxjava3.core.Observable;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.knowm.xchange.currency.CurrencyPair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** Created by Lukas Zaoralek on 10.11.17. */
public class PoloniexStreamingService extends JsonNettyStreamingService {
private static final Logger LOG = LoggerFactory.getLogger(PoloniexStreamingService.class);
private static final String HEARTBEAT = "1010";
private final Map subscribedChannels = new ConcurrentHashMap<>();
private final Map> subscriptions = new ConcurrentHashMap<>();
public PoloniexStreamingService(String apiUrl) {
super(apiUrl, Integer.MAX_VALUE, DEFAULT_CONNECTION_TIMEOUT, DEFAULT_RETRY_DURATION, 2);
}
@Override
protected void handleMessage(JsonNode message) {
if (message.isArray()) {
if (message.size() < 3) {
if (message.get(0).asText().equals(HEARTBEAT)) return;
else if ("1002".equals(message.get(0).asText())) return;
}
int channelId = Integer.parseInt(message.get(0).toString());
if (channelId > 0 && channelId < 1000) {
JsonNode events = message.get(2);
if (events != null && events.isArray()) {
JsonNode event = events.get(0);
if (event.get(0).toString().equals("\"i\"")) {
if (event.get(1).has("orderBook")) {
subscribedChannels.compute(
String.valueOf(channelId),
(key, oldValue) -> {
String currencyPair = event.get(1).get("currencyPair").asText();
if (oldValue != null && !oldValue.equals(currencyPair)) {
throw new RuntimeException("Attempted currency pair channel id reassignment");
}
if (oldValue == null) {
LOG.info("Register {} as {}", channelId, currencyPair);
} else {
LOG.debug("Order book reinitialization {} {}", channelId, currencyPair);
}
return currencyPair;
});
}
}
}
}
}
if (message.has("error")) {
LOG.error("Error with message: " + message.get("error").asText());
return;
}
super.handleMessage(message);
}
@Override
public boolean processArrayMessageSeparately() {
return false;
}
@Override
public synchronized Observable subscribeChannel(String channelName, Object... args) {
if (!channels.containsKey(channelName)) {
subscriptions.put(channelName, super.subscribeChannel(channelName, args));
}
return subscriptions.get(channelName);
}
public Observable> subscribeCurrencyPairChannel(
CurrencyPair currencyPair) {
String channelName = currencyPair.counter.toString() + "_" + currencyPair.base.toString();
return subscribeChannel(channelName)
.map(
jsonNode ->
objectMapper.treeToValue(jsonNode, PoloniexWebSocketEventsTransaction.class))
.scan(
(poloniexWebSocketEventsTransactionOld, poloniexWebSocketEventsTransactionNew) -> {
final boolean initialSnapshot =
poloniexWebSocketEventsTransactionNew.getEvents().stream()
.anyMatch(PoloniexWebSocketOrderbookModifiedEvent.class::isInstance);
final boolean sequenceContinuous =
poloniexWebSocketEventsTransactionOld.getSeqId() + 1
== poloniexWebSocketEventsTransactionNew.getSeqId();
if (!initialSnapshot || sequenceContinuous) {
return poloniexWebSocketEventsTransactionNew;
} else {
throw new RuntimeException(
String.format(
"Invalid sequencing, old: %s new: %s",
objectMapper.writeValueAsString(poloniexWebSocketEventsTransactionOld),
objectMapper.writeValueAsString(poloniexWebSocketEventsTransactionNew)));
}
})
.map(PoloniexWebSocketEventsTransaction::getEvents)
.share();
}
@Override
protected String getChannelNameFromMessage(JsonNode message) {
String strChannelId = message.get(0).asText();
int channelId = Integer.parseInt(strChannelId);
if (channelId >= 1000) return strChannelId;
else return subscribedChannels.get(message.get(0).asText());
}
@Override
public String getSubscribeMessage(String channelName, Object... args) throws IOException {
PoloniexWebSocketSubscriptionMessage subscribeMessage =
new PoloniexWebSocketSubscriptionMessage("subscribe", channelName);
return objectMapper.writeValueAsString(subscribeMessage);
}
@Override
public String getUnsubscribeMessage(String channelName, Object... args) throws IOException {
PoloniexWebSocketSubscriptionMessage subscribeMessage =
new PoloniexWebSocketSubscriptionMessage("unsubscribe", channelName);
return objectMapper.writeValueAsString(subscribeMessage);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy