From ed7ca483218b0a18e3c6d144b92109468adcbdcb Mon Sep 17 00:00:00 2001 From: FalsePattern <30945458+FalsePattern@users.noreply.github.com> Date: Thu, 9 Jun 2022 20:14:11 +0200 Subject: [PATCH] Begin working on the update checker Also added a config for toggling internet capabilities --- .../lib/internal/FalsePatternLib.java | 17 ++++ .../lib/internal/LibraryConfig.java | 18 ++++ .../lib/updates/ModUpdateInfo.java | 11 +++ .../lib/updates/UpdateChecker.java | 85 +++++++++++++++++++ .../assets/falsepatternlib/lang/en_US.lang | 4 + 5 files changed, 135 insertions(+) create mode 100644 src/main/java/com/falsepattern/lib/internal/LibraryConfig.java create mode 100644 src/main/java/com/falsepattern/lib/updates/ModUpdateInfo.java create mode 100644 src/main/java/com/falsepattern/lib/updates/UpdateChecker.java create mode 100644 src/main/resources/assets/falsepatternlib/lang/en_US.lang diff --git a/src/main/java/com/falsepattern/lib/internal/FalsePatternLib.java b/src/main/java/com/falsepattern/lib/internal/FalsePatternLib.java index 9548202..eb7b795 100644 --- a/src/main/java/com/falsepattern/lib/internal/FalsePatternLib.java +++ b/src/main/java/com/falsepattern/lib/internal/FalsePatternLib.java @@ -1,14 +1,20 @@ package com.falsepattern.lib.internal; +import com.falsepattern.lib.config.ConfigException; import com.falsepattern.lib.config.ConfigurationManager; import com.falsepattern.lib.util.ResourceUtil; import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; import cpw.mods.fml.common.DummyModContainer; import cpw.mods.fml.common.LoadController; +import cpw.mods.fml.common.Loader; import cpw.mods.fml.common.MetadataCollection; import cpw.mods.fml.common.event.FMLConstructionEvent; +import cpw.mods.fml.common.event.FMLInterModComms; +import cpw.mods.fml.common.event.FMLPostInitializationEvent; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; import lombok.Getter; +import lombok.SneakyThrows; import net.minecraft.launchwrapper.Launch; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -17,6 +23,7 @@ import org.apache.logging.log4j.Logger; * Utility class used by FalsePatternLib's internal code. This can change between versions without notice, so do not use * this in your code! */ +@SuppressWarnings("UnstableApiUsage") public class FalsePatternLib extends DummyModContainer { @Getter private static final Logger log = LogManager.getLogger(Tags.MODNAME); @@ -33,6 +40,16 @@ public class FalsePatternLib extends DummyModContainer { @Subscribe public void construct(FMLConstructionEvent e) { ConfigurationManager.init(); + try { + ConfigurationManager.registerConfig(LibraryConfig.class); + } catch (ConfigException ex) { + getLog().error("Failed to register " + Tags.MODNAME + " config!", ex); + } + } + + @Subscribe + public void postInit(FMLPostInitializationEvent e) { + } @SuppressWarnings("UnstableApiUsage") diff --git a/src/main/java/com/falsepattern/lib/internal/LibraryConfig.java b/src/main/java/com/falsepattern/lib/internal/LibraryConfig.java new file mode 100644 index 0000000..99a9d38 --- /dev/null +++ b/src/main/java/com/falsepattern/lib/internal/LibraryConfig.java @@ -0,0 +1,18 @@ +package com.falsepattern.lib.internal; + +import com.falsepattern.lib.config.Config; + +@Config(modid = Tags.MODID) +public class LibraryConfig { + @Config.Comment({"Used to control whether FalsePatternLib should check for outdated mods.", + "If you're building a public modpack, you should turn this off so that your users don't " + + "get nagged about outdated mods."}) + @Config.LangKey("config.falsepatternlib.updatecheck") + public static boolean ENABLE_UPDATE_CHECKER = true; + + @Config.Comment({"Used to control whether FalsePatternLib should be allowed to use the internet.", + "If this is enabled, library downloads will be blocked.", + "Note that if a mod tries to download a library that is not downloaded yet, the game will crash."}) + @Config.LangKey("config.falsepatternlib.disableinternet") + public static boolean ENABLE_LIBRARY_DOWNLOADS = true; +} diff --git a/src/main/java/com/falsepattern/lib/updates/ModUpdateInfo.java b/src/main/java/com/falsepattern/lib/updates/ModUpdateInfo.java new file mode 100644 index 0000000..2b363a0 --- /dev/null +++ b/src/main/java/com/falsepattern/lib/updates/ModUpdateInfo.java @@ -0,0 +1,11 @@ +package com.falsepattern.lib.updates; + +import lombok.Data; + +@Data +public class ModUpdateInfo { + public final String modID; + public final String currentVersion; + public final String latestVersion; + public final String updateURL; +} diff --git a/src/main/java/com/falsepattern/lib/updates/UpdateChecker.java b/src/main/java/com/falsepattern/lib/updates/UpdateChecker.java new file mode 100644 index 0000000..7a6837e --- /dev/null +++ b/src/main/java/com/falsepattern/lib/updates/UpdateChecker.java @@ -0,0 +1,85 @@ +package com.falsepattern.lib.updates; + +import com.falsepattern.lib.dependencies.DependencyLoader; +import com.falsepattern.lib.dependencies.SemanticVersion; +import com.falsepattern.lib.internal.FalsePatternLib; +import com.falsepattern.lib.internal.LibraryConfig; +import com.falsepattern.lib.internal.Tags; +import lombok.val; +import lombok.var; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.nio.file.Files; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicBoolean; + +public class UpdateChecker { + private static AtomicBoolean jsonLibraryLoaded = new AtomicBoolean(false); + private static final ExecutorService asyncExecutor = Executors.newSingleThreadExecutor((runnable) -> { + Thread thread = new Thread(runnable); + thread.setDaemon(true); + thread.setName(Tags.MODNAME + " Asynchronous Update Check Thread"); + return thread; + }); + /** + * Same this as {@link #fetchUpdates(String)}, but defers the check to a different thread. Useful for asynchronous + * update checks, if you don't want to block loading. + * @param url The URL to check + * @return A future that will contain the update info about mods that were both available on the URL and installed + */ + public static Future> fetchUpdatesAsync(String url) { + return asyncExecutor.submit(() -> fetchUpdates(url)); + } + + /** + * Checks for updates. The URL should be a JSON file that contains a list of mods, each with a mod ID, one or more + * versions, and a URL for the user to check for updates in case the current and latest versions are different. + * The JSON file must have the following format: + *
{@code
+     *  [
+     *      {
+     *          "modID": "modid",
+     *          "latestVersion": ["1.0.0", "1.0.0-foo"],
+     *          "updateURL": "https://example.com/mods/mymod"
+     *      },
+     *      {
+     *          "modID": "modid2",
+     *          "latestVersion": ["0.2.0", "0.3.0-alpha"],
+     *          "updateURL": "https://example.com/mods/mymod2"
+     *      },
+     *      ...etc, one json object per mod.
+     *  ]
+     * }
+ * @param url The URL to check + * @return A list of mods that were both available on the URL and installed + */ + public static List fetchUpdates(String url) { + if (!LibraryConfig.ENABLE_UPDATE_CHECKER) { + return null; + } + if (!jsonLibraryLoaded.get()) { + DependencyLoader.addMavenRepo("https://maven.falsepattern.com/"); + try { + DependencyLoader.builder() + .groupId("com.falsepattern") + .artifactId("json") + .minVersion(new SemanticVersion(0, 4, 0)) + .maxVersion(new SemanticVersion(0, Integer.MAX_VALUE, Integer.MAX_VALUE)) + .build(); + } catch (Exception e) { + FalsePatternLib.getLog().error("Failed to load json library for update checker!", e); + return null; + } + jsonLibraryLoaded.set(true); + } + //TODO + return null; + } +} diff --git a/src/main/resources/assets/falsepatternlib/lang/en_US.lang b/src/main/resources/assets/falsepatternlib/lang/en_US.lang new file mode 100644 index 0000000..bbe9189 --- /dev/null +++ b/src/main/resources/assets/falsepatternlib/lang/en_US.lang @@ -0,0 +1,4 @@ +config.falsepatternlib.updatecheck=Enable update checks +config.falsepatternlib.updatecheck.tooltip=Used to control whether FalsePatternLib should check for outdated mods. +config.falsepatternlib.disableinternet=FalsePatternLib Offline Mode +config.falsepatternlib.disableinternet.tooltip=Used to control whether FalsePatternLib should be allowed to use the internet. If this is enabled, update checks and library downloads will be completely blocked. \ No newline at end of file