diff --git a/README.md b/README.md
index 78ccda6e8..22184d7a4 100644
--- a/README.md
+++ b/README.md
@@ -33,7 +33,7 @@ current [BOM](https://howtodoinjava.com/maven/maven-bom-bill-of-materials-depend
org.xrpl
xrpl4j-bom
- 3.4.0
+ 3.5.0
pom
import
diff --git a/xrpl4j-client/src/main/java/org/xrpl/xrpl4j/client/JsonRpcClient.java b/xrpl4j-client/src/main/java/org/xrpl/xrpl4j/client/JsonRpcClient.java
index 75a25ddd5..0c8a3ad4e 100644
--- a/xrpl4j-client/src/main/java/org/xrpl/xrpl4j/client/JsonRpcClient.java
+++ b/xrpl4j-client/src/main/java/org/xrpl/xrpl4j/client/JsonRpcClient.java
@@ -27,6 +27,7 @@
import com.google.common.annotations.Beta;
import feign.Feign;
import feign.Headers;
+import feign.Request.Options;
import feign.RequestLine;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
@@ -71,18 +72,34 @@ public interface JsonRpcClient {
/**
* Constructs a new client for the given url.
*
- * @param rippledUrl url for the faucet server.
+ * @param rippledUrl The {@link HttpUrl} of the node to connect to.
*
* @return A {@link JsonRpcClient} that can make request to {@code rippledUrl}
*/
static JsonRpcClient construct(final HttpUrl rippledUrl) {
Objects.requireNonNull(rippledUrl);
+ return construct(rippledUrl, new Options());
+ }
+
+ /**
+ * Constructs a new client for the given url with the given client options.
+ *
+ * @param rippledUrl The {@link HttpUrl} of the node to connect to.
+ * @param options An {@link Options}.
+ *
+ * @return A {@link JsonRpcClient}.
+ */
+ static JsonRpcClient construct(HttpUrl rippledUrl, Options options) {
+ Objects.requireNonNull(rippledUrl);
+ Objects.requireNonNull(options);
+
return Feign.builder()
.encoder(new JacksonEncoder(objectMapper))
// rate limiting will return a 503 status that can be retried
.errorDecoder(new RetryStatusDecoder(RETRY_INTERVAL, SERVICE_UNAVAILABLE_STATUS))
.decode404()
+ .options(options)
.decoder(new OptionalDecoder(new JacksonDecoder(objectMapper)))
.target(JsonRpcClient.class, rippledUrl.toString());
}
diff --git a/xrpl4j-client/src/main/java/org/xrpl/xrpl4j/client/XrplClient.java b/xrpl4j-client/src/main/java/org/xrpl/xrpl4j/client/XrplClient.java
index bf744ea25..26ef8179a 100644
--- a/xrpl4j-client/src/main/java/org/xrpl/xrpl4j/client/XrplClient.java
+++ b/xrpl4j-client/src/main/java/org/xrpl/xrpl4j/client/XrplClient.java
@@ -28,6 +28,8 @@
import com.google.common.collect.Range;
import com.google.common.primitives.UnsignedInteger;
import com.google.common.primitives.UnsignedLong;
+import feign.Request;
+import feign.Request.Options;
import okhttp3.HttpUrl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -99,8 +101,10 @@
import org.xrpl.xrpl4j.model.transactions.Transaction;
import org.xrpl.xrpl4j.model.transactions.TransactionMetadata;
+import java.time.Duration;
import java.util.Objects;
import java.util.Optional;
+import java.util.concurrent.TimeUnit;
/**
*
A client which wraps a rippled network client and is responsible for higher order functionality such as signing
@@ -127,6 +131,31 @@ public XrplClient(final HttpUrl rippledUrl) {
this(JsonRpcClient.construct(rippledUrl));
}
+ /**
+ * Public constructor that allows for configuration of connect and read timeouts.
+ *
+ *
Note that any {@link Duration} passed in that is less than one millisecond will result in the actual timeout
+ * being zero milliseconds. It is therefore advised to never set {@code connectTimeout} or {@code readTimeout} to a
+ * {@link Duration} less than one millisecond.
+ *
+ * @param rippledUrl The {@link HttpUrl} of the node to connect to.
+ * @param connectTimeout A {@link Duration} indicating the client's connect timeout.
+ * @param readTimeout A {@link Duration} indicating the client's read timeout.
+ */
+ public XrplClient(
+ HttpUrl rippledUrl,
+ Duration connectTimeout,
+ Duration readTimeout
+ ) {
+ this(
+ JsonRpcClient.construct(
+ rippledUrl,
+ new Options(connectTimeout.toMillis(), TimeUnit.MILLISECONDS, readTimeout.toMillis(), TimeUnit.MILLISECONDS,
+ true)
+ )
+ );
+ }
+
/**
* Required-args constructor (exists for testing purposes only).
*
diff --git a/xrpl4j-client/src/test/java/org/xrpl/xrpl4j/client/XrplClientTest.java b/xrpl4j-client/src/test/java/org/xrpl/xrpl4j/client/XrplClientTest.java
index 32c4e05be..2aa720346 100644
--- a/xrpl4j-client/src/test/java/org/xrpl/xrpl4j/client/XrplClientTest.java
+++ b/xrpl4j-client/src/test/java/org/xrpl/xrpl4j/client/XrplClientTest.java
@@ -122,9 +122,11 @@
import org.xrpl.xrpl4j.model.transactions.XrpCurrencyAmount;
import java.math.BigDecimal;
+import java.time.Duration;
import java.time.ZonedDateTime;
import java.util.Optional;
import java.util.Set;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
/**
@@ -599,6 +601,18 @@ public void getXrplClientTest() {
assertThat(new XrplClient(rippledUrl) instanceof JsonRpcClient).isFalse();
}
+ @Test
+ void createXrplClientWithDurationTimeouts() {
+ HttpUrl rippledUrl = HttpUrl.parse("https://s.altnet.rippletest.net:51234");
+ XrplClient client = new XrplClient(
+ rippledUrl,
+ Duration.ofSeconds(1),
+ Duration.ofMinutes(2)
+ );
+
+ assertThat(client).isInstanceOf(XrplClient.class);
+ }
+
@Test
public void submitSingleSignedTransaction() {
BcSignatureService bcSignatureService = new BcSignatureService();