From c3b994808f1dc6f5490644b33e063d2697e2b872 Mon Sep 17 00:00:00 2001 From: MD <1917406+mdcfe@users.noreply.github.com> Date: Sat, 26 Feb 2022 22:09:54 +0000 Subject: [PATCH] Use GitHub proxy fallback for update checker (#4818) --- .../essentials/updatecheck/UpdateChecker.java | 85 ++++++++++++------- 1 file changed, 56 insertions(+), 29 deletions(-) diff --git a/Essentials/src/main/java/com/earth2me/essentials/updatecheck/UpdateChecker.java b/Essentials/src/main/java/com/earth2me/essentials/updatecheck/UpdateChecker.java index 0e1391b97..ac0de1468 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/updatecheck/UpdateChecker.java +++ b/Essentials/src/main/java/com/earth2me/essentials/updatecheck/UpdateChecker.java @@ -1,7 +1,6 @@ package com.earth2me.essentials.updatecheck; import com.earth2me.essentials.Essentials; -import com.google.common.base.Charsets; import com.google.gson.Gson; import com.google.gson.JsonObject; import com.google.gson.JsonSyntaxException; @@ -13,6 +12,7 @@ import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; +import java.text.MessageFormat; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; @@ -23,6 +23,12 @@ public final class UpdateChecker { private static final String REPO = "EssentialsX/Essentials"; private static final String BRANCH = "2.x"; + private static final String LATEST_RELEASE_URL = "https://api.github.com/repos/" + REPO + "/releases/latest"; + private static final String LATEST_RELEASE_PROXY_URL = "https://webapi.essentialsx.net/api/v1/github/essx-v2/releases/latest"; + // 0 = base for comparison, 1 = head for comparison - *not* the same as what this class calls them + private static final String DISTANCE_URL = "https://api.github.com/repos/EssentialsX/Essentials/compare/{0}...{1}"; + private static final String DISTANCE_PROXY_URL = "https://webapi.essentialsx.net/api/v1/github/essx-v2/compare/{0}/{1}"; + private final Essentials ess; private final String versionIdentifier; private final String versionBranch; @@ -89,8 +95,7 @@ public final class UpdateChecker { new Thread(() -> { catchBlock: try { - final HttpURLConnection connection = (HttpURLConnection) new URL("https://api.github.com/repos/" + REPO + "/releases/latest").openConnection(); - connection.connect(); + final HttpURLConnection connection = tryRequestWithFallback(LATEST_RELEASE_URL, LATEST_RELEASE_PROXY_URL); if (connection.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) { // Locally built? @@ -102,7 +107,7 @@ public final class UpdateChecker { break catchBlock; } - try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), Charsets.UTF_8))) { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) { latestRelease = new Gson().fromJson(reader, JsonObject.class).get("tag_name").getAsString(); pendingReleaseFuture.complete(cachedRelease = fetchDistance(latestRelease, getVersionIdentifier())); } catch (JsonSyntaxException | NumberFormatException e) { @@ -137,10 +142,54 @@ public final class UpdateChecker { return latestRelease; } + private HttpURLConnection tryRequestWithFallback(final String githubUrl, final String fallbackUrl) throws IOException { + HttpURLConnection connection = (HttpURLConnection) new URL(githubUrl).openConnection(); + try { + connection.connect(); + if (connection.getResponseCode() != HttpURLConnection.HTTP_INTERNAL_ERROR && connection.getResponseCode() != HttpURLConnection.HTTP_FORBIDDEN) { + // Connection succeeded without any errors from GitHub's side. + return connection; + } + } catch (IOException ignored) { + } + + // Connection failed, GitHub's down or we hit a ratelimit, so use the fallback URL + // If the fallback fails, let the exception or error status bubble up + connection = (HttpURLConnection) new URL(fallbackUrl).openConnection(); + connection.connect(); + + return connection; + } + + private RemoteVersion tryProcessDistance(final HttpURLConnection connection) throws IOException { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) { + final JsonObject obj = new Gson().fromJson(reader, JsonObject.class); + switch (obj.get("status").getAsString()) { + case "identical": { + return new RemoteVersion(BranchStatus.IDENTICAL, 0); + } + case "ahead": { + return new RemoteVersion(BranchStatus.AHEAD, 0); + } + case "behind": { + return new RemoteVersion(BranchStatus.BEHIND, obj.get("behind_by").getAsInt()); + } + case "diverged": { + return new RemoteVersion(BranchStatus.DIVERGED, obj.get("behind_by").getAsInt()); + } + default: { + return new RemoteVersion(BranchStatus.UNKNOWN); + } + } + } catch (JsonSyntaxException | NumberFormatException e) { + e.printStackTrace(); + return new RemoteVersion(BranchStatus.ERROR); + } + } + private RemoteVersion fetchDistance(final String head, final String hash) { try { - final HttpURLConnection connection = (HttpURLConnection) new URL("https://api.github.com/repos/" + REPO + "/compare/" + head + "..." + hash).openConnection(); - connection.connect(); + final HttpURLConnection connection = tryRequestWithFallback(MessageFormat.format(DISTANCE_URL, head, hash), MessageFormat.format(DISTANCE_PROXY_URL, head, hash)); if (connection.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) { // Locally built? @@ -150,29 +199,7 @@ public final class UpdateChecker { return new RemoteVersion(BranchStatus.ERROR); } - try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), Charsets.UTF_8))) { - final JsonObject obj = new Gson().fromJson(reader, JsonObject.class); - switch (obj.get("status").getAsString()) { - case "identical": { - return new RemoteVersion(BranchStatus.IDENTICAL, 0); - } - case "ahead": { - return new RemoteVersion(BranchStatus.AHEAD, 0); - } - case "behind": { - return new RemoteVersion(BranchStatus.BEHIND, obj.get("behind_by").getAsInt()); - } - case "diverged": { - return new RemoteVersion(BranchStatus.DIVERGED, obj.get("behind_by").getAsInt()); - } - default: { - return new RemoteVersion(BranchStatus.UNKNOWN); - } - } - } catch (JsonSyntaxException | NumberFormatException e) { - e.printStackTrace(); - return new RemoteVersion(BranchStatus.ERROR); - } + return tryProcessDistance(connection); } catch (IOException e) { e.printStackTrace(); return new RemoteVersion(BranchStatus.ERROR);