From b8242eeed12216dd21d66a49c90c254a9f36ffed Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 20 May 2017 15:42:01 -0400 Subject: [PATCH] runelite-client: load vanilla client if an update has occured --- .../api/updatecheck/UpdateCheckClient.java | 68 +++++++++++++++++++ .../net/runelite/client/ClientLoader.java | 38 +++++++++-- .../net/runelite/client/ConfigLoader.java | 48 ++++++------- .../net/runelite/client/ui/ClientPanel.java | 26 +++++-- 4 files changed, 142 insertions(+), 38 deletions(-) create mode 100644 http-api/src/main/java/net/runelite/http/api/updatecheck/UpdateCheckClient.java diff --git a/http-api/src/main/java/net/runelite/http/api/updatecheck/UpdateCheckClient.java b/http-api/src/main/java/net/runelite/http/api/updatecheck/UpdateCheckClient.java new file mode 100644 index 0000000000..a233cf7900 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/updatecheck/UpdateCheckClient.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2017, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.http.api.updatecheck; + +import com.google.gson.JsonParseException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import net.runelite.http.api.RuneliteAPI; +import okhttp3.HttpUrl; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class UpdateCheckClient +{ + private static final Logger logger = LoggerFactory.getLogger(UpdateCheckClient.class); + + public boolean isOutdated() + { + HttpUrl url = RuneliteAPI.getApiBase().newBuilder() + .addPathSegment("update-check") + .build(); + + logger.debug("Built URI: {}", url); + + Request request = new Request.Builder() + .url(url) + .build(); + + try (Response response = RuneliteAPI.CLIENT.newCall(request).execute()) + { + ResponseBody body = response.body(); + + InputStream in = body.byteStream(); + return RuneliteAPI.GSON.fromJson(new InputStreamReader(in), boolean.class); + } + catch (JsonParseException | IOException ex) + { + logger.debug("Unable to update-check", ex); + return false; + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/ClientLoader.java b/runelite-client/src/main/java/net/runelite/client/ClientLoader.java index 7227d2168a..92d6f84d60 100644 --- a/runelite-client/src/main/java/net/runelite/client/ClientLoader.java +++ b/runelite-client/src/main/java/net/runelite/client/ClientLoader.java @@ -22,12 +22,12 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package net.runelite.client; import java.applet.Applet; import java.io.IOException; -import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,19 +35,47 @@ public class ClientLoader { private static final Logger logger = LoggerFactory.getLogger(ClientLoader.class); - public Applet load() throws MalformedURLException, ClassNotFoundException, IOException, InstantiationException, IllegalAccessException + public Applet loadRunelite() throws ClassNotFoundException, IOException, InstantiationException, IllegalAccessException { ConfigLoader config = new ConfigLoader(); config.fetch(); - + String initialClass = config.getProperty(ConfigLoader.INITIAL_CLASS).replace(".class", ""); + // the injected client is a runtime scoped dependency Class clientClass = this.getClass().getClassLoader().loadClass(initialClass); Applet rs = (Applet) clientClass.newInstance(); rs.setStub(new RSStub(config, rs)); - + + return rs; + } + + public Applet loadVanilla() throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException + { + ConfigLoader config = new ConfigLoader(); + + config.fetch(); + + String codebase = config.getProperty(ConfigLoader.CODEBASE); + String initialJar = config.getProperty(ConfigLoader.INITIAL_JAR); + String initialClass = config.getProperty(ConfigLoader.INITIAL_CLASS).replace(".class", ""); + + URL url = new URL(codebase + initialJar); + + // Must set parent classloader to null, or it will pull from + // this class's classloader first + URLClassLoader classloader = new URLClassLoader(new URL[] + { + url + }, null); + + Class clientClass = classloader.loadClass(initialClass); + Applet rs = (Applet) clientClass.newInstance(); + + rs.setStub(new RSStub(config, rs)); + return rs; } } diff --git a/runelite-client/src/main/java/net/runelite/client/ConfigLoader.java b/runelite-client/src/main/java/net/runelite/client/ConfigLoader.java index 896d467f59..9abf41888b 100644 --- a/runelite-client/src/main/java/net/runelite/client/ConfigLoader.java +++ b/runelite-client/src/main/java/net/runelite/client/ConfigLoader.java @@ -22,59 +22,53 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package net.runelite.client; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLConnection; import java.util.HashMap; import java.util.Map; +import net.runelite.http.api.RuneliteAPI; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; public class ConfigLoader { - private static URL configURL; - + private static final OkHttpClient CLIENT = RuneliteAPI.CLIENT; + private static final HttpUrl CONFIG_URL = HttpUrl.parse("http://oldschool.runescape.com/jav_config.ws"); // https redirects us to rs3 + public static final String CODEBASE = "codebase"; public static final String INITIAL_JAR = "initial_jar"; public static final String INITIAL_CLASS = "initial_class"; - public static final String APP_MINWIDTH = "applet_minwidth"; - public static final String APP_MINHEIGHT = "applet_minheight"; - + private final Map properties = new HashMap<>(), appletProperties = new HashMap<>(); - - static - { - try - { - configURL = new URL("http://oldschool.runescape.com/jav_config.ws"); // https redirects us to rs3 - } - catch (MalformedURLException ex) - { - ex.printStackTrace(); - } - } - + public void fetch() throws IOException { - URLConnection conn = configURL.openConnection(); - try (BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()))) + Request request = new Request.Builder() + .url(CONFIG_URL) + .build(); + + try (Response response = CLIENT.newCall(request).execute(); + BufferedReader in = new BufferedReader(new InputStreamReader(response.body().byteStream()))) { String str; - + while ((str = in.readLine()) != null) { int idx = str.indexOf('='); if (idx == -1) + { continue; + } String s = str.substring(0, idx); - + if (s.equals("param")) { str = str.substring(idx + 1); @@ -94,7 +88,7 @@ public class ConfigLoader } } } - + public String getProperty(String name) { return properties.get(name); diff --git a/runelite-client/src/main/java/net/runelite/client/ui/ClientPanel.java b/runelite-client/src/main/java/net/runelite/client/ui/ClientPanel.java index 2e5801aef1..5e04bb9e50 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/ClientPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/ClientPanel.java @@ -32,6 +32,7 @@ import javax.swing.JPanel; import net.runelite.api.Client; import net.runelite.client.ClientLoader; import net.runelite.client.RuneLite; +import net.runelite.http.api.updatecheck.UpdateCheckClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -58,23 +59,36 @@ final class ClientPanel extends JPanel ClientLoader loader = new ClientLoader(); - rs = loader.load(); + UpdateCheckClient updateCheck = new UpdateCheckClient(); + boolean isOutdated = updateCheck.isOutdated(); + if (isOutdated) + { + logger.info("Runelite is outdated - fetching vanilla client"); + rs = loader.loadVanilla(); + } + else + { + logger.debug("Runelite is up to date"); + rs = loader.loadRunelite(); + } + rs.setLayout(null); rs.init(); rs.start(); add(rs, BorderLayout.CENTER); - Client client = null; - try + if (isOutdated) { - client = new Client((net.runelite.rs.api.Client) rs); + return; } - catch (Exception ex) + + if (!(rs instanceof net.runelite.rs.api.Client)) { - logger.warn("Unable to create client", ex); + logger.error("Injected client does not implement Client!"); System.exit(-1); } + Client client = new Client((net.runelite.rs.api.Client) rs); RuneLite.setClient(client); }