From b247a49a2365b591a814544bbe0acb366473726c Mon Sep 17 00:00:00 2001 From: libraryaddict Date: Mon, 27 Apr 2020 05:09:13 +1200 Subject: [PATCH] Better handling for updates checking, can now autoupdate on dev and release builds --- .../disguise/DisguiseConfig.java | 136 +++++++- .../libraryaddict/disguise/LibsDisguises.java | 18 +- .../commands/libsdisguises/LDUpdate.java | 69 +++-- .../disguise/utilities/UpdateChecker.java | 286 ----------------- .../utilities/listeners/DisguiseListener.java | 90 +----- .../utilities/plugin/BisectHosting.java | 46 +-- .../reflection/ReflectionManager.java | 39 ++- .../utilities/translations/LibsMsg.java | 3 +- .../utilities/updates/DisguiseUpdate.java | 24 ++ .../disguise/utilities/updates/LDGithub.java | 95 ++++++ .../disguise/utilities/updates/LDJenkins.java | 104 +++++++ .../utilities/updates/UpdateChecker.java | 290 ++++++++++++++++++ src/main/resources/config.yml | 9 +- src/main/resources/internal.yml | 8 + 14 files changed, 760 insertions(+), 457 deletions(-) delete mode 100644 src/main/java/me/libraryaddict/disguise/utilities/UpdateChecker.java create mode 100644 src/main/java/me/libraryaddict/disguise/utilities/updates/DisguiseUpdate.java create mode 100644 src/main/java/me/libraryaddict/disguise/utilities/updates/LDGithub.java create mode 100644 src/main/java/me/libraryaddict/disguise/utilities/updates/LDJenkins.java create mode 100644 src/main/java/me/libraryaddict/disguise/utilities/updates/UpdateChecker.java create mode 100644 src/main/resources/internal.yml diff --git a/src/main/java/me/libraryaddict/disguise/DisguiseConfig.java b/src/main/java/me/libraryaddict/disguise/DisguiseConfig.java index dbdc1331..23b28e6a 100644 --- a/src/main/java/me/libraryaddict/disguise/DisguiseConfig.java +++ b/src/main/java/me/libraryaddict/disguise/DisguiseConfig.java @@ -13,6 +13,7 @@ import me.libraryaddict.disguise.utilities.parser.DisguiseParseException; import me.libraryaddict.disguise.utilities.parser.DisguiseParser; import me.libraryaddict.disguise.utilities.parser.DisguisePerm; import me.libraryaddict.disguise.utilities.reflection.NmsVersion; +import me.libraryaddict.disguise.utilities.reflection.ReflectionManager; import me.libraryaddict.disguise.utilities.translations.LibsMsg; import me.libraryaddict.disguise.utilities.translations.TranslateType; import org.bukkit.Bukkit; @@ -26,16 +27,16 @@ import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Entity; import org.bukkit.permissions.Permission; import org.bukkit.permissions.PermissionDefault; +import org.bukkit.scheduler.BukkitTask; -import java.io.File; -import java.io.IOException; -import java.io.PrintWriter; +import java.io.*; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Map.Entry; import java.util.Random; +import java.util.concurrent.TimeUnit; public class DisguiseConfig { @Getter @@ -46,9 +47,6 @@ public class DisguiseConfig { private static HashMap customDisguises = new HashMap<>(); @Getter @Setter - private static String updateNotificationPermission; - @Getter - @Setter private static UpdatesBranch updatesBranch = UpdatesBranch.SAME_BUILDS; @Getter @Setter @@ -231,6 +229,127 @@ public class DisguiseConfig { @Getter @Setter private static int tablistRemoveDelay; + @Getter + private static boolean usingReleaseBuild = true; + @Getter + private static boolean bisectHosted = true; + @Getter + private static String savedServerIp = ""; + @Getter + private static boolean autoUpdate; + @Getter + private static boolean notifyUpdate; + private static BukkitTask updaterTask; + + public static void setAutoUpdate(boolean update) { + if (isAutoUpdate() == update) { + return; + } + + autoUpdate = update; + doUpdaterTask(); + } + + public static void setNotifyUpdate(boolean update) { + if (isNotifyUpdate() == update) { + return; + } + + notifyUpdate = update; + doUpdaterTask(); + } + + private static void doUpdaterTask() { + boolean startTask = isAutoUpdate() || isNotifyUpdate(); + + // Don't ever run the auto updater on a custom build.. + if (!LibsDisguises.getInstance().isNumberedBuild()) { + return; + } + + if (updaterTask == null != startTask) { + return; + } + + if (!startTask) { + updaterTask.cancel(); + updaterTask = null; + return; + } + + updaterTask = Bukkit.getScheduler().runTaskTimerAsynchronously(LibsDisguises.getInstance(), new Runnable() { + @Override + public void run() { + LibsDisguises.getInstance().getUpdateChecker().doAutoUpdateCheck(); + } + }, 0, (20 * TimeUnit.HOURS.toSeconds(6))); // Check every 6 hours + } + + public static void setUsingReleaseBuilds(boolean useReleaseBuilds) { + if (useReleaseBuilds == isUsingReleaseBuild()) { + return; + } + + usingReleaseBuild = useReleaseBuilds; + saveInternalConfig(); + } + + public static void setBisectHosted(boolean isBisectHosted, String serverIP) { + if (isBisectHosted() == isBisectHosted && getSavedServerIp().equals(serverIP)) { + return; + } + + bisectHosted = isBisectHosted; + savedServerIp = serverIP; + saveInternalConfig(); + } + + public static void loadInternalConfig() { + File internalFile = new File(LibsDisguises.getInstance().getDataFolder(), "internal.yml"); + + if (!internalFile.exists()) { + saveInternalConfig(); + } + + YamlConfiguration configuration = YamlConfiguration.loadConfiguration(internalFile); + + bisectHosted = configuration.getBoolean("Bisect-Hosted", isBisectHosted()); + savedServerIp = configuration.getString("Server-IP", getSavedServerIp()); + usingReleaseBuild = configuration.getBoolean("ReleaseBuild", isUsingReleaseBuild()); + + if (!configuration.contains("Bisect-Hosted") || !configuration.contains("Server-IP") || + !configuration.contains("ReleaseBuild")) { + saveInternalConfig(); + } + } + + public static void saveInternalConfig() { + File internalFile = new File(LibsDisguises.getInstance().getDataFolder(), "internal.yml"); + + String internalConfig = ReflectionManager + .getResourceAsString(LibsDisguises.getInstance().getFile(), "internal.yml"); + + // Bisect hosted, server ip, release builds + for (Object s : new Object[]{isBisectHosted(), getSavedServerIp(), isUsingReleaseBuild()}) { + internalConfig = internalConfig.replaceFirst("%data%", "" + s); + } + + internalFile.delete(); + + try { + internalFile.createNewFile(); + } + catch (IOException e) { + e.printStackTrace(); + } + + try (PrintWriter writer = new PrintWriter(internalFile, "UTF-8")) { + writer.write(internalConfig); + } + catch (FileNotFoundException | UnsupportedEncodingException e) { + e.printStackTrace(); + } + } public static PermissionDefault getCommandVisibility() { return commandVisibility; @@ -438,7 +557,6 @@ public class DisguiseConfig { setUUIDGeneratedVersion(config.getInt("UUIDVersion")); setUndisguiseOnWorldChange(config.getBoolean("UndisguiseOnWorldChange")); setUpdateGameProfiles(config.getBoolean("UpdateGameProfiles")); - setUpdateNotificationPermission(config.getString("Permission")); setUseTranslations(config.getBoolean("Translations")); setVelocitySent(config.getBoolean("SendVelocity")); setViewDisguises(config.getBoolean("ViewSelfDisguises")); @@ -447,6 +565,7 @@ public class DisguiseConfig { setWolfDyeable(config.getBoolean("DyeableWolf")); setScoreboardDisguiseNames(config.getBoolean("ScoreboardNames")); setTablistRemoveDelay(config.getInt("TablistRemoveDelay")); + setAutoUpdate(config.getBoolean("AutoUpdate")); if (!LibsPremium.isPremium() && (isSavePlayerDisguises() || isSaveEntityDisguises())) { DisguiseUtilities.getLogger().warning("You must purchase the plugin to use saved disguises!"); @@ -561,7 +680,8 @@ public class DisguiseConfig { if (missingConfigs > 0) { DisguiseUtilities.getLogger().warning("Your config is missing " + missingConfigs + " options! Please consider regenerating your config!"); - DisguiseUtilities.getLogger().info("You can also add the missing entries yourself! Try '/libsdisguises config'"); + DisguiseUtilities.getLogger() + .info("You can also add the missing entries yourself! Try '/libsdisguises config'"); } } diff --git a/src/main/java/me/libraryaddict/disguise/LibsDisguises.java b/src/main/java/me/libraryaddict/disguise/LibsDisguises.java index 29d2db2b..0ed16218 100644 --- a/src/main/java/me/libraryaddict/disguise/LibsDisguises.java +++ b/src/main/java/me/libraryaddict/disguise/LibsDisguises.java @@ -17,7 +17,7 @@ import me.libraryaddict.disguise.commands.undisguise.UndisguiseRadiusCommand; import me.libraryaddict.disguise.commands.utils.*; import me.libraryaddict.disguise.utilities.DisguiseUtilities; import me.libraryaddict.disguise.utilities.LibsPremium; -import me.libraryaddict.disguise.utilities.UpdateChecker; +import me.libraryaddict.disguise.utilities.updates.UpdateChecker; import me.libraryaddict.disguise.utilities.listeners.DisguiseListener; import me.libraryaddict.disguise.utilities.metrics.MetricsInitalizer; import me.libraryaddict.disguise.utilities.packets.PacketsManager; @@ -31,10 +31,13 @@ import org.bukkit.command.CommandExecutor; import org.bukkit.command.PluginCommand; import org.bukkit.command.TabCompleter; import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.craftbukkit.libs.org.apache.commons.io.FileUtils; import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.util.FileUtil; import java.io.File; +import java.io.IOException; import java.util.Arrays; import java.util.stream.Collectors; @@ -81,6 +84,8 @@ public class LibsDisguises extends JavaPlugin { getLogger().info("Build Date: " + pluginYml.getString("build-date")); + DisguiseConfig.loadInternalConfig(); + LibsPremium.check(getDescription().getVersion(), getFile()); if (!LibsPremium.isPremium()) { @@ -98,6 +103,17 @@ public class LibsDisguises extends JavaPlugin { return; } + // If this is a release build, even if jenkins build.. + if (isReleaseBuild()) { + // If downloaded from spigot, forcibly set release build to true + if (LibsPremium.getUserID().matches("[0-9]+")) { + DisguiseConfig.setUsingReleaseBuilds(true); + } + // Otherwise leave it untouched as they might've just happened to hit a dev build, which is a release build + } else { + DisguiseConfig.setUsingReleaseBuilds(false); + } + ReflectionManager.init(); PacketsManager.init(); diff --git a/src/main/java/me/libraryaddict/disguise/commands/libsdisguises/LDUpdate.java b/src/main/java/me/libraryaddict/disguise/commands/libsdisguises/LDUpdate.java index 071c558c..19a4da8b 100644 --- a/src/main/java/me/libraryaddict/disguise/commands/libsdisguises/LDUpdate.java +++ b/src/main/java/me/libraryaddict/disguise/commands/libsdisguises/LDUpdate.java @@ -1,7 +1,8 @@ package me.libraryaddict.disguise.commands.libsdisguises; import me.libraryaddict.disguise.LibsDisguises; -import me.libraryaddict.disguise.utilities.UpdateChecker; +import me.libraryaddict.disguise.utilities.DisguiseUtilities; +import me.libraryaddict.disguise.utilities.updates.UpdateChecker; import me.libraryaddict.disguise.utilities.plugin.PluginInformation; import me.libraryaddict.disguise.utilities.translations.LibsMsg; import org.bukkit.Bukkit; @@ -18,7 +19,10 @@ import java.util.List; public class LDUpdate implements LDCommand { @Override public List getTabComplete() { - return Arrays.asList("update", "update!"); + // Update by download + // Update check + // Update to latest dev build + return Arrays.asList("update", "update?", "update!"); } @Override @@ -35,16 +39,21 @@ public class LDUpdate implements LDCommand { return; } + boolean check = args[0].endsWith("?"); boolean force = args[0].endsWith("!"); - if (!force) { - if (checker.getLatestSnapshot() <= 0) { - sender.sendMessage(LibsMsg.UPDATE_NOT_READY.get()); + if (!check && !force && checker.getUpdate() != null) { + if (checker.getUpdate().getVersion().equals(checker.getUpdate().isReleaseBuild() ? + LibsDisguises.getInstance().getDescription().getDescription() : + LibsDisguises.getInstance().getBuildNumber())) { + sender.sendMessage(LibsMsg.UPDATE_ON_LATEST.get()); return; } - if (checker.getLatestSnapshot() == LibsDisguises.getInstance().getBuildNumber()) { - sender.sendMessage(LibsMsg.UPDATE_ON_LATEST.get()); + if (checker.getLastDownload() != null && checker.getUpdate().getVersion() + .equals(checker.isUsingReleaseBuilds() ? checker.getLastDownload().getVersion() : + checker.getLastDownload().getBuildNumber())) { + sender.sendMessage(LibsMsg.UPDATE_ALREADY_DOWNLOADED.get()); return; } } @@ -52,29 +61,49 @@ public class LDUpdate implements LDCommand { new BukkitRunnable() { @Override public void run() { - PluginInformation result; + LibsMsg updateResult = null; - if (force) { - result = checker.grabLatestSnapshot(); - } else { - result = checker.grabSnapshotBuild(); + if (check || checker.getUpdate() == null || force) { + updateResult = checker.doUpdateCheck(); } + if (checker.getUpdate() == null) { + sender.sendMessage(LibsMsg.UPDATE_FAILED.get()); + return; + } + + if (!checker.isUpdateReady()) { + sender.sendMessage(LibsMsg.UPDATE_ON_LATEST.get()); + return; + } + + if (check) { + if (updateResult != null) { + sender.sendMessage(updateResult.get()); + } else { + for (String msg : checker.getUpdateMessage()) { + sender.sendMessage(msg); + } + } + + return; + } + + PluginInformation result = checker.doUpdate(); + if (result == null) { sender.sendMessage(LibsMsg.UPDATE_FAILED.get()); return; } - sender.sendMessage(LibsMsg.UPDATE_SUCCESS.get()); // Update success, please restart to update - sender.sendMessage(LibsMsg.UPDATE_INFO - .get(result.getVersion(), result.getBuildNumber(), result.getParsedBuildDate().toString(), - result.getSize() / 1024)); + for (String msg : checker.getUpdateMessage()) { + sender.sendMessage(msg); + } if (sender instanceof Player) { - Bukkit.getConsoleSender().sendMessage(LibsMsg.UPDATE_SUCCESS.get()); - Bukkit.getConsoleSender().sendMessage(LibsMsg.UPDATE_INFO - .get(result.getVersion(), result.getBuildNumber(), result.getParsedBuildDate().toString(), - result.getSize() / 1024)); + for (String msg : checker.getUpdateMessage()) { + DisguiseUtilities.getLogger().info(msg); + } } } }.runTaskAsynchronously(LibsDisguises.getInstance()); diff --git a/src/main/java/me/libraryaddict/disguise/utilities/UpdateChecker.java b/src/main/java/me/libraryaddict/disguise/utilities/UpdateChecker.java deleted file mode 100644 index f8d8342a..00000000 --- a/src/main/java/me/libraryaddict/disguise/utilities/UpdateChecker.java +++ /dev/null @@ -1,286 +0,0 @@ -package me.libraryaddict.disguise.utilities; - -import com.google.gson.Gson; -import lombok.Getter; -import me.libraryaddict.disguise.LibsDisguises; -import me.libraryaddict.disguise.utilities.plugin.PluginInformation; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.libs.org.apache.commons.io.FileUtils; - -import java.io.BufferedReader; -import java.io.File; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.Date; -import java.util.Map; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - -public class UpdateChecker { - private final String resourceID; - @Getter - private String latestVersion; - @Getter - private int latestSnapshot; - private final long started = System.currentTimeMillis(); - private int lastDownload; - - public UpdateChecker(String resourceID) { - this.resourceID = resourceID; - } - - public PluginInformation grabSnapshotBuild() { - if (getLatestSnapshot() == 0) { - throw new IllegalArgumentException(); - } - - if (lastDownload == -1) { - return null; - } - - if (getLatestSnapshot() == lastDownload) { - return null; - } - - return grabSnapshotBuild(getLatestSnapshot()); - } - - public PluginInformation grabSnapshotBuild(int buildNo) { - PluginInformation result = grabSnapshotBuild( - "https://ci.md-5.net/job/LibsDisguises/" + buildNo + "/artifact/target/LibsDisguises.jar"); - - if (result != null) { - lastDownload = buildNo; - } - - return result; - } - - public PluginInformation grabLatestSnapshot() { - PluginInformation result = grabSnapshotBuild( - "https://ci.md-5.net/job/LibsDisguises/lastSuccessfulBuild/artifact/target/LibsDisguises.jar"); - - if (result != null) { - lastDownload = LibsDisguises.getInstance().getBuildNumber(); - } - - return result; - } - - public boolean isDownloading() { - return lastDownload == -1; - } - - public int getLastDownload() { - return lastDownload; - } - - public PluginInformation grabSnapshotBuild(String urlString) { - DisguiseUtilities.getLogger().info("Now downloading latest build of Lib's Disguises from " + urlString); - lastDownload = -1; - - File dest = new File(Bukkit.getUpdateFolderFile(), "LibsDisguises.jar"); - - if (dest.exists()) { - dest.delete(); - } - - dest.getParentFile().mkdirs(); - - try { - // We're connecting to spigot's API - URL url = new URL(urlString); - // Creating a connection - HttpURLConnection con = (HttpURLConnection) url.openConnection(); - con.setDefaultUseCaches(false); - - // Get the input stream, what we receive - try (InputStream input = con.getInputStream()) { - FileUtils.copyInputStreamToFile(input, dest); - } - - DisguiseUtilities.getLogger().info("Download success!"); - - return LibsPremium.getInformation(dest); - } - catch (Exception ex) { - // Failed, set the last download back to previous build - dest.delete(); - DisguiseUtilities.getLogger().warning("Failed to download snapshot build."); - lastDownload = 0; - ex.printStackTrace(); - } - - return null; - } - - public void checkSnapshotUpdate(int buildNumber) { - Map lastBuild = fetchLastSnapshotBuild(); - - if (lastBuild == null || !lastBuild.containsKey("id") || !lastBuild.containsKey("timestamp")) { - return; - } - - int newBuildNumber = Integer.parseInt((String) lastBuild.get("id")); - - // If new build number is same or older - if (newBuildNumber <= buildNumber) { - return; - } - - Date newBuildDate = new Date(((Number) lastBuild.get("timestamp")).longValue()); - - // If the new snapshot is at least 3 days old - /*if (newBuildDate.getTime() >= System.currentTimeMillis() - TimeUnit.DAYS.toMillis(3)) { - return; - }*/ - - latestSnapshot = newBuildNumber; - } - - public void checkOfficialUpdate(String currentVersion) { - String version = fetchSpigotVersion(); - - if (version == null) { - return; - } - - if (!isNewerVersion(currentVersion, version)) { - return; - } - - latestVersion = version; - } - - /** - * Asks spigot for the version - */ - private String fetchSpigotVersion() { - try { - // We're connecting to spigot's API - URL url = new URL("https://api.spigotmc.org/legacy/update.php?resource=" + resourceID); - // Creating a connection - HttpURLConnection con = (HttpURLConnection) url.openConnection(); - con.setDefaultUseCaches(false); - - // Get the input stream, what we receive - try (InputStream input = con.getInputStream()) { - // Read it to string - String version = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)).lines() - .collect(Collectors.joining("\n")); - - // If the version is not empty, return it - if (!version.isEmpty()) { - return version; - } - } - } - catch (Exception ex) { - DisguiseUtilities.getLogger().warning("Failed to check for a update on spigot."); - } - - return null; - } - - private boolean isNewerVersion(String currentVersion, String newVersion) { - currentVersion = currentVersion.replaceAll("(v)|(-SNAPSHOT)", ""); - newVersion = newVersion.replaceAll("(v)|(-SNAPSHOT)", ""); - - // If the server has been online for less than 6 hours and both versions are 1.1.1 kind of versions - if (started + TimeUnit.HOURS.toMillis(6) > System.currentTimeMillis() && - currentVersion.matches("[0-9]+(\\.[0-9]+)*") && newVersion.matches("[0-9]+(\\.[0-9]+)*")) { - - int cVersion = Integer.parseInt(currentVersion.replace(".", "")); - int nVersion = Integer.parseInt(newVersion.replace(".", "")); - - // If the current version is a higher version, and is only a higher version by 3 minor numbers - // Then we have a cache problem - if (cVersion > nVersion && nVersion + 3 > cVersion) { - return false; - } - } - - // Lets just ignore all this fancy logic, and say that if you're not on the current release, you're outdated! - return !currentVersion.equals(newVersion); - - /* - // Remove 'v' and '-SNAPSHOT' from string, split by decimal points - String[] cSplit = currentVersion.replaceAll("(v)|(-SNAPSHOT)", "").split("\\."); - String[] nSplit = newVersion.replaceAll("(v)|(-SNAPSHOT)", "").split("\\."); - - // Lets just ignore all this fancy logic, and say that if you're not on the current release, you're outdated! - return !Arrays.equals(cSplit, nSplit); - - // Iterate over the versions from left to right - for (int i = 0; i < Math.max(cSplit.length, nSplit.length); i++) { - // If the current version doesn't have the next version, then it's older - if (cSplit.length <= i) { - return true; - } else if (nSplit.length <= i) { - // If the new version doesn't have the next version, then it's older - return false; - } - - // If both strings are numerical - if (cSplit[i].matches("[0-9]+") && nSplit[i].matches("[0-9]+")) { - int cInt = Integer.parseInt(cSplit[i]); - int nInt = Integer.parseInt(nSplit[i]); - - // Same version - if (cInt == nInt) { - continue; - } - - // Return if current version is inferior to new version - return cInt < nInt; - } - - // String compare the versions, should perform the same as an int compare - int compareResult = cSplit[i].compareTo(nSplit[i]); - - // Same version - if (compareResult == 0) { - continue; - } - - // Return if current version is inferior to new versio - return compareResult < 0; - } - - // Both versions should be the same, return false as it's not a newer version - return false;*/ - } - - /** - * Fetches from jenkins, using the REST api the last snapshot build information - */ - private Map fetchLastSnapshotBuild() { - try { - // We're connecting to md_5's jenkins REST api - URL url = new URL("https://ci.md-5.net/job/LibsDisguises/lastSuccessfulBuild/api/json"); - // Creating a connection - HttpURLConnection con = (HttpURLConnection) url.openConnection(); - con.setDefaultUseCaches(false); - Map jsonObject; - - // Get the input stream, what we receive - try (InputStream input = con.getInputStream()) { - // Read it to string - String json = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)).lines() - .collect(Collectors.joining("\n")); - - jsonObject = new Gson().fromJson(json, Map.class); - } - - return jsonObject; - } - catch (Exception ex) { - DisguiseUtilities.getLogger().warning("Failed to check for a snapshot update on jenkins."); - } - - return null; - } -} diff --git a/src/main/java/me/libraryaddict/disguise/utilities/listeners/DisguiseListener.java b/src/main/java/me/libraryaddict/disguise/utilities/listeners/DisguiseListener.java index d201480b..11e1c1f6 100644 --- a/src/main/java/me/libraryaddict/disguise/utilities/listeners/DisguiseListener.java +++ b/src/main/java/me/libraryaddict/disguise/utilities/listeners/DisguiseListener.java @@ -14,7 +14,7 @@ import me.libraryaddict.disguise.disguisetypes.TargetedDisguise; import me.libraryaddict.disguise.utilities.DisguiseUtilities; import me.libraryaddict.disguise.utilities.LibsEntityInteract; import me.libraryaddict.disguise.utilities.LibsPremium; -import me.libraryaddict.disguise.utilities.UpdateChecker; +import me.libraryaddict.disguise.utilities.updates.UpdateChecker; import me.libraryaddict.disguise.utilities.modded.ModdedEntity; import me.libraryaddict.disguise.utilities.modded.ModdedManager; import me.libraryaddict.disguise.utilities.plugin.PluginInformation; @@ -53,13 +53,9 @@ import java.util.Set; import java.util.concurrent.TimeUnit; public class DisguiseListener implements Listener { - private String currentVersion; private HashMap interactions = new HashMap<>(); private HashMap disguiseRunnable = new HashMap<>(); - private String latestVersion; - private LibsMsg updateMessage; private LibsDisguises plugin; - private BukkitTask updaterTask; public DisguiseListener(LibsDisguises libsDisguises) { plugin = libsDisguises; @@ -117,87 +113,6 @@ public class DisguiseListener implements Listener { DisguiseUtilities.getLogger() .info("Plugin will attempt to auto update when new builds are ready! Check config to disable."); } - - updaterTask = Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, new Runnable() { - @Override - public void run() { - try { - UpdateChecker updateChecker = LibsDisguises.getInstance().getUpdateChecker(); - boolean checkReleases = isCheckReleases(); - - if (checkReleases) { - currentVersion = plugin.getDescription().getVersion(); - updateChecker.checkOfficialUpdate(currentVersion); - String version = updateChecker.getLatestVersion(); - - if (version == null) { - return; - } - - latestVersion = version; - updateMessage = LibsMsg.UPDATE_READY; - } else { - updateChecker.checkSnapshotUpdate(plugin.getBuildNumber()); - - if (updateChecker.getLatestSnapshot() <= 0) { - return; - } - - latestVersion = "" + updateChecker.getLatestSnapshot(); - - if (autoUpdate && plugin.isNumberedBuild()) { - PluginInformation result = updateChecker.grabSnapshotBuild(); - updateMessage = result != null ? LibsMsg.UPDATE_SUCCESS : LibsMsg.UPDATE_FAILED; - Bukkit.getConsoleSender().sendMessage(LibsMsg.UPDATE_INFO - .get(result.getVersion(), result.getBuildNumber(), - result.getParsedBuildDate().toString(), result.getSize() / 1024)); - } else { - currentVersion = plugin.getBuildNo(); - updateMessage = LibsMsg.UPDATE_READY_SNAPSHOT; - } - } - - Bukkit.getScheduler().runTask(plugin, new Runnable() { - @Override - public void run() { - notifyUpdate(Bukkit.getConsoleSender()); - - for (Player p : Bukkit.getOnlinePlayers()) { - notifyUpdate(p); - } - } - }); - } - catch (Exception ex) { - DisguiseUtilities.getLogger() - .warning(String.format("Failed to check for update: %s", ex.getMessage())); - } - } - }, 0, (20 * TimeUnit.HOURS.toSeconds(6))); // Check every 6 hours - } - - private void notifyUpdate(CommandSender player) { - if (!player.hasPermission(DisguiseConfig.getUpdateNotificationPermission())) { - return; - } - - if (latestVersion == null) { - return; - } - - if (updateMessage == LibsMsg.UPDATE_SUCCESS || updateMessage == LibsMsg.UPDATE_FAILED) { - if (player instanceof Player) { - player.sendMessage(updateMessage.get()); - } else { - DisguiseUtilities.getLogger().info(updateMessage.get()); - } - } else { - if (player instanceof Player) { - player.sendMessage(updateMessage.get(currentVersion, latestVersion)); - } else { - DisguiseUtilities.getLogger().info(updateMessage.get(currentVersion, latestVersion)); - } - } } public void cleanup() { @@ -206,7 +121,6 @@ public class DisguiseListener implements Listener { } interactions.clear(); - updaterTask.cancel(); } private void checkPlayerCanBlowDisguise(Player player) { @@ -423,7 +337,7 @@ public class DisguiseListener implements Listener { public void onJoin(PlayerJoinEvent event) { Player p = event.getPlayer(); - notifyUpdate(p); + plugin.getUpdateChecker().notifyUpdate(p); if (DisguiseConfig.isSaveGameProfiles() && DisguiseConfig.isUpdateGameProfiles() && DisguiseUtilities.hasGameProfile(p.getName())) { diff --git a/src/main/java/me/libraryaddict/disguise/utilities/plugin/BisectHosting.java b/src/main/java/me/libraryaddict/disguise/utilities/plugin/BisectHosting.java index 1c5c9ad6..93fa0a31 100644 --- a/src/main/java/me/libraryaddict/disguise/utilities/plugin/BisectHosting.java +++ b/src/main/java/me/libraryaddict/disguise/utilities/plugin/BisectHosting.java @@ -1,5 +1,6 @@ package me.libraryaddict.disguise.utilities.plugin; +import me.libraryaddict.disguise.DisguiseConfig; import me.libraryaddict.disguise.LibsDisguises; import org.bukkit.Bukkit; import org.bukkit.configuration.file.YamlConfiguration; @@ -13,24 +14,15 @@ import java.net.URL; */ public class BisectHosting { public boolean isBisectHosted(String pluginName) { - File configFile = new File("plugins/" + pluginName + "/internal.yml"); - boolean claimedHosted = false; - String serverIp = Bukkit.getIp().replaceAll("[^:0-9.]", ""); + boolean claimedHosted = DisguiseConfig.isBisectHosted(); + String ip = Bukkit.getIp(); + String parsedIP = ip.replaceAll("[^:0-9.]", ""); - if (configFile.exists()) { - YamlConfiguration configuration = YamlConfiguration.loadConfiguration(configFile); - - if (configuration.contains("Bisect-Hosted") && configuration.contains("Server-IP")) { - claimedHosted = configuration.getBoolean("Bisect-Hosted"); - - // If not hosted by bisect - if (!claimedHosted && configuration.getString("Server-IP").equals(serverIp)) { - return false; - } - } + // If not hosted by bisect + if (!claimedHosted && DisguiseConfig.getSavedServerIp().equals(parsedIP)) { + return false; } - String ip = Bukkit.getIp(); boolean hostedBy = false; if (ip.matches("((25[0-5]|(2[0-4]|1[0-9]|[1-9]|)[0-9])(\\.(?!$)|$)){4}")) { @@ -45,27 +37,11 @@ public class BisectHosting { } } - // If config doesn't exist, or it's not a bisect server - if (!configFile.exists()) { - if (!configFile.getParentFile().exists()) { - configFile.getParentFile().mkdirs(); - } + if (claimedHosted != hostedBy || !DisguiseConfig.getSavedServerIp().equals(parsedIP)) { + DisguiseConfig.setBisectHosted(hostedBy, Bukkit.getIp()); + } - try (PrintWriter writer = new PrintWriter(configFile, "UTF-8")) { - // This setting is if the server should check if you are using Bisect Hosting", - writer.write("# If you're using BisectHosting, this will tell the server to enable premium for free!"); - writer.write("\n# However if you're not using BisectHosting, this is false so the server won't waste " + - "time"); - writer.write( - "\n# Coupon 'libraryaddict' for 25% off your first invoice on any of their gaming servers"); - writer.write("\n# Be sure to visit through this link! https://bisecthosting.com/libraryaddict"); - writer.write("\nBisect-Hosted: " + hostedBy); - writer.write("\nServer-IP: " + serverIp); - } - catch (FileNotFoundException | UnsupportedEncodingException e) { - e.printStackTrace(); - } - } else if (claimedHosted) { + if (!hostedBy && !DisguiseConfig.getSavedServerIp().equals("")) { // Just a small message for those who tried to enable it LibsDisguises.getInstance().getLogger().severe("Check for BisectHosting failed! Connection error?"); } diff --git a/src/main/java/me/libraryaddict/disguise/utilities/reflection/ReflectionManager.java b/src/main/java/me/libraryaddict/disguise/utilities/reflection/ReflectionManager.java index e542a15a..8ec52b38 100644 --- a/src/main/java/me/libraryaddict/disguise/utilities/reflection/ReflectionManager.java +++ b/src/main/java/me/libraryaddict/disguise/utilities/reflection/ReflectionManager.java @@ -16,6 +16,7 @@ import me.libraryaddict.disguise.utilities.LibsPremium; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.StringUtils; import org.bukkit.*; +import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.*; import org.bukkit.inventory.EquipmentSlot; @@ -158,21 +159,13 @@ public class ReflectionManager { return true; } - /** - * Copied from Bukkit - */ - public static YamlConfiguration getPluginYAML(File file) { + public static String getResourceAsString(File file, String fileName) { try (JarFile jar = new JarFile(file)) { - JarEntry entry = jar.getJarEntry("plugin.yml"); + JarEntry entry = jar.getJarEntry(fileName); try (InputStream stream = jar.getInputStream(entry)) { - YamlConfiguration config = new YamlConfiguration(); - - String configString = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8)).lines() + return new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8)).lines() .collect(Collectors.joining("\n")); - config.loadFromString(configString); - - return config; } } catch (Exception ex) { @@ -182,6 +175,30 @@ public class ReflectionManager { return null; } + /** + * Copied from Bukkit + */ + public static YamlConfiguration getPluginYAML(File file) { + try { + String s = getResourceAsString(file, "plugin.yml"); + + if (s == null) { + return null; + } + + YamlConfiguration config = new YamlConfiguration(); + + config.loadFromString(getResourceAsString(file, "plugin.yml")); + + return config; + } + catch (InvalidConfigurationException e) { + e.printStackTrace(); + } + + return null; + } + public static int getNewEntityId() { return getNewEntityId(true); } diff --git a/src/main/java/me/libraryaddict/disguise/utilities/translations/LibsMsg.java b/src/main/java/me/libraryaddict/disguise/utilities/translations/LibsMsg.java index 9bb76c5c..62eda66b 100644 --- a/src/main/java/me/libraryaddict/disguise/utilities/translations/LibsMsg.java +++ b/src/main/java/me/libraryaddict/disguise/utilities/translations/LibsMsg.java @@ -143,9 +143,8 @@ public enum LibsMsg { NO_MODS(ChatColor.RED + "%s is not using any mods!"), MODS_LIST(ChatColor.DARK_GREEN + "%s has the mods:" + ChatColor.AQUA + " %s"), NO_PERM(ChatColor.RED + "You are forbidden to use this command."), - UPDATE_NOT_READY(ChatColor.RED + - "Lib's Disguises doesn't know what's the latest update! Use 'update!' to force an update to latest!"), UPDATE_ON_LATEST(ChatColor.RED + "You are already on the latest version of LibsDisguises!"), + UPDATE_ALREADY_DOWNLOADED(ChatColor.RED + "That update has already been downloaded!"), UPDATE_FAILED(ChatColor.RED + "LibsDisguises update failed! Check console for errors."), UPDATE_SUCCESS(ChatColor.DARK_GREEN + "LibsDisguises update success! Restart server to update!"), UPDATE_INFO(ChatColor.DARK_GREEN + "Lib's Disguises v%s, build %s, built %s and size %skb"), diff --git a/src/main/java/me/libraryaddict/disguise/utilities/updates/DisguiseUpdate.java b/src/main/java/me/libraryaddict/disguise/utilities/updates/DisguiseUpdate.java new file mode 100644 index 00000000..43c54855 --- /dev/null +++ b/src/main/java/me/libraryaddict/disguise/utilities/updates/DisguiseUpdate.java @@ -0,0 +1,24 @@ +package me.libraryaddict.disguise.utilities.updates; + +import java.util.Date; + +/** + * Created by libraryaddict on 26/04/2020. + */ +public interface DisguiseUpdate { + /** + * Null if invalid + */ + String getVersion(); + + boolean isReleaseBuild(); + + String getDownload(); + + String[] getChangelog(); + + /** + * When was this update fetched? + */ + Date getFetched(); +} diff --git a/src/main/java/me/libraryaddict/disguise/utilities/updates/LDGithub.java b/src/main/java/me/libraryaddict/disguise/utilities/updates/LDGithub.java new file mode 100644 index 00000000..635baea1 --- /dev/null +++ b/src/main/java/me/libraryaddict/disguise/utilities/updates/LDGithub.java @@ -0,0 +1,95 @@ +package me.libraryaddict.disguise.utilities.updates; + +import com.google.gson.Gson; +import lombok.AllArgsConstructor; +import lombok.Getter; +import me.libraryaddict.disguise.utilities.DisguiseUtilities; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.stream.Collectors; + +/** + * Created by libraryaddict on 26/04/2020. + */ +public class LDGithub { + @Getter + @AllArgsConstructor + private class GithubUpdate implements DisguiseUpdate { + private String version; + private String[] changelog; + private String download; + private final Date fetched = new Date(); + + @Override + public boolean isReleaseBuild() { + return true; + } + } + + @Getter + private class GithubData { + @Getter + class Asset { + String browser_download_url; + String name; + String content_type; + } + + String name; + String tag_name; + String body; + Date published_at; + Asset[] assets; + } + + public DisguiseUpdate getLatestRelease() { + try { + // We're connecting to md_5's jenkins REST api + URL url = new URL("https://api.github.com/repos/libraryaddict/LibsDisguises/releases/latest"); + // Creating a connection + HttpURLConnection con = (HttpURLConnection) url.openConnection(); + con.setRequestProperty("User-Agent", "libraryaddict/LibsDisguises"); + con.setRequestProperty("Accept", "application/vnd.github.v3+json"); + + GithubData gitData; + + // Get the input stream, what we receive + try (InputStream input = con.getInputStream()) { + // Read it to string + String json = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)).lines() + .collect(Collectors.joining("\n")); + + gitData = new Gson().fromJson(json, GithubData.class); + } + + String download = null; + + for (GithubData.Asset asset : gitData.getAssets()) { + if (!asset.getName().endsWith(".jar")) { + continue; + } + + download = asset.getBrowser_download_url(); + break; + } + + if (download == null) { + throw new IllegalStateException("Download url is missing"); + } + + return new GithubUpdate(gitData.getTag_name().replace("v", ""), gitData.getBody().split("(\\r|\\n)+"), download); + } + catch (Exception ex) { + DisguiseUtilities.getLogger().warning("Failed to check for a release on Github"); + ex.printStackTrace(); + } + + return null; + } +} diff --git a/src/main/java/me/libraryaddict/disguise/utilities/updates/LDJenkins.java b/src/main/java/me/libraryaddict/disguise/utilities/updates/LDJenkins.java new file mode 100644 index 00000000..fa45ced7 --- /dev/null +++ b/src/main/java/me/libraryaddict/disguise/utilities/updates/LDJenkins.java @@ -0,0 +1,104 @@ +package me.libraryaddict.disguise.utilities.updates; + +import com.google.gson.Gson; +import lombok.AllArgsConstructor; +import lombok.Getter; +import me.libraryaddict.disguise.LibsDisguises; +import me.libraryaddict.disguise.utilities.DisguiseUtilities; +import me.libraryaddict.disguise.utilities.plugin.PluginInformation; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * Created by libraryaddict on 26/04/2020. + */ +public class LDJenkins { + private UpdateChecker updateChecker; + + @AllArgsConstructor + @Getter + private class JenkinsUpdate implements DisguiseUpdate { + private final Date fetched = new Date(); + private final String version; + private final String[] changelog; + + @Override + public String getDownload() { + return "https://ci.md-5.net/job/LibsDisguises/" + getVersion() + "/artifact/target/LibsDisguises.jar"; + } + + @Override + public boolean isReleaseBuild() { + return false; + } + } + + /** + * Fetches from jenkins, using the REST api the last snapshot build information + */ + private Map fetchLastSnapshotBuild() { + try { + // We're connecting to md_5's jenkins REST api + URL url = new URL("https://ci.md-5.net/job/LibsDisguises/lastSuccessfulBuild/api/json"); + // Creating a connection + HttpURLConnection con = (HttpURLConnection) url.openConnection(); + con.setDefaultUseCaches(false); + Map jsonObject; + + // Get the input stream, what we receive + try (InputStream input = con.getInputStream()) { + // Read it to string + String json = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)).lines() + .collect(Collectors.joining("\n")); + + jsonObject = new Gson().fromJson(json, Map.class); + } + + return jsonObject; + } + catch (Exception ex) { + DisguiseUtilities.getLogger().warning("Failed to check for a snapshot update on jenkins."); + ex.printStackTrace(); + } + + return null; + } + + public DisguiseUpdate getLatestSnapshot() { + Map lastBuild = fetchLastSnapshotBuild(); + + if (lastBuild == null || !lastBuild.containsKey("id") || !lastBuild.containsKey("timestamp")) { + return null; + } + + ArrayList changelog = new ArrayList<>(); + + if (lastBuild.get("changeSet") instanceof Map) { + Object items = ((Map) lastBuild.get("changeSet")).get("items"); + + if (items instanceof Map[]) { + for (Map item : (Map[]) items) { + String msg = (String) item.get("msg"); + + if (msg == null) { + continue; + } + + changelog.add(msg); + } + } + } + + return new JenkinsUpdate((String) lastBuild.get("id"), changelog.toArray(new String[0])); + } +} diff --git a/src/main/java/me/libraryaddict/disguise/utilities/updates/UpdateChecker.java b/src/main/java/me/libraryaddict/disguise/utilities/updates/UpdateChecker.java new file mode 100644 index 00000000..27690144 --- /dev/null +++ b/src/main/java/me/libraryaddict/disguise/utilities/updates/UpdateChecker.java @@ -0,0 +1,290 @@ +package me.libraryaddict.disguise.utilities.updates; + +import lombok.Getter; +import me.libraryaddict.disguise.DisguiseConfig; +import me.libraryaddict.disguise.LibsDisguises; +import me.libraryaddict.disguise.utilities.DisguiseUtilities; +import me.libraryaddict.disguise.utilities.LibsPremium; +import me.libraryaddict.disguise.utilities.plugin.PluginInformation; +import me.libraryaddict.disguise.utilities.translations.LibsMsg; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.craftbukkit.libs.org.apache.commons.io.FileUtils; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitTask; + +import java.io.BufferedReader; +import java.io.File; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; + +public class UpdateChecker { + private final String resourceID; + private final long started = System.currentTimeMillis(); + @Getter + private PluginInformation lastDownload; + private final AtomicBoolean downloading = new AtomicBoolean(false); + @Getter + private DisguiseUpdate update; + private LDGithub githubUpdater = new LDGithub(); + private LDJenkins jenkinsUpdater = new LDJenkins(); + @Getter + private String[] updateMessage = new String[0]; + + public UpdateChecker(String resourceID) { + this.resourceID = resourceID; + } + + public boolean isDownloading() { + return downloading.get(); + } + + public boolean isUsingReleaseBuilds() { + DisguiseConfig.UpdatesBranch builds = DisguiseConfig.getUpdatesBranch(); + + return builds == DisguiseConfig.UpdatesBranch.RELEASES || + (builds == DisguiseConfig.UpdatesBranch.SAME_BUILDS && DisguiseConfig.isUsingReleaseBuild()); + } + + public void notifyUpdate(CommandSender player) { + if (!DisguiseConfig.isNotifyUpdate() || !player.hasPermission("libsdisguises.update")) { + return; + } + + if (updateMessage == null || updateMessage.length == 0) { + return; + } + + if (player instanceof Player) { + player.sendMessage(updateMessage); + } else { + for (String s : updateMessage) { + DisguiseUtilities.getLogger().info(s); + } + } + } + + public boolean isUpdateReady() { + if (getUpdate() == null) { + return false; + } + + String version; + + if (getUpdate().isReleaseBuild()) { + if (lastDownload != null) { + version = lastDownload.getVersion(); + } else { + version = LibsDisguises.getInstance().getDescription().getVersion(); + } + } else { + if (lastDownload != null) { + version = lastDownload.getBuildNumber(); + } else { + version = LibsDisguises.getInstance().getBuildNo(); + } + } + + return getUpdate() != null && !getUpdate().getVersion().equals(version); + } + + public void doAutoUpdateCheck() { + try { + DisguiseUpdate oldUpdate = getUpdate(); + + updateMessage = new String[0]; + + doUpdateCheck(); + + if (!isUpdateReady() || (oldUpdate != null && oldUpdate.getVersion().equals(getUpdate().getVersion()))) { + return; + } + + notifyUpdate(Bukkit.getConsoleSender()); + + if (DisguiseConfig.isAutoUpdate()) { + // Update message changed by download + grabJarDownload(getUpdate().getDownload()); + + notifyUpdate(Bukkit.getConsoleSender()); + } + + Bukkit.getScheduler().runTask(LibsDisguises.getInstance(), () -> { + for (Player p : Bukkit.getOnlinePlayers()) { + notifyUpdate(p); + } + }); + } + catch (Exception ex) { + DisguiseUtilities.getLogger().warning(String.format("Failed to check for update: %s", ex.getMessage())); + } + } + + public PluginInformation doUpdate() { + // If no update on file, or more than 6 hours hold. Check for update + if (getUpdate() == null || + getUpdate().getFetched().before(new Date(System.currentTimeMillis() - TimeUnit.HOURS.toMillis(6)))) { + doUpdateCheck(); + } + + if (getUpdate() == null) { + return null; + } + + return grabJarDownload(getUpdate().getDownload()); + } + + public LibsMsg doUpdateCheck() { + downloading.set(false); + + try { + update = null; + + if (isUsingReleaseBuilds()) { + update = githubUpdater.getLatestRelease(); + } else { + update = jenkinsUpdater.getLatestSnapshot(); + } + } + finally { + downloading.set(false); + } + + if (getUpdate() == null) { + return LibsMsg.UPDATE_FAILED; + } + + if (getUpdate().isReleaseBuild()) { + String currentVersion = LibsDisguises.getInstance().getDescription().getVersion(); + + if (!isNewerVersion(currentVersion, getUpdate().getVersion())) { + return LibsMsg.UPDATE_ON_LATEST; + } + + updateMessage = new String[]{LibsMsg.UPDATE_READY.get(currentVersion, getUpdate().getVersion())}; + } else { + if (!getUpdate().getVersion().matches("[0-9]+")) { + return LibsMsg.UPDATE_FAILED; + } + + int newBuild = Integer.parseInt(getUpdate().getVersion()); + + if (newBuild <= LibsDisguises.getInstance().getBuildNumber()) { + return LibsMsg.UPDATE_ON_LATEST; + } + + updateMessage = new String[]{ + LibsMsg.UPDATE_READY_SNAPSHOT.get(LibsDisguises.getInstance().getBuildNo(), newBuild)}; + } + + return null; + } + + private PluginInformation grabJarDownload(String urlString) { + downloading.set(true); + + DisguiseUtilities.getLogger().info("Now downloading build of Lib's Disguises from " + urlString); + + File dest = new File(Bukkit.getUpdateFolderFile(), LibsDisguises.getInstance().getFile().getName()); + + if (dest.exists()) { + dest.delete(); + } + + dest.getParentFile().mkdirs(); + + try { + // We're connecting to spigot's API + URL url = new URL(urlString); + // Creating a connection + HttpURLConnection con = (HttpURLConnection) url.openConnection(); + con.setDefaultUseCaches(false); + + // Get the input stream, what we receive + try (InputStream input = con.getInputStream()) { + FileUtils.copyInputStreamToFile(input, dest); + } + + DisguiseUtilities.getLogger().info("Download success!"); + + PluginInformation result = LibsPremium.getInformation(dest); + lastDownload = result; + + updateMessage = new String[]{LibsMsg.UPDATE_SUCCESS.get(), + LibsMsg.UPDATE_INFO.get(result.getVersion(), result.getBuildNumber(), + result.getParsedBuildDate().toString(), result.getSize() / 1024)}; + + return result; + } + catch (Exception ex) { + // Failed, set the last download back to previous build + dest.delete(); + DisguiseUtilities.getLogger().warning("Failed to download snapshot build."); + ex.printStackTrace(); + } + finally { + downloading.set(false); + } + + return null; + } + + /** + * Asks spigot for the version + */ + private String fetchSpigotVersion() { + try { + // We're connecting to spigot's API + URL url = new URL("https://api.spigotmc.org/legacy/update.php?resource=" + resourceID); + // Creating a connection + HttpURLConnection con = (HttpURLConnection) url.openConnection(); + con.setDefaultUseCaches(false); + + // Get the input stream, what we receive + try (InputStream input = con.getInputStream()) { + // Read it to string + String version = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)).lines() + .collect(Collectors.joining("\n")); + + // If the version is not empty, return it + if (!version.isEmpty()) { + return version; + } + } + } + catch (Exception ex) { + DisguiseUtilities.getLogger().warning("Failed to check for a update on spigot."); + } + + return null; + } + + private boolean isNewerVersion(String currentVersion, String newVersion) { + currentVersion = currentVersion.replaceAll("(v)|(-SNAPSHOT)", ""); + newVersion = newVersion.replaceAll("(v)|(-SNAPSHOT)", ""); + + // If the server has been online for less than 6 hours and both versions are 1.1.1 kind of versions + if (started + TimeUnit.HOURS.toMillis(6) > System.currentTimeMillis() && + currentVersion.matches("[0-9]+(\\.[0-9]+)*") && newVersion.matches("[0-9]+(\\.[0-9]+)*")) { + + int cVersion = Integer.parseInt(currentVersion.replace(".", "")); + int nVersion = Integer.parseInt(newVersion.replace(".", "")); + + // If the current version is a higher version, and is only a higher version by 3 minor numbers + // Then we have a cache problem + if (cVersion > nVersion && nVersion + 3 > cVersion) { + return false; + } + } + + // Lets just ignore all this fancy logic, and say that if you're not on the current release, you're outdated! + return !currentVersion.equals(newVersion); + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 9a35a993..f5e44c54 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -99,19 +99,16 @@ Scoreboard: WarnConflict: true # Shall I notify those with the correct permission when there's a LibsDisguises update? -# Disabling this will also disable auto updating +# Disabling this will also disable notifications when the plugin updated NotifyUpdate: true - -# Whats the permission to get the notification? -Permission: 'libsdisguises.update' +# Should the plugin automatically update? +AutoUpdate: true # Where should the plugin check for updates? # SAME_BUILDS - Will check snapshots if you're not using a release build # RELEASES - Only check for actual releases # SNAPSHOTS - Only check for new snapshots UpdatesBranch: SAME_BUILDS -# Should the plugin automatically update if the server is using dev builds? -AutoUpdateDev: true # Whats the max size allowed for command disguiseradius DisguiseRadiusMax: 50 diff --git a/src/main/resources/internal.yml b/src/main/resources/internal.yml new file mode 100644 index 00000000..e6e97553 --- /dev/null +++ b/src/main/resources/internal.yml @@ -0,0 +1,8 @@ +# If you're using BisectHosting, this will tell the server to enable premium for free! +# However if you're not using BisectHosting, this is false so the server won't waste time +# Coupon 'libraryaddict' for 25% off your first invoice on any of their gaming server +# Be sure to visit through this link! https://bisecthosting.com/libraryaddict +Bisect-Hosted: %data% +Server-IP: %data% +# Should the plugin be doing release or dev builds updating? +ReleaseBuild: %data% \ No newline at end of file