11package com .earth2me .essentials .updatecheck ;
22
33import com .earth2me .essentials .Essentials ;
4- import com .google .common .base .Charsets ;
54import com .google .gson .Gson ;
65import com .google .gson .JsonObject ;
76import com .google .gson .JsonSyntaxException ;
1312import java .net .HttpURLConnection ;
1413import java .net .URL ;
1514import java .nio .charset .StandardCharsets ;
15+ import java .text .MessageFormat ;
1616import java .util .List ;
1717import java .util .concurrent .CompletableFuture ;
1818import java .util .stream .Collectors ;
@@ -23,6 +23,12 @@ public final class UpdateChecker {
2323 private static final String REPO = "EssentialsX/Essentials" ;
2424 private static final String BRANCH = "2.x" ;
2525
26+ private static final String LATEST_RELEASE_URL = "https://api.github.com/repos/" + REPO + "/releases/latest" ;
27+ private static final String LATEST_RELEASE_PROXY_URL = "https://webapi.essentialsx.net/api/v1/github/essx-v2/releases/latest" ;
28+ // 0 = base for comparison, 1 = head for comparison - *not* the same as what this class calls them
29+ private static final String DISTANCE_URL = "https://api.github.com/repos/EssentialsX/Essentials/compare/{0}...{1}" ;
30+ private static final String DISTANCE_PROXY_URL = "https://webapi.essentialsx.net/api/v1/github/essx-v2/compare/{0}/{1}" ;
31+
2632 private final Essentials ess ;
2733 private final String versionIdentifier ;
2834 private final String versionBranch ;
@@ -89,8 +95,7 @@ public CompletableFuture<RemoteVersion> fetchLatestRelease() {
8995 new Thread (() -> {
9096 catchBlock :
9197 try {
92- final HttpURLConnection connection = (HttpURLConnection ) new URL ("https://api.github.com/repos/" + REPO + "/releases/latest" ).openConnection ();
93- connection .connect ();
98+ final HttpURLConnection connection = tryRequestWithFallback (LATEST_RELEASE_URL , LATEST_RELEASE_PROXY_URL );
9499
95100 if (connection .getResponseCode () == HttpURLConnection .HTTP_NOT_FOUND ) {
96101 // Locally built?
@@ -102,7 +107,7 @@ public CompletableFuture<RemoteVersion> fetchLatestRelease() {
102107 break catchBlock ;
103108 }
104109
105- try (BufferedReader reader = new BufferedReader (new InputStreamReader (connection .getInputStream (), Charsets .UTF_8 ))) {
110+ try (BufferedReader reader = new BufferedReader (new InputStreamReader (connection .getInputStream (), StandardCharsets .UTF_8 ))) {
106111 latestRelease = new Gson ().fromJson (reader , JsonObject .class ).get ("tag_name" ).getAsString ();
107112 pendingReleaseFuture .complete (cachedRelease = fetchDistance (latestRelease , getVersionIdentifier ()));
108113 } catch (JsonSyntaxException | NumberFormatException e ) {
@@ -137,10 +142,54 @@ public String getLatestRelease() {
137142 return latestRelease ;
138143 }
139144
140- private RemoteVersion fetchDistance (final String head , final String hash ) {
145+ private HttpURLConnection tryRequestWithFallback (final String githubUrl , final String fallbackUrl ) throws IOException {
146+ HttpURLConnection connection = (HttpURLConnection ) new URL (githubUrl ).openConnection ();
141147 try {
142- final HttpURLConnection connection = (HttpURLConnection ) new URL ("https://api.github.com/repos/" + REPO + "/compare/" + head + "..." + hash ).openConnection ();
143148 connection .connect ();
149+ if (connection .getResponseCode () != HttpURLConnection .HTTP_INTERNAL_ERROR && connection .getResponseCode () != HttpURLConnection .HTTP_FORBIDDEN ) {
150+ // Connection succeeded without any errors from GitHub's side.
151+ return connection ;
152+ }
153+ } catch (IOException ignored ) {
154+ }
155+
156+ // Connection failed, GitHub's down or we hit a ratelimit, so use the fallback URL
157+ // If the fallback fails, let the exception or error status bubble up
158+ connection = (HttpURLConnection ) new URL (fallbackUrl ).openConnection ();
159+ connection .connect ();
160+
161+ return connection ;
162+ }
163+
164+ private RemoteVersion tryProcessDistance (final HttpURLConnection connection ) throws IOException {
165+ try (BufferedReader reader = new BufferedReader (new InputStreamReader (connection .getInputStream (), StandardCharsets .UTF_8 ))) {
166+ final JsonObject obj = new Gson ().fromJson (reader , JsonObject .class );
167+ switch (obj .get ("status" ).getAsString ()) {
168+ case "identical" : {
169+ return new RemoteVersion (BranchStatus .IDENTICAL , 0 );
170+ }
171+ case "ahead" : {
172+ return new RemoteVersion (BranchStatus .AHEAD , 0 );
173+ }
174+ case "behind" : {
175+ return new RemoteVersion (BranchStatus .BEHIND , obj .get ("behind_by" ).getAsInt ());
176+ }
177+ case "diverged" : {
178+ return new RemoteVersion (BranchStatus .DIVERGED , obj .get ("behind_by" ).getAsInt ());
179+ }
180+ default : {
181+ return new RemoteVersion (BranchStatus .UNKNOWN );
182+ }
183+ }
184+ } catch (JsonSyntaxException | NumberFormatException e ) {
185+ e .printStackTrace ();
186+ return new RemoteVersion (BranchStatus .ERROR );
187+ }
188+ }
189+
190+ private RemoteVersion fetchDistance (final String head , final String hash ) {
191+ try {
192+ final HttpURLConnection connection = tryRequestWithFallback (MessageFormat .format (DISTANCE_URL , head , hash ), MessageFormat .format (DISTANCE_PROXY_URL , head , hash ));
144193
145194 if (connection .getResponseCode () == HttpURLConnection .HTTP_NOT_FOUND ) {
146195 // Locally built?
@@ -150,29 +199,7 @@ private RemoteVersion fetchDistance(final String head, final String hash) {
150199 return new RemoteVersion (BranchStatus .ERROR );
151200 }
152201
153- try (BufferedReader reader = new BufferedReader (new InputStreamReader (connection .getInputStream (), Charsets .UTF_8 ))) {
154- final JsonObject obj = new Gson ().fromJson (reader , JsonObject .class );
155- switch (obj .get ("status" ).getAsString ()) {
156- case "identical" : {
157- return new RemoteVersion (BranchStatus .IDENTICAL , 0 );
158- }
159- case "ahead" : {
160- return new RemoteVersion (BranchStatus .AHEAD , 0 );
161- }
162- case "behind" : {
163- return new RemoteVersion (BranchStatus .BEHIND , obj .get ("behind_by" ).getAsInt ());
164- }
165- case "diverged" : {
166- return new RemoteVersion (BranchStatus .DIVERGED , obj .get ("behind_by" ).getAsInt ());
167- }
168- default : {
169- return new RemoteVersion (BranchStatus .UNKNOWN );
170- }
171- }
172- } catch (JsonSyntaxException | NumberFormatException e ) {
173- e .printStackTrace ();
174- return new RemoteVersion (BranchStatus .ERROR );
175- }
202+ return tryProcessDistance (connection );
176203 } catch (IOException e ) {
177204 e .printStackTrace ();
178205 return new RemoteVersion (BranchStatus .ERROR );
0 commit comments