diff --git a/pom.xml b/pom.xml index 7189b12..14ddddb 100644 --- a/pom.xml +++ b/pom.xml @@ -67,6 +67,11 @@ vertx-redis-client 3.2.0 + + com.google.guava + guava + 19.0 + org.projectlombok lombok diff --git a/src/main/java/net/frozenorb/apiv3/APIv3.java b/src/main/java/net/frozenorb/apiv3/APIv3.java index d2d6596..048ae3c 100644 --- a/src/main/java/net/frozenorb/apiv3/APIv3.java +++ b/src/main/java/net/frozenorb/apiv3/APIv3.java @@ -1,15 +1,15 @@ package net.frozenorb.apiv3; +import com.google.common.collect.ImmutableList; import io.vertx.core.AbstractVerticle; -import io.vertx.core.Vertx; import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonObject; import io.vertx.ext.mongo.MongoClient; import io.vertx.ext.web.Router; -import io.vertx.ext.web.impl.RouterImpl; import lombok.Getter; - -import java.util.List; +import net.frozenorb.apiv3.types.Server; +import net.frozenorb.apiv3.types.ServerGroup; +import net.frozenorb.apiv3.utils.ErrorUtils; public class APIv3 extends AbstractVerticle { @@ -31,11 +31,40 @@ public class APIv3 extends AbstractVerticle { ctx.next(); }); - coreHttpRouter.get("/servers").handler(ctx -> { - + Server.findServersByGroup("MineHG", res -> { + res.result().forEach(Server::update); }); - vertx.createHttpServer().requestHandler(coreHttpRouter::accept).listen(80); + coreHttpRouter.get("/servers").handler(ctx -> { + Server.findServersByGroup("MineHG", res -> { + if (res.succeeded()) { + JsonArray response = new JsonArray(); + + res.result().forEach(server -> { + response.add(server.toLiteJson()); + }); + + ctx.response().end(response.encode()); + } else { + JsonObject error = ErrorUtils.toJson(res.cause()); + ctx.response().end(error.encode()); + } + }); + }); + + coreHttpRouter.get("/server/:server").handler(ctx -> { + Server.findServerById(ctx.request().getParam("server"), res -> { + if (res.succeeded()) { + JsonObject json = res.result().toFullJson(); + ctx.response().end(json.encode()); + } else { + JsonObject error = ErrorUtils.toJson(res.cause()); + ctx.response().end(error.encode()); + } + }); + }); + + vertx.createHttpServer().requestHandler(coreHttpRouter::accept).listen(8080); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/types/Rank.java b/src/main/java/net/frozenorb/apiv3/types/Rank.java new file mode 100644 index 0000000..cd92d59 --- /dev/null +++ b/src/main/java/net/frozenorb/apiv3/types/Rank.java @@ -0,0 +1,7 @@ +package net.frozenorb.apiv3.types; + +public class Rank { + + + +} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/types/Server.java b/src/main/java/net/frozenorb/apiv3/types/Server.java index c0b1643..8b0b7e8 100644 --- a/src/main/java/net/frozenorb/apiv3/types/Server.java +++ b/src/main/java/net/frozenorb/apiv3/types/Server.java @@ -1,33 +1,83 @@ package net.frozenorb.apiv3.types; -import com.fasterxml.jackson.databind.util.JSONPObject; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import io.vertx.core.AsyncResult; -import io.vertx.core.Future; import io.vertx.core.Handler; import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonObject; import lombok.Getter; +import lombok.ToString; import net.frozenorb.apiv3.APIv3; +import net.frozenorb.apiv3.utils.MongoUtils; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.time.Instant; +import java.util.*; -public class Server { +@ToString(exclude={ "secret" }) +public final class Server { + + public static final String COLLECTION_NAME = "server"; @Getter private String id; + @Getter private String bungeeId; + @Getter private String displayName; + @Getter private String secret; + @Getter private String group; + @Getter private String internalIp; + @Getter private Instant lastUpdate; + @Getter private double lastTps; + @Getter private List players; - private static void findServers(JSONPObject query, Handler>> callback) { - APIv3.getMongoClient().find("servers", query, result -> { - if (result.succeeded()) { - List servers = result.result(); - ctx.response().end(new JsonArray(servers).encode()); + public static void findServerById(String id, Handler> callback) { + MongoUtils.findOneAndTransform(COLLECTION_NAME, new JsonObject().put("_id", id), Server::new, callback); + } - servers. - } else { - callback.handle(Future.failedFuture()); - } - }); + public static void findServersByGroup(String groupId, Handler>> callback) { + MongoUtils.findManyAndTransform(COLLECTION_NAME, new JsonObject().put("group", groupId), Server::new, callback); + } + + private Server(JsonObject json) { + this.id = json.getString("_id"); + this.bungeeId = json.getString("bungeeId"); + this.displayName = json.getString("displayName"); + this.secret = json.getString("secret"); + this.group = json.getString("group"); + this.internalIp = json.getString("internalIp"); + this.lastUpdate = json.getInstant("lastUpdate"); + this.lastTps = json.getDouble("lastTps"); + this.players = new ArrayList<>(); + + for (Object uuidString : json.getJsonArray("players")) { + players.add(UUID.fromString((String) uuidString)); + } + } + + public void update() { + this.lastUpdate = Instant.now(); + APIv3.getMongoClient().update(COLLECTION_NAME, new JsonObject().put("_id", id), MongoUtils.set(new JsonObject().put("lastUpdate", lastUpdate)), res -> {}); + } + + public JsonObject toLiteJson() { + JsonObject json = new JsonObject(); + + json.put("_id", id); + json.put("bungeeId", bungeeId); + json.put("displayName", displayName); + json.put("group", group); + json.put("internalIp", internalIp); + + return json; + } + + public JsonObject toFullJson() { + JsonObject json = toLiteJson(); + + json.put("lastUpdate", lastUpdate); + json.put("lastTps", lastTps); + json.put("players", new JsonArray(players)); + + return json; } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/types/ServerGroup.java b/src/main/java/net/frozenorb/apiv3/types/ServerGroup.java new file mode 100644 index 0000000..0f75519 --- /dev/null +++ b/src/main/java/net/frozenorb/apiv3/types/ServerGroup.java @@ -0,0 +1,11 @@ +package net.frozenorb.apiv3.types; + +import lombok.Getter; + +public class ServerGroup { + + @Getter private String id; + @Getter private ServerGroup[] inheritsFrom; + //@Getter private Map<> + +} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/utils/ErrorUtils.java b/src/main/java/net/frozenorb/apiv3/utils/ErrorUtils.java new file mode 100644 index 0000000..bdd3c96 --- /dev/null +++ b/src/main/java/net/frozenorb/apiv3/utils/ErrorUtils.java @@ -0,0 +1,22 @@ +package net.frozenorb.apiv3.utils; + +import io.vertx.core.json.JsonObject; +import lombok.experimental.UtilityClass; + +@UtilityClass +public class ErrorUtils { + + public static JsonObject toJson(Throwable throwable) { + return toJson(throwable.getClass().getSimpleName()); + } + + public static JsonObject toJson(String reason) { + JsonObject json = new JsonObject(); + + json.put("failed", true); + json.put("reason", reason); + + return json; + } + +} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/utils/IPUtils.java b/src/main/java/net/frozenorb/apiv3/utils/IPUtils.java new file mode 100644 index 0000000..258a2a6 --- /dev/null +++ b/src/main/java/net/frozenorb/apiv3/utils/IPUtils.java @@ -0,0 +1,37 @@ +package net.frozenorb.apiv3.utils; + +import lombok.experimental.UtilityClass; + +@UtilityClass +public class IPUtils { + + public static String machineToHuman(long machine) { + StringBuilder builder = new StringBuilder(15); // All IPv4 addresses are 15 characters + + for (int i = 0; i < 4; i++) { + builder.insert(0, Long.toString(machine & 0xFF)); + + if (i < 3) { + builder.insert(0, '.'); + } + + machine >>= 8; + } + + return builder.toString(); + } + + public static long humanToMachine(String human) { + long result = 0; + String[] octets = human.split("\\."); + + for (int i = 3; i >= 0; i--) { + long ip = Long.parseLong(octets[3 - i]); + + result |= ip << (i * 8); + } + + return result; + } + +} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/utils/MongoUtils.java b/src/main/java/net/frozenorb/apiv3/utils/MongoUtils.java new file mode 100644 index 0000000..ec6d72e --- /dev/null +++ b/src/main/java/net/frozenorb/apiv3/utils/MongoUtils.java @@ -0,0 +1,54 @@ +package net.frozenorb.apiv3.utils; + +import com.google.common.base.Function; +import com.google.common.collect.Collections2; +import com.google.common.collect.ImmutableList; +import io.vertx.core.AsyncResult; +import io.vertx.core.Future; +import io.vertx.core.Handler; +import io.vertx.core.json.JsonObject; +import io.vertx.ext.mongo.FindOptions; +import lombok.experimental.UtilityClass; +import net.frozenorb.apiv3.APIv3; + +import java.util.Collection; +import java.util.List; + +@UtilityClass +public class MongoUtils { + + private static final FindOptions limitOne = new FindOptions().setLimit(1); + + public static void findOneAndTransform(String collection, JsonObject query, Function transformation, Handler> callback) { + APIv3.getMongoClient().findWithOptions(collection, query, limitOne, res -> { + if (res.succeeded()) { + if (!res.result().isEmpty()) { + JsonObject json = res.result().get(0); + T transformed = transformation.apply(json); + + callback.handle(Future.succeededFuture(transformed)); + } else { + callback.handle(Future.succeededFuture(null)); + } + } else { + callback.handle(Future.failedFuture(res.cause())); + } + }); + } + + public static void findManyAndTransform(String collection, JsonObject query, Function transformation, Handler>> callback) { + APIv3.getMongoClient().find(collection, query, res -> { + if (res.succeeded()) { + Collection servers = Collections2.transform(res.result(), transformation); + callback.handle(Future.succeededFuture(ImmutableList.copyOf(servers))); + } else { + callback.handle(Future.failedFuture(res.cause())); + } + }); + } + + public static JsonObject set(JsonObject json) { + return new JsonObject().put("$set", json); + } + +} \ No newline at end of file