From 544414a8cf406bcffb391ea912d9deeff0673f75 Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 25 Mar 2020 12:55:20 -0400 Subject: [PATCH] clientloader: use fallback config if gamepack fails to load --- .../net/runelite/client/rs/ClientLoader.java | 90 ++++++++++++------- .../java/net/runelite/client/rs/RSConfig.java | 5 ++ 2 files changed, 62 insertions(+), 33 deletions(-) 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 4309a10bbf..b52a19e937 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 @@ -49,12 +49,13 @@ import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.util.Arrays; import java.util.Collection; -import java.util.Map; import java.util.Enumeration; +import java.util.Map; import java.util.function.Supplier; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.JarInputStream; +import javax.annotation.Nonnull; import javax.swing.SwingUtilities; import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; @@ -66,9 +67,9 @@ import static net.runelite.client.rs.ClientUpdateCheckMode.VANILLA; import net.runelite.client.ui.FatalErrorDialog; import net.runelite.client.ui.SplashScreen; import net.runelite.client.util.CountingInputStream; +import net.runelite.client.util.VerificationException; import net.runelite.http.api.RuneLiteAPI; import net.runelite.http.api.worlds.World; -import net.runelite.client.util.VerificationException; import okhttp3.HttpUrl; import okhttp3.Request; import okhttp3.Response; @@ -86,7 +87,6 @@ public class ClientLoader implements Supplier private Object client = null; private WorldSupplier worldSupplier = new WorldSupplier(); - private RSConfig config; public ClientLoader(ClientUpdateCheckMode updateCheckMode) { @@ -118,7 +118,7 @@ public class ClientLoader implements Supplier try { SplashScreen.stage(0, null, "Fetching applet viewer config"); - downloadConfig(); + RSConfig config = downloadConfig(); SplashScreen.stage(.05, null, "Waiting for other clients to start"); @@ -129,7 +129,24 @@ public class ClientLoader implements Supplier FileLock flock = lockfile.lock()) { SplashScreen.stage(.05, null, "Downloading Old School RuneScape"); - updateVanilla(); + try + { + updateVanilla(config); + } + catch (IOException ex) + { + // try again with the fallback config and gamepack + if (!config.isFallback()) + { + log.warn("Unable to download game client, attempting to use fallback config", ex); + config = downloadFallbackConfig(); + updateVanilla(config); + } + else + { + throw ex; + } + } if (updateCheckMode == AUTO) { @@ -146,7 +163,7 @@ public class ClientLoader implements Supplier SplashScreen.stage(.465, "Starting", "Starting Old School RuneScape"); - Applet rs = loadClient(classLoader); + Applet rs = loadClient(config, classLoader); SplashScreen.stage(.5, null, "Starting core classes"); @@ -162,7 +179,7 @@ public class ClientLoader implements Supplier } } - private void downloadConfig() throws IOException + private RSConfig downloadConfig() throws IOException { HttpUrl url = HttpUrl.parse(RuneLiteProperties.getJavConfig()); IOException err = null; @@ -170,14 +187,14 @@ public class ClientLoader implements Supplier { try { - config = ClientConfigLoader.fetch(url); + RSConfig config = ClientConfigLoader.fetch(url); if (Strings.isNullOrEmpty(config.getCodeBase()) || Strings.isNullOrEmpty(config.getInitialJar()) || Strings.isNullOrEmpty(config.getInitialClass())) { throw new IOException("Invalid or missing jav_config"); } - return; + return config; } catch (IOException e) { @@ -192,35 +209,42 @@ public class ClientLoader implements Supplier try { - RSConfig backupConfig = ClientConfigLoader.fetch(HttpUrl.parse(RuneLiteProperties.getJavConfigBackup())); - - if (Strings.isNullOrEmpty(backupConfig.getCodeBase()) || Strings.isNullOrEmpty(backupConfig.getInitialJar()) || Strings.isNullOrEmpty(backupConfig.getInitialClass())) - { - throw new IOException("Invalid or missing jav_config"); - } - - if (Strings.isNullOrEmpty(backupConfig.getRuneLiteGamepack()) || Strings.isNullOrEmpty(backupConfig.getRuneLiteWorldParam())) - { - throw new IOException("Backup config does not have RuneLite gamepack url"); - } - - // Randomize the codebase - World world = worldSupplier.get(); - backupConfig.setCodebase("http://" + world.getAddress() + "/"); - - // Update the world applet parameter - Map appletProperties = backupConfig.getAppletProperties(); - appletProperties.put(backupConfig.getRuneLiteWorldParam(), Integer.toString(world.getId())); - - config = backupConfig; + return downloadFallbackConfig(); } catch (IOException ex) { + log.debug("error downloading backup config", ex); throw err; // use error from Jagex's servers } } - private void updateVanilla() throws IOException, VerificationException + @Nonnull + private RSConfig downloadFallbackConfig() throws IOException + { + RSConfig backupConfig = ClientConfigLoader.fetch(HttpUrl.parse(RuneLiteProperties.getJavConfigBackup())); + + if (Strings.isNullOrEmpty(backupConfig.getCodeBase()) || Strings.isNullOrEmpty(backupConfig.getInitialJar()) || Strings.isNullOrEmpty(backupConfig.getInitialClass())) + { + throw new IOException("Invalid or missing jav_config"); + } + + if (Strings.isNullOrEmpty(backupConfig.getRuneLiteGamepack()) || Strings.isNullOrEmpty(backupConfig.getRuneLiteWorldParam())) + { + throw new IOException("Backup config does not have RuneLite gamepack url"); + } + + // Randomize the codebase + World world = worldSupplier.get(); + backupConfig.setCodebase("http://" + world.getAddress() + "/"); + + // Update the world applet parameter + Map appletProperties = backupConfig.getAppletProperties(); + appletProperties.put(backupConfig.getRuneLiteWorldParam(), Integer.toString(world.getId())); + + return backupConfig; + } + + private void updateVanilla(RSConfig config) throws IOException, VerificationException { Certificate[] jagexCertificateChain = getJagexCertificateChain(); @@ -256,7 +280,7 @@ public class ClientLoader implements Supplier // Start downloading the vanilla client HttpUrl url; - if (config.getRuneLiteGamepack() != null) + if (config.isFallback()) { // If we are using the backup config, use our own gamepack and ignore the codebase url = HttpUrl.parse(config.getRuneLiteGamepack()); @@ -503,7 +527,7 @@ public class ClientLoader implements Supplier } } - private Applet loadClient(ClassLoader classLoader) throws ClassNotFoundException, IllegalAccessException, InstantiationException + private Applet loadClient(RSConfig config, ClassLoader classLoader) throws ClassNotFoundException, IllegalAccessException, InstantiationException { String initialClass = config.getInitialClass(); Class clientClass = classLoader.loadClass(initialClass); diff --git a/runelite-client/src/main/java/net/runelite/client/rs/RSConfig.java b/runelite-client/src/main/java/net/runelite/client/rs/RSConfig.java index b1c43b14e9..cf7a46ad9d 100644 --- a/runelite-client/src/main/java/net/runelite/client/rs/RSConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/rs/RSConfig.java @@ -55,6 +55,11 @@ class RSConfig return classLoaderProperties.get("initial_class").replace(".class", ""); } + boolean isFallback() + { + return getRuneLiteGamepack() != null; + } + String getRuneLiteGamepack() { return classLoaderProperties.get("runelite.gamepack");