diff --git a/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindLocation.java b/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindLocation.java index a509c50..f896123 100644 --- a/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindLocation.java +++ b/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindLocation.java @@ -20,9 +20,9 @@ public final class MaxMindLocation { this.longitude = legacy.getDouble("longitude"); this.accuracyRadius = legacy.getInteger("accuracy_radius"); this.timeZone = legacy.getString("time_zone"); - this.populationDensity = legacy.getInteger("population_density"); - this.metroCode = legacy.getInteger("metro_code"); - this.averageIncome = legacy.getInteger("average_income"); + this.populationDensity = legacy.getInteger("population_density", -1); + this.metroCode = legacy.getInteger("metro_code", -1); // Metro codes are US only + this.averageIncome = legacy.getInteger("average_income", -1); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindPostal.java b/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindPostal.java index d6fd924..31247d9 100644 --- a/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindPostal.java +++ b/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindPostal.java @@ -12,6 +12,12 @@ public final class MaxMindPostal { public MaxMindPostal(Document legacy) { this.code = legacy.getString("code"); + + // Postal codes aren't guaranteed to exist for all areas + if (code == null) { + code = ""; + } + this.confidence = legacy.getInteger("confidence"); } diff --git a/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindSubdivision.java b/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindSubdivision.java index 80185f5..ae28e47 100644 --- a/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindSubdivision.java +++ b/src/main/java/net/frozenorb/apiv3/maxmind/MaxMindSubdivision.java @@ -15,7 +15,7 @@ public final class MaxMindSubdivision { public MaxMindSubdivision(Document legacy) { this.isoCode = legacy.getString("iso_code"); - this.confidence = legacy.getInteger("confidence"); + this.confidence = legacy.getInteger("confidence", -1); this.geonameId = legacy.getInteger("geoname_id"); this.name = MaxMindUtils.getEnglishName(legacy); } diff --git a/src/main/java/net/frozenorb/apiv3/model/IpIntel.java b/src/main/java/net/frozenorb/apiv3/model/IpIntel.java index de83aa9..1dc550b 100644 --- a/src/main/java/net/frozenorb/apiv3/model/IpIntel.java +++ b/src/main/java/net/frozenorb/apiv3/model/IpIntel.java @@ -8,8 +8,7 @@ import lombok.AllArgsConstructor; import lombok.Getter; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.maxmind.MaxMindResult; -import net.frozenorb.apiv3.unsorted.BlockingCallback; -import net.frozenorb.apiv3.util.SyncUtils; +import net.frozenorb.apiv3.util.MaxMindUtils; import org.bson.Document; import java.time.Instant; @@ -26,14 +25,6 @@ public final class IpIntel { @Getter private Instant lastUpdatedAt; @Getter private MaxMindResult result; - public static List findAllSync() { - return SyncUtils.blockMulti(ipIntelCollection.find().sort(new Document("lastSeenAt", -1))); - } - - public static IpIntel findByIdSync(String id) { - return SyncUtils.blockOne(ipIntelCollection.find(new Document("_id", id))); - } - public static void findAll(SingleResultCallback> callback) { ipIntelCollection.find().sort(new Document("lastSeenAt", -1)).into(new ArrayList<>(), callback); } @@ -42,6 +33,32 @@ public final class IpIntel { ipIntelCollection.find(new Document("_id", id)).first(callback); } + public static void findByIdOrInsert(String id, SingleResultCallback callback) { + findById(id, (existingIpIntel, error) -> { + if (error != null) { + callback.onResult(null, error); + } else if (existingIpIntel != null) { + callback.onResult(existingIpIntel, null); + } else { + MaxMindUtils.getInsights(id, (maxMindResult, error2) -> { + if (error2 != null) { + callback.onResult(null, error2); + } else { + IpIntel newIpIntel = new IpIntel(id, maxMindResult); + + newIpIntel.insert((ignored, error3) -> { + if (error3 != null) { + callback.onResult(null, error3); + } else { + callback.onResult(newIpIntel, null); + } + }); + } + }); + } + }); + } + public IpIntel() {} // For Jackson public IpIntel(String ip, MaxMindResult result) { @@ -50,10 +67,8 @@ public final class IpIntel { this.result = result; } - public void insert() { - BlockingCallback callback = new BlockingCallback<>(); + public void insert(SingleResultCallback callback) { ipIntelCollection.insertOne(this, callback); - callback.get(); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/route/ipIntel/GETIPIntel.java b/src/main/java/net/frozenorb/apiv3/route/ipIntel/GETIPIntel.java new file mode 100644 index 0000000..2678e7f --- /dev/null +++ b/src/main/java/net/frozenorb/apiv3/route/ipIntel/GETIPIntel.java @@ -0,0 +1,29 @@ +package net.frozenorb.apiv3.route.ipIntel; + +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import net.frozenorb.apiv3.APIv3; +import net.frozenorb.apiv3.model.IpIntel; +import net.frozenorb.apiv3.util.ErrorUtils; +import net.frozenorb.apiv3.util.IpUtils; + +public final class GETIpIntel implements Handler { + + public void handle(RoutingContext ctx) { + String userIp = ctx.request().getParam("id"); + + if (!IpUtils.isValidIp(userIp)) { + ErrorUtils.respondInvalidInput(ctx, "Ip address \"" + userIp + "\" is not valid."); + return; + } + + IpIntel.findByIdOrInsert(userIp, (ipIntel, error) -> { + if (error != null) { + ErrorUtils.respondInternalError(ctx, error); + } else { + APIv3.respondJson(ctx, ipIntel); + } + }); + } + +} \ No newline at end of file