Skip to content

Commit 260899b

Browse files
committed
[3.0.0-SNAPSHOT]
Added JdkEthHttpClient gzip/deflate protocol support Added EthScanAPIBuilder key required
1 parent 8dbcc82 commit 260899b

File tree

6 files changed

+59
-25
lines changed

6 files changed

+59
-25
lines changed

src/main/java/io/goodforgod/api/etherscan/BasicProvider.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,9 @@ protected <T> T getResponse(String urlParameters, Class<T> tClass) {
129129

130130
protected <T> T getResponse(String urlParameters, Class<T> tClass, int retryCount) {
131131
try {
132+
System.out.println("URL - " + URI.create(baseUrl + module + urlParameters));
132133
EthResponse response = getResponse(urlParameters);
134+
System.out.println("Response - " + new String(response.body(), StandardCharsets.UTF_8));
133135
return convert(response.body(), tClass);
134136
} catch (Exception e) {
135137
if (retryCount < retryCountLimit) {

src/main/java/io/goodforgod/api/etherscan/EthScanAPIBuilder.java

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import java.io.IOException;
1313
import java.io.InputStreamReader;
1414
import java.nio.charset.StandardCharsets;
15+
import java.util.Objects;
1516
import java.util.function.Supplier;
1617
import org.jetbrains.annotations.NotNull;
1718

@@ -22,12 +23,11 @@
2223
public class EthScanAPIBuilder implements EtherScanAPI.Builder {
2324

2425
private static final Supplier<EthHttpClient> DEFAULT_SUPPLIER = JdkEthHttpClient::new;
25-
private static final String DEFAULT_KEY = "YourApiKeyToken";
2626

2727
private final Gson gson = new GsonConfiguration().builder().create();
2828

2929
private int retryCountOnLimitReach = 0;
30-
private String apiKey = DEFAULT_KEY;
30+
private String apiKey;
3131
private RequestQueueManager queueManager;
3232
private EthNetwork ethNetwork = EthNetworks.MAINNET;
3333
private Supplier<EthHttpClient> ethHttpClientSupplier = DEFAULT_SUPPLIER;
@@ -43,6 +43,10 @@ public class EthScanAPIBuilder implements EtherScanAPI.Builder {
4343
}
4444
};
4545

46+
public EthScanAPIBuilder(String apiKey) {
47+
this.apiKey = apiKey;
48+
}
49+
4650
@NotNull
4751
@Override
4852
public EtherScanAPI.Builder withApiKey(@NotNull String apiKey) {
@@ -101,13 +105,7 @@ public EtherScanAPI.Builder withRetryOnRateLimit(int maxRetryCount) {
101105
@Override
102106
public @NotNull EtherScanAPI build() {
103107
RequestQueueManager requestQueueManager;
104-
if (queueManager != null) {
105-
requestQueueManager = queueManager;
106-
} else if (DEFAULT_KEY.equals(apiKey)) {
107-
requestQueueManager = RequestQueueManager.anonymous();
108-
} else {
109-
requestQueueManager = RequestQueueManager.planFree();
110-
}
108+
requestQueueManager = Objects.requireNonNullElseGet(queueManager, RequestQueueManager::planFree);
111109

112110
return new EtherScanAPIProvider(apiKey, ethNetwork, requestQueueManager, ethHttpClientSupplier.get(),
113111
converterSupplier.get(), retryCountOnLimitReach);

src/main/java/io/goodforgod/api/etherscan/EtherScanAPI.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ public interface EtherScanAPI extends AutoCloseable {
4040
GasTrackerAPI gasTracker();
4141

4242
@NotNull
43-
static Builder builder() {
44-
return new EthScanAPIBuilder();
43+
static Builder builder(@NotNull String key) {
44+
return new EthScanAPIBuilder(key);
4545
}
4646

4747
interface Builder {

src/main/java/io/goodforgod/api/etherscan/http/impl/JdkEthHttpClient.java

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,17 @@
55
import io.goodforgod.api.etherscan.http.EthHttpClient;
66
import io.goodforgod.api.etherscan.http.EthResponse;
77
import java.io.IOException;
8+
import java.io.InputStream;
9+
import java.io.UncheckedIOException;
810
import java.net.URI;
911
import java.net.http.HttpClient;
1012
import java.net.http.HttpConnectTimeoutException;
1113
import java.net.http.HttpRequest;
1214
import java.net.http.HttpResponse;
1315
import java.time.Duration;
14-
import java.util.HashMap;
15-
import java.util.List;
16-
import java.util.Map;
16+
import java.util.*;
17+
import java.util.zip.GZIPInputStream;
18+
import java.util.zip.InflaterInputStream;
1719
import org.jetbrains.annotations.ApiStatus.Internal;
1820
import org.jetbrains.annotations.NotNull;
1921

@@ -75,7 +77,9 @@ public EthResponse get(@NotNull URI uri) {
7577
headers.forEach(requestBuilder::header);
7678

7779
try {
78-
HttpResponse<byte[]> response = httpClient.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofByteArray());
80+
HttpResponse<InputStream> response = httpClient.send(requestBuilder.build(),
81+
HttpResponse.BodyHandlers.ofInputStream());
82+
byte[] bodyAsBytes = getDeflatedBytes(response);
7983
return new EthResponse() {
8084

8185
@Override
@@ -85,7 +89,7 @@ public int statusCode() {
8589

8690
@Override
8791
public byte[] body() {
88-
return response.body();
92+
return bodyAsBytes;
8993
}
9094

9195
@Override
@@ -115,7 +119,9 @@ public EthResponse post(@NotNull URI uri, byte[] body) {
115119
headers.forEach(requestBuilder::header);
116120

117121
try {
118-
HttpResponse<byte[]> response = httpClient.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofByteArray());
122+
HttpResponse<InputStream> response = httpClient.send(requestBuilder.build(),
123+
HttpResponse.BodyHandlers.ofInputStream());
124+
byte[] bodyAsBytes = getDeflatedBytes(response);
119125
return new EthResponse() {
120126

121127
@Override
@@ -125,7 +131,7 @@ public int statusCode() {
125131

126132
@Override
127133
public byte[] body() {
128-
return response.body();
134+
return bodyAsBytes;
129135
}
130136

131137
@Override
@@ -144,4 +150,28 @@ public byte[] body() {
144150
throw new EtherScanConnectionException("Etherscan HTTP server interrupt exception occurred: " + e.getMessage(), e);
145151
}
146152
}
153+
154+
private static byte[] getDeflatedBytes(HttpResponse<InputStream> response) {
155+
try {
156+
Optional<String> encoding = response.headers().firstValue("content-encoding");
157+
if (encoding.isEmpty()) {
158+
try (var is = response.body()) {
159+
return is.readAllBytes();
160+
}
161+
}
162+
163+
switch (encoding.get().strip().toLowerCase(Locale.ROOT)) {
164+
case "gzip":
165+
return new GZIPInputStream(response.body()).readAllBytes();
166+
case "deflate":
167+
return new InflaterInputStream(response.body()).readAllBytes();
168+
default:
169+
try (var is = response.body()) {
170+
return is.readAllBytes();
171+
}
172+
}
173+
} catch (IOException e) {
174+
throw new UncheckedIOException(e);
175+
}
176+
}
147177
}

src/test/java/io/goodforgod/api/etherscan/ApiRunner.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ public class ApiRunner extends Assertions {
2525
? RequestQueueManager.anonymous()
2626
: RequestQueueManager.planFree();
2727

28-
API = EtherScanAPI.builder()
29-
.withApiKey(ApiRunner.API_KEY)
28+
API = EtherScanAPI.builder(ApiRunner.API_KEY)
3029
.withNetwork(EthNetworks.MAINNET)
3130
.withQueue(queueManager)
3231
.withRetryOnRateLimit(5)
@@ -37,6 +36,10 @@ public static EtherScanAPI getApi() {
3736
return API;
3837
}
3938

39+
public static String getKey() {
40+
return API_KEY;
41+
}
42+
4043
@AfterAll
4144
public static void cleanup() throws Exception {
4245
API.close();

src/test/java/io/goodforgod/api/etherscan/EtherScanAPITests.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,25 +22,26 @@ class EtherScanAPITests extends ApiRunner {
2222
@Test
2323
void validKey() {
2424
String validKey = "YourKey";
25-
EtherScanAPI api = EtherScanAPI.builder().withApiKey(validKey).withNetwork(network).build();
25+
EtherScanAPI api = EtherScanAPI.builder(validKey).withApiKey(validKey).withNetwork(network).build();
2626
assertNotNull(api);
2727
}
2828

2929
@Test
3030
void emptyKey() {
31-
assertThrows(EtherScanKeyException.class, () -> EtherScanAPI.builder().withApiKey("").build());
31+
assertThrows(EtherScanKeyException.class, () -> EtherScanAPI.builder("someKey").withApiKey("").build());
3232
}
3333

3434
@Test
3535
void blankKey() {
3636
assertThrows(EtherScanKeyException.class,
37-
() -> EtherScanAPI.builder().withApiKey(" ").withNetwork(network).build());
37+
() -> EtherScanAPI.builder("someKey").withApiKey(" ").withNetwork(network).build());
3838
}
3939

4040
@Test
4141
void noTimeoutOnRead() {
4242
Supplier<EthHttpClient> supplier = () -> new UrlEthHttpClient(Duration.ofMillis(300));
43-
EtherScanAPI api = EtherScanAPI.builder().withNetwork(EthNetworks.MAINNET).withHttpClient(supplier).build();
43+
EtherScanAPI api = EtherScanAPI.builder(ApiRunner.getKey()).withNetwork(EthNetworks.MAINNET).withHttpClient(supplier)
44+
.build();
4445
Balance balance = api.account().balance("0xF318ABc9A5a92357c4Fea8d082dade4D43e780B7");
4546
assertNotNull(balance);
4647
}
@@ -67,7 +68,7 @@ void noTimeoutUnlimitedAwait() {
6768
void timeout() throws InterruptedException {
6869
TimeUnit.SECONDS.sleep(5);
6970
Supplier<EthHttpClient> supplier = () -> new UrlEthHttpClient(Duration.ofMillis(300), Duration.ofMillis(300));
70-
EtherScanAPI api = EtherScanAPI.builder()
71+
EtherScanAPI api = EtherScanAPI.builder(ApiRunner.getKey())
7172
.withNetwork(() -> URI.create("https://api-unknown.etherscan.io/api"))
7273
.withHttpClient(supplier)
7374
.build();

0 commit comments

Comments
 (0)