From fb6f9682bd5e91f5d66760f855501ff73ada2e7e Mon Sep 17 00:00:00 2001 From: Max Weber Date: Thu, 24 Mar 2022 13:55:40 -0600 Subject: [PATCH] rl-client: open FatalErrorDialog early during outages --- .../java/net/runelite/client/RuneLite.java | 4 +- .../runelite/client/RuneLiteProperties.java | 6 +++ .../net/runelite/client/RuntimeConfig.java | 33 ++++++++++++++ .../runelite/client/RuntimeConfigLoader.java | 18 +++++++- .../net/runelite/client/rs/ClientLoader.java | 44 +++++++++++++++++-- .../runelite/client/ui/FatalErrorDialog.java | 21 +++++---- .../net/runelite/client/runelite.properties | 3 +- 7 files changed, 115 insertions(+), 14 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/RuneLite.java b/runelite-client/src/main/java/net/runelite/client/RuneLite.java index c970428798..538121bc92 100644 --- a/runelite-client/src/main/java/net/runelite/client/RuneLite.java +++ b/runelite-client/src/main/java/net/runelite/client/RuneLite.java @@ -228,8 +228,8 @@ public class RuneLite try { - final ClientLoader clientLoader = new ClientLoader(okHttpClient, options.valueOf(updateMode), (String) options.valueOf("jav_config")); final RuntimeConfigLoader runtimeConfigLoader = new RuntimeConfigLoader(okHttpClient); + final ClientLoader clientLoader = new ClientLoader(okHttpClient, options.valueOf(updateMode), runtimeConfigLoader, (String) options.valueOf("jav_config")); new Thread(() -> { @@ -247,6 +247,7 @@ public class RuneLite { SwingUtilities.invokeLater(() -> new FatalErrorDialog("Developers should enable assertions; Add `-ea` to your JVM arguments`") + .addHelpButtons() .addBuildingGuide() .open()); return; @@ -282,6 +283,7 @@ public class RuneLite log.error("Failure during startup", e); SwingUtilities.invokeLater(() -> new FatalErrorDialog("RuneLite has encountered an unexpected error during startup.") + .addHelpButtons() .open()); } finally diff --git a/runelite-client/src/main/java/net/runelite/client/RuneLiteProperties.java b/runelite-client/src/main/java/net/runelite/client/RuneLiteProperties.java index 1bead1101c..84f2c1ff7c 100644 --- a/runelite-client/src/main/java/net/runelite/client/RuneLiteProperties.java +++ b/runelite-client/src/main/java/net/runelite/client/RuneLiteProperties.java @@ -49,6 +49,7 @@ public class RuneLiteProperties private static final String PLUGINHUB_VERSION = "runelite.pluginhub.version"; private static final String API_BASE = "runelite.api.base"; private static final String RUNELITE_CONFIG = "runelite.config"; + private static final String OSRS_TWITTER_LINK = "runelite.osrstwitter.link"; @Getter(AccessLevel.PACKAGE) private static final Properties properties = new Properties(); @@ -136,4 +137,9 @@ public class RuneLiteProperties { return properties.getProperty(RUNELITE_CONFIG); } + + public static String getOSRSTwitterLink() + { + return properties.getProperty(OSRS_TWITTER_LINK); + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/RuntimeConfig.java b/runelite-client/src/main/java/net/runelite/client/RuntimeConfig.java index 0d41a3573c..fc7fdb4492 100644 --- a/runelite-client/src/main/java/net/runelite/client/RuntimeConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/RuntimeConfig.java @@ -24,13 +24,46 @@ */ package net.runelite.client; +import com.google.common.base.Strings; import java.util.Collections; import java.util.Map; +import javax.swing.SwingUtilities; import lombok.Data; +import net.runelite.client.ui.FatalErrorDialog; +import net.runelite.client.util.LinkBrowser; @Data public class RuntimeConfig { private Map props = Collections.emptyMap(); private Map sysProps = Collections.emptyMap(); + + private String outageMessage; + private Map outageLinks; + + public boolean showOutageMessage() + { + if (Strings.isNullOrEmpty(getOutageMessage())) + { + return false; + } + + SwingUtilities.invokeLater(() -> + { + FatalErrorDialog fed = new FatalErrorDialog(getOutageMessage()); + if (getOutageLinks() != null) + { + for (Map.Entry e : getOutageLinks().entrySet()) + { + fed.addButton(e.getKey(), () -> LinkBrowser.browse(e.getValue())); + } + } + else + { + fed.addButton("OSRS Twitter", () -> LinkBrowser.browse(RuneLiteProperties.getOSRSTwitterLink())); + } + fed.open(); + }); + return true; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/RuntimeConfigLoader.java b/runelite-client/src/main/java/net/runelite/client/RuntimeConfigLoader.java index aa82fe44dc..470c1f93e7 100644 --- a/runelite-client/src/main/java/net/runelite/client/RuntimeConfigLoader.java +++ b/runelite-client/src/main/java/net/runelite/client/RuntimeConfigLoader.java @@ -31,7 +31,10 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.function.Supplier; +import javax.annotation.Nullable; import lombok.extern.slf4j.Slf4j; import net.runelite.http.api.RuneLiteAPI; import okhttp3.Call; @@ -41,7 +44,7 @@ import okhttp3.Request; import okhttp3.Response; @Slf4j -class RuntimeConfigLoader implements Supplier +public class RuntimeConfigLoader implements Supplier { private final OkHttpClient okHttpClient; private final CompletableFuture configFuture; @@ -66,6 +69,19 @@ class RuntimeConfigLoader implements Supplier } } + @Nullable + public RuntimeConfig tryGet() + { + try + { + return configFuture.get(0, TimeUnit.SECONDS); + } + catch (InterruptedException | ExecutionException | TimeoutException e) + { + return null; + } + } + private CompletableFuture fetch() { CompletableFuture future = new CompletableFuture<>(); diff --git a/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java b/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java index 108cd7db02..943ab57886 100644 --- a/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java +++ b/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java @@ -61,6 +61,8 @@ import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; import net.runelite.client.RuneLite; import net.runelite.client.RuneLiteProperties; +import net.runelite.client.RuntimeConfig; +import net.runelite.client.RuntimeConfigLoader; import static net.runelite.client.rs.ClientUpdateCheckMode.AUTO; import static net.runelite.client.rs.ClientUpdateCheckMode.NONE; import static net.runelite.client.rs.ClientUpdateCheckMode.VANILLA; @@ -75,7 +77,7 @@ import okhttp3.Request; import okhttp3.Response; @Slf4j -@SuppressWarnings("deprecation") +@SuppressWarnings({"deprecation", "removal"}) public class ClientLoader implements Supplier { private static final int NUM_ATTEMPTS = 6; @@ -87,16 +89,18 @@ public class ClientLoader implements Supplier private final ClientConfigLoader clientConfigLoader; private ClientUpdateCheckMode updateCheckMode; private final WorldSupplier worldSupplier; + private final RuntimeConfigLoader runtimeConfigLoader; private final String javConfigUrl; private Object client; - public ClientLoader(OkHttpClient okHttpClient, ClientUpdateCheckMode updateCheckMode, String javConfigUrl) + public ClientLoader(OkHttpClient okHttpClient, ClientUpdateCheckMode updateCheckMode, RuntimeConfigLoader runtimeConfigLoader, String javConfigUrl) { this.okHttpClient = okHttpClient; this.clientConfigLoader = new ClientConfigLoader(okHttpClient); this.updateCheckMode = updateCheckMode; this.worldSupplier = new WorldSupplier(okHttpClient); + this.runtimeConfigLoader = runtimeConfigLoader; this.javConfigUrl = javConfigUrl; } @@ -176,12 +180,19 @@ public class ClientLoader implements Supplier return rs; } + catch (OutageException e) + { + return e; + } catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException | VerificationException | SecurityException e) { log.error("Error loading RS!", e); - SwingUtilities.invokeLater(() -> FatalErrorDialog.showNetErrorWindow("loading the client", e)); + if (!checkOutages()) + { + SwingUtilities.invokeLater(() -> FatalErrorDialog.showNetErrorWindow("loading the client", e)); + } return e; } } @@ -206,6 +217,10 @@ public class ClientLoader implements Supplier catch (IOException e) { log.info("Failed to get jav_config from host \"{}\" ({})", url.host(), e.getMessage()); + if (checkOutages()) + { + throw new OutageException(e); + } if (!javConfigUrl.equals(RuneLiteProperties.getJavConfig())) { @@ -405,6 +420,10 @@ public class ClientLoader implements Supplier catch (IOException e) { log.warn("Failed to download gamepack from \"{}\"", url, e); + if (checkOutages()) + { + throw new OutageException(e); + } // With fallback config do 1 attempt (there are no additional urls to try) if (!javConfigUrl.equals(RuneLiteProperties.getJavConfig()) || config.isFallback() || attempt >= NUM_ATTEMPTS) @@ -430,6 +449,7 @@ public class ClientLoader implements Supplier SwingUtilities.invokeLater(() -> new FatalErrorDialog("The client-patch is missing from the classpath. If you are building " + "the client you need to re-run maven") + .addHelpButtons() .addBuildingGuide() .open()); throw new NullPointerException(); @@ -603,4 +623,22 @@ public class ClientLoader implements Supplier verifyJarEntry(je, chains); } } + + private static class OutageException extends RuntimeException + { + private OutageException(Throwable cause) + { + super(cause); + } + } + + private boolean checkOutages() + { + RuntimeConfig rtc = runtimeConfigLoader.tryGet(); + if (rtc != null) + { + return rtc.showOutageMessage(); + } + return false; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/FatalErrorDialog.java b/runelite-client/src/main/java/net/runelite/client/ui/FatalErrorDialog.java index 23591f8dcf..aadea93aec 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/FatalErrorDialog.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/FatalErrorDialog.java @@ -137,13 +137,6 @@ public class FatalErrorDialog extends JDialog rightColumn.setBackground(ColorScheme.DARK_GRAY_COLOR); rightColumn.setMaximumSize(new Dimension(200, Integer.MAX_VALUE)); - addButton("Open logs folder", () -> - { - LinkBrowser.open(RuneLite.LOGS_DIR.toString()); - }); - addButton("Get help on Discord", () -> LinkBrowser.browse(RuneLiteProperties.getDiscordInvite())); - addButton("Troubleshooting steps", () -> LinkBrowser.browse(RuneLiteProperties.getTroubleshootingLink())); - pane.add(rightColumn, BorderLayout.EAST); } @@ -193,6 +186,13 @@ public class FatalErrorDialog extends JDialog return this; } + public FatalErrorDialog addHelpButtons() + { + return addButton("Open logs folder", () -> LinkBrowser.open(RuneLite.LOGS_DIR.toString())) + .addButton("Get help on Discord", () -> LinkBrowser.browse(RuneLiteProperties.getDiscordInvite())) + .addButton("Troubleshooting steps", () -> LinkBrowser.browse(RuneLiteProperties.getTroubleshootingLink())); + } + public FatalErrorDialog addBuildingGuide() { return addButton("Building guide", () -> LinkBrowser.browse(RuneLiteProperties.getBuildingLink())); @@ -205,6 +205,7 @@ public class FatalErrorDialog extends JDialog new FatalErrorDialog("RuneLite was unable to verify the security of its connection to the internet while " + action + ". You may have a misbehaving antivirus, internet service provider, a proxy, or an incomplete" + " java installation.") + .addHelpButtons() .open(); return; } @@ -213,6 +214,7 @@ public class FatalErrorDialog extends JDialog { new FatalErrorDialog("RuneLite is unable to connect to a required server while " + action + ". " + "Please check your internet connection") + .addHelpButtons() .open(); return; } @@ -222,11 +224,14 @@ public class FatalErrorDialog extends JDialog new FatalErrorDialog("RuneLite is unable to resolve the address of a required server while " + action + ". " + "Your DNS resolver may be misconfigured, pointing to an inaccurate resolver, or your internet connection may " + "be down. ") + .addHelpButtons() .addButton("Change your DNS resolver", () -> LinkBrowser.browse(RuneLiteProperties.getDNSChangeLink())) .open(); return; } - new FatalErrorDialog("RuneLite encountered a fatal error while " + action + ".").open(); + new FatalErrorDialog("RuneLite encountered a fatal error while " + action + ".") + .addHelpButtons() + .open(); } } diff --git a/runelite-client/src/main/resources/net/runelite/client/runelite.properties b/runelite-client/src/main/resources/net/runelite/client/runelite.properties index ae3ba68c2b..601193633f 100644 --- a/runelite-client/src/main/resources/net/runelite/client/runelite.properties +++ b/runelite-client/src/main/resources/net/runelite/client/runelite.properties @@ -19,4 +19,5 @@ runelite.api.base=https://api.runelite.net/runelite-${project.version} runelite.session=https://api.runelite.net/session runelite.static.base=https://static.runelite.net runelite.ws=https://api.runelite.net/ws -runelite.config=https://static.runelite.net/config.json \ No newline at end of file +runelite.config=https://static.runelite.net/config.json +runelite.osrstwitter.link=https://twitter.com/OldSchoolRS \ No newline at end of file