From 5317e71e4456b875cad9a7e9eb195c98caf4c252 Mon Sep 17 00:00:00 2001 From: FalsePattern Date: Thu, 16 Nov 2023 13:21:35 +0100 Subject: [PATCH] Remove the update checker --- README.MD | 1 - .../impl/updates/UpdateCheckerImpl.java | 340 ------------------ .../lib/internal/proxy/CommonProxy.java | 21 -- .../lib/updates/ModUpdateInfo.java | 7 +- .../lib/updates/UpdateCheckException.java | 8 +- .../lib/updates/UpdateChecker.java | 110 +----- .../lib/updates/package-info.java | 40 +++ 7 files changed, 68 insertions(+), 459 deletions(-) delete mode 100644 src/main/java/com/falsepattern/lib/internal/impl/updates/UpdateCheckerImpl.java create mode 100644 src/main/java/com/falsepattern/lib/updates/package-info.java diff --git a/README.MD b/README.MD index 0f66d2b..58edf30 100644 --- a/README.MD +++ b/README.MD @@ -10,7 +10,6 @@ A library for 1.7.10 with lots of useful stuff, licensed under the LGPLv3 licens | [mixin](src/main/java/com/falsepattern/lib/mixin) | Mixin loader plugin boilerplate code | | [text](src/main/java/com/falsepattern/lib/text) | Better Chat and GUI text processing | | [toasts](src/main/java/com/falsepattern/lib/toasts) | The toast system from newer versions, with some extras | -| [updates](src/main/java/com/falsepattern/lib/updates) | Helper code for update checking | | [util](src/main/java/com/falsepattern/lib/util) | Additional utilities that do not fit the above categories, see below for more information | The contents of the [util](src/main/java/com/falsepattern/lib/util) package so far: diff --git a/src/main/java/com/falsepattern/lib/internal/impl/updates/UpdateCheckerImpl.java b/src/main/java/com/falsepattern/lib/internal/impl/updates/UpdateCheckerImpl.java deleted file mode 100644 index 58b08de..0000000 --- a/src/main/java/com/falsepattern/lib/internal/impl/updates/UpdateCheckerImpl.java +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Copyright (C) 2022-2023 FalsePattern - * All Rights Reserved - * - * The above copyright notice and this permission notice - * shall be included in all copies or substantial portions of the Software. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser 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 General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.falsepattern.lib.internal.impl.updates; - -import com.falsepattern.lib.internal.Internet; -import com.falsepattern.lib.internal.config.LibraryConfig; -import com.falsepattern.lib.text.FormattedText; -import com.falsepattern.lib.updates.ModUpdateInfo; -import com.falsepattern.lib.updates.UpdateCheckException; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import lombok.val; -import lombok.var; - -import net.minecraft.client.resources.I18n; -import net.minecraft.event.ClickEvent; -import net.minecraft.util.IChatComponent; -import cpw.mods.fml.common.Loader; - -import java.io.InputStreamReader; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionException; -import java.util.concurrent.atomic.AtomicReference; - -public final class UpdateCheckerImpl { - public static CompletableFuture> fetchUpdatesAsyncV2(String url) { - return CompletableFuture.supplyAsync(() -> { - try { - return fetchUpdatesV2(url); - } catch (UpdateCheckException e) { - throw new RuntimeException(e); - } - }); - } - - public static List fetchUpdatesV2(String url) throws UpdateCheckException { - try { - val modList = fetchRootListShared(url); - val result = new ArrayList(); - val installedMods = Loader.instance().getIndexedModList(); - for (val node : modList) { - if (!node.isJsonObject()) { - continue; - } - val obj = node.getAsJsonObject(); - if (!obj.has("modid")) { - continue; - } - if (!obj.has("versions")) { - continue; - } - val modid = obj.get("modid").getAsString(); - if (!installedMods.containsKey(modid)) { - continue; - } - val mod = installedMods.get(modid); - var versions = obj.get("versions"); - if (!versions.isJsonArray()) { - if (!versions.isJsonObject()) { - continue; - } - val ver = versions.getAsJsonObject(); - versions = new JsonArray(); - versions.getAsJsonArray().add(ver); - } - val parsedVersions = parseVersionSpecs(versions.getAsJsonArray()).join(); - val latestVersions = new ArrayList(); - for (val version : parsedVersions) { - val versionObj = version.getAsJsonObject(); - latestVersions.add(versionObj.get("version").getAsString()); - } - val currentVersion = mod.getVersion(); - if (latestVersions.contains(currentVersion)) { - continue; - } - val latest = parsedVersions.get(0).getAsJsonObject(); - result.add(new ModUpdateInfo(modid, - currentVersion, - latest.get("version").getAsString(), - latest.get("url").getAsString())); - } - return result; - } catch (Exception e) { - throw new UpdateCheckException("Failed to check for updates!", e); - } - } - - public static List updateListToChatMessages(String initiator, List updates) { - if (updates == null || updates.size() == 0) { - return null; - } - val updateText = new ArrayList(FormattedText.parse(I18n.format( - "falsepatternlib.chat.updatesavailable", - initiator)).toChatText()); - val mods = Loader.instance().getIndexedModList(); - for (val update : updates) { - val mod = mods.get(update.modID); - updateText.addAll(FormattedText.parse(I18n.format("falsepatternlib.chat.modname", mod.getName())) - .toChatText()); - updateText.addAll(FormattedText.parse(I18n.format("falsepatternlib.chat.currentversion", - update.currentVersion)).toChatText()); - updateText.addAll(FormattedText.parse(I18n.format("falsepatternlib.chat.latestversion", - update.latestVersion)).toChatText()); - if (!update.updateURL.isEmpty()) { - val pre = FormattedText.parse(I18n.format("falsepatternlib.chat.updateurlpre")).toChatText(); - val link = FormattedText.parse(I18n.format("falsepatternlib.chat.updateurl")).toChatText(); - val post = FormattedText.parse(I18n.format("falsepatternlib.chat.updateurlpost")).toChatText(); - pre.get(pre.size() - 1).appendSibling(link.get(0)); - link.get(link.size() - 1).appendSibling(post.get(0)); - for (val l : link) { - l.getChatStyle().setChatClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, update.updateURL)); - } - link.remove(0); - post.remove(0); - updateText.addAll(pre); - updateText.addAll(link); - updateText.addAll(post); - } - } - return updateText; - } - - private static JsonArray fetchRootListShared(String url) { - if (!LibraryConfig.ENABLE_UPDATE_CHECKER) { - throw new CompletionException(new UpdateCheckException("Update checker is disabled in config!")); - } - URL URL; - try { - URL = new URL(url); - } catch (MalformedURLException e) { - throw new CompletionException(new UpdateCheckException("Invalid URL: " + url, e)); - } - JsonElement parsed; - try { - parsed = new JsonParser().parse(Internet.download(URL).thenApply(String::new).join()); - } catch (CompletionException e) { - throw new CompletionException(new UpdateCheckException("Failed to download update checker JSON file!", - e.getCause() == null ? e : e.getCause())); - } - JsonArray modList; - if (parsed.isJsonArray()) { - modList = parsed.getAsJsonArray(); - } else { - modList = new JsonArray(); - modList.add(parsed); - } - return modList; - } - - private static String getString(JsonObject object, String entry) { - if (!object.has(entry)) { - return null; - } - val element = object.get(entry); - if (element.isJsonPrimitive() && element.getAsJsonPrimitive().isString()) { - return element.getAsString(); - } - return null; - } - - private static CompletableFuture parseVersionSpecs(JsonArray versions) { - return CompletableFuture.supplyAsync(() -> { - val result = new JsonArray(); - for (val entry : versions) { - if (!entry.isJsonObject()) { - continue; - } - val obj = entry.getAsJsonObject(); - val type = getString(obj, "type"); - if (type == null) { - continue; - } - switch (type) { - case "raw": { - val version = getString(obj, "version"); - val url = getString(obj, "updateURL"); - if (version == null || url == null) { - continue; - } - val res = new JsonObject(); - res.addProperty("version", version); - res.addProperty("url", url); - result.add(res); - } - case "github": { - val repo = getString(obj, "repo"); - if (repo == null) { - continue; - } - JsonObject response; - try { - response = parseLatestGithubVersion(repo); - } catch (MalformedURLException e) { - e.printStackTrace(); - continue; - } - if (response == null) { - continue; - } - result.add(response); - } - } - } - return result; - }); - } - - private static JsonObject parseLatestGithubVersion(String repo) throws MalformedURLException { - val parts = repo.split("/"); - if (parts.length != 2) { - return null; - } - val owner = parts[0]; - val name = parts[1]; - val response = new AtomicReference(); - val result = new JsonObject(); - Internet.connect(new URL("https://api.github.com/repos/" + owner + "/" + name + "/releases/latest"), - Internet.constructHeaders("Accept", - "application/vnd.github+json", - "X-GitHub-Api-Version", - "2022-11-28"), - (e) -> { - throw new CompletionException(e); - }, - (stream) -> { - val parser = new JsonParser(); - val json = parser.parse(new InputStreamReader(stream)); - if (!json.isJsonObject()) { - return; - } - response.set(json.getAsJsonObject()); - }); - if (response.get() == null) { - return null; - } - val payload = response.get(); - val url = getString(payload, "html_url"); - val version = getString(payload, "tag_name"); - if (version == null) { - return null; - } - result.addProperty("version", version); - result.addProperty("url", url == null ? "" : url); - return result; - } - - //region deprecated - @Deprecated - public static CompletableFuture> fetchUpdatesAsync(String url) { - return CompletableFuture.supplyAsync(() -> { - val modList = fetchRootListShared(url); - val result = new ArrayList(); - val installedMods = Loader.instance().getIndexedModList(); - for (val node : modList) { - if (!node.isJsonObject()) { - continue; - } - val obj = node.getAsJsonObject(); - if (!obj.has("modid")) { - continue; - } - if (!obj.has("latestVersion")) { - continue; - } - val modid = obj.get("modid").getAsString(); - if (!installedMods.containsKey(modid)) { - continue; - } - val mod = installedMods.get(modid); - val latestVersionsNode = obj.get("latestVersion"); - List latestVersions; - if (latestVersionsNode.isJsonPrimitive() && (latestVersionsNode.getAsJsonPrimitive().isString())) { - latestVersions = Collections.singletonList(latestVersionsNode.getAsString()); - } else if (latestVersionsNode.isJsonArray()) { - latestVersions = new ArrayList<>(); - for (val version : latestVersionsNode.getAsJsonArray()) { - if (!version.isJsonPrimitive() || !version.getAsJsonPrimitive().isString()) { - continue; - } - latestVersions.add(version.getAsString()); - } - } else { - continue; - } - val currentVersion = mod.getVersion(); - if (latestVersions.contains(currentVersion)) { - continue; - } - val updateURL = obj.has("updateURL") && obj.get("updateURL").isJsonPrimitive() && obj.get("updateURL") - .getAsJsonPrimitive() - .isString() - ? obj.get("updateURL").getAsString() : ""; - result.add(new ModUpdateInfo(modid, currentVersion, latestVersions.get(0), updateURL)); - } - return result; - }); - } - - @Deprecated - public static List fetchUpdates(String url) throws UpdateCheckException { - try { - return fetchUpdatesAsync(url).join(); - } catch (CompletionException e) { - try { - throw e.getCause(); - } catch (UpdateCheckException e1) { - throw e1; - } catch (Throwable e1) { - throw new UpdateCheckException("Failed to check for updates!", e1); - } - } - } - //endregion -} diff --git a/src/main/java/com/falsepattern/lib/internal/proxy/CommonProxy.java b/src/main/java/com/falsepattern/lib/internal/proxy/CommonProxy.java index c5219f6..6c3212a 100644 --- a/src/main/java/com/falsepattern/lib/internal/proxy/CommonProxy.java +++ b/src/main/java/com/falsepattern/lib/internal/proxy/CommonProxy.java @@ -52,29 +52,8 @@ public class CommonProxy { public void preInit(FMLPreInitializationEvent e) { CommonEventHandlerPre.registerBus(); - if (LibraryConfig.ENABLE_UPDATE_CHECKER) { - Share.LOG.info("Launching asynchronous update check."); - UpdateChecker.fetchUpdatesAsyncV2(FalsePatternLib.UPDATE_URL).thenApplyAsync(updates -> { - if (updates == null) { - updates = Collections.emptyList(); - } - if (updates.isEmpty()) { - Share.LOG.info("No updates found."); - } else { - Share.LOG.info("Found {} updates.", updates.size()); - for (val update : updates) { - update.log(Share.LOG); - } - } - return updates; - }).exceptionally(ex -> { - Share.LOG.error("Failed to check for updates!", ex); - return Collections.emptyList(); - }); - } } - @Mod.EventHandler public void init(FMLInitializationEvent e) { } diff --git a/src/main/java/com/falsepattern/lib/updates/ModUpdateInfo.java b/src/main/java/com/falsepattern/lib/updates/ModUpdateInfo.java index df0d7dc..6fc4fc1 100644 --- a/src/main/java/com/falsepattern/lib/updates/ModUpdateInfo.java +++ b/src/main/java/com/falsepattern/lib/updates/ModUpdateInfo.java @@ -20,16 +20,21 @@ */ package com.falsepattern.lib.updates; +import com.falsepattern.lib.DeprecationDetails; import com.falsepattern.lib.StableAPI; import lombok.Data; import lombok.NonNull; import org.apache.logging.log4j.Logger; /** - * Information about a new version of a mod. + * Obsolete, marked for removal. */ @Data @StableAPI(since = "0.8.0") +@DeprecationDetails(deprecatedSince = "1.0.0", + replacement = "None, the update checker system is being removed.") +@DeprecationDetails.RemovedInVersion("1.1.0") +@Deprecated public class ModUpdateInfo { @NonNull @StableAPI.Expose diff --git a/src/main/java/com/falsepattern/lib/updates/UpdateCheckException.java b/src/main/java/com/falsepattern/lib/updates/UpdateCheckException.java index 00fce9a..a8c1f1c 100644 --- a/src/main/java/com/falsepattern/lib/updates/UpdateCheckException.java +++ b/src/main/java/com/falsepattern/lib/updates/UpdateCheckException.java @@ -20,13 +20,17 @@ */ package com.falsepattern.lib.updates; +import com.falsepattern.lib.DeprecationDetails; import com.falsepattern.lib.StableAPI; /** - * Exception only thrown by methods of {@link UpdateChecker}. - * Please don't throw this in your own code, only catch/handle it. + * Obsolete, marked for removal. */ @StableAPI(since = "0.8.3") +@DeprecationDetails(deprecatedSince = "1.0.0", + replacement = "None, the update checker system is being removed.") +@DeprecationDetails.RemovedInVersion("1.1.0") +@Deprecated public class UpdateCheckException extends Exception { @StableAPI.Internal public UpdateCheckException(String message) { diff --git a/src/main/java/com/falsepattern/lib/updates/UpdateChecker.java b/src/main/java/com/falsepattern/lib/updates/UpdateChecker.java index 9cfdc37..fefc398 100644 --- a/src/main/java/com/falsepattern/lib/updates/UpdateChecker.java +++ b/src/main/java/com/falsepattern/lib/updates/UpdateChecker.java @@ -23,124 +23,46 @@ package com.falsepattern.lib.updates; import com.falsepattern.lib.DeprecationDetails; import com.falsepattern.lib.StableAPI; import com.falsepattern.lib.internal.Share; -import com.falsepattern.lib.internal.impl.updates.UpdateCheckerImpl; import net.minecraft.util.IChatComponent; +import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; +/** + * Obsolete, marked for removal. + */ @StableAPI(since = "0.8.0") +@DeprecationDetails(deprecatedSince = "1.0.0", + replacement = "None, the update checker system is being removed.") +@DeprecationDetails.RemovedInVersion("1.1.0") +@Deprecated public final class UpdateChecker { /** - * Checks for updates. The URL should be a JSON file that contains a list of mods, each with a mod ID, and one or more - * versions. The JSON file must have the following format: - *
{@code
-     *  [
-     *      {
-     *          "modid": "modid",
-     *          "versions": [
-     *              {
-     *                  ...version object...
-     *              },
-     *              {
-     *                  ...version object...
-     *              }
-     *          ]
-     *      },
-     *      {
-     *          "modid": "modid2",
-     *          "versions": {
-     *              ...version object...
-     *          },
-     *          "updateURL": "https://example.com/mods/mymod2"
-     *      },
-     *      ...etc, one json object per mod.
-     *  ]
-     * }
- * The currently supported version object formats are: - *

