org.bcos.web3j.protocol.rx.JsonRpc2_0Rx Maven / Gradle / Ivy
package org.bcos.web3j.protocol.rx;
import java.io.IOException;
import java.math.BigInteger;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.stream.Collectors;
import rx.Observable;
import rx.Scheduler;
import rx.Subscriber;
import rx.schedulers.Schedulers;
import rx.subscriptions.Subscriptions;
import org.bcos.web3j.protocol.Web3j;
import org.bcos.web3j.protocol.core.DefaultBlockParameter;
import org.bcos.web3j.protocol.core.DefaultBlockParameterName;
import org.bcos.web3j.protocol.core.DefaultBlockParameterNumber;
import org.bcos.web3j.protocol.core.filters.BlockFilter;
import org.bcos.web3j.protocol.core.filters.LogFilter;
import org.bcos.web3j.protocol.core.filters.PendingTransactionFilter;
import org.bcos.web3j.protocol.core.methods.response.EthBlock;
import org.bcos.web3j.protocol.core.methods.response.Log;
import org.bcos.web3j.protocol.core.methods.response.Transaction;
import org.bcos.web3j.utils.Observables;
/**
* web3j reactive API implementation.
*/
public class JsonRpc2_0Rx {
private final Web3j web3j;
private final ScheduledExecutorService scheduledExecutorService;
private final Scheduler scheduler;
public JsonRpc2_0Rx(Web3j web3j, ScheduledExecutorService scheduledExecutorService) {
this.web3j = web3j;
this.scheduledExecutorService = scheduledExecutorService;
this.scheduler = Schedulers.from(scheduledExecutorService);
}
public Observable ethBlockHashObservable(long pollingInterval) {
return Observable.create(subscriber -> {
BlockFilter blockFilter = new BlockFilter(
web3j, subscriber::onNext);
run(blockFilter, subscriber, pollingInterval);
});
}
public Observable ethPendingTransactionHashObservable(long pollingInterval) {
return Observable.create(subscriber -> {
PendingTransactionFilter pendingTransactionFilter = new PendingTransactionFilter(
web3j, subscriber::onNext);
run(pendingTransactionFilter, subscriber, pollingInterval);
});
}
public Observable ethLogObservable(
org.bcos.web3j.protocol.core.methods.request.EthFilter ethFilter, long pollingInterval) {
return Observable.create((Subscriber super Log> subscriber) -> {
LogFilter logFilter = new LogFilter(
web3j, subscriber::onNext, ethFilter);
run(logFilter, subscriber, pollingInterval);
});
}
private void run(
org.bcos.web3j.protocol.core.filters.Filter filter, Subscriber super T> subscriber,
long pollingInterval) {
filter.run(scheduledExecutorService, pollingInterval);
subscriber.add(Subscriptions.create(filter::cancel));
}
public Observable transactionObservable(long pollingInterval) {
return blockObservable(true, pollingInterval)
.flatMapIterable(JsonRpc2_0Rx::toTransactions);
}
public Observable pendingTransactionObservable(long pollingInterval) {
return ethPendingTransactionHashObservable(pollingInterval)
.flatMap(transactionHash ->
web3j.ethGetTransactionByHash(transactionHash).observable())
.map(ethTransaction -> ethTransaction.getTransaction().get());
}
public Observable blockObservable(
boolean fullTransactionObjects, long pollingInterval) {
return ethBlockHashObservable(pollingInterval)
.flatMap(blockHash ->
web3j.ethGetBlockByHash(blockHash, fullTransactionObjects).observable());
}
public Observable replayBlocksObservable(
DefaultBlockParameter startBlock, DefaultBlockParameter endBlock,
boolean fullTransactionObjects) {
// We use a scheduler to ensure this Observable runs asynchronously for users to be
// consistent with the other Observables
return replayBlocksObservableSync(startBlock, endBlock, fullTransactionObjects)
.subscribeOn(scheduler);
}
private Observable replayBlocksObservableSync(
DefaultBlockParameter startBlock, DefaultBlockParameter endBlock,
boolean fullTransactionObjects) {
BigInteger startBlockNumber = null;
BigInteger endBlockNumber = null;
try {
startBlockNumber = getBlockNumber(startBlock);
endBlockNumber = getBlockNumber(endBlock);
} catch (IOException e) {
Observable.error(e);
}
return Observables.range(startBlockNumber, endBlockNumber)
.flatMap(i -> web3j.ethGetBlockByNumber(
new DefaultBlockParameterNumber(i), fullTransactionObjects).observable());
}
public Observable replayTransactionsObservable(
DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) {
return replayBlocksObservable(startBlock, endBlock, true)
.flatMapIterable(JsonRpc2_0Rx::toTransactions);
}
public Observable catchUpToLatestBlockObservable(
DefaultBlockParameter startBlock, boolean fullTransactionObjects,
Observable onCompleteObservable) {
// We use a scheduler to ensure this Observable runs asynchronously for users to be
// consistent with the other Observables
return catchUpToLatestBlockObservableSync(
startBlock, fullTransactionObjects, onCompleteObservable)
.subscribeOn(scheduler);
}
public Observable catchUpToLatestBlockObservable(
DefaultBlockParameter startBlock, boolean fullTransactionObjects) {
return catchUpToLatestBlockObservable(
startBlock, fullTransactionObjects, Observable.empty());
}
private Observable catchUpToLatestBlockObservableSync(
DefaultBlockParameter startBlock, boolean fullTransactionObjects,
Observable onCompleteObservable) {
BigInteger startBlockNumber;
BigInteger latestBlockNumber;
try {
startBlockNumber = getBlockNumber(startBlock);
latestBlockNumber = getLatestBlockNumber();
} catch (IOException e) {
return Observable.error(e);
}
if (startBlockNumber.compareTo(latestBlockNumber) > -1) {
return onCompleteObservable;
} else {
return Observable.concat(
replayBlocksObservableSync(
new DefaultBlockParameterNumber(startBlockNumber),
new DefaultBlockParameterNumber(latestBlockNumber),
fullTransactionObjects),
Observable.defer(() -> catchUpToLatestBlockObservableSync(
new DefaultBlockParameterNumber(latestBlockNumber.add(BigInteger.ONE)),
fullTransactionObjects,
onCompleteObservable)));
}
}
public Observable catchUpToLatestTransactionObservable(
DefaultBlockParameter startBlock) {
return catchUpToLatestBlockObservable(
startBlock, true, Observable.empty())
.flatMapIterable(JsonRpc2_0Rx::toTransactions);
}
public Observable catchUpToLatestAndSubscribeToNewBlocksObservable(
DefaultBlockParameter startBlock, boolean fullTransactionObjects,
long pollingInterval) {
return catchUpToLatestBlockObservable(
startBlock, fullTransactionObjects,
blockObservable(fullTransactionObjects, pollingInterval));
}
public Observable catchUpToLatestAndSubscribeToNewTransactionsObservable(
DefaultBlockParameter startBlock, long pollingInterval) {
return catchUpToLatestAndSubscribeToNewBlocksObservable(
startBlock, true, pollingInterval)
.flatMapIterable(JsonRpc2_0Rx::toTransactions);
}
private BigInteger getLatestBlockNumber() throws IOException {
return getBlockNumber(DefaultBlockParameterName.LATEST);
}
private BigInteger getBlockNumber(
DefaultBlockParameter defaultBlockParameter) throws IOException {
if (defaultBlockParameter instanceof DefaultBlockParameterNumber) {
return ((DefaultBlockParameterNumber) defaultBlockParameter).getBlockNumber();
} else {
EthBlock latestEthBlock = web3j.ethGetBlockByNumber(
defaultBlockParameter, false).send();
return latestEthBlock.getBlock().getNumber();
}
}
private static List toTransactions(EthBlock ethBlock) {
// If you ever see an exception thrown here, it's probably due to an incomplete chain in
// Geth/Parity. You should resync to solve.
return ethBlock.getBlock().getTransactions().stream()
.map(transactionResult -> (Transaction) transactionResult.get())
.collect(Collectors.toList());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy