From ee2b1e3d16f42670b8ba0aaf95d1ffda66b6b7fb Mon Sep 17 00:00:00 2001 From: Max Isom Date: Fri, 7 Jan 2022 14:58:10 -0600 Subject: [PATCH] Handle disconnect events --- README.md | 4 +- .../net/fabricmc/diorite/DioriteConfig.java | 1 + .../java/net/fabricmc/diorite/DioriteMod.java | 69 ++++++++++++++++--- 3 files changed, 64 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 19dc67d..68fe341 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,15 @@ If the API responds with 401, the player is blocked from joining and the body of Download a build from the [Releases page](https://github.com/Keweenaw-Kube/diorite/releases) and put it in the `mods/` directory. -After running the server with it installed for the first time, a config file will be created at `mods/diorite/config.yaml`. Fill in `endpoint` with the URL you want Diorite to call. There's an additional, optional property: +After running the server with it installed for the first time, a config file will be created at `mods/diorite/config.yaml`. Fill in `endpoint` with the URL you want Diorite to call. There's a few additional, optional properties: ```yml # Will make request https://example.com?uuid=player-id&token=my-auth-token endpoint: "https://example.com" queryParams: token: "my-auth-token" +# If true, will make call on player disconnect like https://example.com?uuid=player-id&state=disconnected +callOnDisconnect: false ``` ### License diff --git a/src/main/java/net/fabricmc/diorite/DioriteConfig.java b/src/main/java/net/fabricmc/diorite/DioriteConfig.java index 8a83de0..51debae 100644 --- a/src/main/java/net/fabricmc/diorite/DioriteConfig.java +++ b/src/main/java/net/fabricmc/diorite/DioriteConfig.java @@ -12,6 +12,7 @@ public class DioriteConfig { public String endpoint; public HashMap queryParams; + public boolean callOnDisconnect = false; private static String getConfigFileLocation() { File root = new File(DioriteMod.class.getProtectionDomain().getCodeSource().getLocation().getPath()); diff --git a/src/main/java/net/fabricmc/diorite/DioriteMod.java b/src/main/java/net/fabricmc/diorite/DioriteMod.java index 5b2843c..e93db71 100644 --- a/src/main/java/net/fabricmc/diorite/DioriteMod.java +++ b/src/main/java/net/fabricmc/diorite/DioriteMod.java @@ -4,12 +4,20 @@ import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; +import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.stream.Collectors; +import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.mojang.authlib.GameProfile; +import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerLoginNetworkHandler; @@ -19,14 +27,21 @@ import net.fabricmc.fabric.api.networking.v1.PacketSender; import net.fabricmc.fabric.api.networking.v1.ServerLoginNetworking; +import net.minecraft.server.network.ServerPlayNetworkHandler; import net.minecraft.text.LiteralText; public final class DioriteMod implements ModInitializer { private DioriteConfig config; + private Executor scheduler = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder() + .setDaemon(true) + .setNameFormat("diorite-scheduler") + .build()); @Override public void onInitialize() { - ServerLoginConnectionEvents.QUERY_START.register(this::onLoginStart); + ServerLoginConnectionEvents.QUERY_START.register(this::onPreLogin); + + ServerPlayConnectionEvents.DISCONNECT.register(this::onDisconnect); try { this.config = DioriteConfig.loadConfig(); @@ -41,20 +56,19 @@ public void onInitialize() { } } - private void onLoginStart(ServerLoginNetworkHandler networkHandler, MinecraftServer server, PacketSender sender, ServerLoginNetworking.LoginSynchronizer synchronizer) { + private void onPreLogin(ServerLoginNetworkHandler networkHandler, MinecraftServer server, PacketSender sender, ServerLoginNetworking.LoginSynchronizer sync) { GameProfile profile = ((ServerLoginNetworkHandlerAccessor) networkHandler).getProfile(); + String playerUUID = PlayerEntity.getUuidFromProfile(profile).toString(); - String playerUUID = profile.getId().toString(); + sync.waitFor(CompletableFuture.runAsync(() -> onPreLoginAsync(networkHandler, playerUUID), this.scheduler)); + } + private void onPreLoginAsync(ServerLoginNetworkHandler networkHandler, String playerUUID) { // Decide here whether to allow connection or not by calling external HTTP API try { - HashMap queryParams = this.config.queryParams == null ? new HashMap<>() : new HashMap(this.config.queryParams); - - queryParams.put("uuid", playerUUID.replaceAll("-", "")); + HashMap queryParams = this.getQueryParams(playerUUID); - URL url = new URL(this.config.endpoint + '?' + DioriteUtil.getQueryParamsFrom(queryParams)); - - HttpURLConnection http = (HttpURLConnection) url.openConnection(); + HttpURLConnection http = (HttpURLConnection) this.getURL(queryParams).openConnection(); http.setConnectTimeout(1000); int statusCode = http.getResponseCode(); @@ -68,4 +82,41 @@ private void onLoginStart(ServerLoginNetworkHandler networkHandler, MinecraftSer networkHandler.disconnect(new LiteralText("Whitelist API errored out.")); } } + + private void onDisconnect(ServerPlayNetworkHandler networkHandler, MinecraftServer server) { + String playerUUID = networkHandler.player.getUuidAsString(); + + if (this.config.callOnDisconnect) { + try { + HashMap queryParams = this.getQueryParams(playerUUID); + + queryParams.put("state", "disconnected"); + + HttpURLConnection http = (HttpURLConnection) this.getURL(queryParams).openConnection(); + http.setConnectTimeout(1000); + int statusCode = http.getResponseCode(); + + if (statusCode == 401) { + BufferedReader br = new BufferedReader(new InputStreamReader(http.getErrorStream())); + String msg = br.lines().collect(Collectors.joining()); + + networkHandler.disconnect(new LiteralText(msg)); + } + } catch (IOException error) { + System.err.println("Whitelist API errored out."); + } + } + } + + private HashMap getQueryParams(String playerUUID) { + HashMap queryParams = this.config.queryParams == null ? new HashMap<>() : new HashMap(this.config.queryParams); + + queryParams.put("uuid", playerUUID.replaceAll("-", "")); + + return queryParams; + } + + private URL getURL(HashMap queryParams) throws MalformedURLException { + return new URL(this.config.endpoint + '?' + DioriteUtil.getQueryParamsFrom(queryParams)); + } }