From 226002a6765535a24e89a26306bdf2d9aa038ba6 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Tue, 16 Jul 2024 12:55:27 +0100 Subject: [PATCH] Update to better RestClient --- .../org/geysermc/discordbot/GeyserBot.java | 5 +- .../commands/FloodgateUuidCommand.java | 10 +- .../discordbot/commands/QueueCommand.java | 4 +- .../commands/search/ProviderCommand.java | 4 +- .../dump_issues/IntegrityDumpIssueCheck.java | 4 +- .../discordbot/listeners/BadLinksHandler.java | 4 +- .../discordbot/listeners/DumpHandler.java | 6 +- .../discordbot/listeners/ErrorAnalyzer.java | 6 +- .../discordbot/listeners/FileHandler.java | 34 ++- .../discordbot/listeners/SupportHandler.java | 79 ------ .../discordbot/updates/JiraUpdateCheck.java | 6 +- .../updates/MinecraftUpdateCheck.java | 6 +- .../pw/chew/chewbotcca/util/RestClient.java | 257 +++++++++++------- 13 files changed, 200 insertions(+), 225 deletions(-) delete mode 100644 src/main/java/org/geysermc/discordbot/listeners/SupportHandler.java diff --git a/src/main/java/org/geysermc/discordbot/GeyserBot.java b/src/main/java/org/geysermc/discordbot/GeyserBot.java index b1156cbf..6607e009 100644 --- a/src/main/java/org/geysermc/discordbot/GeyserBot.java +++ b/src/main/java/org/geysermc/discordbot/GeyserBot.java @@ -237,7 +237,6 @@ public static void main(String[] args) throws IOException { new VoiceGroupHandler(), new BadLinksHandler(), new HelpHandler(), - new SupportHandler(), new DeleteHandler(), new PreviewHandler(), client.build(), @@ -282,8 +281,8 @@ public static void main(String[] args) throws IOException { // Start the bStats tracking thread generalThreadPool.scheduleAtFixedRate(() -> { - JSONArray servers = RestClient.simpleGetJsonArray("https://bstats.org/api/v1/plugins/5273/charts/servers/data"); - JSONArray players = RestClient.simpleGetJsonArray("https://bstats.org/api/v1/plugins/5273/charts/players/data"); + JSONArray servers = RestClient.get("https://bstats.org/api/v1/plugins/5273/charts/servers/data").asJSONArray(); + JSONArray players = RestClient.get("https://bstats.org/api/v1/plugins/5273/charts/players/data").asJSONArray(); int serverCount = servers.getJSONArray(servers.length() - 1).getInt(1); int playerCount = players.getJSONArray(players.length() - 1).getInt(1); jda.getPresence().setActivity(Activity.playing(BotHelpers.coolFormat(serverCount) + " servers, " + BotHelpers.coolFormat(playerCount) + " players")); diff --git a/src/main/java/org/geysermc/discordbot/commands/FloodgateUuidCommand.java b/src/main/java/org/geysermc/discordbot/commands/FloodgateUuidCommand.java index ad7c1a8a..8dca5364 100644 --- a/src/main/java/org/geysermc/discordbot/commands/FloodgateUuidCommand.java +++ b/src/main/java/org/geysermc/discordbot/commands/FloodgateUuidCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020-2022 GeyserMC. http://geysermc.org + * Copyright (c) 2020-2024 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -33,7 +33,6 @@ import org.geysermc.discordbot.util.BotColors; import org.json.JSONObject; import pw.chew.chewbotcca.util.RestClient; -import pw.chew.chewbotcca.util.RestClient.RestResponse; import java.util.Collections; import java.util.UUID; @@ -59,10 +58,9 @@ protected void execute(SlashCommandEvent event) { EmbedBuilder builder = new EmbedBuilder(); builder.setTitle("Floodgate Player UUID"); - RestResponse restResponse = - RestClient.getJsonObject("https://api.geysermc.org/v2/xbox/xuid/" + username); - int serverCode = restResponse.statusCode(); - JSONObject response = restResponse.body(); + RestClient.Response restResponse = RestClient.get("https://api.geysermc.org/v2/xbox/xuid/" + username); + int serverCode = restResponse.code(); + JSONObject response = restResponse.asJSONObject(); // Check what code the server returns and send the corresponding embed to author. switch (serverCode) { diff --git a/src/main/java/org/geysermc/discordbot/commands/QueueCommand.java b/src/main/java/org/geysermc/discordbot/commands/QueueCommand.java index 222baa13..b7dc2eab 100644 --- a/src/main/java/org/geysermc/discordbot/commands/QueueCommand.java +++ b/src/main/java/org/geysermc/discordbot/commands/QueueCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020-2022 GeyserMC. http://geysermc.org + * Copyright (c) 2020-2024 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -61,7 +61,7 @@ protected void execute(CommandEvent event) { } protected MessageEmbed handle() { - JSONObject stats = RestClient.simpleGetJsonObject("https://api.geysermc.org/v2/stats"); + JSONObject stats = RestClient.get("https://api.geysermc.org/v2/stats").asJSONObject(); if (stats.has("error")) { return MessageHelper.errorResponse( null, diff --git a/src/main/java/org/geysermc/discordbot/commands/search/ProviderCommand.java b/src/main/java/org/geysermc/discordbot/commands/search/ProviderCommand.java index f64b1505..4b1ebff4 100644 --- a/src/main/java/org/geysermc/discordbot/commands/search/ProviderCommand.java +++ b/src/main/java/org/geysermc/discordbot/commands/search/ProviderCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020-2022 GeyserMC. http://geysermc.org + * Copyright (c) 2020-2024 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -172,7 +172,7 @@ List getProviders() { } // Fetch the search page - JSONObject contents = RestClient.simpleGetJsonObject("https://raw.githubusercontent.com/GeyserMC/GeyserWiki/master/_data/providers.json"); + JSONObject contents = RestClient.get("https://raw.githubusercontent.com/GeyserMC/GeyserWiki/master/_data/providers.json").asJSONObject(); Map descriptionTemplates = contents.getJSONObject("description_templates").toMap(); List providers = new ArrayList<>(); diff --git a/src/main/java/org/geysermc/discordbot/dump_issues/IntegrityDumpIssueCheck.java b/src/main/java/org/geysermc/discordbot/dump_issues/IntegrityDumpIssueCheck.java index b66e102f..11c3ff36 100644 --- a/src/main/java/org/geysermc/discordbot/dump_issues/IntegrityDumpIssueCheck.java +++ b/src/main/java/org/geysermc/discordbot/dump_issues/IntegrityDumpIssueCheck.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020-2022 GeyserMC. http://geysermc.org + * Copyright (c) 2020-2024 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -45,7 +45,7 @@ public List checkIssues(JSONObject dump) { } String md5Hash = dump.getJSONObject("hashInfo").getString("md5Hash"); - String response = RestClient.simpleGetString("https://ci.opencollab.dev/fingerprint/" + md5Hash + "/api/json"); + String response = RestClient.get("https://ci.opencollab.dev/fingerprint/" + md5Hash + "/api/json").asString(); // Check if 404 if (response.startsWith("")) { diff --git a/src/main/java/org/geysermc/discordbot/listeners/BadLinksHandler.java b/src/main/java/org/geysermc/discordbot/listeners/BadLinksHandler.java index 00a50d90..034b338a 100644 --- a/src/main/java/org/geysermc/discordbot/listeners/BadLinksHandler.java +++ b/src/main/java/org/geysermc/discordbot/listeners/BadLinksHandler.java @@ -119,8 +119,8 @@ public void onMessageReceived(@NotNull MessageReceivedEvent event) { if (!foundMatch) { // Make request to https://anti-fish.bitflow.dev/check - RequestBody body = RequestBody.create("{\"message\":" + JSONObject.quote(event.getMessage().getContentRaw()) + "}", RestClient.JSON); - JSONObject response = RestClient.simplePost("https://anti-fish.bitflow.dev/check", body); + JSONObject body = new JSONObject().put("message", event.getMessage().getContentRaw()); + JSONObject response = RestClient.post("https://anti-fish.bitflow.dev/check", body).asJSONObject(); if (response.getBoolean("match")) { JSONArray matches = response.getJSONArray("matches"); for (int i = 0; i < matches.length(); i++) { diff --git a/src/main/java/org/geysermc/discordbot/listeners/DumpHandler.java b/src/main/java/org/geysermc/discordbot/listeners/DumpHandler.java index 9cbcada4..14cee8fd 100644 --- a/src/main/java/org/geysermc/discordbot/listeners/DumpHandler.java +++ b/src/main/java/org/geysermc/discordbot/listeners/DumpHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020-2022 GeyserMC. http://geysermc.org + * Copyright (c) 2020-2024 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -92,7 +92,7 @@ public void onMessageReceived(@NotNull MessageReceivedEvent event) { // Check attached files for (Message.Attachment attachment : event.getMessage().getAttachments()) { if (attachment.getFileName().equals("dump.json")) { - String contents = RestClient.simpleGetString(attachment.getUrl()); + String contents = RestClient.get(attachment.getUrl()).asString(); if (isDump(contents)) { parseDump(event, null, contents); @@ -106,7 +106,7 @@ public void onMessageReceived(@NotNull MessageReceivedEvent event) { String cleanURL = "https://geysermc.org/utilities/dump_viewer#" + matcher.group(2); String rawURL = "https://dump.geysermc.org/raw/" + matcher.group(2); - parseDump(event, cleanURL, RestClient.simpleGetString(rawURL)); + parseDump(event, cleanURL, RestClient.get(rawURL).asString()); } /** diff --git a/src/main/java/org/geysermc/discordbot/listeners/ErrorAnalyzer.java b/src/main/java/org/geysermc/discordbot/listeners/ErrorAnalyzer.java index 9d282b27..f07e9b48 100644 --- a/src/main/java/org/geysermc/discordbot/listeners/ErrorAnalyzer.java +++ b/src/main/java/org/geysermc/discordbot/listeners/ErrorAnalyzer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020-2022 GeyserMC. http://geysermc.org + * Copyright (c) 2020-2024 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -162,7 +162,7 @@ public void onMessageReceived(MessageReceivedEvent event) { extensions.add("0"); } if (extensions.contains(attachment.getFileExtension())) { - handleLog(event, RestClient.simpleGetString(attachment.getUrl()), false); + handleLog(event, RestClient.get(attachment.getUrl()).asString(), false); } } } @@ -192,7 +192,7 @@ public void onMessageReceived(MessageReceivedEvent event) { content = rawContent; } else { // We didn't find a url so use the message content - content = RestClient.simpleGetString(url); + content = RestClient.get(url).asString(); } handleLog(event, content, false); diff --git a/src/main/java/org/geysermc/discordbot/listeners/FileHandler.java b/src/main/java/org/geysermc/discordbot/listeners/FileHandler.java index 6b058eac..c5060082 100644 --- a/src/main/java/org/geysermc/discordbot/listeners/FileHandler.java +++ b/src/main/java/org/geysermc/discordbot/listeners/FileHandler.java @@ -27,6 +27,7 @@ import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; +import com.nimbusds.jose.shaded.json.JSONArray; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.events.message.MessageDeleteEvent; @@ -85,21 +86,24 @@ public void onMessageReceived(@NotNull MessageReceivedEvent event) { try { File attachmentFile = attachment.getProxy().downloadToFile(File.createTempFile("GeyserBotTempFile", ".temp")).get(); - RequestBody body = RequestBody.create("{" + - "\"name\":" + JSONObject.quote(attachment.getFileName()) + "," + - "\"expires\":\"" + event.getMessage().getTimeCreated().plusDays(1) + "\"," + - "\"files\": [" + - "{" + - "\"name\":" + JSONObject.quote(attachment.getFileName()) + "," + - "\"content\": {" + - "\"format\": \"text\"," + - "\"value\": " + JSONObject.quote(new String(Files.readAllBytes(attachmentFile.toPath()))) + - "}" + - "}" + - "]" + - "}", RestClient.JSON); - - JSONObject response = RestClient.simplePost("https://api.paste.gg/v1/pastes", body); + JSONObject body = new JSONObject(); + body.put("name", attachment.getFileName()); + body.put("expires", event.getMessage().getTimeCreated().plusDays(1)); + + JSONObject file = new JSONObject(); + file.put("name", attachment.getFileName()); + + JSONObject content = new JSONObject(); + content.put("format", "text"); + content.put("value", new String(Files.readAllBytes(attachmentFile.toPath()))); + + file.put("content", content); + + JSONArray files = new JSONArray(); + files.add(file); + body.put("files", files); + + JSONObject response = RestClient.post("https://api.paste.gg/v1/pastes", body).asJSONObject(); // Cleanup the file attachmentFile.delete(); diff --git a/src/main/java/org/geysermc/discordbot/listeners/SupportHandler.java b/src/main/java/org/geysermc/discordbot/listeners/SupportHandler.java deleted file mode 100644 index 52fe426b..00000000 --- a/src/main/java/org/geysermc/discordbot/listeners/SupportHandler.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2020-2023 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/GeyserDiscordBot - */ - -package org.geysermc.discordbot.listeners; - -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; -import net.dv8tion.jda.api.hooks.ListenerAdapter; -import org.jetbrains.annotations.NotNull; -import org.json.JSONObject; -import pw.chew.chewbotcca.util.RestClient; - -import java.util.Arrays; -import java.util.concurrent.TimeUnit; -import java.util.regex.Pattern; - -public class SupportHandler extends ListenerAdapter { - - @Override - public void onMessageReceived(@NotNull MessageReceivedEvent event) { - if (event.getAuthor().isBot()) return; - - long channelID = Long.parseLong("1091474266643509408"); - if (!(event.getChannel().getIdLong() == channelID)) { - return; - } - String discordMessage = event.getMessage().getContentRaw().toLowerCase(); - // A list of words to check. - String[] keywordsToCheck = {"pls", "please", "help", "me", "need", "how", "install", "setup", "geyser", "floodgate", "what", "why"}; - // Check if the message contains a match. - if (Arrays.stream(keywordsToCheck).noneMatch(p -> Pattern.compile("\\b" + p + "\\b").matcher(discordMessage).find())) { - return; - } - // Joke Api - RestClient.RestResponse restResponse = - RestClient.getJsonObject("https://v2.jokeapi.dev/joke/Programming,Miscellaneous,Pun,Spooky?blacklistFlags=nsfw,religious,political,racist,sexist,explicit"); - JSONObject serverResponse = restResponse.body(); - - switch (serverResponse.getString("type")) { - case "single" -> event.getChannel().sendMessage(event.getAuthor().getName() + ", " + serverResponse.getString("joke")).queue(); - case "twopart" -> { - long Time0 = System.currentTimeMillis(); - long Time1; - long runTime = 0; - // Setup the joke - event.getChannel().sendMessage(event.getAuthor().getName() + ", " + serverResponse.getString("setup")).queue(); - // Delay the delivery which makes it funnier. - while (runTime < 1000 * 5) { // 1000 milliseconds or 1 second - Time1 = System.currentTimeMillis(); - runTime = Time1 - Time0; - } - // Make the joke - event.getChannel().sendMessage(serverResponse.getString("delivery")).delay(70L, TimeUnit.SECONDS).queue(); - } - } - - } -} diff --git a/src/main/java/org/geysermc/discordbot/updates/JiraUpdateCheck.java b/src/main/java/org/geysermc/discordbot/updates/JiraUpdateCheck.java index dbe5f910..9e641c1b 100644 --- a/src/main/java/org/geysermc/discordbot/updates/JiraUpdateCheck.java +++ b/src/main/java/org/geysermc/discordbot/updates/JiraUpdateCheck.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020-2022 GeyserMC. http://geysermc.org + * Copyright (c) 2020-2024 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -49,7 +49,7 @@ public JiraUpdateCheck(String project, String platform) { @Override public void populate() throws JSONException { - JSONArray versions = RestClient.simpleGetJsonArray(CHECK_URL + project + "/versions"); + JSONArray versions = RestClient.get(CHECK_URL + project + "/versions").asJSONArray(); for (int i = 0; i < versions.length(); i++) { String name = versions.getJSONObject(i).getString("name"); @@ -63,7 +63,7 @@ public void populate() throws JSONException { @Override public void check() { - String versionsText = RestClient.simpleGetString(CHECK_URL + project + "/versions"); + String versionsText = RestClient.get(CHECK_URL + project + "/versions").asString(); try { JSONArray versions = new JSONArray(versionsText); diff --git a/src/main/java/org/geysermc/discordbot/updates/MinecraftUpdateCheck.java b/src/main/java/org/geysermc/discordbot/updates/MinecraftUpdateCheck.java index aae9fad1..81dd4695 100644 --- a/src/main/java/org/geysermc/discordbot/updates/MinecraftUpdateCheck.java +++ b/src/main/java/org/geysermc/discordbot/updates/MinecraftUpdateCheck.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020-2022 GeyserMC. http://geysermc.org + * Copyright (c) 2020-2024 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -41,7 +41,7 @@ public class MinecraftUpdateCheck extends AbstractUpdateCheck { @Override public void populate() throws JSONException { - JSONObject versionsData = RestClient.simpleGetJsonObject(CHECK_URL); + JSONObject versionsData = RestClient.get(CHECK_URL).asJSONObject(); JSONArray versions = versionsData.getJSONArray("versions"); for (int i = 0; i < versions.length(); i++) { @@ -53,7 +53,7 @@ public void populate() throws JSONException { @Override public void check() { - JSONObject versionsData = RestClient.simpleGetJsonObject(CHECK_URL); + JSONObject versionsData = RestClient.get(CHECK_URL).asJSONObject(); if (versionsData.has("error")) { GeyserBot.LOGGER.warn("Error while checking '" + CHECK_URL + "': " + versionsData.getString("error")); return; diff --git a/src/main/java/pw/chew/chewbotcca/util/RestClient.java b/src/main/java/pw/chew/chewbotcca/util/RestClient.java index eb7abe6c..29bf44a2 100644 --- a/src/main/java/pw/chew/chewbotcca/util/RestClient.java +++ b/src/main/java/pw/chew/chewbotcca/util/RestClient.java @@ -1,151 +1,204 @@ /* - * Copyright (C) 2020 Chewbotcca + * Copyright (c) 2024 GeyserMC. http://geysermc.org * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/GeyserDiscordBot */ package pw.chew.chewbotcca.util; -import okhttp3.*; -import org.geysermc.discordbot.GeyserBot; import org.json.JSONArray; import org.json.JSONObject; import org.slf4j.LoggerFactory; import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; -// Off brand RestClient based on the ruby gem of the same name +/** + * Modified from https://github.com/Chewbotcca/Chewbotcca-Discord/blob/74f17a0d35490696642421b7aafb8154517148d1/src/main/java/pw/chew/chewbotcca/util/RestClient.java + * + * Off brand RestClient based on the ruby gem of the same name + */ public class RestClient { - public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); - public static final String USER_AGENT = "GeyserMC-9444/2.0 (JDA; +https://geysermc.org) DBots/739572267855511652"; + public static final String JSON = "application/json; charset=utf-8"; + public static final String USER_AGENT = "GeyserMC-DiscordBot/1.0 (JDA; +https://geysermc.org) DBots/739572267855511652"; + + private static final HttpClient client = HttpClient.newBuilder() + .followRedirects(HttpClient.Redirect.NORMAL) + .build(); + private static Duration timeout = Duration.ofSeconds(30); + private static boolean debug = true; /** - * Make a GET request - * @param url the url to get - * @return a JSONArray response - * @throws RuntimeException when an (IO)Exception occurred while executing the request + * Gets the HTTP client used for this session + * + * @return The HTTP Client */ - public static JSONArray simpleGetJsonArray(String url) throws RuntimeException { - Request request = new Request.Builder() - .url(url) - .get() - .addHeader("User-Agent", USER_AGENT) - .build(); - try { - return performRequestJsonArray(request).body(); - } catch (IOException exception) { - throw new RuntimeException(exception); - } + public static HttpClient getHttpClient() { + return client; } /** - * Make a GET request - * @param url the url to get - * @return a RestResponse with a JSONObject body + * Sets the timeout used for this session. + * + * @param timeout The new timeout. */ - public static RestResponse getJsonObject(String url) { - Request request = new Request.Builder() - .url(url) - .get() - .addHeader("User-Agent", USER_AGENT) - .build(); - return performRequestJsonObject(request); + public static void setTimeout(Duration timeout) { + RestClient.timeout = timeout; } /** - * Make a GET request - * @param url the url to get - * @return a JSONObject response + * Sets debug logging for this session. + * + * @param debug The new debug option. */ - public static JSONObject simpleGetJsonObject(String url) { - return getJsonObject(url).body(); + public static void setDebug(boolean debug) { + RestClient.debug = debug; } /** * Make a GET request + * * @param url the url to get - * @return a string response + * @param headers Optional set of headers as "Header: Value" like "Authorization: Bearer bob" + * @throws IllegalArgumentException If an invalid header is passed + * @throws RuntimeException If the request fails + * @return a String response */ - public static String simpleGetString(String url) { - Request request = new Request.Builder() - .url(url) - .get() - .addHeader("User-Agent", USER_AGENT) - .build(); - return performRequestString(request).body(); + public static Response get(String url, String ...headers) { + HttpRequest.Builder request = HttpRequest.newBuilder(URI.create(url)) + .header("User-Agent", USER_AGENT) + .timeout(timeout); + + for (String header : headers) { + String[] details = header.split(":"); + if (details.length != 2) { + throw new IllegalArgumentException("Invalid header syntax provided: " + header); + } + request.header(details[0].trim(), details[1].trim()); + } + + if (debug) LoggerFactory.getLogger(RestClient.class).debug("Making call to GET " + url); + return performRequest(request.build()); } /** - * Make an Unauthenticated POST Request with a RequestBody + * Make a POST Request + * * @param url the url - * @param requestBody the requestBody to send - * @return the JSONObject response + * @param data the body to send (will run through toString()) + * @param headers vararg of headers in "Key: Value" format + * @throws IllegalArgumentException If an invalid header is passed + * @throws RuntimeException If the request fails + * @return a response */ - public static JSONObject simplePost(String url, RequestBody requestBody) { - Request request = new Request.Builder() - .url(url) - .post(requestBody) - .addHeader("User-Agent", USER_AGENT) - .build(); - return performRequestJsonObject(request).body(); - } + public static Response post(String url, Object data, String... headers) { + HttpRequest.Builder request = HttpRequest.newBuilder(URI.create(url)) + .POST(HttpRequest.BodyPublishers.ofString(data.toString())) + .header("User-Agent", USER_AGENT) + .timeout(timeout); - private static RestResponse performRequestJsonArray(Request request) throws IOException { - RestResponse response = performRequestUnsafe(request); - return new RestResponse<>(response.statusCode(), new JSONArray(response.body())); - } + for (String header : headers) { + String[] details = header.split(":"); + if (details.length != 2) { + throw new IllegalArgumentException("Invalid header syntax provided: " + header); + } + request.header(details[0].trim(), details[1].trim()); + } - private static RestResponse performRequestJsonObject(Request request) { - RestResponse response; - try { - response = performRequestUnsafe(request); - } catch (IOException exception) { - response = new RestResponse<>( - -1, - "{\"error\": \"%s\"}".formatted(JSONObject.quote(exception.getMessage())) - ); + if (data instanceof JSONObject || data instanceof JSONArray) { + request.header("Content-Type", JSON); } - return new RestResponse<>(response.statusCode(), new JSONObject(response.body())); + + if (debug) LoggerFactory.getLogger(RestClient.class).debug("Making call to POST {}", url); + return performRequest(request.build()); } - private static RestResponse performRequestString(Request request) { + /** + * Actually perform the request + * @param request a request + * @return a response + */ + public static Response performRequest(HttpRequest request) { try { - return performRequestUnsafe(request); - } catch (IOException exception) { - return new RestResponse<>(-1, exception.getMessage()); + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + int code = response.statusCode(); + String body = response.body(); + if (debug) { + LoggerFactory.getLogger(RestClient.class).debug("Response is " + body); + } + return new Response(code, body); + } catch (IOException | InterruptedException e) { + // Rethrow exceptions as runtime + throw new RuntimeException(e.getMessage()); } } - private static RestResponse performRequestUnsafe(Request request) throws IOException { - // GeyserMC - Replace JDA call with our JDA - OkHttpClient client = GeyserBot.getJDA() == null ? new OkHttpClient() : GeyserBot.getJDA().getHttpClient(); - - LoggerFactory.getLogger(RestClient.class).debug( - "Making call to %s %s".formatted(request.method(), request.url()) - ); - try (Response response = client.newCall(request).execute()) { - //noinspection ConstantConditions - responseBody cannot be null when using 'execute' - String body = response.body().string(); - LoggerFactory.getLogger(RestClient.class).debug("Response is " + body); - return new RestResponse<>(response.code(), body); - } catch (IOException exception) { - LoggerFactory.getLogger(RestClient.class).warn( - "Call to %s failed with %s!".formatted(request.url(), exception.getClass().getSimpleName()) - ); - throw exception; + /** + * A response from a REST call + */ + public record Response(int code, String response) { + /** + * Check to see if the request was successful. + * Codes 200-299 are considered successful. + * @return true if successful + */ + public boolean success() { + return code >= 200 && code < 300; + } + + /** + * Get the response as a String + * @return a String + */ + public String asString() { + return response; } - } - public record RestResponse(int statusCode, T body) { + /** + * Get the response as a JSONObject + * @return a JSONObject + */ + public JSONObject asJSONObject() { + return new JSONObject(response); + } + + /** + * Get the response as a JSONArray + * @return a JSONArray + */ + public JSONArray asJSONArray() { + return new JSONArray(response); + } + + /** + * Get the response as a String + * @return a String + */ + @Override + public String toString() { + return asString(); + } } }