Skip to content
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
220 changes: 143 additions & 77 deletions src/main/java/io/ipinfo/api/IPinfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,11 @@
import io.ipinfo.api.model.ASNResponse;
import io.ipinfo.api.model.IPResponse;
import io.ipinfo.api.model.MapResponse;
import io.ipinfo.api.model.ResproxyResponse;
import io.ipinfo.api.request.ASNRequest;
import io.ipinfo.api.request.IPRequest;
import io.ipinfo.api.request.MapRequest;
import okhttp3.*;

import javax.annotation.ParametersAreNonnullByDefault;
import io.ipinfo.api.request.ResproxyRequest;
import java.io.IOException;
import java.lang.reflect.Type;
import java.time.Duration;
Expand All @@ -26,15 +25,19 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import javax.annotation.ParametersAreNonnullByDefault;
import okhttp3.*;

public class IPinfo {

private static final int batchMaxSize = 1000;
private static final int batchReqTimeoutDefault = 5;
private static final BatchReqOpts defaultBatchReqOpts = new BatchReqOpts.Builder()
private static final BatchReqOpts defaultBatchReqOpts =
new BatchReqOpts.Builder()
.setBatchSize(batchMaxSize)
.setTimeoutPerBatch(batchReqTimeoutDefault)
.build();
private final static Gson gson = new Gson();
private static final Gson gson = new Gson();

private final OkHttpClient client;
private final Context context;
Expand All @@ -49,7 +52,9 @@ public class IPinfo {
}

public static void main(String... args) {
System.out.println("This library is not meant to be run as a standalone jar.");
System.out.println(
"This library is not meant to be run as a standalone jar."
);
System.exit(0);
}

Expand All @@ -61,7 +66,7 @@ public static void main(String... args) {
* @throws RateLimitedException an exception when your api key has been rate limited.
*/
public IPResponse lookupIP(String ip) throws RateLimitedException {
IPResponse response = (IPResponse)cache.get(cacheKey(ip));
IPResponse response = (IPResponse) cache.get(cacheKey(ip));
if (response != null) {
return response;
}
Expand All @@ -81,7 +86,7 @@ public IPResponse lookupIP(String ip) throws RateLimitedException {
* @throws RateLimitedException an exception when your api key has been rate limited.
*/
public ASNResponse lookupASN(String asn) throws RateLimitedException {
ASNResponse response = (ASNResponse)cache.get(cacheKey(asn));
ASNResponse response = (ASNResponse) cache.get(cacheKey(asn));
if (response != null) {
return response;
}
Expand All @@ -93,6 +98,29 @@ public ASNResponse lookupASN(String asn) throws RateLimitedException {
return response;
}

/**
* Lookup residential proxy information using the IP.
*
* @param ip the ip string to lookup - accepts both ipv4 and ipv6.
* @return ResproxyResponse response from the api.
* @throws RateLimitedException an exception when your api key has been rate limited.
*/
public ResproxyResponse lookupResproxy(String ip)
throws RateLimitedException {
String cacheKeyStr = "resproxy:" + ip;
ResproxyResponse response = (ResproxyResponse) cache.get(
cacheKey(cacheKeyStr)
);
if (response != null) {
return response;
}

response = new ResproxyRequest(client, token, ip).handle();

cache.set(cacheKey(cacheKeyStr), response);
return response;
}

/**
* Get a map of a list of IPs.
*
Expand All @@ -112,9 +140,8 @@ public String getMap(List<String> ips) throws RateLimitedException {
* @return the result where each URL is the key and the value is the data for that URL.
* @throws RateLimitedException an exception when your API key has been rate limited.
*/
public ConcurrentHashMap<String, Object> getBatch(
List<String> urls
) throws RateLimitedException {
public ConcurrentHashMap<String, Object> getBatch(List<String> urls)
throws RateLimitedException {
return this.getBatchGeneric(urls, defaultBatchReqOpts);
}

Expand All @@ -127,8 +154,8 @@ public ConcurrentHashMap<String, Object> getBatch(
* @throws RateLimitedException an exception when your API key has been rate limited.
*/
public ConcurrentHashMap<String, Object> getBatch(
List<String> urls,
BatchReqOpts opts
List<String> urls,
BatchReqOpts opts
) throws RateLimitedException {
return this.getBatchGeneric(urls, opts);
}
Expand All @@ -140,10 +167,11 @@ public ConcurrentHashMap<String, Object> getBatch(
* @return the result where each IP is the key and the value is the data for that IP.
* @throws RateLimitedException an exception when your API key has been rate limited.
*/
public ConcurrentHashMap<String, IPResponse> getBatchIps(
List<String> ips
) throws RateLimitedException {
return new ConcurrentHashMap(this.getBatchGeneric(ips, defaultBatchReqOpts));
public ConcurrentHashMap<String, IPResponse> getBatchIps(List<String> ips)
throws RateLimitedException {
return new ConcurrentHashMap(
this.getBatchGeneric(ips, defaultBatchReqOpts)
);
}

/**
Expand All @@ -155,8 +183,8 @@ public ConcurrentHashMap<String, IPResponse> getBatchIps(
* @throws RateLimitedException an exception when your API key has been rate limited.
*/
public ConcurrentHashMap<String, IPResponse> getBatchIps(
List<String> ips,
BatchReqOpts opts
List<String> ips,
BatchReqOpts opts
) throws RateLimitedException {
return new ConcurrentHashMap(this.getBatchGeneric(ips, opts));
}
Expand All @@ -169,9 +197,11 @@ public ConcurrentHashMap<String, IPResponse> getBatchIps(
* @throws RateLimitedException an exception when your API key has been rate limited.
*/
public ConcurrentHashMap<String, ASNResponse> getBatchAsns(
List<String> asns
List<String> asns
) throws RateLimitedException {
return new ConcurrentHashMap(this.getBatchGeneric(asns, defaultBatchReqOpts));
return new ConcurrentHashMap(
this.getBatchGeneric(asns, defaultBatchReqOpts)
);
}

/**
Expand All @@ -183,15 +213,15 @@ public ConcurrentHashMap<String, ASNResponse> getBatchAsns(
* @throws RateLimitedException an exception when your API key has been rate limited.
*/
public ConcurrentHashMap<String, ASNResponse> getBatchAsns(
List<String> asns,
BatchReqOpts opts
List<String> asns,
BatchReqOpts opts
) throws RateLimitedException {
return new ConcurrentHashMap(this.getBatchGeneric(asns, opts));
}

private ConcurrentHashMap<String, Object> getBatchGeneric(
List<String> urls,
BatchReqOpts opts
List<String> urls,
BatchReqOpts opts
) throws RateLimitedException {
int batchSize;
int timeoutPerBatch;
Expand All @@ -201,7 +231,7 @@ private ConcurrentHashMap<String, Object> getBatchGeneric(
// if the cache is available, filter out URLs already cached.
result = new ConcurrentHashMap<>(urls.size());
if (this.cache != null) {
lookupUrls = new ArrayList<>(urls.size()/2);
lookupUrls = new ArrayList<>(urls.size() / 2);
for (String url : urls) {
Object val = cache.get(cacheKey(url));
if (val != null) {
Expand Down Expand Up @@ -244,12 +274,14 @@ private ConcurrentHashMap<String, Object> getBatchGeneric(

// prepare latch & common request.
// each request, when complete, will countdown the latch.
CountDownLatch latch = new CountDownLatch((int)Math.ceil(lookupUrls.size()/1000.0));
CountDownLatch latch = new CountDownLatch(
(int) Math.ceil(lookupUrls.size() / 1000.0)
);
Request.Builder reqCommon = new Request.Builder()
.url(postUrl)
.addHeader("Content-Type", "application/json")
.addHeader("Authorization", Credentials.basic(token, ""))
.addHeader("User-Agent", "IPinfoClient/Java/3.2.0");
.url(postUrl)
.addHeader("Content-Type", "application/json")
.addHeader("Authorization", Credentials.basic(token, ""))
.addHeader("User-Agent", "IPinfoClient/Java/3.2.0");

for (int i = 0; i < lookupUrls.size(); i += batchSize) {
// create chunk.
Expand All @@ -263,57 +295,83 @@ private ConcurrentHashMap<String, Object> getBatchGeneric(
String urlListJson = gson.toJson(urlsChunk);
RequestBody requestBody = RequestBody.create(null, urlListJson);
Request req = reqCommon.post(requestBody).build();
OkHttpClient chunkClient = client.newBuilder()
.connectTimeout(timeoutPerBatch, TimeUnit.SECONDS)
.readTimeout(timeoutPerBatch, TimeUnit.SECONDS)
.build();
chunkClient.newCall(req).enqueue(new Callback() {
@Override
@ParametersAreNonnullByDefault
public void onFailure(Call call, IOException e) {
latch.countDown();
}

@Override
@ParametersAreNonnullByDefault
public void onResponse(Call call, Response response) throws IOException {
if (response.body() == null || response.code() == 429) {
return;
}
OkHttpClient chunkClient = client
.newBuilder()
.connectTimeout(timeoutPerBatch, TimeUnit.SECONDS)
.readTimeout(timeoutPerBatch, TimeUnit.SECONDS)
.build();
chunkClient
.newCall(req)
.enqueue(
new Callback() {
@Override
@ParametersAreNonnullByDefault
public void onFailure(Call call, IOException e) {
latch.countDown();
}

Type respType = new TypeToken<HashMap<String, Object>>() {}.getType();
HashMap<String, Object> localResult
= gson.fromJson(response.body().string(), respType);
localResult.forEach(new BiConsumer<String, Object>() {
@Override
public void accept(String k, Object v) {
if (k.startsWith("AS")) {
String vStr = gson.toJson(v);
ASNResponse vCasted = gson.fromJson(vStr, ASNResponse.class);
vCasted.setContext(context);
result.put(k, vCasted);
} else if (InetAddresses.isInetAddress(k)) {
String vStr = gson.toJson(v);
IPResponse vCasted = gson.fromJson(vStr, IPResponse.class);
vCasted.setContext(context);
result.put(k, vCasted);
} else {
result.put(k, v);
@ParametersAreNonnullByDefault
public void onResponse(Call call, Response response)
throws IOException {
if (
response.body() == null ||
response.code() == 429
) {
return;
}
}
});

latch.countDown();
}
});
Type respType = new TypeToken<
HashMap<String, Object>
>() {}.getType();
HashMap<String, Object> localResult = gson.fromJson(
response.body().string(),
respType
);
localResult.forEach(
new BiConsumer<String, Object>() {
@Override
public void accept(String k, Object v) {
if (k.startsWith("AS")) {
String vStr = gson.toJson(v);
ASNResponse vCasted = gson.fromJson(
vStr,
ASNResponse.class
);
vCasted.setContext(context);
result.put(k, vCasted);
} else if (
InetAddresses.isInetAddress(k)
) {
String vStr = gson.toJson(v);
IPResponse vCasted = gson.fromJson(
vStr,
IPResponse.class
);
vCasted.setContext(context);
result.put(k, vCasted);
} else {
result.put(k, v);
}
}
}
);

latch.countDown();
}
}
);
}

// wait for all requests to finish.
try {
if (opts.timeoutTotal == 0) {
latch.await();
} else {
boolean success = latch.await(opts.timeoutTotal, TimeUnit.SECONDS);
boolean success = latch.await(
opts.timeoutTotal,
TimeUnit.SECONDS
);
if (!success) {
if (result.size() == 0) {
return null;
Expand Down Expand Up @@ -350,10 +408,11 @@ public void accept(String k, Object v) {
* @return the versioned cache key.
*/
public static String cacheKey(String k) {
return k+":1";
return k + ":1";
}

public static class Builder {

private OkHttpClient client = new OkHttpClient.Builder().build();
private String token = "";
private Cache cache = new SimpleCache(Duration.ofDays(1));
Expand All @@ -379,16 +438,17 @@ public IPinfo build() {
}

public static class BatchReqOpts {

public final int batchSize;
public final int timeoutPerBatch;
public final int timeoutTotal;
public final boolean filter;

public BatchReqOpts(
int batchSize,
int timeoutPerBatch,
int timeoutTotal,
boolean filter
int batchSize,
int timeoutPerBatch,
int timeoutTotal,
boolean filter
) {
this.batchSize = batchSize;
this.timeoutPerBatch = timeoutPerBatch;
Expand All @@ -397,6 +457,7 @@ public BatchReqOpts(
}

public static class Builder {

private int batchSize = 1000;
private int timeoutPerBatch = 5;
private int timeoutTotal = 0;
Expand Down Expand Up @@ -462,7 +523,12 @@ public Builder setFilter(boolean filter) {
}

public IPinfo.BatchReqOpts build() {
return new IPinfo.BatchReqOpts(batchSize, timeoutPerBatch, timeoutTotal, filter);
return new IPinfo.BatchReqOpts(
batchSize,
timeoutPerBatch,
timeoutTotal,
filter
);
}
}
}
Expand Down
Loading