Update updater
- Updated the updater to use the same system BigDoors uses. This system is much cleaner and better and it uses Spiget to check for updates instead of DBO. - Introduced new config option "auto-update" to control if new updates are downloaded automatically or not.
This commit is contained in:
		| @@ -10,7 +10,7 @@ import nl.pim16aap2.armoredElytra.util.ArmorTier; | ||||
| import nl.pim16aap2.armoredElytra.util.ArmorTierName; | ||||
| import nl.pim16aap2.armoredElytra.util.ConfigLoader; | ||||
| import nl.pim16aap2.armoredElytra.util.Messages; | ||||
| import nl.pim16aap2.armoredElytra.util.Update; | ||||
| import nl.pim16aap2.armoredElytra.util.UpdateManager; | ||||
| import org.bstats.bukkit.Metrics; | ||||
| import org.bukkit.Bukkit; | ||||
| import org.bukkit.ChatColor; | ||||
| @@ -25,10 +25,10 @@ import java.util.Objects; | ||||
| import java.util.logging.Level; | ||||
| import java.util.regex.Pattern; | ||||
|  | ||||
| // TODO: Use this for NBT stuff: https://www.spigotmc.org/resources/item-entity-tile-nbt-api.7939/ | ||||
| // TODO: Figure out if the config really does read the list of enchantments accurately. A bug report with a customized config seemed to load the default settings... | ||||
| // TODO: Verify enchantments on startup. Remove them from the list if they're invalid. | ||||
| // TODO: Don't delete the config file. Look at BigDoors. | ||||
| // TODO: Don't delete the config/translation file. Look at BigDoors. | ||||
| // TODO: Enchanting should require XP. | ||||
|  | ||||
| public class ArmoredElytra extends JavaPlugin implements Listener | ||||
| { | ||||
| @@ -36,13 +36,13 @@ public class ArmoredElytra extends JavaPlugin implements Listener | ||||
|     private Messages messages; | ||||
|     private ConfigLoader config; | ||||
|  | ||||
|     //    private String leatherName, ironName, goldName, chainName, diamondName; | ||||
|     private final Map<ArmorTier, ArmorTierName> armorTierNames = new EnumMap(ArmorTier.class); | ||||
|     private final Map<ArmorTier, ArmorTierName> armorTierNames = new EnumMap<>(ArmorTier.class); | ||||
|     private String elytraReceivedMessage; | ||||
|     private String usageDeniedMessage; | ||||
|     private String elytraLore; | ||||
|     private boolean upToDate; | ||||
|     private boolean is1_9; | ||||
|     private UpdateManager updateManager; | ||||
|  | ||||
|     @Override | ||||
|     public void onEnable() | ||||
| @@ -52,48 +52,10 @@ public class ArmoredElytra extends JavaPlugin implements Listener | ||||
|         messages = new Messages(this); | ||||
|         readMessages(); | ||||
|  | ||||
|         updateManager = new UpdateManager(this, 47136); | ||||
|  | ||||
|         // Check if the user allows checking for updates. | ||||
|         if (config.checkForUpdates()) | ||||
|         { | ||||
|             // Check for updates in a new thread, so the server won't hang when it cannot contact the update servers. | ||||
|             final Thread thread = new Thread( | ||||
|                 () -> | ||||
|                 { | ||||
|                     final ArmoredElytra plugin = getPlugin(); | ||||
|                     final Update update = new Update(278437, plugin); | ||||
|                     final String latestVersion = update.getLatestVersion(); | ||||
|  | ||||
|                     if (latestVersion == null) | ||||
|                         plugin.myLogger(Level.WARNING, | ||||
|                                         "Encountered problem contacting update servers! Please check manually! The error above does not affect the plugin!"); | ||||
|                     else | ||||
|                     { | ||||
|                         final String thisVersion = plugin.getDescription().getVersion(); | ||||
|                         // Check if this is the latest version or not. | ||||
|                         final int updateStatus = update.versionCompare(latestVersion, thisVersion); | ||||
|  | ||||
|                         if (updateStatus > 0) | ||||
|                         { | ||||
|                             // Load the loginHandler to show messages to the user when they join. | ||||
|                             Bukkit.getPluginManager() | ||||
|                                   .registerEvents(new LoginHandler(plugin, "The Armored Elytra plugin is out of date!"), | ||||
|                                                   plugin); | ||||
|                             plugin.myLogger(Level.INFO, "Plugin out of date! You are using version " + thisVersion + | ||||
|                                 " but the latest version is version " + latestVersion + "!"); | ||||
|                             plugin.setUpToDate(false); | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                             plugin.setUpToDate(true); | ||||
|                             plugin.myLogger(Level.INFO, "You seem to be using the latest version of this plugin!"); | ||||
|                         } | ||||
|                     } | ||||
|                 }); | ||||
|             thread.start(); | ||||
|         } | ||||
|         else | ||||
|             myLogger(Level.INFO, | ||||
|                      "Plugin update checking not enabled! You will not receive any messages about new updates for this plugin. Please consider turning this on in the config."); | ||||
|         updateManager.setEnabled(config.checkForUpdates(), config.autoDLUpdate()); | ||||
|  | ||||
|         if (config.allowStats()) | ||||
|         { | ||||
| @@ -280,6 +242,11 @@ public class ArmoredElytra extends JavaPlugin implements Listener | ||||
|             player.getInventory().addItem(item); | ||||
|     } | ||||
|  | ||||
|     public UpdateManager getUpdateManager() | ||||
|     { | ||||
|         return updateManager; | ||||
|     } | ||||
|  | ||||
|     // Check + initialize for the correct version of Minecraft. | ||||
|     public boolean compatibleMCVer() | ||||
|     { | ||||
|   | ||||
| @@ -1,5 +1,9 @@ | ||||
| package nl.pim16aap2.armoredElytra.util; | ||||
|  | ||||
| import nl.pim16aap2.armoredElytra.ArmoredElytra; | ||||
| import org.bukkit.Bukkit; | ||||
| import org.bukkit.configuration.file.FileConfiguration; | ||||
|  | ||||
| import java.io.File; | ||||
| import java.io.FileWriter; | ||||
| import java.io.IOException; | ||||
| @@ -9,11 +13,6 @@ import java.util.Arrays; | ||||
| import java.util.List; | ||||
| import java.util.logging.Level; | ||||
|  | ||||
| import org.bukkit.Bukkit; | ||||
| import org.bukkit.configuration.file.FileConfiguration; | ||||
|  | ||||
| import nl.pim16aap2.armoredElytra.ArmoredElytra; | ||||
|  | ||||
| public class ConfigLoader | ||||
| { | ||||
|     private final String header; | ||||
| @@ -25,6 +24,7 @@ public class ConfigLoader | ||||
|     private int IRON_TO_FULL; | ||||
|     private boolean uninstallMode; | ||||
|     private boolean checkForUpdates; | ||||
|     private boolean autoDLUpdate; | ||||
|     private int LEATHER_TO_FULL; | ||||
|     private int DIAMONDS_TO_FULL; | ||||
|     private boolean noFlightDurability; | ||||
| @@ -33,7 +33,7 @@ public class ConfigLoader | ||||
|     public boolean bypassWearPerm; | ||||
|     public boolean bypassCraftPerm; | ||||
|  | ||||
|     private ArrayList<ConfigOption<?>> configOptionsList; | ||||
|     private ArrayList<nl.pim16aap2.armoredElytra.util.ConfigOption<?>> configOptionsList; | ||||
|     private ArmoredElytra plugin; | ||||
|  | ||||
|     public ConfigLoader(ArmoredElytra plugin) | ||||
| @@ -73,7 +73,12 @@ public class ConfigLoader | ||||
|             }; | ||||
|         String[] updateComment = | ||||
|             { | ||||
|                 "Allow this plugin to check for updates on startup. It will not download new versions!" | ||||
|                 "Allow this plugin to check for updates on startup. It will not download new versions unless \"auto-update is enabled\'!" | ||||
|             }; | ||||
|         String[] autoDLUpdateComment = | ||||
|             { | ||||
|                 "Allow this plugin to automatically download new updates. They will be applied on restart.", | ||||
|                 "This option has no effect if \"checkForUpdates\" is disabled." | ||||
|             }; | ||||
|         String[] bStatsComment = | ||||
|             { | ||||
| @@ -112,7 +117,8 @@ public class ConfigLoader | ||||
|  | ||||
|         // Set default list of allowed enchantments. | ||||
|         allowedEnchantments = new ArrayList<>(Arrays.asList("DURABILITY", "PROTECTION_FIRE", "PROTECTION_EXPLOSIONS", | ||||
|                                                                   "PROTECTION_PROJECTILE", "PROTECTION_ENVIRONMENTAL", "THORNS", | ||||
|                                                             "PROTECTION_PROJECTILE", "PROTECTION_ENVIRONMENTAL", | ||||
|                                                             "THORNS", | ||||
|                                                             "BINDING_CURSE", "VANISHING_CURSE", "MENDING")); | ||||
|  | ||||
|         FileConfiguration config = plugin.getConfig(); | ||||
| @@ -123,9 +129,12 @@ public class ConfigLoader | ||||
|         GOLD_TO_FULL = addNewConfigOption(config, "goldRepair", 5, null); | ||||
|         IRON_TO_FULL = addNewConfigOption(config, "ironRepair", 4, null); | ||||
|         DIAMONDS_TO_FULL = addNewConfigOption(config, "diamondsRepair", 3, null); | ||||
|         allowedEnchantments = addNewConfigOption(config, "allowedEnchantments", allowedEnchantments, enchantmentsComment); | ||||
|         allowMultipleProtectionEnchantments = addNewConfigOption(config, "allowMultipleProtectionEnchantments", false, allowMultipleProtectionEnchantmentsComment); | ||||
|         allowedEnchantments = addNewConfigOption(config, "allowedEnchantments", allowedEnchantments, | ||||
|                                                  enchantmentsComment); | ||||
|         allowMultipleProtectionEnchantments = addNewConfigOption(config, "allowMultipleProtectionEnchantments", false, | ||||
|                                                                  allowMultipleProtectionEnchantmentsComment); | ||||
|         checkForUpdates = addNewConfigOption(config, "checkForUpdates", true, updateComment); | ||||
|         autoDLUpdate = addNewConfigOption(config, "auto-update", true, autoDLUpdateComment); | ||||
|         allowStats = addNewConfigOption(config, "allowStats", true, bStatsComment); | ||||
|         enableDebug = addNewConfigOption(config, "enableDebug", false, debugComment); | ||||
|         uninstallMode = addNewConfigOption(config, "uninstallMode", false, uninstallComment); | ||||
| @@ -138,7 +147,8 @@ public class ConfigLoader | ||||
|  | ||||
|     private <T> T addNewConfigOption(FileConfiguration config, String optionName, T defaultValue, String[] comment) | ||||
|     { | ||||
|         ConfigOption<T> option = new ConfigOption<>(plugin, config, optionName, defaultValue, comment); | ||||
|         nl.pim16aap2.armoredElytra.util.ConfigOption<T> option = new nl.pim16aap2.armoredElytra.util.ConfigOption<>( | ||||
|             plugin, config, optionName, defaultValue, comment); | ||||
|         configOptionsList.add(option); | ||||
|         return option.getValue(); | ||||
|     } | ||||
| @@ -170,15 +180,16 @@ public class ConfigLoader | ||||
|             for (int idx = 0; idx < configOptionsList.size(); ++idx) | ||||
|                 pw.println(configOptionsList.get(idx).toString() + | ||||
|                                // Only print an additional newLine if the next config option has a comment. | ||||
|                     (idx < configOptionsList.size() - 1 && configOptionsList.get(idx + 1).getComment() == null ? "" | ||||
|                                                                                                                : "\n")); | ||||
|                                (idx < configOptionsList.size() - 1 && | ||||
|                                     configOptionsList.get(idx + 1).getComment() == null ? "" : "\n")); | ||||
|  | ||||
|             pw.flush(); | ||||
|             pw.close(); | ||||
|         } | ||||
|         catch (IOException e) | ||||
|         { | ||||
|             Bukkit.getLogger().log(Level.SEVERE, "Could not save config.yml! Please contact pim16aap2 and show him the following code:"); | ||||
|             Bukkit.getLogger().log(Level.SEVERE, | ||||
|                                    "Could not save config.yml! Please contact pim16aap2 and show him the following code:"); | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|     } | ||||
| @@ -239,6 +250,11 @@ public class ConfigLoader | ||||
|         return checkForUpdates; | ||||
|     } | ||||
|  | ||||
|     public boolean autoDLUpdate() | ||||
|     { | ||||
|         return autoDLUpdate; | ||||
|     } | ||||
|  | ||||
|     public boolean noFlightDurability() | ||||
|     { | ||||
|         return noFlightDurability; | ||||
|   | ||||
							
								
								
									
										466
									
								
								src/main/java/nl/pim16aap2/armoredElytra/util/UpdateChecker.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										466
									
								
								src/main/java/nl/pim16aap2/armoredElytra/util/UpdateChecker.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,466 @@ | ||||
| package nl.pim16aap2.armoredElytra.util; | ||||
|  | ||||
| import com.google.common.base.Preconditions; | ||||
| import com.google.gson.JsonElement; | ||||
| import com.google.gson.JsonObject; | ||||
| import com.google.gson.JsonParser; | ||||
| import com.google.gson.JsonSyntaxException; | ||||
| import nl.pim16aap2.armoredElytra.ArmoredElytra; | ||||
| import org.apache.commons.lang.math.NumberUtils; | ||||
| import org.bukkit.Bukkit; | ||||
| import org.bukkit.plugin.java.JavaPlugin; | ||||
|  | ||||
| import java.io.BufferedInputStream; | ||||
| import java.io.BufferedOutputStream; | ||||
| import java.io.File; | ||||
| import java.io.FileOutputStream; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStreamReader; | ||||
| import java.net.HttpURLConnection; | ||||
| import java.net.URL; | ||||
| import java.time.Instant; | ||||
| import java.util.concurrent.CompletableFuture; | ||||
| import java.util.logging.Level; | ||||
| import java.util.regex.Matcher; | ||||
| import java.util.regex.Pattern; | ||||
|  | ||||
| /** | ||||
|  * A utility class to assist in checking for updates for plugins uploaded to | ||||
|  * <a href="https://spigotmc.org/resources/">SpigotMC</a>. Before any members of | ||||
|  * this class are accessed, {@link #init(ArmoredElytra, int)} must be invoked by the plugin, preferably in its {@link | ||||
|  * JavaPlugin#onEnable()} method, though that is not a requirement. | ||||
|  * <p> | ||||
|  * This class performs asynchronous queries to | ||||
|  * <a href="https://spiget.org">SpiGet</a>, an REST server which is updated | ||||
|  * periodically. If the results of {@link #requestUpdateCheck()} are inconsistent with what is published on SpigotMC, it | ||||
|  * may be due to SpiGet's cache. Results will be updated in due time. | ||||
|  * <p> | ||||
|  * Some modifications were made to support downloading of updates and storing the age of an update. | ||||
|  * | ||||
|  * @author Parker Hawke - 2008Choco | ||||
|  */ | ||||
| public final class UpdateChecker | ||||
| { | ||||
|     public static final VersionScheme VERSION_SCHEME_DECIMAL = (first, second) -> | ||||
|     { | ||||
|         String[] firstSplit = splitVersionInfo(first), secondSplit = splitVersionInfo(second); | ||||
|         if (firstSplit == null || secondSplit == null) | ||||
|             return null; | ||||
|  | ||||
|         for (int i = 0; i < Math.min(firstSplit.length, secondSplit.length); i++) | ||||
|         { | ||||
|             int currentValue = NumberUtils.toInt(firstSplit[i]), newestValue = NumberUtils.toInt(secondSplit[i]); | ||||
|  | ||||
|             if (newestValue > currentValue) | ||||
|                 return second; | ||||
|             else if (newestValue < currentValue) | ||||
|                 return first; | ||||
|         } | ||||
|  | ||||
|         return (secondSplit.length > firstSplit.length) ? second : first; | ||||
|     }; | ||||
|  | ||||
|     private static final String USER_AGENT = "ArmoredElytra-update-checker"; | ||||
|     private static final String UPDATE_URL = "https://api.spiget.org/v2/resources/%d/versions?size=1&sort=-releaseDate"; | ||||
|     private static final Pattern DECIMAL_SCHEME_PATTERN = Pattern.compile("\\d+(?:\\.\\d+)*"); | ||||
|     private final String downloadURL; | ||||
|  | ||||
|     private static UpdateChecker instance; | ||||
|  | ||||
|     private UpdateResult lastResult = null; | ||||
|  | ||||
|     private final ArmoredElytra plugin; | ||||
|     private final int pluginID; | ||||
|     private final VersionScheme versionScheme; | ||||
|  | ||||
|     private UpdateChecker(final ArmoredElytra plugin, final int pluginID, final VersionScheme versionScheme) | ||||
|     { | ||||
|         this.plugin = plugin; | ||||
|         this.pluginID = pluginID; | ||||
|         this.versionScheme = versionScheme; | ||||
|         downloadURL = "https://api.spiget.org/v2/resources/" + pluginID + "/download"; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Requests an update check to SpiGet. This request is asynchronous and may not complete immediately as an HTTP GET | ||||
|      * request is published to the SpiGet API. | ||||
|      * | ||||
|      * @return a future update result | ||||
|      */ | ||||
|     public CompletableFuture<UpdateResult> requestUpdateCheck() | ||||
|     { | ||||
|         return CompletableFuture.supplyAsync( | ||||
|             () -> | ||||
|             { | ||||
|                 int responseCode = -1; | ||||
|                 try | ||||
|                 { | ||||
|                     URL url = new URL(String.format(UPDATE_URL, pluginID)); | ||||
|                     HttpURLConnection connection = (HttpURLConnection) url.openConnection(); | ||||
|                     connection.addRequestProperty("User-Agent", USER_AGENT); | ||||
|  | ||||
|                     InputStreamReader reader = new InputStreamReader(connection.getInputStream()); | ||||
|                     responseCode = connection.getResponseCode(); | ||||
|  | ||||
|                     JsonElement element = new JsonParser().parse(reader); | ||||
|                     if (!element.isJsonArray()) | ||||
|                         return new UpdateResult(UpdateReason.INVALID_JSON); | ||||
|  | ||||
|                     reader.close(); | ||||
|  | ||||
|                     JsonObject versionObject = element.getAsJsonArray().get(0).getAsJsonObject(); | ||||
|  | ||||
|                     long age = -1; | ||||
|                     String ageString = versionObject.get("releaseDate").getAsString(); | ||||
|                     try | ||||
|                     { | ||||
|                         age = getAge(Long.parseLong(ageString)); | ||||
|                     } | ||||
|                     catch (NumberFormatException e) | ||||
|                     { | ||||
|                         plugin.myLogger(Level.WARNING, | ||||
|                                         "Failed to obtain age of update from ageString: \"" + ageString + "\""); | ||||
|                     } | ||||
|  | ||||
|                     String current = plugin.getDescription().getVersion(), newest = versionObject.get("name") | ||||
|                                                                                                  .getAsString(); | ||||
|                     String latest = versionScheme.compareVersions(current, newest); | ||||
|  | ||||
|                     if (latest == null) | ||||
|                         return new UpdateResult(UpdateReason.UNSUPPORTED_VERSION_SCHEME); | ||||
|                     else if (latest.equals(current)) | ||||
|                         return new UpdateResult(current.equals(newest) ? | ||||
|                                                 UpdateReason.UP_TO_DATE : | ||||
|                                                 UpdateReason.UNRELEASED_VERSION, current, age); | ||||
|                     else if (latest.equals(newest)) | ||||
|                         return new UpdateResult(UpdateReason.NEW_UPDATE, latest, age); | ||||
|                 } | ||||
|                 catch (IOException e) | ||||
|                 { | ||||
|                     return new UpdateResult(UpdateReason.COULD_NOT_CONNECT); | ||||
|                 } | ||||
|                 catch (JsonSyntaxException e) | ||||
|                 { | ||||
|                     return new UpdateResult(UpdateReason.INVALID_JSON); | ||||
|                 } | ||||
|  | ||||
|                 return new UpdateResult(responseCode == 401 ? | ||||
|                                         UpdateReason.UNAUTHORIZED_QUERY : UpdateReason.UNKNOWN_ERROR); | ||||
|             }); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Gets the difference in seconds between a given time and the current time. | ||||
|      * | ||||
|      * @param updateTime A moment in time to compare the current time to. | ||||
|      * @return The difference in seconds between a given time and the current time. | ||||
|      */ | ||||
|     private long getAge(final long updateTime) | ||||
|     { | ||||
|         long currentTime = Instant.now().getEpochSecond(); | ||||
|         return currentTime - updateTime; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Gets the last update result that was queried by {@link #requestUpdateCheck()}. If no update check was performed | ||||
|      * since this class' initialization, this method will return null. | ||||
|      * | ||||
|      * @return the last update check result. null if none. | ||||
|      */ | ||||
|     public UpdateResult getLastResult() | ||||
|     { | ||||
|         return lastResult; | ||||
|     } | ||||
|  | ||||
|     private static String[] splitVersionInfo(String version) | ||||
|     { | ||||
|         Matcher matcher = DECIMAL_SCHEME_PATTERN.matcher(version); | ||||
|         if (!matcher.find()) | ||||
|             return null; | ||||
|  | ||||
|         return matcher.group().split("\\."); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Gets the url to download the latest version from. | ||||
|      * | ||||
|      * @return The url to download the latest version from. | ||||
|      */ | ||||
|     public String getDownloadUrl() | ||||
|     { | ||||
|         return downloadURL; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Downloads the latest update. | ||||
|      * | ||||
|      * @return True if the download was successful. | ||||
|      */ | ||||
|     public boolean downloadUpdate() | ||||
|     { | ||||
|         boolean downloadSuccessfull = false; | ||||
|         try | ||||
|         { | ||||
|             File updateFolder = Bukkit.getUpdateFolderFile(); | ||||
|             if (!updateFolder.exists()) | ||||
|                 if (!updateFolder.mkdirs()) | ||||
|                     throw new RuntimeException("Failed to create update folder!"); | ||||
|  | ||||
|             String fileName = plugin.getName() + ".jar"; | ||||
|             File updateFile = new File(updateFolder + "/" + fileName); | ||||
|  | ||||
|             // Follow any and all redirects until we've finally found the actual file. | ||||
|             String location = downloadURL; | ||||
|             HttpURLConnection httpConnection = null; | ||||
|             for (; ; ) | ||||
|             { | ||||
|                 URL url = new URL(location); | ||||
|                 httpConnection = (HttpURLConnection) url.openConnection(); | ||||
|                 httpConnection.setInstanceFollowRedirects(false); | ||||
|                 httpConnection.setRequestProperty("User-Agent", "ArmoredElytraUpdater"); | ||||
|                 String redirectLocation = httpConnection.getHeaderField("Location"); | ||||
|                 if (redirectLocation == null) | ||||
|                     break; | ||||
|                 location = redirectLocation; | ||||
|                 httpConnection.disconnect(); | ||||
|             } | ||||
|  | ||||
|             if (httpConnection == null) | ||||
|             { | ||||
|                 plugin.myLogger(Level.WARNING, "Failed to construct connection: " + location); | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
|             if (httpConnection.getResponseCode() != 200) | ||||
|             { | ||||
|                 plugin.myLogger(Level.WARNING, | ||||
|                                 Util.exceptionToString(new RuntimeException("Download returned status #" | ||||
|                                                                                 + httpConnection | ||||
|                                     .getResponseCode() + "\n for URL: " + downloadURL))); | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
|             int grabSize = 4096; | ||||
|             BufferedInputStream in = new BufferedInputStream(httpConnection.getInputStream()); | ||||
|             FileOutputStream fos = new FileOutputStream(updateFile); | ||||
|             BufferedOutputStream bout = new BufferedOutputStream(fos, grabSize); | ||||
|  | ||||
|             byte[] data = new byte[grabSize]; | ||||
|             int grab; | ||||
|             while ((grab = in.read(data, 0, grabSize)) >= 0) | ||||
|                 bout.write(data, 0, grab); | ||||
|  | ||||
|             bout.flush(); | ||||
|             bout.close(); | ||||
|             in.close(); | ||||
|             fos.flush(); | ||||
|             fos.close(); | ||||
|             downloadSuccessfull = true; | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|         return downloadSuccessfull; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Initializes this update checker with the specified values and return its instance. If an instance of | ||||
|      * UpdateChecker has already been initialized, this method will act similarly to {@link #get()} (which is | ||||
|      * recommended after initialization). | ||||
|      * | ||||
|      * @param plugin        the plugin for which to check updates. Cannot be null | ||||
|      * @param pluginID      the ID of the plugin as identified in the SpigotMC resource link. For example, | ||||
|      *                      "https://www.spigotmc.org/resources/veinminer.<b>12038</b>/" would expect "12038" as a | ||||
|      *                      value. The value must be greater than 0 | ||||
|      * @param versionScheme a custom version scheme parser. Cannot be null | ||||
|      * @return the UpdateChecker instance | ||||
|      */ | ||||
|     public static UpdateChecker init(final ArmoredElytra plugin, final int pluginID, final VersionScheme versionScheme) | ||||
|     { | ||||
|         Preconditions.checkArgument(pluginID > 0, "Plugin ID must be greater than 0"); | ||||
|  | ||||
|         return (instance == null) ? instance = new UpdateChecker(plugin, pluginID, versionScheme) : instance; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Initializes this update checker with the specified values and return its instance. If an instance of | ||||
|      * UpdateChecker has already been initialized, this method will act similarly to {@link #get()} (which is | ||||
|      * recommended after initialization). | ||||
|      * | ||||
|      * @param plugin   the plugin for which to check updates. Cannot be null | ||||
|      * @param pluginID the ID of the plugin as identified in the SpigotMC resource link. For example, | ||||
|      *                 "https://www.spigotmc.org/resources/veinminer.<b>12038</b>/" would expect "12038" as a value. The | ||||
|      *                 value must be greater than 0 | ||||
|      * @return the UpdateChecker instance | ||||
|      */ | ||||
|     public static UpdateChecker init(final ArmoredElytra plugin, final int pluginID) | ||||
|     { | ||||
|         return init(plugin, pluginID, VERSION_SCHEME_DECIMAL); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Gets the initialized instance of UpdateChecker. If {@link #init(ArmoredElytra, int)} has not yet been invoked, | ||||
|      * this method will throw an exception. | ||||
|      * | ||||
|      * @return the UpdateChecker instance | ||||
|      */ | ||||
|     public static UpdateChecker get() | ||||
|     { | ||||
|         Preconditions.checkState(instance != null, | ||||
|                                  "Instance has not yet been initialized. Be sure #init() has been invoked"); | ||||
|         return instance; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Checks whether the UpdateChecker has been initialized or not (if {@link #init(ArmoredElytra, int)} has been | ||||
|      * invoked) and {@link #get()} is safe to use. | ||||
|      * | ||||
|      * @return true if initialized, false otherwise | ||||
|      */ | ||||
|     public static boolean isInitialized() | ||||
|     { | ||||
|         return instance != null; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * A functional interface to compare two version Strings with similar version schemes. | ||||
|      */ | ||||
|     @FunctionalInterface | ||||
|     public static interface VersionScheme | ||||
|     { | ||||
|  | ||||
|         /** | ||||
|          * Compare two versions and return the higher of the two. If null is returned, it is assumed that at least one | ||||
|          * of the two versions are unsupported by this version scheme parser. | ||||
|          * | ||||
|          * @param first  the first version to check | ||||
|          * @param second the second version to check | ||||
|          * @return the greater of the two versions. null if unsupported version schemes | ||||
|          */ | ||||
|         public String compareVersions(String first, String second); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * A constant reason for the result of {@link UpdateResult}. | ||||
|      */ | ||||
|     public static enum UpdateReason | ||||
|     { | ||||
|  | ||||
|         /** | ||||
|          * A new update is available for download on SpigotMC. | ||||
|          */ | ||||
|         NEW_UPDATE, // The only reason that requires an update | ||||
|  | ||||
|         /** | ||||
|          * A successful connection to the SpiGet API could not be established. | ||||
|          */ | ||||
|         COULD_NOT_CONNECT, | ||||
|  | ||||
|         /** | ||||
|          * The JSON retrieved from SpiGet was invalid or malformed. | ||||
|          */ | ||||
|         INVALID_JSON, | ||||
|  | ||||
|         /** | ||||
|          * A 401 error was returned by the SpiGet API. | ||||
|          */ | ||||
|         UNAUTHORIZED_QUERY, | ||||
|  | ||||
|         /** | ||||
|          * The version of the plugin installed on the server is greater than the one uploaded to SpigotMC's resources | ||||
|          * section. | ||||
|          */ | ||||
|         UNRELEASED_VERSION, | ||||
|  | ||||
|         /** | ||||
|          * An unknown error occurred. | ||||
|          */ | ||||
|         UNKNOWN_ERROR, | ||||
|  | ||||
|         /** | ||||
|          * The plugin uses an unsupported version scheme, therefore a proper comparison between versions could not be | ||||
|          * made. | ||||
|          */ | ||||
|         UNSUPPORTED_VERSION_SCHEME, | ||||
|  | ||||
|         /** | ||||
|          * The plugin is up to date with the version released on SpigotMC's resources section. | ||||
|          */ | ||||
|         UP_TO_DATE | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Represents a result for an update query performed by {@link UpdateChecker#requestUpdateCheck()}. | ||||
|      */ | ||||
|     public final class UpdateResult | ||||
|     { | ||||
|         private final UpdateReason reason; | ||||
|         private final String newestVersion; | ||||
|         private final long age; | ||||
|  | ||||
|         { // An actual use for initializer blocks. This is madness! | ||||
|             lastResult = this; | ||||
|         } | ||||
|  | ||||
|         private UpdateResult(final UpdateReason reason, final String newestVersion, final long age) | ||||
|         { | ||||
|             this.reason = reason; | ||||
|             this.newestVersion = newestVersion; | ||||
|             this.age = age; | ||||
|         } | ||||
|  | ||||
|         private UpdateResult(final UpdateReason reason) | ||||
|         { | ||||
|             Preconditions | ||||
|                 .checkArgument(reason != UpdateReason.NEW_UPDATE && reason != UpdateReason.UP_TO_DATE, | ||||
|                                "Reasons that might require updates must also provide the latest version String"); | ||||
|             this.reason = reason; | ||||
|             newestVersion = plugin.getDescription().getVersion(); | ||||
|             age = -1; | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|          * Gets the constant reason of this result. | ||||
|          * | ||||
|          * @return the reason | ||||
|          */ | ||||
|         public UpdateReason getReason() | ||||
|         { | ||||
|             return reason; | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|          * Checks whether or not this result requires the user to update. | ||||
|          * | ||||
|          * @return true if requires update, false otherwise | ||||
|          */ | ||||
|         public boolean requiresUpdate() | ||||
|         { | ||||
|             return reason == UpdateReason.NEW_UPDATE; | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|          * Gets the latest version of the plugin. This may be the currently installed version, it may not be. This | ||||
|          * depends entirely on the result of the update. | ||||
|          * | ||||
|          * @return the newest version of the plugin | ||||
|          */ | ||||
|         public String getNewestVersion() | ||||
|         { | ||||
|             return newestVersion; | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|          * Gets the number of seconds since the last update was released. | ||||
|          * | ||||
|          * @return The number of seconds since the last update was released or -1 if unavailable. | ||||
|          */ | ||||
|         public long getAge() | ||||
|         { | ||||
|             return age; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										117
									
								
								src/main/java/nl/pim16aap2/armoredElytra/util/UpdateManager.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								src/main/java/nl/pim16aap2/armoredElytra/util/UpdateManager.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,117 @@ | ||||
| package nl.pim16aap2.armoredElytra.util; | ||||
|  | ||||
| import nl.pim16aap2.armoredElytra.ArmoredElytra; | ||||
| import nl.pim16aap2.armoredElytra.util.UpdateChecker.UpdateReason; | ||||
| import org.bukkit.scheduler.BukkitRunnable; | ||||
| import org.bukkit.scheduler.BukkitTask; | ||||
|  | ||||
| import java.util.logging.Level; | ||||
|  | ||||
| /** | ||||
|  * @author Pim | ||||
|  */ | ||||
| public final class UpdateManager | ||||
| { | ||||
|     private final ArmoredElytra plugin; | ||||
|     private boolean checkForUpdates = false; | ||||
|     private boolean downloadUpdates = false; | ||||
|     private boolean updateDownloaded = false; | ||||
|  | ||||
|     private UpdateChecker updater; | ||||
|     private BukkitTask updateRunner = null; | ||||
|  | ||||
|     public UpdateManager(final ArmoredElytra plugin, final int pluginID) | ||||
|     { | ||||
|         this.plugin = plugin; | ||||
|         updater = UpdateChecker.init(plugin, pluginID); | ||||
|     } | ||||
|  | ||||
|     public void setEnabled(final boolean newCheckForUpdates, final boolean newDownloadUpdates) | ||||
|     { | ||||
|         checkForUpdates = newCheckForUpdates; | ||||
|         downloadUpdates = newDownloadUpdates; | ||||
|         initUpdater(); | ||||
|     } | ||||
|  | ||||
|     public boolean hasUpdateBeenDownloaded() | ||||
|     { | ||||
|         return updateDownloaded; | ||||
|     } | ||||
|  | ||||
|     public String getNewestVersion() | ||||
|     { | ||||
|         if (!checkForUpdates || updater.getLastResult() == null) | ||||
|             return null; | ||||
|         return updater.getLastResult().getNewestVersion(); | ||||
|     } | ||||
|  | ||||
|     public boolean updateAvailable() | ||||
|     { | ||||
|         // Updates disabled, so no new updates available by definition. | ||||
|         if (!checkForUpdates || updater.getLastResult() == null) | ||||
|             return false; | ||||
|  | ||||
|         // There's a newer version available. | ||||
|         if (updater.getLastResult().requiresUpdate()) | ||||
|             return true; | ||||
|  | ||||
|         // The plugin is "up-to-date", but this is a dev-build, so it must be newer. | ||||
|         if (updater.getLastResult().getReason().equals(UpdateReason.UP_TO_DATE)) | ||||
|             return true; | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     public void checkForUpdates() | ||||
|     { | ||||
|         updater.requestUpdateCheck().whenComplete( | ||||
|             (result, throwable) -> | ||||
|             { | ||||
|                 boolean updateAvailable = updateAvailable(); | ||||
|                 if (updateAvailable) | ||||
|                     plugin.myLogger(Level.INFO, | ||||
|                                     "A new update is available: " + plugin.getUpdateManager().getNewestVersion()); | ||||
|  | ||||
|                 if (downloadUpdates && updateAvailable) | ||||
|                 { | ||||
|                     updateDownloaded = updater.downloadUpdate(); | ||||
|                     if (updateDownloaded) | ||||
|                         plugin.myLogger(Level.INFO, "Update downloaded! Restart to apply it! " + | ||||
|                             "New version is " + updater.getLastResult().getNewestVersion() + | ||||
|                             ", Currently running " + plugin.getDescription().getVersion()); | ||||
|                     else | ||||
|                         plugin.myLogger(Level.INFO, | ||||
|                                         "Failed to download latest version! You can download it manually at: " + | ||||
|                                             updater.getDownloadUrl()); | ||||
|                 } | ||||
|             }); | ||||
|     } | ||||
|  | ||||
|     private void initUpdater() | ||||
|     { | ||||
|         if (checkForUpdates) | ||||
|         { | ||||
|             // Run the UpdateChecker regularly. | ||||
|             if (updateRunner == null) | ||||
|                 updateRunner = new BukkitRunnable() | ||||
|                 { | ||||
|                     @Override | ||||
|                     public void run() | ||||
|                     { | ||||
|                         checkForUpdates(); | ||||
|                     } | ||||
|                 }.runTaskTimer(plugin, 0L, 288000L); // Run immediately, then every 4 hours. | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             plugin.myLogger(Level.INFO, | ||||
|                             "Plugin update checking not enabled! You will not receive any messages about new updates " + | ||||
|                                 "for this plugin. Please consider turning this on in the config."); | ||||
|             if (updateRunner != null) | ||||
|             { | ||||
|                 updateRunner.cancel(); | ||||
|                 updateRunner = null; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 
				 Pim van der Loos
					Pim van der Loos