Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.cryptape.cita.protocol.rx.JsonRpc2_0Rx Maven / Gradle / Ivy
package com.cryptape.cita.protocol.rx;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import com.cryptape.cita.protocol.CITAj;
import com.cryptape.cita.protocol.core.DefaultBlockParameter;
import com.cryptape.cita.protocol.core.DefaultBlockParameterName;
import com.cryptape.cita.protocol.core.DefaultBlockParameterNumber;
import com.cryptape.cita.protocol.core.methods.request.AppFilter;
import com.cryptape.cita.protocol.core.methods.response.AppBlock;
import com.cryptape.cita.protocol.core.methods.response.AppTransaction;
import com.cryptape.cita.protocol.core.methods.response.Log;
import com.cryptape.cita.utils.Flowables;
import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import io.reactivex.FlowableEmitter;
import io.reactivex.FlowableOnSubscribe;
import io.reactivex.Scheduler;
import io.reactivex.functions.Cancellable;
import io.reactivex.functions.Function;
import io.reactivex.functions.Predicate;
import io.reactivex.schedulers.Schedulers;
import com.cryptape.cita.protocol.core.filters.BlockFilter;
import com.cryptape.cita.protocol.core.filters.Callback;
import com.cryptape.cita.protocol.core.filters.Filter;
import com.cryptape.cita.protocol.core.filters.LogFilter;
import com.cryptape.cita.protocol.core.filters.PendingTransactionFilter;
import com.cryptape.cita.protocol.core.methods.response.Transaction;
import org.reactivestreams.Publisher;
/**
* citaj reactive API implementation.
*/
public class JsonRpc2_0Rx {
private final CITAj citaj;
private final ScheduledExecutorService scheduledExecutorService;
private final Scheduler scheduler;
public JsonRpc2_0Rx(CITAj citaj, ScheduledExecutorService scheduledExecutorService) {
this.citaj = citaj;
this.scheduledExecutorService = scheduledExecutorService;
this.scheduler = Schedulers.from(scheduledExecutorService);
}
public Flowable appBlockHashFlowable(long pollingInterval) {
return Flowable.create(subscriber -> {
BlockFilter blockFilter = new BlockFilter(citaj, new Callback() {
@Override
public void onEvent(final String value) {
subscriber.onNext(value);
}
});
JsonRpc2_0Rx.this.run(blockFilter, subscriber, pollingInterval);
}, BackpressureStrategy.BUFFER);
}
public Flowable appPendingTransactionHashFlowable(long pollingInterval) {
return Flowable.create(subscriber -> {
PendingTransactionFilter pendingTransactionFilter = new PendingTransactionFilter(
citaj, subscriber::onNext);
run(pendingTransactionFilter, subscriber, pollingInterval);
}, BackpressureStrategy.BUFFER);
}
public Flowable appLogFlowable(AppFilter appFilter, long pollingInterval) {
return Flowable.create(new FlowableOnSubscribe() {
@Override
public void subscribe(FlowableEmitter emitter) throws Exception {
final LogFilter logFilter = new LogFilter(citaj, new Callback() {
@Override
public void onEvent(Log value) {
emitter.onNext(value);
}
}, appFilter);
run(logFilter, emitter, pollingInterval);
}
}, BackpressureStrategy.BUFFER);
}
private void run(
Filter filter, FlowableEmitter emitter,
long pollingInterval) {
filter.run(scheduledExecutorService, pollingInterval);
emitter.setCancellable(new Cancellable() {
@Override
public void cancel() throws Exception {
filter.cancel();
}
});
}
public Flowable transactionFlowable(long pollingInterval) {
return blockFlowable(true, pollingInterval)
.flatMapIterable(JsonRpc2_0Rx::toTransactions);
}
public Flowable pendingTransactionFlowable(long pollingInterval) {
return appPendingTransactionHashFlowable(pollingInterval)
.flatMap(new Function>() {
@Override
public Publisher apply(String transactionHash) throws Exception {
return citaj.appGetTransactionByHash(transactionHash).flowable();
}
})
.filter(new Predicate() {
@Override
public boolean test(AppTransaction ethTransaction) throws Exception {
return ethTransaction.getTransaction() != null;
}
})
.map(new Function() {
@Override
public Transaction apply(AppTransaction ethTransaction) throws Exception {
return ethTransaction.getTransaction();
}
});
}
public Flowable blockFlowable(
boolean fullTransactionObjects, long pollingInterval) {
return appBlockHashFlowable(pollingInterval)
.flatMap(blockHash ->
citaj.appGetBlockByHash(
blockHash, fullTransactionObjects).flowable());
}
public Flowable replayBlocksFlowable(
DefaultBlockParameter startBlock, DefaultBlockParameter endBlock,
boolean fullTransactionObjects) {
return replayBlocksFlowable(startBlock, endBlock, fullTransactionObjects, true);
}
public Flowable replayBlocksFlowable(
DefaultBlockParameter startBlock, DefaultBlockParameter endBlock,
boolean fullTransactionObjects, boolean ascending) {
// We use a scheduler to ensure this Flowable runs asynchronously for users to be
// consistent with the other Flowables
return replayBlocksFlowableSync(startBlock, endBlock, fullTransactionObjects, ascending)
.subscribeOn(scheduler);
}
private Flowable replayBlocksFlowableSync(
DefaultBlockParameter startBlock, DefaultBlockParameter endBlock,
boolean fullTransactionObjects) {
return replayBlocksFlowableSync(startBlock, endBlock, fullTransactionObjects, true);
}
private Flowable replayBlocksFlowableSync(
DefaultBlockParameter startBlock, DefaultBlockParameter endBlock,
boolean fullTransactionObjects, boolean ascending) {
BigInteger startBlockNumber = null;
BigInteger endBlockNumber = null;
try {
startBlockNumber = getBlockNumber(startBlock);
endBlockNumber = getBlockNumber(endBlock);
} catch (IOException e) {
Flowable.error(e);
}
if (ascending) {
return Flowables.range(startBlockNumber, endBlockNumber)
.flatMap(i -> citaj.appGetBlockByNumber(
new DefaultBlockParameterNumber(i),
fullTransactionObjects).flowable());
} else {
return Flowables.range(startBlockNumber, endBlockNumber, false)
.flatMap(i -> citaj.appGetBlockByNumber(
new DefaultBlockParameterNumber(i),
fullTransactionObjects).flowable());
}
}
public Flowable replayTransactionsFlowable(
DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) {
return replayBlocksFlowable(startBlock, endBlock, true)
.flatMapIterable(JsonRpc2_0Rx::toTransactions);
}
public Flowable catchUpToLatestBlockFlowable(
DefaultBlockParameter startBlock, boolean fullTransactionObjects,
Flowable onCompleteFlowable) {
// We use a scheduler to ensure this Flowable runs asynchronously for users to be
// consistent with the other Flowables
return catchUpToLatestBlockFlowableSync(
startBlock, fullTransactionObjects, onCompleteFlowable)
.subscribeOn(scheduler);
}
public Flowable catchUpToLatestBlockFlowable(
DefaultBlockParameter startBlock, boolean fullTransactionObjects) {
return catchUpToLatestBlockFlowable(
startBlock, fullTransactionObjects, Flowable.empty());
}
private Flowable catchUpToLatestBlockFlowableSync(
DefaultBlockParameter startBlock, boolean fullTransactionObjects,
Flowable onCompleteFlowable) {
BigInteger startBlockNumber;
BigInteger latestBlockNumber;
try {
startBlockNumber = getBlockNumber(startBlock);
latestBlockNumber = getLatestBlockNumber();
} catch (IOException e) {
return Flowable.error(e);
}
if (startBlockNumber.compareTo(latestBlockNumber) > -1) {
return onCompleteFlowable;
} else {
return Flowable.concat(
replayBlocksFlowableSync(
new DefaultBlockParameterNumber(startBlockNumber),
new DefaultBlockParameterNumber(latestBlockNumber),
fullTransactionObjects),
Flowable.defer(() -> catchUpToLatestBlockFlowableSync(
new DefaultBlockParameterNumber(latestBlockNumber.add(BigInteger.ONE)),
fullTransactionObjects,
onCompleteFlowable)));
}
}
public Flowable catchUpToLatestTransactionFlowable(
DefaultBlockParameter startBlock) {
return catchUpToLatestBlockFlowable(
startBlock, true, Flowable.empty())
.flatMapIterable(JsonRpc2_0Rx::toTransactions);
}
public Flowable catchUpToLatestAndSubscribeToNewBlocksFlowable(
DefaultBlockParameter startBlock, boolean fullTransactionObjects,
long pollingInterval) {
return catchUpToLatestBlockFlowable(
startBlock, fullTransactionObjects,
blockFlowable(fullTransactionObjects, pollingInterval));
}
public Flowable catchUpToLatestAndSubscribeToNewTransactionsFlowable(
DefaultBlockParameter startBlock, long pollingInterval) {
return catchUpToLatestAndSubscribeToNewBlocksFlowable(
startBlock, true, pollingInterval)
.flatMapIterable(JsonRpc2_0Rx::toTransactions);
}
private BigInteger getLatestBlockNumber() throws IOException {
return getBlockNumber(DefaultBlockParameterName.PENDING);
}
private BigInteger getBlockNumber(
DefaultBlockParameter defaultBlockParameter) throws IOException {
if (defaultBlockParameter instanceof DefaultBlockParameterNumber) {
return ((DefaultBlockParameterNumber) defaultBlockParameter).getBlockNumber();
} else {
AppBlock latestEthBlock = citaj.appGetBlockByNumber(
defaultBlockParameter, false).send();
return latestEthBlock.getBlock().getHeader().getNumberDec();
}
}
private static List toTransactions(AppBlock appBlock) {
// If you ever see an exception thrown here, it's probably due to an incomplete chain in
// Geth/Parity. You should resync to solve.
List transactionResults = appBlock.getBlock().getBody().getTransactions();
List transactions = new ArrayList(transactionResults.size());
for (AppBlock.TransactionResult transactionResult : transactionResults) {
transactions.add((Transaction) transactionResult.get());
}
return transactions;
}
}