diff options
author | nea <romangraef@gmail.com> | 2022-07-17 00:30:48 +0200 |
---|---|---|
committer | nea <romangraef@gmail.com> | 2022-07-23 14:51:13 +0200 |
commit | 23f79bb3b523f6fb67ca7d6b209841ea9e6c5f48 (patch) | |
tree | c1211e206594a64fed5ce8734a0db8e7d293c0ee | |
parent | 01ce1186f271be0fc9cd65d759bc3905392c4ca8 (diff) | |
download | NotEnoughUpdates-23f79bb3b523f6fb67ca7d6b209841ea9e6c5f48.tar.gz NotEnoughUpdates-23f79bb3b523f6fb67ca7d6b209841ea9e6c5f48.tar.bz2 NotEnoughUpdates-23f79bb3b523f6fb67ca7d6b209841ea9e6c5f48.zip |
add autoupdater (linux)
9 files changed, 590 insertions, 70 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c1913734..77726499 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -73,6 +73,7 @@ public static final int HOTFIX_VERSION_ID = 0; /* Reset the HOTFIX_VERSION_ID ba "pre_version": "0.0", /* Reset to 0.0 */ "pre_version_id": 0, /* Reset to 0 */ "update_link": "https://github.com/NotEnoughUpdates/NotEnoughUpdates/releases/tag/<VERSIONNAME>", /* Change download link to the github release */ + "update_direct": "https://github.com/NotEnoughUpdates/NotEnoughUpdates/releases/download/<VERSIONNAME>/NotEnoughUpdates-<VERSIONNAME>.jar", /* Change direct link to a direct download link */ } ``` @@ -103,7 +104,8 @@ public static final int PRE_VERSION_ID = 1; /* Increment the PRE_VERSION_ID */ "pre_update_msg": "§7§m§l--------------------§5§l[§c§lNEU§5§l]§7§m§l--------------------\n\n§7A new pre-release, v§52.0-PRE{pre_version}§7, is now available!\n ", /* Update the version name. Remove old patch notes; Optionally add in a short new patch note. */ "pre_version": "0.0", /* Set to a new string (preferably increase the major version every time, except for hotfixes on the prerelease stream) */ "pre_version_id": 0, /* Set to PRE_VERSION_ID from java */ - "update_link": "https://github.com/NotEnoughUpdates/NotEnoughUpdates/releases/tag/<VERSIONNAME>", /* Change download link to the github release */ + "pre_update_link": "https://github.com/NotEnoughUpdates/NotEnoughUpdates/releases/tag/<VERSIONNAME>", /* Change download link to the github release */ + "pre_update_direct": "https://github.com/NotEnoughUpdates/NotEnoughUpdates/releases/download/<VERSIONNAME>/NotEnoughUpdates-<VERSIONNAME>.jar", /* Change direct link to a direct download link */ } ``` @@ -135,6 +137,7 @@ public static final int HOTFIX_VERSION_ID = 1; /* Increment the HOTFIX_VERSION_I "version_id": 20100, /* Same as version */ "update_msg": "§7§m§l--------------------§6§l[§c§lNEU§6§l]§7§m§l--------------------\n\n§7A new version, v§6{version}§7, is now available!\n ", /* Update the version name. Don't remove old patch notes; Optionally add in a short new patch note. Indicate that there is a hotfix present */ "update_link": "https://github.com/NotEnoughUpdates/NotEnoughUpdates/releases/tag/<VERSIONNAME>", /* Change download link to the github release */ + "update_direct": "https://github.com/NotEnoughUpdates/NotEnoughUpdates/releases/download/<VERSIONNAME>/NotEnoughUpdates-<VERSIONNAME>.jar", /* Change direct link to a direct download link */ } ``` diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java index 8c23aa60..b1f7c267 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java @@ -55,6 +55,7 @@ import io.github.moulberry.notenoughupdates.miscfeatures.SunTzu; import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.CustomBiomes; import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.CustomBlockSounds; import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.DwarvenMinesTextures; +import io.github.moulberry.notenoughupdates.miscfeatures.updater.AutoUpdater; import io.github.moulberry.notenoughupdates.miscgui.CalendarOverlay; import io.github.moulberry.notenoughupdates.miscgui.InventoryStorageSelector; import io.github.moulberry.notenoughupdates.miscgui.SignCalculator; @@ -109,7 +110,7 @@ import java.util.Set; public class NotEnoughUpdates { public static final String MODID = "notenoughupdates"; public static final String VERSION = "2.1.0-REL"; - public static final int VERSION_ID = 20200; + public static final int VERSION_ID = 20100; public static final int PRE_VERSION_ID = 0; public static final int HOTFIX_VERSION_ID = 1; /** @@ -170,6 +171,7 @@ public class NotEnoughUpdates { public Commands commands; public boolean packDevEnabled = false; public Color[][] colourMap = null; + public AutoUpdater autoUpdater = new AutoUpdater(this); private File configFile; private long lastChatMessage = 0; private long secondLastChatMessage = 0; diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/Commands.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/Commands.java index b152bc09..917185ab 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/commands/Commands.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/Commands.java @@ -19,6 +19,7 @@ package io.github.moulberry.notenoughupdates.commands; +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; import io.github.moulberry.notenoughupdates.commands.dev.DevTestCommand; import io.github.moulberry.notenoughupdates.commands.dev.DiagCommand; import io.github.moulberry.notenoughupdates.commands.dev.DungeonWinTestCommand; @@ -41,6 +42,7 @@ import io.github.moulberry.notenoughupdates.commands.misc.CalculatorCommand; import io.github.moulberry.notenoughupdates.commands.misc.CalendarCommand; import io.github.moulberry.notenoughupdates.commands.misc.CosmeticsCommand; import io.github.moulberry.notenoughupdates.commands.misc.CustomizeCommand; +import io.github.moulberry.notenoughupdates.commands.misc.UpdateCommand; import io.github.moulberry.notenoughupdates.commands.profile.CataCommand; import io.github.moulberry.notenoughupdates.commands.profile.PeekCommand; import io.github.moulberry.notenoughupdates.commands.profile.PvCommand; @@ -94,6 +96,7 @@ public class Commands { ClientCommandHandler.instance.registerCommand(new AhCommand()); ClientCommandHandler.instance.registerCommand(new CalculatorCommand()); ClientCommandHandler.instance.registerCommand(new CalendarCommand()); + ClientCommandHandler.instance.registerCommand(new UpdateCommand(NotEnoughUpdates.INSTANCE)); // Fairy Soul Commands ClientCommandHandler.instance.registerCommand(new FairySouls.FairySoulsCommand()); diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/UpdateCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/UpdateCommand.java new file mode 100644 index 00000000..4cf8a62c --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/UpdateCommand.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2022 NotEnoughUpdates contributors + * + * This file is part of NotEnoughUpdates. + * + * NotEnoughUpdates 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. + * + * NotEnoughUpdates 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>. + */ + +package io.github.moulberry.notenoughupdates.commands.misc; + +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import io.github.moulberry.notenoughupdates.commands.ClientCommandBase; +import net.minecraft.command.CommandException; +import net.minecraft.command.ICommandSender; +import net.minecraft.util.ChatComponentText; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +public class UpdateCommand extends ClientCommandBase { + NotEnoughUpdates neu; + + public UpdateCommand(NotEnoughUpdates neu) { + super("neuupdate"); + this.neu = neu; + } + + @Override + public List<String> getCommandAliases() { + return Arrays.asList("neuupdates", "enoughupdates"); + } + + public void displayHelp(ICommandSender sender) { + sender.addChatMessage(new ChatComponentText( + "" + + "§e[NEU] §b/neuupdate help - View help.\n" + + "§e[NEU] §b/neuupdate check - Check for updates.\n" + + "§e[NEU] §b/neuupdate url <url> - Load an update from an direct download URL.\n" + + " §cONLY DO THIS WITH TRUSTED URLS OR IT MIGHT RESULT IN A RAT!\n" + + "§e[NEU] §b/neuupdate fromartifact <url> - Load an update from an artifact.\n" + + " §cIf you don't know what this is, don't use it.\n" + + "" + )); + + } + + @Override + public void processCommand(ICommandSender sender, String[] args) throws CommandException { + if ((args.length == 1 && Objects.equals(args[0], "help")) || args.length == 0) { + displayHelp(sender); + return; + } + switch (args[0].toLowerCase().intern()) { + case "check": + neu.autoUpdater.displayUpdateMessageIfOutOfDate(); + break; + case "url": + if (args.length != 2) { + sender.addChatMessage(new ChatComponentText("§e[NEU] §cPlease provide an URL")); + } + URL url; + try { + url = new URL(args[1]); + } catch (MalformedURLException e) { + e.printStackTrace(); + sender.addChatMessage(new ChatComponentText("§e[NEU] §cInvalid URL")); + return; + } + neu.autoUpdater.updateFromURL(url); + break; + case "scheduledownload": + neu.autoUpdater.scheduleDownload(); + break; + case "updatemodes": + sender.addChatMessage(new ChatComponentText("§e[NEU] §bTo ensure we do not accidentally corrupt your mod folder, we can only offer support for autoupdates on system with certain capabilities for file deletions (specifically linux), or systems that have SkyClient Updater installed. Updating NEU through SCU and through NEUs autoupdate with the SCU compatibility enabled behaves potentially different, so we suggest turning off NEU updates in SCU if you want to use NEU specific update features (such as betas and faster access to hotfixes).")); + break; + default: + displayHelp(sender); + + } + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/listener/NEUEventListener.java b/src/main/java/io/github/moulberry/notenoughupdates/listener/NEUEventListener.java index 26c2d1f9..041da446 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/listener/NEUEventListener.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/listener/NEUEventListener.java @@ -80,73 +80,6 @@ public class NEUEventListener { this.neu = neu; } - private void displayUpdateMessage(JsonObject updateJson, String updateMessage, String downloadLink) { - int firstWidth = -1; - - for (String line : Iterables.concat(Arrays.asList(updateMessage.split("\n")), Arrays.asList("Download here"))) { - FontRenderer fr = Minecraft.getMinecraft().fontRendererObj; - boolean isDownloadLink = line.equals("Download here"); - int width = fr.getStringWidth(line); - if (firstWidth == -1) { - firstWidth = width; - } - int missingLen = firstWidth - width; - if (missingLen > 0) { - StringBuilder sb = new StringBuilder(missingLen / 4 / 2 +line.length()); - for (int i = 0; i < missingLen / 4 / 2; i++) { /* fr.getCharWidth(' ') == 4 */ - sb.append(" "); - } - sb.append(line); - line = sb.toString(); - } - ChatComponentText cp = new ChatComponentText(line); - if (isDownloadLink) - cp.setChatStyle(Utils.createClickStyle(ClickEvent.Action.OPEN_URL, downloadLink)); - Minecraft.getMinecraft().thePlayer.addChatMessage(cp); - } - neu.displayLinks(updateJson, firstWidth); - NotificationHandler.displayNotification(Arrays.asList( - "§eThere is a new version of NotEnoughUpdates available.", - "§eCheck the chat for more information" - ), true); - } - - private void displayUpdateMessageIfOutOfDate() { - File repo = neu.manager.repoLocation; - if (repo.exists()) { - File updateJson = new File(repo, "update.json"); - try { - JsonObject o = neu.manager.getJsonFromFile(updateJson); - - int fullReleaseVersion = - o.has("version_id") && o.get("version_id").isJsonPrimitive() ? o.get("version_id").getAsInt() : -1; - int preReleaseVersion = - o.has("version_id") && o.get("version_id").isJsonPrimitive() ? o.get("version_id").getAsInt() : -1; - int hotfixVersion = - o.has("hotfix_id") && o.get("hotfix_id").isJsonPrimitive() ? o.get("hotfix_id").getAsInt() : -1; - - boolean hasFullReleaseAvailableForUpgrade = fullReleaseVersion > NotEnoughUpdates.VERSION_ID; - boolean hasHotfixAvailableForUpgrade = - fullReleaseVersion == NotEnoughUpdates.VERSION_ID && hotfixVersion > NotEnoughUpdates.HOTFIX_VERSION_ID; - boolean hasPreReleaseAvailableForUpdate = - fullReleaseVersion == NotEnoughUpdates.VERSION_ID && preReleaseVersion > NotEnoughUpdates.PRE_VERSION_ID; - - int updateChannel = NotEnoughUpdates.INSTANCE.config.notifications.updateChannel; /* 1 = Full, 2 = Pre */ - if (hasFullReleaseAvailableForUpgrade || (hasHotfixAvailableForUpgrade && updateChannel == 1)) { - displayUpdateMessage(o, o.get("update_msg").getAsString(), o.get("update_link").getAsString()); - } else if (hasPreReleaseAvailableForUpdate && updateChannel == 2) { - displayUpdateMessage(o, o.get("pre_update_msg").getAsString(), o.get("pre_update_link").getAsString()); - } - } catch (Exception e) { - e.printStackTrace(); - Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText( - "§e[NEU] §cThere has been an error checking for updates. Check the log or join the discord for more information.").setChatStyle( - Utils.createClickStyle( - ClickEvent.Action.OPEN_URL, "https://discord.gg/moulberry"))); - } - } - } - @SubscribeEvent public void onWorldLoad(WorldEvent.Unload event) { NotEnoughUpdates.INSTANCE.saveConfig(); @@ -266,7 +199,7 @@ public class NEUEventListener { joinedSB = true; if (NotEnoughUpdates.INSTANCE.config.notifications.updateChannel != 0) { - displayUpdateMessageIfOutOfDate(); + NotEnoughUpdates.INSTANCE.autoUpdater.displayUpdateMessageIfOutOfDate(); } if (NotEnoughUpdates.INSTANCE.config.notifications.doRamNotif) { diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/AutoUpdater.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/AutoUpdater.java new file mode 100644 index 00000000..7814c6e9 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/AutoUpdater.java @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2022 NotEnoughUpdates contributors + * + * This file is part of NotEnoughUpdates. + * + * NotEnoughUpdates 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. + * + * NotEnoughUpdates 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>. + */ + +package io.github.moulberry.notenoughupdates.miscfeatures.updater; + +import com.google.common.collect.Iterables; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSyntaxException; +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import io.github.moulberry.notenoughupdates.util.NotificationHandler; +import io.github.moulberry.notenoughupdates.util.Utils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.event.ClickEvent; +import net.minecraft.event.HoverEvent; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.ChatStyle; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.IChatComponent; +import net.minecraftforge.fml.common.Loader; +import org.apache.commons.lang3.SystemUtils; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Arrays; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +public class AutoUpdater { + + NotEnoughUpdates neu; + + public AutoUpdater(NotEnoughUpdates neu) { + this.neu = neu; + } + + public void logProgress(String str) { + logProgress(new ChatComponentText(str)); + } + + public void logProgress(IChatComponent chatComponent) { + Minecraft.getMinecraft().addScheduledTask(() -> { + IChatComponent chatComponent1 = new ChatComponentText(""); + chatComponent1.setChatStyle(new ChatStyle().setColor(EnumChatFormatting.AQUA)); + chatComponent1.appendSibling(chatComponent); + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("§e[NEU-AutoUpdater] ").appendSibling( + chatComponent1)); + }); + } + + public UpdateLoader getUpdateLoader(URL url) { + if (SystemUtils.IS_OS_UNIX) { + return new LinuxBasedUpdater(this, url); + } + if (Loader.isModLoaded("skyblockclientupdater")) { + // TODO: add SCU support + } + return null; + } + + UpdateLoader updateLoader; + + public void updateFromURL(URL url) { + if (updateLoader != null) { + logProgress( + "There is already an update in progress, so the auto updater cannot process this update (as it might already be installed or is currently being downloaded). Please restart your client to install another update"); + return; + } + if (!"https".equals(url.getProtocol())) { + logProgress("§cInvalid protocol in url: " + url + ". Only https is a valid protocol."); + return; + } + updateLoader = getUpdateLoader(url); + if (updateLoader == null) { + logProgress(new ChatComponentText( + "Your system does not support auto updates. Please download this update manually. Click here to read more about auto update compatibility (or the link above for manual downloads)") + .setChatStyle( + new ChatStyle() + .setChatHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ChatComponentText("Click here to read about auto update modalities"))) + .setChatClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/neuupdate updatemodes")) + )); + return; + } + updateLoader.greet(); + logProgress(new ChatComponentText("[Start download now]") + .setChatStyle(new ChatStyle() + .setColor(EnumChatFormatting.GREEN) + .setChatHoverEvent(new HoverEvent( + HoverEvent.Action.SHOW_TEXT, + new ChatComponentText("Click to start download.") + )) + .setChatClickEvent(new ClickEvent( + ClickEvent.Action.RUN_COMMAND, + "/neuupdate scheduleDownload" + )))); + } + + public void scheduleDownload() { + if (updateLoader == null) { + logProgress("§cNo update found. Try running /neuupdate check first"); + return; + } + if (updateLoader.getState() != UpdateLoader.State.NOTHING) { + logProgress("§cUpdate download already started. No need to start the download again."); + return; + } + logProgress("Download started."); + updateLoader.scheduleDownload(); + } + + private void displayUpdateMessage( + JsonObject updateJson, + String updateMessage, + String downloadLink, + String directDownload + ) { + int firstWidth = -1; + + for (String line : Iterables.concat(Arrays.asList(updateMessage.split("\n")), Arrays.asList("Download here"))) { + FontRenderer fr = Minecraft.getMinecraft().fontRendererObj; + boolean isDownloadLink = line.equals("Download here"); + int width = fr.getStringWidth(line); + if (firstWidth == -1) { + firstWidth = width; + } + int missingLen = firstWidth - width; + if (missingLen > 0) { + StringBuilder sb = new StringBuilder(missingLen / 4 / 2 + line.length()); + for (int i = 0; i < missingLen / 4 / 2; i++) { /* fr.getCharWidth(' ') == 4 */ + sb.append(" "); + } + sb.append(line); + line = sb.toString(); + } + ChatComponentText cp = new ChatComponentText(line); + if (isDownloadLink) + cp.setChatStyle(Utils.createClickStyle(ClickEvent.Action.OPEN_URL, downloadLink)); + Minecraft.getMinecraft().thePlayer.addChatMessage(cp); + } + neu.displayLinks(updateJson, firstWidth); + NotificationHandler.displayNotification(Arrays.asList( + "§eThere is a new version of NotEnoughUpdates available.", + "§eCheck the chat for more information" + ), true); + try { + if (directDownload != null) + updateFromURL(new URL(directDownload)); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + } + + public void displayUpdateMessageIfOutOfDate() { + File repo = neu.manager.repoLocation; + if (repo.exists()) { + File updateJson = new File(repo, "update.json"); + try { + JsonObject o = neu.manager.getJsonFromFile(updateJson); + + int fullReleaseVersion = + o.has("version_id") && o.get("version_id").isJsonPrimitive() ? o.get("version_id").getAsInt() : -1; + int preReleaseVersion = + o.has("version_id") && o.get("version_id").isJsonPrimitive() ? o.get("version_id").getAsInt() : -1; + int hotfixVersion = + o.has("hotfix_id") && o.get("hotfix_id").isJsonPrimitive() ? o.get("hotfix_id").getAsInt() : -1; + + boolean hasFullReleaseAvailableForUpgrade = fullReleaseVersion > NotEnoughUpdates.VERSION_ID; + boolean hasHotfixAvailableForUpgrade = + fullReleaseVersion == NotEnoughUpdates.VERSION_ID && hotfixVersion > NotEnoughUpdates.HOTFIX_VERSION_ID; + boolean hasPreReleaseAvailableForUpdate = + fullReleaseVersion == NotEnoughUpdates.VERSION_ID && preReleaseVersion > NotEnoughUpdates.PRE_VERSION_ID; + + int updateChannel = NotEnoughUpdates.INSTANCE.config.notifications.updateChannel; /* 1 = Full, 2 = Pre */ + if (hasFullReleaseAvailableForUpgrade || (hasHotfixAvailableForUpgrade && updateChannel == 1)) { + displayUpdateMessage( + o, + o.get("update_msg").getAsString(), + o.get("update_link").getAsString(), + o.has("update_direct") ? o.get("update_direct").getAsString() : null + ); + } else if (hasPreReleaseAvailableForUpdate && updateChannel == 2) { + displayUpdateMessage( + o, + o.get("pre_update_msg").getAsString(), + o.get("pre_update_link").getAsString(), + o.has("pre_update_direct") ? o.get("pre_update_direct").getAsString() : null + ); + } + } catch (Exception e) { + e.printStackTrace(); + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText( + "§e[NEU] §cThere has been an error checking for updates. Check the log or join the discord for more information.").setChatStyle( + Utils.createClickStyle( + ClickEvent.Action.OPEN_URL, "https://discord.gg/moulberry"))); + } + } + } + + private boolean validateMcModInfo(JsonArray array) { + if (array.size() != 1) return false; + JsonElement jsonElement = array.get(0); + if (!jsonElement.isJsonObject()) return false; + JsonObject jsonObject = jsonElement.getAsJsonObject(); + if (!jsonObject.has("modid")) return false; + JsonElement modid = jsonObject.get("modid"); + if (!modid.isJsonPrimitive()) return false; + JsonPrimitive primitive = modid.getAsJsonPrimitive(); + if (!primitive.isString()) return false; + return "notenoughupdates".equals(primitive.getAsString()); + } + + public boolean isNeuJar(File sus) { + try (ZipFile zipFile = new ZipFile(sus)) { + ZipEntry entry = zipFile.getEntry("mcmod.info"); + if (entry == null) { + return false; + } + try (InputStream inputStream = zipFile.getInputStream(entry)) { + JsonArray jsonArray = neu.manager.gson.fromJson( + new InputStreamReader(inputStream), + JsonArray.class + ); + return validateMcModInfo(jsonArray); + } + } catch (IOException | JsonSyntaxException e) { + return false; + } + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/LinuxBasedUpdater.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/LinuxBasedUpdater.java new file mode 100644 index 00000000..a7eddf7b --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/LinuxBasedUpdater.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2022 NotEnoughUpdates contributors + * + * This file is part of NotEnoughUpdates. + * + * NotEnoughUpdates 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. + * + * NotEnoughUpdates 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>. + */ + +package io.github.moulberry.notenoughupdates.miscfeatures.updater; + +import com.google.common.io.Files; +import net.minecraft.client.Minecraft; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; + +/* Based on what? */ +class LinuxBasedUpdater extends UpdateLoader { + + LinuxBasedUpdater(AutoUpdater updater, URL url) { + super(updater, url); + } + + @Override + public void greet() { + updater.logProgress( + "Welcome Aristocrat! Your superior linux system configuration is supported for NEU auto updates."); + } + + @Override + public void launchUpdate(File file) { + if (state != State.DOWNLOAD_FINISHED) { + updater.logProgress("§cUpdate is invalid state " + state + " to start update."); + state = State.FAILED; + return; + } + File mcDataDir = new File(Minecraft.getMinecraft().mcDataDir, "mods"); + if (!mcDataDir.exists() || !mcDataDir.isDirectory() || !mcDataDir.canRead()) { + updater.logProgress("§cCould not find mods folder. Searched: " + mcDataDir); + state = State.FAILED; + return; + } + ArrayList<File> toDelete = new ArrayList<>(); + for (File sus : mcDataDir.listFiles()) { + if (sus.getName().endsWith(".jar")) { + if (updater.isNeuJar(sus)) { + updater.logProgress("Found old NEU file: " + sus + ". Deleting later."); + toDelete.add(sus); + } + } + } + File dest = new File(mcDataDir, file.getName()); + try { + Files.copy(file, dest); + } catch (IOException e) { + e.printStackTrace(); + updater.logProgress( + "§cFailed to copy release JAR. Not making any changes to your mod folder. Consult your logs for more info."); + state = State.FAILED; + } + for (File toDel : toDelete) { + if (!toDel.delete()) { + updater.logProgress("§cCould not delete old version of NEU: " + toDel + ". Please manually delete file."); + state = State.FAILED; + } + } + if (state != State.FAILED) + state = State.INSTALLED; + updater.logProgress("Update successful. Thank you for your time."); + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/UpdateLoader.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/UpdateLoader.java new file mode 100644 index 00000000..0f2a943b --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/UpdateLoader.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2022 NotEnoughUpdates contributors + * + * This file is part of NotEnoughUpdates. + * + * NotEnoughUpdates 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. + * + * NotEnoughUpdates 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>. + */ + +package io.github.moulberry.notenoughupdates.miscfeatures.updater; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSyntaxException; +import io.github.moulberry.notenoughupdates.util.NetUtils; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +abstract class UpdateLoader { + + enum State { + NOTHING, DOWNLOAD_STARTED, DOWNLOAD_FINISHED, INSTALLED, FAILED + } + + URL url; + AutoUpdater updater; + + State state = State.NOTHING; + + UpdateLoader(AutoUpdater updater, URL url) { + this.url = url; + this.updater = updater; + } + + public State getState() { + return state; + } + + public void setState(State state) { + this.state = state; + } + + public URL getUrl() { + return url; + } + + public void scheduleDownload() { + state = State.DOWNLOAD_STARTED; + try { + NetUtils.downloadAsync(url, File.createTempFile("NotEnoughUpdates-update", ".jar")) + .handle( + (f, exc) -> { + if (exc != null) { + state = State.FAILED; + updater.logProgress("§cError while downloading. Check your logs for more info."); + exc.printStackTrace(); + return null; + } + state = State.DOWNLOAD_FINISHED; + + + updater.logProgress("Download completed. Trying to install"); + launchUpdate(f); + return null; + }); + } catch (IOException e) { + state = State.FAILED; + updater.logProgress("§cError while creating download. Check your logs for more info."); + e.printStackTrace(); + } + } + + public abstract void greet(); + + public abstract void launchUpdate(File file); +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/NetUtils.java b/src/main/java/io/github/moulberry/notenoughupdates/util/NetUtils.java new file mode 100644 index 00000000..251a2b3a --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/NetUtils.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2022 NotEnoughUpdates contributors + * + * This file is part of NotEnoughUpdates. + * + * NotEnoughUpdates 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. + * + * NotEnoughUpdates 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>. + */ + +package io.github.moulberry.notenoughupdates.util; + +import org.apache.commons.io.IOUtils; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URL; +import java.net.URLConnection; +import java.nio.file.Files; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; + +public class NetUtils { + + public static CompletableFuture<File> downloadAsync(URL httpURL, File outputFile) { + return CompletableFuture.supplyAsync(() -> { + try { + URLConnection urlConnection = httpURL.openConnection(); + try ( + InputStream from = urlConnection.getInputStream(); + OutputStream to = Files.newOutputStream(outputFile.toPath()); + ) { + IOUtils.copyLarge(from, to); + } + return outputFile; + } catch (IOException e) { + throw new CompletionException(e); + } + }); + } + +} |