diff --git a/src/main/java/eu/m724/tweaks/updater/PluginScanner.java b/src/main/java/eu/m724/tweaks/updater/PluginScanner.java deleted file mode 100644 index a437b1c..0000000 --- a/src/main/java/eu/m724/tweaks/updater/PluginScanner.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2024 Minecon724 - * Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file - * in the project root for the full license text. - */ - -package eu.m724.tweaks.updater; - -import eu.m724.tweaks.updater.cache.SpigotResource; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.plugin.Plugin; - -import java.io.File; -import java.io.IOException; -import java.util.HashSet; -import java.util.Set; - -public class PluginScanner { - private final Plugin thisPlugin; - - PluginScanner(Plugin thisPlugin) { - this.thisPlugin = thisPlugin; - } - - public Set load() throws IOException { - File installedPluginsYml = new File(thisPlugin.getDataFolder(), "installed_plugins.yml"); - - if (!installedPluginsYml.exists()) { - thisPlugin.saveResource("installed_plugins.yml", false); - } - - YamlConfiguration configuration = YamlConfiguration.loadConfiguration(installedPluginsYml); - - - Plugin[] plugins = thisPlugin.getServer().getPluginManager().getPlugins(); - Set spigotResources = new HashSet<>(); - - for (Plugin plugin : plugins) { - String pluginName = plugin.getName(); - - if (!configuration.isSet(pluginName)) { - configuration.set(pluginName, -1); - continue; - } - - int pluginId = configuration.getInt(pluginName); - if (pluginId > 0) { - spigotResources.add( - new SpigotResource(plugin, pluginId, pluginName) - ); - } - } - - configuration.save(installedPluginsYml); - - return spigotResources; - - } -} diff --git a/src/main/java/eu/m724/tweaks/updater/UpdaterCommands.java b/src/main/java/eu/m724/tweaks/updater/UpdaterCommands.java index 46b7c9e..a801093 100644 --- a/src/main/java/eu/m724/tweaks/updater/UpdaterCommands.java +++ b/src/main/java/eu/m724/tweaks/updater/UpdaterCommands.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Minecon724 + * Copyright (C) 2025 Minecon724 * Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file * in the project root for the full license text. */ @@ -7,7 +7,8 @@ package eu.m724.tweaks.updater; import eu.m724.tweaks.Language; -import eu.m724.tweaks.updater.cache.VersionedResource; +import eu.m724.tweaks.updater.backend.UpdateChecker; +import eu.m724.tweaks.updater.object.VersionedResource; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.ClickEvent; @@ -20,18 +21,25 @@ import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; import java.awt.*; +import java.time.Instant; import java.time.format.DateTimeFormatter; public class UpdaterCommands implements CommandExecutor { + private final UpdateChecker updateChecker; + + public UpdaterCommands(UpdateChecker updateChecker) { + this.updateChecker = updateChecker; + } + @Override public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { - if (UpdateChecker.lastChecked == null) { + var lastChecked = updateChecker.getLastChecked(); + if (updateChecker.getLastChecked() == -1) { sender.sendMessage(Language.getString("updatesNotChecked")); return true; } - String lastChecked = UpdateChecker.lastChecked.format(DateTimeFormatter.ofPattern("HH:mm")); - int n = UpdateChecker.availableUpdates.size(); + int n = updateChecker.getAvailableUpdates().size(); if (n > 0) { sender.spigot().sendMessage( @@ -39,13 +47,14 @@ public class UpdaterCommands implements CommandExecutor { ); int i = 0; - for (VersionedResource v : UpdateChecker.availableUpdates) { + for (VersionedResource v : updateChecker.getAvailableUpdates()) { sender.spigot().sendMessage( new ComponentBuilder(++i + ". ").color(ChatColor.GRAY).build(), resourceToBaseComponent(v) ); } } else { - sender.spigot().sendMessage(Language.getComponent("updatesNoUpdates", ChatColor.GREEN, lastChecked)); + var lastCheckedFormat = DateTimeFormatter.ofPattern("HH:mm").format(Instant.ofEpochMilli(lastChecked)); + sender.spigot().sendMessage(Language.getComponent("updatesNoUpdates", ChatColor.GREEN, lastCheckedFormat)); } return true; diff --git a/src/main/java/eu/m724/tweaks/updater/UpdaterModule.java b/src/main/java/eu/m724/tweaks/updater/UpdaterModule.java index 7df2351..c76522c 100644 --- a/src/main/java/eu/m724/tweaks/updater/UpdaterModule.java +++ b/src/main/java/eu/m724/tweaks/updater/UpdaterModule.java @@ -8,9 +8,13 @@ package eu.m724.tweaks.updater; import eu.m724.tweaks.DebugLogger; import eu.m724.tweaks.TweaksModule; -import eu.m724.tweaks.updater.cache.ResourceVersion; -import eu.m724.tweaks.updater.cache.SpigotResource; -import eu.m724.tweaks.updater.cache.VersionedResource; +import eu.m724.tweaks.updater.backend.UpdateChecker; +import eu.m724.tweaks.updater.backend.VersionCache; +import eu.m724.tweaks.updater.object.ResourceVersion; +import eu.m724.tweaks.updater.object.SpigotResource; +import eu.m724.tweaks.updater.object.VersionedResource; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.plugin.Plugin; import java.io.File; import java.io.FileInputStream; @@ -23,38 +27,72 @@ import java.util.stream.Collectors; public class UpdaterModule extends TweaksModule { @Override protected void onInit() { - // scan installed plugins - Set resources; - try { - resources = new PluginScanner(getPlugin()).load(); - } catch (IOException e) { - throw new RuntimeException("Loading plugins", e); - } - + var resources = loadInstalledPlugins(); // load installed versions from cache var cacheFile = new File(getPlugin().getDataFolder(), "storage/cache/updater"); - Set installedVersions; + final var installedVersions = loadInstalledVersionCache(cacheFile); + + var versionedResources = resources.stream() + .map(res -> new VersionedResource( + res, installedVersions.stream().filter(iv -> iv.resourceId() == res.resourceId()).findFirst().orElse(null), null + )) + .collect(Collectors.toSet()); + + + var updateChecker = new UpdateChecker(getPlugin().getLogger(), cacheFile, versionedResources); + updateChecker.runTaskTimerAsynchronously(getPlugin(), 600, 12 * 3600 * 20); // 12 hours + + registerCommand("updates", new UpdaterCommands(updateChecker)); + } + + private Set loadInstalledVersionCache(File cacheFile) { try (FileInputStream inputStream = new FileInputStream(cacheFile)) { - installedVersions = VersionCheckCache.loadAll(inputStream); - } catch (FileNotFoundException e) { - installedVersions = new HashSet<>(); + return VersionCache.loadAll(inputStream); + } catch (FileNotFoundException ignored) { } catch (IOException e) { DebugLogger.warning("Error loading installed version cache, starting fresh. " + e.getMessage()); - installedVersions = new HashSet<>(); } - final Set ivf = installedVersions; - Set versionedResources = resources.stream() - .map(res -> new VersionedResource( - res, ivf.stream().filter(iv -> iv.resourceId() == res.resourceId()).findFirst().orElse(null), null - )).collect(Collectors.toSet()); + return new HashSet<>(); + } + private Set loadInstalledPlugins() { + File installedPluginsYml = new File(getPlugin().getDataFolder(), "installed_plugins.yml"); - new UpdateChecker(getPlugin().getLogger(), cacheFile, versionedResources) - .runTaskTimerAsynchronously(getPlugin(), 600, 12 * 3600 * 20); // 12 hours + if (!installedPluginsYml.exists()) { + getPlugin().saveResource("installed_plugins.yml", false); + } + + YamlConfiguration configuration = YamlConfiguration.loadConfiguration(installedPluginsYml); + + Plugin[] plugins = getPlugin().getServer().getPluginManager().getPlugins(); + Set spigotResources = new HashSet<>(); + + for (Plugin plugin : plugins) { + String pluginName = plugin.getName(); + + if (!configuration.isSet(pluginName)) { + configuration.set(pluginName, -1); + continue; + } + + int pluginId = configuration.getInt(pluginName); + if (pluginId > 0) { + spigotResources.add( + new SpigotResource(plugin, pluginId, pluginName) + ); + } + } + + try { + configuration.save(installedPluginsYml); + } catch (IOException e) { + throw new RuntimeException("Failed to update installed_plugins.yml", e); + } + + return spigotResources; - registerCommand("updates", new UpdaterCommands()); } } diff --git a/src/main/java/eu/m724/tweaks/updater/UpdateChecker.java b/src/main/java/eu/m724/tweaks/updater/backend/UpdateChecker.java similarity index 72% rename from src/main/java/eu/m724/tweaks/updater/UpdateChecker.java rename to src/main/java/eu/m724/tweaks/updater/backend/UpdateChecker.java index 2f4d4d5..72f3ac6 100644 --- a/src/main/java/eu/m724/tweaks/updater/UpdateChecker.java +++ b/src/main/java/eu/m724/tweaks/updater/backend/UpdateChecker.java @@ -4,18 +4,16 @@ * in the project root for the full license text. */ -package eu.m724.tweaks.updater; +package eu.m724.tweaks.updater.backend; import eu.m724.tweaks.DebugLogger; import eu.m724.tweaks.Language; -import eu.m724.tweaks.updater.cache.VersionedResource; +import eu.m724.tweaks.updater.object.VersionedResource; import org.bukkit.scheduler.BukkitRunnable; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; -import java.time.LocalTime; -import java.time.ZoneOffset; import java.util.HashSet; import java.util.Objects; import java.util.Set; @@ -28,10 +26,10 @@ public class UpdateChecker extends BukkitRunnable { private final File cacheFile; private final Set resources; - static final Set availableUpdates = new HashSet<>(); - static LocalTime lastChecked = null; + private final Set availableUpdates = new HashSet<>(); + private long lastChecked = -1; - UpdateChecker(Logger logger, File cacheFile, Set resources) { + public UpdateChecker(Logger logger, File cacheFile, Set resources) { this.logger = logger; this.cacheFile = cacheFile; this.resources = resources; // TODO make a copy? @@ -39,7 +37,7 @@ public class UpdateChecker extends BukkitRunnable { private void checkAll() { DebugLogger.fine("Checking for updates"); - lastChecked = LocalTime.now(ZoneOffset.UTC); + lastChecked = System.currentTimeMillis(); availableUpdates.clear(); for (VersionedResource versionedResource : Set.copyOf(resources)) { @@ -47,19 +45,21 @@ public class UpdateChecker extends BukkitRunnable { int page = versionedResource.running() != null ? versionedResource.running().page() : 1; try { - VersionedResource newResource = new VersionFinder(versionedResource.resource(), page).join(); // this runs async so it's ok + VersionedResource newResource = new VersionScanner(versionedResource.resource(), page).join(); // this runs async so it's ok if (!versionedResource.equals(newResource)) { resources.remove(versionedResource); + if (newResource.running() == null) { - logger.warning("Unable to find installed version of %s".formatted(pluginName)); + DebugLogger.warning("Unable to find installed version of %s", pluginName); if (versionedResource.running() != null) { - logger.warning("Did you downgrade %s? If so, clear cache".formatted(pluginName)); + DebugLogger.warning("Did you downgrade %s? If so, clear cache", pluginName); } } else { if (!newResource.running().equals(newResource.latest())) { availableUpdates.add(newResource); } } + resources.add(newResource); } } catch (CompletionException e) { @@ -85,11 +85,19 @@ public class UpdateChecker extends BukkitRunnable { DebugLogger.finer("Done checking, now saving"); cacheFile.getParentFile().mkdirs(); try (FileOutputStream outputStream = new FileOutputStream(cacheFile)) { - VersionCheckCache.writeAll(outputStream, resources.stream().map(VersionedResource::running).filter(Objects::nonNull).collect(Collectors.toSet())); + VersionCache.writeAll(outputStream, resources.stream().map(VersionedResource::running).filter(Objects::nonNull).collect(Collectors.toSet())); } catch (IOException e) { throw new RuntimeException(e); } alert(); } + + public long getLastChecked() { + return lastChecked; + } + + public Set getAvailableUpdates() { + return availableUpdates; + } } diff --git a/src/main/java/eu/m724/tweaks/updater/VersionCheckCache.java b/src/main/java/eu/m724/tweaks/updater/backend/VersionCache.java similarity index 94% rename from src/main/java/eu/m724/tweaks/updater/VersionCheckCache.java rename to src/main/java/eu/m724/tweaks/updater/backend/VersionCache.java index 7bc9b44..a2f0797 100644 --- a/src/main/java/eu/m724/tweaks/updater/VersionCheckCache.java +++ b/src/main/java/eu/m724/tweaks/updater/backend/VersionCache.java @@ -1,12 +1,12 @@ /* - * Copyright (C) 2024 Minecon724 + * Copyright (C) 2025 Minecon724 * Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file * in the project root for the full license text. */ -package eu.m724.tweaks.updater; +package eu.m724.tweaks.updater.backend; -import eu.m724.tweaks.updater.cache.ResourceVersion; +import eu.m724.tweaks.updater.object.ResourceVersion; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -15,7 +15,7 @@ import java.io.OutputStream; import java.util.HashSet; import java.util.Set; -public class VersionCheckCache { +public class VersionCache { private static final byte FILE_VERSION = 1; public static Set loadAll(FileInputStream inputStream) throws IOException { diff --git a/src/main/java/eu/m724/tweaks/updater/VersionFinder.java b/src/main/java/eu/m724/tweaks/updater/backend/VersionScanner.java similarity index 74% rename from src/main/java/eu/m724/tweaks/updater/VersionFinder.java rename to src/main/java/eu/m724/tweaks/updater/backend/VersionScanner.java index 35676ef..6cd6262 100644 --- a/src/main/java/eu/m724/tweaks/updater/VersionFinder.java +++ b/src/main/java/eu/m724/tweaks/updater/backend/VersionScanner.java @@ -1,19 +1,20 @@ /* - * Copyright (C) 2024 Minecon724 + * Copyright (C) 2025 Minecon724 * Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file * in the project root for the full license text. */ -package eu.m724.tweaks.updater; +package eu.m724.tweaks.updater.backend; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; -import eu.m724.tweaks.updater.cache.SpigotResource; -import eu.m724.tweaks.updater.cache.ResourceVersion; -import eu.m724.tweaks.updater.cache.UpdateDescription; -import eu.m724.tweaks.updater.cache.VersionedResource; +import eu.m724.tweaks.DebugLogger; +import eu.m724.tweaks.updater.object.SpigotResource; +import eu.m724.tweaks.updater.object.ResourceVersion; +import eu.m724.tweaks.updater.object.UpdateDescription; +import eu.m724.tweaks.updater.object.VersionedResource; import java.net.URI; import java.net.URISyntaxException; @@ -26,23 +27,25 @@ import java.util.concurrent.Executors; // TODO optimize -public class VersionFinder extends CompletableFuture { +public class VersionScanner extends CompletableFuture { private final SpigotResource resource; private final int fromPage; - VersionFinder(SpigotResource resource, int fromPage) { + VersionScanner(SpigotResource resource, int fromPage) { this.resource = resource; this.fromPage = fromPage; start(); } - VersionFinder(SpigotResource resource) { + VersionScanner(SpigotResource resource) { this(resource, 1); } private void start() { //System.out.printf("STarting for %d %s\n", resource.resourceId(), resource.plugin().getName()); + DebugLogger.finer("Scanning %s (#%d) from page %d", resource.name(), resource.resourceId(), fromPage); + try (ExecutorService executor = Executors.newSingleThreadExecutor()) { executor.execute(() -> { try { @@ -51,13 +54,14 @@ public class VersionFinder extends CompletableFuture { int page; for (page = fromPage; page < 1000; page++) { - //System.out.println("Page " + page); + DebugLogger.finer("Scan %s now at page %d", resource.name(), fromPage); + String url = "https://api.spigotmc.org/simple/0.2/index.php?action=getResourceUpdates&page=%d&id=%d".formatted(page, resource.resourceId()); HttpRequest request; try { request = HttpRequest.newBuilder(new URI(url)) - .header("User-Agent", "twu/1") + .header("User-Agent", "twu/1") // tweaks updater v1 .build(); } catch (URISyntaxException e) { throw new RuntimeException(e); @@ -68,6 +72,7 @@ public class VersionFinder extends CompletableFuture { String body = response.body(); if (body.isBlank()) { + DebugLogger.finer("Body is blank, stopping"); page--; break; } @@ -75,15 +80,7 @@ public class VersionFinder extends CompletableFuture { JsonArray jsonArray = JsonParser.parseString(body).getAsJsonArray(); for (JsonElement ele : jsonArray) { JsonObject versionJson = ele.getAsJsonObject(); - if (isRunningVersion(versionJson)) { - runningVersion = new ResourceVersion( - resource.resourceId(), - page, - versionJson.get("id").getAsInt(), - versionJson.get("resource_version").getAsString(), - null // no need for changelog of running version - ); - } + latestVersion = new ResourceVersion( resource.resourceId(), page, @@ -94,14 +91,17 @@ public class VersionFinder extends CompletableFuture { versionJson.get("message").getAsString() ) ); - //System.out.printf("%d %d %s\n", page, versionJson.get("id").getAsInt(), versionJson.get("resource_version").getAsString()); + + if (isRunningVersion(versionJson)) + runningVersion = latestVersion; + + DebugLogger.finer("%s - %s #%d", resource.name(), latestVersion.updateId(), latestVersion.updateId()); } if (jsonArray.size() < 10) break; } } - //System.out.println("Done"); if (page > 999) { throw new Exception("Too many pages"); @@ -117,7 +117,8 @@ public class VersionFinder extends CompletableFuture { } private boolean isRunningVersion(JsonObject versionJson) { - // TODO - return versionJson.get("resource_version").getAsString().equals(resource.plugin().getDescription().getVersion()); + // TODO make it work with more advanced strings + return versionJson.get("resource_version").getAsString() + .equals(resource.plugin().getDescription().getVersion()); } } diff --git a/src/main/java/eu/m724/tweaks/updater/cache/ResourceVersion.java b/src/main/java/eu/m724/tweaks/updater/object/ResourceVersion.java similarity index 90% rename from src/main/java/eu/m724/tweaks/updater/cache/ResourceVersion.java rename to src/main/java/eu/m724/tweaks/updater/object/ResourceVersion.java index d5d0fd3..6bebcea 100644 --- a/src/main/java/eu/m724/tweaks/updater/cache/ResourceVersion.java +++ b/src/main/java/eu/m724/tweaks/updater/object/ResourceVersion.java @@ -1,10 +1,10 @@ /* - * Copyright (C) 2024 Minecon724 + * Copyright (C) 2025 Minecon724 * Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file * in the project root for the full license text. */ -package eu.m724.tweaks.updater.cache; +package eu.m724.tweaks.updater.object; import java.util.Objects; diff --git a/src/main/java/eu/m724/tweaks/updater/cache/SpigotResource.java b/src/main/java/eu/m724/tweaks/updater/object/SpigotResource.java similarity index 77% rename from src/main/java/eu/m724/tweaks/updater/cache/SpigotResource.java rename to src/main/java/eu/m724/tweaks/updater/object/SpigotResource.java index dce97cf..c2c7a8a 100644 --- a/src/main/java/eu/m724/tweaks/updater/cache/SpigotResource.java +++ b/src/main/java/eu/m724/tweaks/updater/object/SpigotResource.java @@ -1,10 +1,10 @@ /* - * Copyright (C) 2024 Minecon724 + * Copyright (C) 2025 Minecon724 * Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file * in the project root for the full license text. */ -package eu.m724.tweaks.updater.cache; +package eu.m724.tweaks.updater.object; import org.bukkit.plugin.Plugin; @@ -12,5 +12,4 @@ public record SpigotResource( Plugin plugin, int resourceId, String name -) { -} +) { } diff --git a/src/main/java/eu/m724/tweaks/updater/cache/UpdateDescription.java b/src/main/java/eu/m724/tweaks/updater/object/UpdateDescription.java similarity index 74% rename from src/main/java/eu/m724/tweaks/updater/cache/UpdateDescription.java rename to src/main/java/eu/m724/tweaks/updater/object/UpdateDescription.java index 1837716..508b8bd 100644 --- a/src/main/java/eu/m724/tweaks/updater/cache/UpdateDescription.java +++ b/src/main/java/eu/m724/tweaks/updater/object/UpdateDescription.java @@ -1,13 +1,12 @@ /* - * Copyright (C) 2024 Minecon724 + * Copyright (C) 2025 Minecon724 * Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file * in the project root for the full license text. */ -package eu.m724.tweaks.updater.cache; +package eu.m724.tweaks.updater.object; public record UpdateDescription( String title, String description -) { -} +) { } diff --git a/src/main/java/eu/m724/tweaks/updater/cache/VersionedResource.java b/src/main/java/eu/m724/tweaks/updater/object/VersionedResource.java similarity index 79% rename from src/main/java/eu/m724/tweaks/updater/cache/VersionedResource.java rename to src/main/java/eu/m724/tweaks/updater/object/VersionedResource.java index 18d4bb2..f140bb9 100644 --- a/src/main/java/eu/m724/tweaks/updater/cache/VersionedResource.java +++ b/src/main/java/eu/m724/tweaks/updater/object/VersionedResource.java @@ -1,10 +1,10 @@ /* - * Copyright (C) 2024 Minecon724 + * Copyright (C) 2025 Minecon724 * Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file * in the project root for the full license text. */ -package eu.m724.tweaks.updater.cache; +package eu.m724.tweaks.updater.object; public record VersionedResource( SpigotResource resource,