diff options
| author | syeyoung <cyoung06@naver.com> | 2022-11-16 17:45:55 +0900 |
|---|---|---|
| committer | syeyoung <cyoung06@naver.com> | 2022-11-16 17:59:56 +0900 |
| commit | 60032db80aefe4a9f58b354b5a26938ed76f5c46 (patch) | |
| tree | 17a7b6e873db2ea3c40aef508134842ce69c5991 /loader/src | |
| parent | 3708965c0c22c216336f8aa28158ba22bfc03b60 (diff) | |
| parent | 241893934ef119566693165589fce0921c35e4af (diff) | |
| download | Skyblock-Dungeons-Guide-60032db80aefe4a9f58b354b5a26938ed76f5c46.tar.gz Skyblock-Dungeons-Guide-60032db80aefe4a9f58b354b5a26938ed76f5c46.tar.bz2 Skyblock-Dungeons-Guide-60032db80aefe4a9f58b354b5a26938ed76f5c46.zip | |
- Update Downloading and Signature Verification
Signed-off-by: syeyoung <cyoung06@naver.com>
Diffstat (limited to 'loader/src')
15 files changed, 681 insertions, 112 deletions
diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/DungeonsGuideReloadListener.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/DungeonsGuideReloadListener.java index 7252a9db..a96805c1 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/DungeonsGuideReloadListener.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/DungeonsGuideReloadListener.java @@ -19,6 +19,9 @@ package kr.syeyoung.dungeonsguide.launcher; public interface DungeonsGuideReloadListener { + /** + * @implNote This is very important that you GET RID OF referene to DGInterface when this is called, or else dg is gonna crash with ReferenceLeakedException. + */ public void unloadReference(); public void onLoad(DGInterface dgInterface); } diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/Main.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/Main.java index 0ec65780..e8d3e36b 100755 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/Main.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/Main.java @@ -19,7 +19,9 @@ package kr.syeyoung.dungeonsguide.launcher; import kr.syeyoung.dungeonsguide.launcher.auth.AuthManager; +import kr.syeyoung.dungeonsguide.launcher.branch.UpdateRetrieverUtil; import kr.syeyoung.dungeonsguide.launcher.exceptions.NoSuitableLoaderFoundException; +import kr.syeyoung.dungeonsguide.launcher.exceptions.NoVersionFoundException; import kr.syeyoung.dungeonsguide.launcher.exceptions.ReferenceLeakedException; import kr.syeyoung.dungeonsguide.launcher.gui.screen.GuiDisplayer; import kr.syeyoung.dungeonsguide.launcher.gui.screen.GuiLoadingError; @@ -28,6 +30,7 @@ import kr.syeyoung.dungeonsguide.launcher.gui.screen.SpecialGuiScreen; import kr.syeyoung.dungeonsguide.launcher.loader.IDGLoader; import kr.syeyoung.dungeonsguide.launcher.loader.JarLoader; import kr.syeyoung.dungeonsguide.launcher.loader.LocalLoader; +import kr.syeyoung.dungeonsguide.launcher.loader.RemoteLoader; import net.minecraft.client.Minecraft; import net.minecraft.client.resources.IReloadableResourceManager; import net.minecraftforge.common.MinecraftForge; @@ -96,7 +99,7 @@ public class Main } currentLoader = null; } - private void load(IDGLoader newLoader) throws ClassNotFoundException, InstantiationException, IllegalAccessException { + private void load(IDGLoader newLoader) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException { if (dgInterface != null) throw new IllegalStateException("DG is loaded"); dgInterface = newLoader.loadDungeonsGuide(); currentLoader = newLoader; @@ -157,7 +160,19 @@ public class Main return new JarLoader(); } else if (loader.equals("auto") ){ // remote load - throw new UnsupportedOperationException(""); // yet + String branch = System.getProperty("branch") == null ? configuration.get("loader", "remoteBranch", "$default").getString() : System.getProperty("branch"); + String version = System.getProperty("version") == null ? configuration.get("loader", "remoteVersion", "latest").getString() : System.getProperty("version"); + try { + UpdateRetrieverUtil.VersionInfo versionInfo = UpdateRetrieverUtil.getIds( + branch, + version + ); + if (versionInfo == null) throw new NoVersionFoundException(branch, version); + + return new RemoteLoader(versionInfo.getFriendlyBranchName(), versionInfo.getBranchId(), versionInfo.getUpdateId()); + } catch (IOException e) { + throw new NoVersionFoundException(branch, version, e); + } } else { throw new NoSuitableLoaderFoundException(System.getProperty("dg.loader"), configuration.get("loader", "modsource", "auto").getString()); } diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/AuthManager.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/AuthManager.java index 1613e687..c3dd747a 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/AuthManager.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/AuthManager.java @@ -3,6 +3,7 @@ package kr.syeyoung.dungeonsguide.launcher.auth; import com.google.common.base.Throwables; import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.mojang.authlib.exceptions.AuthenticationException; +import kr.syeyoung.dungeonsguide.launcher.Main; import kr.syeyoung.dungeonsguide.launcher.auth.token.*; import kr.syeyoung.dungeonsguide.launcher.events.AuthChangedEvent; import kr.syeyoung.dungeonsguide.launcher.exceptions.AuthFailedExeption; @@ -34,10 +35,6 @@ public class AuthManager { if(INSTANCE == null) INSTANCE = new AuthManager(); return INSTANCE; } - - @Setter - private String baseserverurl = "https://dungeons.guide"; - private AuthToken currentToken = new NullToken(); public AuthToken getToken() { @@ -98,9 +95,9 @@ public class AuthManager { reauthLock = true; try { - String token = DgAuthUtil.requestAuth(baseserverurl); + String token = DgAuthUtil.requestAuth(); byte[] encSecret = DgAuthUtil.checkSessionAuthenticityAndReturnEncryptedSecret(token); - currentToken = DgAuthUtil.verifyAuth(token, encSecret, baseserverurl); + currentToken = DgAuthUtil.verifyAuth(token, encSecret); MinecraftForge.EVENT_BUS.post(new AuthChangedEvent(currentToken)); if (currentToken instanceof PrivacyPolicyRequiredToken) { @@ -130,7 +127,7 @@ public class AuthManager { if (currentToken instanceof PrivacyPolicyRequiredToken) { reauthLock = true; try { - currentToken = DgAuthUtil.acceptNewPrivacyPolicy(currentToken.getToken(), baseserverurl); + currentToken = DgAuthUtil.acceptNewPrivacyPolicy(currentToken.getToken()); if (currentToken instanceof PrivacyPolicyRequiredToken) throw new PrivacyPolicyRequiredException(); } catch (IOException e) { currentToken = new FailedAuthToken(e); diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/DgAuthUtil.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/DgAuthUtil.java index f585ac20..78fc91c9 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/DgAuthUtil.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/DgAuthUtil.java @@ -5,6 +5,7 @@ import com.google.gson.JsonParser; import com.mojang.authlib.GameProfile; import com.mojang.authlib.exceptions.AuthenticationException; import com.mojang.authlib.minecraft.MinecraftSessionService; +import kr.syeyoung.dungeonsguide.launcher.Main; import kr.syeyoung.dungeonsguide.launcher.auth.token.AuthToken; import kr.syeyoung.dungeonsguide.launcher.auth.token.DGAuthToken; import kr.syeyoung.dungeonsguide.launcher.auth.token.PrivacyPolicyRequiredToken; @@ -52,14 +53,16 @@ public class DgAuthUtil { ); } catch (Exception e) { throw new ResponseParsingException(payload, e.getMessage()); + } finally { + toRead.close(); } } - public static String requestAuth(String baseurl) throws IOException { + public static String requestAuth() throws IOException { GameProfile profile = Minecraft.getMinecraft().getSession().getProfile(); - HttpsURLConnection connection = (HttpsURLConnection) new URL(baseurl + "/auth/requestAuth").openConnection(); + HttpsURLConnection connection = (HttpsURLConnection) new URL(Main.DOMAIN + "/auth/requestAuth").openConnection(); connection.setRequestProperty("User-Agent", "DungeonsGuide/1.0"); connection.setRequestProperty("Content-Type", "application/json"); connection.setRequestMethod("POST"); @@ -96,8 +99,8 @@ public class DgAuthUtil { return result; } - public static AuthToken verifyAuth(String tempToken, byte[] encSecret, String baseurl) throws IOException { - HttpsURLConnection urlConnection = (HttpsURLConnection) new URL(baseurl + "/auth/authenticate").openConnection(); + public static AuthToken verifyAuth(String tempToken, byte[] encSecret) throws IOException { + HttpsURLConnection urlConnection = (HttpsURLConnection) new URL(Main.DOMAIN + "/auth/authenticate").openConnection(); urlConnection.setRequestMethod("POST"); urlConnection.setRequestProperty("User-Agent", "DungeonsGuide/1.0"); urlConnection.setRequestProperty("Content-Type", "application/json"); @@ -120,8 +123,8 @@ public class DgAuthUtil { } } - public static AuthToken acceptNewPrivacyPolicy(String tempToken, String baseurl) throws IOException { - HttpsURLConnection urlConnection = (HttpsURLConnection) new URL(baseurl + "/auth/acceptPrivacyPolicy").openConnection(); + public static AuthToken acceptNewPrivacyPolicy(String tempToken) throws IOException { + HttpsURLConnection urlConnection = (HttpsURLConnection) new URL(Main.DOMAIN + "/auth/acceptPrivacyPolicy").openConnection(); urlConnection.setRequestMethod("POST"); urlConnection.setRequestProperty("User-Agent", "DungeonsGuide/1.0"); urlConnection.setRequestProperty("Content-Type", "application/json"); diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/branch/UpdateRetrieverUtil.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/branch/UpdateRetrieverUtil.java new file mode 100644 index 00000000..fe7e54dd --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/branch/UpdateRetrieverUtil.java @@ -0,0 +1,182 @@ +package kr.syeyoung.dungeonsguide.launcher.branch; + +import kr.syeyoung.dungeonsguide.launcher.Main; +import kr.syeyoung.dungeonsguide.launcher.auth.DGResponse; +import kr.syeyoung.dungeonsguide.launcher.exceptions.AssetNotFoundException; +import kr.syeyoung.dungeonsguide.launcher.exceptions.NoVersionFoundException; +import kr.syeyoung.dungeonsguide.launcher.exceptions.ResponseParsingException; +import lombok.Builder; +import lombok.Data; +import org.apache.commons.io.IOUtils; +import org.json.JSONArray; +import org.json.JSONObject; + +import javax.net.ssl.HttpsURLConnection; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.ProtocolException; +import java.net.URL; +import java.time.Instant; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; + +public class UpdateRetrieverUtil { + private static String getResponse(HttpsURLConnection connection) throws IOException { + connection.getResponseCode(); + InputStream toRead = connection.getErrorStream(); + if (toRead == null) + toRead = connection.getInputStream(); + String payload = IOUtils.readLines(toRead).stream().collect(Collectors.joining("\n")); + return payload; + } + + public static List<UpdateBranch> getUpdateBranches() throws IOException { + HttpsURLConnection connection = (HttpsURLConnection) new URL(Main.DOMAIN + "/updates/").openConnection(); + connection.setRequestProperty("User-Agent", "DungeonsGuide/1.0"); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setRequestMethod("GET"); + connection.setDoInput(true); + connection.setDoOutput(true); + + JSONArray jsonArray = new JSONArray(getResponse(connection)); + return jsonArray.toList() + .stream() + .map(a -> (JSONObject)a) + .map(a -> { + UpdateBranch updateBranch = new UpdateBranch(); + updateBranch.setId(a.getLong("id")); + updateBranch.setName(a.getString("name")); + updateBranch.setMetadata(a.getJSONObject("metadata")); + return updateBranch; + }).collect(Collectors.toList()); + } + + public static List<Update> getLatestUpdates(long branchId, int page) throws IOException { + HttpsURLConnection connection = (HttpsURLConnection) new URL(Main.DOMAIN + "/updates/"+branchId+"/?page="+page).openConnection(); + connection.setRequestProperty("User-Agent", "DungeonsGuide/1.0"); + connection.setRequestMethod("GET"); + connection.setDoInput(true); + connection.setDoOutput(true); + + JSONArray jsonArray = new JSONArray(getResponse(connection)); + return jsonArray.toList() + .stream() + .map(a -> (JSONObject)a) + .map(a -> { + Update update = new Update(); + update.setId(a.getLong("id")); + update.setBranchId(a.getLong("branchId")); + update.setName(a.getString("name")); + update.setUpdateLog(a.getString("updateLog")); + update.setMetadata(a.getJSONObject("metadata")); + update.setAssets(a.getJSONObject("assets").getJSONArray("assets").toList().stream().map(b -> (JSONObject)b) + .map(b -> { + Update.Asset asset = new Update.Asset(); + asset.setName(b.getString("name")); + asset.setAssetId(UUID.fromString(b.getString("assetId"))); + asset.setSize(b.getLong("size")); + asset.setObjectId(b.getString("objectId")); + return asset; + }).collect(Collectors.toList())); + update.setReleaseDate(Instant.parse(a.getString("releaseDate"))); + return update; + }).collect(Collectors.toList()); + } + + public static Update getUpdate(long branchId, long updateId) throws IOException { + HttpsURLConnection connection = (HttpsURLConnection) new URL(Main.DOMAIN + "/updates/"+branchId+"/"+updateId).openConnection(); + connection.setRequestProperty("User-Agent", "DungeonsGuide/1.0"); + connection.setRequestMethod("GET"); + connection.setDoInput(true); + connection.setDoOutput(true); + + JSONObject a = new JSONObject(getResponse(connection)); + + Update update = new Update(); + update.setId(a.getLong("id")); + update.setBranchId(a.getLong("branchId")); + update.setName(a.getString("name")); + update.setUpdateLog(a.getString("updateLog")); + update.setMetadata(a.getJSONObject("metadata")); + update.setAssets(a.getJSONObject("assets").getJSONArray("assets").toList().stream().map(b -> (JSONObject)b) + .map(b -> { + Update.Asset asset = new Update.Asset(); + asset.setName(b.getString("name")); + asset.setAssetId(UUID.fromString(b.getString("assetId"))); + asset.setSize(b.getLong("size")); + asset.setObjectId(b.getString("objectId")); + return asset; + }).collect(Collectors.toList())); + update.setReleaseDate(Instant.parse(a.getString("releaseDate"))); + return update; + } + + public static InputStream downloadFile(Update update, String assetName) throws IOException { + Update.Asset asset = update.getAssets().stream().filter(a -> a.getName().equals(assetName)) + .findFirst().orElseThrow(() -> new AssetNotFoundException(update.getBranchId()+"", update.getId()+"("+update.getName()+")", assetName)); + + + HttpsURLConnection connection = (HttpsURLConnection) new URL(Main.DOMAIN + "/updates/"+update.getBranchId()+"/"+update.getId()+"/"+asset.getAssetId()).openConnection(); + connection.setRequestProperty("User-Agent", "DungeonsGuide/1.0"); + connection.setRequestMethod("GET"); + connection.setDoInput(true); + connection.setDoOutput(true); + + JSONObject result = new JSONObject(getResponse(connection)); + String url = result.getString("url"); + String method = result.getString("method"); + + connection = (HttpsURLConnection) new URL(url).openConnection(); + connection.setRequestProperty("User-Agent", "DungeonsGuide/1.0"); + connection.setRequestMethod(method); + return connection.getInputStream(); + } + + @Data @Builder + public static class VersionInfo { + String friendlyBranchName = ""; + long branchId; + String friendlyVersionName = ""; + long updateId; + } + public static VersionInfo getIds(String branch, String version) throws IOException { + long branchId = -1, updateId = -1; + UpdateBranch branch1 = null; + for (UpdateBranch updateBranch : UpdateRetrieverUtil.getUpdateBranches()) { + if (updateBranch.getName().equals(branch) || (branch.equals("$default") && + Optional.ofNullable(updateBranch.getMetadata()) + .map(a -> a.getJSONObject("additionalMeta")) + .map(a -> a.getBoolean("defaultMod")).orElse(false))) { + branchId = updateBranch.getId(); + branch1 = updateBranch; + break; + } + } + if (branchId == -1) return null; + + Update target = null; + int page = 0; + while (updateId == -1) { + List<Update> updateList = UpdateRetrieverUtil.getLatestUpdates(branchId, page++); + if (updateList == null || updateList.isEmpty()) return null; + for (Update update : updateList) { + if (update.getName().equals(version) || version.equals("latest")) { // if latest, get the first one. + updateId = update.getId(); + target = update; + break; + } + } + } + + + return VersionInfo.builder() + .branchId(branchId) + .updateId(updateId) + .friendlyBranchName(branch1.getName()) + .friendlyVersionName(target.getName()) + .build(); + } +} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/AssetNotFoundException.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/AssetNotFoundException.java new file mode 100644 index 00000000..d04608e4 --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/AssetNotFoundException.java @@ -0,0 +1,35 @@ +/* + * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod + * Copyright (C) 2021 cyoung06 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +package kr.syeyoung.dungeonsguide.launcher.exceptions; + +import lombok.Getter; + +@Getter +public class AssetNotFoundException extends RuntimeException { + private String branch; + private String version; + private String asset; + + public AssetNotFoundException(String branch, String version, String asset) { + super("No asset found: "+branch+" - "+version+" - "+asset); + this.branch = branch; + this.version = version; + this.asset = asset; + } +} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/InvalidSignatureException.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/InvalidSignatureException.java new file mode 100644 index 00000000..bda43ea4 --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/InvalidSignatureException.java @@ -0,0 +1,37 @@ +/* + * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod + * Copyright (C) 2021 cyoung06 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +package kr.syeyoung.dungeonsguide.launcher.exceptions; + +import kr.syeyoung.dungeonsguide.launcher.branch.Update; +import lombok.Getter; + +@Getter +public class InvalidSignatureException extends RuntimeException { + private Update update; + + public InvalidSignatureException(Update update, String message) { + super(message); + this.update = update; + } + + public InvalidSignatureException(Update update, Throwable t) { + super(t); + this.update = update; + } +} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/NoVersionFoundException.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/NoVersionFoundException.java new file mode 100644 index 00000000..b99d12c1 --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/NoVersionFoundException.java @@ -0,0 +1,38 @@ +/* + * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod + * Copyright (C) 2021 cyoung06 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +package kr.syeyoung.dungeonsguide.launcher.exceptions; + +import lombok.Getter; + +@Getter +public class NoVersionFoundException extends RuntimeException { + private String branch; + private String version; + + public NoVersionFoundException(String branch, String version) { + super("No version found: "+branch+" - "+version); + this.branch = branch; + this.version = version; + } + public NoVersionFoundException(String branch, String version, Throwable e) { + super("No version found: "+branch+" - "+version, e); + this.branch = branch; + this.version = version; + } +} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/ByteStreamURLHandler.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/ByteStreamURLHandler.java new file mode 100644 index 00000000..d0859076 --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/ByteStreamURLHandler.java @@ -0,0 +1,46 @@ +package kr.syeyoung.dungeonsguide.launcher.loader; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; + +public class ByteStreamURLHandler extends URLStreamHandler { + private InputStreamGenerator converter; + public ByteStreamURLHandler(InputStreamGenerator converter) { + this.converter = converter; + } + public interface InputStreamGenerator { + InputStream convert(String name); + } + + public class ByteStreamURLConnection extends URLConnection { + + /** + * Constructs a URL connection to the specified URL. A connection to + * the object referenced by the URL is not created. + * + * @param url the specified URL. + */ + protected ByteStreamURLConnection(URL url) { + super(url); + connected = false; + } + + @Override + public void connect() throws IOException { + connected = true; + } + + @Override + public InputStream getInputStream() throws IOException { + return converter.convert(url.getPath()); + } + } + + @Override + protected URLConnection openConnection(URL u) throws IOException { + return new ByteStreamURLConnection(u); + } +} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/DGClassLoader.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/DGClassLoader.java new file mode 100644 index 00000000..1fbc39b0 --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/DGClassLoader.java @@ -0,0 +1,81 @@ +package kr.syeyoung.dungeonsguide.launcher.loader; + +import sun.misc.Resource; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; + +public abstract class DGClassLoader extends ClassLoader implements ByteStreamURLHandler.InputStreamGenerator{ + public DGClassLoader(ClassLoader parent) { + super(parent); + } + + public Class<?> loadClass(String name, boolean resolve) + throws ClassNotFoundException + { + synchronized (getClassLoadingLock(name)) { + // First, check if the class has already been loaded + Class<?> c = findLoadedClass(name); + if (c == null) { + try { + if (c == null) { + long t0 = System.nanoTime(); + c = findClass(name); + + sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t0); + sun.misc.PerfCounter.getFindClasses().increment(); + } + } catch (ClassNotFoundException e) { + // ClassNotFoundException thrown if class not found + // from the non-null parent class loader + } + if (getParent() != null && c == null) { + long t0 = System.nanoTime(); + c = getParent().loadClass(name); + long t1 = System.nanoTime(); + sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); + } + } + if (resolve) { + resolveClass(c); + } + return c; + } + } + + @Override + protected Class<?> findClass(String name) throws ClassNotFoundException { + byte[] res; + try { + res = getClassBytes(name); + } catch (IOException e) { + throw new ClassNotFoundException(name, e); + } + if (res != null) { + return defineClass(name, res, 0, res.length); + } else { + throw new ClassNotFoundException(name); + } + } + + public abstract byte[] getClassBytes(String name) throws IOException; + + public URL getResource(String name) { + URL url = findResource(name); + if (url == null && getParent() != null ) { + url = getParent().getResource(name); + } + return url; + } + + private ByteStreamURLHandler urlHandler = new ByteStreamURLHandler(this); + @Override + public URL findResource(String name) { + try { + return new URL("dungeonsguide", "",0, name, urlHandler); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + } +} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/IDGLoader.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/IDGLoader.java index f5149f82..a79fdb7e 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/IDGLoader.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/IDGLoader.java @@ -21,8 +21,10 @@ package kr.syeyoung.dungeonsguide.launcher.loader; import kr.syeyoung.dungeonsguide.launcher.DGInterface; import kr.syeyoung.dungeonsguide.launcher.exceptions.ReferenceLeakedException; +import java.io.IOException; + public interface IDGLoader { - DGInterface loadDungeonsGuide() throws InstantiationException, IllegalAccessException, ClassNotFoundException; + DGInterface loadDungeonsGuide() throws InstantiationException, IllegalAccessException, ClassNotFoundException, IOException; DGInterface getInstance(); void unloadDungeonsGuide() throws ReferenceLeakedException; diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/JarLoader.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/JarLoader.java index 6baee0f3..fa86054d 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/JarLoader.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/JarLoader.java @@ -21,7 +21,12 @@ package kr.syeyoung.dungeonsguide.launcher.loader; import kr.syeyoung.dungeonsguide.launcher.DGInterface; import kr.syeyoung.dungeonsguide.launcher.Main; import kr.syeyoung.dungeonsguide.launcher.exceptions.ReferenceLeakedException; +import org.apache.commons.io.IOUtils; +import sun.misc.Resource; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.io.InputStream; import java.lang.ref.PhantomReference; import java.lang.ref.Reference; @@ -29,6 +34,9 @@ import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.net.URL; import java.net.URLClassLoader; +import java.util.HashMap; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; public class JarLoader implements IDGLoader { private DGInterface dgInterface; @@ -37,60 +45,40 @@ public class JarLoader implements IDGLoader { private boolean loaded; - public static class JarClassLoader extends URLClassLoader { - public JarClassLoader(URL[] urls, ClassLoader parent) { - super(urls, parent); - } + public static class JarClassLoader extends DGClassLoader { + public JarClassLoader(ClassLoader parent, ZipInputStream zipInputStream) throws IOException { + super(parent); - @Override - protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { - - |
