diff --git a/dependency-reduced-pom.xml b/dependency-reduced-pom.xml index d5c355b..a701296 100644 --- a/dependency-reduced-pom.xml +++ b/dependency-reduced-pom.xml @@ -3,7 +3,7 @@ 4.0.0 nl.iobyte themeparkconnector - 3.0.1 + 3.0.2 diff --git a/pom.xml b/pom.xml index 21a7d71..e88cecf 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,7 @@ nl.iobyte themeparkconnector - 3.0.1 + 3.0.2 diff --git a/src/main/java/nl/iobyte/themeparkconnector/ThemeParkConnector.java b/src/main/java/nl/iobyte/themeparkconnector/ThemeParkConnector.java index eee554c..cfb04aa 100644 --- a/src/main/java/nl/iobyte/themeparkconnector/ThemeParkConnector.java +++ b/src/main/java/nl/iobyte/themeparkconnector/ThemeParkConnector.java @@ -35,15 +35,47 @@ public class ThemeParkConnector extends JavaPlugin { loadCommands(); loadListeners(); + loadUpdateManager(); + } - //Check Version - new UpdateManager(this, 4, UpdateManager.CheckType.SBDPLUGINS).handleResponse((versionResponse, version) -> { - if (versionResponse == UpdateManager.VersionResponse.FOUND_NEW) { - Bukkit.getLogger().warning("[ThemeParkConnector] There is a new version available! Curent: " + getDescription().getVersion() + " New: " + version); - } else if (versionResponse == UpdateManager.VersionResponse.LATEST) { - Bukkit.getLogger().info("[ThemeParkConnector] You are running the latest version [" + getDescription().getVersion() + "]!"); - } else if (versionResponse == UpdateManager.VersionResponse.UNAVAILABLE) { - Bukkit.getLogger().severe("[ThemeParkConnector] Unable to perform an update check."); + private void loadUpdateManager() { + if(!api.getConfigurationManager().getBoolean(StorageKey.UPDATE_CHECK_ENABLED)) + return; + + UpdateManager manager = new UpdateManager( + this, + 5, + api.getConfigurationManager().getString(StorageKey.LICENSE) + ); + manager.handleResponse((response, version) -> { + switch (response) { + case LATEST: + getLogger().info("You're running the latest version("+version.get()+")"); + break; + case THIS_NEWER: + getLogger().info("You're running a newer version("+version.get()+")"); + break; + case UNAVAILABLE: + getLogger().info("Unable to check for updates"); + break; + case FOUND_NEW: + getLogger().info("Found newer version("+version.get()+")"); + if(!api.getConfigurationManager().getBoolean(StorageKey.UPDATE_DOWNLOAD_ENABLED)) + return; + + manager.handleDownloadResponse((downloadResponse, fileName) -> { + switch (downloadResponse) { + case DONE: + getLogger().info("Update downloaded! If you restart your server, it will be loaded. Filename: " + fileName); + break; + case ERROR: + getLogger().severe("Something went wrong when trying downloading the latest version."); + break; + case UNAVAILABLE: + getLogger().warning("Unable to download the latest version."); + break; + } + }).runUpdate(); } }).check(); } diff --git a/src/main/java/nl/iobyte/themeparkconnector/api/config/enums/StorageKey.java b/src/main/java/nl/iobyte/themeparkconnector/api/config/enums/StorageKey.java index f7b0c52..a4cd7b7 100644 --- a/src/main/java/nl/iobyte/themeparkconnector/api/config/enums/StorageKey.java +++ b/src/main/java/nl/iobyte/themeparkconnector/api/config/enums/StorageKey.java @@ -6,6 +6,10 @@ public enum StorageKey { LICENSE(StorageLocation.SETTINGS, "license"), ACTIONFOTO(StorageLocation.SETTINGS, "actionfoto"), + //Update Settings + UPDATE_CHECK_ENABLED(StorageLocation.SETTINGS, "update.check"), + UPDATE_DOWNLOAD_ENABLED(StorageLocation.SETTINGS, "update.download"), + //Sign SIGN_CONTROL_NAME(StorageLocation.SETTINGS, "sign.control.name"), SIGN_CONTROL_TITLE(StorageLocation.SETTINGS, "sign.control.title"), diff --git a/src/main/java/nl/iobyte/themeparkconnector/sbd/UpdateManager.java b/src/main/java/nl/iobyte/themeparkconnector/sbd/UpdateManager.java index 130f16d..09d9cb3 100644 --- a/src/main/java/nl/iobyte/themeparkconnector/sbd/UpdateManager.java +++ b/src/main/java/nl/iobyte/themeparkconnector/sbd/UpdateManager.java @@ -5,45 +5,70 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; import org.bukkit.Bukkit; import org.bukkit.plugin.Plugin; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; +import org.bukkit.plugin.java.JavaPlugin; +import javax.net.ssl.HttpsURLConnection; +import java.io.*; +import java.lang.reflect.Method; import java.net.HttpURLConnection; import java.net.URL; +import java.nio.channels.Channels; +import java.nio.channels.FileChannel; +import java.nio.channels.ReadableByteChannel; +import java.nio.charset.StandardCharsets; import java.util.function.BiConsumer; /** * Update class for SBDevelopment * @author Stijn [SBDeveloper] - * @since 18-01-2020 - * @version 1.2 + * @since 05-03-2020 + * @version 2.0 [26-12-2020] - This class supports the v2 Update API * - * © Stijn Bannink - All rights reserved. + *

© Stijn Bannink [stijnbannink23@gmail.com] - All rights reserved.

*/ public class UpdateManager { - private static String SPIGOT_API = "http://api.spiget.org/v2/resources/%d/versions?size=1&sort=-releaseDate"; - private static String SBDPLUGINS_API = "http://updates.sbdplugins.nl:4000/api/resources/%d"; + private static final String SPIGOT_API = "https://api.spigotmc.org/legacy/update.php?resource=%d"; + private static final String SPIGOT_DOWNLOAD = "http://api.spiget.org/v2/resources/%s/download"; - private Plugin plugin; - private String currentVersion; - private int resourceID; - private CheckType type; - private BiConsumer versionResponse; + private static final String SBDPLUGINS_API = "https://updates.sbdplugins.nl/api/v2/plugins/%d"; + private static final String SBDPLUGINS_DOWNLOAD = "https://updates.sbdplugins.nl/api/v2/download/%d"; + + private final Plugin plugin; + private final Version currentVersion; + private final int resourceID; + private final CheckType type; + private final String license; + + private BiConsumer versionResponse; + private BiConsumer downloadResponse; /** - * Construct a new UpdateManager + * Construct a new UpdateManager for Spigot * * @param plugin The javaplugin (Main class) * @param resourceID The resourceID on spigot/sbdplugins - * @param type The check type */ - public UpdateManager(Plugin plugin, int resourceID, CheckType type) { + public UpdateManager(Plugin plugin, int resourceID) { this.plugin = plugin; - this.currentVersion = plugin.getDescription().getVersion(); + this.currentVersion = new Version(plugin.getDescription().getVersion()); this.resourceID = resourceID; - this.type = type; + this.type = CheckType.SPIGOT; + this.license = null; + } + + /** + * Construct a new UpdateManager for SBDPlugins + * + * @param plugin The javaplugin (Main class) + * @param resourceID The resourceID on spigot/sbdplugins + * @param license The license for the download + */ + public UpdateManager(Plugin plugin, int resourceID, String license) { + this.plugin = plugin; + this.currentVersion = new Version(plugin.getDescription().getVersion()); + this.resourceID = resourceID; + this.type = CheckType.SBDPLUGINS; + this.license = license; } /** @@ -51,32 +76,41 @@ public class UpdateManager { * @param versionResponse The response * @return The updatemanager */ - public UpdateManager handleResponse(BiConsumer versionResponse) { + public UpdateManager handleResponse(BiConsumer versionResponse) { this.versionResponse = versionResponse; return this; } + public UpdateManager handleDownloadResponse(BiConsumer downloadResponse) { + this.downloadResponse = downloadResponse; + return this; + } + /** * Check for a new version */ public void check() { Bukkit.getScheduler().runTaskAsynchronously(this.plugin, () -> { try { - HttpURLConnection con = null; + BufferedReader in = null; if (type == CheckType.SPIGOT) { - con = (HttpURLConnection) new URL(String.format(SPIGOT_API, this.resourceID)).openConnection(); + HttpsURLConnection con = (HttpsURLConnection) new URL(String.format(SPIGOT_API, this.resourceID)).openConnection(); + con.setRequestMethod("GET"); + con.setRequestProperty("User-Agent", "Mozilla/5.0"); + + in = new BufferedReader(new InputStreamReader(con.getInputStream())); } else if (type == CheckType.SBDPLUGINS) { - con = (HttpURLConnection) new URL(String.format(SBDPLUGINS_API, this.resourceID)).openConnection(); + HttpsURLConnection con = (HttpsURLConnection) new URL(String.format(SBDPLUGINS_API, this.resourceID)).openConnection(); + con.setRequestMethod("GET"); + con.setRequestProperty("User-Agent", "Mozilla/5.0"); + + in = new BufferedReader(new InputStreamReader(con.getInputStream())); } - if (con == null) return; + if (in == null) return; - con.setRequestMethod("GET"); - con.setRequestProperty("User-Agent", "Mozilla/5.0"); + String version; - String version = null; - - BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); String inputLine; StringBuilder response = new StringBuilder(); while ((inputLine = in.readLine()) != null) { @@ -90,18 +124,19 @@ public class UpdateManager { JsonArray array = parser.parse(response.toString()).getAsJsonArray(); version = array.get(0).getAsJsonObject().get("name").getAsString(); - } else if (type == CheckType.SBDPLUGINS) { + } else { JsonObject object = parser.parse(response.toString()).getAsJsonObject(); - version = object.get("data").getAsJsonObject().get("version").getAsString(); + version = object.get("version").getAsString(); } if (version == null) return; - boolean latestVersion = version.equalsIgnoreCase(this.currentVersion); + Version onlineVersion = new Version(version); - String finalVersion = version; - Bukkit.getScheduler().runTask(this.plugin, () -> this.versionResponse.accept(latestVersion ? VersionResponse.LATEST : VersionResponse.FOUND_NEW, latestVersion ? this.currentVersion : finalVersion)); + VersionResponse verRes = this.currentVersion.check(onlineVersion); + + Bukkit.getScheduler().runTask(this.plugin, () -> this.versionResponse.accept(verRes, onlineVersion)); } catch (IOException | NullPointerException e) { e.printStackTrace(); Bukkit.getScheduler().runTask(this.plugin, () -> this.versionResponse.accept(VersionResponse.UNAVAILABLE, null)); @@ -109,12 +144,165 @@ public class UpdateManager { }); } - public enum CheckType { + public void runUpdate() { + File pluginFile = getPluginFile(); // /plugins/XXX.jar + if (pluginFile == null) { + this.downloadResponse.accept(DownloadResponse.ERROR, null); + Bukkit.getLogger().info("Pluginfile is null"); + return; + } + File updateFolder = Bukkit.getUpdateFolderFile(); + if (!updateFolder.exists()) { + if (!updateFolder.mkdirs()) { + this.downloadResponse.accept(DownloadResponse.ERROR, null); + Bukkit.getLogger().info("Updatefolder doesn't exists, and can't be made"); + return; + } + } + final File updateFile = new File(updateFolder, pluginFile.getName()); + + Bukkit.getScheduler().runTaskAsynchronously(this.plugin, () -> { + ReadableByteChannel channel; + try { + //https://stackoverflow.com/questions/921262/how-to-download-and-save-a-file-from-internet-using-java + int response; + InputStream stream; + if (type == CheckType.SBDPLUGINS) { + HttpURLConnection connection = (HttpURLConnection) new URL(String.format(SBDPLUGINS_DOWNLOAD, this.resourceID)).openConnection(); + + String urlParameters = "license=" + license + "&port=" + Bukkit.getPort(); + byte[] postData = urlParameters.getBytes(StandardCharsets.UTF_8); + int postDataLength = postData.length; + + connection.setRequestMethod("GET"); + connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + connection.setRequestProperty("charset", "utf-8"); + connection.setRequestProperty("Content-Length", Integer.toString(postDataLength)); + connection.setRequestProperty("User-Agent", "Mozilla/5.0"); + connection.setDoOutput(true); + + DataOutputStream wr = new DataOutputStream(connection.getOutputStream()); + wr.write(postData); + wr.close(); + + response = connection.getResponseCode(); + stream = connection.getInputStream(); + } else { + HttpsURLConnection connection = (HttpsURLConnection) new URL(String.format(SPIGOT_DOWNLOAD, this.resourceID)).openConnection(); + connection.setRequestProperty("User-Agent", "Mozilla/5.0"); + + response = connection.getResponseCode(); + stream = connection.getInputStream(); + } + + if (response != 200) { + BufferedReader in = new BufferedReader(new InputStreamReader(stream)); + + String inputLine; + StringBuilder responsestr = new StringBuilder(); + while ((inputLine = in.readLine()) != null) { + responsestr.append(inputLine); + } + in.close(); + + throw new RuntimeException("Download returned status #" + response, new Throwable(responsestr.toString())); + } + + channel = Channels.newChannel(stream); + } catch (IOException e) { + Bukkit.getScheduler().runTask(this.plugin, () -> this.downloadResponse.accept(DownloadResponse.ERROR, null)); + e.printStackTrace(); + return; + } + + FileChannel fileChannel = null; + try { + FileOutputStream fosForDownloadedFile = new FileOutputStream(updateFile); + fileChannel = fosForDownloadedFile.getChannel(); + + fileChannel.transferFrom(channel, 0, Long.MAX_VALUE); + } catch (IOException e) { + Bukkit.getScheduler().runTask(this.plugin, () -> this.downloadResponse.accept(DownloadResponse.ERROR, null)); + e.printStackTrace(); + return; + } finally { + if (channel != null) { + try { + channel.close(); + } catch (IOException ioe) { + System.out.println("Error while closing response body channel"); + } + } + + if (fileChannel != null) { + try { + fileChannel.close(); + } catch (IOException ioe) { + System.out.println("Error while closing file channel for downloaded file"); + } + } + } + + Bukkit.getScheduler().runTask(this.plugin, () -> this.downloadResponse.accept(DownloadResponse.DONE, updateFile.getPath())); + }); + } + + private File getPluginFile() { + if (!(this.plugin instanceof JavaPlugin)) { return null; } + try { + Method method = JavaPlugin.class.getDeclaredMethod("getFile"); + method.setAccessible(true); + return (File) method.invoke(this.plugin); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("Could not get plugin file", e); + } + } + + private enum CheckType { SPIGOT, SBDPLUGINS } public enum VersionResponse { - LATEST, FOUND_NEW, UNAVAILABLE + LATEST, //Latest version + FOUND_NEW, //Newer available + THIS_NEWER, //Local version is newer? + UNAVAILABLE //Error } -} + public enum DownloadResponse { + DONE, ERROR, UNAVAILABLE + } + + public static class Version { + + private final String version; + + public final String get() { + return this.version; + } + + private Version(String version) { + if(version == null) + throw new IllegalArgumentException("Version can not be null"); + if(!version.matches("[0-9]+(\\.[0-9]+)*")) + throw new IllegalArgumentException("Invalid version format"); + this.version = version; + } + + private VersionResponse check(Version that) { + String[] thisParts = this.get().split("\\."); + String[] thatParts = that.get().split("\\."); + + int length = Math.max(thisParts.length, thatParts.length); + for (int i = 0; i < length; i++) { + int thisPart = i < thisParts.length ? Integer.parseInt(thisParts[i]) : 0; + int thatPart = i < thatParts.length ? Integer.parseInt(thatParts[i]) : 0; + if(thisPart < thatPart) + return VersionResponse.FOUND_NEW; + if(thisPart > thatPart) + return VersionResponse.THIS_NEWER; + } + return VersionResponse.LATEST; + } + } +} \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 1d49add..48e4376 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,5 +1,5 @@ name: ThemeParkConnector -version: 3.0.1 +version: 3.0.2 author: IOByte website: 'https://www.iobyte.nl' main: nl.iobyte.themeparkconnector.ThemeParkConnector diff --git a/src/main/resources/settings.yml b/src/main/resources/settings.yml index ca4c29e..045c197 100644 --- a/src/main/resources/settings.yml +++ b/src/main/resources/settings.yml @@ -1,7 +1,11 @@ -version: 1.0 +version: 1.1 license: '' +update: + check: true + download: true + socket: id: 'themepark' url: 'websocket.iobyte.nl'