|
|
@ -11,6 +11,7 @@ import org.jetbrains.annotations.NotNull; |
|
|
|
import org.jetbrains.annotations.Nullable; |
|
|
|
|
|
|
|
import java.util.*; |
|
|
|
import java.util.concurrent.atomic.AtomicLong; |
|
|
|
|
|
|
|
import static com.sparrowwallet.sparrow.net.BatchedElectrumServerRpc.MAX_RETRIES; |
|
|
|
import static com.sparrowwallet.sparrow.net.BatchedElectrumServerRpc.RETRY_DELAY; |
|
|
@ -18,8 +19,10 @@ import static com.sparrowwallet.sparrow.net.BatchedElectrumServerRpc.RETRY_DELAY |
|
|
|
public class PagedBatchRequestBuilder<K, V> extends AbstractBuilder { |
|
|
|
public static final int DEFAULT_PAGE_SIZE = 500; |
|
|
|
|
|
|
|
private final AtomicLong counter; |
|
|
|
|
|
|
|
@NotNull |
|
|
|
private final List<Request> requests; |
|
|
|
private final List<Request<K>> requests; |
|
|
|
|
|
|
|
/** |
|
|
|
* Type of request ids |
|
|
@ -41,17 +44,19 @@ public class PagedBatchRequestBuilder<K, V> extends AbstractBuilder { |
|
|
|
* @param transport transport for request performing |
|
|
|
* @param mapper mapper for JSON processing |
|
|
|
*/ |
|
|
|
public PagedBatchRequestBuilder(@NotNull Transport transport, @NotNull ObjectMapper mapper) { |
|
|
|
this(transport, mapper, new ArrayList<Request>(), null, null); |
|
|
|
public PagedBatchRequestBuilder(@NotNull Transport transport, @NotNull ObjectMapper mapper, AtomicLong counter) { |
|
|
|
this(transport, mapper, new ArrayList<Request<K>>(), null, null, counter); |
|
|
|
} |
|
|
|
|
|
|
|
public PagedBatchRequestBuilder(@NotNull Transport transport, @NotNull ObjectMapper mapper, |
|
|
|
@NotNull List<Request> requests, |
|
|
|
@Nullable Class<K> keysType, @Nullable Class<V> returnType) { |
|
|
|
@NotNull List<Request<K>> requests, |
|
|
|
@Nullable Class<K> keysType, @Nullable Class<V> returnType, |
|
|
|
@Nullable AtomicLong counter) { |
|
|
|
super(transport, mapper); |
|
|
|
this.requests = requests; |
|
|
|
this.keysType = keysType; |
|
|
|
this.returnType = returnType; |
|
|
|
this.counter = counter; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
@ -63,8 +68,8 @@ public class PagedBatchRequestBuilder<K, V> extends AbstractBuilder { |
|
|
|
* @return the current builder |
|
|
|
*/ |
|
|
|
@NotNull |
|
|
|
public PagedBatchRequestBuilder<K, V> add(Object id, @NotNull String method, @NotNull Object param) { |
|
|
|
requests.add(new Request(id, method, param)); |
|
|
|
public PagedBatchRequestBuilder<K, V> add(K id, @NotNull String method, @NotNull Object param) { |
|
|
|
requests.add(new Request<K>(id, counter == null ? null : counter.incrementAndGet(), method, param)); |
|
|
|
return this; |
|
|
|
} |
|
|
|
|
|
|
@ -77,7 +82,7 @@ public class PagedBatchRequestBuilder<K, V> extends AbstractBuilder { |
|
|
|
* @return a new builder |
|
|
|
*/ |
|
|
|
public <NK> PagedBatchRequestBuilder<NK, V> keysType(@NotNull Class<NK> keysClass) { |
|
|
|
return new PagedBatchRequestBuilder<NK, V>(transport, mapper, requests, keysClass, returnType); |
|
|
|
return new PagedBatchRequestBuilder<NK, V>(transport, mapper, new ArrayList<Request<NK>>(), keysClass, returnType, counter); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
@ -89,7 +94,7 @@ public class PagedBatchRequestBuilder<K, V> extends AbstractBuilder { |
|
|
|
* @return a new builder |
|
|
|
*/ |
|
|
|
public <NV> PagedBatchRequestBuilder<K, NV> returnType(@NotNull Class<NV> valuesClass) { |
|
|
|
return new PagedBatchRequestBuilder<K, NV>(transport, mapper, requests, keysType, valuesClass); |
|
|
|
return new PagedBatchRequestBuilder<K, NV>(transport, mapper, requests, keysType, valuesClass, counter); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
@ -102,21 +107,35 @@ public class PagedBatchRequestBuilder<K, V> extends AbstractBuilder { |
|
|
|
Map<K, V> allResults = new HashMap<>(); |
|
|
|
JsonRpcClient client = new JsonRpcClient(transport); |
|
|
|
|
|
|
|
List<List<Request>> pages = Lists.partition(requests, getPageSize()); |
|
|
|
for(List<Request> page : pages) { |
|
|
|
BatchRequestBuilder<K, V> batchRequest = client.createBatchRequest().keysType(keysType).returnType(returnType); |
|
|
|
for(Request request : page) { |
|
|
|
if(request.id instanceof String strReq) { |
|
|
|
batchRequest.add(strReq, request.method, request.param); |
|
|
|
} else if(request.id instanceof Integer intReq) { |
|
|
|
batchRequest.add(intReq, request.method, request.param); |
|
|
|
} else { |
|
|
|
throw new IllegalArgumentException("Id of class " + request.id.getClass().getName() + " not supported"); |
|
|
|
List<List<Request<K>>> pages = Lists.partition(requests, getPageSize()); |
|
|
|
for(List<Request<K>> page : pages) { |
|
|
|
if(counter != null) { |
|
|
|
Map<Long, K> counterIdMap = new HashMap<>(); |
|
|
|
BatchRequestBuilder<Long, V> batchRequest = client.createBatchRequest().keysType(Long.class).returnType(returnType); |
|
|
|
for(Request<K> request : page) { |
|
|
|
counterIdMap.put(request.counterId, request.id); |
|
|
|
batchRequest.add(request.counterId, request.method, request.param); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
Map<K, V> pageResult = new RetryLogic<Map<K, V>>(MAX_RETRIES, RETRY_DELAY, List.of(IllegalStateException.class, IllegalArgumentException.class)).getResult(batchRequest::execute); |
|
|
|
allResults.putAll(pageResult); |
|
|
|
Map<Long, V> pageResult = new RetryLogic<Map<Long, V>>(MAX_RETRIES, RETRY_DELAY, List.of(IllegalStateException.class, IllegalArgumentException.class)).getResult(batchRequest::execute); |
|
|
|
for(Map.Entry<Long, V> pageEntry : pageResult.entrySet()) { |
|
|
|
allResults.put(counterIdMap.get(pageEntry.getKey()), pageEntry.getValue()); |
|
|
|
} |
|
|
|
} else { |
|
|
|
BatchRequestBuilder<K, V> batchRequest = client.createBatchRequest().keysType(keysType).returnType(returnType); |
|
|
|
for(Request<K> request : page) { |
|
|
|
if(request.id instanceof String strReq) { |
|
|
|
batchRequest.add(strReq, request.method, request.param); |
|
|
|
} else if(request.id instanceof Integer intReq) { |
|
|
|
batchRequest.add(intReq, request.method, request.param); |
|
|
|
} else { |
|
|
|
throw new IllegalArgumentException("Id of class " + request.id.getClass().getName() + " not supported"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
Map<K, V> pageResult = new RetryLogic<Map<K, V>>(MAX_RETRIES, RETRY_DELAY, List.of(IllegalStateException.class, IllegalArgumentException.class)).getResult(batchRequest::execute); |
|
|
|
allResults.putAll(pageResult); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return allResults; |
|
|
@ -138,8 +157,18 @@ public class PagedBatchRequestBuilder<K, V> extends AbstractBuilder { |
|
|
|
*/ |
|
|
|
@NotNull |
|
|
|
public static PagedBatchRequestBuilder<?, ?> create(Transport transport) { |
|
|
|
return new PagedBatchRequestBuilder<Object, Object>(transport, new ObjectMapper()); |
|
|
|
return new PagedBatchRequestBuilder<Object, Object>(transport, new ObjectMapper(), null); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Creates a builder of a JSON-RPC batch request in initial state with a counter for request ids |
|
|
|
* |
|
|
|
* @return batch request builder |
|
|
|
*/ |
|
|
|
@NotNull |
|
|
|
public static PagedBatchRequestBuilder<?, ?> create(Transport transport, AtomicLong counter) { |
|
|
|
return new PagedBatchRequestBuilder<Object, Object>(transport, new ObjectMapper(), counter); |
|
|
|
} |
|
|
|
|
|
|
|
private static record Request(Object id, String method, Object param) {} |
|
|
|
private static record Request<K>(K id, Long counterId, String method, Object param) {} |
|
|
|
} |
|
|
|