From a887875090bc17b42ebd2cf280c5d5f8f62dcf4d Mon Sep 17 00:00:00 2001 From: Intybyte Date: Fri, 6 Dec 2024 15:31:16 +0100 Subject: [PATCH] Add update checker --- api-internal/pom.xml | 8 ++ .../internal/ModrinthUpdateChecker.java | 85 +++++++++++++++++++ .../main/java/at/pavlov/cannons/Cannons.java | 20 +++++ .../cannons/listener/UpdateNotifier.java | 42 +++++++++ 4 files changed, 155 insertions(+) create mode 100644 api-internal/src/main/java/at/pavlov/internal/ModrinthUpdateChecker.java create mode 100644 cannons-bukkit/src/main/java/at/pavlov/cannons/listener/UpdateNotifier.java diff --git a/api-internal/pom.xml b/api-internal/pom.xml index 8bc598c2..49cc600b 100644 --- a/api-internal/pom.xml +++ b/api-internal/pom.xml @@ -15,6 +15,14 @@ UTF-8 + + + com.google.code.gson + gson + 2.11.0 + + + diff --git a/api-internal/src/main/java/at/pavlov/internal/ModrinthUpdateChecker.java b/api-internal/src/main/java/at/pavlov/internal/ModrinthUpdateChecker.java new file mode 100644 index 00000000..65728549 --- /dev/null +++ b/api-internal/src/main/java/at/pavlov/internal/ModrinthUpdateChecker.java @@ -0,0 +1,85 @@ +package at.pavlov.internal; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +public class ModrinthUpdateChecker { + private static final String API_URL = "https://api.modrinth.com/v2/project/cannons-revamped/version"; + private final Logger logger; + private String downloadUrl = null; + + public static final String YELLOW = "\u001B[33m"; + public static final String GREEN = "\u001B[32m"; + public static final String RESET = "\u001B[0m"; + + public ModrinthUpdateChecker(Logger logger) { + this.logger = logger; + } + + public Boolean isLatest(String current) { + String response; + + try(BufferedReader in = getBufferedReader()) { + response = in.lines().collect(Collectors.joining()); + } catch (IOException e) { + logger.severe("Failed to check for latest version."); + return null; + } + + Gson gson = new Gson(); + JsonArray versions = gson.fromJson(response, JsonArray.class); + + if (versions.isEmpty()) { + logger.severe("No versions found for this project."); + return null; + } + + JsonObject latestVersion = extractLatest(versions); + String latestVersionNumber = latestVersion.get("version_number").getAsString(); + logger.info(GREEN + "Latest version: " + latestVersionNumber + RESET); + + // Compare versions + if (latestVersionNumber.equals(current)) { + logger.info("You are using the latest version"); + return true; + } + + logger.info(YELLOW + "A new version is available: " + current + " --> " + latestVersionNumber + RESET); + JsonArray files = latestVersion.getAsJsonArray("files"); + downloadUrl = files.get(0).getAsJsonObject().get("url").getAsString(); + logger.info(YELLOW + "Download it here: " + downloadUrl + RESET); + return false; + } + + public String getDownloadUrl() { + return downloadUrl; + } + + private static BufferedReader getBufferedReader() throws IOException { + URL url = new URL(API_URL); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + connection.setRequestProperty("User-Agent", "Mozilla/5.0"); + + int responseCode = connection.getResponseCode(); + if (responseCode != 200) { + throw new RuntimeException("Failed to fetch data from Modrinth API: HTTP " + responseCode); + } + + // Read the response + return new BufferedReader(new InputStreamReader(connection.getInputStream())); + } + + private static JsonObject extractLatest(JsonArray versions) { + return versions.get(0).getAsJsonObject(); + } +} diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/Cannons.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/Cannons.java index 91745248..2f916cc3 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/Cannons.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/Cannons.java @@ -11,6 +11,7 @@ import at.pavlov.cannons.config.Config; import at.pavlov.cannons.config.UserMessages; import at.pavlov.cannons.container.ItemHolder; +import at.pavlov.cannons.dao.AsyncTaskManager; import at.pavlov.cannons.dao.PersistenceDatabase; import at.pavlov.cannons.hooks.movecraft.MovecraftHook; import at.pavlov.cannons.hooks.papi.PlaceholderAPIHook; @@ -26,6 +27,7 @@ import at.pavlov.cannons.utils.CannonSelector; import at.pavlov.internal.Hook; import at.pavlov.internal.HookManager; +import at.pavlov.internal.ModrinthUpdateChecker; import lombok.Getter; import net.milkbowl.vault.economy.Economy; import org.bstats.bukkit.Metrics; @@ -72,6 +74,10 @@ public final class Cannons extends JavaPlugin // database private PersistenceDatabase persistenceDatabase; private Connection connection = null; + @Getter + private volatile Boolean isLatest; + @Getter + private ModrinthUpdateChecker updateChecker; private final String cannonDatabase = "cannonlist_2_4_6"; private final String whitelistDatabase = "whitelist_2_4_6"; @@ -87,6 +93,8 @@ public void onLoad() { CannonManager.initialize(this); this.config = Config.getInstance(); + initUpdater(); + if (!config.isMovecraftEnabled()) { return; } @@ -100,6 +108,17 @@ public void onLoad() { MaxCannonsProperty.register(); } + private void initUpdater() { + var taskManager = AsyncTaskManager.get(); + updateChecker = new ModrinthUpdateChecker(this.getLogger()); + taskManager.async.submit( () -> { + isLatest = updateChecker.isLatest(this + .getPluginDescription() + .getVersion() + ); + }); + } + public void onDisable() { getServer().getScheduler().cancelTasks(this); @@ -193,6 +212,7 @@ public void onEnable() pm.registerEvents(playerListener, this); pm.registerEvents(entityListener, this); pm.registerEvents(redstoneListener, this); + pm.registerEvents(new UpdateNotifier(this), this); //call command executer initializeCommands(); diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/listener/UpdateNotifier.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/listener/UpdateNotifier.java new file mode 100644 index 00000000..92b35311 --- /dev/null +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/listener/UpdateNotifier.java @@ -0,0 +1,42 @@ +package at.pavlov.cannons.listener; + +import at.pavlov.cannons.Cannons; +import at.pavlov.cannons.dao.AsyncTaskManager; +import at.pavlov.internal.ModrinthUpdateChecker; +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; + +import java.util.HashSet; +import java.util.UUID; + +public class UpdateNotifier implements Listener { + private final HashSet notified = new HashSet<>(); + private final Cannons plugin; + + public UpdateNotifier(Cannons plugin) { + this.plugin = plugin; + } + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + Player player = event.getPlayer(); + if (!player.isOp()) { + return; + } + + UUID uuid = player.getUniqueId(); + if (notified.contains(uuid)) { + return; + } + + if (plugin.getIsLatest() == Boolean.FALSE) { + notified.add(uuid); + String download = plugin.getUpdateChecker().getDownloadUrl(); + player.sendMessage(ChatColor.YELLOW + "[Cannons] You are not on the latest version. Download new version here: " + download); + } + + } +}