Skip to content

Commit

Permalink
Roughly finished stage 0 and stage 1
Browse files Browse the repository at this point in the history
  • Loading branch information
Candicey authored and Candicey committed Jul 27, 2024
1 parent 3f99b32 commit 6e5a5bb
Show file tree
Hide file tree
Showing 17 changed files with 330 additions and 132 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
@Getter
public abstract class LoaderBase implements ILoader {
protected static final String UNKNOWN_VERSION = "0.0.0+unknown";
private final @NotNull String name;
private final @NotNull String version;
private final @NotNull @Getter String name;
private final @NotNull @Getter String version;
protected final @NotNull Capabilities capabilities;

protected final org.apache.logging.log4j.Logger logger;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package org.polyfrost.oneconfig.loader.utils;

import lombok.extern.log4j.Log4j2;
import org.apache.logging.log4j.LogManager;
import org.jetbrains.annotations.NotNull;
import org.polyfrost.oneconfig.loader.ILoader;
import org.polyfrost.oneconfig.loader.IMetaHolder;
import lombok.extern.log4j.Log4j2;
import org.jetbrains.annotations.NotNull;

import javax.swing.*;
import java.awt.*;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
Expand All @@ -30,6 +31,18 @@ private IOUtils() {
throw new IllegalStateException("This class cannot be instantiated.");
}

public static void readInto(InputStream input, OutputStream output) throws IOException {
readInto(input, output, 1024);

This comment has been minimized.

Copy link
@xtrm-en

xtrm-en Jul 27, 2024

Member

nitpick: This should be 8192

This comment has been minimized.

Copy link
@pauliesnug

pauliesnug Jul 27, 2024

Member

you should be 8192

}

public static void readInto(InputStream input, OutputStream output, int bufferSize) throws IOException {
byte[] buffer = new byte[bufferSize];
int bytesRead;
while ((bytesRead = input.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
}
}

public static byte[] readAllBytes(InputStream inputStream) throws IOException {
return readNBytes(inputStream, Integer.MAX_VALUE);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.polyfrost.oneconfig.loader.stage1.util;
package org.polyfrost.oneconfig.loader.utils;

import java.util.function.Supplier;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,11 @@ public class RequestHelper {
private static IMetaHolder metaHolder;
private static SSLSocketFactory sslSocketFactory;

protected URLConnection establishConnection(URL url) throws IOException {
public URLConnection establishConnection(URL url) throws IOException {
return establishConnection(url, "application/json");
}

protected URLConnection establishConnection(URL url, String requestedType) throws IOException {
public URLConnection establishConnection(URL url, String requestedType) throws IOException {
URLConnection connection = url.openConnection();
if (connection instanceof HttpsURLConnection) {
((HttpsURLConnection) connection).setSSLSocketFactory(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.polyfrost.oneconfig.loader.stage1.util;
package org.polyfrost.oneconfig.loader.utils;

import lombok.Data;
import org.jetbrains.annotations.Nullable;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package org.polyfrost.oneconfig.loader.stage0;

import net.minecraft.launchwrapper.Launch;
import org.polyfrost.oneconfig.loader.ILoader;
import org.polyfrost.oneconfig.loader.utils.EnumEntrypoint;
import lombok.Data;
import net.minecraft.launchwrapper.Launch;
import net.minecraft.launchwrapper.LaunchClassLoader;
import org.jetbrains.annotations.NotNull;
import org.polyfrost.oneconfig.loader.ILoader;
import org.polyfrost.oneconfig.loader.utils.EnumEntrypoint;

import java.net.URL;
import java.nio.file.Path;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package org.polyfrost.oneconfig.loader.stage0;

import org.polyfrost.oneconfig.loader.ILoader;
import net.minecraft.launchwrapper.ITweaker;
import net.minecraft.launchwrapper.LaunchClassLoader;
import org.polyfrost.oneconfig.loader.ILoader;

import java.io.File;
import java.util.List;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
package org.polyfrost.oneconfig.loader.stage0;

import lombok.SneakyThrows;
import org.polyfrost.oneconfig.loader.IMetaHolder;
import org.polyfrost.oneconfig.loader.LoaderBase;
import org.polyfrost.oneconfig.loader.utils.IOUtils;
import org.polyfrost.oneconfig.loader.utils.RequestHelper;
import org.polyfrost.oneconfig.loader.utils.XDG;

import javax.swing.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.net.URLConnection;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.Arrays;
import java.util.function.Supplier;
import java.util.jar.Attributes;
import java.util.jar.Manifest;

/**
* The first stage of the OneConfig Loader.
Expand All @@ -31,6 +35,8 @@ public class Stage0Loader extends LoaderBase {

private static final String STAGE1_CLASS_NAME = "org.polyfrost.oneconfig.loader.stage1.Stage1Loader";

private final Attributes manifestAttributes;

Stage0Loader(Capabilities capabilities) {
super(
"stage0",
Expand All @@ -39,20 +45,17 @@ public class Stage0Loader extends LoaderBase {
),
capabilities
);
}

/*private static final String TEST_FILE_PATH =
"/home/x/Work/Polyfrost/test/build/libs/test-1.0-SNAPSHOT.jar";*/
try {
this.manifestAttributes = new Manifest(this.getClass().getResourceAsStream("/META-INF/MANIFEST.MF")).getMainAttributes();

This comment has been minimized.

Copy link
@xtrm-en

xtrm-en Jul 27, 2024

Member

The Manifest attributes should be provided by the stage1's downloaded/cached jar, so that the target class isn't hardcoded in the embedded stage0

} catch (IOException e) {
throw new RuntimeException(e);
}
}

@SneakyThrows
@Override
public void load() {
/*capabilities.appendToClassPath(
false,
new File(TEST_FILE_PATH).toURI().toURL()
);*/
// Class<?> testingClass = capabilities.getClassLoader().loadClass("me.xtrm.test.Testing2");
// testingClass.getMethod("hi").invoke(null);
JOptionPane.showMessageDialog(null, "Loading hook");

// fetch settings
Expand All @@ -61,106 +64,57 @@ public void load() {

// Fetch stage1 version info
logger.info("Fetching stage1 version info");
URL stage1JarUrl = buildMavenJarArtifactUrlPath(stage1Version, ".jar", "org", "polyfrost", "oneconfig", "loader", "stage1");
// JsonObject stage1MavenJson = (JsonObject) new JsonParser().parse(getString(stage1JarUrl.toString(), DEF_AGENT, 5000, true));
Supplier<String> stage1JarUrl = () -> MAVEN_URL + MAVEN_REPO + "/org/polyfrost/oneconfig/loader/stage1/" + stage1Version + "Stage1.jar";

This comment has been minimized.

Copy link
@xtrm-en

xtrm-en Jul 27, 2024

Member

This realistically doesn't need to be a Supplier


// Lookup stage1 in cache, handle downloading
logger.info("Getting stage1 from cache");
File stage1Jar = lookupStage1CacheOrDownload(stage1Version, stage1JarUrl.toString());
File stage1Jar = lookupStage1CacheOrDownload(stage1Version, stage1JarUrl);

// Load in classloader as a library
logger.info("Loading stage1 as a library");
capabilities.appendToClassPath(false, stage1Jar.toURI().toURL());

// Delegate loading to stage1
logger.info("GO");

Class<?> stage1Class = capabilities.getClassLoader().loadClass(STAGE1_CLASS_NAME);
Class<?> stage1Class = capabilities.getClassLoader().loadClass(manifestAttributes.getValue("Stage1-Class"));
Object stage1Instance = stage1Class.getDeclaredConstructor(Capabilities.class).newInstance(capabilities);
stage1Class.getDeclaredMethod("load").invoke(stage1Instance);
}

private String fetchStage1Version() {
// TODO: Change the way to fetch version later
String version = System.getProperty("oneconfig.stage0.version");
return version;
}

private File lookupStage1CacheOrDownload(String version, String downloadUrl) {
File cache = new File("./OneConfig/cache/OneConfigLoader/stage1/OneConfigLoader-stage1-" + version + ".jar");
if (!cache.exists()) {
cache.getParentFile().mkdirs();
downloadFile(downloadUrl, cache.toPath());
}

return cache;
String value = manifestAttributes.getValue("OneConfig-Stage1-Version");

This comment has been minimized.

Copy link
@xtrm-en

xtrm-en Jul 27, 2024

Member

Try and keep your properties/attributes in the same naming convention (with/without the OneConfig- prefix)

This comment has been minimized.

Copy link
@xtrm-en

xtrm-en Jul 27, 2024

Member

Also the version for stage1 should always be latest, or overidden by a system property

This comment has been minimized.

Copy link
@Monmcgt

Monmcgt Jul 28, 2024

Also the version for stage1 should always be latest, or overidden by a system property

that means it needs to fetch the API every launch?

return value != null ? value : System.getProperty("oneconfig.stage0.version");
}

public URL buildMavenJarArtifactUrlPath(String version, String extension, String... path) {
StringBuilder stringBuilder = new StringBuilder(MAVEN_URL);
stringBuilder.append(MAVEN_REPO);

for (String s : path) {
stringBuilder.append('/');
stringBuilder.append(s);
}

stringBuilder.append(version);

stringBuilder.append('/');
stringBuilder.append(path[path.length - 1]);
stringBuilder.append('-');
stringBuilder.append(version);
stringBuilder.append(extension);

try {
return new URL(stringBuilder.toString());
} catch (MalformedURLException e) {
logger.error("Failed to build maven artifact url from {}", String.join(", ", Arrays.asList(path)));
return null;
}
}

public String getString(String url, String userAgent, int timeout, boolean useCaches) {
StringBuilder sb = new StringBuilder();
try (BufferedReader input = new BufferedReader(new InputStreamReader(setupConnection(url, userAgent, timeout, useCaches), StandardCharsets.UTF_8))) {
String line;
while ((line = input.readLine()) != null) {
sb.append(line).append('\n');
private File lookupStage1CacheOrDownload(String version, Supplier<String> downloadUrl) {
Path cache = XDG.provideCacheDir("OneConfig").resolve("loader");
File cacheFile = cache.toFile();

This comment has been minimized.

Copy link
@xtrm-en

xtrm-en Jul 27, 2024

Member

Try and use the NIO Paths instead of Files


if (!cacheFile.exists()) {
cacheFile.getParentFile().mkdirs();

LoaderBase instance = this;
RequestHelper.tryInitialize(new IMetaHolder() {

This comment has been minimized.

Copy link
@xtrm-en

xtrm-en Jul 27, 2024

Member

I'm not sure about trying for initialization here, maybe in the stage1's main constructor.
Also, you can just pass this since ILoader extends IMetaHolder

@Override
public String getName() {
return instance.getName();
}

@Override
public String getVersion() {
return instance.getVersion();
}
});

try {
URLConnection urlConnection = new RequestHelper().establishConnection(new URL(downloadUrl.get()));

This comment has been minimized.

Copy link
@xtrm-en

xtrm-en Jul 27, 2024

Member

No need to reinstantiate RequestHelper as LoaderBase extends from it. Kind of a weird api, tell me if you'd like me to change it

This comment has been minimized.

Copy link
@Monmcgt

Monmcgt Jul 28, 2024

No need to reinstantiate RequestHelper as LoaderBase extends from it. Kind of a weird api, tell me if you'd like me to change it

LoaderBase doesn't extend RequestHelper. I think the way to initialise RequestHelper is kinda weird but it's fine I guess.

OutputStream outputStream = Files.newOutputStream(cache);
IOUtils.readInto(urlConnection.getInputStream(), outputStream);
} catch (IOException e) {
throw new RuntimeException("Failed to download Stage1 jar", e);

This comment has been minimized.

Copy link
@xtrm-en

xtrm-en Jul 27, 2024

Member

Maybe have a throws clause in this method instead of wrapping in an unchecked exception, to then be passed to ErrorHandler

This comment has been minimized.

Copy link
@Monmcgt

Monmcgt Jul 28, 2024

Personally, I don't think it's that important because the method is used only once and only in that class. Looking forward to your opinion.

}
} catch (Exception e) {
logger.error("Failed to getString from {}", url, e);
return null;
}
return sb.toString();
}

public InputStream setupConnection(String url) throws IOException {
return setupConnection(url, DEF_AGENT, 5000, false);
}

public InputStream setupConnection(String url, String userAgent, int timeout, boolean useCaches) throws IOException {
HttpURLConnection connection = ((HttpURLConnection) new URL(url).openConnection());
connection.setRequestMethod("GET");
connection.setUseCaches(useCaches);
connection.addRequestProperty("User-Agent", userAgent);
connection.setReadTimeout(timeout);
connection.setConnectTimeout(timeout);
connection.setDoOutput(true);
return connection.getInputStream();
}

public boolean downloadFile(String url, Path path, String userAgent, int timeout, boolean useCaches) {
try (BufferedInputStream in = new BufferedInputStream(setupConnection(url, userAgent, timeout, useCaches))) {
Files.copy(in, path, StandardCopyOption.REPLACE_EXISTING);
} catch (Exception e) {
logger.error("Failed to download file from {}", url, e);
return false;
}
return true;
}

public boolean downloadFile(String url, Path path) {
return downloadFile(url, path, DEF_AGENT, 5000, false);
return cacheFile;
}
}
Loading

0 comments on commit 6e5a5bb

Please sign in to comment.