aboutsummaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
authornea <romangraef@gmail.com>2022-07-17 00:30:48 +0200
committernea <romangraef@gmail.com>2022-07-23 14:51:13 +0200
commit23f79bb3b523f6fb67ca7d6b209841ea9e6c5f48 (patch)
treec1211e206594a64fed5ce8734a0db8e7d293c0ee /src/main/java
parent01ce1186f271be0fc9cd65d759bc3905392c4ca8 (diff)
downloadNotEnoughUpdates-23f79bb3b523f6fb67ca7d6b209841ea9e6c5f48.tar.gz
NotEnoughUpdates-23f79bb3b523f6fb67ca7d6b209841ea9e6c5f48.tar.bz2
NotEnoughUpdates-23f79bb3b523f6fb67ca7d6b209841ea9e6c5f48.zip
add autoupdater (linux)
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java4
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/Commands.java3
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/misc/UpdateCommand.java96
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/listener/NEUEventListener.java69
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/AutoUpdater.java252
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/LinuxBasedUpdater.java84
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/UpdateLoader.java94
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/NetUtils.java53
8 files changed, 586 insertions, 69 deletions
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);
+ }
+ });
+ }
+
+}