From 6350d64e88735cca0db4cca5d86abe95c912a528 Mon Sep 17 00:00:00 2001 From: Jens Collaert <63231928+Jens-Co@users.noreply.github.com> Date: Sun, 1 Oct 2023 19:37:53 +0200 Subject: [PATCH] Use new download API and jar file checksum (#99) * Update to new download api and sha checking for file integrity * remove old messages class * unneeded spacing * Make the enum return a lowercase string as url component * Konica wanted changes? :) * delete file issue catching * use getters for pojos and up the version number * initialize gson only once * Cleanup --------- Co-authored-by: Konicai <71294714+Konicai@users.noreply.github.com> --- pom.xml | 9 ++- .../geyserupdater/bungee/BungeeUpdater.java | 20 ++--- .../bungee/command/GeyserUpdateCommand.java | 29 +++---- .../bungee/util/GeyserBungeeDownloader.java | 23 +++--- .../geyserupdater/common/Messages.java | 15 ---- .../common/json_schema/EndpointResponse.java | 75 +++++++++++++++++++ .../common/logger/UpdaterLogger.java | 10 +++ .../geyserupdater/common/util/Constants.java | 11 +++ .../geyserupdater/common/util/FileUtils.java | 72 +++++++++++------- .../common/util/GeyserDownloadApi.java | 26 +++++++ .../common/util/GeyserProperties.java | 23 +++--- .../common/util/ServerPlatform.java | 18 +++++ .../geyserupdater/spigot/SpigotUpdater.java | 7 +- .../spigot/command/GeyserUpdateCommand.java | 28 +++---- .../spigot/util/GeyserSpigotDownloader.java | 31 +++----- .../velocity/VelocityUpdater.java | 18 ++--- .../velocity/command/GeyserUpdateCommand.java | 20 +++-- .../velocity/logger/Slf4jUpdaterLogger.java | 5 ++ .../util/GeyserVelocityDownloader.java | 23 +++--- src/main/resources/bungee.yml | 2 +- 20 files changed, 286 insertions(+), 179 deletions(-) delete mode 100644 src/main/java/com/projectg/geyserupdater/common/Messages.java create mode 100644 src/main/java/com/projectg/geyserupdater/common/json_schema/EndpointResponse.java create mode 100644 src/main/java/com/projectg/geyserupdater/common/util/Constants.java create mode 100644 src/main/java/com/projectg/geyserupdater/common/util/GeyserDownloadApi.java create mode 100644 src/main/java/com/projectg/geyserupdater/common/util/ServerPlatform.java diff --git a/pom.xml b/pom.xml index f418192f..6ea6d228 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.projectg GeyserUpdater GeyserUpdater - 1.6.2 + 1.6.3 UTF-8 @@ -70,6 +70,13 @@ 2.1.0-SNAPSHOT provided + + + org.projectlombok + lombok + 1.18.28 + provided + diff --git a/src/main/java/com/projectg/geyserupdater/bungee/BungeeUpdater.java b/src/main/java/com/projectg/geyserupdater/bungee/BungeeUpdater.java index e61f738d..6c946f00 100644 --- a/src/main/java/com/projectg/geyserupdater/bungee/BungeeUpdater.java +++ b/src/main/java/com/projectg/geyserupdater/bungee/BungeeUpdater.java @@ -84,20 +84,17 @@ public void onDisable() { try { deleteGeyserJar(); break; - } catch (IOException ioException) { - logger.warn("An I/O error occurred while attempting to delete an unnecessary Geyser jar! Trying again " + (2 - i) + " more times."); - ioException.printStackTrace(); + } catch (Exception e) { + logger.warn("An error occurred while attempting to delete an unnecessary Geyser jar! Trying again " + (2 - i) + " more times."); try { Thread.sleep(50); - } catch (InterruptedException interruptException) { - logger.error("Failed to delay an additional attempt!"); - interruptException.printStackTrace(); + } catch (InterruptedException interruptedException) { + logger.error("Failed to delay an additional attempt!", interruptedException); } } } - } catch (IOException e) { - logger.error("An I/O error occurred while attempting to replace the current Geyser jar with the new one!"); - e.printStackTrace(); + } catch (Exception e) { + logger.error("An error occurred while attempting to replace the current Geyser jar with the new one! Giving up.", e); } } @@ -157,9 +154,8 @@ public void scheduleAutoUpdate() { logger.info("A newer build of Geyser is available! Attempting to download the latest build now..."); GeyserBungeeDownloader.updateGeyser(); } - } catch (IOException e) { - logger.error("Failed to check for updates to Geyser! We were unable to reach the Geyser build server, or your local branch does not exist on it."); - e.printStackTrace(); + } catch (Exception e) { + logger.error("Failed to check for updates to Geyser! We were unable to reach the Geyser build server, or your local branch does not exist on it.", e); } }, 1, getConfig().getLong("Auto-Update-Interval", 24L) * 60, TimeUnit.MINUTES); } diff --git a/src/main/java/com/projectg/geyserupdater/bungee/command/GeyserUpdateCommand.java b/src/main/java/com/projectg/geyserupdater/bungee/command/GeyserUpdateCommand.java index 72309d8d..0f51c189 100644 --- a/src/main/java/com/projectg/geyserupdater/bungee/command/GeyserUpdateCommand.java +++ b/src/main/java/com/projectg/geyserupdater/bungee/command/GeyserUpdateCommand.java @@ -1,8 +1,8 @@ package com.projectg.geyserupdater.bungee.command; import com.projectg.geyserupdater.bungee.util.GeyserBungeeDownloader; -import com.projectg.geyserupdater.common.Messages; import com.projectg.geyserupdater.common.logger.UpdaterLogger; +import com.projectg.geyserupdater.common.util.Constants; import com.projectg.geyserupdater.common.util.GeyserProperties; import net.md_5.bungee.api.ChatColor; @@ -11,9 +11,6 @@ import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.plugin.Command; -import java.io.IOException; - - public class GeyserUpdateCommand extends Command { public GeyserUpdateCommand() { @@ -25,33 +22,31 @@ public void execute(CommandSender commandSender, String[] args) { if (commandSender instanceof ProxiedPlayer player) { try { - player.sendMessage(new TextComponent(ChatColor.GOLD + "[GeyserUpdater] " + Messages.Command.CHECK_START)); + player.sendMessage(new TextComponent(ChatColor.GOLD + "[GeyserUpdater] " + Constants.CHECK_START)); boolean isLatest = GeyserProperties.isLatestBuild(); if (isLatest) { - player.sendMessage(new TextComponent(ChatColor.GOLD + "[GeyserUpdater] " + Messages.Command.LATEST)); + player.sendMessage(new TextComponent(ChatColor.GOLD + "[GeyserUpdater] " + Constants.LATEST)); } else { - player.sendMessage(new TextComponent(ChatColor.GOLD + "[GeyserUpdater] " + Messages.Command.OUTDATED)); + player.sendMessage(new TextComponent(ChatColor.GOLD + "[GeyserUpdater] " + Constants.OUTDATED)); GeyserBungeeDownloader.updateGeyser(); } - } catch (IOException e) { - player.sendMessage(new TextComponent(ChatColor.RED + "[GeyserUpdater] " + Messages.Command.FAIL_CHECK)); - logger.error(Messages.Command.FAIL_CHECK); - e.printStackTrace(); + } catch (Exception e) { + player.sendMessage(new TextComponent(ChatColor.RED + "[GeyserUpdater] " + Constants.FAIL_CHECK)); + logger.error(Constants.FAIL_CHECK, e); } } else { // TODO: filter this against command blocks try { - logger.info(Messages.Command.CHECK_START); + logger.info(Constants.CHECK_START); boolean isLatest = GeyserProperties.isLatestBuild(); if (isLatest) { - logger.info(Messages.Command.LATEST); + logger.info(Constants.LATEST); } else { - logger.info(Messages.Command.OUTDATED); + logger.info(Constants.OUTDATED); GeyserBungeeDownloader.updateGeyser(); } - } catch (IOException e) { - logger.error(Messages.Command.FAIL_CHECK); - e.printStackTrace(); + } catch (Exception e) { + logger.error(Constants.FAIL_CHECK, e); } } } diff --git a/src/main/java/com/projectg/geyserupdater/bungee/util/GeyserBungeeDownloader.java b/src/main/java/com/projectg/geyserupdater/bungee/util/GeyserBungeeDownloader.java index 67d1f7b7..9121acba 100644 --- a/src/main/java/com/projectg/geyserupdater/bungee/util/GeyserBungeeDownloader.java +++ b/src/main/java/com/projectg/geyserupdater/bungee/util/GeyserBungeeDownloader.java @@ -2,14 +2,15 @@ import com.projectg.geyserupdater.bungee.BungeeUpdater; import com.projectg.geyserupdater.common.logger.UpdaterLogger; +import com.projectg.geyserupdater.common.util.Constants; import com.projectg.geyserupdater.common.util.FileUtils; -import com.projectg.geyserupdater.common.util.GeyserProperties; +import com.projectg.geyserupdater.common.util.GeyserDownloadApi; +import com.projectg.geyserupdater.common.util.ServerPlatform; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.connection.ProxiedPlayer; -import java.io.IOException; import java.util.concurrent.TimeUnit; public class GeyserBungeeDownloader { @@ -58,20 +59,14 @@ public static void updateGeyser() { * @return true if the download was successful, false if not. */ private static boolean downloadGeyser() { - String fileUrl; - try { - fileUrl = "https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/" + GeyserProperties.getGeyserGitPropertiesValue("git.branch") + "/lastSuccessfulBuild/artifact/bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar"; - } catch (IOException e) { - logger.error("Failed to get the current Geyser branch when attempting to download a new build of Geyser!"); - e.printStackTrace(); - return false; - } + String fileUrl = Constants.GEYSER_BASE_URL + Constants.GEYSER_DOWNLOAD_LINK + ServerPlatform.BUNGEECORD.getUrlComponent(); String outputPath = "plugins/GeyserUpdater/BuildUpdate/Geyser-BungeeCord.jar"; try { - FileUtils.downloadFile(fileUrl, outputPath); - } catch (IOException e) { - logger.error("Failed to download the newest build of Geyser"); - e.printStackTrace(); + String expectedHash = new GeyserDownloadApi().data().downloads().bungeecord().sha256(); + FileUtils.downloadFile(fileUrl, outputPath, expectedHash); + } catch (Exception e) { + logger.error("Failed to download the newest build of Geyser" + e.getMessage()); + logger.debug("Stack trace: " + e); return false; } diff --git a/src/main/java/com/projectg/geyserupdater/common/Messages.java b/src/main/java/com/projectg/geyserupdater/common/Messages.java deleted file mode 100644 index 72d0faae..00000000 --- a/src/main/java/com/projectg/geyserupdater/common/Messages.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.projectg.geyserupdater.common; - -public class Messages { - - public static class Command { - public static final String CHECK_START = "Checking for updates to Geyser..."; - public static final String LATEST = "You are using the latest build of Geyser!"; - public static final String OUTDATED = "A newer build of Geyser is available! Attempting to download the latest build now..."; - public static final String FAIL_CHECK = "Failed to check for updates to Geyser! We were unable to reach the Geyser build server, or your local branch does not exist on it."; - } - -} - - - diff --git a/src/main/java/com/projectg/geyserupdater/common/json_schema/EndpointResponse.java b/src/main/java/com/projectg/geyserupdater/common/json_schema/EndpointResponse.java new file mode 100644 index 00000000..48338b81 --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/json_schema/EndpointResponse.java @@ -0,0 +1,75 @@ +package com.projectg.geyserupdater.common.json_schema; + +import lombok.Getter; +import lombok.experimental.Accessors; + +import java.util.Date; +import java.util.List; + +@SuppressWarnings({"UnusedDeclaration"}) +@Getter +@Accessors(fluent = true) +public class EndpointResponse { + private String project_id; + private String project_name; + private String version; + private int build; + private Date time; + private String channel; + private boolean promoted; + private List changes; + private Downloads downloads; + + @Getter + public static class Bungeecord { + private String name; + private String sha256; + } + + @Getter + public static class Change { + private String commit; + private String summary; + private String message; + } + + @Getter + public static class Downloads { + private Bungeecord bungeecord; + private Fabric fabric; + private Spigot spigot; + private Sponge sponge; + private Standalone standalone; + private Velocity velocity; + } + + @Getter + public static class Fabric { + private String name; + private String sha256; + } + + @Getter + public static class Spigot { + private String name; + private String sha256; + } + + @Getter + public static class Sponge { + private String name; + private String sha256; + } + + @Getter + public static class Standalone { + private String name; + private String sha256; + } + + @Getter + public static class Velocity { + private String name; + private String sha256; + } +} \ No newline at end of file diff --git a/src/main/java/com/projectg/geyserupdater/common/logger/UpdaterLogger.java b/src/main/java/com/projectg/geyserupdater/common/logger/UpdaterLogger.java index db610f46..7683ae03 100644 --- a/src/main/java/com/projectg/geyserupdater/common/logger/UpdaterLogger.java +++ b/src/main/java/com/projectg/geyserupdater/common/logger/UpdaterLogger.java @@ -16,6 +16,16 @@ static UpdaterLogger getLogger() { */ void error(String message); + /** + * Logs an error message to the console. + * + * @param message the message to log to the console + */ + default void error(String message, Throwable throwable) { + error(message); + throwable.printStackTrace(); + } + /** * Logs a warning message to the console. * diff --git a/src/main/java/com/projectg/geyserupdater/common/util/Constants.java b/src/main/java/com/projectg/geyserupdater/common/util/Constants.java new file mode 100644 index 00000000..3b016368 --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/util/Constants.java @@ -0,0 +1,11 @@ +package com.projectg.geyserupdater.common.util; + +public class Constants { + public static final String GEYSER_BASE_URL = "https://download.geysermc.org"; + public static final String GEYSER_LATEST_MASTER_ENDPOINT = "/v2/projects/geyser/versions/latest/builds/latest"; + public static final String GEYSER_DOWNLOAD_LINK = "/v2/projects/geyser/versions/latest/builds/latest/downloads/"; + public static final String CHECK_START = "Checking for updates to Geyser..."; + public static final String LATEST = "You are using the latest build of Geyser!"; + public static final String OUTDATED = "A newer build of Geyser is available! Attempting to download the latest build now..."; + public static final String FAIL_CHECK = "Failed to check for updates to Geyser! We were unable to reach the Geyser build server, or your local branch does not exist on it."; +} \ No newline at end of file diff --git a/src/main/java/com/projectg/geyserupdater/common/util/FileUtils.java b/src/main/java/com/projectg/geyserupdater/common/util/FileUtils.java index 0f9506df..c5375fb9 100644 --- a/src/main/java/com/projectg/geyserupdater/common/util/FileUtils.java +++ b/src/main/java/com/projectg/geyserupdater/common/util/FileUtils.java @@ -1,19 +1,19 @@ package com.projectg.geyserupdater.common.util; +import com.google.common.hash.Hashing; +import com.google.common.io.ByteSource; import com.projectg.geyserupdater.common.logger.UpdaterLogger; +import org.jetbrains.annotations.Nullable; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; +import java.io.*; import java.net.URL; -import java.net.URLConnection; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; public class FileUtils { - // TODO: this whole cached thing only works if you're using checkFile for one file... /** * Epoch time of that last occurrence that {@link #checkFile(String, boolean)} directly checked a file. Returns a value of 0 if the check file method has never been called. @@ -25,6 +25,8 @@ public class FileUtils { */ private static boolean cachedResult; + // todo this is absolutely abhorrent and assumes we are always downloading the same jar + /** * Check if a file exists. * @@ -57,34 +59,46 @@ public static boolean checkFile(String path, boolean allowCached) { * * @param fileURL the url of the file * @param outputPath the path of the output file to write to + * @param expectedSha256 the expected sha256 hash of the downloaded file */ - public static void downloadFile(String fileURL, String outputPath) throws IOException { - // TODO: better download code? - - UpdaterLogger.getLogger().debug("Attempting to download a file with URL and output path: " + fileURL + " , " + outputPath); + public static void downloadFile(String fileURL, String outputPath, @Nullable String expectedSha256) throws IOException { + UpdaterLogger logger = UpdaterLogger.getLogger(); + logger.debug("Attempting to download a file with URL and output path: " + fileURL + " , " + outputPath); Path outputDirectory = Paths.get(outputPath).getParent(); Files.createDirectories(outputDirectory); - OutputStream os; - InputStream is; - // create a url object + // Download Jar file URL url = new URL(fileURL); - // connection to the file - URLConnection connection = url.openConnection(); - // get input stream to the file - is = connection.getInputStream(); - // get output stream to download file - os = new FileOutputStream(outputPath); - final byte[] b = new byte[2048]; - int length; - // read from input stream and write to output stream - while ((length = is.read(b)) != -1) { - os.write(b, 0, length); + try (ReadableByteChannel rbc = Channels.newChannel(url.openStream()); + FileOutputStream fos = new FileOutputStream(outputPath)) { + + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + } catch (Exception e) { + logger.error("Failed to download %s to %s".formatted(fileURL, outputPath), e); } - // close streams - is.close(); - os.close(); - } -} + if (expectedSha256 != null) { + // hash the file + File file = new File(outputPath); + ByteSource byteSource = com.google.common.io.Files.asByteSource(file); + String hash = byteSource.hash(Hashing.sha256()).toString(); + + // compare + if (expectedSha256.equals(hash)) { + if (logger.isDebug()) { + logger.debug("Successful checksum for %s of %s".formatted(file, hash)); + } + } else { + logger.warn("Expected a hash of %s but got %s".formatted(expectedSha256, hash)); + + // If the checksum failed we attempt to delete the broken build. + if (file.delete()) { + logger.warn("Downloaded a jar whose checksum was incorrect, deleting: " + file); + } else { + logger.error("Failed to delete a defective download, please delete manually: " + file); + } + } + } + } +} \ No newline at end of file diff --git a/src/main/java/com/projectg/geyserupdater/common/util/GeyserDownloadApi.java b/src/main/java/com/projectg/geyserupdater/common/util/GeyserDownloadApi.java new file mode 100644 index 00000000..02e10ef7 --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/util/GeyserDownloadApi.java @@ -0,0 +1,26 @@ +package com.projectg.geyserupdater.common.util; + +import com.google.gson.Gson; +import com.projectg.geyserupdater.common.json_schema.EndpointResponse; + +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; + +public class GeyserDownloadApi { + private static final Gson gson = new Gson(); + + public EndpointResponse data() throws Exception { + URL url = new URL(Constants.GEYSER_BASE_URL + Constants.GEYSER_LATEST_MASTER_ENDPOINT); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + + if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) { + throw new IllegalStateException("Received %s from GET of %s".formatted(connection.getResponseCode(), url)); + } + + try (InputStreamReader reader = new InputStreamReader(connection.getInputStream())) { + return gson.fromJson(reader, EndpointResponse.class); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/projectg/geyserupdater/common/util/GeyserProperties.java b/src/main/java/com/projectg/geyserupdater/common/util/GeyserProperties.java index d84489eb..4c45e261 100644 --- a/src/main/java/com/projectg/geyserupdater/common/util/GeyserProperties.java +++ b/src/main/java/com/projectg/geyserupdater/common/util/GeyserProperties.java @@ -2,12 +2,8 @@ import com.projectg.geyserupdater.common.logger.UpdaterLogger; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.util.WebUtils; import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; import java.util.Properties; public class GeyserProperties { @@ -21,14 +17,16 @@ public class GeyserProperties { * @return true if local build number equals latest build number on Geyser CI * @throws IOException if it fails to fetch either build number */ - public static boolean isLatestBuild() throws IOException { + public static boolean isLatestBuild() throws Exception { UpdaterLogger.getLogger().debug("Running isLatestBuild()"); - int jenkinsBuildNumber = getLatestGeyserBuildNumberFromJenkins(getGeyserGitPropertiesValue("git.branch")); + // Removed get branch since current Geyser endpoints do not yet support it + // getLatestGeyserBuildNumberFromDownloadPage(getGeyserGitPropertiesValue("git.branch")); + int downloadPageBuildNumber = getLatestGeyserBuildNumberFromDownloadPage(); int localBuildNumber = Integer.parseInt(getGeyserGitPropertiesValue("git.build.number")); // Compare build numbers. // We treat higher build numbers as "out of date" here because Geyser's build numbers have been (accidentally) reset in the past. // Self-compiled builds of Geyser simply do not have a `git.build.number` value, so it is /very/ unlikely that a user will ever have a Git build number higher than upstream anyway. - return jenkinsBuildNumber == localBuildNumber; + return downloadPageBuildNumber == localBuildNumber; } /** Query the git properties of Geyser @@ -44,15 +42,12 @@ public static String getGeyserGitPropertiesValue(String propertyKey) throws IOEx return gitProperties.getProperty(propertyKey); } - /** Get the latest build number of a given branch of Geyser from jenkins CI + /** Get the latest build number of a given branch of Geyser from Geyser download page. * - * @param gitBranch the branch to query - * @return the latest build number - * @throws UnsupportedEncodingException if failed to encode the given gitBranch + * @return the latest build number from Geyser API */ - public static int getLatestGeyserBuildNumberFromJenkins(String gitBranch) throws UnsupportedEncodingException { + public static int getLatestGeyserBuildNumberFromDownloadPage() throws Exception { UpdaterLogger.getLogger().debug("Running getLatestGeyserBuildNumberFromJenkins()"); - String buildXMLContents = WebUtils.getBody("https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/" + URLEncoder.encode(gitBranch, StandardCharsets.UTF_8.toString()) + "/lastSuccessfulBuild/api/xml?xpath=//buildNumber"); - return Integer.parseInt(buildXMLContents.replaceAll("<(\\\\)?(/)?buildNumber>", "").trim()); + return new GeyserDownloadApi().data().build(); } } \ No newline at end of file diff --git a/src/main/java/com/projectg/geyserupdater/common/util/ServerPlatform.java b/src/main/java/com/projectg/geyserupdater/common/util/ServerPlatform.java new file mode 100644 index 00000000..6366ae7d --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/util/ServerPlatform.java @@ -0,0 +1,18 @@ +package com.projectg.geyserupdater.common.util; + +public enum ServerPlatform { + SPIGOT("spigot"), + BUNGEECORD("bungeecord"), + VELOCITY("velocity"); + + private final String urlComponent; + + ServerPlatform(String urlComponent) { + this.urlComponent = urlComponent; + } + + public String getUrlComponent() { + return urlComponent; + } +} + diff --git a/src/main/java/com/projectg/geyserupdater/spigot/SpigotUpdater.java b/src/main/java/com/projectg/geyserupdater/spigot/SpigotUpdater.java index 913a0cdb..56a987da 100644 --- a/src/main/java/com/projectg/geyserupdater/spigot/SpigotUpdater.java +++ b/src/main/java/com/projectg/geyserupdater/spigot/SpigotUpdater.java @@ -108,7 +108,7 @@ public void checkUpdaterVersion() { @Override public void run() { String latestVersion = SpigotResourceUpdateChecker.getVersion(); - if (latestVersion == null || latestVersion.length() == 0) { + if (latestVersion == null || latestVersion.isEmpty()) { logger.error("Failed to determine the latest GeyserUpdater version!"); } else { if (latestVersion.equals(pluginVersion)) { @@ -138,9 +138,8 @@ public void run() { UpdaterLogger.getLogger().info("A newer build of Geyser is available! Attempting to download the latest build now..."); GeyserSpigotDownloader.updateGeyser(); } - } catch (IOException e) { - UpdaterLogger.getLogger().error("Failed to check for updates to Geyser! We were unable to reach the Geyser build server, or your local branch does not exist on it."); - e.printStackTrace(); + } catch (Exception e) { + UpdaterLogger.getLogger().error("Failed to check for updates to Geyser! We were unable to reach the Geyser build server, or your local branch does not exist on it.", e); } // Auto-Update-Interval is in hours. We convert it into ticks } diff --git a/src/main/java/com/projectg/geyserupdater/spigot/command/GeyserUpdateCommand.java b/src/main/java/com/projectg/geyserupdater/spigot/command/GeyserUpdateCommand.java index bddb8bf6..b274da3e 100644 --- a/src/main/java/com/projectg/geyserupdater/spigot/command/GeyserUpdateCommand.java +++ b/src/main/java/com/projectg/geyserupdater/spigot/command/GeyserUpdateCommand.java @@ -1,7 +1,7 @@ package com.projectg.geyserupdater.spigot.command; -import com.projectg.geyserupdater.common.Messages; import com.projectg.geyserupdater.common.logger.UpdaterLogger; +import com.projectg.geyserupdater.common.util.Constants; import com.projectg.geyserupdater.common.util.GeyserProperties; import com.projectg.geyserupdater.spigot.util.GeyserSpigotDownloader; @@ -14,8 +14,6 @@ import org.jetbrains.annotations.NotNull; -import java.io.IOException; - public class GeyserUpdateCommand implements CommandExecutor { @Override @@ -24,34 +22,32 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command if (sender instanceof Player player) { if (command.getName().equalsIgnoreCase("geyserupdate") && player.hasPermission("gupdater.geyserupdate")) { - sender.sendMessage(ChatColor.GOLD + "[GeyserUpdater] " + Messages.Command.CHECK_START); + sender.sendMessage(ChatColor.GOLD + "[GeyserUpdater] " + Constants.CHECK_START); try { boolean isLatest = GeyserProperties.isLatestBuild(); if (isLatest) { - sender.sendMessage(ChatColor.GOLD + "[GeyserUpdater] " + Messages.Command.LATEST); + sender.sendMessage(ChatColor.GOLD + "[GeyserUpdater] " + Constants.LATEST); } else { - sender.sendMessage(ChatColor.GOLD + "[GeyserUpdater] " + Messages.Command.OUTDATED); + sender.sendMessage(ChatColor.GOLD + "[GeyserUpdater] " + Constants.OUTDATED); GeyserSpigotDownloader.updateGeyser(); } - } catch (IOException e) { - sender.sendMessage(ChatColor.RED + "[GeyserUpdater] " + Messages.Command.FAIL_CHECK); - logger.error(Messages.Command.FAIL_CHECK); - e.printStackTrace(); + } catch (Exception e) { + sender.sendMessage(ChatColor.RED + "[GeyserUpdater] " + Constants.FAIL_CHECK); + logger.error(Constants.FAIL_CHECK, e); } } } else if (sender instanceof ConsoleCommandSender) { - logger.info(Messages.Command.CHECK_START); + logger.info(Constants.CHECK_START); try { boolean isLatest = GeyserProperties.isLatestBuild(); if (isLatest) { - logger.info(Messages.Command.LATEST); + logger.info(Constants.LATEST); } else { - logger.info(Messages.Command.OUTDATED); + logger.info(Constants.OUTDATED); GeyserSpigotDownloader.updateGeyser(); } - } catch (IOException e) { - logger.error(Messages.Command.FAIL_CHECK); - e.printStackTrace(); + } catch (Exception e) { + logger.error(Constants.FAIL_CHECK, e); } } else { return false; diff --git a/src/main/java/com/projectg/geyserupdater/spigot/util/GeyserSpigotDownloader.java b/src/main/java/com/projectg/geyserupdater/spigot/util/GeyserSpigotDownloader.java index dca20b06..e0b208be 100644 --- a/src/main/java/com/projectg/geyserupdater/spigot/util/GeyserSpigotDownloader.java +++ b/src/main/java/com/projectg/geyserupdater/spigot/util/GeyserSpigotDownloader.java @@ -1,8 +1,10 @@ package com.projectg.geyserupdater.spigot.util; import com.projectg.geyserupdater.common.logger.UpdaterLogger; +import com.projectg.geyserupdater.common.util.Constants; import com.projectg.geyserupdater.common.util.FileUtils; -import com.projectg.geyserupdater.common.util.GeyserProperties; +import com.projectg.geyserupdater.common.util.GeyserDownloadApi; +import com.projectg.geyserupdater.common.util.ServerPlatform; import com.projectg.geyserupdater.spigot.SpigotUpdater; import org.bukkit.Bukkit; @@ -10,7 +12,6 @@ import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; -import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -73,21 +74,14 @@ public void run() { * @return true if the download was successful, false if not. */ private static boolean downloadGeyser() { - String fileUrl; - try { - fileUrl = "https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/" + GeyserProperties.getGeyserGitPropertiesValue("git.branch") + "/lastSuccessfulBuild/artifact/bootstrap/spigot/build/libs/Geyser-Spigot.jar"; - } catch (IOException e) { - logger.error("Failed to get the current Geyser branch when attempting to download a new build of Geyser!"); - e.printStackTrace(); - return false; - } + String fileUrl = Constants.GEYSER_BASE_URL + Constants.GEYSER_DOWNLOAD_LINK + ServerPlatform.SPIGOT.getUrlComponent(); // todo: make sure we use the update folder defined in bukkit.yml (it can be changed) String outputPath = "plugins/update/Geyser-Spigot.jar"; try { - FileUtils.downloadFile(fileUrl, outputPath); - } catch (IOException e) { - logger.error("Failed to download the newest build of Geyser"); - e.printStackTrace(); + String expectedHash = new GeyserDownloadApi().data().downloads().spigot().sha256(); + FileUtils.downloadFile(fileUrl, outputPath, expectedHash); + } catch (Exception e) { + logger.error("Failed to download the newest build of Geyser", e); return false; } @@ -116,19 +110,16 @@ public void run() { try { spigotServer = SpigotUpdater.getPlugin().getServer().getClass().getMethod("spigot").invoke(SpigotUpdater.getPlugin().getServer()); } catch (NoSuchMethodException e) { - logger.error("You are not running Spigot (or a fork of it, such as Paper)! GeyserUpdater cannot automatically restart your server!"); - e.printStackTrace(); + logger.error("You are not running Spigot (or a fork of it, such as Paper)! GeyserUpdater cannot automatically restart your server!", e); return; } Method restartMethod = spigotServer.getClass().getMethod("restart"); restartMethod.setAccessible(true); restartMethod.invoke(spigotServer); } catch (NoSuchMethodException e) { - logger.error("Your server version is too old to be able to be automatically restarted!"); - e.printStackTrace(); + logger.error("Your server version is too old to be able to be automatically restarted!", e); } catch (InvocationTargetException | IllegalAccessException e) { - logger.error("Failed to restart the server!"); - e.printStackTrace(); + logger.error("Failed to restart the server!", e); } } }.runTaskLater(plugin, 200); // 200 ticks is around 10 seconds (at 20 TPS) diff --git a/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java b/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java index d9ca5f4a..3aa5843c 100644 --- a/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java +++ b/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java @@ -36,7 +36,7 @@ import java.nio.file.Paths; import java.util.concurrent.TimeUnit; -@Plugin(id = "geyserupdater", name = "GeyserUpdater", version = "1.6.1", description = "Automatically or manually downloads new builds of Geyser and applies them on server restart.", authors = {"Jens"}, +@Plugin(id = "geyserupdater", name = "GeyserUpdater", version = "1.6.3", description = "Automatically or manually downloads new builds of Geyser and applies them on server restart.", authors = {"KejonaMC"}, dependencies = {@Dependency(id = "geyser")}) public class VelocityUpdater { @@ -110,20 +110,17 @@ public void onShutdown(ProxyShutdownEvent event) { try { deleteGeyserJar(); break; - } catch (IOException ioException) { - UpdaterLogger.getLogger().warn("An I/O error occurred while attempting to delete an unnecessary Geyser jar! Trying again " + (2 - i) + " more times."); - ioException.printStackTrace(); + } catch (Exception e) { + UpdaterLogger.getLogger().warn("An error occurred while attempting to delete an unnecessary Geyser jar! Trying again " + (2 - i) + " more times."); try { Thread.sleep(50); } catch (InterruptedException interruptException) { - UpdaterLogger.getLogger().error("Failed to delay an additional attempt!"); - interruptException.printStackTrace(); + UpdaterLogger.getLogger().error("Failed to delay an additional attempt!", interruptException); } } } } catch (IOException e) { - UpdaterLogger.getLogger().error("An I/O error occurred while attempting to replace the current Geyser jar with the new one!"); - e.printStackTrace(); + UpdaterLogger.getLogger().error("An error occurred while attempting to replace the current Geyser jar with the new one! Giving up.", e); } } @@ -181,9 +178,8 @@ public void scheduleAutoUpdate() { UpdaterLogger.getLogger().info("A newer build of Geyser is available! Attempting to download the latest build now..."); GeyserVelocityDownloader.updateGeyser(); } - } catch (IOException e) { - UpdaterLogger.getLogger().error("Failed to check for updates to Geyser! We were unable to reach the Geyser build server, or your local branch does not exist on it."); - e.printStackTrace(); + } catch (Exception e) { + UpdaterLogger.getLogger().error("Failed to check for updates to Geyser! We were unable to reach the Geyser build server, or your local branch does not exist on it.", e); } }) .delay(1L, TimeUnit.MINUTES) diff --git a/src/main/java/com/projectg/geyserupdater/velocity/command/GeyserUpdateCommand.java b/src/main/java/com/projectg/geyserupdater/velocity/command/GeyserUpdateCommand.java index c5ddae66..b50ade15 100644 --- a/src/main/java/com/projectg/geyserupdater/velocity/command/GeyserUpdateCommand.java +++ b/src/main/java/com/projectg/geyserupdater/velocity/command/GeyserUpdateCommand.java @@ -1,6 +1,6 @@ package com.projectg.geyserupdater.velocity.command; -import com.projectg.geyserupdater.common.Messages; +import com.projectg.geyserupdater.common.util.Constants; import com.projectg.geyserupdater.common.util.GeyserProperties; import com.projectg.geyserupdater.velocity.util.GeyserVelocityDownloader; @@ -8,32 +8,30 @@ import com.velocitypowered.api.command.RawCommand; import net.kyori.adventure.text.Component; - -import java.io.IOException; +import org.jetbrains.annotations.NotNull; public class GeyserUpdateCommand implements RawCommand { @Override - public void execute(final Invocation invocation) { + public void execute(final @NotNull Invocation invocation) { CommandSource source = invocation.source(); try { - source.sendMessage(Component.text(Messages.Command.CHECK_START)); + source.sendMessage(Component.text(Constants.CHECK_START)); boolean isLatest = GeyserProperties.isLatestBuild(); if (isLatest) { - source.sendMessage(Component.text(Messages.Command.LATEST)); + source.sendMessage(Component.text(Constants.LATEST)); } else { - source.sendMessage(Component.text(Messages.Command.OUTDATED)); + source.sendMessage(Component.text(Constants.OUTDATED)); GeyserVelocityDownloader.updateGeyser(); } - } catch (IOException e) { - source.sendMessage(Component.text(Messages.Command.FAIL_CHECK)); + } catch (Exception e) { + source.sendMessage(Component.text(Constants.FAIL_CHECK)); e.printStackTrace(); } } @Override - public boolean hasPermission(final Invocation invocation) { + public boolean hasPermission(final @NotNull Invocation invocation) { return invocation.source().hasPermission("gupdater.geyserupdate"); } } - diff --git a/src/main/java/com/projectg/geyserupdater/velocity/logger/Slf4jUpdaterLogger.java b/src/main/java/com/projectg/geyserupdater/velocity/logger/Slf4jUpdaterLogger.java index d8fbb5f5..fd5b8440 100644 --- a/src/main/java/com/projectg/geyserupdater/velocity/logger/Slf4jUpdaterLogger.java +++ b/src/main/java/com/projectg/geyserupdater/velocity/logger/Slf4jUpdaterLogger.java @@ -19,6 +19,11 @@ public void error(String message) { logger.error(message); } + @Override + public void error(String message, Throwable throwable) { + logger.error(message, throwable); + } + @Override public void warn(String message) { logger.warn(message); diff --git a/src/main/java/com/projectg/geyserupdater/velocity/util/GeyserVelocityDownloader.java b/src/main/java/com/projectg/geyserupdater/velocity/util/GeyserVelocityDownloader.java index d62bb05c..697165ab 100644 --- a/src/main/java/com/projectg/geyserupdater/velocity/util/GeyserVelocityDownloader.java +++ b/src/main/java/com/projectg/geyserupdater/velocity/util/GeyserVelocityDownloader.java @@ -1,8 +1,10 @@ package com.projectg.geyserupdater.velocity.util; import com.projectg.geyserupdater.common.logger.UpdaterLogger; +import com.projectg.geyserupdater.common.util.Constants; import com.projectg.geyserupdater.common.util.FileUtils; -import com.projectg.geyserupdater.common.util.GeyserProperties; +import com.projectg.geyserupdater.common.util.GeyserDownloadApi; +import com.projectg.geyserupdater.common.util.ServerPlatform; import com.projectg.geyserupdater.velocity.VelocityUpdater; import com.velocitypowered.api.proxy.Player; @@ -11,7 +13,6 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.TextColor; -import java.io.IOException; import java.util.concurrent.TimeUnit; public class GeyserVelocityDownloader { @@ -63,20 +64,14 @@ public static void updateGeyser() { * @return true if the download was successful, false if not. */ private static boolean downloadGeyser() { - String fileUrl; - try { - fileUrl = "https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/" + GeyserProperties.getGeyserGitPropertiesValue("git.branch") + "/lastSuccessfulBuild/artifact/bootstrap/velocity/build/libs/Geyser-Velocity.jar"; - } catch (IOException e) { - logger.error("Failed to get the current Geyser branch when attempting to download a new build of Geyser!"); - e.printStackTrace(); - return false; - } + String fileUrl = Constants.GEYSER_BASE_URL + Constants.GEYSER_DOWNLOAD_LINK + ServerPlatform.VELOCITY.getUrlComponent(); String outputPath = "plugins/GeyserUpdater/BuildUpdate/Geyser-Velocity.jar"; + try { - FileUtils.downloadFile(fileUrl, outputPath); - } catch (IOException e) { - logger.error("Failed to download the newest build of Geyser"); - e.printStackTrace(); + String expectedHash = new GeyserDownloadApi().data().downloads().velocity().sha256(); + FileUtils.downloadFile(fileUrl, outputPath, expectedHash); + } catch (Exception e) { + logger.error("Failed to download the newest build of Geyser", e); return false; } diff --git a/src/main/resources/bungee.yml b/src/main/resources/bungee.yml index b2cdfbdb..26733528 100644 --- a/src/main/resources/bungee.yml +++ b/src/main/resources/bungee.yml @@ -2,5 +2,5 @@ name: ${project.name} main: com.projectg.geyserupdater.bungee.BungeeUpdater version: ${project.version} description: Automatically or manually downloads new builds of Geyser and applies them on server restart. -author: Jens +author: KejonaMC depends: ["Geyser-BungeeCord"]