diff --git a/README.md b/README.md index 1168c1d..4659f54 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ Resource and maintenance requirements for Cardano blockchain components (e.g. ca - Sorting Supported - API Token Supported - Inner Retry Mechanism upon Timeouts +- HTTP GZIP Compression Supported
Supported REST Services @@ -334,7 +335,7 @@ Resource and maintenance requirements for Cardano blockchain components (e.g. ca | Koios Instance | Koios Java Client | |:--------------:|:-----------------:| -| 1.1.0 | 1.18.0 | +| 1.1.0 | 1.18.1 | | 1.0.10 | 1.17.3 | | 1.0.9 | 1.16.3 | | 1.0.8 | 1.15.2 | @@ -351,13 +352,13 @@ Resource and maintenance requirements for Cardano blockchain components (e.g. ca io.github.cardano-community koios-java-client - 1.18.0 + 1.18.1 ``` - For Gradle, add the following dependency to build.gradle ``` -compile group: 'io.github.cardano-community', name: 'koios-java-client', version: '1.18.0' +compile group: 'io.github.cardano-community', name: 'koios-java-client', version: '1.18.1' ``` ### Get Koios Backend Service (No API Token) @@ -424,9 +425,10 @@ Result> transactionsResult = addressService.getAddressTransactions( |------------------------------------|:-------:|----------------------------------------------------------------|:-------:| | KOIOS_JAVA_LIB_LOGGING | boolean | Toggle Logging | false | | KOIOS_JAVA_LIB_RETRIES_COUNT | integer | Sets the max retry count upon request timeout | 5 | -| KOIOS_JAVA_LIB_READ_TIMEOUT_SEC | integer | Sets the default read timeout for new connections (seconds) | 60 | -| KOIOS_JAVA_LIB_CONNECT_TIMEOUT_SEC | integer | Sets the default connect timeout for new connections (seconds) | 60 | +| KOIOS_JAVA_LIB_READ_TIMEOUT_SEC | integer | Sets the default read timeout for new connections (seconds) | 300 | +| KOIOS_JAVA_LIB_CONNECT_TIMEOUT_SEC | integer | Sets the default connect timeout for new connections (seconds) | 300 | | KOIOS_JAVA_LIB_RETRY_ON_TIMEOUT | boolean | Sets whether to retry upon request timeout | true | +| KOIOS_JAVA_LIB_GZIP_COMPRESSION | boolean | Sets whether to use GZIP Compression | true | ## Clone & Build with Maven ```shell diff --git a/pom.xml b/pom.xml index e1c15af..b15702a 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 io.github.cardano-community koios-java-client - 1.18.0 + 1.18.1 ${project.groupId}:${project.artifactId} Koios Java Client is a Java REST Client library which allows interacting with Koios Server Instances using Java Objects https://github.com/cardano-community/koios-java-client diff --git a/src/main/java/rest/koios/client/backend/api/address/AddressService.java b/src/main/java/rest/koios/client/backend/api/address/AddressService.java index 6bd3bb2..ebddb3e 100644 --- a/src/main/java/rest/koios/client/backend/api/address/AddressService.java +++ b/src/main/java/rest/koios/client/backend/api/address/AddressService.java @@ -42,7 +42,7 @@ public interface AddressService { * @return Result of Type List of {@link AddressInfo} with Balance, Stake Address, UTxO set associated with the specified address. * @throws ApiException if an error occurs while attempting to invoke the API */ - Result getAddressInformation(List addressList, SortType utxoSortType, Options options) throws ApiException; + Result> getAddressInformation(List addressList, SortType utxoSortType, Options options) throws ApiException; /** * Address UTXOs diff --git a/src/main/java/rest/koios/client/backend/api/address/impl/AddressServiceImpl.java b/src/main/java/rest/koios/client/backend/api/address/impl/AddressServiceImpl.java index 4c8d783..6ae3b77 100644 --- a/src/main/java/rest/koios/client/backend/api/address/impl/AddressServiceImpl.java +++ b/src/main/java/rest/koios/client/backend/api/address/impl/AddressServiceImpl.java @@ -1,14 +1,14 @@ package rest.koios.client.backend.api.address.impl; -import rest.koios.client.backend.api.address.api.AddressApi; import rest.koios.client.backend.api.address.AddressService; +import rest.koios.client.backend.api.address.api.AddressApi; import rest.koios.client.backend.api.address.model.AddressAsset; import rest.koios.client.backend.api.address.model.AddressInfo; import rest.koios.client.backend.api.base.BaseService; import rest.koios.client.backend.api.base.Result; +import rest.koios.client.backend.api.base.common.TxHash; import rest.koios.client.backend.api.base.common.UTxO; import rest.koios.client.backend.api.base.exception.ApiException; -import rest.koios.client.backend.api.base.common.TxHash; import rest.koios.client.backend.factory.options.Options; import rest.koios.client.backend.factory.options.SortType; import retrofit2.Call; @@ -40,25 +40,37 @@ public AddressServiceImpl(String baseUrl, String apiToken) { @Override public Result getAddressInformation(String address) throws ApiException { - return getAddressInformation(List.of(address), SortType.DESC, null); + validateBech32(address); + Call> call = addressApi.getAddressInformation(buildBody("_addresses", List.of(address), null), optionsToParamMap(Options.EMPTY)); + try { + Response> response = (Response) execute(call); + Result result = processResponseGetOne(response); + if (result.isSuccessful()) { + result.getValue().setUtxoSet(new TreeSet<>(result.getValue().getUtxoSet())); + } + return result; + } catch (IOException e) { + throw new ApiException(e.getMessage(), e); + } } @Override - public Result getAddressInformation(List addressList, SortType utxoSortType, Options options) throws ApiException { + public Result> getAddressInformation(List addressList, SortType utxoSortType, Options options) throws ApiException { for (String address : addressList) { validateBech32(address); } Call> call = addressApi.getAddressInformation(buildBody("_addresses", addressList, null), optionsToParamMap(options)); try { Response> response = (Response) execute(call); - Result result = processResponseGetOne(response); + Result> result = processResponse(response); if (result.isSuccessful()) { - //Sort - if (utxoSortType == SortType.DESC) { - result.getValue().setUtxoSet(new TreeSet<>(result.getValue().getUtxoSet()).descendingSet()); - } else { - result.getValue().setUtxoSet(new TreeSet<>(result.getValue().getUtxoSet())); - } + result.getValue().forEach(addressInfo -> { + if (utxoSortType == SortType.DESC) { + addressInfo.setUtxoSet(new TreeSet<>(addressInfo.getUtxoSet()).descendingSet()); + } else { + addressInfo.setUtxoSet(new TreeSet<>(addressInfo.getUtxoSet())); + } + }); } return result; } catch (IOException e) { diff --git a/src/main/java/rest/koios/client/backend/api/base/BaseService.java b/src/main/java/rest/koios/client/backend/api/base/BaseService.java index a1d479a..79aefd1 100644 --- a/src/main/java/rest/koios/client/backend/api/base/BaseService.java +++ b/src/main/java/rest/koios/client/backend/api/base/BaseService.java @@ -10,6 +10,7 @@ import okhttp3.logging.HttpLoggingInterceptor; import org.jetbrains.annotations.NotNull; import rest.koios.client.backend.api.base.exception.ApiException; +import rest.koios.client.backend.api.base.interceptor.GzipInterceptor; import rest.koios.client.backend.factory.options.Options; import rest.koios.client.utils.Bech32Util; import retrofit2.Call; @@ -37,6 +38,9 @@ public class BaseService { private static final int SLEEP_TIME_MILLIS = 2000; private boolean retryOnTimeout = true; private final String apiToken; + private int readTimeoutSec = 300; + private int connectTimeoutSec = 300; + private boolean gzipCompression = true; /** * Base Service Constructor @@ -55,8 +59,23 @@ public BaseService(String baseUrl) { */ public BaseService(String baseUrl, String apiToken) { this.apiToken = apiToken; - int readTimeoutSec = getReadTimeoutSec(); - int connectTimeoutSec = getConnectTimeoutSec(); + + String strReadTimeoutSec = System.getenv("KOIOS_JAVA_LIB_READ_TIMEOUT_SEC"); + if (strReadTimeoutSec != null && !strReadTimeoutSec.isEmpty()) { + int readTimeoutSec = Integer.parseInt(strReadTimeoutSec); + if (readTimeoutSec >= 1) { + this.readTimeoutSec = readTimeoutSec; + } + } + + String strConnectTimeoutSec = System.getenv("KOIOS_JAVA_LIB_CONNECT_TIMEOUT_SEC"); + if (strConnectTimeoutSec != null && !strConnectTimeoutSec.isEmpty()) { + int connectTimeoutSec = Integer.parseInt(strConnectTimeoutSec); + if (connectTimeoutSec >= 1) { + this.connectTimeoutSec = connectTimeoutSec; + } + } + boolean logging = Boolean.parseBoolean(System.getenv("KOIOS_JAVA_LIB_LOGGING")); OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder(); okHttpClientBuilder.readTimeout(readTimeoutSec, TimeUnit.SECONDS) @@ -81,6 +100,14 @@ public okhttp3.Response intercept(@NotNull Chain chain) throws IOException { } }); } + + if (System.getenv("KOIOS_JAVA_LIB_GZIP_COMPRESSION") != null) { + gzipCompression = Boolean.parseBoolean(System.getenv("KOIOS_JAVA_LIB_GZIP_COMPRESSION")); + } + if (gzipCompression) { + okHttpClientBuilder.addInterceptor(new GzipInterceptor()); + } + String strRetries = System.getenv("KOIOS_JAVA_LIB_RETRIES_COUNT"); if (strRetries != null && !strRetries.isEmpty()) { retriesCount = Math.max(Integer.parseInt(strRetries), 1); @@ -95,24 +122,6 @@ public okhttp3.Response intercept(@NotNull Chain chain) throws IOException { .create(objectMapper)).build(); } - private int getReadTimeoutSec() { - int readTimeoutSec = 60; - String strReadTimeoutSec = System.getenv("KOIOS_JAVA_LIB_READ_TIMEOUT_SEC"); - if (strReadTimeoutSec != null && !strReadTimeoutSec.isEmpty()) { - readTimeoutSec = Integer.parseInt(strReadTimeoutSec); - } - return readTimeoutSec >= 1 ? readTimeoutSec : 60; - } - - private int getConnectTimeoutSec() { - int connectTimeoutSec = 60; - String strReadTimeoutSec = System.getenv("KOIOS_JAVA_LIB_CONNECT_TIMEOUT_SEC"); - if (strReadTimeoutSec != null && !strReadTimeoutSec.isEmpty()) { - connectTimeoutSec = Integer.parseInt(strReadTimeoutSec); - } - return connectTimeoutSec >= 1 ? connectTimeoutSec : 60; - } - protected Result processResponseGetOne(Response> response) throws IOException { if (response.isSuccessful()) { if (response.body() != null && !response.body().isEmpty()) { diff --git a/src/main/java/rest/koios/client/backend/api/base/interceptor/GzipInterceptor.java b/src/main/java/rest/koios/client/backend/api/base/interceptor/GzipInterceptor.java new file mode 100644 index 0000000..747b2f1 --- /dev/null +++ b/src/main/java/rest/koios/client/backend/api/base/interceptor/GzipInterceptor.java @@ -0,0 +1,57 @@ +package rest.koios.client.backend.api.base.interceptor; + + +import java.io.IOException; +import java.util.Objects; + +import okhttp3.Headers; +import okhttp3.Interceptor; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; +import okio.GzipSource; +import okio.Okio; +import org.jetbrains.annotations.NotNull; + +public class GzipInterceptor implements Interceptor { + @NotNull + @Override + public Response intercept(Chain chain) throws IOException { + Request.Builder newRequest = chain.request().newBuilder(); + newRequest.addHeader("Accept-Encoding", "deflate, gzip"); + Response response = chain.proceed(newRequest.build()); + + if (isGzipped(response)) { + return unzip(response); + } else { + return response; + } + } + + private Response unzip(final Response response) throws IOException { + + if (response.body() == null) { + return response; + } + + GzipSource gzipSource = new GzipSource(response.body().source()); + String bodyString = Okio.buffer(gzipSource).readUtf8(); + + ResponseBody responseBody = ResponseBody.create(bodyString, response.body().contentType()); + + Headers strippedHeaders = response.headers().newBuilder() + .removeAll("Content-Encoding") + .removeAll("Content-Length") + .build(); + return response.newBuilder() + .headers(strippedHeaders) + .body(responseBody) + .message(response.message()) + .build(); + + } + + private Boolean isGzipped(Response response) { + return response.header("Content-Encoding") != null && Objects.equals(response.header("Content-Encoding"), "gzip"); + } +} \ No newline at end of file diff --git a/src/test/java/rest/koios/client/backend/api/address/AddressServiceMainnetIntegrationTest.java b/src/test/java/rest/koios/client/backend/api/address/AddressServiceMainnetIntegrationTest.java index d5b96d1..67cf162 100644 --- a/src/test/java/rest/koios/client/backend/api/address/AddressServiceMainnetIntegrationTest.java +++ b/src/test/java/rest/koios/client/backend/api/address/AddressServiceMainnetIntegrationTest.java @@ -13,6 +13,7 @@ import rest.koios.client.backend.api.base.exception.ApiException; import rest.koios.client.backend.factory.BackendFactory; import rest.koios.client.backend.factory.options.Options; +import rest.koios.client.backend.factory.options.SortType; import java.util.List; @@ -39,6 +40,16 @@ void getAddressInformationTest() throws ApiException { log.info(addressInformationResult.getValue().toString()); } + @Test + void getAddressInformationTest2() throws ApiException { + List addresses = List.of("addr1qy2jt0qpqz2z2z9zx5w4xemekkce7yderz53kjue53lpqv90lkfa9sgrfjuz6uvt4uqtrqhl2kj0a9lnr9ndzutx32gqleeckv", + "addr1q9xvgr4ehvu5k5tmaly7ugpnvekpqvnxj8xy50pa7kyetlnhel389pa4rnq6fmkzwsaynmw0mnldhlmchn2sfd589fgsz9dd0y"); + Result> addressInformationResult = addressService.getAddressInformation(addresses, SortType.ASC, Options.EMPTY); + Assertions.assertTrue(addressInformationResult.isSuccessful()); + Assertions.assertNotNull(addressInformationResult.getValue()); + log.info(addressInformationResult.getValue().toString()); + } + @Test void getAddressInformationBadRequestTest() { String address = "a123sd"; diff --git a/src/test/java/rest/koios/client/backend/api/address/AddressServicePreprodIntegrationTest.java b/src/test/java/rest/koios/client/backend/api/address/AddressServicePreprodIntegrationTest.java index a5639b9..4deeef7 100644 --- a/src/test/java/rest/koios/client/backend/api/address/AddressServicePreprodIntegrationTest.java +++ b/src/test/java/rest/koios/client/backend/api/address/AddressServicePreprodIntegrationTest.java @@ -13,6 +13,7 @@ import rest.koios.client.backend.api.base.common.TxHash; import rest.koios.client.backend.factory.BackendFactory; import rest.koios.client.backend.factory.options.Options; +import rest.koios.client.backend.factory.options.SortType; import java.util.List; @@ -39,6 +40,16 @@ void getAddressInformationTest() throws ApiException { log.info(addressInformationResult.getValue().toString()); } + @Test + void getAddressInformationTest2() throws ApiException { + List addresses = List.of("addr_test1vzpwq95z3xyum8vqndgdd9mdnmafh3djcxnc6jemlgdmswcve6tkw", + "addr_test1vpfwv0ezc5g8a4mkku8hhy3y3vp92t7s3ul8g778g5yegsgalc6gc"); + Result> addressInformationResult = addressService.getAddressInformation(addresses, SortType.ASC, Options.EMPTY); + Assertions.assertTrue(addressInformationResult.isSuccessful()); + Assertions.assertNotNull(addressInformationResult.getValue()); + log.info(addressInformationResult.getValue().toString()); + } + @Test void getAddressInformationBadRequestTest() { String address = "a123sd"; diff --git a/src/test/java/rest/koios/client/backend/api/address/AddressServicePreviewIntegrationTest.java b/src/test/java/rest/koios/client/backend/api/address/AddressServicePreviewIntegrationTest.java index b2415b3..93a20aa 100644 --- a/src/test/java/rest/koios/client/backend/api/address/AddressServicePreviewIntegrationTest.java +++ b/src/test/java/rest/koios/client/backend/api/address/AddressServicePreviewIntegrationTest.java @@ -13,6 +13,7 @@ import rest.koios.client.backend.api.base.exception.ApiException; import rest.koios.client.backend.factory.BackendFactory; import rest.koios.client.backend.factory.options.Options; +import rest.koios.client.backend.factory.options.SortType; import java.util.List; @@ -38,6 +39,16 @@ void getAddressInformationTest() throws ApiException { log.info(addressInformationResult.getValue().toString()); } + @Test + void getAddressInformationTest2() throws ApiException { + List addresses = List.of("addr_test1vpfwv0ezc5g8a4mkku8hhy3y3vp92t7s3ul8g778g5yegsgalc6gc", + "addr_test1vqneq3v0dqh3x3muv6ee3lt8e5729xymnxuavx6tndcjc2cv24ef9"); + Result> addressInformationResult = addressService.getAddressInformation(addresses, SortType.ASC, Options.EMPTY); + Assertions.assertTrue(addressInformationResult.isSuccessful()); + Assertions.assertNotNull(addressInformationResult.getValue()); + log.info(addressInformationResult.getValue().toString()); + } + @Test void getAddressInformationBadRequestTest() { String address = "a123sd";