- * Raw version entry: - *

{@code
-     * {
-     *     "type": "raw",
-     *     "version": "1.0.0",
-     *     "updateURL": "https://example.com/mods/mymod"
-     * }
-     * }
- *

- * GitHub version entry: - *

{@code
-     * {
-     *    "type": "github",
-     *    "repo": "Example/ExampleMod"
-     * }
-     * }
- *

- * The GitHub version entry will automatically fetch the latest release from the specified repository using the GitHub API. - * - * @param url The URL to check - * - * @return A list of mods that were both available on the URL and installed + * Obsolete, marked for removal. */ @StableAPI.Expose(since = "0.11.0") public static CompletableFuture> fetchUpdatesAsyncV2(String url) { - return UpdateCheckerImpl.fetchUpdatesAsyncV2(url); + Share.deprecatedWarning(new Throwable()); + return CompletableFuture.completedFuture(Collections.emptyList()); } /** - * Same this as {@link #fetchUpdatesAsyncV2(String)}, but returns the result in a blocking fashion. - * - * @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 - * - * @throws UpdateCheckException If the update checker is disabled in config, the URL is invalid, or + * Obsolete, marked for removal. */ @StableAPI.Expose(since = "0.11.0") public static List fetchUpdatesV2(String url) throws UpdateCheckException { - return UpdateCheckerImpl.fetchUpdatesV2(url); + Share.deprecatedWarning(new Throwable()); + return Collections.emptyList(); } /** - * Formats the raw list of updates into lines of chat messages you can send to players. - * - * @param initiator Who/what/which mod did this update check - * @param updates The list of updates to convert - * - * @return A list of chat messages that can be sent to players + * Obsolete, marked for removal. */ @StableAPI.Expose public static List updateListToChatMessages(String initiator, List updates) { - return UpdateCheckerImpl.updateListToChatMessages(initiator, updates); - } - - //region deprecated - - /** - * DEPRECATED: Use the V2 API instead. This is kept for backwards compatibility. - */ - @Deprecated - @DeprecationDetails(deprecatedSince = "0.11.0", - replacement = "fetchUpdatesV2") - @DeprecationDetails.RemovedInVersion("0.13") - @StableAPI.Expose - public static List fetchUpdates(String url) throws UpdateCheckException { Share.deprecatedWarning(new Throwable()); - return UpdateCheckerImpl.fetchUpdates(url); + return Collections.emptyList(); } - - /** - * DEPRECATED: Use the V2 API instead. This is kept for backwards compatibility. - */ - @StableAPI.Expose - @Deprecated - @DeprecationDetails(deprecatedSince = "0.11.0", - replacement = "fetchUpdatesAsyncV2") - @DeprecationDetails.RemovedInVersion("0.13") - public static CompletableFuture> fetchUpdatesAsync(String url) { - Share.deprecatedWarning(new Throwable()); - return UpdateCheckerImpl.fetchUpdatesAsync(url); - } - //endregion } diff --git a/src/main/java/com/falsepattern/lib/updates/package-info.java b/src/main/java/com/falsepattern/lib/updates/package-info.java new file mode 100644 index 0000000..8e8ae48 --- /dev/null +++ b/src/main/java/com/falsepattern/lib/updates/package-info.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2022-2023 FalsePattern + * All Rights Reserved + * + * The above copyright notice and this permission notice + * shall be included in all copies or substantial portions of the Software. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser 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 General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/** + * This package used to contain a system for checking for updates to mods. + * This system is being removed, and this package is being kept for backwards compatibility. + * Reasons for removal: + * - In older versions of the mod, this used to show a message in chat when an update was available. This was annoying and + * not very useful, so it was removed. + * - In 0.12, the updates were shown only in the console, which is not very visible, so people didn't notice them. + * - The update checker system was very complicated and hard to maintain, and required externally hosted JSON files. + *

+ * For anyone who wants to implement their own update checker, don't. Nobody cares about mod updates anyway, + * they will keep playing on ancient versions of the mod no matter what you do or how many critical bugs you fix. + */ +@DeprecationDetails(deprecatedSince = "1.0.0", + replacement = "None, the update checker system is being removed.") +@DeprecationDetails.RemovedInVersion("1.1.0") +@Deprecated +package com.falsepattern.lib.updates; + +import com.falsepattern.lib.DeprecationDetails; \ No newline at end of file