Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#149: Allow HTTP requests with data compression enhancement #150

Merged
merged 9 commits into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
<details open>
<summary>Supported REST Services</summary>
<table>
Expand Down Expand Up @@ -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 |
Expand All @@ -351,13 +352,13 @@ Resource and maintenance requirements for Cardano blockchain components (e.g. ca
<dependency>
<groupId>io.github.cardano-community</groupId>
<artifactId>koios-java-client</artifactId>
<version>1.18.0</version>
<version>1.18.1</version>
</dependency>
```

- 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)
Expand Down Expand Up @@ -424,9 +425,10 @@ Result<List<TxHash>> 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
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>io.github.cardano-community</groupId>
<artifactId>koios-java-client</artifactId>
<version>1.18.0</version>
<version>1.18.1</version>
<name>${project.groupId}:${project.artifactId}</name>
<description>Koios Java Client is a Java REST Client library which allows interacting with Koios Server Instances using Java Objects</description>
<url>https://github.com/cardano-community/koios-java-client</url>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<AddressInfo> getAddressInformation(List<String> addressList, SortType utxoSortType, Options options) throws ApiException;
Result<List<AddressInfo>> getAddressInformation(List<String> addressList, SortType utxoSortType, Options options) throws ApiException;

/**
* Address UTXOs
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -40,25 +40,37 @@ public AddressServiceImpl(String baseUrl, String apiToken) {

@Override
public Result<AddressInfo> getAddressInformation(String address) throws ApiException {
return getAddressInformation(List.of(address), SortType.DESC, null);
validateBech32(address);
Call<List<AddressInfo>> call = addressApi.getAddressInformation(buildBody("_addresses", List.of(address), null), optionsToParamMap(Options.EMPTY));
try {
Response<List<AddressInfo>> response = (Response) execute(call);
Result<AddressInfo> 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<AddressInfo> getAddressInformation(List<String> addressList, SortType utxoSortType, Options options) throws ApiException {
public Result<List<AddressInfo>> getAddressInformation(List<String> addressList, SortType utxoSortType, Options options) throws ApiException {
for (String address : addressList) {
validateBech32(address);
}
Call<List<AddressInfo>> call = addressApi.getAddressInformation(buildBody("_addresses", addressList, null), optionsToParamMap(options));
try {
Response<List<AddressInfo>> response = (Response) execute(call);
Result<AddressInfo> result = processResponseGetOne(response);
Result<List<AddressInfo>> 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) {
Expand Down
49 changes: 29 additions & 20 deletions src/main/java/rest/koios/client/backend/api/base/BaseService.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand All @@ -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);
Expand All @@ -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 <T> Result<T> processResponseGetOne(Response<List<T>> response) throws IOException {
if (response.isSuccessful()) {
if (response.body() != null && !response.body().isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -39,6 +40,16 @@ void getAddressInformationTest() throws ApiException {
log.info(addressInformationResult.getValue().toString());
}

@Test
void getAddressInformationTest2() throws ApiException {
List<String> addresses = List.of("addr1qy2jt0qpqz2z2z9zx5w4xemekkce7yderz53kjue53lpqv90lkfa9sgrfjuz6uvt4uqtrqhl2kj0a9lnr9ndzutx32gqleeckv",
"addr1q9xvgr4ehvu5k5tmaly7ugpnvekpqvnxj8xy50pa7kyetlnhel389pa4rnq6fmkzwsaynmw0mnldhlmchn2sfd589fgsz9dd0y");
Result<List<AddressInfo>> 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";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -39,6 +40,16 @@ void getAddressInformationTest() throws ApiException {
log.info(addressInformationResult.getValue().toString());
}

@Test
void getAddressInformationTest2() throws ApiException {
List<String> addresses = List.of("addr_test1vzpwq95z3xyum8vqndgdd9mdnmafh3djcxnc6jemlgdmswcve6tkw",
"addr_test1vpfwv0ezc5g8a4mkku8hhy3y3vp92t7s3ul8g778g5yegsgalc6gc");
Result<List<AddressInfo>> 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";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -38,6 +39,16 @@ void getAddressInformationTest() throws ApiException {
log.info(addressInformationResult.getValue().toString());
}

@Test
void getAddressInformationTest2() throws ApiException {
List<String> addresses = List.of("addr_test1vpfwv0ezc5g8a4mkku8hhy3y3vp92t7s3ul8g778g5yegsgalc6gc",
"addr_test1vqneq3v0dqh3x3muv6ee3lt8e5729xymnxuavx6tndcjc2cv24ef9");
Result<List<AddressInfo>> 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";
Expand Down
Loading