From 98a0f6946d47c19deb3154035734cb3b3b25fa76 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Mon, 5 Jul 2021 21:48:29 -0400 Subject: [PATCH 01/42] improve spigot resource checker Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../com/projectg/geyserupdater/bungee/BungeeUpdater.java | 2 +- .../common/util/SpigotResourceUpdateChecker.java | 6 +++--- .../com/projectg/geyserupdater/spigot/SpigotUpdater.java | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/projectg/geyserupdater/bungee/BungeeUpdater.java b/src/main/java/com/projectg/geyserupdater/bungee/BungeeUpdater.java index e61f738d..59fad103 100644 --- a/src/main/java/com/projectg/geyserupdater/bungee/BungeeUpdater.java +++ b/src/main/java/com/projectg/geyserupdater/bungee/BungeeUpdater.java @@ -128,7 +128,7 @@ public void checkConfigVersion(){ public void checkUpdaterVersion() { getProxy().getScheduler().runAsync(this, () -> { String pluginVersion = getDescription().getVersion(); - String latestVersion = SpigotResourceUpdateChecker.getVersion(); + String latestVersion = SpigotResourceUpdateChecker.getVersion(88555); if (latestVersion == null || latestVersion.length() == 0) { logger.error("Failed to determine the latest GeyserUpdater version!"); } else { diff --git a/src/main/java/com/projectg/geyserupdater/common/util/SpigotResourceUpdateChecker.java b/src/main/java/com/projectg/geyserupdater/common/util/SpigotResourceUpdateChecker.java index c81fc9d5..08e02db0 100644 --- a/src/main/java/com/projectg/geyserupdater/common/util/SpigotResourceUpdateChecker.java +++ b/src/main/java/com/projectg/geyserupdater/common/util/SpigotResourceUpdateChecker.java @@ -9,15 +9,15 @@ public class SpigotResourceUpdateChecker { - private static final String VERSION_REGEX = "(\\d+.){1,2}\\d+"; + private static final String VERSION_REGEX = "(\\d+.){1,2}\\d+(-SNAPSHOT){0,1}"; /** * Get the latest version of GeyserUpdater from the spigot resource page * @return the latest version, null if there was an error. */ - public static String getVersion() { + public static String getVersion(int resourceId) { - try (InputStream inputStream = new URL("https://api.spigotmc.org/legacy/update.php?resource=88555").openStream(); Scanner scanner = new Scanner(inputStream)) { + try (InputStream inputStream = new URL("https://api.spigotmc.org/legacy/update.php?resource=" + resourceId).openStream(); Scanner scanner = new Scanner(inputStream)) { StringBuilder builder = new StringBuilder(); while (scanner.hasNext()) { builder.append(scanner.next()); diff --git a/src/main/java/com/projectg/geyserupdater/spigot/SpigotUpdater.java b/src/main/java/com/projectg/geyserupdater/spigot/SpigotUpdater.java index 913a0cdb..dbb16f28 100644 --- a/src/main/java/com/projectg/geyserupdater/spigot/SpigotUpdater.java +++ b/src/main/java/com/projectg/geyserupdater/spigot/SpigotUpdater.java @@ -107,7 +107,7 @@ public void checkUpdaterVersion() { new BukkitRunnable() { @Override public void run() { - String latestVersion = SpigotResourceUpdateChecker.getVersion(); + String latestVersion = SpigotResourceUpdateChecker.getVersion(88555); if (latestVersion == null || latestVersion.length() == 0) { logger.error("Failed to determine the latest GeyserUpdater version!"); } else { From 11aa0380e30a7f6075086fc41d0b107abe1d90ea Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Mon, 5 Jul 2021 22:58:59 -0400 Subject: [PATCH 02/42] add (unused) scheduler interface and implementations Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../geyserupdater/bungee/BungeeScheduler.java | 25 ++++++++++ .../common/UpdaterScheduler.java | 47 +++++++++++++++++++ .../geyserupdater/spigot/SpigotScheduler.java | 28 +++++++++++ .../velocity/VelocityScheduler.java | 27 +++++++++++ 4 files changed, 127 insertions(+) create mode 100644 src/main/java/com/projectg/geyserupdater/bungee/BungeeScheduler.java create mode 100644 src/main/java/com/projectg/geyserupdater/common/UpdaterScheduler.java create mode 100644 src/main/java/com/projectg/geyserupdater/spigot/SpigotScheduler.java create mode 100644 src/main/java/com/projectg/geyserupdater/velocity/VelocityScheduler.java diff --git a/src/main/java/com/projectg/geyserupdater/bungee/BungeeScheduler.java b/src/main/java/com/projectg/geyserupdater/bungee/BungeeScheduler.java new file mode 100644 index 00000000..210cc8eb --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/bungee/BungeeScheduler.java @@ -0,0 +1,25 @@ +package com.projectg.geyserupdater.bungee; + +import com.projectg.geyserupdater.common.UpdaterScheduler; +import net.md_5.bungee.api.plugin.Plugin; +import org.jetbrains.annotations.NotNull; + +import javax.annotation.Nonnull; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +public class BungeeScheduler implements UpdaterScheduler { + + private final Plugin plugin; + + public BungeeScheduler(@Nonnull Plugin plugin) { + Objects.requireNonNull(plugin); + this.plugin = plugin; + } + + @Override + public void schedule(@NotNull Runnable runnable, boolean async, long delay, long repeat) { + Objects.requireNonNull(runnable); + plugin.getProxy().getScheduler().schedule(plugin, runnable, delay, repeat, TimeUnit.MILLISECONDS); + } +} diff --git a/src/main/java/com/projectg/geyserupdater/common/UpdaterScheduler.java b/src/main/java/com/projectg/geyserupdater/common/UpdaterScheduler.java new file mode 100644 index 00000000..bcebba2d --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/UpdaterScheduler.java @@ -0,0 +1,47 @@ +package com.projectg.geyserupdater.common; + +import javax.annotation.Nonnull; +import java.util.Objects; + +public interface UpdaterScheduler { + + default void run(@Nonnull Runnable runnable, boolean async) { + Objects.requireNonNull(runnable); + schedule(runnable, async, 0, 0); + } + + /** + * Schedule a Runnable to be run. + * @param runnable The Runnable + * @param async True to run the task async (Disregarded for BungeeCord, Velocity) + * @param delay The delay in milliseconds + */ + default void runDelayed(@Nonnull Runnable runnable, boolean async, long delay) { + Objects.requireNonNull(runnable); + schedule(runnable, async, delay, 0); + } + + /** + * Schedule a Runnable to be run. + * @param runnable The Runnable + * @param async True to run the task async (Disregarded for BungeeCord, Velocity) + * @param repeat The repeat period, in milliseconds. A value of 0 will only run the Runnable once. + */ + default void runTimer(@Nonnull Runnable runnable, boolean async, long repeat) { + Objects.requireNonNull(runnable); + schedule(runnable, async, 0, repeat); + } + + /** + * Schedule a Runnable to be run. + * @param runnable The Runnable + * @param async True to run the task async (Disregarded for BungeeCord, Velocity) + * @param delay The delay in milliseconds + * @param repeat The repeat period, in milliseconds. A value of 0 will only run the Runnable once. + */ + void schedule(@Nonnull Runnable runnable, boolean async, long delay, long repeat); + // todo: make sure that repeat of 0 is handled properly on all platforms + +} + + diff --git a/src/main/java/com/projectg/geyserupdater/spigot/SpigotScheduler.java b/src/main/java/com/projectg/geyserupdater/spigot/SpigotScheduler.java new file mode 100644 index 00000000..28cdcf1c --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/spigot/SpigotScheduler.java @@ -0,0 +1,28 @@ +package com.projectg.geyserupdater.spigot; + +import com.projectg.geyserupdater.common.UpdaterScheduler; +import org.bukkit.plugin.java.JavaPlugin; +import org.jetbrains.annotations.NotNull; + +import javax.annotation.Nonnull; +import java.util.Objects; + +public class SpigotScheduler implements UpdaterScheduler { + + private final JavaPlugin plugin; + + public SpigotScheduler(@Nonnull JavaPlugin plugin) { + Objects.requireNonNull(plugin); + this.plugin = plugin; + } + + @Override + public void schedule(@NotNull Runnable runnable, boolean async, long delay, long repeat) { + Objects.requireNonNull(runnable); + if (async) { + plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, runnable, delay * 50, repeat * 50); // multiply by 50 for milliseconds -> ticks + } else { + plugin.getServer().getScheduler().runTaskTimer(plugin, runnable, delay * 50, repeat * 50); + } + } +} diff --git a/src/main/java/com/projectg/geyserupdater/velocity/VelocityScheduler.java b/src/main/java/com/projectg/geyserupdater/velocity/VelocityScheduler.java new file mode 100644 index 00000000..caf2838b --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/velocity/VelocityScheduler.java @@ -0,0 +1,27 @@ +package com.projectg.geyserupdater.velocity; + +import com.projectg.geyserupdater.common.UpdaterScheduler; +import org.jetbrains.annotations.NotNull; + +import javax.annotation.Nonnull; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +public class VelocityScheduler implements UpdaterScheduler { + + private final VelocityUpdater plugin; + + public VelocityScheduler(@Nonnull VelocityUpdater plugin) { + Objects.requireNonNull(plugin); + this.plugin = plugin; + } + + @Override + public void schedule(@NotNull Runnable runnable, boolean async, long delay, long repeat) { + Objects.requireNonNull(runnable); + this.plugin.getProxyServer().getScheduler().buildTask(plugin, runnable) + .delay(delay, TimeUnit.MILLISECONDS) + .repeat(repeat, TimeUnit.MILLISECONDS) + .schedule(); + } +} From 5b83d05014b447a5f372cac43c965f157fe6cfdd Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Mon, 5 Jul 2021 23:36:12 -0400 Subject: [PATCH 03/42] some more abstraction stuff Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../bungee/BungeePlayerHandler.java | 28 +++++++++++++++ .../geyserupdater/bungee/BungeeScheduler.java | 2 +- .../geyserupdater/common/GeyserUpdater.java | 23 +++++++++++++ .../geyserupdater/common/PlayerHandler.java | 16 +++++++++ .../{ => scheduler}/UpdaterScheduler.java | 2 +- .../spigot/SpigotPlayerHandler.java | 27 +++++++++++++++ .../geyserupdater/spigot/SpigotScheduler.java | 2 +- .../velocity/VelocityPlayerHandler.java | 34 +++++++++++++++++++ .../velocity/VelocityScheduler.java | 2 +- 9 files changed, 132 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/projectg/geyserupdater/bungee/BungeePlayerHandler.java create mode 100644 src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java create mode 100644 src/main/java/com/projectg/geyserupdater/common/PlayerHandler.java rename src/main/java/com/projectg/geyserupdater/common/{ => scheduler}/UpdaterScheduler.java (96%) create mode 100644 src/main/java/com/projectg/geyserupdater/spigot/SpigotPlayerHandler.java create mode 100644 src/main/java/com/projectg/geyserupdater/velocity/VelocityPlayerHandler.java diff --git a/src/main/java/com/projectg/geyserupdater/bungee/BungeePlayerHandler.java b/src/main/java/com/projectg/geyserupdater/bungee/BungeePlayerHandler.java new file mode 100644 index 00000000..7c2c30fd --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/bungee/BungeePlayerHandler.java @@ -0,0 +1,28 @@ +package com.projectg.geyserupdater.bungee; + +import com.projectg.geyserupdater.common.PlayerHandler; +import net.md_5.bungee.api.ProxyServer; +import net.md_5.bungee.api.chat.TextComponent; +import net.md_5.bungee.api.connection.ProxiedPlayer; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class BungeePlayerHandler implements PlayerHandler { + + @Override + public @NotNull List getOnlinePlayers() { + List uuidList = new ArrayList<>(); + for (ProxiedPlayer player : ProxyServer.getInstance().getPlayers()) { + uuidList.add(player.getUniqueId()); + } + return uuidList; + } + + @Override + public void sendMessage(@NotNull UUID uuid, @NotNull String message) { + ProxyServer.getInstance().getPlayer(uuid).sendMessage(new TextComponent(message)); + } +} diff --git a/src/main/java/com/projectg/geyserupdater/bungee/BungeeScheduler.java b/src/main/java/com/projectg/geyserupdater/bungee/BungeeScheduler.java index 210cc8eb..19f14122 100644 --- a/src/main/java/com/projectg/geyserupdater/bungee/BungeeScheduler.java +++ b/src/main/java/com/projectg/geyserupdater/bungee/BungeeScheduler.java @@ -1,6 +1,6 @@ package com.projectg.geyserupdater.bungee; -import com.projectg.geyserupdater.common.UpdaterScheduler; +import com.projectg.geyserupdater.common.scheduler.UpdaterScheduler; import net.md_5.bungee.api.plugin.Plugin; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java b/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java new file mode 100644 index 00000000..d079c282 --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java @@ -0,0 +1,23 @@ +package com.projectg.geyserupdater.common; + +import com.projectg.geyserupdater.common.scheduler.UpdaterScheduler; + + +public class GeyserUpdater { + + private final UpdaterScheduler scheduler; + private final PlayerHandler playerHandler; + + public GeyserUpdater(UpdaterScheduler scheduler, PlayerHandler playerHandler) { + this.scheduler = scheduler; + this.playerHandler = playerHandler; + } + + + public UpdaterScheduler getScheduler() { + return scheduler; + } + public PlayerHandler getPlayerHandler() { + return playerHandler; + } +} diff --git a/src/main/java/com/projectg/geyserupdater/common/PlayerHandler.java b/src/main/java/com/projectg/geyserupdater/common/PlayerHandler.java new file mode 100644 index 00000000..448c24e7 --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/PlayerHandler.java @@ -0,0 +1,16 @@ +package com.projectg.geyserupdater.common; + +import org.jetbrains.annotations.NotNull; + +import javax.annotation.Nonnull; +import java.util.List; +import java.util.UUID; + +public interface PlayerHandler { + + @Nonnull + List getOnlinePlayers(); + + void sendMessage(@Nonnull UUID uuid, @NotNull String message); + +} diff --git a/src/main/java/com/projectg/geyserupdater/common/UpdaterScheduler.java b/src/main/java/com/projectg/geyserupdater/common/scheduler/UpdaterScheduler.java similarity index 96% rename from src/main/java/com/projectg/geyserupdater/common/UpdaterScheduler.java rename to src/main/java/com/projectg/geyserupdater/common/scheduler/UpdaterScheduler.java index bcebba2d..9141cfb9 100644 --- a/src/main/java/com/projectg/geyserupdater/common/UpdaterScheduler.java +++ b/src/main/java/com/projectg/geyserupdater/common/scheduler/UpdaterScheduler.java @@ -1,4 +1,4 @@ -package com.projectg.geyserupdater.common; +package com.projectg.geyserupdater.common.scheduler; import javax.annotation.Nonnull; import java.util.Objects; diff --git a/src/main/java/com/projectg/geyserupdater/spigot/SpigotPlayerHandler.java b/src/main/java/com/projectg/geyserupdater/spigot/SpigotPlayerHandler.java new file mode 100644 index 00000000..f73a9c12 --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/spigot/SpigotPlayerHandler.java @@ -0,0 +1,27 @@ +package com.projectg.geyserupdater.spigot; + +import com.projectg.geyserupdater.common.PlayerHandler; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class SpigotPlayerHandler implements PlayerHandler { + + @Override + public @NotNull List getOnlinePlayers() { + List uuidList = new ArrayList<>(); + for (Player player : Bukkit.getServer().getOnlinePlayers()) { + uuidList.add(player.getUniqueId()); + } + return uuidList; + } + + @Override + public void sendMessage(@NotNull UUID uuid, @NotNull String message) { + Bukkit.getServer().getPlayer(uuid).sendMessage(message); + } +} diff --git a/src/main/java/com/projectg/geyserupdater/spigot/SpigotScheduler.java b/src/main/java/com/projectg/geyserupdater/spigot/SpigotScheduler.java index 28cdcf1c..bbaeb8e7 100644 --- a/src/main/java/com/projectg/geyserupdater/spigot/SpigotScheduler.java +++ b/src/main/java/com/projectg/geyserupdater/spigot/SpigotScheduler.java @@ -1,6 +1,6 @@ package com.projectg.geyserupdater.spigot; -import com.projectg.geyserupdater.common.UpdaterScheduler; +import com.projectg.geyserupdater.common.scheduler.UpdaterScheduler; import org.bukkit.plugin.java.JavaPlugin; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/projectg/geyserupdater/velocity/VelocityPlayerHandler.java b/src/main/java/com/projectg/geyserupdater/velocity/VelocityPlayerHandler.java new file mode 100644 index 00000000..9a958c83 --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/velocity/VelocityPlayerHandler.java @@ -0,0 +1,34 @@ +package com.projectg.geyserupdater.velocity; + +import com.projectg.geyserupdater.common.PlayerHandler; +import com.velocitypowered.api.proxy.Player; +import com.velocitypowered.api.proxy.ProxyServer; +import org.jetbrains.annotations.NotNull; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class VelocityPlayerHandler implements PlayerHandler { + + private final ProxyServer proxyServer; + + public VelocityPlayerHandler(@Nonnull ProxyServer proxyServer) { + this.proxyServer = proxyServer; + } + + @Override + public @NotNull List getOnlinePlayers() { + List uuidList = new ArrayList<>(); + for (Player player : proxyServer.getAllPlayers()) { + uuidList.add(player.getUniqueId()); + } + return uuidList; + } + + @Override + public void sendMessage(@NotNull UUID uuid, @NotNull String message) { + + } +} diff --git a/src/main/java/com/projectg/geyserupdater/velocity/VelocityScheduler.java b/src/main/java/com/projectg/geyserupdater/velocity/VelocityScheduler.java index caf2838b..5d22be78 100644 --- a/src/main/java/com/projectg/geyserupdater/velocity/VelocityScheduler.java +++ b/src/main/java/com/projectg/geyserupdater/velocity/VelocityScheduler.java @@ -1,6 +1,6 @@ package com.projectg.geyserupdater.velocity; -import com.projectg.geyserupdater.common.UpdaterScheduler; +import com.projectg.geyserupdater.common.scheduler.UpdaterScheduler; import org.jetbrains.annotations.NotNull; import javax.annotation.Nonnull; From 4043c42467a60b65400afba89607a9a450466114 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Tue, 6 Jul 2021 12:18:33 -0400 Subject: [PATCH 04/42] improve scheduler Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../geyserupdater/bungee/BungeeScheduler.java | 4 ++-- .../common/scheduler/UpdaterScheduler.java | 13 ++++++------ .../geyserupdater/spigot/SpigotScheduler.java | 20 +++++++++++++++---- .../velocity/VelocityScheduler.java | 6 +++--- 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/projectg/geyserupdater/bungee/BungeeScheduler.java b/src/main/java/com/projectg/geyserupdater/bungee/BungeeScheduler.java index 19f14122..a03d9554 100644 --- a/src/main/java/com/projectg/geyserupdater/bungee/BungeeScheduler.java +++ b/src/main/java/com/projectg/geyserupdater/bungee/BungeeScheduler.java @@ -18,8 +18,8 @@ public BungeeScheduler(@Nonnull Plugin plugin) { } @Override - public void schedule(@NotNull Runnable runnable, boolean async, long delay, long repeat) { + public void schedule(@NotNull Runnable runnable, boolean async, long delay, long repeat, TimeUnit unit) { Objects.requireNonNull(runnable); - plugin.getProxy().getScheduler().schedule(plugin, runnable, delay, repeat, TimeUnit.MILLISECONDS); + plugin.getProxy().getScheduler().schedule(plugin, runnable, delay, repeat, unit); } } diff --git a/src/main/java/com/projectg/geyserupdater/common/scheduler/UpdaterScheduler.java b/src/main/java/com/projectg/geyserupdater/common/scheduler/UpdaterScheduler.java index 9141cfb9..7352750f 100644 --- a/src/main/java/com/projectg/geyserupdater/common/scheduler/UpdaterScheduler.java +++ b/src/main/java/com/projectg/geyserupdater/common/scheduler/UpdaterScheduler.java @@ -2,12 +2,13 @@ import javax.annotation.Nonnull; import java.util.Objects; +import java.util.concurrent.TimeUnit; public interface UpdaterScheduler { default void run(@Nonnull Runnable runnable, boolean async) { Objects.requireNonNull(runnable); - schedule(runnable, async, 0, 0); + schedule(runnable, async, 0, 0, TimeUnit.MILLISECONDS); } /** @@ -16,9 +17,9 @@ default void run(@Nonnull Runnable runnable, boolean async) { * @param async True to run the task async (Disregarded for BungeeCord, Velocity) * @param delay The delay in milliseconds */ - default void runDelayed(@Nonnull Runnable runnable, boolean async, long delay) { + default void runDelayed(@Nonnull Runnable runnable, boolean async, long delay, TimeUnit unit) { Objects.requireNonNull(runnable); - schedule(runnable, async, delay, 0); + schedule(runnable, async, delay, 0, unit); } /** @@ -27,9 +28,9 @@ default void runDelayed(@Nonnull Runnable runnable, boolean async, long delay) { * @param async True to run the task async (Disregarded for BungeeCord, Velocity) * @param repeat The repeat period, in milliseconds. A value of 0 will only run the Runnable once. */ - default void runTimer(@Nonnull Runnable runnable, boolean async, long repeat) { + default void runTimer(@Nonnull Runnable runnable, boolean async, long repeat, TimeUnit unit) { Objects.requireNonNull(runnable); - schedule(runnable, async, 0, repeat); + schedule(runnable, async, 0, repeat, unit); } /** @@ -39,7 +40,7 @@ default void runTimer(@Nonnull Runnable runnable, boolean async, long repeat) { * @param delay The delay in milliseconds * @param repeat The repeat period, in milliseconds. A value of 0 will only run the Runnable once. */ - void schedule(@Nonnull Runnable runnable, boolean async, long delay, long repeat); + void schedule(@Nonnull Runnable runnable, boolean async, long delay, long repeat, TimeUnit unit); // todo: make sure that repeat of 0 is handled properly on all platforms } diff --git a/src/main/java/com/projectg/geyserupdater/spigot/SpigotScheduler.java b/src/main/java/com/projectg/geyserupdater/spigot/SpigotScheduler.java index bbaeb8e7..f15065dc 100644 --- a/src/main/java/com/projectg/geyserupdater/spigot/SpigotScheduler.java +++ b/src/main/java/com/projectg/geyserupdater/spigot/SpigotScheduler.java @@ -2,10 +2,12 @@ import com.projectg.geyserupdater.common.scheduler.UpdaterScheduler; import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitScheduler; import org.jetbrains.annotations.NotNull; import javax.annotation.Nonnull; import java.util.Objects; +import java.util.concurrent.TimeUnit; public class SpigotScheduler implements UpdaterScheduler { @@ -17,12 +19,22 @@ public SpigotScheduler(@Nonnull JavaPlugin plugin) { } @Override - public void schedule(@NotNull Runnable runnable, boolean async, long delay, long repeat) { + public void schedule(@NotNull Runnable runnable, boolean async, long delay, long repeat, TimeUnit unit) { Objects.requireNonNull(runnable); - if (async) { - plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, runnable, delay * 50, repeat * 50); // multiply by 50 for milliseconds -> ticks + + BukkitScheduler scheduler = plugin.getServer().getScheduler(); + if (repeat <= 0) { + if (async) { + scheduler.runTaskLaterAsynchronously(plugin, runnable, unit.toSeconds(delay) * 20); // 20 ticks in a second + } else { + scheduler.runTaskLater(plugin, runnable, unit.toSeconds(delay) * 20); + } } else { - plugin.getServer().getScheduler().runTaskTimer(plugin, runnable, delay * 50, repeat * 50); + if (async) { + scheduler.runTaskTimerAsynchronously(plugin, runnable, unit.toSeconds(delay) * 20, unit.toSeconds(repeat) * 20); + } else { + scheduler.runTaskTimer(plugin, runnable, unit.toSeconds(delay) * 20, unit.toSeconds(repeat) * 20); + } } } } diff --git a/src/main/java/com/projectg/geyserupdater/velocity/VelocityScheduler.java b/src/main/java/com/projectg/geyserupdater/velocity/VelocityScheduler.java index 5d22be78..655b5558 100644 --- a/src/main/java/com/projectg/geyserupdater/velocity/VelocityScheduler.java +++ b/src/main/java/com/projectg/geyserupdater/velocity/VelocityScheduler.java @@ -17,11 +17,11 @@ public VelocityScheduler(@Nonnull VelocityUpdater plugin) { } @Override - public void schedule(@NotNull Runnable runnable, boolean async, long delay, long repeat) { + public void schedule(@NotNull Runnable runnable, boolean async, long delay, long repeat, TimeUnit unit) { Objects.requireNonNull(runnable); this.plugin.getProxyServer().getScheduler().buildTask(plugin, runnable) - .delay(delay, TimeUnit.MILLISECONDS) - .repeat(repeat, TimeUnit.MILLISECONDS) + .delay(delay, unit) + .repeat(repeat, unit) .schedule(); } } From c265eecfd0a6b16e9e544e4df0d602e5e0bcacea Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Tue, 6 Jul 2021 15:38:41 -0400 Subject: [PATCH 05/42] more stuff Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- pom.xml | 15 +++--- .../geyserupdater/common/GeyserUpdater.java | 50 +++++++++++++++++- .../common/UpdaterConfiguration.java | 52 +++++++++++++++++++ src/main/resources/config.yml | 2 +- 4 files changed, 109 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/projectg/geyserupdater/common/UpdaterConfiguration.java diff --git a/pom.xml b/pom.xml index bd451a3a..5f4873df 100644 --- a/pom.xml +++ b/pom.xml @@ -59,17 +59,10 @@ jar provided - - net.md-5 - bungeecord-api - 1.16-R0.5-SNAPSHOT - javadoc - provided - com.velocitypowered velocity-api - 1.1.8 + 3.0.0 provided @@ -90,6 +83,12 @@ 1.4.0-SNAPSHOT provided + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + 2.10.2 + compile + diff --git a/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java b/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java index d079c282..1ec835dd 100644 --- a/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java +++ b/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java @@ -1,19 +1,67 @@ package com.projectg.geyserupdater.common; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import com.projectg.geyserupdater.common.logger.UpdaterLogger; import com.projectg.geyserupdater.common.scheduler.UpdaterScheduler; +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; + public class GeyserUpdater { + private final UpdaterLogger logger; private final UpdaterScheduler scheduler; private final PlayerHandler playerHandler; - public GeyserUpdater(UpdaterScheduler scheduler, PlayerHandler playerHandler) { + private UpdaterConfiguration config; + + public GeyserUpdater(Path dataFolder, UpdaterLogger logger, UpdaterScheduler scheduler, PlayerHandler playerHandler, + boolean loopRestartScript) throws IOException { + this.logger = logger; this.scheduler = scheduler; this.playerHandler = playerHandler; + + this.loadConfig(dataFolder.resolve("config.yml")); + + + + + + if (config.isEnableDebug()) { + logger.enableDebug(); + } + } + private void loadConfig(Path userConfig) throws IOException { + if (!Files.exists(userConfig)) { + //Files.createDirectories(userConfig.getParent()); todo: necessary? + try (InputStream inputStream = this.getClass().getResourceAsStream("/config.yml")) { + Objects.requireNonNull(inputStream); + Files.copy(inputStream, userConfig); + } + } + ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory()); + UpdaterConfiguration config = yamlMapper.readValue(userConfig.toFile(), UpdaterConfiguration.class); + + int localVersion = config.getConfigVersion(); + int defaultVersion = UpdaterConfiguration.DEFAULT_CONFIG_VERSION; + if (localVersion == defaultVersion) { + this.config = config; + } else { + logger.error("Your copy of config.yml is outdated (your version: " + localVersion + ", latest version: " + defaultVersion + "). Please delete it and let a fresh copy of config.yml be regenerated!"); + } + } + + + public UpdaterConfiguration getConfig() { + return config; + } public UpdaterScheduler getScheduler() { return scheduler; } diff --git a/src/main/java/com/projectg/geyserupdater/common/UpdaterConfiguration.java b/src/main/java/com/projectg/geyserupdater/common/UpdaterConfiguration.java new file mode 100644 index 00000000..b093fb7e --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/UpdaterConfiguration.java @@ -0,0 +1,52 @@ +package com.projectg.geyserupdater.common; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class UpdaterConfiguration { + + public static int DEFAULT_CONFIG_VERSION = 2; + + @JsonProperty(value = "Auto-Update-Geyser", required = true) + private boolean autoUpdate = false; + public boolean isAutoUpdate() { + return autoUpdate; + } + + @JsonProperty(value = "Auto-Update-Interval", required = true) + private int autoUpdateInterval = 24; + public int getAutoUpdateInterval() { + return autoUpdateInterval; + } + + @JsonProperty(value = "Auto-Restart-Server", required = true) + private boolean restartServer = false; + public boolean isRestartServer() { + return restartServer; + } + + @JsonProperty(value = "Auto-Script-Generating", required = true) + private boolean generateRestartScript = false; + public boolean isGenerateRestartScript() { + return generateRestartScript; + } + + @JsonProperty(value = "Restart-Message-Players", required = true) + private String restartMessage = "§2This server will be restarting in 10 seconds!"; + public String getRestartMessage() { + return restartMessage; + } + + @JsonProperty(value = "Enable-Debug", required = true) + private boolean enableDebug = false; + public boolean isEnableDebug() { + return enableDebug; + } + + @JsonProperty(value = "Config-Version", required = true) + private int configVersion = 2; + public int getConfigVersion() { + return configVersion; + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 78e0f5e8..861786b0 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -17,7 +17,7 @@ Auto-Restart-Server: false Auto-Script-Generating: false # Configure the message that is sent to all online players warning them that the server will be restarting in 10 seconds. -Restart-Message-Players: '&2This server will be restarting in 10 seconds!' +Restart-Message-Players: "§2This server will be restarting in 10 seconds!" # Enable debug logging Enable-Debug: false From bd2828a41afdfe13e8b21ad0169a8d887a9f9ef4 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Tue, 6 Jul 2021 23:49:12 -0400 Subject: [PATCH 06/42] slightly update velocity to new stuff Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../common/UpdaterConfiguration.java | 4 + .../geyserupdater/common/util/FileUtils.java | 15 ++++ .../velocity/VelocityUpdater.java | 75 +++++-------------- .../util/GeyserVelocityDownloader.java | 4 +- 4 files changed, 39 insertions(+), 59 deletions(-) diff --git a/src/main/java/com/projectg/geyserupdater/common/UpdaterConfiguration.java b/src/main/java/com/projectg/geyserupdater/common/UpdaterConfiguration.java index b093fb7e..1b12b716 100644 --- a/src/main/java/com/projectg/geyserupdater/common/UpdaterConfiguration.java +++ b/src/main/java/com/projectg/geyserupdater/common/UpdaterConfiguration.java @@ -49,4 +49,8 @@ public boolean isEnableDebug() { public int getConfigVersion() { return configVersion; } + + public boolean isIncorrectVersion() { + return getConfigVersion() != DEFAULT_CONFIG_VERSION; + } } 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..c59c71dd 100644 --- a/src/main/java/com/projectg/geyserupdater/common/util/FileUtils.java +++ b/src/main/java/com/projectg/geyserupdater/common/util/FileUtils.java @@ -1,5 +1,8 @@ package com.projectg.geyserupdater.common.util; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import com.projectg.geyserupdater.common.UpdaterConfiguration; import com.projectg.geyserupdater.common.logger.UpdaterLogger; import java.io.FileOutputStream; @@ -11,6 +14,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Objects; public class FileUtils { // TODO: this whole cached thing only works if you're using checkFile for one file... @@ -86,5 +90,16 @@ public static void downloadFile(String fileURL, String outputPath) throws IOExce is.close(); os.close(); } + + public static UpdaterConfiguration getConfig(Path userConfig, InputStream defaultConfig) throws IOException { + if (!Files.exists(userConfig)) { + //Files.createDirectories(userConfig.getParent()); todo: necessary? + Objects.requireNonNull(defaultConfig); + Files.copy(defaultConfig, userConfig); + } + + ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory()); + return yamlMapper.readValue(userConfig.toFile(), UpdaterConfiguration.class); + } } diff --git a/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java b/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java index 00a61959..8909171e 100644 --- a/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java +++ b/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java @@ -1,5 +1,6 @@ package com.projectg.geyserupdater.velocity; +import com.projectg.geyserupdater.common.UpdaterConfiguration; import com.projectg.geyserupdater.common.logger.UpdaterLogger; import com.projectg.geyserupdater.common.util.FileUtils; import com.projectg.geyserupdater.common.util.GeyserProperties; @@ -12,8 +13,6 @@ import com.google.inject.Inject; -import com.moandjiezana.toml.Toml; - import org.geysermc.connector.GeyserConnector; import org.slf4j.Logger; @@ -30,7 +29,6 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -42,32 +40,33 @@ public class VelocityUpdater { private static VelocityUpdater plugin; private final ProxyServer server; - private final Logger baseLogger; private final Path dataDirectory; - private final Toml config; + private final UpdaterConfiguration config; private final Metrics.Factory metricsFactory; @Inject - public VelocityUpdater(ProxyServer server, Logger baseLogger, @DataDirectory final Path folder, Metrics.Factory metricsFactory) { + public VelocityUpdater(ProxyServer server, Logger baseLogger, @DataDirectory final Path folder, Metrics.Factory metricsFactory) throws IOException { VelocityUpdater.plugin = this; this.server = server; - this.baseLogger = baseLogger; this.dataDirectory = folder; - this.config = loadConfig(dataDirectory); this.metricsFactory = metricsFactory; - } - @Subscribe - public void onProxyInitialization(ProxyInitializeEvent event) { - metricsFactory.make(this, 10673); new Slf4jUpdaterLogger(baseLogger); - if (getConfig().getBoolean("Enable-Debug", false)) { - UpdaterLogger.getLogger().info("Trying to enable debug logging."); + config = FileUtils.getConfig(dataDirectory.resolve("config.yml"), this.getClass().getResourceAsStream("/config.yml")); + if (config.isIncorrectVersion()) { + throw new RuntimeException("Your copy of config.yml is outdated! Please delete it and let a fresh copy of config.yml be regenerated!"); + } + + if (getConfig().isEnableDebug()) { UpdaterLogger.getLogger().enableDebug(); } + } + + @Subscribe + public void onProxyInitialization(ProxyInitializeEvent event) { + metricsFactory.make(this, 10673); - checkConfigVersion(); // todo: meta version checking // Register our only command @@ -76,7 +75,7 @@ public void onProxyInitialization(ProxyInitializeEvent event) { server.getEventManager().register(this, new VelocityJoinListener()); // Make startup script if enabled - if (config.getBoolean("Auto-Script-Generating")) { + if (config.isGenerateRestartScript()) { try { ScriptCreator.createRestartScript(true); } catch (IOException e) { @@ -84,7 +83,7 @@ public void onProxyInitialization(ProxyInitializeEvent event) { } } // Auto update Geyser if enabled in the config - if (config.getBoolean("Auto-Update-Geyser")) { + if (config.isAutoUpdate()) { scheduleAutoUpdate(); } // Check if downloaded Geyser file exists periodically @@ -127,44 +126,6 @@ public void onShutdown(ProxyShutdownEvent event) { } } - /** - * Load GeyserUpdater's config - * - * @param path The config's directory - * @return The configuration - */ - private Toml loadConfig(Path path) { - File folder = path.toFile(); - File file = new File(folder, "config.toml"); - - if (!file.exists()) { - if (!file.getParentFile().exists()) { - file.getParentFile().mkdirs(); - } - try (InputStream input = getClass().getResourceAsStream("/" + file.getName())) { - if (input != null) { - Files.copy(input, file.toPath()); - } else { - file.createNewFile(); - } - } catch (IOException exception) { - exception.printStackTrace(); - return null; - } - } - return new Toml().read(file); - } - - /** - * Check the config version of GeyserUpdater - */ - public void checkConfigVersion() { - //Change version number only when editing config.yml! - if (getConfig().getLong("Config-Version", 0L).compareTo(2L) != 0) { - UpdaterLogger.getLogger().warn("Your copy of config.yml is outdated. Please delete it and let a fresh copy of config.yml be regenerated!"); - } - } - /** * Check for a newer version of Geyser every 24hrs */ @@ -187,7 +148,7 @@ public void scheduleAutoUpdate() { } }) .delay(1L, TimeUnit.MINUTES) - .repeat(getConfig().getLong("Auto-Update-Interval", 24L), TimeUnit.HOURS) + .repeat(getConfig().getAutoUpdateInterval(), TimeUnit.HOURS) .schedule(); } @@ -237,7 +198,7 @@ public ProxyServer getProxyServer() { public Path getDataDirectory() { return dataDirectory; } - public Toml getConfig() { + public UpdaterConfiguration getConfig() { return config; } } 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 a6087c9e..11a05313 100644 --- a/src/main/java/com/projectg/geyserupdater/velocity/util/GeyserVelocityDownloader.java +++ b/src/main/java/com/projectg/geyserupdater/velocity/util/GeyserVelocityDownloader.java @@ -42,7 +42,7 @@ public static void updateGeyser() { player.sendMessage(Component.text(successMsg).color(TextColor.fromHexString("55FF55"))); } } - if (plugin.getConfig().getBoolean("Auto-Restart-Server")) { + if (plugin.getConfig().isRestartServer()) { restartServer(); } } else { @@ -93,7 +93,7 @@ private static boolean downloadGeyser() { private static void restartServer() { logger.warn("The server will be restarting in 10 seconds!"); for (Player player : server.getAllPlayers()) { - player.sendMessage(Component.text(plugin.getConfig().getString("Restart-Message-Players"))); + player.sendMessage(Component.text(plugin.getConfig().getRestartMessage())); } server.getScheduler() .buildTask(plugin, server::shutdown) From d54a15ff5c3b2c57eebbb25a18c1c82651d846ef Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Wed, 14 Jul 2021 23:55:23 -0400 Subject: [PATCH 07/42] more progress (more mess) Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- pom.xml | 6 + .../geyserupdater/bungee/BungeeScheduler.java | 3 + .../geyserupdater/common/GeyserUpdater.java | 85 ++++++++----- .../geyserupdater/common/PluginId.java | 24 ++++ .../geyserupdater/common/UpdateManager.java | 43 +++++++ .../geyserupdater/common/Updateable.java | 14 +++ .../{ => config}/UpdaterConfiguration.java | 5 +- .../common/scheduler/UpdaterScheduler.java | 8 +- .../geyserupdater/common/util/FileUtils.java | 15 ++- .../common/util/GeyserProperties.java | 58 --------- .../common/util/PropertiesUtils.java | 31 +++++ .../geyserupdater/common/util/WebUtils.java | 113 ++++++++++++++++++ .../geyserupdater/spigot/SpigotScheduler.java | 3 + .../velocity/VelocityScheduler.java | 3 + .../velocity/VelocityUpdater.java | 94 ++++----------- 15 files changed, 332 insertions(+), 173 deletions(-) create mode 100644 src/main/java/com/projectg/geyserupdater/common/PluginId.java create mode 100644 src/main/java/com/projectg/geyserupdater/common/UpdateManager.java create mode 100644 src/main/java/com/projectg/geyserupdater/common/Updateable.java rename src/main/java/com/projectg/geyserupdater/common/{ => config}/UpdaterConfiguration.java (91%) delete mode 100644 src/main/java/com/projectg/geyserupdater/common/util/GeyserProperties.java create mode 100644 src/main/java/com/projectg/geyserupdater/common/util/PropertiesUtils.java create mode 100644 src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java diff --git a/pom.xml b/pom.xml index 5f4873df..a1fce616 100644 --- a/pom.xml +++ b/pom.xml @@ -83,6 +83,12 @@ 1.4.0-SNAPSHOT provided + + org.geysermc.floodgate + common + 2.0-SNAPSHOT + provided + com.fasterxml.jackson.dataformat jackson-dataformat-yaml diff --git a/src/main/java/com/projectg/geyserupdater/bungee/BungeeScheduler.java b/src/main/java/com/projectg/geyserupdater/bungee/BungeeScheduler.java index a03d9554..c07e8136 100644 --- a/src/main/java/com/projectg/geyserupdater/bungee/BungeeScheduler.java +++ b/src/main/java/com/projectg/geyserupdater/bungee/BungeeScheduler.java @@ -19,7 +19,10 @@ public BungeeScheduler(@Nonnull Plugin plugin) { @Override public void schedule(@NotNull Runnable runnable, boolean async, long delay, long repeat, TimeUnit unit) { + // https://github.com/SpigotMC/BungeeCord/blob/master/proxy/src/main/java/net/md_5/bungee/scheduler/BungeeTask.java + Objects.requireNonNull(runnable); + plugin.getProxy().getScheduler().schedule(plugin, runnable, delay, repeat, unit); } } diff --git a/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java b/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java index 1ec835dd..5e704c0e 100644 --- a/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java +++ b/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java @@ -1,67 +1,94 @@ package com.projectg.geyserupdater.common; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import com.projectg.geyserupdater.common.config.UpdaterConfiguration; import com.projectg.geyserupdater.common.logger.UpdaterLogger; import com.projectg.geyserupdater.common.scheduler.UpdaterScheduler; +import com.projectg.geyserupdater.common.util.FileUtils; +import com.projectg.geyserupdater.common.util.ScriptCreator; +import com.projectg.geyserupdater.common.util.SpigotResourceUpdateChecker; import java.io.*; -import java.nio.file.Files; import java.nio.file.Path; -import java.util.Objects; public class GeyserUpdater { + private static GeyserUpdater INSTANCE = null; + private final UpdaterLogger logger; private final UpdaterScheduler scheduler; private final PlayerHandler playerHandler; + public final String version; private UpdaterConfiguration config; public GeyserUpdater(Path dataFolder, UpdaterLogger logger, UpdaterScheduler scheduler, PlayerHandler playerHandler, - boolean loopRestartScript) throws IOException { + boolean ignoreRestartScriptOption, boolean loopRestartScript, String version) throws IOException { this.logger = logger; this.scheduler = scheduler; this.playerHandler = playerHandler; - - this.loadConfig(dataFolder.resolve("config.yml")); - - - - - + this.version = version; + + INSTANCE = this; + + // Meta version checking + scheduler.run(() -> { + String latestVersion = SpigotResourceUpdateChecker.getVersion(88555); + if (latestVersion == null || latestVersion.isEmpty()) { + logger.error("Failed to determine the latest GeyserUpdater version!"); + } else { + if (latestVersion.equals(version)) { + logger.info("You are using the latest version of GeyserUpdater!"); + } else { + logger.info("Your version: " + version + ". Latest version: " + latestVersion + ". Download the newer version at https://www.spigotmc.org/resources/geyserupdater.88555/."); + } + } + }, true); + + // Load the config + logger.debug("Loading config"); + UpdaterConfiguration config = FileUtils.loadConfig(dataFolder.resolve("config.yml")); //todo will this resolve work? + if (config.isIncorrectVersion()) { + logger.error("Your copy of config.yml is outdated (your version: " + config.getConfigVersion() + ", latest version: " + UpdaterConfiguration.DEFAULT_CONFIG_VERSION + "). Please delete it and let a fresh copy of config.yml be regenerated!"); + return; + } if (config.isEnableDebug()) { logger.enableDebug(); } + if (ignoreRestartScriptOption) { + // This is basically just for spigot, so that we don't generate a script if the one defined in spigot.yml exists. + config.setGenerateRestartScript(false); + } - } - - private void loadConfig(Path userConfig) throws IOException { - if (!Files.exists(userConfig)) { - //Files.createDirectories(userConfig.getParent()); todo: necessary? - try (InputStream inputStream = this.getClass().getResourceAsStream("/config.yml")) { - Objects.requireNonNull(inputStream); - Files.copy(inputStream, userConfig); + // Make startup script if enabled + if (config.isGenerateRestartScript()) { + try { + logger.debug("Attempting to create restart script"); + ScriptCreator.createRestartScript(true); + } catch (IOException e) { + logger.error("Error while creating restart script:"); + e.printStackTrace(); } } - ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory()); - UpdaterConfiguration config = yamlMapper.readValue(userConfig.toFile(), UpdaterConfiguration.class); - - int localVersion = config.getConfigVersion(); - int defaultVersion = UpdaterConfiguration.DEFAULT_CONFIG_VERSION; - if (localVersion == defaultVersion) { - this.config = config; - } else { - logger.error("Your copy of config.yml is outdated (your version: " + localVersion + ", latest version: " + defaultVersion + "). Please delete it and let a fresh copy of config.yml be regenerated!"); + // Load all the data what we are updating + UpdateManager updateManager = new UpdateManager(); + for (PluginId pluginId : PluginId.values()) { + updateManager.add(pluginId); } } + + public static GeyserUpdater getInstance() { + return INSTANCE; + } public UpdaterConfiguration getConfig() { return config; } + public UpdaterLogger getLogger() { + return logger; + } public UpdaterScheduler getScheduler() { return scheduler; } diff --git a/src/main/java/com/projectg/geyserupdater/common/PluginId.java b/src/main/java/com/projectg/geyserupdater/common/PluginId.java new file mode 100644 index 00000000..1d2bd9a4 --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/PluginId.java @@ -0,0 +1,24 @@ +package com.projectg.geyserupdater.common; + +import org.geysermc.connector.GeyserConnector; +import org.geysermc.floodgate.FloodgatePlatform; + +public enum PluginId { + GEYSER("https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/", GeyserConnector.class), + FLOODGATE("https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/", FloodgatePlatform.class); + + /** + * https://ci.opencollab.dev/job/GeyserMC/job/{PLUGIN_PAGE}/job/ + */ + public final String link; + + /** + * A class from the given plugin + */ + public final Class pluginClass; + + PluginId(String link, Class pluginClass) { + this.link = link; + this.pluginClass = pluginClass; + } +} diff --git a/src/main/java/com/projectg/geyserupdater/common/UpdateManager.java b/src/main/java/com/projectg/geyserupdater/common/UpdateManager.java new file mode 100644 index 00000000..1cf20b79 --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/UpdateManager.java @@ -0,0 +1,43 @@ +package com.projectg.geyserupdater.common; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Properties; + +public class UpdateManager { + + private List updateables = new ArrayList<>(); + + public UpdateManager() { + } + + public List getUpdateables() { + return new ArrayList<>(updateables); + } + + public void add(Updateable updateable) { + updateables.add(updateable); + } + + public void add(PluginId pluginId) throws IOException { + // todo: have this stuff in Updateable or PluginId (probably the former) + Properties properties = new Properties(); + + InputStream is = pluginId.pluginClass.getResourceAsStream("git.properties"); + if (is == null) { + throw new AssertionError("Unable to find resource: git.properties"); + } + + properties.load(is); + is.close(); + + String branch = properties.getProperty("git.branch"); //todo: pass default here? + String number = properties.getProperty("git.build.number"); + Objects.requireNonNull(branch, number); + + updateables.add(new Updateable(pluginId, branch, Integer.parseInt(number))); + } +} diff --git a/src/main/java/com/projectg/geyserupdater/common/Updateable.java b/src/main/java/com/projectg/geyserupdater/common/Updateable.java new file mode 100644 index 00000000..ad0da135 --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/Updateable.java @@ -0,0 +1,14 @@ +package com.projectg.geyserupdater.common; + +public class Updateable { + + public final PluginId pluginId; + public final String branch; + public final int buildNumber; + + public Updateable(PluginId pluginId, String branch, int buildNumber) { + this.pluginId = pluginId; + this.branch = branch; + this.buildNumber = buildNumber; + } +} diff --git a/src/main/java/com/projectg/geyserupdater/common/UpdaterConfiguration.java b/src/main/java/com/projectg/geyserupdater/common/config/UpdaterConfiguration.java similarity index 91% rename from src/main/java/com/projectg/geyserupdater/common/UpdaterConfiguration.java rename to src/main/java/com/projectg/geyserupdater/common/config/UpdaterConfiguration.java index 1b12b716..4a43b75c 100644 --- a/src/main/java/com/projectg/geyserupdater/common/UpdaterConfiguration.java +++ b/src/main/java/com/projectg/geyserupdater/common/config/UpdaterConfiguration.java @@ -1,4 +1,4 @@ -package com.projectg.geyserupdater.common; +package com.projectg.geyserupdater.common.config; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -31,6 +31,9 @@ public boolean isRestartServer() { public boolean isGenerateRestartScript() { return generateRestartScript; } + public void setGenerateRestartScript(boolean generate) { + generateRestartScript = generate; + } @JsonProperty(value = "Restart-Message-Players", required = true) private String restartMessage = "§2This server will be restarting in 10 seconds!"; diff --git a/src/main/java/com/projectg/geyserupdater/common/scheduler/UpdaterScheduler.java b/src/main/java/com/projectg/geyserupdater/common/scheduler/UpdaterScheduler.java index 7352750f..eadc84e2 100644 --- a/src/main/java/com/projectg/geyserupdater/common/scheduler/UpdaterScheduler.java +++ b/src/main/java/com/projectg/geyserupdater/common/scheduler/UpdaterScheduler.java @@ -15,7 +15,7 @@ default void run(@Nonnull Runnable runnable, boolean async) { * Schedule a Runnable to be run. * @param runnable The Runnable * @param async True to run the task async (Disregarded for BungeeCord, Velocity) - * @param delay The delay in milliseconds + * @param delay The delay in milliseconds. A value less than zero should be considered unsafe. */ default void runDelayed(@Nonnull Runnable runnable, boolean async, long delay, TimeUnit unit) { Objects.requireNonNull(runnable); @@ -26,7 +26,7 @@ default void runDelayed(@Nonnull Runnable runnable, boolean async, long delay, T * Schedule a Runnable to be run. * @param runnable The Runnable * @param async True to run the task async (Disregarded for BungeeCord, Velocity) - * @param repeat The repeat period, in milliseconds. A value of 0 will only run the Runnable once. + * @param repeat The repeat period, in milliseconds. A value of 0 or less will only run the Runnable once. A value less than zero should be considered unsafe. */ default void runTimer(@Nonnull Runnable runnable, boolean async, long repeat, TimeUnit unit) { Objects.requireNonNull(runnable); @@ -37,8 +37,8 @@ default void runTimer(@Nonnull Runnable runnable, boolean async, long repeat, Ti * Schedule a Runnable to be run. * @param runnable The Runnable * @param async True to run the task async (Disregarded for BungeeCord, Velocity) - * @param delay The delay in milliseconds - * @param repeat The repeat period, in milliseconds. A value of 0 will only run the Runnable once. + * @param delay The delay in milliseconds. A value less than zero should be considered unsafe. + * @param repeat The repeat period, in milliseconds. A value of 0 or less will only run the Runnable once. A value less than zero should be considered unsafe. */ void schedule(@Nonnull Runnable runnable, boolean async, long delay, long repeat, TimeUnit unit); // todo: make sure that repeat of 0 is handled properly on all platforms 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 c59c71dd..f0829848 100644 --- a/src/main/java/com/projectg/geyserupdater/common/util/FileUtils.java +++ b/src/main/java/com/projectg/geyserupdater/common/util/FileUtils.java @@ -2,13 +2,10 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; -import com.projectg.geyserupdater.common.UpdaterConfiguration; +import com.projectg.geyserupdater.common.config.UpdaterConfiguration; import com.projectg.geyserupdater.common.logger.UpdaterLogger; -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.file.Files; @@ -91,11 +88,13 @@ public static void downloadFile(String fileURL, String outputPath) throws IOExce os.close(); } - public static UpdaterConfiguration getConfig(Path userConfig, InputStream defaultConfig) throws IOException { + public static UpdaterConfiguration loadConfig(Path userConfig) throws IOException { if (!Files.exists(userConfig)) { //Files.createDirectories(userConfig.getParent()); todo: necessary? - Objects.requireNonNull(defaultConfig); - Files.copy(defaultConfig, userConfig); + try (InputStream inputStream = FileUtils.class.getResourceAsStream("/config.yml")) { + Objects.requireNonNull(inputStream); + Files.copy(inputStream, userConfig); + } } ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory()); diff --git a/src/main/java/com/projectg/geyserupdater/common/util/GeyserProperties.java b/src/main/java/com/projectg/geyserupdater/common/util/GeyserProperties.java deleted file mode 100644 index 48b63603..00000000 --- a/src/main/java/com/projectg/geyserupdater/common/util/GeyserProperties.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.projectg.geyserupdater.common.util; - -import com.projectg.geyserupdater.common.logger.UpdaterLogger; -import org.geysermc.connector.utils.FileUtils; -import org.geysermc.connector.utils.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 { - - // todo: a check to see if the local git branch is available on the CI (that knows if it failed because of a bad connection or not) - // todo: proper error handling - - /** - * Compare the local build number to the latest build number on Geyser CI - * - * @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 { - UpdaterLogger.getLogger().debug("Running isLatestBuild()"); - int jenkinsBuildNumber = getLatestGeyserBuildNumberFromJenkins(getGeyserGitPropertiesValue("git.branch")); - 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; - } - - /** Query the git properties of Geyser - * - * @param propertyKey the key of property to query - * @return the value of the property - * @throws IOException if failed to load the Geyser git properties - */ - public static String getGeyserGitPropertiesValue(String propertyKey) throws IOException { - UpdaterLogger.getLogger().debug("Running getGeyserGitPropertiesValue()"); - Properties gitProperties = new Properties(); - gitProperties.load(FileUtils.getResource("git.properties")); - return gitProperties.getProperty(propertyKey); - } - - /** Get the latest build number of a given branch of Geyser from jenkins CI - * - * @param gitBranch the branch to query - * @return the latest build number - * @throws UnsupportedEncodingException if failed to encode the given gitBranch - */ - public static int getLatestGeyserBuildNumberFromJenkins(String gitBranch) throws UnsupportedEncodingException { - 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()); - } -} \ No newline at end of file diff --git a/src/main/java/com/projectg/geyserupdater/common/util/PropertiesUtils.java b/src/main/java/com/projectg/geyserupdater/common/util/PropertiesUtils.java new file mode 100644 index 00000000..1a17dfac --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/util/PropertiesUtils.java @@ -0,0 +1,31 @@ +package com.projectg.geyserupdater.common.util; + +import com.projectg.geyserupdater.common.Updateable; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +public class PropertiesUtils { + + /** + * Compare the local build number to the latest build number on Geyser CI + * + * @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(Updateable updateable) throws IOException { + int jenkinsBuildNumber = WebUtils.getLatestGeyserBuildNumberFromJenkins(updateable.branch); + int localBuildNumber = updateable.buildNumber; + // 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; + } + + public static Properties getProperties(InputStream is) throws IOException { + Properties properties = new Properties(); + properties.load(is); + return properties; + } +} diff --git a/src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java b/src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java new file mode 100644 index 00000000..77c3cf57 --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java @@ -0,0 +1,113 @@ +package com.projectg.geyserupdater.common.util; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.projectg.geyserupdater.common.GeyserUpdater; + +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; + +// Full credit to GeyserMC +// https://github.com/GeyserMC/Geyser/blob/master/connector/src/main/java/org/geysermc/connector/utils/WebUtils.java + +public class WebUtils { + + /** + * Makes a web request to the given URL and returns the body as a string + * + * @param reqURL URL to fetch + * @return Body contents or error message if the request fails + */ + public static String getBody(String reqURL) { + try { + URL url = new URL(reqURL); + HttpURLConnection con = (HttpURLConnection) url.openConnection(); + con.setRequestMethod("GET"); + con.setRequestProperty("User-Agent", "GeyserUpdater-" + GeyserUpdater.getInstance().version); // Otherwise Java 8 fails on checking updates + + return connectionToString(con); + } catch (Exception e) { + return e.getMessage(); + } + } + + /** + * Makes a web request to the given URL and returns the body as a {@link JsonNode}. + * + * @param reqURL URL to fetch + * @return the response as JSON + */ + public static JsonNode getJson(String reqURL) throws IOException { + HttpURLConnection con = (HttpURLConnection) new URL(reqURL).openConnection(); + con.setRequestProperty("User-Agent", "GeyserUpdater-" + GeyserUpdater.getInstance().version); + return new ObjectMapper().readTree(con.getInputStream()); + } + + /** + * Downloads a file from the given URL and saves it to disk + * + * @param reqURL File to fetch + * @param fileLocation Location to save on disk + */ + public static void downloadFile(String reqURL, String fileLocation) { + try { + HttpURLConnection con = (HttpURLConnection) new URL(reqURL).openConnection(); + con.setRequestProperty("User-Agent", "GeyserUpdater-" + GeyserUpdater.getInstance().version); + InputStream in = con.getInputStream(); + Files.copy(in, Paths.get(fileLocation), StandardCopyOption.REPLACE_EXISTING); + // todo: need to close stuff? + } catch (Exception e) { + throw new AssertionError("Unable to download and save file: " + fileLocation + " (" + reqURL + ")", e); + } + } + + + /** + * Get the string output from the passed {@link HttpURLConnection} + * + * @param con The connection to get the string from + * @return The body of the returned page + */ + private static String connectionToString(HttpURLConnection con) throws IOException { + // Send the request (we don't use this but its required for getErrorStream() to work) + con.getResponseCode(); + + // Read the error message if there is one if not just read normally + InputStream inputStream = con.getErrorStream(); + if (inputStream == null) { + inputStream = con.getInputStream(); + } + + StringBuilder content = new StringBuilder(); + try (BufferedReader in = new BufferedReader(new InputStreamReader(inputStream))) { + String inputLine; + + while ((inputLine = in.readLine()) != null) { + content.append(inputLine); + content.append("\n"); + } + + con.disconnect(); + } + + return content.toString(); + } + + /** Get the latest build number of a given branch of Geyser from jenkins CI + * + * @param gitBranch the branch to query + * @return the latest build number + * @throws UnsupportedEncodingException if failed to encode the given gitBranch + */ + public static int getLatestGeyserBuildNumberFromJenkins(String gitBranch) throws UnsupportedEncodingException { + // todo use json + 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()); + } +} diff --git a/src/main/java/com/projectg/geyserupdater/spigot/SpigotScheduler.java b/src/main/java/com/projectg/geyserupdater/spigot/SpigotScheduler.java index f15065dc..690282ee 100644 --- a/src/main/java/com/projectg/geyserupdater/spigot/SpigotScheduler.java +++ b/src/main/java/com/projectg/geyserupdater/spigot/SpigotScheduler.java @@ -20,6 +20,9 @@ public SpigotScheduler(@Nonnull JavaPlugin plugin) { @Override public void schedule(@NotNull Runnable runnable, boolean async, long delay, long repeat, TimeUnit unit) { + // https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/browse/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java + // https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/browse/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java + Objects.requireNonNull(runnable); BukkitScheduler scheduler = plugin.getServer().getScheduler(); diff --git a/src/main/java/com/projectg/geyserupdater/velocity/VelocityScheduler.java b/src/main/java/com/projectg/geyserupdater/velocity/VelocityScheduler.java index 655b5558..4e6f5f45 100644 --- a/src/main/java/com/projectg/geyserupdater/velocity/VelocityScheduler.java +++ b/src/main/java/com/projectg/geyserupdater/velocity/VelocityScheduler.java @@ -18,7 +18,10 @@ public VelocityScheduler(@Nonnull VelocityUpdater plugin) { @Override public void schedule(@NotNull Runnable runnable, boolean async, long delay, long repeat, TimeUnit unit) { + // https://github.com/VelocityPowered/Velocity/blob/dev/3.0.0/proxy/src/main/java/com/velocitypowered/proxy/scheduler/VelocityScheduler.java + Objects.requireNonNull(runnable); + this.plugin.getProxyServer().getScheduler().buildTask(plugin, runnable) .delay(delay, unit) .repeat(repeat, unit) diff --git a/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java b/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java index 8909171e..ccb9e969 100644 --- a/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java +++ b/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java @@ -1,18 +1,15 @@ package com.projectg.geyserupdater.velocity; -import com.projectg.geyserupdater.common.UpdaterConfiguration; +import com.projectg.geyserupdater.common.GeyserUpdater; import com.projectg.geyserupdater.common.logger.UpdaterLogger; -import com.projectg.geyserupdater.common.util.FileUtils; -import com.projectg.geyserupdater.common.util.GeyserProperties; -import com.projectg.geyserupdater.common.util.ScriptCreator; import com.projectg.geyserupdater.velocity.command.GeyserUpdateCommand; import com.projectg.geyserupdater.velocity.listeners.VelocityJoinListener; import com.projectg.geyserupdater.velocity.logger.Slf4jUpdaterLogger; -import com.projectg.geyserupdater.velocity.util.GeyserVelocityDownloader; import com.projectg.geyserupdater.velocity.util.bstats.Metrics; import com.google.inject.Inject; +import com.velocitypowered.api.plugin.PluginContainer; import org.geysermc.connector.GeyserConnector; import org.slf4j.Logger; @@ -32,7 +29,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.concurrent.TimeUnit; +import java.util.Optional; @Plugin(id = "geyserupdater", name = "GeyserUpdater", version = "1.5.0", description = "Automatically or manually downloads new builds of Geyser and applies them on server restart.", authors = {"Jens"}, dependencies = {@Dependency(id = "geyser")}) @@ -41,7 +38,6 @@ public class VelocityUpdater { private static VelocityUpdater plugin; private final ProxyServer server; private final Path dataDirectory; - private final UpdaterConfiguration config; private final Metrics.Factory metricsFactory; @Inject @@ -51,50 +47,34 @@ public VelocityUpdater(ProxyServer server, Logger baseLogger, @DataDirectory fin this.dataDirectory = folder; this.metricsFactory = metricsFactory; - new Slf4jUpdaterLogger(baseLogger); - - config = FileUtils.getConfig(dataDirectory.resolve("config.yml"), this.getClass().getResourceAsStream("/config.yml")); - if (config.isIncorrectVersion()) { - throw new RuntimeException("Your copy of config.yml is outdated! Please delete it and let a fresh copy of config.yml be regenerated!"); + String version = null; + Optional geyserUpdater = server.getPluginManager().getPlugin("geyserupdater"); + if (geyserUpdater.isPresent()) { + if (geyserUpdater.get().getDescription().getVersion().isPresent()) { + version = geyserUpdater.get().getDescription().getVersion().get(); + } } - if (getConfig().isEnableDebug()) { - UpdaterLogger.getLogger().enableDebug(); - } + new GeyserUpdater( + dataDirectory, + new Slf4jUpdaterLogger(baseLogger), + new VelocityScheduler(this), + new VelocityPlayerHandler(server), + false, + true, + version + ); } @Subscribe public void onProxyInitialization(ProxyInitializeEvent event) { metricsFactory.make(this, 10673); - // todo: meta version checking - // Register our only command server.getCommandManager().register("geyserupdate", new GeyserUpdateCommand()); // Player alert if a restart is required when they join server.getEventManager().register(this, new VelocityJoinListener()); - // Make startup script if enabled - if (config.isGenerateRestartScript()) { - try { - ScriptCreator.createRestartScript(true); - } catch (IOException e) { - e.printStackTrace(); - } - } - // Auto update Geyser if enabled in the config - if (config.isAutoUpdate()) { - scheduleAutoUpdate(); - } - // Check if downloaded Geyser file exists periodically - server.getScheduler() - .buildTask(this, () -> { - FileUtils.checkFile("plugins/GeyserUpdater/BuildUpdate/Geyser-Velocity.jar", true); - UpdaterLogger.getLogger().info("A new Geyser build has been downloaded! Please restart Velocity in order to use the updated build!"); - }) - .delay(30L, TimeUnit.MINUTES) - .repeat(12L, TimeUnit.HOURS) - .schedule(); } @Subscribe(order = PostOrder.LAST) @@ -126,32 +106,6 @@ public void onShutdown(ProxyShutdownEvent event) { } } - /** - * Check for a newer version of Geyser every 24hrs - */ - public void scheduleAutoUpdate() { - UpdaterLogger.getLogger().debug("Scheduling auto updater"); - // Checking for the build numbers of current build. - // todo: build this in different way so that we don't repeat it if the Auto-Update-Interval is zero or -1 or something - server.getScheduler() - .buildTask(this, () -> { - UpdaterLogger.getLogger().debug("Checking if a new build of Geyser exists."); - try { - boolean isLatest = GeyserProperties.isLatestBuild(); - if (!isLatest) { - 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(); - } - }) - .delay(1L, TimeUnit.MINUTES) - .repeat(getConfig().getAutoUpdateInterval(), TimeUnit.HOURS) - .schedule(); - } - /** * Replace the Geyser jar in the plugin folder with the one in GeyserUpdater/BuildUpdate * Should only be called once Geyser has been disabled @@ -160,11 +114,11 @@ public void scheduleAutoUpdate() { */ public void moveGeyserJar() throws IOException { // Moving Geyser Jar to Plugins folder "Overwriting". - File fileToCopy = new File("plugins/GeyserUpdater/BuildUpdate/Geyser-Velocity.jar"); + File fileToCopy = new File("plugins/GeyserUpdater/BuildUpdate/Geyser-Velocity.jar"); //todo: improve if (fileToCopy.exists()) { UpdaterLogger.getLogger().debug("Moving the new Geyser jar to the plugins folder."); FileInputStream input = new FileInputStream(fileToCopy); - File newFile = new File("plugins/Geyser-Velocity.jar"); + File newFile = new File("plugins/Geyser-Velocity.jar"); //todo: improve FileOutputStream output = new FileOutputStream(newFile); byte[] buf = new byte[1024]; int bytesRead; @@ -185,7 +139,7 @@ public void moveGeyserJar() throws IOException { */ private void deleteGeyserJar() throws IOException { UpdaterLogger.getLogger().debug("Deleting the Geyser jar in the BuildUpdate folder if it exists"); - Path file = Paths.get("plugins/GeyserUpdater/BuildUpdate/Geyser-Velocity.jar"); + Path file = Paths.get("plugins/GeyserUpdater/BuildUpdate/Geyser-Velocity.jar"); //todo: improve Files.deleteIfExists(file); } @@ -195,12 +149,6 @@ public static VelocityUpdater getPlugin() { public ProxyServer getProxyServer() { return server; } - public Path getDataDirectory() { - return dataDirectory; - } - public UpdaterConfiguration getConfig() { - return config; - } } From f3198c80d8f35e482fa0205b6ded70f9270ce7fe Mon Sep 17 00:00:00 2001 From: Konicai <71294714+konicai@users.noreply.github.com> Date: Sun, 1 Aug 2021 14:50:15 -0400 Subject: [PATCH 08/42] dump changes --- .../geyserupdater/common/GeyserUpdater.java | 21 ++++---- .../geyserupdater/common/UpdateManager.java | 43 --------------- .../geyserupdater/common/Updateable.java | 14 ----- .../common/config/UpdaterConfiguration.java | 12 +++-- .../common/update/JenkinsUpdatable.java | 53 +++++++++++++++++++ .../common/{ => update}/PluginId.java | 13 ++--- .../common/update/Updatable.java | 36 +++++++++++++ .../common/update/UpdateManager.java | 29 ++++++++++ .../common/util/PropertiesUtils.java | 13 +++-- .../geyserupdater/common/util/WebUtils.java | 4 +- .../velocity/VelocityScheduler.java | 4 +- .../velocity/VelocityUpdater.java | 33 +++++------- src/main/resources/config.toml | 26 --------- src/main/resources/config.yml | 2 + 14 files changed, 171 insertions(+), 132 deletions(-) delete mode 100644 src/main/java/com/projectg/geyserupdater/common/UpdateManager.java delete mode 100644 src/main/java/com/projectg/geyserupdater/common/Updateable.java create mode 100644 src/main/java/com/projectg/geyserupdater/common/update/JenkinsUpdatable.java rename src/main/java/com/projectg/geyserupdater/common/{ => update}/PluginId.java (57%) create mode 100644 src/main/java/com/projectg/geyserupdater/common/update/Updatable.java create mode 100644 src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java delete mode 100644 src/main/resources/config.toml diff --git a/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java b/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java index 5e704c0e..36940633 100644 --- a/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java +++ b/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java @@ -3,6 +3,8 @@ import com.projectg.geyserupdater.common.config.UpdaterConfiguration; import com.projectg.geyserupdater.common.logger.UpdaterLogger; import com.projectg.geyserupdater.common.scheduler.UpdaterScheduler; +import com.projectg.geyserupdater.common.update.PluginId; +import com.projectg.geyserupdater.common.update.UpdateManager; import com.projectg.geyserupdater.common.util.FileUtils; import com.projectg.geyserupdater.common.util.ScriptCreator; import com.projectg.geyserupdater.common.util.SpigotResourceUpdateChecker; @@ -22,8 +24,15 @@ public class GeyserUpdater { private UpdaterConfiguration config; - public GeyserUpdater(Path dataFolder, UpdaterLogger logger, UpdaterScheduler scheduler, PlayerHandler playerHandler, - boolean ignoreRestartScriptOption, boolean loopRestartScript, String version) throws IOException { + public GeyserUpdater(Path dataFolder, + UpdaterLogger logger, + UpdaterScheduler scheduler, + PlayerHandler playerHandler, + boolean ignoreRestartScriptOption, + boolean loopRestartScript, + String version, + String geyserArtifact, + String floodgateArtifact) throws IOException { this.logger = logger; this.scheduler = scheduler; this.playerHandler = playerHandler; @@ -64,18 +73,12 @@ public GeyserUpdater(Path dataFolder, UpdaterLogger logger, UpdaterScheduler sch if (config.isGenerateRestartScript()) { try { logger.debug("Attempting to create restart script"); - ScriptCreator.createRestartScript(true); + ScriptCreator.createRestartScript(loopRestartScript); } catch (IOException e) { logger.error("Error while creating restart script:"); e.printStackTrace(); } } - - // Load all the data what we are updating - UpdateManager updateManager = new UpdateManager(); - for (PluginId pluginId : PluginId.values()) { - updateManager.add(pluginId); - } } diff --git a/src/main/java/com/projectg/geyserupdater/common/UpdateManager.java b/src/main/java/com/projectg/geyserupdater/common/UpdateManager.java deleted file mode 100644 index 1cf20b79..00000000 --- a/src/main/java/com/projectg/geyserupdater/common/UpdateManager.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.projectg.geyserupdater.common; - -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.Properties; - -public class UpdateManager { - - private List updateables = new ArrayList<>(); - - public UpdateManager() { - } - - public List getUpdateables() { - return new ArrayList<>(updateables); - } - - public void add(Updateable updateable) { - updateables.add(updateable); - } - - public void add(PluginId pluginId) throws IOException { - // todo: have this stuff in Updateable or PluginId (probably the former) - Properties properties = new Properties(); - - InputStream is = pluginId.pluginClass.getResourceAsStream("git.properties"); - if (is == null) { - throw new AssertionError("Unable to find resource: git.properties"); - } - - properties.load(is); - is.close(); - - String branch = properties.getProperty("git.branch"); //todo: pass default here? - String number = properties.getProperty("git.build.number"); - Objects.requireNonNull(branch, number); - - updateables.add(new Updateable(pluginId, branch, Integer.parseInt(number))); - } -} diff --git a/src/main/java/com/projectg/geyserupdater/common/Updateable.java b/src/main/java/com/projectg/geyserupdater/common/Updateable.java deleted file mode 100644 index ad0da135..00000000 --- a/src/main/java/com/projectg/geyserupdater/common/Updateable.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.projectg.geyserupdater.common; - -public class Updateable { - - public final PluginId pluginId; - public final String branch; - public final int buildNumber; - - public Updateable(PluginId pluginId, String branch, int buildNumber) { - this.pluginId = pluginId; - this.branch = branch; - this.buildNumber = buildNumber; - } -} diff --git a/src/main/java/com/projectg/geyserupdater/common/config/UpdaterConfiguration.java b/src/main/java/com/projectg/geyserupdater/common/config/UpdaterConfiguration.java index 4a43b75c..0934aaca 100644 --- a/src/main/java/com/projectg/geyserupdater/common/config/UpdaterConfiguration.java +++ b/src/main/java/com/projectg/geyserupdater/common/config/UpdaterConfiguration.java @@ -9,9 +9,15 @@ public class UpdaterConfiguration { public static int DEFAULT_CONFIG_VERSION = 2; @JsonProperty(value = "Auto-Update-Geyser", required = true) - private boolean autoUpdate = false; - public boolean isAutoUpdate() { - return autoUpdate; + private boolean autoUpdateGeyser = false; + public boolean isAutoUpdateGeyser() { + return autoUpdateGeyser; + } + + @JsonProperty(value = "Auto-Update-Floodgate", required = true) + private boolean autoUpdateFloodgate = false; + public boolean isAutoUpdateFloodgate() { + return autoUpdateFloodgate; } @JsonProperty(value = "Auto-Update-Interval", required = true) diff --git a/src/main/java/com/projectg/geyserupdater/common/update/JenkinsUpdatable.java b/src/main/java/com/projectg/geyserupdater/common/update/JenkinsUpdatable.java new file mode 100644 index 00000000..b6e75dbe --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/update/JenkinsUpdatable.java @@ -0,0 +1,53 @@ +package com.projectg.geyserupdater.common.update; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +public class JenkinsUpdatable implements Updatable{ + + public final PluginId pluginId; + public final String branch; + public final int buildNumber; + + public JenkinsUpdatable(PluginId pluginId) throws IOException { + this.pluginId = pluginId; + + // Get the class of the plugin + Class pluginClass; + try { + pluginClass = Class.forName(pluginId.pluginClass); + } catch (ClassNotFoundException e) { + throw new AssertionError("Failed to find Class '" + pluginId.pluginClass + "' for plugin: " + pluginId.name()); + } + + // Get the git.properties + InputStream is = pluginClass.getResourceAsStream("git.properties"); + if (is == null) { + throw new AssertionError("Unable to find resource 'git.properties' for plugin: " + pluginId.name()); + } + + Properties properties = new Properties(); + properties.load(is); + is.close(); + + String branch = properties.getProperty("git.branch"); + String number = properties.getProperty("git.build.number"); + if (branch == null || number == null) { + throw new AssertionError("Failed to find branch or build number in git.properties of plugin: " + pluginId.name()); + } + + this.branch = branch; + this.buildNumber = Integer.parseUnsignedInt(number); + } + + @Override + public boolean isOutdated() { + return false; + } + + @Override + public String getLatestDownloadLink() { + return null; + } +} diff --git a/src/main/java/com/projectg/geyserupdater/common/PluginId.java b/src/main/java/com/projectg/geyserupdater/common/update/PluginId.java similarity index 57% rename from src/main/java/com/projectg/geyserupdater/common/PluginId.java rename to src/main/java/com/projectg/geyserupdater/common/update/PluginId.java index 1d2bd9a4..14eeaf28 100644 --- a/src/main/java/com/projectg/geyserupdater/common/PluginId.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/PluginId.java @@ -1,11 +1,8 @@ -package com.projectg.geyserupdater.common; - -import org.geysermc.connector.GeyserConnector; -import org.geysermc.floodgate.FloodgatePlatform; +package com.projectg.geyserupdater.common.update; public enum PluginId { - GEYSER("https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/", GeyserConnector.class), - FLOODGATE("https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/", FloodgatePlatform.class); + GEYSER("https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/", "org.geysermc.connector.GeyserConnector"), + FLOODGATE("https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/", "org.geysermc.floodgate.FloodgatePlatform"); /** * https://ci.opencollab.dev/job/GeyserMC/job/{PLUGIN_PAGE}/job/ @@ -15,9 +12,9 @@ public enum PluginId { /** * A class from the given plugin */ - public final Class pluginClass; + public final String pluginClass; - PluginId(String link, Class pluginClass) { + PluginId(String link, String pluginClass) { this.link = link; this.pluginClass = pluginClass; } diff --git a/src/main/java/com/projectg/geyserupdater/common/update/Updatable.java b/src/main/java/com/projectg/geyserupdater/common/update/Updatable.java new file mode 100644 index 00000000..6bedf64e --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/update/Updatable.java @@ -0,0 +1,36 @@ +package com.projectg.geyserupdater.common.update; + +import com.projectg.geyserupdater.common.util.WebUtils; + +import java.io.IOException; +import java.util.Objects; + +public class Updatable { + + private final String projectLink; + private final String branch; + private final int localBuildNumber; + + public Updatable(String artifactLink, PluginId pluginId) { + Objects.requireNonNull(artifactLink); + Objects.requireNonNull(pluginId); + + + + } + + + /** + * Compare the local build number to the latest build number on Geyser CI + * + * @return true if local build number equals latest build number on Geyser CI + * @throws IOException if it fails to fetch either build number + */ + public boolean isLatestBuild() throws IOException { + int jenkinsBuildNumber = WebUtils.getLatestGeyserBuildNumberFromJenkins(projectLink + "/" + branch); + // 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; + } +} diff --git a/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java b/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java new file mode 100644 index 00000000..9acceb69 --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java @@ -0,0 +1,29 @@ +package com.projectg.geyserupdater.common.update; + +import com.projectg.geyserupdater.common.GeyserUpdater; +import com.projectg.geyserupdater.common.config.UpdaterConfiguration; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Properties; + +public class UpdateManager { + + private List updatables = new ArrayList<>(); + + public UpdateManager(GeyserUpdater geyserUpdater) { + UpdaterConfiguration config = geyserUpdater.getConfig(); + boolean updateGeyser = config.isAutoUpdateGeyser(); + boolean updateFloodgate = config.isAutoUpdateFloodgate(); + + + + + + + + } +} diff --git a/src/main/java/com/projectg/geyserupdater/common/util/PropertiesUtils.java b/src/main/java/com/projectg/geyserupdater/common/util/PropertiesUtils.java index 1a17dfac..19f73ef6 100644 --- a/src/main/java/com/projectg/geyserupdater/common/util/PropertiesUtils.java +++ b/src/main/java/com/projectg/geyserupdater/common/util/PropertiesUtils.java @@ -1,6 +1,6 @@ package com.projectg.geyserupdater.common.util; -import com.projectg.geyserupdater.common.Updateable; +import com.projectg.geyserupdater.common.update.JenkinsUpdatable; import java.io.IOException; import java.io.InputStream; @@ -14,15 +14,20 @@ public class PropertiesUtils { * @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(Updateable updateable) throws IOException { - int jenkinsBuildNumber = WebUtils.getLatestGeyserBuildNumberFromJenkins(updateable.branch); - int localBuildNumber = updateable.buildNumber; + public static boolean isLatestBuild(JenkinsUpdatable updatable) throws IOException { + int jenkinsBuildNumber = WebUtils.getLatestGeyserBuildNumberFromJenkins(updatable.branch); + int localBuildNumber = updatable.buildNumber; // 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; } + + public static String getBranch(Properties properties) { + properties.get + } + public static Properties getProperties(InputStream is) throws IOException { Properties properties = new Properties(); properties.load(is); diff --git a/src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java b/src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java index 77c3cf57..359af27d 100644 --- a/src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java +++ b/src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java @@ -105,9 +105,9 @@ private static String connectionToString(HttpURLConnection con) throws IOExcepti * @return the latest build number * @throws UnsupportedEncodingException if failed to encode the given gitBranch */ - public static int getLatestGeyserBuildNumberFromJenkins(String gitBranch) throws UnsupportedEncodingException { + public static int getLatestGeyserBuildNumberFromJenkins(String branchLink) throws UnsupportedEncodingException { // todo use json - 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"); + String buildXMLContents = WebUtils.getBody(URLEncoder.encode(branchLink, StandardCharsets.UTF_8.toString()) + "/lastSuccessfulBuild/api/xml?xpath=//buildNumber"); return Integer.parseInt(buildXMLContents.replaceAll("<(\\\\)?(/)?buildNumber>", "").trim()); } } diff --git a/src/main/java/com/projectg/geyserupdater/velocity/VelocityScheduler.java b/src/main/java/com/projectg/geyserupdater/velocity/VelocityScheduler.java index 4e6f5f45..08abf043 100644 --- a/src/main/java/com/projectg/geyserupdater/velocity/VelocityScheduler.java +++ b/src/main/java/com/projectg/geyserupdater/velocity/VelocityScheduler.java @@ -1,7 +1,6 @@ package com.projectg.geyserupdater.velocity; import com.projectg.geyserupdater.common.scheduler.UpdaterScheduler; -import org.jetbrains.annotations.NotNull; import javax.annotation.Nonnull; import java.util.Objects; @@ -17,10 +16,11 @@ public VelocityScheduler(@Nonnull VelocityUpdater plugin) { } @Override - public void schedule(@NotNull Runnable runnable, boolean async, long delay, long repeat, TimeUnit unit) { + public void schedule(@Nonnull Runnable runnable, boolean async, long delay, long repeat, @Nonnull TimeUnit unit) { // https://github.com/VelocityPowered/Velocity/blob/dev/3.0.0/proxy/src/main/java/com/velocitypowered/proxy/scheduler/VelocityScheduler.java Objects.requireNonNull(runnable); + Objects.requireNonNull(unit); this.plugin.getProxyServer().getScheduler().buildTask(plugin, runnable) .delay(delay, unit) diff --git a/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java b/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java index ccb9e969..09669335 100644 --- a/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java +++ b/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java @@ -1,18 +1,12 @@ package com.projectg.geyserupdater.velocity; +import com.google.inject.Inject; import com.projectg.geyserupdater.common.GeyserUpdater; import com.projectg.geyserupdater.common.logger.UpdaterLogger; import com.projectg.geyserupdater.velocity.command.GeyserUpdateCommand; import com.projectg.geyserupdater.velocity.listeners.VelocityJoinListener; import com.projectg.geyserupdater.velocity.logger.Slf4jUpdaterLogger; import com.projectg.geyserupdater.velocity.util.bstats.Metrics; - -import com.google.inject.Inject; - -import com.velocitypowered.api.plugin.PluginContainer; -import org.geysermc.connector.GeyserConnector; -import org.slf4j.Logger; - import com.velocitypowered.api.event.PostOrder; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; @@ -21,6 +15,8 @@ import com.velocitypowered.api.plugin.Plugin; import com.velocitypowered.api.plugin.annotation.DataDirectory; import com.velocitypowered.api.proxy.ProxyServer; +import org.geysermc.connector.GeyserConnector; +import org.slf4j.Logger; import java.io.File; import java.io.FileInputStream; @@ -29,32 +25,25 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.Optional; -@Plugin(id = "geyserupdater", name = "GeyserUpdater", version = "1.5.0", description = "Automatically or manually downloads new builds of Geyser and applies them on server restart.", authors = {"Jens"}, +@Plugin(id = "geyserupdater", name = "GeyserUpdater", version = VelocityUpdater.VERSION, description = "Automatically or manually downloads new builds of Geyser and applies them on server restart.", authors = {"Jens"}, dependencies = {@Dependency(id = "geyser")}) public class VelocityUpdater { - private static VelocityUpdater plugin; + public static final String VERSION = "1.6.0"; + private static VelocityUpdater PLUGIN; + private final ProxyServer server; private final Path dataDirectory; private final Metrics.Factory metricsFactory; @Inject public VelocityUpdater(ProxyServer server, Logger baseLogger, @DataDirectory final Path folder, Metrics.Factory metricsFactory) throws IOException { - VelocityUpdater.plugin = this; + VelocityUpdater.PLUGIN = this; this.server = server; this.dataDirectory = folder; this.metricsFactory = metricsFactory; - String version = null; - Optional geyserUpdater = server.getPluginManager().getPlugin("geyserupdater"); - if (geyserUpdater.isPresent()) { - if (geyserUpdater.get().getDescription().getVersion().isPresent()) { - version = geyserUpdater.get().getDescription().getVersion().get(); - } - } - new GeyserUpdater( dataDirectory, new Slf4jUpdaterLogger(baseLogger), @@ -62,7 +51,9 @@ public VelocityUpdater(ProxyServer server, Logger baseLogger, @DataDirectory fin new VelocityPlayerHandler(server), false, true, - version + VERSION, + "/artifact/bootstrap/velocity/target/Geyser-Velocity.jar", + "/artifact/velocity/target/floodgate-velocity.jar" ); } @@ -144,7 +135,7 @@ private void deleteGeyserJar() throws IOException { } public static VelocityUpdater getPlugin() { - return plugin; + return PLUGIN; } public ProxyServer getProxyServer() { return server; diff --git a/src/main/resources/config.toml b/src/main/resources/config.toml deleted file mode 100644 index 24a572d7..00000000 --- a/src/main/resources/config.toml +++ /dev/null @@ -1,26 +0,0 @@ -# GeyserUpdater -# Made by Jens & YHDiamond - -# NOTICE: Please read the README on our github page for full information regarding these options! -# https://github.com/ProjectG-Plugins/GeyserUpdater - -# If enabled, GeyserUpdater will check for new Geyser builds on server start, and on the interval specified by Auto-Update-Interval. If a new build exists, it will be downloaded. -Auto-Update-Geyser=false -# The interval in hours between each auto update check. -Auto-Update-Interval=24 - -# If enabled, GeyserUpdater will attempt to restart the server 10 seconds after a new version of Geyser has been successfully downloaded. -# If you aren't using a hosting provider or a server wrapper, you will need a restart script. -Auto-Restart-Server=false -# When enabled, GeyserUpdater will automatically generate a restart script for you. If you are using CraftBukkit or a proxy -# you will need to use the generated script to start your server! If you are using a hosting provider or a server wrapper you probably don't need this. -Auto-Script-Generating=false - -# Configure the message that is sent to all online players warning them that the server will be restarting in 10 seconds. -Restart-Message-Players='&2This server will be restarting in 10 seconds!' - -# Enable debug logging -Enable-Debug=false - -# Please do not change this version value! -Config-Version=2 \ No newline at end of file diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 861786b0..756d5484 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -6,6 +6,8 @@ # If enabled, GeyserUpdater will check for new Geyser builds on server start, and on the interval specified by Auto-Update-Interval. If a new build exists, it will be downloaded. Auto-Update-Geyser: false +Auto-Update-Floodgate: false + # The interval in hours between each auto update check. Auto-Update-Interval: 24 From 69f8483ee80cb6ba9d4344e0348f89438850cf2d Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Wed, 4 Aug 2021 23:36:24 -0400 Subject: [PATCH 09/42] intitial age stuff impl Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../common/update/JenkinsUpdatable.java | 53 ----------------- .../geyserupdater/common/update/PluginId.java | 27 ++++++++- .../common/update/Updatable.java | 32 ++--------- .../common/update/UpdateManager.java | 57 +++++++++++++++---- .../common/update/age/AgeComparer.java | 51 +++++++++++++++++ .../update/age/provider/AgeProvider.java | 8 +++ .../age/provider/JenkinsBuildProvider.java | 15 +++++ .../common/update/age/type/Age.java | 10 ++++ .../common/update/age/type/BuildNumber.java | 15 +++++ 9 files changed, 174 insertions(+), 94 deletions(-) delete mode 100644 src/main/java/com/projectg/geyserupdater/common/update/JenkinsUpdatable.java create mode 100644 src/main/java/com/projectg/geyserupdater/common/update/age/AgeComparer.java create mode 100644 src/main/java/com/projectg/geyserupdater/common/update/age/provider/AgeProvider.java create mode 100644 src/main/java/com/projectg/geyserupdater/common/update/age/provider/JenkinsBuildProvider.java create mode 100644 src/main/java/com/projectg/geyserupdater/common/update/age/type/Age.java create mode 100644 src/main/java/com/projectg/geyserupdater/common/update/age/type/BuildNumber.java diff --git a/src/main/java/com/projectg/geyserupdater/common/update/JenkinsUpdatable.java b/src/main/java/com/projectg/geyserupdater/common/update/JenkinsUpdatable.java deleted file mode 100644 index b6e75dbe..00000000 --- a/src/main/java/com/projectg/geyserupdater/common/update/JenkinsUpdatable.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.projectg.geyserupdater.common.update; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Properties; - -public class JenkinsUpdatable implements Updatable{ - - public final PluginId pluginId; - public final String branch; - public final int buildNumber; - - public JenkinsUpdatable(PluginId pluginId) throws IOException { - this.pluginId = pluginId; - - // Get the class of the plugin - Class pluginClass; - try { - pluginClass = Class.forName(pluginId.pluginClass); - } catch (ClassNotFoundException e) { - throw new AssertionError("Failed to find Class '" + pluginId.pluginClass + "' for plugin: " + pluginId.name()); - } - - // Get the git.properties - InputStream is = pluginClass.getResourceAsStream("git.properties"); - if (is == null) { - throw new AssertionError("Unable to find resource 'git.properties' for plugin: " + pluginId.name()); - } - - Properties properties = new Properties(); - properties.load(is); - is.close(); - - String branch = properties.getProperty("git.branch"); - String number = properties.getProperty("git.build.number"); - if (branch == null || number == null) { - throw new AssertionError("Failed to find branch or build number in git.properties of plugin: " + pluginId.name()); - } - - this.branch = branch; - this.buildNumber = Integer.parseUnsignedInt(number); - } - - @Override - public boolean isOutdated() { - return false; - } - - @Override - public String getLatestDownloadLink() { - return null; - } -} diff --git a/src/main/java/com/projectg/geyserupdater/common/update/PluginId.java b/src/main/java/com/projectg/geyserupdater/common/update/PluginId.java index 14eeaf28..df352aff 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/PluginId.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/PluginId.java @@ -1,5 +1,7 @@ package com.projectg.geyserupdater.common.update; +import com.projectg.geyserupdater.common.GeyserUpdater; + public enum PluginId { GEYSER("https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/", "org.geysermc.connector.GeyserConnector"), FLOODGATE("https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/", "org.geysermc.floodgate.FloodgatePlatform"); @@ -12,10 +14,29 @@ public enum PluginId { /** * A class from the given plugin */ - public final String pluginClass; + public final String pluginClassName; - PluginId(String link, String pluginClass) { + PluginId(String link, String pluginClassName) { this.link = link; - this.pluginClass = pluginClass; + this.pluginClassName = pluginClassName; + } + + public Class getPluginClass() { + try { + return Class.forName(pluginClassName); + } catch (ClassNotFoundException e) { + throw new AssertionError("Failed to find Class '" + pluginClassName + "' for plugin: " + this.name() + ". Is the plugin loaded?"); + } + } + + public boolean isEnabled() { + if (this == GEYSER) { + return GeyserUpdater.getInstance().getConfig().isAutoUpdateGeyser(); + } else if (this == FLOODGATE) { + return GeyserUpdater.getInstance().getConfig().isAutoUpdateFloodgate(); + } else { + //todo fix this bs + return false; + } } } diff --git a/src/main/java/com/projectg/geyserupdater/common/update/Updatable.java b/src/main/java/com/projectg/geyserupdater/common/update/Updatable.java index 6bedf64e..4c1e8e81 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/Updatable.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/Updatable.java @@ -1,36 +1,16 @@ package com.projectg.geyserupdater.common.update; -import com.projectg.geyserupdater.common.util.WebUtils; +import com.projectg.geyserupdater.common.update.age.AgeComparer; -import java.io.IOException; +import javax.annotation.Nonnull; import java.util.Objects; public class Updatable { - private final String projectLink; - private final String branch; - private final int localBuildNumber; + private final AgeComparer ageComparer; - public Updatable(String artifactLink, PluginId pluginId) { - Objects.requireNonNull(artifactLink); - Objects.requireNonNull(pluginId); - - - - } - - - /** - * Compare the local build number to the latest build number on Geyser CI - * - * @return true if local build number equals latest build number on Geyser CI - * @throws IOException if it fails to fetch either build number - */ - public boolean isLatestBuild() throws IOException { - int jenkinsBuildNumber = WebUtils.getLatestGeyserBuildNumberFromJenkins(projectLink + "/" + branch); - // 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; + public Updatable(@Nonnull AgeComparer ageComparer) { + Objects.requireNonNull(ageComparer); + this.ageComparer = ageComparer; } } diff --git a/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java b/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java index 9acceb69..fa7b0f7a 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java @@ -1,29 +1,62 @@ package com.projectg.geyserupdater.common.update; import com.projectg.geyserupdater.common.GeyserUpdater; -import com.projectg.geyserupdater.common.config.UpdaterConfiguration; +import com.projectg.geyserupdater.common.logger.UpdaterLogger; +import com.projectg.geyserupdater.common.update.age.AgeComparer; +import com.projectg.geyserupdater.common.update.age.provider.JenkinsBuildProvider; +import com.projectg.geyserupdater.common.update.age.type.BuildNumber; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; -import java.util.Objects; import java.util.Properties; public class UpdateManager { - private List updatables = new ArrayList<>(); + private final List updatables = new ArrayList<>(); public UpdateManager(GeyserUpdater geyserUpdater) { - UpdaterConfiguration config = geyserUpdater.getConfig(); - boolean updateGeyser = config.isAutoUpdateGeyser(); - boolean updateFloodgate = config.isAutoUpdateFloodgate(); - - - - - - + UpdaterLogger logger = UpdaterLogger.getLogger(); + + for (PluginId pluginId : PluginId.values()) { + if (pluginId.isEnabled()) { + // Get the git.properties + InputStream is = pluginId.getPluginClass().getResourceAsStream("git.properties"); + if (is == null) { + throw new AssertionError("Unable to find resource 'git.properties' for plugin: " + pluginId.name()); + } + + Properties gitProperties = new Properties(); + try { + gitProperties.load(is); + is.close(); + } catch (IOException e) { + logger.error("Failed to get git.properties for plugin: " + pluginId.name() + ". Unable to update."); + e.printStackTrace(); + } + + String buildNumberString = gitProperties.getProperty("git.build.number"); + String branch = gitProperties.getProperty("git.branch"); + if (buildNumberString == null || branch == null) { + throw new AssertionError("Failed to find build number or branch in Git Properties '" + gitProperties + "' of plugin '" + pluginId.name() + "'"); + } + + BuildNumber buildNumber = new BuildNumber(Integer.parseInt(buildNumberString)); + JenkinsBuildProvider jenkins = new JenkinsBuildProvider(); + register(new Updatable(new AgeComparer<>(buildNumber, jenkins))); + } + } + + // Load extra stuff from the config if we wanted, I guess + } + /** + * Register an {@link Updatable} to be updated + * @param updatable The {@link Updatable} to be updated + * @return true, if it was registered. + */ + public boolean register(Updatable updatable) { + return updatables.add(updatable); } } diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/AgeComparer.java b/src/main/java/com/projectg/geyserupdater/common/update/age/AgeComparer.java new file mode 100644 index 00000000..b1679242 --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/update/age/AgeComparer.java @@ -0,0 +1,51 @@ +package com.projectg.geyserupdater.common.update.age; + +import com.projectg.geyserupdater.common.update.age.provider.AgeProvider; +import com.projectg.geyserupdater.common.update.age.type.Age; + +import javax.annotation.Nonnull; +import java.util.Objects; + +/** + * @param The external {@link AgeProvider} implementation + * @param The {@link Age} implementation + */ +public class AgeComparer, S extends Age> { + + S localAge; + T externalAgeProvider; + + /** + * Create an age comparer, which stores a local age and way to check an external age. Both params should provide the same {@link Age} implementation. + * @param localAgeProvider The local age provider. {@link AgeProvider#getAge()} will be called once and stored forever. + * @param externalAgeProvider The external age provider. {@link AgeProvider#getAge()} will be called every time {@link AgeComparer#checkIfOutdated()} is called. + */ + public > AgeComparer(@Nonnull U localAgeProvider, @Nonnull T externalAgeProvider) { + Objects.requireNonNull(localAgeProvider); + Objects.requireNonNull(externalAgeProvider); + + this.localAge = localAgeProvider.getAge(); + this.externalAgeProvider = externalAgeProvider; + } + + /** + * Create an age comparer, which stores a local age and way to check an external age + * @param localAge The local age. + * @param externalAgeProvider The external age provider. {@link AgeProvider#getAge()} will be called every time {@link AgeComparer#checkIfOutdated()} is called. + */ + public AgeComparer(@Nonnull S localAge, @Nonnull T externalAgeProvider) { + Objects.requireNonNull(localAge); + Objects.requireNonNull(externalAgeProvider); + + this.localAge = localAge; + this.externalAgeProvider = externalAgeProvider; + } + + /** + * Request the {@link Age} from the external {@link AgeProvider} and compare it to the stored local {@link Age}. + * @return True if the local age {@link Object#equals(Object)} the external age + */ + public boolean checkIfOutdated() { + return localAge.value().equals(externalAgeProvider.getAge()); + } +} diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/provider/AgeProvider.java b/src/main/java/com/projectg/geyserupdater/common/update/age/provider/AgeProvider.java new file mode 100644 index 00000000..8ceed5db --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/update/age/provider/AgeProvider.java @@ -0,0 +1,8 @@ +package com.projectg.geyserupdater.common.update.age.provider; + +import com.projectg.geyserupdater.common.update.age.type.Age; + +public interface AgeProvider> { + + S getAge(); +} diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/provider/JenkinsBuildProvider.java b/src/main/java/com/projectg/geyserupdater/common/update/age/provider/JenkinsBuildProvider.java new file mode 100644 index 00000000..1bde9e97 --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/update/age/provider/JenkinsBuildProvider.java @@ -0,0 +1,15 @@ +package com.projectg.geyserupdater.common.update.age.provider; + +import com.projectg.geyserupdater.common.update.age.type.BuildNumber; + +public class JenkinsBuildProvider implements AgeProvider{ + + public JenkinsBuildProvider() { + //todo finish this + } + + @Override + public BuildNumber getAge() { + return null; + } +} diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/type/Age.java b/src/main/java/com/projectg/geyserupdater/common/update/age/type/Age.java new file mode 100644 index 00000000..98d7c761 --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/update/age/type/Age.java @@ -0,0 +1,10 @@ +package com.projectg.geyserupdater.common.update.age.type; + +/** + * Provides implementation for something that can be quantified as an age of something. + * @param The Type of the age. + */ +public interface Age { + + T value(); +} diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/type/BuildNumber.java b/src/main/java/com/projectg/geyserupdater/common/update/age/type/BuildNumber.java new file mode 100644 index 00000000..26b77e3f --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/update/age/type/BuildNumber.java @@ -0,0 +1,15 @@ +package com.projectg.geyserupdater.common.update.age.type; + +public class BuildNumber implements Age { + + private final int buildNumber; + + public BuildNumber(int buildNumber) { + this.buildNumber = buildNumber; + } + + @Override + public Integer value() { + return buildNumber; + } +} From cf13093f4711777d7874164ef45eb40ac9a01a13 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Thu, 5 Aug 2021 23:52:57 -0400 Subject: [PATCH 10/42] implement DownloadManager and finish Updatable Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../geyserupdater/common/GeyserUpdater.java | 13 ++- .../common/update/DownloadManager.java | 40 +++++++++ .../geyserupdater/common/update/PluginId.java | 36 +++++++- .../common/update/Updatable.java | 42 +++++++++- .../common/update/UpdateManager.java | 52 +++++++++--- .../common/update/age/AgeComparer.java | 6 +- .../geyserupdater/common/util/FileUtils.java | 82 +------------------ .../geyserupdater/common/util/WebUtils.java | 11 +-- .../velocity/VelocityUpdater.java | 1 + 9 files changed, 178 insertions(+), 105 deletions(-) create mode 100644 src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java diff --git a/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java b/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java index 36940633..d79b702d 100644 --- a/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java +++ b/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java @@ -3,6 +3,7 @@ import com.projectg.geyserupdater.common.config.UpdaterConfiguration; import com.projectg.geyserupdater.common.logger.UpdaterLogger; import com.projectg.geyserupdater.common.scheduler.UpdaterScheduler; +import com.projectg.geyserupdater.common.update.DownloadManager; import com.projectg.geyserupdater.common.update.PluginId; import com.projectg.geyserupdater.common.update.UpdateManager; import com.projectg.geyserupdater.common.util.FileUtils; @@ -22,9 +23,10 @@ public class GeyserUpdater { private final PlayerHandler playerHandler; public final String version; - private UpdaterConfiguration config; + private final UpdaterConfiguration config; public GeyserUpdater(Path dataFolder, + Path downloadFolder, UpdaterLogger logger, UpdaterScheduler scheduler, PlayerHandler playerHandler, @@ -56,7 +58,7 @@ public GeyserUpdater(Path dataFolder, // Load the config logger.debug("Loading config"); - UpdaterConfiguration config = FileUtils.loadConfig(dataFolder.resolve("config.yml")); //todo will this resolve work? + config = FileUtils.loadConfig(dataFolder.resolve("config.yml")); if (config.isIncorrectVersion()) { logger.error("Your copy of config.yml is outdated (your version: " + config.getConfigVersion() + ", latest version: " + UpdaterConfiguration.DEFAULT_CONFIG_VERSION + "). Please delete it and let a fresh copy of config.yml be regenerated!"); return; @@ -79,9 +81,14 @@ public GeyserUpdater(Path dataFolder, e.printStackTrace(); } } - } + // Set the correct download links for geyser and floodgate + PluginId.GEYSER.setArtifact(geyserArtifact); + PluginId.FLOODGATE.setArtifact(floodgateArtifact); + // Manager for updating plugins + UpdateManager updateManager = new UpdateManager(new DownloadManager(downloadFolder)); + } public static GeyserUpdater getInstance() { return INSTANCE; diff --git a/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java b/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java new file mode 100644 index 00000000..f28e56f6 --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java @@ -0,0 +1,40 @@ +package com.projectg.geyserupdater.common.update; + +import com.projectg.geyserupdater.common.util.WebUtils; + +import javax.annotation.Nonnull; +import java.nio.file.Path; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; + +public class DownloadManager { + + private final List queue = new LinkedList<>(); + private final Path outputDirectory; + + private boolean isDownloading = false; + + public DownloadManager(@Nonnull Path outputDirectory) { + this.outputDirectory = Objects.requireNonNull(outputDirectory); + } + + public void queue(Updatable updatable) { + queue.add(updatable); + check(); + } + + private void download(Updatable updatable) { + isDownloading = true; + WebUtils.downloadFile(updatable.downloadUrl, outputDirectory.resolve(updatable.outputFileName)); + queue.remove(updatable); + isDownloading = false; + check(); + } + + private void check() { + if (!queue.isEmpty() && !isDownloading) { + download(queue.get(0)); + } + } +} diff --git a/src/main/java/com/projectg/geyserupdater/common/update/PluginId.java b/src/main/java/com/projectg/geyserupdater/common/update/PluginId.java index df352aff..6a88da2c 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/PluginId.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/PluginId.java @@ -9,18 +9,45 @@ public enum PluginId { /** * https://ci.opencollab.dev/job/GeyserMC/job/{PLUGIN_PAGE}/job/ */ - public final String link; + private final String projectLink; + + private String branch; + private String artifactLink; /** * A class from the given plugin */ - public final String pluginClassName; + private final String pluginClassName; PluginId(String link, String pluginClassName) { - this.link = link; + this.projectLink = link; this.pluginClassName = pluginClassName; } + /** + * @return The download link. Not usable if {@link PluginId#setArtifact(String)} has not been called. + */ + public String getLatestFileLink() { + return projectLink + branch + "/lastSuccessfulBuild/" + artifactLink; + } + + /** + * @param branch The branch to be used for {@link PluginId#getLatestFileLink()} + */ + public void setBranch(String branch) { + this.branch = branch; + } + + /** + * @param artifactLink The artifact link. `artifact/bootstrap/spigot/target/Geyser-Spigot.jar` for example. + */ + public void setArtifact(String artifactLink) { + this.artifactLink = artifactLink; + } + + /** + * @return A class from the plugin. Will throw an {@link AssertionError} if the class is not available, i.e. the plugin is not loaded. + */ public Class getPluginClass() { try { return Class.forName(pluginClassName); @@ -29,6 +56,9 @@ public Class getPluginClass() { } } + /** + * @return True if the plugin is enabled in {@link com.projectg.geyserupdater.common.config.UpdaterConfiguration} + */ public boolean isEnabled() { if (this == GEYSER) { return GeyserUpdater.getInstance().getConfig().isAutoUpdateGeyser(); diff --git a/src/main/java/com/projectg/geyserupdater/common/update/Updatable.java b/src/main/java/com/projectg/geyserupdater/common/update/Updatable.java index 4c1e8e81..48a67d3c 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/Updatable.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/Updatable.java @@ -3,14 +3,52 @@ import com.projectg.geyserupdater.common.update.age.AgeComparer; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.Objects; public class Updatable { - private final AgeComparer ageComparer; + @Nonnull public final String pluginIdentity; + @Nonnull public final AgeComparer ageComparer; + @Nonnull public final String downloadUrl; + @Nonnull public final String outputFileName; - public Updatable(@Nonnull AgeComparer ageComparer) { + /** + * @param pluginIdentity The plugin name, which can be used to identify the plugin. + * @param ageComparer The age comparer to check if the plugin is outdated + * @param downloadUrl The complete download link of the plugin + * @param outputFileName The output file name. May be null to attempt to use the file name that the downloadUrl provides. + */ + public Updatable(@Nonnull String pluginIdentity, @Nonnull AgeComparer ageComparer, @Nonnull String downloadUrl, @Nullable String outputFileName) { + Objects.requireNonNull(pluginIdentity); Objects.requireNonNull(ageComparer); + Objects.requireNonNull(downloadUrl); + + this.pluginIdentity = pluginIdentity; this.ageComparer = ageComparer; + + // Remove / from the end of the link if necessary + if (downloadUrl.endsWith("/")) { + this.downloadUrl = downloadUrl.substring(0, downloadUrl.length() - 1); + } else { + this.downloadUrl = downloadUrl; + } + + // Make sure the file linked is a jar + if (!downloadUrl.endsWith(".jar")) { + throw new IllegalArgumentException("Download URL provided for plugin '" + pluginIdentity + "' must direct to a file that ends in '.jar'"); + } + + // Figure out the output file name if necessary + if (outputFileName == null) { + this.outputFileName = downloadUrl.substring(downloadUrl.lastIndexOf("/") + 1); + } else { + this.outputFileName = outputFileName; + } + } + + @Override + public String toString() { + return pluginIdentity; } } diff --git a/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java b/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java index fa7b0f7a..31cc2ada 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java @@ -1,6 +1,5 @@ package com.projectg.geyserupdater.common.update; -import com.projectg.geyserupdater.common.GeyserUpdater; import com.projectg.geyserupdater.common.logger.UpdaterLogger; import com.projectg.geyserupdater.common.update.age.AgeComparer; import com.projectg.geyserupdater.common.update.age.provider.JenkinsBuildProvider; @@ -8,15 +7,27 @@ import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; +import java.util.*; public class UpdateManager { - private final List updatables = new ArrayList<>(); + /** + * The {@link DownloadManager} to use for downloading new versions of plugins. + */ + private final DownloadManager downloadManager; + + /** + * All tracked plugins + */ + private final Set updatables = new HashSet<>(); + + /** + * Plugins that are outdated and must be updated + */ + private Set outdatedPlugins = new HashSet<>(); - public UpdateManager(GeyserUpdater geyserUpdater) { + public UpdateManager(DownloadManager downloadManager) { + this.downloadManager = downloadManager; UpdaterLogger logger = UpdaterLogger.getLogger(); for (PluginId pluginId : PluginId.values()) { @@ -44,7 +55,11 @@ public UpdateManager(GeyserUpdater geyserUpdater) { BuildNumber buildNumber = new BuildNumber(Integer.parseInt(buildNumberString)); JenkinsBuildProvider jenkins = new JenkinsBuildProvider(); - register(new Updatable(new AgeComparer<>(buildNumber, jenkins))); + register(new Updatable( + pluginId.name(), + new AgeComparer<>(buildNumber, jenkins), + pluginId.getLatestFileLink(), + null)); } } @@ -54,9 +69,26 @@ public UpdateManager(GeyserUpdater geyserUpdater) { /** * Register an {@link Updatable} to be updated * @param updatable The {@link Updatable} to be updated - * @return true, if it was registered. */ - public boolean register(Updatable updatable) { - return updatables.add(updatable); + public void register(Updatable updatable) { + updatables.add(updatable); + } + + public void checkAll() { + outdatedPlugins = new HashSet<>(); + for (Updatable updatable : updatables) { + // todo: make sure we don't run this sync... maybe instantiate GeyserUpdater.class async? + if (!updatable.ageComparer.checkIfEquals()) { + outdatedPlugins.add(updatable); + } + } + + UpdaterLogger.getLogger().info("Updates required for plugins: " + outdatedPlugins); + } + + public void updateAll() { + for (Updatable updatable : outdatedPlugins) { + downloadManager.queue(updatable); + } } } diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/AgeComparer.java b/src/main/java/com/projectg/geyserupdater/common/update/age/AgeComparer.java index b1679242..11b51e5c 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/age/AgeComparer.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/age/AgeComparer.java @@ -18,7 +18,7 @@ public class AgeComparer, S extends Age> { /** * Create an age comparer, which stores a local age and way to check an external age. Both params should provide the same {@link Age} implementation. * @param localAgeProvider The local age provider. {@link AgeProvider#getAge()} will be called once and stored forever. - * @param externalAgeProvider The external age provider. {@link AgeProvider#getAge()} will be called every time {@link AgeComparer#checkIfOutdated()} is called. + * @param externalAgeProvider The external age provider. {@link AgeProvider#getAge()} will be called every time {@link AgeComparer#checkIfEquals()} is called. */ public > AgeComparer(@Nonnull U localAgeProvider, @Nonnull T externalAgeProvider) { Objects.requireNonNull(localAgeProvider); @@ -31,7 +31,7 @@ public > AgeComparer(@Nonnull U localAgeProvider, @Nonn /** * Create an age comparer, which stores a local age and way to check an external age * @param localAge The local age. - * @param externalAgeProvider The external age provider. {@link AgeProvider#getAge()} will be called every time {@link AgeComparer#checkIfOutdated()} is called. + * @param externalAgeProvider The external age provider. {@link AgeProvider#getAge()} will be called every time {@link AgeComparer#checkIfEquals()} is called. */ public AgeComparer(@Nonnull S localAge, @Nonnull T externalAgeProvider) { Objects.requireNonNull(localAge); @@ -45,7 +45,7 @@ public AgeComparer(@Nonnull S localAge, @Nonnull T externalAgeProvider) { * Request the {@link Age} from the external {@link AgeProvider} and compare it to the stored local {@link Age}. * @return True if the local age {@link Object#equals(Object)} the external age */ - public boolean checkIfOutdated() { + public boolean checkIfEquals() { return localAge.value().equals(externalAgeProvider.getAge()); } } 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 f0829848..2151062e 100644 --- a/src/main/java/com/projectg/geyserupdater/common/util/FileUtils.java +++ b/src/main/java/com/projectg/geyserupdater/common/util/FileUtils.java @@ -3,94 +3,18 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import com.projectg.geyserupdater.common.config.UpdaterConfiguration; -import com.projectg.geyserupdater.common.logger.UpdaterLogger; -import java.io.*; -import java.net.URL; -import java.net.URLConnection; +import java.io.IOException; +import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Objects; 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. - */ - private static long callTime = 0; - - /** - * Returns a cached result of {@link #checkFile(String, boolean)}. Returns null if the method has never been called. - */ - private static boolean cachedResult; - - /** - * Check if a file exists. - * - * @param path the path of the file to test - * @param allowCached allow a cached result of maximum 30 minutes to be returned - * @return true if the file exists, false if not - */ - public static boolean checkFile(String path, boolean allowCached) { - UpdaterLogger logger = UpdaterLogger.getLogger(); - if (allowCached) { - long elapsedTime = System.currentTimeMillis() - callTime; - if (elapsedTime < 30 * 60 * 1000) { - logger.debug("Returning a cached result of the last time we checked if a file exists. The cached result is: " + cachedResult); - return cachedResult; - } else { - logger.debug("Not returning a cached result of the last time we checked if a file exists because it has been too long."); - } - } - Path p = Paths.get(path); - boolean exists = Files.exists(p); - - logger.debug("Checked if a file exists. The result: " + exists); - callTime = System.currentTimeMillis(); - cachedResult = exists; - return exists; - } - - /** - * Download a file - * - * @param fileURL the url of the file - * @param outputPath the path of the output file to write to - */ - 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); - - Path outputDirectory = Paths.get(outputPath).getParent(); - Files.createDirectories(outputDirectory); - - OutputStream os; - InputStream is; - // create a url object - 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); - } - // close streams - is.close(); - os.close(); - } public static UpdaterConfiguration loadConfig(Path userConfig) throws IOException { if (!Files.exists(userConfig)) { - //Files.createDirectories(userConfig.getParent()); todo: necessary? + Files.createDirectories(userConfig.getParent()); try (InputStream inputStream = FileUtils.class.getResourceAsStream("/config.yml")) { Objects.requireNonNull(inputStream); Files.copy(inputStream, userConfig); diff --git a/src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java b/src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java index 359af27d..d7ebbbe1 100644 --- a/src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java +++ b/src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java @@ -10,7 +10,7 @@ import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.nio.file.Files; -import java.nio.file.Paths; +import java.nio.file.Path; import java.nio.file.StandardCopyOption; // Full credit to GeyserMC @@ -55,13 +55,14 @@ public static JsonNode getJson(String reqURL) throws IOException { * @param reqURL File to fetch * @param fileLocation Location to save on disk */ - public static void downloadFile(String reqURL, String fileLocation) { + public static void downloadFile(String reqURL, Path fileLocation) { try { HttpURLConnection con = (HttpURLConnection) new URL(reqURL).openConnection(); con.setRequestProperty("User-Agent", "GeyserUpdater-" + GeyserUpdater.getInstance().version); InputStream in = con.getInputStream(); - Files.copy(in, Paths.get(fileLocation), StandardCopyOption.REPLACE_EXISTING); - // todo: need to close stuff? + Files.copy(in, fileLocation, StandardCopyOption.REPLACE_EXISTING); + // todo: need to close the inputstream or not? + in.close(); } catch (Exception e) { throw new AssertionError("Unable to download and save file: " + fileLocation + " (" + reqURL + ")", e); } @@ -101,7 +102,7 @@ private static String connectionToString(HttpURLConnection con) throws IOExcepti /** Get the latest build number of a given branch of Geyser from jenkins CI * - * @param gitBranch the branch to query + * @param branchLink Example: https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/master * @return the latest build number * @throws UnsupportedEncodingException if failed to encode the given gitBranch */ diff --git a/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java b/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java index 09669335..19b36f27 100644 --- a/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java +++ b/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java @@ -46,6 +46,7 @@ public VelocityUpdater(ProxyServer server, Logger baseLogger, @DataDirectory fin new GeyserUpdater( dataDirectory, + dataDirectory.resolve("BuildUpdate"), new Slf4jUpdaterLogger(baseLogger), new VelocityScheduler(this), new VelocityPlayerHandler(server), From e7f5a1a07e6ab1c939690874d61d3cc8308695c2 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Mon, 9 Aug 2021 22:58:40 -0400 Subject: [PATCH 11/42] add a hang checker to DownloadManager, implement cancellable tasks, refactor config a bit Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../geyserupdater/bungee/BungeeScheduler.java | 19 ++++- .../geyserupdater/common/GeyserUpdater.java | 2 +- .../common/config/UpdaterConfiguration.java | 23 ++++-- .../geyserupdater/common/scheduler/Task.java | 6 ++ .../common/scheduler/UpdaterScheduler.java | 21 ++--- .../common/update/DownloadManager.java | 79 ++++++++++++++++--- .../geyserupdater/spigot/SpigotScheduler.java | 28 +++++-- .../velocity/VelocityScheduler.java | 21 ++++- src/main/resources/config.yml | 19 +++-- 9 files changed, 172 insertions(+), 46 deletions(-) create mode 100644 src/main/java/com/projectg/geyserupdater/common/scheduler/Task.java diff --git a/src/main/java/com/projectg/geyserupdater/bungee/BungeeScheduler.java b/src/main/java/com/projectg/geyserupdater/bungee/BungeeScheduler.java index c07e8136..3f2c9177 100644 --- a/src/main/java/com/projectg/geyserupdater/bungee/BungeeScheduler.java +++ b/src/main/java/com/projectg/geyserupdater/bungee/BungeeScheduler.java @@ -1,7 +1,9 @@ package com.projectg.geyserupdater.bungee; +import com.projectg.geyserupdater.common.scheduler.Task; import com.projectg.geyserupdater.common.scheduler.UpdaterScheduler; import net.md_5.bungee.api.plugin.Plugin; +import net.md_5.bungee.api.scheduler.ScheduledTask; import org.jetbrains.annotations.NotNull; import javax.annotation.Nonnull; @@ -18,11 +20,24 @@ public BungeeScheduler(@Nonnull Plugin plugin) { } @Override - public void schedule(@NotNull Runnable runnable, boolean async, long delay, long repeat, TimeUnit unit) { + public Task schedule(@NotNull Runnable runnable, boolean async, long delay, long repeat, TimeUnit unit) { // https://github.com/SpigotMC/BungeeCord/blob/master/proxy/src/main/java/net/md_5/bungee/scheduler/BungeeTask.java Objects.requireNonNull(runnable); - plugin.getProxy().getScheduler().schedule(plugin, runnable, delay, repeat, unit); + return new BungeeTask(plugin.getProxy().getScheduler().schedule(plugin, runnable, delay, repeat, unit)); + } + + private static class BungeeTask implements Task { + private final ScheduledTask task; + + public BungeeTask(ScheduledTask task) { + this.task = task; + } + + @Override + public void cancel() { + task.cancel(); + } } } diff --git a/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java b/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java index d79b702d..dac5b5d1 100644 --- a/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java +++ b/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java @@ -87,7 +87,7 @@ public GeyserUpdater(Path dataFolder, PluginId.FLOODGATE.setArtifact(floodgateArtifact); // Manager for updating plugins - UpdateManager updateManager = new UpdateManager(new DownloadManager(downloadFolder)); + UpdateManager updateManager = new UpdateManager(new DownloadManager(this, downloadFolder)); } public static GeyserUpdater getInstance() { diff --git a/src/main/java/com/projectg/geyserupdater/common/config/UpdaterConfiguration.java b/src/main/java/com/projectg/geyserupdater/common/config/UpdaterConfiguration.java index 0934aaca..09075583 100644 --- a/src/main/java/com/projectg/geyserupdater/common/config/UpdaterConfiguration.java +++ b/src/main/java/com/projectg/geyserupdater/common/config/UpdaterConfiguration.java @@ -1,38 +1,41 @@ package com.projectg.geyserupdater.common.config; +import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @JsonIgnoreProperties(ignoreUnknown = true) +@JsonFormat(with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES) +@SuppressWarnings("FieldMayBeFinal") // Must be non-final for Jackson to work public class UpdaterConfiguration { public static int DEFAULT_CONFIG_VERSION = 2; - @JsonProperty(value = "Auto-Update-Geyser", required = true) + @JsonProperty(value = "Auto-Update-Geyser") private boolean autoUpdateGeyser = false; public boolean isAutoUpdateGeyser() { return autoUpdateGeyser; } - @JsonProperty(value = "Auto-Update-Floodgate", required = true) + @JsonProperty(value = "Auto-Update-Floodgate") private boolean autoUpdateFloodgate = false; public boolean isAutoUpdateFloodgate() { return autoUpdateFloodgate; } - @JsonProperty(value = "Auto-Update-Interval", required = true) + @JsonProperty(value = "Auto-Update-Interval") private int autoUpdateInterval = 24; public int getAutoUpdateInterval() { return autoUpdateInterval; } - @JsonProperty(value = "Auto-Restart-Server", required = true) + @JsonProperty(value = "Auto-Restart-Server") private boolean restartServer = false; public boolean isRestartServer() { return restartServer; } - @JsonProperty(value = "Auto-Script-Generating", required = true) + @JsonProperty(value = "Auto-Script-Generating") private boolean generateRestartScript = false; public boolean isGenerateRestartScript() { return generateRestartScript; @@ -41,13 +44,19 @@ public void setGenerateRestartScript(boolean generate) { generateRestartScript = generate; } - @JsonProperty(value = "Restart-Message-Players", required = true) + @JsonProperty(value = "Restart-Message-Players") private String restartMessage = "§2This server will be restarting in 10 seconds!"; public String getRestartMessage() { return restartMessage; } - @JsonProperty(value = "Enable-Debug", required = true) + @JsonProperty(value = "download-time-limit") + private int downloadTimeLimit = 180; + public int getDownloadTimeLimit() { + return downloadTimeLimit; + } + + @JsonProperty(value = "Enable-Debug") private boolean enableDebug = false; public boolean isEnableDebug() { return enableDebug; diff --git a/src/main/java/com/projectg/geyserupdater/common/scheduler/Task.java b/src/main/java/com/projectg/geyserupdater/common/scheduler/Task.java new file mode 100644 index 00000000..e98d59ee --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/scheduler/Task.java @@ -0,0 +1,6 @@ +package com.projectg.geyserupdater.common.scheduler; + +public interface Task { + + void cancel(); +} diff --git a/src/main/java/com/projectg/geyserupdater/common/scheduler/UpdaterScheduler.java b/src/main/java/com/projectg/geyserupdater/common/scheduler/UpdaterScheduler.java index eadc84e2..3f414dde 100644 --- a/src/main/java/com/projectg/geyserupdater/common/scheduler/UpdaterScheduler.java +++ b/src/main/java/com/projectg/geyserupdater/common/scheduler/UpdaterScheduler.java @@ -6,9 +6,14 @@ public interface UpdaterScheduler { - default void run(@Nonnull Runnable runnable, boolean async) { + /** + * Schedule a Runnable to be run. + * @param runnable The Runnable + * @param async True to run the task async (Disregarded for BungeeCord, Velocity) + */ + default Task run(@Nonnull Runnable runnable, boolean async) { Objects.requireNonNull(runnable); - schedule(runnable, async, 0, 0, TimeUnit.MILLISECONDS); + return schedule(runnable, async, 0, 0, TimeUnit.MILLISECONDS); } /** @@ -17,9 +22,9 @@ default void run(@Nonnull Runnable runnable, boolean async) { * @param async True to run the task async (Disregarded for BungeeCord, Velocity) * @param delay The delay in milliseconds. A value less than zero should be considered unsafe. */ - default void runDelayed(@Nonnull Runnable runnable, boolean async, long delay, TimeUnit unit) { + default Task runDelayed(@Nonnull Runnable runnable, boolean async, long delay, TimeUnit unit) { Objects.requireNonNull(runnable); - schedule(runnable, async, delay, 0, unit); + return schedule(runnable, async, delay, 0, unit); } /** @@ -28,9 +33,9 @@ default void runDelayed(@Nonnull Runnable runnable, boolean async, long delay, T * @param async True to run the task async (Disregarded for BungeeCord, Velocity) * @param repeat The repeat period, in milliseconds. A value of 0 or less will only run the Runnable once. A value less than zero should be considered unsafe. */ - default void runTimer(@Nonnull Runnable runnable, boolean async, long repeat, TimeUnit unit) { + default Task runTimer(@Nonnull Runnable runnable, boolean async, long repeat, TimeUnit unit) { Objects.requireNonNull(runnable); - schedule(runnable, async, 0, repeat, unit); + return schedule(runnable, async, 0, repeat, unit); } /** @@ -40,9 +45,7 @@ default void runTimer(@Nonnull Runnable runnable, boolean async, long repeat, Ti * @param delay The delay in milliseconds. A value less than zero should be considered unsafe. * @param repeat The repeat period, in milliseconds. A value of 0 or less will only run the Runnable once. A value less than zero should be considered unsafe. */ - void schedule(@Nonnull Runnable runnable, boolean async, long delay, long repeat, TimeUnit unit); - // todo: make sure that repeat of 0 is handled properly on all platforms - + Task schedule(@Nonnull Runnable runnable, boolean async, long delay, long repeat, TimeUnit unit); } diff --git a/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java b/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java index f28e56f6..2a79a606 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java @@ -1,40 +1,97 @@ package com.projectg.geyserupdater.common.update; +import com.projectg.geyserupdater.common.GeyserUpdater; +import com.projectg.geyserupdater.common.logger.UpdaterLogger; +import com.projectg.geyserupdater.common.scheduler.Task; +import com.projectg.geyserupdater.common.scheduler.UpdaterScheduler; import com.projectg.geyserupdater.common.util.WebUtils; -import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.nio.file.Path; import java.util.LinkedList; import java.util.List; -import java.util.Objects; +import java.util.concurrent.TimeUnit; public class DownloadManager { - private final List queue = new LinkedList<>(); + private final GeyserUpdater updater; private final Path outputDirectory; + private final List queue = new LinkedList<>(); + + // Used for making sure one download is ever running private boolean isDownloading = false; - public DownloadManager(@Nonnull Path outputDirectory) { - this.outputDirectory = Objects.requireNonNull(outputDirectory); + // Used by the hang checker to check if the current download is the same as when it was scheduled + @Nullable private Updatable currentUpdate = null; + + // Used by the hang checker to cancel the download if necessary + @Nullable private Task downloader = null; + + // todo: maybe refactor this to use a for loop instead of being recursive? i dunno + + public DownloadManager(GeyserUpdater updater, Path outputDirectory) { + //todo: move outputDirectory to Updatable + this.updater = updater; + this.outputDirectory = outputDirectory; } public void queue(Updatable updatable) { queue.add(updatable); - check(); + downloadIfPossible(); } private void download(Updatable updatable) { isDownloading = true; - WebUtils.downloadFile(updatable.downloadUrl, outputDirectory.resolve(updatable.outputFileName)); - queue.remove(updatable); - isDownloading = false; - check(); + currentUpdate = updatable; + + UpdaterScheduler scheduler = updater.getScheduler(); + + // Run the download on a new thread + this.downloader = scheduler.run(() -> { + + // Create a timer to stop this download from running too long. Either the hang checker is cancelled or the hang checker cancels this. + Task hangChecker = scheduleHangChecker(updater, updatable); + + WebUtils.downloadFile(updatable.downloadUrl, outputDirectory.resolve(updatable.outputFileName)); + hangChecker.cancel(); + + // Revert everything while having it locked so that the state is always correctly read by original thread + synchronized (this) { + this.queue.remove(updatable); + this.isDownloading = false; + this.currentUpdate = null; + this.downloader = null; + } + + // Initiate another download if necessary + downloadIfPossible(); + }, true); } - private void check() { + private void downloadIfPossible() { if (!queue.isEmpty() && !isDownloading) { download(queue.get(0)); } } + + private Task scheduleHangChecker(GeyserUpdater updater, Updatable updatable) { + // The time to allow the download to take, in seconds + int downloadTimeLimit = updater.getConfig().getDownloadTimeLimit(); + + return updater.getScheduler().runDelayed(() -> { + if (isDownloading && downloader != null && this.currentUpdate == updatable) { + // Revert everything while having it locked so that the state is always correctly read by original thread + synchronized (this) { + isDownloading = false; + currentUpdate = null; + downloader.cancel(); + downloader = null; + } + + UpdaterLogger.getLogger().error("The download queue has been stopped because the download for " + updatable + " took longer than " + downloadTimeLimit + + " seconds. Increase the download-time-limit in the config if you have a slow internet connection."); + } + }, true, downloadTimeLimit, TimeUnit.SECONDS); + } } diff --git a/src/main/java/com/projectg/geyserupdater/spigot/SpigotScheduler.java b/src/main/java/com/projectg/geyserupdater/spigot/SpigotScheduler.java index 690282ee..bfcc2fe6 100644 --- a/src/main/java/com/projectg/geyserupdater/spigot/SpigotScheduler.java +++ b/src/main/java/com/projectg/geyserupdater/spigot/SpigotScheduler.java @@ -1,8 +1,10 @@ package com.projectg.geyserupdater.spigot; +import com.projectg.geyserupdater.common.scheduler.Task; import com.projectg.geyserupdater.common.scheduler.UpdaterScheduler; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitScheduler; +import org.bukkit.scheduler.BukkitTask; import org.jetbrains.annotations.NotNull; import javax.annotation.Nonnull; @@ -19,25 +21,41 @@ public SpigotScheduler(@Nonnull JavaPlugin plugin) { } @Override - public void schedule(@NotNull Runnable runnable, boolean async, long delay, long repeat, TimeUnit unit) { + public Task schedule(@NotNull Runnable runnable, boolean async, long delay, long repeat, TimeUnit unit) { // https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/browse/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java // https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/browse/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java Objects.requireNonNull(runnable); BukkitScheduler scheduler = plugin.getServer().getScheduler(); + + BukkitTask bukkitTask; if (repeat <= 0) { if (async) { - scheduler.runTaskLaterAsynchronously(plugin, runnable, unit.toSeconds(delay) * 20); // 20 ticks in a second + bukkitTask = scheduler.runTaskLaterAsynchronously(plugin, runnable, unit.toSeconds(delay) * 20); // 20 ticks in a second } else { - scheduler.runTaskLater(plugin, runnable, unit.toSeconds(delay) * 20); + bukkitTask = scheduler.runTaskLater(plugin, runnable, unit.toSeconds(delay) * 20); } } else { if (async) { - scheduler.runTaskTimerAsynchronously(plugin, runnable, unit.toSeconds(delay) * 20, unit.toSeconds(repeat) * 20); + bukkitTask = scheduler.runTaskTimerAsynchronously(plugin, runnable, unit.toSeconds(delay) * 20, unit.toSeconds(repeat) * 20); } else { - scheduler.runTaskTimer(plugin, runnable, unit.toSeconds(delay) * 20, unit.toSeconds(repeat) * 20); + bukkitTask = scheduler.runTaskTimer(plugin, runnable, unit.toSeconds(delay) * 20, unit.toSeconds(repeat) * 20); } } + return new SpigotTask(bukkitTask); + } + + private static class SpigotTask implements Task { + private final BukkitTask task; + + private SpigotTask(BukkitTask task) { + this.task = task; + } + + @Override + public void cancel() { + task.cancel(); + } } } diff --git a/src/main/java/com/projectg/geyserupdater/velocity/VelocityScheduler.java b/src/main/java/com/projectg/geyserupdater/velocity/VelocityScheduler.java index 08abf043..0fd6bff2 100644 --- a/src/main/java/com/projectg/geyserupdater/velocity/VelocityScheduler.java +++ b/src/main/java/com/projectg/geyserupdater/velocity/VelocityScheduler.java @@ -1,6 +1,8 @@ package com.projectg.geyserupdater.velocity; +import com.projectg.geyserupdater.common.scheduler.Task; import com.projectg.geyserupdater.common.scheduler.UpdaterScheduler; +import com.velocitypowered.api.scheduler.ScheduledTask; import javax.annotation.Nonnull; import java.util.Objects; @@ -16,15 +18,28 @@ public VelocityScheduler(@Nonnull VelocityUpdater plugin) { } @Override - public void schedule(@Nonnull Runnable runnable, boolean async, long delay, long repeat, @Nonnull TimeUnit unit) { + public Task schedule(@Nonnull Runnable runnable, boolean async, long delay, long repeat, @Nonnull TimeUnit unit) { // https://github.com/VelocityPowered/Velocity/blob/dev/3.0.0/proxy/src/main/java/com/velocitypowered/proxy/scheduler/VelocityScheduler.java Objects.requireNonNull(runnable); Objects.requireNonNull(unit); - this.plugin.getProxyServer().getScheduler().buildTask(plugin, runnable) + return new VelocityTask(plugin.getProxyServer().getScheduler().buildTask(plugin, runnable) .delay(delay, unit) .repeat(repeat, unit) - .schedule(); + .schedule()); + } + + private static class VelocityTask implements Task { + private final ScheduledTask task; + + private VelocityTask(ScheduledTask task) { + this.task = task; + } + + @Override + public void cancel() { + task.cancel(); + } } } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 756d5484..dbeb50e6 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -5,24 +5,27 @@ # https://github.com/ProjectG-Plugins/GeyserUpdater # If enabled, GeyserUpdater will check for new Geyser builds on server start, and on the interval specified by Auto-Update-Interval. If a new build exists, it will be downloaded. -Auto-Update-Geyser: false -Auto-Update-Floodgate: false +auto-update-geyser: false +auto-update-floodgate: false # The interval in hours between each auto update check. -Auto-Update-Interval: 24 +auto-update-interval: 24 # If enabled, GeyserUpdater will attempt to restart the server 10 seconds after a new version of Geyser has been successfully downloaded. # If you aren't using a hosting provider or a server wrapper, you will need a restart script. -Auto-Restart-Server: false +auto-restart-server: false # When enabled, GeyserUpdater will automatically generate a restart script for you. If you are using CraftBukkit or a proxy # you will need to use the generated script to start your server! If you are using a hosting provider or a server wrapper you probably don't need this. -Auto-Script-Generating: false +auto-script-generating: false # Configure the message that is sent to all online players warning them that the server will be restarting in 10 seconds. -Restart-Message-Players: "§2This server will be restarting in 10 seconds!" +restart-message-players: "§2This server will be restarting in 10 seconds!" + +# The maximum amount of seconds that a download is allowed to run for. Increase if you are running into issues on a slow internet connection. +download-time-limit: 180 # Enable debug logging -Enable-Debug: false +enable-debug: false # Please do not change this version value! -Config-Version: 2 \ No newline at end of file +config-version: 2 \ No newline at end of file From 5b188dc5853eb393fe175eaed444ec433e0b5977 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Tue, 10 Aug 2021 17:32:23 -0400 Subject: [PATCH 12/42] refactor download manager Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../common/update/DownloadManager.java | 68 +++++++---- .../update/RecursiveDownloadManager.java | 114 ++++++++++++++++++ 2 files changed, 157 insertions(+), 25 deletions(-) create mode 100644 src/main/java/com/projectg/geyserupdater/common/update/RecursiveDownloadManager.java diff --git a/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java b/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java index 2a79a606..28992438 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java @@ -7,6 +7,8 @@ import com.projectg.geyserupdater.common.util.WebUtils; import javax.annotation.Nullable; +import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import java.util.LinkedList; import java.util.List; @@ -28,8 +30,6 @@ public class DownloadManager { // Used by the hang checker to cancel the download if necessary @Nullable private Task downloader = null; - // todo: maybe refactor this to use a for loop instead of being recursive? i dunno - public DownloadManager(GeyserUpdater updater, Path outputDirectory) { //todo: move outputDirectory to Updatable this.updater = updater; @@ -38,59 +38,77 @@ public DownloadManager(GeyserUpdater updater, Path outputDirectory) { public void queue(Updatable updatable) { queue.add(updatable); - downloadIfPossible(); + if (!isDownloading) { + downloadAll(); + } } - private void download(Updatable updatable) { + private void downloadAll() { isDownloading = true; - currentUpdate = updatable; UpdaterScheduler scheduler = updater.getScheduler(); // Run the download on a new thread this.downloader = scheduler.run(() -> { - // Create a timer to stop this download from running too long. Either the hang checker is cancelled or the hang checker cancels this. - Task hangChecker = scheduleHangChecker(updater, updatable); + for (int i = 0; ; i++) { + Updatable updatable = queue.get(i); + if (updatable == null) { + break; + } + currentUpdate = updatable; - WebUtils.downloadFile(updatable.downloadUrl, outputDirectory.resolve(updatable.outputFileName)); - hangChecker.cancel(); + // Create a timer to stop this download from running too long. Either the hang checker is cancelled or the hang checker cancels this. + Task hangChecker = scheduleHangChecker(updater, updatable); - // Revert everything while having it locked so that the state is always correctly read by original thread + WebUtils.downloadFile(updatable.downloadUrl, outputDirectory.resolve(updatable.outputFileName)); + hangChecker.cancel(); + } + + // Revert everything while having it locked so that the state is always correctly read by a different thread synchronized (this) { - this.queue.remove(updatable); - this.isDownloading = false; - this.currentUpdate = null; - this.downloader = null; + queue.clear(); + isDownloading = false; + currentUpdate = null; + downloader = null; } - // Initiate another download if necessary - downloadIfPossible(); + // Everything should be downloaded now unless the queue was added to after the above for loop was finished + // But the synchronized block was not entered }, true); } - private void downloadIfPossible() { - if (!queue.isEmpty() && !isDownloading) { - download(queue.get(0)); - } - } - private Task scheduleHangChecker(GeyserUpdater updater, Updatable updatable) { // The time to allow the download to take, in seconds int downloadTimeLimit = updater.getConfig().getDownloadTimeLimit(); return updater.getScheduler().runDelayed(() -> { - if (isDownloading && downloader != null && this.currentUpdate == updatable) { - // Revert everything while having it locked so that the state is always correctly read by original thread + if (!isDownloading || downloader == null) { + throw new AssertionError("HangChecker should not execute while nothing is downloading."); + } + + if (updatable == currentUpdate) { + // Revert everything while having it locked so that the state is always correctly read by a different thread synchronized (this) { + queue.clear(); isDownloading = false; currentUpdate = null; downloader.cancel(); downloader = null; } - UpdaterLogger.getLogger().error("The download queue has been stopped because the download for " + updatable + " took longer than " + downloadTimeLimit + + UpdaterLogger logger = UpdaterLogger.getLogger(); + + logger.error("The download queue has been stopped and cleared because the download for " + updatable + " took longer than " + downloadTimeLimit + " seconds. Increase the download-time-limit in the config if you have a slow internet connection."); + + try { + boolean deletedFailedFile = Files.deleteIfExists(outputDirectory.resolve(updatable.outputFileName)); + logger.debug("Failed download for " + updatable + " had a file?: " + deletedFailedFile); + } catch (IOException e) { + logger.error("Failed to delete failed download file of " + updatable); + e.printStackTrace(); + } } }, true, downloadTimeLimit, TimeUnit.SECONDS); } diff --git a/src/main/java/com/projectg/geyserupdater/common/update/RecursiveDownloadManager.java b/src/main/java/com/projectg/geyserupdater/common/update/RecursiveDownloadManager.java new file mode 100644 index 00000000..b83f7c8f --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/update/RecursiveDownloadManager.java @@ -0,0 +1,114 @@ +package com.projectg.geyserupdater.common.update; + +import com.projectg.geyserupdater.common.GeyserUpdater; +import com.projectg.geyserupdater.common.logger.UpdaterLogger; +import com.projectg.geyserupdater.common.scheduler.Task; +import com.projectg.geyserupdater.common.scheduler.UpdaterScheduler; +import com.projectg.geyserupdater.common.util.WebUtils; + +import javax.annotation.Nullable; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +public class RecursiveDownloadManager { + + private final GeyserUpdater updater; + private final Path outputDirectory; + + private final List queue = new LinkedList<>(); + + // Used for making sure one download is ever running + private boolean isDownloading = false; + + // Used by the hang checker to check if the current download is the same as when it was scheduled + @Nullable private Updatable currentUpdate = null; + + // Used by the hang checker to cancel the download if necessary + @Nullable private Task downloader = null; + + // todo: maybe refactor this to use a for loop instead of being recursive? i dunno + + public RecursiveDownloadManager(GeyserUpdater updater, Path outputDirectory) { + //todo: move outputDirectory to Updatable + this.updater = updater; + this.outputDirectory = outputDirectory; + } + + public void queue(Updatable updatable) { + queue.add(updatable); + downloadIfPossible(); + } + + private void download(Updatable updatable) { + isDownloading = true; + currentUpdate = updatable; + + UpdaterScheduler scheduler = updater.getScheduler(); + + // Run the download on a new thread + this.downloader = scheduler.run(() -> { + + // Create a timer to stop this download from running too long. Either the hang checker is cancelled or the hang checker cancels this. + Task hangChecker = scheduleHangChecker(updater, updatable); + + WebUtils.downloadFile(updatable.downloadUrl, outputDirectory.resolve(updatable.outputFileName)); + hangChecker.cancel(); + + // Revert everything while having it locked so that the state is always correctly read by original thread + synchronized (this) { + this.queue.remove(updatable); + this.isDownloading = false; + this.currentUpdate = null; + this.downloader = null; + } + + // Initiate another download if necessary + downloadIfPossible(); + }, true); + } + + private void downloadIfPossible() { + if (!queue.isEmpty() && !isDownloading) { + download(queue.get(0)); + } + } + + private Task scheduleHangChecker(GeyserUpdater updater, Updatable updatable) { + // The time to allow the download to take, in seconds + int downloadTimeLimit = updater.getConfig().getDownloadTimeLimit(); + + return updater.getScheduler().runDelayed(() -> { + if (!isDownloading || downloader == null) { + throw new AssertionError("HangChecker should not execute while nothing is downloading."); + } + + if (updatable == currentUpdate) { + // Revert everything while having it locked so that the state is always correctly read by a different thread + synchronized (this) { + queue.clear(); + isDownloading = false; + currentUpdate = null; + downloader.cancel(); + downloader = null; + } + + UpdaterLogger logger = UpdaterLogger.getLogger(); + + logger.error("The download queue has been stopped and cleared because the download for " + updatable + " took longer than " + downloadTimeLimit + + " seconds. Increase the download-time-limit in the config if you have a slow internet connection."); + + try { + boolean deletedFailedFile = Files.deleteIfExists(outputDirectory.resolve(updatable.outputFileName)); + logger.debug("Failed download for " + updatable + " had a file?: " + deletedFailedFile); + } catch (IOException e) { + logger.error("Failed to delete failed download file of " + updatable); + e.printStackTrace(); + } + } + }, true, downloadTimeLimit, TimeUnit.SECONDS); + } +} From 8edda1035506138fb6879aa67b7314bfdfdfc9c0 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Thu, 12 Aug 2021 18:49:00 -0400 Subject: [PATCH 13/42] allow for more dynamic download locations Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../geyserupdater/common/GeyserUpdater.java | 2 +- .../common/update/DownloadManager.java | 9 +++------ .../geyserupdater/common/update/Updatable.java | 16 +++++++++------- .../age/provider/JenkinsHashProvider.java | 17 +++++++++++++++++ .../common/update/age/type/Md5FileHash.java | 15 +++++++++++++++ 5 files changed, 45 insertions(+), 14 deletions(-) create mode 100644 src/main/java/com/projectg/geyserupdater/common/update/age/provider/JenkinsHashProvider.java create mode 100644 src/main/java/com/projectg/geyserupdater/common/update/age/type/Md5FileHash.java diff --git a/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java b/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java index dac5b5d1..8e097936 100644 --- a/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java +++ b/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java @@ -87,7 +87,7 @@ public GeyserUpdater(Path dataFolder, PluginId.FLOODGATE.setArtifact(floodgateArtifact); // Manager for updating plugins - UpdateManager updateManager = new UpdateManager(new DownloadManager(this, downloadFolder)); + UpdateManager updateManager = new UpdateManager(new DownloadManager(this)); } public static GeyserUpdater getInstance() { diff --git a/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java b/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java index 28992438..4406e56e 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java @@ -9,7 +9,6 @@ import javax.annotation.Nullable; import java.io.IOException; import java.nio.file.Files; -import java.nio.file.Path; import java.util.LinkedList; import java.util.List; import java.util.concurrent.TimeUnit; @@ -17,7 +16,6 @@ public class DownloadManager { private final GeyserUpdater updater; - private final Path outputDirectory; private final List queue = new LinkedList<>(); @@ -30,10 +28,9 @@ public class DownloadManager { // Used by the hang checker to cancel the download if necessary @Nullable private Task downloader = null; - public DownloadManager(GeyserUpdater updater, Path outputDirectory) { + public DownloadManager(GeyserUpdater updater) { //todo: move outputDirectory to Updatable this.updater = updater; - this.outputDirectory = outputDirectory; } public void queue(Updatable updatable) { @@ -61,7 +58,7 @@ private void downloadAll() { // Create a timer to stop this download from running too long. Either the hang checker is cancelled or the hang checker cancels this. Task hangChecker = scheduleHangChecker(updater, updatable); - WebUtils.downloadFile(updatable.downloadUrl, outputDirectory.resolve(updatable.outputFileName)); + WebUtils.downloadFile(updatable.downloadUrl, updatable.outputFile); hangChecker.cancel(); } @@ -103,7 +100,7 @@ private Task scheduleHangChecker(GeyserUpdater updater, Updatable updatable) { " seconds. Increase the download-time-limit in the config if you have a slow internet connection."); try { - boolean deletedFailedFile = Files.deleteIfExists(outputDirectory.resolve(updatable.outputFileName)); + boolean deletedFailedFile = Files.deleteIfExists(updatable.outputFile); logger.debug("Failed download for " + updatable + " had a file?: " + deletedFailedFile); } catch (IOException e) { logger.error("Failed to delete failed download file of " + updatable); diff --git a/src/main/java/com/projectg/geyserupdater/common/update/Updatable.java b/src/main/java/com/projectg/geyserupdater/common/update/Updatable.java index 48a67d3c..5f08adf0 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/Updatable.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/Updatable.java @@ -3,7 +3,8 @@ import com.projectg.geyserupdater.common.update.age.AgeComparer; import javax.annotation.Nonnull; -import javax.annotation.Nullable; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Objects; public class Updatable { @@ -11,18 +12,19 @@ public class Updatable { @Nonnull public final String pluginIdentity; @Nonnull public final AgeComparer ageComparer; @Nonnull public final String downloadUrl; - @Nonnull public final String outputFileName; + @Nonnull public final Path outputFile; /** * @param pluginIdentity The plugin name, which can be used to identify the plugin. * @param ageComparer The age comparer to check if the plugin is outdated * @param downloadUrl The complete download link of the plugin - * @param outputFileName The output file name. May be null to attempt to use the file name that the downloadUrl provides. + * @param file If the Path is a file, the download will be written to that file. If the Path is a directory, the file will be written to that directory, and the filename will deduced from the link provided. */ - public Updatable(@Nonnull String pluginIdentity, @Nonnull AgeComparer ageComparer, @Nonnull String downloadUrl, @Nullable String outputFileName) { + public Updatable(@Nonnull String pluginIdentity, @Nonnull AgeComparer ageComparer, @Nonnull String downloadUrl, @Nonnull Path file) { Objects.requireNonNull(pluginIdentity); Objects.requireNonNull(ageComparer); Objects.requireNonNull(downloadUrl); + Objects.requireNonNull(file); this.pluginIdentity = pluginIdentity; this.ageComparer = ageComparer; @@ -40,10 +42,10 @@ public Updatable(@Nonnull String pluginIdentity, @Nonnull AgeComparer ageC } // Figure out the output file name if necessary - if (outputFileName == null) { - this.outputFileName = downloadUrl.substring(downloadUrl.lastIndexOf("/") + 1); + if (Files.isDirectory(file)) { + this.outputFile = file.resolve(downloadUrl.substring(downloadUrl.lastIndexOf("/") + 1)); } else { - this.outputFileName = outputFileName; + this.outputFile = file; } } diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/provider/JenkinsHashProvider.java b/src/main/java/com/projectg/geyserupdater/common/update/age/provider/JenkinsHashProvider.java new file mode 100644 index 00000000..b6d9aa5e --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/update/age/provider/JenkinsHashProvider.java @@ -0,0 +1,17 @@ +package com.projectg.geyserupdater.common.update.age.provider; + +import com.projectg.geyserupdater.common.update.age.type.Age; +import com.projectg.geyserupdater.common.update.age.type.Md5FileHash; + +public class JenkinsHashProvider implements Age { + + public JenkinsHashProvider(String link) { + + } + + + @Override + public Md5FileHash value() { + return null; + } +} diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/type/Md5FileHash.java b/src/main/java/com/projectg/geyserupdater/common/update/age/type/Md5FileHash.java new file mode 100644 index 00000000..6086719a --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/update/age/type/Md5FileHash.java @@ -0,0 +1,15 @@ +package com.projectg.geyserupdater.common.update.age.type; + +public class Md5FileHash implements Age { + + private final String hash; + + private Md5FileHash(String md5Hash) { + hash = md5Hash; + } + + @Override + public String value() { + return hash; + } +} From 9205980b7deacc219fb455031091813bc9325f29 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Thu, 12 Aug 2021 19:26:08 -0400 Subject: [PATCH 14/42] cleanup download/update stuff Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../geyserupdater/common/GeyserUpdater.java | 2 +- .../common/update/DownloadManager.java | 1 - .../update/RecursiveDownloadManager.java | 10 ++-- .../common/update/Updatable.java | 9 ++-- .../common/update/UpdateManager.java | 48 ++++++++++++++--- .../common/update/age/AgeComparer.java | 51 ------------------- .../common/update/age/IdentityComparer.java | 51 +++++++++++++++++++ .../update/age/provider/AgeProvider.java | 8 --- .../update/age/provider/FileHashProvider.java | 12 +++++ .../update/age/provider/IdentityProvider.java | 8 +++ .../age/provider/JenkinsBuildProvider.java | 4 +- .../age/provider/JenkinsHashProvider.java | 8 ++- .../common/update/age/type/BuildNumber.java | 2 +- .../age/type/{Age.java => Identity.java} | 2 +- .../common/update/age/type/Md5FileHash.java | 2 +- 15 files changed, 129 insertions(+), 89 deletions(-) delete mode 100644 src/main/java/com/projectg/geyserupdater/common/update/age/AgeComparer.java create mode 100644 src/main/java/com/projectg/geyserupdater/common/update/age/IdentityComparer.java delete mode 100644 src/main/java/com/projectg/geyserupdater/common/update/age/provider/AgeProvider.java create mode 100644 src/main/java/com/projectg/geyserupdater/common/update/age/provider/FileHashProvider.java create mode 100644 src/main/java/com/projectg/geyserupdater/common/update/age/provider/IdentityProvider.java rename src/main/java/com/projectg/geyserupdater/common/update/age/type/{Age.java => Identity.java} (87%) diff --git a/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java b/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java index 8e097936..12d15c6b 100644 --- a/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java +++ b/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java @@ -87,7 +87,7 @@ public GeyserUpdater(Path dataFolder, PluginId.FLOODGATE.setArtifact(floodgateArtifact); // Manager for updating plugins - UpdateManager updateManager = new UpdateManager(new DownloadManager(this)); + UpdateManager updateManager = new UpdateManager(downloadFolder, new DownloadManager(this)); } public static GeyserUpdater getInstance() { diff --git a/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java b/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java index 4406e56e..413d2570 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java @@ -29,7 +29,6 @@ public class DownloadManager { @Nullable private Task downloader = null; public DownloadManager(GeyserUpdater updater) { - //todo: move outputDirectory to Updatable this.updater = updater; } diff --git a/src/main/java/com/projectg/geyserupdater/common/update/RecursiveDownloadManager.java b/src/main/java/com/projectg/geyserupdater/common/update/RecursiveDownloadManager.java index b83f7c8f..17e013a4 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/RecursiveDownloadManager.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/RecursiveDownloadManager.java @@ -9,15 +9,14 @@ import javax.annotation.Nullable; import java.io.IOException; import java.nio.file.Files; -import java.nio.file.Path; import java.util.LinkedList; import java.util.List; import java.util.concurrent.TimeUnit; +@SuppressWarnings("unused") // Keeping this to compare to DownloadManager public class RecursiveDownloadManager { private final GeyserUpdater updater; - private final Path outputDirectory; private final List queue = new LinkedList<>(); @@ -32,10 +31,9 @@ public class RecursiveDownloadManager { // todo: maybe refactor this to use a for loop instead of being recursive? i dunno - public RecursiveDownloadManager(GeyserUpdater updater, Path outputDirectory) { + public RecursiveDownloadManager(GeyserUpdater updater) { //todo: move outputDirectory to Updatable this.updater = updater; - this.outputDirectory = outputDirectory; } public void queue(Updatable updatable) { @@ -55,7 +53,7 @@ private void download(Updatable updatable) { // Create a timer to stop this download from running too long. Either the hang checker is cancelled or the hang checker cancels this. Task hangChecker = scheduleHangChecker(updater, updatable); - WebUtils.downloadFile(updatable.downloadUrl, outputDirectory.resolve(updatable.outputFileName)); + WebUtils.downloadFile(updatable.downloadUrl, updatable.outputFile); hangChecker.cancel(); // Revert everything while having it locked so that the state is always correctly read by original thread @@ -102,7 +100,7 @@ private Task scheduleHangChecker(GeyserUpdater updater, Updatable updatable) { " seconds. Increase the download-time-limit in the config if you have a slow internet connection."); try { - boolean deletedFailedFile = Files.deleteIfExists(outputDirectory.resolve(updatable.outputFileName)); + boolean deletedFailedFile = Files.deleteIfExists(updatable.outputFile); logger.debug("Failed download for " + updatable + " had a file?: " + deletedFailedFile); } catch (IOException e) { logger.error("Failed to delete failed download file of " + updatable); diff --git a/src/main/java/com/projectg/geyserupdater/common/update/Updatable.java b/src/main/java/com/projectg/geyserupdater/common/update/Updatable.java index 5f08adf0..b1bb32f5 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/Updatable.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/Updatable.java @@ -1,6 +1,6 @@ package com.projectg.geyserupdater.common.update; -import com.projectg.geyserupdater.common.update.age.AgeComparer; +import com.projectg.geyserupdater.common.update.age.IdentityComparer; import javax.annotation.Nonnull; import java.nio.file.Files; @@ -10,17 +10,18 @@ public class Updatable { @Nonnull public final String pluginIdentity; - @Nonnull public final AgeComparer ageComparer; + @Nonnull public final IdentityComparer ageComparer; @Nonnull public final String downloadUrl; @Nonnull public final Path outputFile; /** * @param pluginIdentity The plugin name, which can be used to identify the plugin. - * @param ageComparer The age comparer to check if the plugin is outdated + * @param ageComparer The {@link IdentityComparer} to check if the plugin is outdated + * @param hashComparer The {@link IdentityComparer} to check if the hash of the downloaded file is acceptable. * @param downloadUrl The complete download link of the plugin * @param file If the Path is a file, the download will be written to that file. If the Path is a directory, the file will be written to that directory, and the filename will deduced from the link provided. */ - public Updatable(@Nonnull String pluginIdentity, @Nonnull AgeComparer ageComparer, @Nonnull String downloadUrl, @Nonnull Path file) { + public Updatable(@Nonnull String pluginIdentity, @Nonnull IdentityComparer ageComparer, @Nonnull IdentityComparer hashComparer, @Nonnull String downloadUrl, @Nonnull Path file) { Objects.requireNonNull(pluginIdentity); Objects.requireNonNull(ageComparer); Objects.requireNonNull(downloadUrl); diff --git a/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java b/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java index 31cc2ada..7a0a7b45 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java @@ -1,13 +1,18 @@ package com.projectg.geyserupdater.common.update; import com.projectg.geyserupdater.common.logger.UpdaterLogger; -import com.projectg.geyserupdater.common.update.age.AgeComparer; +import com.projectg.geyserupdater.common.update.age.IdentityComparer; +import com.projectg.geyserupdater.common.update.age.provider.FileHashProvider; import com.projectg.geyserupdater.common.update.age.provider.JenkinsBuildProvider; +import com.projectg.geyserupdater.common.update.age.provider.JenkinsHashProvider; import com.projectg.geyserupdater.common.update.age.type.BuildNumber; import java.io.IOException; import java.io.InputStream; -import java.util.*; +import java.nio.file.Path; +import java.util.HashSet; +import java.util.Properties; +import java.util.Set; public class UpdateManager { @@ -26,7 +31,7 @@ public class UpdateManager { */ private Set outdatedPlugins = new HashSet<>(); - public UpdateManager(DownloadManager downloadManager) { + public UpdateManager(Path defaultDownloadLocation, DownloadManager downloadManager) { this.downloadManager = downloadManager; UpdaterLogger logger = UpdaterLogger.getLogger(); @@ -53,13 +58,20 @@ public UpdateManager(DownloadManager downloadManager) { throw new AssertionError("Failed to find build number or branch in Git Properties '" + gitProperties + "' of plugin '" + pluginId.name() + "'"); } + // For age comparer BuildNumber buildNumber = new BuildNumber(Integer.parseInt(buildNumberString)); - JenkinsBuildProvider jenkins = new JenkinsBuildProvider(); + JenkinsBuildProvider buildProvider = new JenkinsBuildProvider(); + + // For file hash provider + FileHashProvider localHashProvider = new FileHashProvider(); + JenkinsHashProvider jenkinsHashProvider = new JenkinsHashProvider(); + register(new Updatable( pluginId.name(), - new AgeComparer<>(buildNumber, jenkins), + new IdentityComparer<>(buildNumber, buildProvider), + new IdentityComparer<>(localHashProvider, jenkinsHashProvider), pluginId.getLatestFileLink(), - null)); + defaultDownloadLocation)); } } @@ -74,7 +86,7 @@ public void register(Updatable updatable) { updatables.add(updatable); } - public void checkAll() { + public void setOutdatedPlugins() { outdatedPlugins = new HashSet<>(); for (Updatable updatable : updatables) { // todo: make sure we don't run this sync... maybe instantiate GeyserUpdater.class async? @@ -86,9 +98,29 @@ public void checkAll() { UpdaterLogger.getLogger().info("Updates required for plugins: " + outdatedPlugins); } + public Set getOutdatedPlugins() { + return outdatedPlugins; + } + + /** + * Update an outdated Updatable + * @return true if the download was queued, false if the Updatable is not outdated. + */ + public boolean update(Updatable updatable) { + if (outdatedPlugins.contains(updatable)) { + downloadManager.queue(updatable); + return true; + } else { + return false; + } + } + + /** + * Update all outdated Updatables tracked. + */ public void updateAll() { for (Updatable updatable : outdatedPlugins) { - downloadManager.queue(updatable); + update(updatable); } } } diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/AgeComparer.java b/src/main/java/com/projectg/geyserupdater/common/update/age/AgeComparer.java deleted file mode 100644 index 11b51e5c..00000000 --- a/src/main/java/com/projectg/geyserupdater/common/update/age/AgeComparer.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.projectg.geyserupdater.common.update.age; - -import com.projectg.geyserupdater.common.update.age.provider.AgeProvider; -import com.projectg.geyserupdater.common.update.age.type.Age; - -import javax.annotation.Nonnull; -import java.util.Objects; - -/** - * @param The external {@link AgeProvider} implementation - * @param The {@link Age} implementation - */ -public class AgeComparer, S extends Age> { - - S localAge; - T externalAgeProvider; - - /** - * Create an age comparer, which stores a local age and way to check an external age. Both params should provide the same {@link Age} implementation. - * @param localAgeProvider The local age provider. {@link AgeProvider#getAge()} will be called once and stored forever. - * @param externalAgeProvider The external age provider. {@link AgeProvider#getAge()} will be called every time {@link AgeComparer#checkIfEquals()} is called. - */ - public > AgeComparer(@Nonnull U localAgeProvider, @Nonnull T externalAgeProvider) { - Objects.requireNonNull(localAgeProvider); - Objects.requireNonNull(externalAgeProvider); - - this.localAge = localAgeProvider.getAge(); - this.externalAgeProvider = externalAgeProvider; - } - - /** - * Create an age comparer, which stores a local age and way to check an external age - * @param localAge The local age. - * @param externalAgeProvider The external age provider. {@link AgeProvider#getAge()} will be called every time {@link AgeComparer#checkIfEquals()} is called. - */ - public AgeComparer(@Nonnull S localAge, @Nonnull T externalAgeProvider) { - Objects.requireNonNull(localAge); - Objects.requireNonNull(externalAgeProvider); - - this.localAge = localAge; - this.externalAgeProvider = externalAgeProvider; - } - - /** - * Request the {@link Age} from the external {@link AgeProvider} and compare it to the stored local {@link Age}. - * @return True if the local age {@link Object#equals(Object)} the external age - */ - public boolean checkIfEquals() { - return localAge.value().equals(externalAgeProvider.getAge()); - } -} diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/IdentityComparer.java b/src/main/java/com/projectg/geyserupdater/common/update/age/IdentityComparer.java new file mode 100644 index 00000000..71e2c603 --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/update/age/IdentityComparer.java @@ -0,0 +1,51 @@ +package com.projectg.geyserupdater.common.update.age; + +import com.projectg.geyserupdater.common.update.age.provider.IdentityProvider; +import com.projectg.geyserupdater.common.update.age.type.Identity; + +import javax.annotation.Nonnull; +import java.util.Objects; + +/** + * @param The external {@link IdentityProvider} implementation + * @param The {@link Identity} implementation + */ +public class IdentityComparer, S extends Identity> { + + S localIdentity; + T externalIdentityProvider; + + /** + * Create an identity comparer, which stores a local identity and way to check an external identity. Both params should provide the same {@link Identity} implementation. + * @param localIdentityProvider The local identity provider. {@link IdentityProvider#getValue()} will be called once and stored forever. + * @param externalIdentityProvider The external identity provider. {@link IdentityProvider#getValue()} will be called every time {@link IdentityComparer#checkIfEquals()} is called. + */ + public > IdentityComparer(@Nonnull U localIdentityProvider, @Nonnull T externalIdentityProvider) { + Objects.requireNonNull(localIdentityProvider); + Objects.requireNonNull(externalIdentityProvider); + + this.localIdentity = localIdentityProvider.getValue(); + this.externalIdentityProvider = externalIdentityProvider; + } + + /** + * Create an identity comparer, which stores a local identity and way to check an external identity + * @param localIdentity The local identity. + * @param externalIdentityProvider The external identity provider. {@link IdentityProvider#getValue()} will be called every time {@link IdentityComparer#checkIfEquals()} is called. + */ + public IdentityComparer(@Nonnull S localIdentity, @Nonnull T externalIdentityProvider) { + Objects.requireNonNull(localIdentity); + Objects.requireNonNull(externalIdentityProvider); + + this.localIdentity = localIdentity; + this.externalIdentityProvider = externalIdentityProvider; + } + + /** + * Request the {@link Identity} from the external {@link IdentityProvider} and compare it to the stored local {@link Identity}. + * @return True if the local identity {@link Object#equals(Object)} the external identity + */ + public boolean checkIfEquals() { + return localIdentity.value().equals(externalIdentityProvider.getValue()); + } +} diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/provider/AgeProvider.java b/src/main/java/com/projectg/geyserupdater/common/update/age/provider/AgeProvider.java deleted file mode 100644 index 8ceed5db..00000000 --- a/src/main/java/com/projectg/geyserupdater/common/update/age/provider/AgeProvider.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.projectg.geyserupdater.common.update.age.provider; - -import com.projectg.geyserupdater.common.update.age.type.Age; - -public interface AgeProvider> { - - S getAge(); -} diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/provider/FileHashProvider.java b/src/main/java/com/projectg/geyserupdater/common/update/age/provider/FileHashProvider.java new file mode 100644 index 00000000..62375b77 --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/update/age/provider/FileHashProvider.java @@ -0,0 +1,12 @@ +package com.projectg.geyserupdater.common.update.age.provider; + +import com.projectg.geyserupdater.common.update.age.type.Md5FileHash; + +public class FileHashProvider implements IdentityProvider { + + @Override + public Md5FileHash getValue() { + //todo + return null; + } +} diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/provider/IdentityProvider.java b/src/main/java/com/projectg/geyserupdater/common/update/age/provider/IdentityProvider.java new file mode 100644 index 00000000..845fa6dc --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/update/age/provider/IdentityProvider.java @@ -0,0 +1,8 @@ +package com.projectg.geyserupdater.common.update.age.provider; + +import com.projectg.geyserupdater.common.update.age.type.Identity; + +public interface IdentityProvider> { + + S getValue(); +} diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/provider/JenkinsBuildProvider.java b/src/main/java/com/projectg/geyserupdater/common/update/age/provider/JenkinsBuildProvider.java index 1bde9e97..ea276bc3 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/age/provider/JenkinsBuildProvider.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/age/provider/JenkinsBuildProvider.java @@ -2,14 +2,14 @@ import com.projectg.geyserupdater.common.update.age.type.BuildNumber; -public class JenkinsBuildProvider implements AgeProvider{ +public class JenkinsBuildProvider implements IdentityProvider { public JenkinsBuildProvider() { //todo finish this } @Override - public BuildNumber getAge() { + public BuildNumber getValue() { return null; } } diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/provider/JenkinsHashProvider.java b/src/main/java/com/projectg/geyserupdater/common/update/age/provider/JenkinsHashProvider.java index b6d9aa5e..37b95d2d 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/age/provider/JenkinsHashProvider.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/age/provider/JenkinsHashProvider.java @@ -1,17 +1,15 @@ package com.projectg.geyserupdater.common.update.age.provider; -import com.projectg.geyserupdater.common.update.age.type.Age; import com.projectg.geyserupdater.common.update.age.type.Md5FileHash; -public class JenkinsHashProvider implements Age { +public class JenkinsHashProvider implements IdentityProvider { - public JenkinsHashProvider(String link) { + public JenkinsHashProvider() { } - @Override - public Md5FileHash value() { + public Md5FileHash getValue() { return null; } } diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/type/BuildNumber.java b/src/main/java/com/projectg/geyserupdater/common/update/age/type/BuildNumber.java index 26b77e3f..477797a6 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/age/type/BuildNumber.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/age/type/BuildNumber.java @@ -1,6 +1,6 @@ package com.projectg.geyserupdater.common.update.age.type; -public class BuildNumber implements Age { +public class BuildNumber implements Identity { private final int buildNumber; diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/type/Age.java b/src/main/java/com/projectg/geyserupdater/common/update/age/type/Identity.java similarity index 87% rename from src/main/java/com/projectg/geyserupdater/common/update/age/type/Age.java rename to src/main/java/com/projectg/geyserupdater/common/update/age/type/Identity.java index 98d7c761..7115f7ff 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/age/type/Age.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/age/type/Identity.java @@ -4,7 +4,7 @@ * Provides implementation for something that can be quantified as an age of something. * @param The Type of the age. */ -public interface Age { +public interface Identity { T value(); } diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/type/Md5FileHash.java b/src/main/java/com/projectg/geyserupdater/common/update/age/type/Md5FileHash.java index 6086719a..13c51ff8 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/age/type/Md5FileHash.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/age/type/Md5FileHash.java @@ -1,6 +1,6 @@ package com.projectg.geyserupdater.common.update.age.type; -public class Md5FileHash implements Age { +public class Md5FileHash implements Identity { private final String hash; From 9a842f4adb3f766c2b779cbbfb1cdd4928c30098 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Thu, 12 Aug 2021 20:02:42 -0400 Subject: [PATCH 15/42] dependency injection refactor Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../geyserupdater/bungee/BungeeUpdater.java | 1 - .../geyserupdater/common/GeyserUpdater.java | 13 ++++----- .../common/update/DownloadManager.java | 28 ++++++++++++------- .../common/update/UpdateManager.java | 13 +++++++-- 4 files changed, 33 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/projectg/geyserupdater/bungee/BungeeUpdater.java b/src/main/java/com/projectg/geyserupdater/bungee/BungeeUpdater.java index 59fad103..78d843cc 100644 --- a/src/main/java/com/projectg/geyserupdater/bungee/BungeeUpdater.java +++ b/src/main/java/com/projectg/geyserupdater/bungee/BungeeUpdater.java @@ -7,7 +7,6 @@ import com.projectg.geyserupdater.common.logger.JavaUtilUpdaterLogger; import com.projectg.geyserupdater.common.logger.UpdaterLogger; import com.projectg.geyserupdater.common.util.FileUtils; -import com.projectg.geyserupdater.common.util.GeyserProperties; import com.projectg.geyserupdater.common.util.ScriptCreator; import com.projectg.geyserupdater.common.util.SpigotResourceUpdateChecker; diff --git a/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java b/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java index 12d15c6b..b680dc6d 100644 --- a/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java +++ b/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java @@ -3,7 +3,6 @@ import com.projectg.geyserupdater.common.config.UpdaterConfiguration; import com.projectg.geyserupdater.common.logger.UpdaterLogger; import com.projectg.geyserupdater.common.scheduler.UpdaterScheduler; -import com.projectg.geyserupdater.common.update.DownloadManager; import com.projectg.geyserupdater.common.update.PluginId; import com.projectg.geyserupdater.common.update.UpdateManager; import com.projectg.geyserupdater.common.util.FileUtils; @@ -18,10 +17,12 @@ public class GeyserUpdater { private static GeyserUpdater INSTANCE = null; + public final String version; + private final UpdaterLogger logger; private final UpdaterScheduler scheduler; private final PlayerHandler playerHandler; - public final String version; + private final UpdateManager updateManager; private final UpdaterConfiguration config; @@ -60,8 +61,7 @@ public GeyserUpdater(Path dataFolder, logger.debug("Loading config"); config = FileUtils.loadConfig(dataFolder.resolve("config.yml")); if (config.isIncorrectVersion()) { - logger.error("Your copy of config.yml is outdated (your version: " + config.getConfigVersion() + ", latest version: " + UpdaterConfiguration.DEFAULT_CONFIG_VERSION + "). Please delete it and let a fresh copy of config.yml be regenerated!"); - return; + throw new IllegalStateException("Your copy of config.yml is outdated (your version: " + config.getConfigVersion() + ", latest version: " + UpdaterConfiguration.DEFAULT_CONFIG_VERSION + "). Please delete it and let a fresh copy of config.yml be regenerated!"); } if (config.isEnableDebug()) { logger.enableDebug(); @@ -87,7 +87,7 @@ public GeyserUpdater(Path dataFolder, PluginId.FLOODGATE.setArtifact(floodgateArtifact); // Manager for updating plugins - UpdateManager updateManager = new UpdateManager(downloadFolder, new DownloadManager(this)); + this.updateManager = new UpdateManager(downloadFolder, scheduler, config.getDownloadTimeLimit()); } public static GeyserUpdater getInstance() { @@ -102,7 +102,4 @@ public UpdaterLogger getLogger() { public UpdaterScheduler getScheduler() { return scheduler; } - public PlayerHandler getPlayerHandler() { - return playerHandler; - } } diff --git a/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java b/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java index 413d2570..29790d00 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java @@ -1,6 +1,5 @@ package com.projectg.geyserupdater.common.update; -import com.projectg.geyserupdater.common.GeyserUpdater; import com.projectg.geyserupdater.common.logger.UpdaterLogger; import com.projectg.geyserupdater.common.scheduler.Task; import com.projectg.geyserupdater.common.scheduler.UpdaterScheduler; @@ -15,7 +14,9 @@ public class DownloadManager { - private final GeyserUpdater updater; + private final UpdateManager updateManager; + private final UpdaterScheduler scheduler; + private final int downloadTimeLimit; private final List queue = new LinkedList<>(); @@ -28,8 +29,10 @@ public class DownloadManager { // Used by the hang checker to cancel the download if necessary @Nullable private Task downloader = null; - public DownloadManager(GeyserUpdater updater) { - this.updater = updater; + public DownloadManager(UpdateManager updateManager, UpdaterScheduler scheduler, int downloadTimeLimit) { + this.updateManager = updateManager; + this.scheduler = scheduler; + this.downloadTimeLimit = downloadTimeLimit; } public void queue(Updatable updatable) { @@ -42,8 +45,6 @@ public void queue(Updatable updatable) { private void downloadAll() { isDownloading = true; - UpdaterScheduler scheduler = updater.getScheduler(); - // Run the download on a new thread this.downloader = scheduler.run(() -> { @@ -55,14 +56,22 @@ private void downloadAll() { currentUpdate = updatable; // Create a timer to stop this download from running too long. Either the hang checker is cancelled or the hang checker cancels this. - Task hangChecker = scheduleHangChecker(updater, updatable); + Task hangChecker = scheduleHangChecker(updatable); WebUtils.downloadFile(updatable.downloadUrl, updatable.outputFile); hangChecker.cancel(); + + synchronized (this) { + updateManager.outdatedPlugins.remove(updatable); + updateManager.updatablesInQueue.remove(updatable); + } + + // todo: hash checker & tell audience the result of the download attempt } // Revert everything while having it locked so that the state is always correctly read by a different thread synchronized (this) { + // Clear the queue here so that the for loop above doesn't get messed up queue.clear(); isDownloading = false; currentUpdate = null; @@ -74,11 +83,10 @@ private void downloadAll() { }, true); } - private Task scheduleHangChecker(GeyserUpdater updater, Updatable updatable) { + private Task scheduleHangChecker(Updatable updatable) { // The time to allow the download to take, in seconds - int downloadTimeLimit = updater.getConfig().getDownloadTimeLimit(); - return updater.getScheduler().runDelayed(() -> { + return scheduler.runDelayed(() -> { if (!isDownloading || downloader == null) { throw new AssertionError("HangChecker should not execute while nothing is downloading."); } diff --git a/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java b/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java index 7a0a7b45..6678ef31 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java @@ -1,6 +1,7 @@ package com.projectg.geyserupdater.common.update; import com.projectg.geyserupdater.common.logger.UpdaterLogger; +import com.projectg.geyserupdater.common.scheduler.UpdaterScheduler; import com.projectg.geyserupdater.common.update.age.IdentityComparer; import com.projectg.geyserupdater.common.update.age.provider.FileHashProvider; import com.projectg.geyserupdater.common.update.age.provider.JenkinsBuildProvider; @@ -29,10 +30,16 @@ public class UpdateManager { /** * Plugins that are outdated and must be updated */ - private Set outdatedPlugins = new HashSet<>(); + protected Set outdatedPlugins = new HashSet<>(); - public UpdateManager(Path defaultDownloadLocation, DownloadManager downloadManager) { - this.downloadManager = downloadManager; + /** + * Plugins that are in the queue for download or are being downloaded + */ + protected final Set updatablesInQueue = new HashSet<>(); + + + public UpdateManager(Path defaultDownloadLocation, UpdaterScheduler scheduler, int downloadTimeLimit) { + this.downloadManager = new DownloadManager(this, scheduler, downloadTimeLimit); UpdaterLogger logger = UpdaterLogger.getLogger(); for (PluginId pluginId : PluginId.values()) { From ace1f3628d5601a7c68a0718a2c33176e41495ed Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Thu, 12 Aug 2021 20:22:38 -0400 Subject: [PATCH 16/42] tie ends with download manager Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../common/update/DownloadManager.java | 22 ++++++++++++------- .../common/update/UpdateManager.java | 7 ++++++ .../common/update/age/DownloadResult.java | 8 +++++++ .../geyserupdater/common/util/WebUtils.java | 18 ++++++--------- 4 files changed, 36 insertions(+), 19 deletions(-) create mode 100644 src/main/java/com/projectg/geyserupdater/common/update/age/DownloadResult.java diff --git a/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java b/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java index 29790d00..e76461f0 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java @@ -3,6 +3,7 @@ import com.projectg.geyserupdater.common.logger.UpdaterLogger; import com.projectg.geyserupdater.common.scheduler.Task; import com.projectg.geyserupdater.common.scheduler.UpdaterScheduler; +import com.projectg.geyserupdater.common.update.age.DownloadResult; import com.projectg.geyserupdater.common.util.WebUtils; import javax.annotation.Nullable; @@ -58,15 +59,19 @@ private void downloadAll() { // Create a timer to stop this download from running too long. Either the hang checker is cancelled or the hang checker cancels this. Task hangChecker = scheduleHangChecker(updatable); - WebUtils.downloadFile(updatable.downloadUrl, updatable.outputFile); - hangChecker.cancel(); - - synchronized (this) { - updateManager.outdatedPlugins.remove(updatable); - updateManager.updatablesInQueue.remove(updatable); + try { + WebUtils.downloadFile(updatable.downloadUrl, updatable.outputFile); + } catch (IOException e) { + UpdaterLogger.getLogger().error("Failed to download file at location " + updatable.outputFile + " with URL: " + updatable.downloadUrl); + e.printStackTrace(); + updateManager.finish(updatable, DownloadResult.UNKNOWN_FAIL); + continue; } - // todo: hash checker & tell audience the result of the download attempt + hangChecker.cancel(); + updateManager.finish(updatable, DownloadResult.SUCCESS); + + // todo: hash checker } // Revert everything while having it locked so that the state is always correctly read by a different thread @@ -101,8 +106,9 @@ private Task scheduleHangChecker(Updatable updatable) { downloader = null; } - UpdaterLogger logger = UpdaterLogger.getLogger(); + updateManager.finish(updatable, DownloadResult.TIMEOUT); + UpdaterLogger logger = UpdaterLogger.getLogger(); logger.error("The download queue has been stopped and cleared because the download for " + updatable + " took longer than " + downloadTimeLimit + " seconds. Increase the download-time-limit in the config if you have a slow internet connection."); diff --git a/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java b/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java index 6678ef31..2d0b44d4 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java @@ -2,6 +2,7 @@ import com.projectg.geyserupdater.common.logger.UpdaterLogger; import com.projectg.geyserupdater.common.scheduler.UpdaterScheduler; +import com.projectg.geyserupdater.common.update.age.DownloadResult; import com.projectg.geyserupdater.common.update.age.IdentityComparer; import com.projectg.geyserupdater.common.update.age.provider.FileHashProvider; import com.projectg.geyserupdater.common.update.age.provider.JenkinsBuildProvider; @@ -130,4 +131,10 @@ public void updateAll() { update(updatable); } } + + protected void finish(Updatable updatable, DownloadResult result) { + outdatedPlugins.remove(updatable); + updatablesInQueue.remove(updatable); + UpdaterLogger.getLogger().info("Finished download for " + updatable + " with result: " + result); + } } diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/DownloadResult.java b/src/main/java/com/projectg/geyserupdater/common/update/age/DownloadResult.java new file mode 100644 index 00000000..0e0745dc --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/update/age/DownloadResult.java @@ -0,0 +1,8 @@ +package com.projectg.geyserupdater.common.update.age; + +public enum DownloadResult { + SUCCESS, + TIMEOUT, + HASH_FAIl, + UNKNOWN_FAIL; +} diff --git a/src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java b/src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java index d7ebbbe1..b0506718 100644 --- a/src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java +++ b/src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java @@ -55,17 +55,13 @@ public static JsonNode getJson(String reqURL) throws IOException { * @param reqURL File to fetch * @param fileLocation Location to save on disk */ - public static void downloadFile(String reqURL, Path fileLocation) { - try { - HttpURLConnection con = (HttpURLConnection) new URL(reqURL).openConnection(); - con.setRequestProperty("User-Agent", "GeyserUpdater-" + GeyserUpdater.getInstance().version); - InputStream in = con.getInputStream(); - Files.copy(in, fileLocation, StandardCopyOption.REPLACE_EXISTING); - // todo: need to close the inputstream or not? - in.close(); - } catch (Exception e) { - throw new AssertionError("Unable to download and save file: " + fileLocation + " (" + reqURL + ")", e); - } + public static void downloadFile(String reqURL, Path fileLocation) throws IOException { + HttpURLConnection con = (HttpURLConnection) new URL(reqURL).openConnection(); + con.setRequestProperty("User-Agent", "GeyserUpdater-" + GeyserUpdater.getInstance().version); + InputStream in = con.getInputStream(); + Files.copy(in, fileLocation, StandardCopyOption.REPLACE_EXISTING); + // todo: need to close the inputstream or not? + in.close(); } From fa6b1d85818182d52265303fdf541758d8b9779a Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Sat, 14 Aug 2021 21:58:16 -0400 Subject: [PATCH 17/42] add ability to compare file hashes Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../common/update/DownloadManager.java | 2 - .../common/update/Updatable.java | 14 +++--- .../common/update/UpdateManager.java | 34 ++++++++++++--- .../common/update/age/IdentityComparer.java | 4 ++ .../update/age/provider/FileHashProvider.java | 27 +++++++++++- .../update/age/provider/IdentityProvider.java | 3 ++ .../age/provider/JenkinsHashProvider.java | 43 ++++++++++++++++++- .../common/update/age/type/Md5FileHash.java | 2 +- .../geyserupdater/common/util/FileUtils.java | 12 ++++++ .../geyserupdater/common/util/WebUtils.java | 25 +++++------ 10 files changed, 134 insertions(+), 32 deletions(-) diff --git a/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java b/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java index e76461f0..695952ac 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java @@ -70,8 +70,6 @@ private void downloadAll() { hangChecker.cancel(); updateManager.finish(updatable, DownloadResult.SUCCESS); - - // todo: hash checker } // Revert everything while having it locked so that the state is always correctly read by a different thread diff --git a/src/main/java/com/projectg/geyserupdater/common/update/Updatable.java b/src/main/java/com/projectg/geyserupdater/common/update/Updatable.java index b1bb32f5..09b04eed 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/Updatable.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/Updatable.java @@ -3,6 +3,7 @@ import com.projectg.geyserupdater.common.update.age.IdentityComparer; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.nio.file.Files; import java.nio.file.Path; import java.util.Objects; @@ -10,25 +11,28 @@ public class Updatable { @Nonnull public final String pluginIdentity; - @Nonnull public final IdentityComparer ageComparer; + @Nonnull public final IdentityComparer identityComparer; + @Nullable public final IdentityComparer hashComparer; @Nonnull public final String downloadUrl; @Nonnull public final Path outputFile; /** + * Immutable container for information regarding how to update something * @param pluginIdentity The plugin name, which can be used to identify the plugin. - * @param ageComparer The {@link IdentityComparer} to check if the plugin is outdated + * @param identityComparer The {@link IdentityComparer} to check if the plugin is outdated * @param hashComparer The {@link IdentityComparer} to check if the hash of the downloaded file is acceptable. * @param downloadUrl The complete download link of the plugin * @param file If the Path is a file, the download will be written to that file. If the Path is a directory, the file will be written to that directory, and the filename will deduced from the link provided. */ - public Updatable(@Nonnull String pluginIdentity, @Nonnull IdentityComparer ageComparer, @Nonnull IdentityComparer hashComparer, @Nonnull String downloadUrl, @Nonnull Path file) { + public Updatable(@Nonnull String pluginIdentity, @Nonnull IdentityComparer identityComparer, @Nullable IdentityComparer hashComparer, @Nonnull String downloadUrl, @Nonnull Path file) { Objects.requireNonNull(pluginIdentity); - Objects.requireNonNull(ageComparer); + Objects.requireNonNull(identityComparer); Objects.requireNonNull(downloadUrl); Objects.requireNonNull(file); this.pluginIdentity = pluginIdentity; - this.ageComparer = ageComparer; + this.identityComparer = identityComparer; + this.hashComparer = hashComparer; // Remove / from the end of the link if necessary if (downloadUrl.endsWith("/")) { diff --git a/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java b/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java index 2d0b44d4..4ef7928f 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java @@ -8,9 +8,12 @@ import com.projectg.geyserupdater.common.update.age.provider.JenkinsBuildProvider; import com.projectg.geyserupdater.common.update.age.provider.JenkinsHashProvider; import com.projectg.geyserupdater.common.update.age.type.BuildNumber; +import com.projectg.geyserupdater.common.util.FileUtils; import java.io.IOException; import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URISyntaxException; import java.nio.file.Path; import java.util.HashSet; import java.util.Properties; @@ -63,21 +66,29 @@ public UpdateManager(Path defaultDownloadLocation, UpdaterScheduler scheduler, i String buildNumberString = gitProperties.getProperty("git.build.number"); String branch = gitProperties.getProperty("git.branch"); if (buildNumberString == null || branch == null) { - throw new AssertionError("Failed to find build number or branch in Git Properties '" + gitProperties + "' of plugin '" + pluginId.name() + "'"); + UpdaterLogger.getLogger().error("Failed to find build number or branch in git Properties '" + gitProperties + "' of plugin '" + pluginId.name() + "'. Not updating."); + continue; } // For age comparer BuildNumber buildNumber = new BuildNumber(Integer.parseInt(buildNumberString)); JenkinsBuildProvider buildProvider = new JenkinsBuildProvider(); - // For file hash provider - FileHashProvider localHashProvider = new FileHashProvider(); - JenkinsHashProvider jenkinsHashProvider = new JenkinsHashProvider(); + // File hash comparer + IdentityComparer hashComparer = null; + try { + FileHashProvider localHashProvider = new FileHashProvider(FileUtils.getCodeSourceLocation(pluginId.getClass())); + JenkinsHashProvider jenkinsHashProvider = new JenkinsHashProvider(pluginId.getLatestFileLink() + "/*fingerprint*/"); + hashComparer = new IdentityComparer<>(localHashProvider, jenkinsHashProvider); + } catch (URISyntaxException | MalformedURLException e) { + UpdaterLogger.getLogger().error("Failure while getting location of file for " + pluginId.name() + ". It will be possible to update it, but not to compare file hashes."); + e.printStackTrace(); + } register(new Updatable( pluginId.name(), new IdentityComparer<>(buildNumber, buildProvider), - new IdentityComparer<>(localHashProvider, jenkinsHashProvider), + hashComparer, pluginId.getLatestFileLink(), defaultDownloadLocation)); } @@ -98,7 +109,7 @@ public void setOutdatedPlugins() { outdatedPlugins = new HashSet<>(); for (Updatable updatable : updatables) { // todo: make sure we don't run this sync... maybe instantiate GeyserUpdater.class async? - if (!updatable.ageComparer.checkIfEquals()) { + if (!updatable.identityComparer.checkIfEquals()) { outdatedPlugins.add(updatable); } } @@ -135,6 +146,15 @@ public void updateAll() { protected void finish(Updatable updatable, DownloadResult result) { outdatedPlugins.remove(updatable); updatablesInQueue.remove(updatable); - UpdaterLogger.getLogger().info("Finished download for " + updatable + " with result: " + result); + + DownloadResult finalResult = result; + if (updatable.hashComparer != null) { + if (!updatable.hashComparer.checkIfEquals()) { + UpdaterLogger.getLogger().warn("The file hash of the downloaded file did not match the hash provided online for " + updatable); + finalResult = DownloadResult.HASH_FAIl; + } + } + + UpdaterLogger.getLogger().info("Finished download for " + updatable + " with result: " + finalResult); } } diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/IdentityComparer.java b/src/main/java/com/projectg/geyserupdater/common/update/age/IdentityComparer.java index 71e2c603..bec934de 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/age/IdentityComparer.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/age/IdentityComparer.java @@ -46,6 +46,10 @@ public IdentityComparer(@Nonnull S localIdentity, @Nonnull T externalIdentityPro * @return True if the local identity {@link Object#equals(Object)} the external identity */ public boolean checkIfEquals() { + if (localIdentity == null) { + return false; + } + return localIdentity.value().equals(externalIdentityProvider.getValue()); } } diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/provider/FileHashProvider.java b/src/main/java/com/projectg/geyserupdater/common/update/age/provider/FileHashProvider.java index 62375b77..577689ee 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/age/provider/FileHashProvider.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/age/provider/FileHashProvider.java @@ -1,12 +1,35 @@ package com.projectg.geyserupdater.common.update.age.provider; +import com.google.common.hash.Hashing; +import com.google.common.io.ByteSource; +import com.google.common.io.Files; +import com.projectg.geyserupdater.common.logger.UpdaterLogger; import com.projectg.geyserupdater.common.update.age.type.Md5FileHash; +import java.io.IOException; +import java.nio.file.Path; + public class FileHashProvider implements IdentityProvider { + Path file; + + public FileHashProvider(Path file) { + this.file = file; + } + @Override public Md5FileHash getValue() { - //todo - return null; + // https://stackoverflow.com/questions/304268/getting-a-files-md5-checksum-in-java + ByteSource byteSource = Files.asByteSource(file.toFile()); + + // todo: non beta usage? I dont know. + String md5Hash = null; + try { + md5Hash = byteSource.hash(Hashing.md5()).toString(); + } catch (IOException e) { + UpdaterLogger.getLogger().error("Exception while getting md5 hash of file: " + file.getFileName()); + e.printStackTrace(); + } + return new Md5FileHash(md5Hash); } } diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/provider/IdentityProvider.java b/src/main/java/com/projectg/geyserupdater/common/update/age/provider/IdentityProvider.java index 845fa6dc..5136449c 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/age/provider/IdentityProvider.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/age/provider/IdentityProvider.java @@ -2,7 +2,10 @@ import com.projectg.geyserupdater.common.update.age.type.Identity; +import javax.annotation.Nullable; + public interface IdentityProvider> { + @Nullable S getValue(); } diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/provider/JenkinsHashProvider.java b/src/main/java/com/projectg/geyserupdater/common/update/age/provider/JenkinsHashProvider.java index 37b95d2d..acbd9751 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/age/provider/JenkinsHashProvider.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/age/provider/JenkinsHashProvider.java @@ -1,15 +1,56 @@ package com.projectg.geyserupdater.common.update.age.provider; +import com.projectg.geyserupdater.common.logger.UpdaterLogger; import com.projectg.geyserupdater.common.update.age.type.Md5FileHash; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; + public class JenkinsHashProvider implements IdentityProvider { - public JenkinsHashProvider() { + private final URL url; + public JenkinsHashProvider(String url) throws MalformedURLException { + this.url = new URL(url); } @Override public Md5FileHash getValue() { + // Don't use WebUtils so that we don't have to iterate over the whole page contents, and have better error messages. + + try { + HttpURLConnection con = (HttpURLConnection) url.openConnection(); + con.setRequestMethod("GET"); + con.setRequestProperty("User-Agent", "GeyserUpdater"); + + if (con.getResponseCode() != 200) { + UpdaterLogger.getLogger().error("Unable to find md5 from jenkins fingerprint at: " + url + " because the Http response code was not 200 (OK)."); + return null; + } + + try (BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()))) { + + String inputLine; + while ((inputLine = in.readLine()) != null) { + if (inputLine.contains("MD5")) { + con.disconnect(); + return new Md5FileHash(inputLine.substring(inputLine.indexOf("MD5: ") + 4, inputLine.indexOf(""))); + } + } + con.disconnect(); + + UpdaterLogger.getLogger().error("Unable to find md5 from jenkins fingerprint at: " + url + " because the page scan failed to find the hash."); + return null; + } + } catch (IOException e) { + e.printStackTrace(); + } + + UpdaterLogger.getLogger().error("Unable to find md5 from jenkins fingerprint at: " + url + " because of an exception."); return null; } } diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/type/Md5FileHash.java b/src/main/java/com/projectg/geyserupdater/common/update/age/type/Md5FileHash.java index 13c51ff8..0c27b40f 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/age/type/Md5FileHash.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/age/type/Md5FileHash.java @@ -4,7 +4,7 @@ public class Md5FileHash implements Identity { private final String hash; - private Md5FileHash(String md5Hash) { + public Md5FileHash(String md5Hash) { hash = md5Hash; } 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 2151062e..3e114590 100644 --- a/src/main/java/com/projectg/geyserupdater/common/util/FileUtils.java +++ b/src/main/java/com/projectg/geyserupdater/common/util/FileUtils.java @@ -6,8 +6,10 @@ import java.io.IOException; import java.io.InputStream; +import java.net.URISyntaxException; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Objects; public class FileUtils { @@ -24,5 +26,15 @@ public static UpdaterConfiguration loadConfig(Path userConfig) throws IOExceptio ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory()); return yamlMapper.readValue(userConfig.toFile(), UpdaterConfiguration.class); } + + /** + * Get the file that a class resides in. + * @param clazz The class + * @return The file as a {@link Path} + * @throws URISyntaxException if there was a failure getting the {@link java.net.URL} of the {@link java.security.CodeSource} + */ + public static Path getCodeSourceLocation(Class clazz) throws URISyntaxException { + return Paths.get(clazz.getProtectionDomain().getCodeSource().getLocation().toURI()); + } } diff --git a/src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java b/src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java index b0506718..00595bab 100644 --- a/src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java +++ b/src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java @@ -22,19 +22,15 @@ public class WebUtils { * Makes a web request to the given URL and returns the body as a string * * @param reqURL URL to fetch - * @return Body contents or error message if the request fails + * @return Body contents */ - public static String getBody(String reqURL) { - try { - URL url = new URL(reqURL); - HttpURLConnection con = (HttpURLConnection) url.openConnection(); - con.setRequestMethod("GET"); - con.setRequestProperty("User-Agent", "GeyserUpdater-" + GeyserUpdater.getInstance().version); // Otherwise Java 8 fails on checking updates - - return connectionToString(con); - } catch (Exception e) { - return e.getMessage(); - } + public static String getBody(String reqURL) throws IOException { + URL url = new URL(reqURL); + HttpURLConnection con = (HttpURLConnection) url.openConnection(); + con.setRequestMethod("GET"); + con.setRequestProperty("User-Agent", "GeyserUpdater-" + GeyserUpdater.getInstance().version); // Otherwise Java 8 fails on checking updates + + return connectionToString(con); } /** @@ -62,6 +58,7 @@ public static void downloadFile(String reqURL, Path fileLocation) throws IOExcep Files.copy(in, fileLocation, StandardCopyOption.REPLACE_EXISTING); // todo: need to close the inputstream or not? in.close(); + con.disconnect(); } @@ -100,9 +97,9 @@ private static String connectionToString(HttpURLConnection con) throws IOExcepti * * @param branchLink Example: https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/master * @return the latest build number - * @throws UnsupportedEncodingException if failed to encode the given gitBranch + * @throws IOException if an exception occurred parsing the branchLink or there was a failure in the web request */ - public static int getLatestGeyserBuildNumberFromJenkins(String branchLink) throws UnsupportedEncodingException { + public static int getLatestGeyserBuildNumberFromJenkins(String branchLink) throws IOException { // todo use json String buildXMLContents = WebUtils.getBody(URLEncoder.encode(branchLink, StandardCharsets.UTF_8.toString()) + "/lastSuccessfulBuild/api/xml?xpath=//buildNumber"); return Integer.parseInt(buildXMLContents.replaceAll("<(\\\\)?(/)?buildNumber>", "").trim()); From 63c9bef02d09fc5485922f2bdf1f1f013cfd730f Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Tue, 17 Aug 2021 16:20:36 -0400 Subject: [PATCH 18/42] finish providers, cleanup Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../geyserupdater/common/GeyserUpdater.java | 55 ++++++++++-- .../common/UpdaterBootstrap.java | 11 +++ .../geyserupdater/common/update/PluginId.java | 4 + .../update/RecursiveDownloadManager.java | 10 ++- .../common/update/UpdateManager.java | 40 ++++++--- .../age/provider/JenkinsBuildProvider.java | 36 +++++++- .../common/util/PropertiesUtils.java | 36 -------- .../geyserupdater/common/util/WebUtils.java | 9 +- .../spigot/listeners/SpigotJoinListener.java | 20 ----- .../velocity/VelocityUpdater.java | 87 ++++--------------- .../listeners/VelocityJoinListener.java | 21 ----- 11 files changed, 153 insertions(+), 176 deletions(-) create mode 100644 src/main/java/com/projectg/geyserupdater/common/UpdaterBootstrap.java delete mode 100644 src/main/java/com/projectg/geyserupdater/common/util/PropertiesUtils.java delete mode 100644 src/main/java/com/projectg/geyserupdater/spigot/listeners/SpigotJoinListener.java delete mode 100644 src/main/java/com/projectg/geyserupdater/velocity/listeners/VelocityJoinListener.java diff --git a/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java b/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java index b680dc6d..ab2e4c62 100644 --- a/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java +++ b/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java @@ -6,11 +6,13 @@ import com.projectg.geyserupdater.common.update.PluginId; import com.projectg.geyserupdater.common.update.UpdateManager; import com.projectg.geyserupdater.common.util.FileUtils; -import com.projectg.geyserupdater.common.util.ScriptCreator; import com.projectg.geyserupdater.common.util.SpigotResourceUpdateChecker; +import org.geysermc.connector.GeyserConnector; import java.io.*; +import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardCopyOption; public class GeyserUpdater { @@ -19,23 +21,26 @@ public class GeyserUpdater { public final String version; + private final Path downloadFolder; + private final Path installFolder; private final UpdaterLogger logger; private final UpdaterScheduler scheduler; private final PlayerHandler playerHandler; private final UpdateManager updateManager; - private final UpdaterConfiguration config; public GeyserUpdater(Path dataFolder, Path downloadFolder, + Path installFolder, + UpdaterBootstrap bootstrap, UpdaterLogger logger, UpdaterScheduler scheduler, PlayerHandler playerHandler, - boolean ignoreRestartScriptOption, - boolean loopRestartScript, String version, String geyserArtifact, String floodgateArtifact) throws IOException { + this.downloadFolder = downloadFolder; + this.installFolder = installFolder; this.logger = logger; this.scheduler = scheduler; this.playerHandler = playerHandler; @@ -66,16 +71,12 @@ public GeyserUpdater(Path dataFolder, if (config.isEnableDebug()) { logger.enableDebug(); } - if (ignoreRestartScriptOption) { - // This is basically just for spigot, so that we don't generate a script if the one defined in spigot.yml exists. - config.setGenerateRestartScript(false); - } // Make startup script if enabled if (config.isGenerateRestartScript()) { try { logger.debug("Attempting to create restart script"); - ScriptCreator.createRestartScript(loopRestartScript); + bootstrap.createRestartScript(); } catch (IOException e) { logger.error("Error while creating restart script:"); e.printStackTrace(); @@ -88,6 +89,42 @@ public GeyserUpdater(Path dataFolder, // Manager for updating plugins this.updateManager = new UpdateManager(downloadFolder, scheduler, config.getDownloadTimeLimit()); + + // todo: schedule auto updater + + } + + /** + * Installs all updates to the correct folder, if necessary. Will do nothing if the downloadFolder is the same file as the installFolder. + * @throws IOException If there was a failure moving ALL updates. + */ + public void shutdown() throws IOException { + try { + if (Files.isSameFile(installFolder, downloadFolder)) { + // We don't need to copy anything around + return; + } + } catch (IOException e) { + logger.error("Failed to check if the installFolder is the same as the downloadFolder. Attempting to move files from the downloadFolder to the installFolder anyway..."); + e.printStackTrace(); + } + + // todo: find a way to make sure we are shutdown last + + // This test isn't ideal but it'll work for now + if (!GeyserConnector.getInstance().getBedrockServer().isClosed()) { + throw new UnsupportedOperationException("Cannot replace Geyser before Geyser has shutdown! No updates will be applied."); + } + + UpdaterLogger.getLogger().debug("Installing plugins from the cache."); + Files.walk(downloadFolder, 1).forEach((file) -> { + try { + Files.move(file, installFolder, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + UpdaterLogger.getLogger().error("Failed to copy update " + file + " to the plugins folder."); + e.printStackTrace(); + } + }); } public static GeyserUpdater getInstance() { diff --git a/src/main/java/com/projectg/geyserupdater/common/UpdaterBootstrap.java b/src/main/java/com/projectg/geyserupdater/common/UpdaterBootstrap.java new file mode 100644 index 00000000..524baa96 --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/UpdaterBootstrap.java @@ -0,0 +1,11 @@ +package com.projectg.geyserupdater.common; + +import java.io.IOException; + +public interface UpdaterBootstrap { + + void onDisable(); + + void createRestartScript() throws IOException; + +} diff --git a/src/main/java/com/projectg/geyserupdater/common/update/PluginId.java b/src/main/java/com/projectg/geyserupdater/common/update/PluginId.java index 6a88da2c..cf37e5ff 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/PluginId.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/PluginId.java @@ -31,6 +31,10 @@ public String getLatestFileLink() { return projectLink + branch + "/lastSuccessfulBuild/" + artifactLink; } + public String getLatestBuildNumber() { + return projectLink + branch + "/lastSuccessfulBuild/buildNumber"; + } + /** * @param branch The branch to be used for {@link PluginId#getLatestFileLink()} */ diff --git a/src/main/java/com/projectg/geyserupdater/common/update/RecursiveDownloadManager.java b/src/main/java/com/projectg/geyserupdater/common/update/RecursiveDownloadManager.java index 17e013a4..7fcabec4 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/RecursiveDownloadManager.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/RecursiveDownloadManager.java @@ -29,10 +29,9 @@ public class RecursiveDownloadManager { // Used by the hang checker to cancel the download if necessary @Nullable private Task downloader = null; - // todo: maybe refactor this to use a for loop instead of being recursive? i dunno + // maybe refactor this to use a for loop instead of being recursive? i dunno public RecursiveDownloadManager(GeyserUpdater updater) { - //todo: move outputDirectory to Updatable this.updater = updater; } @@ -53,7 +52,12 @@ private void download(Updatable updatable) { // Create a timer to stop this download from running too long. Either the hang checker is cancelled or the hang checker cancels this. Task hangChecker = scheduleHangChecker(updater, updatable); - WebUtils.downloadFile(updatable.downloadUrl, updatable.outputFile); + try { + WebUtils.downloadFile(updatable.downloadUrl, updatable.outputFile); + } catch (IOException ioException) { + UpdaterLogger.getLogger().error("Failed to download file: " + updatable.downloadUrl + " for " + updatable); + ioException.printStackTrace(); + } hangChecker.cancel(); // Revert everything while having it locked so that the state is always correctly read by original thread diff --git a/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java b/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java index 4ef7928f..34eddd9f 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java @@ -34,7 +34,7 @@ public class UpdateManager { /** * Plugins that are outdated and must be updated */ - protected Set outdatedPlugins = new HashSet<>(); + protected Set outdatedUpdatables = new HashSet<>(); /** * Plugins that are in the queue for download or are being downloaded @@ -72,7 +72,14 @@ public UpdateManager(Path defaultDownloadLocation, UpdaterScheduler scheduler, i // For age comparer BuildNumber buildNumber = new BuildNumber(Integer.parseInt(buildNumberString)); - JenkinsBuildProvider buildProvider = new JenkinsBuildProvider(); + JenkinsBuildProvider buildProvider = null; + try { + buildProvider = new JenkinsBuildProvider(pluginId.getLatestBuildNumber()); + } catch (MalformedURLException e) { + UpdaterLogger.getLogger().error("Failed to create build number checker for " + pluginId + ". Not updating."); + e.printStackTrace(); + continue; + } // File hash comparer IdentityComparer hashComparer = null; @@ -105,20 +112,31 @@ public void register(Updatable updatable) { updatables.add(updatable); } - public void setOutdatedPlugins() { - outdatedPlugins = new HashSet<>(); + /** + * Set the list of {@link Updatable}s which are known to be outdated. Use {@link UpdateManager#getOutdatedUpdatables()} for the result of this check. + * + * @return true if there is at least one {@link Updatable} that is outdated. + */ + public boolean setOutdatedUpdatables() { + boolean outdatedExists = false; + outdatedUpdatables = new HashSet<>(); for (Updatable updatable : updatables) { // todo: make sure we don't run this sync... maybe instantiate GeyserUpdater.class async? if (!updatable.identityComparer.checkIfEquals()) { - outdatedPlugins.add(updatable); + outdatedUpdatables.add(updatable); + outdatedExists = true; } } - UpdaterLogger.getLogger().info("Updates required for plugins: " + outdatedPlugins); + return true; } - public Set getOutdatedPlugins() { - return outdatedPlugins; + /** + * Get the list of {@link Updatable}s which are known to be outdated. Use {@link UpdateManager#setOutdatedUpdatables()} to set the list of outdated Updatables. + * @return The list of {@link Updatable}s + */ + public Set getOutdatedUpdatables() { + return outdatedUpdatables; } /** @@ -126,7 +144,7 @@ public Set getOutdatedPlugins() { * @return true if the download was queued, false if the Updatable is not outdated. */ public boolean update(Updatable updatable) { - if (outdatedPlugins.contains(updatable)) { + if (outdatedUpdatables.contains(updatable)) { downloadManager.queue(updatable); return true; } else { @@ -138,13 +156,13 @@ public boolean update(Updatable updatable) { * Update all outdated Updatables tracked. */ public void updateAll() { - for (Updatable updatable : outdatedPlugins) { + for (Updatable updatable : outdatedUpdatables) { update(updatable); } } protected void finish(Updatable updatable, DownloadResult result) { - outdatedPlugins.remove(updatable); + outdatedUpdatables.remove(updatable); updatablesInQueue.remove(updatable); DownloadResult finalResult = result; diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/provider/JenkinsBuildProvider.java b/src/main/java/com/projectg/geyserupdater/common/update/age/provider/JenkinsBuildProvider.java index ea276bc3..443a4770 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/age/provider/JenkinsBuildProvider.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/age/provider/JenkinsBuildProvider.java @@ -1,15 +1,45 @@ package com.projectg.geyserupdater.common.update.age.provider; +import com.projectg.geyserupdater.common.logger.UpdaterLogger; import com.projectg.geyserupdater.common.update.age.type.BuildNumber; +import com.projectg.geyserupdater.common.util.WebUtils; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; + +/** + * Provides a build number from a given Jenkins link. + */ public class JenkinsBuildProvider implements IdentityProvider { - public JenkinsBuildProvider() { - //todo finish this + private final URL url; + + /** + * Creates a build number provider for a given link. + * @param link A link which onto which "/buildNumber" will be added, which should link to a page that contains only the build number as a plain integer. For example: https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/master/lastSuccessfulBuild/buildNumber + * @throws MalformedURLException If the link provided cannot be converted to a {@link URL} + */ + public JenkinsBuildProvider(String link) throws MalformedURLException { + url = new URL(link + "/buildNumber"); } @Override public BuildNumber getValue() { - return null; + try { + String body = WebUtils.getBody(url); + try { + return new BuildNumber(Integer.parseInt(body)); + } catch (NumberFormatException e) { + UpdaterLogger.getLogger().error("Failed to get a build number from a Jenkins server because an integer was not returned."); + UpdaterLogger.getLogger().error("Body returned: " + body); + e.printStackTrace(); + return null; + } + } catch (IOException e) { + UpdaterLogger.getLogger().error("Failed to get a build number from a Jenkins server:"); + e.printStackTrace(); + return null; + } } } diff --git a/src/main/java/com/projectg/geyserupdater/common/util/PropertiesUtils.java b/src/main/java/com/projectg/geyserupdater/common/util/PropertiesUtils.java deleted file mode 100644 index 19f73ef6..00000000 --- a/src/main/java/com/projectg/geyserupdater/common/util/PropertiesUtils.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.projectg.geyserupdater.common.util; - -import com.projectg.geyserupdater.common.update.JenkinsUpdatable; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Properties; - -public class PropertiesUtils { - - /** - * Compare the local build number to the latest build number on Geyser CI - * - * @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(JenkinsUpdatable updatable) throws IOException { - int jenkinsBuildNumber = WebUtils.getLatestGeyserBuildNumberFromJenkins(updatable.branch); - int localBuildNumber = updatable.buildNumber; - // 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; - } - - - public static String getBranch(Properties properties) { - properties.get - } - - public static Properties getProperties(InputStream is) throws IOException { - Properties properties = new Properties(); - properties.load(is); - return properties; - } -} diff --git a/src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java b/src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java index 00595bab..f3b30d7a 100644 --- a/src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java +++ b/src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java @@ -24,15 +24,18 @@ public class WebUtils { * @param reqURL URL to fetch * @return Body contents */ - public static String getBody(String reqURL) throws IOException { - URL url = new URL(reqURL); - HttpURLConnection con = (HttpURLConnection) url.openConnection(); + public static String getBody(URL reqURL) throws IOException { + HttpURLConnection con = (HttpURLConnection) reqURL.openConnection(); con.setRequestMethod("GET"); con.setRequestProperty("User-Agent", "GeyserUpdater-" + GeyserUpdater.getInstance().version); // Otherwise Java 8 fails on checking updates return connectionToString(con); } + public static String getBody(String reqURL) throws IOException { + return getBody(new URL(reqURL)); + } + /** * Makes a web request to the given URL and returns the body as a {@link JsonNode}. * diff --git a/src/main/java/com/projectg/geyserupdater/spigot/listeners/SpigotJoinListener.java b/src/main/java/com/projectg/geyserupdater/spigot/listeners/SpigotJoinListener.java deleted file mode 100644 index 6e21a573..00000000 --- a/src/main/java/com/projectg/geyserupdater/spigot/listeners/SpigotJoinListener.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.projectg.geyserupdater.spigot.listeners; - -import com.projectg.geyserupdater.common.util.FileUtils; - -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerJoinEvent; - -public class SpigotJoinListener implements Listener { - - @EventHandler - public void onPlayerJoin(PlayerJoinEvent event) { - // We allow a cached result of maximum age 30 minutes to be used - if (FileUtils.checkFile("plugins/update/Geyser-Spigot.jar", true)) { - if (event.getPlayer().hasPermission("gupdater.geyserupdate")) { - event.getPlayer().sendMessage("[GeyserUpdater] A new Geyser build has been downloaded! Please restart the server in order to use the updated build!"); - } - } - } -} \ No newline at end of file diff --git a/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java b/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java index 19b36f27..82046e8e 100644 --- a/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java +++ b/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java @@ -2,9 +2,10 @@ import com.google.inject.Inject; import com.projectg.geyserupdater.common.GeyserUpdater; +import com.projectg.geyserupdater.common.UpdaterBootstrap; import com.projectg.geyserupdater.common.logger.UpdaterLogger; +import com.projectg.geyserupdater.common.util.ScriptCreator; import com.projectg.geyserupdater.velocity.command.GeyserUpdateCommand; -import com.projectg.geyserupdater.velocity.listeners.VelocityJoinListener; import com.projectg.geyserupdater.velocity.logger.Slf4jUpdaterLogger; import com.projectg.geyserupdater.velocity.util.bstats.Metrics; import com.velocitypowered.api.event.PostOrder; @@ -15,24 +16,19 @@ import com.velocitypowered.api.plugin.Plugin; import com.velocitypowered.api.plugin.annotation.DataDirectory; import com.velocitypowered.api.proxy.ProxyServer; -import org.geysermc.connector.GeyserConnector; import org.slf4j.Logger; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; -import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; @Plugin(id = "geyserupdater", name = "GeyserUpdater", version = VelocityUpdater.VERSION, description = "Automatically or manually downloads new builds of Geyser and applies them on server restart.", authors = {"Jens"}, dependencies = {@Dependency(id = "geyser")}) -public class VelocityUpdater { +public class VelocityUpdater implements UpdaterBootstrap { public static final String VERSION = "1.6.0"; private static VelocityUpdater PLUGIN; + private final GeyserUpdater updater; private final ProxyServer server; private final Path dataDirectory; private final Metrics.Factory metricsFactory; @@ -44,14 +40,14 @@ public VelocityUpdater(ProxyServer server, Logger baseLogger, @DataDirectory fin this.dataDirectory = folder; this.metricsFactory = metricsFactory; - new GeyserUpdater( + updater = new GeyserUpdater( dataDirectory, dataDirectory.resolve("BuildUpdate"), + dataDirectory.getParent(), + this, new Slf4jUpdaterLogger(baseLogger), new VelocityScheduler(this), new VelocityPlayerHandler(server), - false, - true, VERSION, "/artifact/bootstrap/velocity/target/Geyser-Velocity.jar", "/artifact/velocity/target/floodgate-velocity.jar" @@ -64,75 +60,26 @@ public void onProxyInitialization(ProxyInitializeEvent event) { // Register our only command server.getCommandManager().register("geyserupdate", new GeyserUpdateCommand()); - // Player alert if a restart is required when they join - server.getEventManager().register(this, new VelocityJoinListener()); - } @Subscribe(order = PostOrder.LAST) public void onShutdown(ProxyShutdownEvent event) { - // This test isn't ideal but it'll work for now - if (!GeyserConnector.getInstance().getBedrockServer().isClosed()) { - throw new UnsupportedOperationException("Cannot shutdown GeyserUpdater before Geyser has shutdown! No updates will be applied."); - } + onDisable(); + } + + @Override + public void onDisable() { try { - moveGeyserJar(); - for (int i = 0; i <= 2; i++) { - 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(); - try { - Thread.sleep(50); - } catch (InterruptedException interruptException) { - UpdaterLogger.getLogger().error("Failed to delay an additional attempt!"); - interruptException.printStackTrace(); - } - } - } + updater.shutdown(); } catch (IOException e) { - UpdaterLogger.getLogger().error("An I/O error occurred while attempting to replace the current Geyser jar with the new one!"); + UpdaterLogger.getLogger().error("Failed to install ALL updates:"); e.printStackTrace(); } } - /** - * Replace the Geyser jar in the plugin folder with the one in GeyserUpdater/BuildUpdate - * Should only be called once Geyser has been disabled - * - * @throws IOException if there was an IO failure - */ - public void moveGeyserJar() throws IOException { - // Moving Geyser Jar to Plugins folder "Overwriting". - File fileToCopy = new File("plugins/GeyserUpdater/BuildUpdate/Geyser-Velocity.jar"); //todo: improve - if (fileToCopy.exists()) { - UpdaterLogger.getLogger().debug("Moving the new Geyser jar to the plugins folder."); - FileInputStream input = new FileInputStream(fileToCopy); - File newFile = new File("plugins/Geyser-Velocity.jar"); //todo: improve - FileOutputStream output = new FileOutputStream(newFile); - byte[] buf = new byte[1024]; - int bytesRead; - while ((bytesRead = input.read(buf)) > 0) { - output.write(buf, 0, bytesRead); - } - input.close(); - output.close(); - } else { - UpdaterLogger.getLogger().debug("Found no new Geyser jar to copy to the plugins folder."); - } - } - - /** - * Delete the Geyser jar in GeyserUpdater/BuildUpdate - * - * @throws IOException if it failed to delete - */ - private void deleteGeyserJar() throws IOException { - UpdaterLogger.getLogger().debug("Deleting the Geyser jar in the BuildUpdate folder if it exists"); - Path file = Paths.get("plugins/GeyserUpdater/BuildUpdate/Geyser-Velocity.jar"); //todo: improve - Files.deleteIfExists(file); + @Override + public void createRestartScript() throws IOException { + ScriptCreator.createRestartScript(true); } public static VelocityUpdater getPlugin() { diff --git a/src/main/java/com/projectg/geyserupdater/velocity/listeners/VelocityJoinListener.java b/src/main/java/com/projectg/geyserupdater/velocity/listeners/VelocityJoinListener.java deleted file mode 100644 index 70b404fa..00000000 --- a/src/main/java/com/projectg/geyserupdater/velocity/listeners/VelocityJoinListener.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.projectg.geyserupdater.velocity.listeners; - -import com.projectg.geyserupdater.common.util.FileUtils; - -import com.velocitypowered.api.event.Subscribe; -import com.velocitypowered.api.event.connection.PostLoginEvent; - -import net.kyori.adventure.text.Component; - -public class VelocityJoinListener { - - @Subscribe - public void onPostLogin(PostLoginEvent event) { - // We allow a cached result of maximum age 30 minutes to be used - if (FileUtils.checkFile("plugins/GeyserUpdater/BuildUpdate/Geyser-Velocity.jar",true)) { - if (event.getPlayer().hasPermission("gupdater.geyserupdate")) { - event.getPlayer().sendMessage(Component.text("[GeyserUpdater] A new Geyser build has been downloaded! Please restart Velocity in order to use the updated build!")); - } - } - } -} From 206ae1b4f0ebcde1df882474180b32210665ca27 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Wed, 18 Aug 2021 17:29:00 -0400 Subject: [PATCH 19/42] More cleanup, changes to config Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- pom.xml | 8 +--- .../common/config/UpdaterConfiguration.java | 44 ++++++++++++------- .../common/scheduler/UpdaterScheduler.java | 14 +++--- .../geyserupdater/common/util/WebUtils.java | 12 ----- .../velocity/VelocityUpdater.java | 2 +- .../util/GeyserVelocityDownloader.java | 1 - src/main/resources/config.yml | 19 ++++++-- 7 files changed, 53 insertions(+), 47 deletions(-) diff --git a/pom.xml b/pom.xml index a1fce616..04dbfc2d 100644 --- a/pom.xml +++ b/pom.xml @@ -80,13 +80,7 @@ org.geysermc connector - 1.4.0-SNAPSHOT - provided - - - org.geysermc.floodgate - common - 2.0-SNAPSHOT + 1.4.1-SNAPSHOT provided diff --git a/src/main/java/com/projectg/geyserupdater/common/config/UpdaterConfiguration.java b/src/main/java/com/projectg/geyserupdater/common/config/UpdaterConfiguration.java index 09075583..f3ddf5a6 100644 --- a/src/main/java/com/projectg/geyserupdater/common/config/UpdaterConfiguration.java +++ b/src/main/java/com/projectg/geyserupdater/common/config/UpdaterConfiguration.java @@ -4,23 +4,19 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Map; + @JsonIgnoreProperties(ignoreUnknown = true) @JsonFormat(with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES) @SuppressWarnings("FieldMayBeFinal") // Must be non-final for Jackson to work public class UpdaterConfiguration { - public static int DEFAULT_CONFIG_VERSION = 2; - - @JsonProperty(value = "Auto-Update-Geyser") - private boolean autoUpdateGeyser = false; - public boolean isAutoUpdateGeyser() { - return autoUpdateGeyser; - } + public static int DEFAULT_CONFIG_VERSION = 3; - @JsonProperty(value = "Auto-Update-Floodgate") - private boolean autoUpdateFloodgate = false; - public boolean isAutoUpdateFloodgate() { - return autoUpdateFloodgate; + @JsonProperty(value = "default-updates") + private Map defaultUpdates; + public Map getDefaultUpdates() { + return defaultUpdates; } @JsonProperty(value = "Auto-Update-Interval") @@ -40,9 +36,6 @@ public boolean isRestartServer() { public boolean isGenerateRestartScript() { return generateRestartScript; } - public void setGenerateRestartScript(boolean generate) { - generateRestartScript = generate; - } @JsonProperty(value = "Restart-Message-Players") private String restartMessage = "§2This server will be restarting in 10 seconds!"; @@ -63,7 +56,7 @@ public boolean isEnableDebug() { } @JsonProperty(value = "Config-Version", required = true) - private int configVersion = 2; + private int configVersion = 3; public int getConfigVersion() { return configVersion; } @@ -71,4 +64,25 @@ public int getConfigVersion() { public boolean isIncorrectVersion() { return getConfigVersion() != DEFAULT_CONFIG_VERSION; } + + public static final class DefaultUpdate { + + @JsonProperty(value = "enable", required = true) + private boolean enable = false; + public boolean isEnable() { + return enable; + } + + @JsonProperty(value = "auto-check", required = true) + private boolean autoCheck = false; + public boolean isAutoCheck() { + return autoCheck; + } + + @JsonProperty(value = "auto-update", required = true) + private boolean autoUpdate = false; + public boolean isAutoUpdate() { + return autoUpdate; + } + } } diff --git a/src/main/java/com/projectg/geyserupdater/common/scheduler/UpdaterScheduler.java b/src/main/java/com/projectg/geyserupdater/common/scheduler/UpdaterScheduler.java index 3f414dde..950defbb 100644 --- a/src/main/java/com/projectg/geyserupdater/common/scheduler/UpdaterScheduler.java +++ b/src/main/java/com/projectg/geyserupdater/common/scheduler/UpdaterScheduler.java @@ -7,9 +7,9 @@ public interface UpdaterScheduler { /** - * Schedule a Runnable to be run. + * Schedule a Runnable to be run on a new thread. * @param runnable The Runnable - * @param async True to run the task async (Disregarded for BungeeCord, Velocity) + * @param async true to run the Runnable off the main server thread, false to run it on the main server thread. Disregarded for BungeeCord and Velocity. */ default Task run(@Nonnull Runnable runnable, boolean async) { Objects.requireNonNull(runnable); @@ -17,9 +17,9 @@ default Task run(@Nonnull Runnable runnable, boolean async) { } /** - * Schedule a Runnable to be run. + * Schedule a Runnable to be run on a new thread. * @param runnable The Runnable - * @param async True to run the task async (Disregarded for BungeeCord, Velocity) + * @param async true to run the Runnable off the main server thread, false to run it on the main server thread. Disregarded for BungeeCord and Velocity. * @param delay The delay in milliseconds. A value less than zero should be considered unsafe. */ default Task runDelayed(@Nonnull Runnable runnable, boolean async, long delay, TimeUnit unit) { @@ -30,7 +30,7 @@ default Task runDelayed(@Nonnull Runnable runnable, boolean async, long delay, T /** * Schedule a Runnable to be run. * @param runnable The Runnable - * @param async True to run the task async (Disregarded for BungeeCord, Velocity) + * @param async true to run the Runnable off the main server thread, false to run it on the main server thread. Disregarded for BungeeCord and Velocity. * @param repeat The repeat period, in milliseconds. A value of 0 or less will only run the Runnable once. A value less than zero should be considered unsafe. */ default Task runTimer(@Nonnull Runnable runnable, boolean async, long repeat, TimeUnit unit) { @@ -39,9 +39,9 @@ default Task runTimer(@Nonnull Runnable runnable, boolean async, long repeat, Ti } /** - * Schedule a Runnable to be run. + * Schedule a Runnable to be run on a new thread. * @param runnable The Runnable - * @param async True to run the task async (Disregarded for BungeeCord, Velocity) + * @param async true to run the Runnable off the main server thread, false to run it on the main server thread. Disregarded for BungeeCord and Velocity. * @param delay The delay in milliseconds. A value less than zero should be considered unsafe. * @param repeat The repeat period, in milliseconds. A value of 0 or less will only run the Runnable once. A value less than zero should be considered unsafe. */ diff --git a/src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java b/src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java index f3b30d7a..33be47a3 100644 --- a/src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java +++ b/src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java @@ -95,16 +95,4 @@ private static String connectionToString(HttpURLConnection con) throws IOExcepti return content.toString(); } - - /** Get the latest build number of a given branch of Geyser from jenkins CI - * - * @param branchLink Example: https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/master - * @return the latest build number - * @throws IOException if an exception occurred parsing the branchLink or there was a failure in the web request - */ - public static int getLatestGeyserBuildNumberFromJenkins(String branchLink) throws IOException { - // todo use json - String buildXMLContents = WebUtils.getBody(URLEncoder.encode(branchLink, StandardCharsets.UTF_8.toString()) + "/lastSuccessfulBuild/api/xml?xpath=//buildNumber"); - return Integer.parseInt(buildXMLContents.replaceAll("<(\\\\)?(/)?buildNumber>", "").trim()); - } } diff --git a/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java b/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java index 82046e8e..032d8bed 100644 --- a/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java +++ b/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java @@ -50,7 +50,7 @@ public VelocityUpdater(ProxyServer server, Logger baseLogger, @DataDirectory fin new VelocityPlayerHandler(server), VERSION, "/artifact/bootstrap/velocity/target/Geyser-Velocity.jar", - "/artifact/velocity/target/floodgate-velocity.jar" + "/artifact/bootstrap/velocity/target/floodgate-velocity.jar" ); } 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 11a05313..7234eaf9 100644 --- a/src/main/java/com/projectg/geyserupdater/velocity/util/GeyserVelocityDownloader.java +++ b/src/main/java/com/projectg/geyserupdater/velocity/util/GeyserVelocityDownloader.java @@ -2,7 +2,6 @@ import com.projectg.geyserupdater.common.logger.UpdaterLogger; import com.projectg.geyserupdater.common.util.FileUtils; -import com.projectg.geyserupdater.common.util.GeyserProperties; import com.projectg.geyserupdater.velocity.VelocityUpdater; import com.velocitypowered.api.proxy.Player; diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index dbeb50e6..a4919f9f 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -8,12 +8,26 @@ auto-update-geyser: false auto-update-floodgate: false +default-updates: + geyser: + enable: true + auto-check: true + auto-update: false + floodgate: + enable: false + auto-check: true + auto-update: false + # The interval in hours between each auto update check. auto-update-interval: 24 +# The maximum amount of seconds that a download is allowed to run for. Increase if you are running into issues on a slow internet connection. +download-time-limit: 180 + # If enabled, GeyserUpdater will attempt to restart the server 10 seconds after a new version of Geyser has been successfully downloaded. # If you aren't using a hosting provider or a server wrapper, you will need a restart script. auto-restart-server: false + # When enabled, GeyserUpdater will automatically generate a restart script for you. If you are using CraftBukkit or a proxy # you will need to use the generated script to start your server! If you are using a hosting provider or a server wrapper you probably don't need this. auto-script-generating: false @@ -21,11 +35,8 @@ auto-script-generating: false # Configure the message that is sent to all online players warning them that the server will be restarting in 10 seconds. restart-message-players: "§2This server will be restarting in 10 seconds!" -# The maximum amount of seconds that a download is allowed to run for. Increase if you are running into issues on a slow internet connection. -download-time-limit: 180 - # Enable debug logging enable-debug: false # Please do not change this version value! -config-version: 2 \ No newline at end of file +config-version: 3 \ No newline at end of file From dfb97e4f59034a91c81903869350ebc3fe703614 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Thu, 19 Aug 2021 16:37:14 -0400 Subject: [PATCH 20/42] dump changes Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../geyserupdater/common/GeyserUpdater.java | 8 +- .../common/config/UpdaterConfiguration.java | 8 +- .../common/update/DownloadManager.java | 24 +-- .../update/{age => }/DownloadResult.java | 3 +- .../geyserupdater/common/update/PluginId.java | 45 +++-- .../geyserupdater/common/update/Status.java | 20 +++ .../common/update/Updatable.java | 25 ++- .../common/update/UpdateManager.java | 156 +++++++++++------- .../common/update/age/IdentityComparer.java | 2 +- src/main/resources/config.yml | 13 +- 10 files changed, 188 insertions(+), 116 deletions(-) rename src/main/java/com/projectg/geyserupdater/common/update/{age => }/DownloadResult.java (52%) create mode 100644 src/main/java/com/projectg/geyserupdater/common/update/Status.java diff --git a/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java b/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java index ab2e4c62..0af28625 100644 --- a/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java +++ b/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java @@ -83,15 +83,15 @@ public GeyserUpdater(Path dataFolder, } } + // Set the enable/autoCheck/autoUpdate values + PluginId.loadSettings(config); + // Set the correct download links for geyser and floodgate PluginId.GEYSER.setArtifact(geyserArtifact); PluginId.FLOODGATE.setArtifact(floodgateArtifact); // Manager for updating plugins - this.updateManager = new UpdateManager(downloadFolder, scheduler, config.getDownloadTimeLimit()); - - // todo: schedule auto updater - + this.updateManager = new UpdateManager(downloadFolder, scheduler, config); } /** diff --git a/src/main/java/com/projectg/geyserupdater/common/config/UpdaterConfiguration.java b/src/main/java/com/projectg/geyserupdater/common/config/UpdaterConfiguration.java index f3ddf5a6..19223afa 100644 --- a/src/main/java/com/projectg/geyserupdater/common/config/UpdaterConfiguration.java +++ b/src/main/java/com/projectg/geyserupdater/common/config/UpdaterConfiguration.java @@ -25,6 +25,12 @@ public int getAutoUpdateInterval() { return autoUpdateInterval; } + @JsonProperty(value = "delete-on-fail") + private boolean deleteOnFail = true; + public boolean isDeleteOnFail() { + return deleteOnFail; + } + @JsonProperty(value = "Auto-Restart-Server") private boolean restartServer = false; public boolean isRestartServer() { @@ -44,7 +50,7 @@ public String getRestartMessage() { } @JsonProperty(value = "download-time-limit") - private int downloadTimeLimit = 180; + private int downloadTimeLimit = 300; public int getDownloadTimeLimit() { return downloadTimeLimit; } diff --git a/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java b/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java index 695952ac..400c36c8 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java @@ -3,12 +3,10 @@ import com.projectg.geyserupdater.common.logger.UpdaterLogger; import com.projectg.geyserupdater.common.scheduler.Task; import com.projectg.geyserupdater.common.scheduler.UpdaterScheduler; -import com.projectg.geyserupdater.common.update.age.DownloadResult; import com.projectg.geyserupdater.common.util.WebUtils; import javax.annotation.Nullable; import java.io.IOException; -import java.nio.file.Files; import java.util.LinkedList; import java.util.List; import java.util.concurrent.TimeUnit; @@ -49,8 +47,8 @@ private void downloadAll() { // Run the download on a new thread this.downloader = scheduler.run(() -> { - for (int i = 0; ; i++) { - Updatable updatable = queue.get(i); + while (true) { + Updatable updatable = queue.get(0); if (updatable == null) { break; } @@ -62,20 +60,19 @@ private void downloadAll() { try { WebUtils.downloadFile(updatable.downloadUrl, updatable.outputFile); } catch (IOException e) { - UpdaterLogger.getLogger().error("Failed to download file at location " + updatable.outputFile + " with URL: " + updatable.downloadUrl); + UpdaterLogger.getLogger().error("Caught exception while downloading file " + updatable.outputFile + " with URL: " + updatable.downloadUrl); e.printStackTrace(); updateManager.finish(updatable, DownloadResult.UNKNOWN_FAIL); continue; } hangChecker.cancel(); + queue.remove(0); updateManager.finish(updatable, DownloadResult.SUCCESS); } // Revert everything while having it locked so that the state is always correctly read by a different thread synchronized (this) { - // Clear the queue here so that the for loop above doesn't get messed up - queue.clear(); isDownloading = false; currentUpdate = null; downloader = null; @@ -104,19 +101,10 @@ private Task scheduleHangChecker(Updatable updatable) { downloader = null; } - updateManager.finish(updatable, DownloadResult.TIMEOUT); - - UpdaterLogger logger = UpdaterLogger.getLogger(); - logger.error("The download queue has been stopped and cleared because the download for " + updatable + " took longer than " + downloadTimeLimit + + UpdaterLogger.getLogger().error("The download queue has been stopped and cleared because the download for " + updatable + " took longer than " + downloadTimeLimit + " seconds. Increase the download-time-limit in the config if you have a slow internet connection."); - try { - boolean deletedFailedFile = Files.deleteIfExists(updatable.outputFile); - logger.debug("Failed download for " + updatable + " had a file?: " + deletedFailedFile); - } catch (IOException e) { - logger.error("Failed to delete failed download file of " + updatable); - e.printStackTrace(); - } + updateManager.finish(updatable, DownloadResult.TIMEOUT); } }, true, downloadTimeLimit, TimeUnit.SECONDS); } diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/DownloadResult.java b/src/main/java/com/projectg/geyserupdater/common/update/DownloadResult.java similarity index 52% rename from src/main/java/com/projectg/geyserupdater/common/update/age/DownloadResult.java rename to src/main/java/com/projectg/geyserupdater/common/update/DownloadResult.java index 0e0745dc..f838d345 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/age/DownloadResult.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/DownloadResult.java @@ -1,8 +1,7 @@ -package com.projectg.geyserupdater.common.update.age; +package com.projectg.geyserupdater.common.update; public enum DownloadResult { SUCCESS, TIMEOUT, - HASH_FAIl, UNKNOWN_FAIL; } diff --git a/src/main/java/com/projectg/geyserupdater/common/update/PluginId.java b/src/main/java/com/projectg/geyserupdater/common/update/PluginId.java index cf37e5ff..7b4878a9 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/PluginId.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/PluginId.java @@ -1,6 +1,6 @@ package com.projectg.geyserupdater.common.update; -import com.projectg.geyserupdater.common.GeyserUpdater; +import com.projectg.geyserupdater.common.config.UpdaterConfiguration; public enum PluginId { GEYSER("https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/", "org.geysermc.connector.GeyserConnector"), @@ -11,19 +11,32 @@ public enum PluginId { */ private final String projectLink; - private String branch; - private String artifactLink; - /** * A class from the given plugin */ private final String pluginClassName; + private String branch; + private String artifactLink; + + private boolean enable = false; + private boolean autoCheck = false; + private boolean autoUpdate = false; PluginId(String link, String pluginClassName) { this.projectLink = link; this.pluginClassName = pluginClassName; } + public boolean isEnable() { + return enable; + } + public boolean isAutoCheck() { + return autoCheck; + } + public boolean isAutoUpdate() { + return autoUpdate; + } + /** * @return The download link. Not usable if {@link PluginId#setArtifact(String)} has not been called. */ @@ -43,10 +56,10 @@ public void setBranch(String branch) { } /** - * @param artifactLink The artifact link. `artifact/bootstrap/spigot/target/Geyser-Spigot.jar` for example. + * @param artifactLink The artifact link. `bootstrap/spigot/target/Geyser-Spigot.jar` for example. */ public void setArtifact(String artifactLink) { - this.artifactLink = artifactLink; + this.artifactLink = "artifact/" + artifactLink; } /** @@ -61,16 +74,18 @@ public Class getPluginClass() { } /** - * @return True if the plugin is enabled in {@link com.projectg.geyserupdater.common.config.UpdaterConfiguration} + * Load the enable, autoCheck, and autoUpdate configuration settings into the enum values. + * {@link UpdaterConfiguration#getDefaultUpdates()} should contain entries whose keys are equal an enum value's name in lowercase + * @param config The config to load from */ - public boolean isEnabled() { - if (this == GEYSER) { - return GeyserUpdater.getInstance().getConfig().isAutoUpdateGeyser(); - } else if (this == FLOODGATE) { - return GeyserUpdater.getInstance().getConfig().isAutoUpdateFloodgate(); - } else { - //todo fix this bs - return false; + public static void loadSettings(UpdaterConfiguration config) { + for (PluginId plugin : PluginId.values()) { + UpdaterConfiguration.DefaultUpdate settings = config.getDefaultUpdates().get(plugin.name().toLowerCase()); + if (settings != null) { + plugin.enable = settings.isEnable(); + plugin.autoCheck = settings.isAutoCheck(); + plugin.autoUpdate = settings.isAutoUpdate(); + } } } } diff --git a/src/main/java/com/projectg/geyserupdater/common/update/Status.java b/src/main/java/com/projectg/geyserupdater/common/update/Status.java new file mode 100644 index 00000000..4a299f31 --- /dev/null +++ b/src/main/java/com/projectg/geyserupdater/common/update/Status.java @@ -0,0 +1,20 @@ +package com.projectg.geyserupdater.common.update; + +public enum Status { + /** + * The Updatable has not been checked, or the last time it was checked it was not outdated. Another check may find that it is outdated. + */ + CURRENT, + /** + * The Updatable is outdated but is not being downloaded. + */ + OUTDATED, + /** + * The Updatable is outdated and is being downloaded. + */ + DOWNLOADING, + /** + * The Updatable is outdated but it has been downloaded. + */ + DOWNLOADED; +} diff --git a/src/main/java/com/projectg/geyserupdater/common/update/Updatable.java b/src/main/java/com/projectg/geyserupdater/common/update/Updatable.java index 09b04eed..285f91e9 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/Updatable.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/Updatable.java @@ -15,24 +15,33 @@ public class Updatable { @Nullable public final IdentityComparer hashComparer; @Nonnull public final String downloadUrl; @Nonnull public final Path outputFile; + public final boolean autoCheck; + public final boolean autoUpdate; /** * Immutable container for information regarding how to update something - * @param pluginIdentity The plugin name, which can be used to identify the plugin. + * @param name The name * @param identityComparer The {@link IdentityComparer} to check if the plugin is outdated * @param hashComparer The {@link IdentityComparer} to check if the hash of the downloaded file is acceptable. * @param downloadUrl The complete download link of the plugin * @param file If the Path is a file, the download will be written to that file. If the Path is a directory, the file will be written to that directory, and the filename will deduced from the link provided. */ - public Updatable(@Nonnull String pluginIdentity, @Nonnull IdentityComparer identityComparer, @Nullable IdentityComparer hashComparer, @Nonnull String downloadUrl, @Nonnull Path file) { - Objects.requireNonNull(pluginIdentity); - Objects.requireNonNull(identityComparer); + public Updatable(@Nonnull String name, + @Nonnull IdentityComparer identityComparer, + @Nullable IdentityComparer hashComparer, + @Nonnull String downloadUrl, + @Nonnull Path file, + boolean autoCheck, + boolean autoUpdate) { + + this.pluginIdentity = Objects.requireNonNull(name); + this.identityComparer = Objects.requireNonNull(identityComparer); + this.hashComparer = hashComparer; Objects.requireNonNull(downloadUrl); Objects.requireNonNull(file); + this.autoCheck = autoCheck; + this.autoUpdate = autoUpdate; - this.pluginIdentity = pluginIdentity; - this.identityComparer = identityComparer; - this.hashComparer = hashComparer; // Remove / from the end of the link if necessary if (downloadUrl.endsWith("/")) { @@ -43,7 +52,7 @@ public Updatable(@Nonnull String pluginIdentity, @Nonnull IdentityComparer // Make sure the file linked is a jar if (!downloadUrl.endsWith(".jar")) { - throw new IllegalArgumentException("Download URL provided for plugin '" + pluginIdentity + "' must direct to a file that ends in '.jar'"); + throw new IllegalArgumentException("Download URL provided for plugin '" + name + "' must direct to a file that ends in '.jar'"); } // Figure out the output file name if necessary diff --git a/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java b/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java index 34eddd9f..5f99d72f 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java @@ -1,8 +1,8 @@ package com.projectg.geyserupdater.common.update; +import com.projectg.geyserupdater.common.config.UpdaterConfiguration; import com.projectg.geyserupdater.common.logger.UpdaterLogger; import com.projectg.geyserupdater.common.scheduler.UpdaterScheduler; -import com.projectg.geyserupdater.common.update.age.DownloadResult; import com.projectg.geyserupdater.common.update.age.IdentityComparer; import com.projectg.geyserupdater.common.update.age.provider.FileHashProvider; import com.projectg.geyserupdater.common.update.age.provider.JenkinsBuildProvider; @@ -14,18 +14,22 @@ import java.io.InputStream; import java.net.MalformedURLException; import java.net.URISyntaxException; +import java.nio.file.Files; import java.nio.file.Path; -import java.util.HashSet; -import java.util.Properties; -import java.util.Set; +import java.util.*; +import java.util.concurrent.TimeUnit; public class UpdateManager { + // todo: make sure we keep track of ones that have been updated, or remove it from the updatables list + /** * The {@link DownloadManager} to use for downloading new versions of plugins. */ private final DownloadManager downloadManager; + private final Map registry = new HashMap<>(); + /** * All tracked plugins */ @@ -34,20 +38,24 @@ public class UpdateManager { /** * Plugins that are outdated and must be updated */ - protected Set outdatedUpdatables = new HashSet<>(); + private Set outdatedUpdatables = new HashSet<>(); /** * Plugins that are in the queue for download or are being downloaded */ - protected final Set updatablesInQueue = new HashSet<>(); + private final Set updatablesInQueue = new HashSet<>(); + private final UpdaterConfiguration config; - public UpdateManager(Path defaultDownloadLocation, UpdaterScheduler scheduler, int downloadTimeLimit) { - this.downloadManager = new DownloadManager(this, scheduler, downloadTimeLimit); + public UpdateManager(Path defaultDownloadLocation, UpdaterScheduler scheduler, UpdaterConfiguration config) { + this.config = config; + this.downloadManager = new DownloadManager(this, scheduler, config.getDownloadTimeLimit()); UpdaterLogger logger = UpdaterLogger.getLogger(); + // If we must schedule a checker to check for updates on an interval + boolean updateCheckerRequired = false; for (PluginId pluginId : PluginId.values()) { - if (pluginId.isEnabled()) { + if (pluginId.isEnable()) { // Get the git.properties InputStream is = pluginId.getPluginClass().getResourceAsStream("git.properties"); if (is == null) { @@ -70,9 +78,11 @@ public UpdateManager(Path defaultDownloadLocation, UpdaterScheduler scheduler, i continue; } + pluginId.setBranch(branch); + // For age comparer BuildNumber buildNumber = new BuildNumber(Integer.parseInt(buildNumberString)); - JenkinsBuildProvider buildProvider = null; + JenkinsBuildProvider buildProvider; try { buildProvider = new JenkinsBuildProvider(pluginId.getLatestBuildNumber()); } catch (MalformedURLException e) { @@ -92,16 +102,28 @@ public UpdateManager(Path defaultDownloadLocation, UpdaterScheduler scheduler, i e.printStackTrace(); } + boolean autoCheck = pluginId.isAutoCheck(); + if (autoCheck) { + updateCheckerRequired = true; + } + register(new Updatable( pluginId.name(), new IdentityComparer<>(buildNumber, buildProvider), hashComparer, pluginId.getLatestFileLink(), - defaultDownloadLocation)); + defaultDownloadLocation, + autoCheck, + pluginId.isAutoUpdate())); } } // Load extra stuff from the config if we wanted, I guess + + // Check for updates on a schedule, if at least one updatable requires it + if (updateCheckerRequired) { + scheduleUpdateChecker(scheduler, config.getAutoUpdateInterval()); + } } /** @@ -109,70 +131,88 @@ public UpdateManager(Path defaultDownloadLocation, UpdaterScheduler scheduler, i * @param updatable The {@link Updatable} to be updated */ public void register(Updatable updatable) { - updatables.add(updatable); + registry.put(updatable, Status.CURRENT); } + /** - * Set the list of {@link Updatable}s which are known to be outdated. Use {@link UpdateManager#getOutdatedUpdatables()} for the result of this check. - * - * @return true if there is at least one {@link Updatable} that is outdated. + * Potentially blocking */ - public boolean setOutdatedUpdatables() { - boolean outdatedExists = false; - outdatedUpdatables = new HashSet<>(); - for (Updatable updatable : updatables) { - // todo: make sure we don't run this sync... maybe instantiate GeyserUpdater.class async? - if (!updatable.identityComparer.checkIfEquals()) { - outdatedUpdatables.add(updatable); - outdatedExists = true; - } + public boolean isOutdated(Updatable updatable) { + Status status = Objects.requireNonNull(registry.get(updatable)); + switch (status) { + case CURRENT: + return !updatable.identityComparer.checkIfEquals(); + case OUTDATED: + return true; + default: + return false; } - - return true; } /** - * Get the list of {@link Updatable}s which are known to be outdated. Use {@link UpdateManager#setOutdatedUpdatables()} to set the list of outdated Updatables. - * @return The list of {@link Updatable}s + * Blocking */ - public Set getOutdatedUpdatables() { - return outdatedUpdatables; - } + protected void finish(Updatable updatable, DownloadResult result) { + if (registry.get(updatable) != Status.DOWNLOADING) { + throw new IllegalStateException("Cannot finish an Updatable if its current status is not DOWNLOADING"); + } + UpdaterLogger logger = UpdaterLogger.getLogger(); - /** - * Update an outdated Updatable - * @return true if the download was queued, false if the Updatable is not outdated. - */ - public boolean update(Updatable updatable) { - if (outdatedUpdatables.contains(updatable)) { - downloadManager.queue(updatable); - return true; + if (updatable.hashComparer == null) { + if (result == DownloadResult.SUCCESS) { + // cant check hash, but the download result is success + Objects.requireNonNull(registry.replace(updatable, Status.DOWNLOADED)); + return; + } } else { - return false; + if (updatable.hashComparer.checkIfEquals()) { + // hash is correct + Objects.requireNonNull(registry.replace(updatable, Status.DOWNLOADED)); + return; + } } - } - /** - * Update all outdated Updatables tracked. - */ - public void updateAll() { - for (Updatable updatable : outdatedUpdatables) { - update(updatable); + // Hash is not correct, or cannot check hash and there was a fail + if (config.isDeleteOnFail()) { + UpdaterLogger.getLogger().warn("The file hash of the downloaded file did not match the hash provided online for " + updatable + ". Deleting file."); + try { + Files.deleteIfExists(updatable.outputFile); + } catch (IOException e) { + logger.error("Failed to delete failed download file of " + updatable); + e.printStackTrace(); + } } } - protected void finish(Updatable updatable, DownloadResult result) { - outdatedUpdatables.remove(updatable); - updatablesInQueue.remove(updatable); - - DownloadResult finalResult = result; - if (updatable.hashComparer != null) { - if (!updatable.hashComparer.checkIfEquals()) { - UpdaterLogger.getLogger().warn("The file hash of the downloaded file did not match the hash provided online for " + updatable); - finalResult = DownloadResult.HASH_FAIl; + private void scheduleUpdateChecker(UpdaterScheduler scheduler, long interval) { + scheduler.schedule(() -> { + List autoDownloads = new ArrayList<>(); + for (Updatable updatable : updatables) { + // Only check if it is not known to be outdated, and if it should be checked automatically + if (!outdatedUpdatables.contains(updatable) && updatable.autoCheck) { + // We should check if it needs an update + if (!updatable.identityComparer.checkIfEquals()) { + // It is outdated + outdatedUpdatables.add(updatable); + if (updatable.autoUpdate) { + autoDownloads.add(updatable.toString()); + updatablesInQueue.add(updatable); + downloadManager.queue(updatable); + } + } + } + } + + // todo: also send messages to players with the permission + if (!outdatedUpdatables.isEmpty()) { + UpdaterLogger logger = UpdaterLogger.getLogger(); + logger.info("The following updatables are outdated: " + outdatedUpdatables.toString().substring(0, outdatedUpdatables.size())); + if (!autoDownloads.isEmpty()) { + logger.info("The following updatables are set to download automatically and have been queued for download: " + autoDownloads.toString().substring(0, autoDownloads.size())); + } } - } - UpdaterLogger.getLogger().info("Finished download for " + updatable + " with result: " + finalResult); + }, true, 0L, interval, TimeUnit.HOURS); } } diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/IdentityComparer.java b/src/main/java/com/projectg/geyserupdater/common/update/age/IdentityComparer.java index bec934de..cd19cb9d 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/age/IdentityComparer.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/age/IdentityComparer.java @@ -42,7 +42,7 @@ public IdentityComparer(@Nonnull S localIdentity, @Nonnull T externalIdentityPro } /** - * Request the {@link Identity} from the external {@link IdentityProvider} and compare it to the stored local {@link Identity}. + * Request the {@link Identity} from the external {@link IdentityProvider} and compare it to the stored local {@link Identity}. Should be regarded as a blocking operation. * @return True if the local identity {@link Object#equals(Object)} the external identity */ public boolean checkIfEquals() { diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index a4919f9f..c173a13d 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -4,10 +4,6 @@ # NOTICE: Please read the README on our github page for full information regarding these options! # https://github.com/ProjectG-Plugins/GeyserUpdater -# If enabled, GeyserUpdater will check for new Geyser builds on server start, and on the interval specified by Auto-Update-Interval. If a new build exists, it will be downloaded. -auto-update-geyser: false -auto-update-floodgate: false - default-updates: geyser: enable: true @@ -20,23 +16,22 @@ default-updates: # The interval in hours between each auto update check. auto-update-interval: 24 - # The maximum amount of seconds that a download is allowed to run for. Increase if you are running into issues on a slow internet connection. -download-time-limit: 180 +download-time-limit: 300 +# Delete the downloaded file if the file hash of the downloaded file did not match what the download server provided. +# If the file hash is not correct the downloaded file is likely corrupt or unfinished. +delete-on-fail: true # If enabled, GeyserUpdater will attempt to restart the server 10 seconds after a new version of Geyser has been successfully downloaded. # If you aren't using a hosting provider or a server wrapper, you will need a restart script. auto-restart-server: false - # When enabled, GeyserUpdater will automatically generate a restart script for you. If you are using CraftBukkit or a proxy # you will need to use the generated script to start your server! If you are using a hosting provider or a server wrapper you probably don't need this. auto-script-generating: false - # Configure the message that is sent to all online players warning them that the server will be restarting in 10 seconds. restart-message-players: "§2This server will be restarting in 10 seconds!" # Enable debug logging enable-debug: false - # Please do not change this version value! config-version: 3 \ No newline at end of file From eb4934eaa68bb30019818fa7a405a3582579e4d6 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+konicai@users.noreply.github.com> Date: Sat, 21 Aug 2021 21:32:42 -0400 Subject: [PATCH 21/42] fully implement spigot and bungeecord, other stuff --- pom.xml | 20 +- .../geyserupdater/bungee/BungeeUpdater.java | 207 +++--------------- .../projectg/geyserupdater/bungee/Config.java | 31 --- .../bungee/{util => }/bstats/Metrics.java | 2 +- .../bungee/command/GeyserUpdateCommand.java | 9 +- .../bungee/listeners/BungeeJoinListener.java | 21 -- .../bungee/util/GeyserBungeeDownloader.java | 96 -------- .../geyserupdater/common/GeyserUpdater.java | 1 - .../common/update/UpdateManager.java | 73 +++--- .../update/{Status.java => UpdateStatus.java} | 6 +- .../spigot/SpigotPlayerHandler.java | 11 +- .../geyserupdater/spigot/SpigotScheduler.java | 6 +- .../geyserupdater/spigot/SpigotUpdater.java | 159 +++----------- .../spigot/command/GeyserUpdateCommand.java | 7 +- .../spigot/util/GeyserSpigotDownloader.java | 136 ------------ .../velocity/VelocityUpdater.java | 17 +- .../velocity/{util => }/bstats/Metrics.java | 2 +- .../velocity/command/GeyserUpdateCommand.java | 4 +- .../util/GeyserVelocityDownloader.java | 103 --------- src/main/resources/bungee.yml | 3 +- src/main/resources/config.yml | 1 + src/main/resources/plugin.yml | 6 +- 22 files changed, 148 insertions(+), 773 deletions(-) delete mode 100644 src/main/java/com/projectg/geyserupdater/bungee/Config.java rename src/main/java/com/projectg/geyserupdater/bungee/{util => }/bstats/Metrics.java (99%) delete mode 100644 src/main/java/com/projectg/geyserupdater/bungee/listeners/BungeeJoinListener.java delete mode 100644 src/main/java/com/projectg/geyserupdater/bungee/util/GeyserBungeeDownloader.java rename src/main/java/com/projectg/geyserupdater/common/update/{Status.java => UpdateStatus.java} (89%) delete mode 100644 src/main/java/com/projectg/geyserupdater/spigot/util/GeyserSpigotDownloader.java rename src/main/java/com/projectg/geyserupdater/velocity/{util => }/bstats/Metrics.java (99%) delete mode 100644 src/main/java/com/projectg/geyserupdater/velocity/util/GeyserVelocityDownloader.java diff --git a/pom.xml b/pom.xml index 04dbfc2d..57ccace1 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.projectg GeyserUpdater GeyserUpdater - 1.5.0 + 1.6.0 UTF-8 @@ -52,6 +52,12 @@ + + org.bukkit + bukkit + 1.8-R0.1-SNAPSHOT + provided + net.md-5 bungeecord-api @@ -71,18 +77,6 @@ 2.13.2 provided - - org.bukkit - bukkit - 1.8-R0.1-SNAPSHOT - provided - - - org.geysermc - connector - 1.4.1-SNAPSHOT - provided - com.fasterxml.jackson.dataformat jackson-dataformat-yaml diff --git a/src/main/java/com/projectg/geyserupdater/bungee/BungeeUpdater.java b/src/main/java/com/projectg/geyserupdater/bungee/BungeeUpdater.java index 78d843cc..34d4c8ce 100644 --- a/src/main/java/com/projectg/geyserupdater/bungee/BungeeUpdater.java +++ b/src/main/java/com/projectg/geyserupdater/bungee/BungeeUpdater.java @@ -1,208 +1,59 @@ package com.projectg.geyserupdater.bungee; import com.projectg.geyserupdater.bungee.command.GeyserUpdateCommand; -import com.projectg.geyserupdater.bungee.listeners.BungeeJoinListener; -import com.projectg.geyserupdater.bungee.util.GeyserBungeeDownloader; -import com.projectg.geyserupdater.bungee.util.bstats.Metrics; +import com.projectg.geyserupdater.bungee.bstats.Metrics; +import com.projectg.geyserupdater.common.GeyserUpdater; +import com.projectg.geyserupdater.common.UpdaterBootstrap; import com.projectg.geyserupdater.common.logger.JavaUtilUpdaterLogger; import com.projectg.geyserupdater.common.logger.UpdaterLogger; -import com.projectg.geyserupdater.common.util.FileUtils; -import com.projectg.geyserupdater.common.util.ScriptCreator; -import com.projectg.geyserupdater.common.util.SpigotResourceUpdateChecker; +import com.projectg.geyserupdater.common.util.ScriptCreator; import net.md_5.bungee.api.plugin.Plugin; -import net.md_5.bungee.config.Configuration; -import net.md_5.bungee.config.ConfigurationProvider; -import net.md_5.bungee.config.YamlConfiguration; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; -import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.concurrent.TimeUnit; -public final class BungeeUpdater extends Plugin { +public class BungeeUpdater extends Plugin implements UpdaterBootstrap { - private static BungeeUpdater plugin; - private Configuration configuration; - private UpdaterLogger logger; + private GeyserUpdater updater; @Override public void onEnable() { - plugin = this; - logger = new JavaUtilUpdaterLogger(getLogger()); - new Metrics(this, 10203); - - this.loadConfig(); - if (getConfig().getBoolean("Enable-Debug", false)) { - UpdaterLogger.getLogger().info("Trying to enable debug logging."); - UpdaterLogger.getLogger().enableDebug(); + Path dataFolder = this.getDataFolder().toPath(); + try { + updater = new GeyserUpdater( + dataFolder, + dataFolder.resolve("BuildUpdate"), + this.getProxy().getPluginsFolder().toPath(), + this, + new JavaUtilUpdaterLogger(getLogger()), + new BungeeScheduler(this), + new BungeePlayerHandler(), + this.getDescription().getVersion(), + "/artifact/bootstrap/bungeecord/target/Geyser-BungeeCord.jar", + "/artifact/bootstrap/bungee/target/floodgate-bungee.jar" + ); + } catch (IOException e) { + getLogger().severe("Failed to start GeyserUpdater! Disabling..."); + e.printStackTrace(); } - this.checkConfigVersion(); - // Check GeyserUpdater version - this.checkUpdaterVersion(); - this.getProxy().getPluginManager().registerCommand(this, new GeyserUpdateCommand()); - // Player alert if a restart is required when they join - getProxy().getPluginManager().registerListener(this, new BungeeJoinListener()); - - // Make startup script - if (configuration.getBoolean("Auto-Script-Generating")) { - try { - // Tell the createScript method that a loop is necessary because bungee has no restart system. - ScriptCreator.createRestartScript(true); - } catch (IOException e) { - e.printStackTrace(); - } - } - // Auto update Geyser if enabled - if (configuration.getBoolean("Auto-Update-Geyser")) { - scheduleAutoUpdate(); - } - // Check if downloaded Geyser file exists periodically - getProxy().getScheduler().schedule(this, () -> { - if (FileUtils.checkFile("plugins/GeyserUpdater/BuildUpdate/Geyser-BungeeCord.jar", true)) { - logger.info("A new Geyser build has been downloaded! Please restart BungeeCord in order to use the updated build!"); - } - }, 30, 720, TimeUnit.MINUTES); - + new Metrics(this, 10203); } @Override public void onDisable() { - // Force Geyser to disable so we can modify the jar in the plugins folder without issue - logger.debug("Forcing Geyser to disable first..."); - getProxy().getPluginManager().getPlugin("Geyser-BungeeCord").onDisable(); try { - moveGeyserJar(); - for (int i = 0; i <= 2; i++) { - 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(); - try { - Thread.sleep(50); - } catch (InterruptedException interruptException) { - logger.error("Failed to delay an additional attempt!"); - interruptException.printStackTrace(); - } - } - } + updater.shutdown(); } catch (IOException e) { - logger.error("An I/O error occurred while attempting to replace the current Geyser jar with the new one!"); + UpdaterLogger.getLogger().error("Failed to install ALL updates:"); e.printStackTrace(); } } - /** - * Load GeyserUpdater's config, create it if it doesn't exist - */ - public void loadConfig() { - try { - configuration = ConfigurationProvider.getProvider(YamlConfiguration.class).load(Config.startConfig(this, "config.yml")); - } catch (IOException exception) { - exception.printStackTrace(); - } - } - - /** - * Check the config version of GeyserUpdater - */ - public void checkConfigVersion(){ - //Change version number only when editing config.yml! - if (configuration.getInt("Config-Version", 0) != 2){ - logger.error("Your copy of config.yml is outdated. Please delete it and let a fresh copy of config.yml be regenerated!"); - } - } - - /** - * Check the version of GeyserUpdater against the spigot resource page - */ - public void checkUpdaterVersion() { - getProxy().getScheduler().runAsync(this, () -> { - String pluginVersion = getDescription().getVersion(); - String latestVersion = SpigotResourceUpdateChecker.getVersion(88555); - if (latestVersion == null || latestVersion.length() == 0) { - logger.error("Failed to determine the latest GeyserUpdater version!"); - } else { - if (latestVersion.equals(pluginVersion)) { - logger.info("You are using the latest version of GeyserUpdater!"); - } else { - logger.info("Your version: " + pluginVersion + ". Latest version: " + latestVersion + ". Download the newer version at https://www.spigotmc.org/resources/geyserupdater.88555/."); - } - } - - }); - } - - /** - * Check for a newer version of Geyser every 24hrs - */ - public void scheduleAutoUpdate() { - UpdaterLogger.getLogger().debug("Scheduling auto updater"); - // todo: build this in different way so that we don't repeat it if the Auto-Update-Interval is zero or -1 or something - getProxy().getScheduler().schedule(this, () -> { - logger.debug("Checking if a new build of Geyser exists."); - try { - // Checking for the build numbers of current build. - boolean isLatest = GeyserProperties.isLatestBuild(); - if (!isLatest) { - 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(); - } - }, 1, getConfig().getLong("Auto-Update-Interval", 24L) * 60, TimeUnit.MINUTES); - } - - /** - * Replace the Geyser jar in the plugin folder with the one in GeyserUpdater/BuildUpdate - * Should only be called once Geyser has been disabled - * - * @throws IOException if there was an IO failure - */ - public void moveGeyserJar() throws IOException { - // Moving Geyser Jar to Plugins folder "Overwriting". - File fileToCopy = new File("plugins/GeyserUpdater/BuildUpdate/Geyser-BungeeCord.jar"); - if (fileToCopy.exists()) { - logger.debug("Moving the new Geyser jar to the plugins folder."); - FileInputStream input = new FileInputStream(fileToCopy); - File newFile = new File("plugins/Geyser-BungeeCord.jar"); - FileOutputStream output = new FileOutputStream(newFile); - byte[] buf = new byte[1024]; - int bytesRead; - while ((bytesRead = input.read(buf)) > 0) { - output.write(buf, 0, bytesRead); - } - input.close(); - output.close(); - } else { - logger.debug("Found no new Geyser jar to copy to the plugins folder."); - } - } - - /** - * Delete the Geyser jar in GeyserUpdater/BuildUpdate - * - * @throws IOException If it failed to delete - */ - private void deleteGeyserJar() throws IOException { - UpdaterLogger.getLogger().debug("Deleting the Geyser jar in the BuildUpdate folder if it exists"); - Path file = Paths.get("plugins/GeyserUpdater/BuildUpdate/Geyser-BungeeCord.jar"); - Files.deleteIfExists(file); - } - public static BungeeUpdater getPlugin() { - return plugin; - } - public Configuration getConfig() { - return configuration; + @Override + public void createRestartScript() throws IOException { + ScriptCreator.createRestartScript(true); } } diff --git a/src/main/java/com/projectg/geyserupdater/bungee/Config.java b/src/main/java/com/projectg/geyserupdater/bungee/Config.java deleted file mode 100644 index 8993d637..00000000 --- a/src/main/java/com/projectg/geyserupdater/bungee/Config.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.projectg.geyserupdater.bungee; - -import net.md_5.bungee.api.plugin.Plugin; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.OutputStream; - -public class Config { - public static File startConfig(Plugin plugin, String file) { - File folder = plugin.getDataFolder(); - if (!folder.exists()) { - folder.mkdir(); - } - File resourceFile = new File(folder, file); - try { - if (!resourceFile.exists()) { - try (InputStream in = plugin.getResourceAsStream(file); - OutputStream out = new FileOutputStream(resourceFile)) { - byte[] buffer = new byte[in.available()]; - in.read(buffer); - out.write(buffer); - } - } - } catch (Exception e) { - e.printStackTrace(); - } - return resourceFile; - } -} diff --git a/src/main/java/com/projectg/geyserupdater/bungee/util/bstats/Metrics.java b/src/main/java/com/projectg/geyserupdater/bungee/bstats/Metrics.java similarity index 99% rename from src/main/java/com/projectg/geyserupdater/bungee/util/bstats/Metrics.java rename to src/main/java/com/projectg/geyserupdater/bungee/bstats/Metrics.java index f9579f84..3b33a157 100644 --- a/src/main/java/com/projectg/geyserupdater/bungee/util/bstats/Metrics.java +++ b/src/main/java/com/projectg/geyserupdater/bungee/bstats/Metrics.java @@ -1,4 +1,4 @@ -package com.projectg.geyserupdater.bungee.util.bstats; +package com.projectg.geyserupdater.bungee.bstats; import com.google.gson.JsonArray; import com.google.gson.JsonObject; 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 9988beed..d583a6d5 100644 --- a/src/main/java/com/projectg/geyserupdater/bungee/command/GeyserUpdateCommand.java +++ b/src/main/java/com/projectg/geyserupdater/bungee/command/GeyserUpdateCommand.java @@ -1,9 +1,7 @@ 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.GeyserProperties; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.CommandSender; @@ -23,6 +21,10 @@ public GeyserUpdateCommand() { public void execute(CommandSender commandSender, String[] args) { UpdaterLogger logger = UpdaterLogger.getLogger(); + //todo: bungee command + + /* + if (commandSender instanceof ProxiedPlayer) { ProxiedPlayer player = (ProxiedPlayer) commandSender; try { @@ -40,7 +42,6 @@ public void execute(CommandSender commandSender, String[] args) { e.printStackTrace(); } } else { - // TODO: filter this against command blocks try { logger.info(Messages.Command.CHECK_START); boolean isLatest = GeyserProperties.isLatestBuild(); @@ -55,5 +56,7 @@ public void execute(CommandSender commandSender, String[] args) { e.printStackTrace(); } } + + */ } } \ No newline at end of file diff --git a/src/main/java/com/projectg/geyserupdater/bungee/listeners/BungeeJoinListener.java b/src/main/java/com/projectg/geyserupdater/bungee/listeners/BungeeJoinListener.java deleted file mode 100644 index 8e8eb787..00000000 --- a/src/main/java/com/projectg/geyserupdater/bungee/listeners/BungeeJoinListener.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.projectg.geyserupdater.bungee.listeners; - -import com.projectg.geyserupdater.common.util.FileUtils; - -import net.md_5.bungee.api.chat.TextComponent; -import net.md_5.bungee.api.event.PostLoginEvent; -import net.md_5.bungee.api.plugin.Listener; -import net.md_5.bungee.event.EventHandler; - -public class BungeeJoinListener implements Listener { - - @EventHandler - public void onPostLogin(PostLoginEvent event) { - // We allow a cached result of maximum age 30 minutes to be used - if (FileUtils.checkFile("plugins/GeyserUpdater/BuildUpdate/Geyser-BungeeCord.jar", true)) { - if (event.getPlayer().hasPermission("gupdater.geyserupdate")) { - event.getPlayer().sendMessage(new TextComponent("[GeyserUpdater] A new Geyser build has been downloaded! Please restart BungeeCord in order to use the updated build!")); - } - } - } -} \ No newline at end of file diff --git a/src/main/java/com/projectg/geyserupdater/bungee/util/GeyserBungeeDownloader.java b/src/main/java/com/projectg/geyserupdater/bungee/util/GeyserBungeeDownloader.java deleted file mode 100644 index 3c8cfe76..00000000 --- a/src/main/java/com/projectg/geyserupdater/bungee/util/GeyserBungeeDownloader.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.projectg.geyserupdater.bungee.util; - -import com.projectg.geyserupdater.bungee.BungeeUpdater; -import com.projectg.geyserupdater.common.logger.UpdaterLogger; -import com.projectg.geyserupdater.common.util.FileUtils; -import com.projectg.geyserupdater.common.util.GeyserProperties; - -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 { - private static BungeeUpdater plugin; - private static UpdaterLogger logger; - - /** - * Download the latest build of Geyser from Jenkins CI for the currently used branch. - * If enabled in the config, the server will also attempt to restart. - */ - public static void updateGeyser() { - plugin = BungeeUpdater.getPlugin(); - logger = UpdaterLogger.getLogger(); - - UpdaterLogger.getLogger().debug("Attempting to download a new build of Geyser."); - - // New task so that we don't block the main thread. All new tasks on bungeecord are async. - plugin.getProxy().getScheduler().runAsync(plugin, () -> { - // Download the newest geyser build - if (downloadGeyser()) { - String successMsg = "The latest build of Geyser has been downloaded! A restart must occur in order for changes to take effect."; - logger.info(successMsg); - for (ProxiedPlayer player : plugin.getProxy().getPlayers()) { - if (player.hasPermission("gupdater.geyserupdate")) { - player.sendMessage(new TextComponent(ChatColor.GREEN + successMsg)); - } - } - if (plugin.getConfig().getBoolean("Auto-Restart-Server")) { - restartServer(); - } - } else { - // fail messages are already sent to the logger in downloadGeyser() - String failMsg = "A severe error occurred when download a new build of Geyser. Please check the server console for further information!"; - for (ProxiedPlayer player : plugin.getProxy().getPlayers()) { - if (player.hasPermission("gupdater.geyserupdate")) { - player.sendMessage(new TextComponent(ChatColor.RED + failMsg)); - } - } - } - }); - } - - /** - * Internal code for downloading the latest build of Geyser from Jenkins CI for the currently used branch. - * - * @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/target/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 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(); - return false; - } - - if (!FileUtils.checkFile(outputPath, false)) { - logger.error("Failed to find the downloaded Geyser build!"); - return false; - } else { - return true; - } - } - - /** - * Attempt to restart the server - */ - private static void restartServer() { - logger.warn("The server will be restarting in 10 seconds!"); - for (ProxiedPlayer player : plugin.getProxy().getPlayers()) { - player.sendMessage(new TextComponent(ChatColor.translateAlternateColorCodes('&', plugin.getConfig().getString("Restart-Message-Players")))); - } - plugin.getProxy().getScheduler().schedule(plugin, () -> plugin.getProxy().stop(), 10L, TimeUnit.SECONDS); - } -} \ No newline at end of file diff --git a/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java b/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java index 0af28625..62684332 100644 --- a/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java +++ b/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java @@ -63,7 +63,6 @@ public GeyserUpdater(Path dataFolder, }, true); // Load the config - logger.debug("Loading config"); config = FileUtils.loadConfig(dataFolder.resolve("config.yml")); if (config.isIncorrectVersion()) { throw new IllegalStateException("Your copy of config.yml is outdated (your version: " + config.getConfigVersion() + ", latest version: " + UpdaterConfiguration.DEFAULT_CONFIG_VERSION + "). Please delete it and let a fresh copy of config.yml be regenerated!"); diff --git a/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java b/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java index 5f99d72f..fac10033 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java @@ -21,33 +21,19 @@ public class UpdateManager { - // todo: make sure we keep track of ones that have been updated, or remove it from the updatables list - /** * The {@link DownloadManager} to use for downloading new versions of plugins. */ private final DownloadManager downloadManager; + private final UpdaterScheduler scheduler; + private final UpdaterConfiguration config; - private final Map registry = new HashMap<>(); - - /** - * All tracked plugins - */ - private final Set updatables = new HashSet<>(); - - /** - * Plugins that are outdated and must be updated - */ - private Set outdatedUpdatables = new HashSet<>(); - - /** - * Plugins that are in the queue for download or are being downloaded - */ - private final Set updatablesInQueue = new HashSet<>(); + private final Map registry = new HashMap<>(); - private final UpdaterConfiguration config; + private boolean isAutoChecking = false; public UpdateManager(Path defaultDownloadLocation, UpdaterScheduler scheduler, UpdaterConfiguration config) { + this.scheduler = scheduler; this.config = config; this.downloadManager = new DownloadManager(this, scheduler, config.getDownloadTimeLimit()); UpdaterLogger logger = UpdaterLogger.getLogger(); @@ -131,21 +117,32 @@ public UpdateManager(Path defaultDownloadLocation, UpdaterScheduler scheduler, U * @param updatable The {@link Updatable} to be updated */ public void register(Updatable updatable) { - registry.put(updatable, Status.CURRENT); + registry.put(updatable, UpdateStatus.UNKNOWN); + if (updatable.autoCheck && !isAutoChecking) { + scheduleUpdateChecker(scheduler, config.getAutoUpdateInterval()); + } } + public boolean isTracked(Updatable updatable) { + return registry.containsKey(updatable); + } /** * Potentially blocking */ public boolean isOutdated(Updatable updatable) { - Status status = Objects.requireNonNull(registry.get(updatable)); + if (!isTracked(updatable)) { + throw new IllegalArgumentException("Updatable must be tracked by the UpdateManager in order to check if it is outdated!"); + } + UpdateStatus status = Objects.requireNonNull(registry.get(updatable)); switch (status) { - case CURRENT: + case UNKNOWN: + // It was latest last we checked, or we haven't checker before return !updatable.identityComparer.checkIfEquals(); case OUTDATED: return true; default: + // A new version is either being downloaded or has been already return false; } } @@ -154,7 +151,7 @@ public boolean isOutdated(Updatable updatable) { * Blocking */ protected void finish(Updatable updatable, DownloadResult result) { - if (registry.get(updatable) != Status.DOWNLOADING) { + if (registry.get(updatable) != UpdateStatus.DOWNLOADING) { throw new IllegalStateException("Cannot finish an Updatable if its current status is not DOWNLOADING"); } UpdaterLogger logger = UpdaterLogger.getLogger(); @@ -162,15 +159,13 @@ protected void finish(Updatable updatable, DownloadResult result) { if (updatable.hashComparer == null) { if (result == DownloadResult.SUCCESS) { // cant check hash, but the download result is success - Objects.requireNonNull(registry.replace(updatable, Status.DOWNLOADED)); - return; - } - } else { - if (updatable.hashComparer.checkIfEquals()) { - // hash is correct - Objects.requireNonNull(registry.replace(updatable, Status.DOWNLOADED)); + registry.put(updatable, UpdateStatus.DOWNLOADED); return; } + } else if (updatable.hashComparer.checkIfEquals()) { + // hash is correct + registry.put(updatable, UpdateStatus.DOWNLOADED); + return; } // Hash is not correct, or cannot check hash and there was a fail @@ -187,32 +182,36 @@ protected void finish(Updatable updatable, DownloadResult result) { private void scheduleUpdateChecker(UpdaterScheduler scheduler, long interval) { scheduler.schedule(() -> { + List outdatedOnes = new ArrayList<>(); List autoDownloads = new ArrayList<>(); - for (Updatable updatable : updatables) { + + for (Updatable updatable : registry.keySet()) { // Only check if it is not known to be outdated, and if it should be checked automatically - if (!outdatedUpdatables.contains(updatable) && updatable.autoCheck) { + if (registry.get(updatable) == UpdateStatus.UNKNOWN && updatable.autoCheck) { // We should check if it needs an update if (!updatable.identityComparer.checkIfEquals()) { // It is outdated - outdatedUpdatables.add(updatable); + registry.put(updatable, UpdateStatus.OUTDATED); + outdatedOnes.add(updatable.toString()); if (updatable.autoUpdate) { - autoDownloads.add(updatable.toString()); - updatablesInQueue.add(updatable); downloadManager.queue(updatable); + autoDownloads.add(updatable.toString()); } } } } // todo: also send messages to players with the permission - if (!outdatedUpdatables.isEmpty()) { + if (!outdatedOnes.isEmpty()) { UpdaterLogger logger = UpdaterLogger.getLogger(); - logger.info("The following updatables are outdated: " + outdatedUpdatables.toString().substring(0, outdatedUpdatables.size())); + logger.info("The following updatables are outdated: " + outdatedOnes.toString().substring(0, outdatedOnes.size())); if (!autoDownloads.isEmpty()) { logger.info("The following updatables are set to download automatically and have been queued for download: " + autoDownloads.toString().substring(0, autoDownloads.size())); } } }, true, 0L, interval, TimeUnit.HOURS); + + isAutoChecking = true; } } diff --git a/src/main/java/com/projectg/geyserupdater/common/update/Status.java b/src/main/java/com/projectg/geyserupdater/common/update/UpdateStatus.java similarity index 89% rename from src/main/java/com/projectg/geyserupdater/common/update/Status.java rename to src/main/java/com/projectg/geyserupdater/common/update/UpdateStatus.java index 4a299f31..a09ed3d6 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/Status.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/UpdateStatus.java @@ -1,10 +1,10 @@ package com.projectg.geyserupdater.common.update; -public enum Status { +public enum UpdateStatus { /** * The Updatable has not been checked, or the last time it was checked it was not outdated. Another check may find that it is outdated. */ - CURRENT, + UNKNOWN, /** * The Updatable is outdated but is not being downloaded. */ @@ -16,5 +16,5 @@ public enum Status { /** * The Updatable is outdated but it has been downloaded. */ - DOWNLOADED; + DOWNLOADED } diff --git a/src/main/java/com/projectg/geyserupdater/spigot/SpigotPlayerHandler.java b/src/main/java/com/projectg/geyserupdater/spigot/SpigotPlayerHandler.java index f73a9c12..c1f3c270 100644 --- a/src/main/java/com/projectg/geyserupdater/spigot/SpigotPlayerHandler.java +++ b/src/main/java/com/projectg/geyserupdater/spigot/SpigotPlayerHandler.java @@ -2,6 +2,7 @@ import com.projectg.geyserupdater.common.PlayerHandler; import org.bukkit.Bukkit; +import org.bukkit.Server; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; @@ -11,10 +12,16 @@ public class SpigotPlayerHandler implements PlayerHandler { + private final Server server; + + public SpigotPlayerHandler(Server server) { + this.server = server; + } + @Override public @NotNull List getOnlinePlayers() { List uuidList = new ArrayList<>(); - for (Player player : Bukkit.getServer().getOnlinePlayers()) { + for (Player player : server.getOnlinePlayers()) { uuidList.add(player.getUniqueId()); } return uuidList; @@ -22,6 +29,6 @@ public class SpigotPlayerHandler implements PlayerHandler { @Override public void sendMessage(@NotNull UUID uuid, @NotNull String message) { - Bukkit.getServer().getPlayer(uuid).sendMessage(message); + server.getPlayer(uuid).sendMessage(message); } } diff --git a/src/main/java/com/projectg/geyserupdater/spigot/SpigotScheduler.java b/src/main/java/com/projectg/geyserupdater/spigot/SpigotScheduler.java index bfcc2fe6..b1dfbda8 100644 --- a/src/main/java/com/projectg/geyserupdater/spigot/SpigotScheduler.java +++ b/src/main/java/com/projectg/geyserupdater/spigot/SpigotScheduler.java @@ -2,7 +2,7 @@ import com.projectg.geyserupdater.common.scheduler.Task; import com.projectg.geyserupdater.common.scheduler.UpdaterScheduler; -import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.plugin.Plugin; import org.bukkit.scheduler.BukkitScheduler; import org.bukkit.scheduler.BukkitTask; import org.jetbrains.annotations.NotNull; @@ -13,9 +13,9 @@ public class SpigotScheduler implements UpdaterScheduler { - private final JavaPlugin plugin; + private final Plugin plugin; - public SpigotScheduler(@Nonnull JavaPlugin plugin) { + public SpigotScheduler(@Nonnull Plugin plugin) { Objects.requireNonNull(plugin); this.plugin = plugin; } diff --git a/src/main/java/com/projectg/geyserupdater/spigot/SpigotUpdater.java b/src/main/java/com/projectg/geyserupdater/spigot/SpigotUpdater.java index dbb16f28..877ce49b 100644 --- a/src/main/java/com/projectg/geyserupdater/spigot/SpigotUpdater.java +++ b/src/main/java/com/projectg/geyserupdater/spigot/SpigotUpdater.java @@ -1,153 +1,64 @@ package com.projectg.geyserupdater.spigot; +import com.projectg.geyserupdater.common.GeyserUpdater; +import com.projectg.geyserupdater.common.UpdaterBootstrap; import com.projectg.geyserupdater.common.logger.JavaUtilUpdaterLogger; import com.projectg.geyserupdater.common.logger.UpdaterLogger; -import com.projectg.geyserupdater.common.util.FileUtils; -import com.projectg.geyserupdater.common.util.GeyserProperties; import com.projectg.geyserupdater.spigot.command.GeyserUpdateCommand; -import com.projectg.geyserupdater.spigot.listeners.SpigotJoinListener; import com.projectg.geyserupdater.spigot.util.CheckSpigotRestart; -import com.projectg.geyserupdater.spigot.util.GeyserSpigotDownloader; -import com.projectg.geyserupdater.common.util.SpigotResourceUpdateChecker; import com.projectg.geyserupdater.spigot.util.bstats.Metrics; -import org.bukkit.Bukkit; -import org.bukkit.configuration.InvalidConfigurationException; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.Server; import org.bukkit.plugin.java.JavaPlugin; -import org.bukkit.scheduler.BukkitRunnable; -import java.io.File; import java.io.IOException; +import java.nio.file.Path; import java.util.Objects; -public class SpigotUpdater extends JavaPlugin { - private static SpigotUpdater plugin; +public class SpigotUpdater extends JavaPlugin implements UpdaterBootstrap { + + private GeyserUpdater updater; + @Override public void onEnable() { - plugin = this; - new JavaUtilUpdaterLogger(getLogger()); - new Metrics(this, 10202); - - loadConfig(); - if (getConfig().getBoolean("Enable-Debug", false)) { - UpdaterLogger.getLogger().info("Trying to enable debug logging."); - UpdaterLogger.getLogger().enableDebug(); + Server server = this.getServer(); + Path updateFolder = server.getUpdateFolderFile().toPath(); + try { + updater = new GeyserUpdater( + this.getDataFolder().toPath(), + updateFolder, + updateFolder, + this, + new JavaUtilUpdaterLogger(getLogger()), + new SpigotScheduler(this), + new SpigotPlayerHandler(server), + this.getDescription().getVersion(), + "/artifact/bootstrap/spigot/target/Geyser-Spigot.jar", + "/artifact/bootstrap/spigot/target/floodgate-spigot.jar" + ); + } catch (IOException e) { + getLogger().severe("Failed to start GeyserUpdater! Disabling..."); + e.printStackTrace(); } - checkConfigVersion(); - // Check our version - checkUpdaterVersion(); - Objects.requireNonNull(getCommand("geyserupdate")).setExecutor(new GeyserUpdateCommand()); getCommand("geyserupdate").setPermission("gupdater.geyserupdate"); - // Player alert if a restart is required when they join - Bukkit.getServer().getPluginManager().registerEvents(new SpigotJoinListener(), this); - - // Check if a restart script already exists - // We create one if it doesn't - if (getConfig().getBoolean("Auto-Script-Generating")) { - try { - CheckSpigotRestart.checkYml(); - } catch (Exception e) { - e.printStackTrace(); - } - } - // If true, start auto updating now and every 24 hours - if (getConfig().getBoolean("Auto-Update-Geyser")) { - scheduleAutoUpdate(); - } - // Enable File Checking here. delay of 30 minutes and period of 12 hours (given in ticks) - new BukkitRunnable() { - - @Override - public void run() { - if (FileUtils.checkFile("plugins/update/Geyser-Spigot.jar", false)) { - UpdaterLogger.getLogger().info("A new Geyser build has been downloaded! Please restart the server in order to use the updated build!"); - } - } - }.runTaskTimerAsynchronously(this, 30 * 60 * 20, 12 * 60 * 60 * 20); + new Metrics(this, 10202); } - /** - * Load GeyserUpdater's config, create it if it doesn't exist - */ - private void loadConfig() { - File configFile = new File(getDataFolder(), "config.yml"); - if (!configFile.exists()) { - configFile.getParentFile().mkdirs(); - saveResource("config.yml", false); - } - FileConfiguration config = new YamlConfiguration(); + @Override + public void onDisable() { try { - config.load(configFile); - } catch (IOException | InvalidConfigurationException e) { + updater.shutdown(); + } catch (IOException e) { + UpdaterLogger.getLogger().error("Failed to install ALL updates:"); e.printStackTrace(); } } - /** - * Check the config version of GeyserUpdater - */ - public void checkConfigVersion() { - //Change version number only when editing config.yml! - if (getConfig().getInt("Config-Version", 0) != 2) { - UpdaterLogger.getLogger().warn("Your copy of config.yml is outdated. Please delete it and let a fresh copy of config.yml be regenerated!"); - } - } - - /** - * Check the version of GeyserUpdater against the spigot resource page - */ - public void checkUpdaterVersion() { - UpdaterLogger logger = UpdaterLogger.getLogger(); - String pluginVersion = plugin.getDescription().getVersion(); - new BukkitRunnable() { - @Override - public void run() { - String latestVersion = SpigotResourceUpdateChecker.getVersion(88555); - if (latestVersion == null || latestVersion.length() == 0) { - logger.error("Failed to determine the latest GeyserUpdater version!"); - } else { - if (latestVersion.equals(pluginVersion)) { - logger.info("You are using the latest version of GeyserUpdater!"); - } else { - logger.info("Your version: " + pluginVersion + ". Latest version: " + latestVersion + ". Download the newer version at https://www.spigotmc.org/resources/geyserupdater.88555/."); - } - } - } - }.runTaskAsynchronously(this); - } - - /** - * Check for a newer version of Geyser every 24hrs - */ - public void scheduleAutoUpdate() { - UpdaterLogger.getLogger().debug("Scheduling auto updater"); - // todo: build this in different way so that we don't repeat it if the Auto-Update-Interval is zero or -1 or something - new BukkitRunnable() { - - @Override - public void run() { - UpdaterLogger.getLogger().debug("Checking if a new build of Geyser exists."); - try { - boolean isLatest = GeyserProperties.isLatestBuild(); - if (!isLatest) { - 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(); - } - // Auto-Update-Interval is in hours. We convert it into ticks - } - }.runTaskTimer(this, 60 * 20, getConfig().getLong("Auto-Update-Interval", 24L) * 60 * 60 * 20); - } - - public static SpigotUpdater getPlugin() { - return plugin; + @Override + public void createRestartScript() throws IOException { + CheckSpigotRestart.checkYml(); } } 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 859e4ee0..c6aa0276 100644 --- a/src/main/java/com/projectg/geyserupdater/spigot/command/GeyserUpdateCommand.java +++ b/src/main/java/com/projectg/geyserupdater/spigot/command/GeyserUpdateCommand.java @@ -2,8 +2,6 @@ import com.projectg.geyserupdater.common.Messages; import com.projectg.geyserupdater.common.logger.UpdaterLogger; -import com.projectg.geyserupdater.common.util.GeyserProperties; -import com.projectg.geyserupdater.spigot.util.GeyserSpigotDownloader; import org.bukkit.ChatColor; import org.bukkit.command.Command; @@ -22,6 +20,10 @@ public class GeyserUpdateCommand implements CommandExecutor { public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { UpdaterLogger logger = UpdaterLogger.getLogger(); + //todo: spigot command + + /* + if (sender instanceof Player) { Player player = (Player) sender; if (command.getName().equalsIgnoreCase("geyserupdate") && player.hasPermission("gupdater.geyserupdate")) { @@ -57,6 +59,7 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command } else { return false; } + */ return true; } } \ No newline at end of file diff --git a/src/main/java/com/projectg/geyserupdater/spigot/util/GeyserSpigotDownloader.java b/src/main/java/com/projectg/geyserupdater/spigot/util/GeyserSpigotDownloader.java deleted file mode 100644 index 0cdbd4a1..00000000 --- a/src/main/java/com/projectg/geyserupdater/spigot/util/GeyserSpigotDownloader.java +++ /dev/null @@ -1,136 +0,0 @@ -package com.projectg.geyserupdater.spigot.util; - -import com.projectg.geyserupdater.common.logger.UpdaterLogger; -import com.projectg.geyserupdater.common.util.FileUtils; -import com.projectg.geyserupdater.common.util.GeyserProperties; -import com.projectg.geyserupdater.spigot.SpigotUpdater; - -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.entity.Player; -import org.bukkit.scheduler.BukkitRunnable; - -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -public class GeyserSpigotDownloader { - private static SpigotUpdater plugin; - private static UpdaterLogger logger; - - /** - * Download the latest build of Geyser from Jenkins CI for the currently used branch. - * If enabled in the config, the server will also attempt to restart. - */ - public static void updateGeyser() { - plugin = SpigotUpdater.getPlugin(); - logger = UpdaterLogger.getLogger(); - - UpdaterLogger.getLogger().debug("Attempting to download a new build of Geyser."); - - boolean doRestart = plugin.getConfig().getBoolean("Auto-Restart-Server"); - - // Start the process async - new BukkitRunnable() { - @Override - public void run() { - // Download the newest build and store the success state - boolean downloadSuccess = downloadGeyser(); - // No additional code should be run after the following BukkitRunnable - // Run it synchronously because it isn't thread-safe - new BukkitRunnable() { - @Override - public void run() { - if (downloadSuccess) { - String successMsg = "The latest build of Geyser has been downloaded! A restart must occur in order for changes to take effect."; - logger.info(successMsg); - for (Player player : Bukkit.getOnlinePlayers()) { - if (player.hasPermission("gupdater.geyserupdate")) { - player.sendMessage(ChatColor.GREEN + successMsg); - } - } - if (doRestart) { - restartServer(); - } - } else { - // fail messages are already sent to the logger in downloadGeyser() - String failMsg = "A error(); error occurred when download a new build of Geyser. Please check the server console for further information!"; - for (Player player : Bukkit.getOnlinePlayers()) { - if (player.hasPermission("gupdater.geyserupdate")) { - player.sendMessage(ChatColor.RED + failMsg); - } - } - } - } - }.runTask(plugin); - } - }.runTaskAsynchronously(plugin); - } - - /** - * Internal code for downloading the latest build of Geyser from Jenkins CI for the currently used branch. - * - * @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/target/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; - } - // 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(); - return false; - } - - if (!FileUtils.checkFile(outputPath, false)) { - logger.error("Failed to find the downloaded Geyser build!"); - return false; - } else { - return true; - } - } - - /** - * Attempt to restart the server - */ - private static void restartServer() { - logger.warn("The server will be restarting in 10 seconds!"); - for (Player player : Bukkit.getOnlinePlayers()) { - player.sendMessage(ChatColor.translateAlternateColorCodes('&', plugin.getConfig().getString("Restart-Message-Players"))); - } - // Attempt to restart the server 10 seconds after the message - new BukkitRunnable() { - @Override - public void run() { - try { - Object spigotServer; - 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(); - 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(); - } catch (InvocationTargetException | IllegalAccessException e) { - logger.error("Failed to restart the server!"); - e.printStackTrace(); - } - } - }.runTaskLater(plugin, 200); // 200 ticks is around 10 seconds (at 20 TPS) - } -} \ No newline at end of file diff --git a/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java b/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java index 032d8bed..22326884 100644 --- a/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java +++ b/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java @@ -7,12 +7,11 @@ import com.projectg.geyserupdater.common.util.ScriptCreator; import com.projectg.geyserupdater.velocity.command.GeyserUpdateCommand; import com.projectg.geyserupdater.velocity.logger.Slf4jUpdaterLogger; -import com.projectg.geyserupdater.velocity.util.bstats.Metrics; +import com.projectg.geyserupdater.velocity.bstats.Metrics; import com.velocitypowered.api.event.PostOrder; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; import com.velocitypowered.api.event.proxy.ProxyShutdownEvent; -import com.velocitypowered.api.plugin.Dependency; import com.velocitypowered.api.plugin.Plugin; import com.velocitypowered.api.plugin.annotation.DataDirectory; import com.velocitypowered.api.proxy.ProxyServer; @@ -21,23 +20,20 @@ import java.io.IOException; import java.nio.file.Path; -@Plugin(id = "geyserupdater", name = "GeyserUpdater", version = VelocityUpdater.VERSION, description = "Automatically or manually downloads new builds of Geyser and applies them on server restart.", authors = {"Jens"}, - dependencies = {@Dependency(id = "geyser")}) +@Plugin(id = "geyserupdater", name = "GeyserUpdater", version = VelocityUpdater.VERSION, + description = "Automatically or manually downloads new builds of Geyser and applies them on server restart.", + authors = {"Jens", "Konicai"}) public class VelocityUpdater implements UpdaterBootstrap { public static final String VERSION = "1.6.0"; - private static VelocityUpdater PLUGIN; private final GeyserUpdater updater; private final ProxyServer server; - private final Path dataDirectory; private final Metrics.Factory metricsFactory; @Inject - public VelocityUpdater(ProxyServer server, Logger baseLogger, @DataDirectory final Path folder, Metrics.Factory metricsFactory) throws IOException { - VelocityUpdater.PLUGIN = this; + public VelocityUpdater(ProxyServer server, Logger baseLogger, @DataDirectory final Path dataDirectory, Metrics.Factory metricsFactory) throws IOException { this.server = server; - this.dataDirectory = folder; this.metricsFactory = metricsFactory; updater = new GeyserUpdater( @@ -82,9 +78,6 @@ public void createRestartScript() throws IOException { ScriptCreator.createRestartScript(true); } - public static VelocityUpdater getPlugin() { - return PLUGIN; - } public ProxyServer getProxyServer() { return server; } diff --git a/src/main/java/com/projectg/geyserupdater/velocity/util/bstats/Metrics.java b/src/main/java/com/projectg/geyserupdater/velocity/bstats/Metrics.java similarity index 99% rename from src/main/java/com/projectg/geyserupdater/velocity/util/bstats/Metrics.java rename to src/main/java/com/projectg/geyserupdater/velocity/bstats/Metrics.java index c1956535..e469e31c 100644 --- a/src/main/java/com/projectg/geyserupdater/velocity/util/bstats/Metrics.java +++ b/src/main/java/com/projectg/geyserupdater/velocity/bstats/Metrics.java @@ -1,4 +1,4 @@ -package com.projectg.geyserupdater.velocity.util.bstats; +package com.projectg.geyserupdater.velocity.bstats; import com.velocitypowered.api.plugin.PluginContainer; import com.velocitypowered.api.plugin.PluginDescription; 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..533db8f7 100644 --- a/src/main/java/com/projectg/geyserupdater/velocity/command/GeyserUpdateCommand.java +++ b/src/main/java/com/projectg/geyserupdater/velocity/command/GeyserUpdateCommand.java @@ -1,8 +1,6 @@ package com.projectg.geyserupdater.velocity.command; import com.projectg.geyserupdater.common.Messages; -import com.projectg.geyserupdater.common.util.GeyserProperties; -import com.projectg.geyserupdater.velocity.util.GeyserVelocityDownloader; import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.command.RawCommand; @@ -15,6 +13,7 @@ public class GeyserUpdateCommand implements RawCommand { @Override public void execute(final Invocation invocation) { + /* CommandSource source = invocation.source(); try { @@ -30,6 +29,7 @@ public void execute(final Invocation invocation) { source.sendMessage(Component.text(Messages.Command.FAIL_CHECK)); e.printStackTrace(); } + */ } @Override public boolean hasPermission(final Invocation invocation) { diff --git a/src/main/java/com/projectg/geyserupdater/velocity/util/GeyserVelocityDownloader.java b/src/main/java/com/projectg/geyserupdater/velocity/util/GeyserVelocityDownloader.java deleted file mode 100644 index 7234eaf9..00000000 --- a/src/main/java/com/projectg/geyserupdater/velocity/util/GeyserVelocityDownloader.java +++ /dev/null @@ -1,103 +0,0 @@ -package com.projectg.geyserupdater.velocity.util; - -import com.projectg.geyserupdater.common.logger.UpdaterLogger; -import com.projectg.geyserupdater.common.util.FileUtils; -import com.projectg.geyserupdater.velocity.VelocityUpdater; - -import com.velocitypowered.api.proxy.Player; -import com.velocitypowered.api.proxy.ProxyServer; - -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 { - private static VelocityUpdater plugin; - private static ProxyServer server; - private static UpdaterLogger logger; - - /** - * Download the latest build of Geyser from Jenkins CI for the currently used branch. - * If enabled in the config, the server will also attempt to restart. - */ - public static void updateGeyser() { - plugin = VelocityUpdater.getPlugin(); - server = plugin.getProxyServer(); - logger = UpdaterLogger.getLogger(); - - UpdaterLogger.getLogger().debug("Attempting to download a new build of Geyser."); - - // New task so that we don't block the main thread. All new tasks on velocity are async. - plugin.getProxyServer().getScheduler().buildTask(plugin, () -> { - // Download the newest geyser build - // todo: do the colour codes for the Adventure text formatting work? - if (downloadGeyser()) { - String successMsg = "The latest build of Geyser has been downloaded! A restart must occur in order for changes to take effect."; - logger.info(successMsg); - for (Player player : server.getAllPlayers()) { - if (player.hasPermission("gupdater.geyserupdate")) { - player.sendMessage(Component.text(successMsg).color(TextColor.fromHexString("55FF55"))); - } - } - if (plugin.getConfig().isRestartServer()) { - restartServer(); - } - } else { - // fail messages are already sent to the logger in downloadGeyser() - String failMsg = "A severe error occurred when download a new build of Geyser. Please check the server console for further information!"; - for (Player player : server.getAllPlayers()) { - if (player.hasPermission("gupdater.geyserupdate")) { - player.sendMessage(Component.text(failMsg).color(TextColor.fromHexString("AA0000"))); - } - } - } - }).schedule(); - } - - /** - * Internal code for downloading the latest build of Geyser from Jenkins CI for the currently used branch. - * - * @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/target/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 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(); - return false; - } - - if (!FileUtils.checkFile(outputPath, false)) { - logger.error("Failed to find the downloaded Geyser build!"); - return false; - } else { - return true; - } - } - /** - * Attempt to restart the server - */ - private static void restartServer() { - logger.warn("The server will be restarting in 10 seconds!"); - for (Player player : server.getAllPlayers()) { - player.sendMessage(Component.text(plugin.getConfig().getRestartMessage())); - } - server.getScheduler() - .buildTask(plugin, server::shutdown) - .delay(10L, TimeUnit.SECONDS) - .schedule(); - } -} - diff --git a/src/main/resources/bungee.yml b/src/main/resources/bungee.yml index b2cdfbdb..a6c8df87 100644 --- a/src/main/resources/bungee.yml +++ b/src/main/resources/bungee.yml @@ -2,5 +2,4 @@ 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 -depends: ["Geyser-BungeeCord"] +author: Jens, Konicai \ No newline at end of file diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index c173a13d..916b642b 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -19,6 +19,7 @@ auto-update-interval: 24 # The maximum amount of seconds that a download is allowed to run for. Increase if you are running into issues on a slow internet connection. download-time-limit: 300 # Delete the downloaded file if the file hash of the downloaded file did not match what the download server provided. +# Or if the file hash was not checked and the download time limit was reached, or an exception occurred. # If the file hash is not correct the downloaded file is likely corrupt or unfinished. delete-on-fail: true diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 6e6c49fe..a3a20926 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,9 +1,11 @@ name: ${project.name} main: com.projectg.geyserupdater.spigot.SpigotUpdater version: ${project.version} -depend: [Geyser-Spigot] -description: Automatically or manually downloads new builds of Geyser and applies them on server restart. api-version: 1.13 +description: Automatically or manually downloads new builds of Geyser and applies them on server restart. +authors: + - Jens + - Konicai commands: geyserupdate: From 25aaed68f7e6c893c35947704c6ba9096084afeb Mon Sep 17 00:00:00 2001 From: Konicai <71294714+konicai@users.noreply.github.com> Date: Sat, 21 Aug 2021 22:08:39 -0400 Subject: [PATCH 22/42] fix building --- pom.xml | 17 +++++++++++- .../geyserupdater/common/GeyserUpdater.java | 13 ++++------ .../common/logger/JavaUtilUpdaterLogger.java | 3 ++- .../common/update/DownloadResult.java | 2 +- .../spigot/util/bstats/Metrics.java | 22 +++------------- .../velocity/bstats/Metrics.java | 26 +++---------------- .../velocity/command/GeyserUpdateCommand.java | 10 +++---- 7 files changed, 35 insertions(+), 58 deletions(-) diff --git a/pom.xml b/pom.xml index 57ccace1..9df7e906 100644 --- a/pom.xml +++ b/pom.xml @@ -14,6 +14,7 @@ UTF-8 1.8 1.8 + 2.10.2 @@ -71,18 +72,32 @@ 3.0.0 provided + org.apache.logging.log4j log4j-core 2.13.2 provided + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + compile + com.fasterxml.jackson.dataformat jackson-dataformat-yaml - 2.10.2 + ${jackson.version} compile + + + com.google.code.findbugs + jsr305 + 3.0.2 + diff --git a/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java b/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java index 62684332..e9900814 100644 --- a/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java +++ b/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java @@ -7,9 +7,8 @@ import com.projectg.geyserupdater.common.update.UpdateManager; import com.projectg.geyserupdater.common.util.FileUtils; import com.projectg.geyserupdater.common.util.SpigotResourceUpdateChecker; -import org.geysermc.connector.GeyserConnector; -import java.io.*; +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; @@ -91,6 +90,9 @@ public GeyserUpdater(Path dataFolder, // Manager for updating plugins this.updateManager = new UpdateManager(downloadFolder, scheduler, config); + + // todo: restart after updates + // todo: better message sending, to players too } /** @@ -108,12 +110,7 @@ public void shutdown() throws IOException { e.printStackTrace(); } - // todo: find a way to make sure we are shutdown last - - // This test isn't ideal but it'll work for now - if (!GeyserConnector.getInstance().getBedrockServer().isClosed()) { - throw new UnsupportedOperationException("Cannot replace Geyser before Geyser has shutdown! No updates will be applied."); - } + // todo: find a way to make sure we are shutdown last (to not modify files still being used) UpdaterLogger.getLogger().debug("Installing plugins from the cache."); Files.walk(downloadFolder, 1).forEach((file) -> { diff --git a/src/main/java/com/projectg/geyserupdater/common/logger/JavaUtilUpdaterLogger.java b/src/main/java/com/projectg/geyserupdater/common/logger/JavaUtilUpdaterLogger.java index 2710bdd1..a7cde593 100644 --- a/src/main/java/com/projectg/geyserupdater/common/logger/JavaUtilUpdaterLogger.java +++ b/src/main/java/com/projectg/geyserupdater/common/logger/JavaUtilUpdaterLogger.java @@ -3,7 +3,8 @@ import java.util.logging.Level; import java.util.logging.Logger; -public final class JavaUtilUpdaterLogger implements UpdaterLogger { +public class JavaUtilUpdaterLogger implements UpdaterLogger { + private final Logger logger; private Level originLevel; diff --git a/src/main/java/com/projectg/geyserupdater/common/update/DownloadResult.java b/src/main/java/com/projectg/geyserupdater/common/update/DownloadResult.java index f838d345..43e2ecb3 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/DownloadResult.java +++ b/src/main/java/com/projectg/geyserupdater/common/update/DownloadResult.java @@ -3,5 +3,5 @@ public enum DownloadResult { SUCCESS, TIMEOUT, - UNKNOWN_FAIL; + UNKNOWN_FAIL } diff --git a/src/main/java/com/projectg/geyserupdater/spigot/util/bstats/Metrics.java b/src/main/java/com/projectg/geyserupdater/spigot/util/bstats/Metrics.java index 54c664b9..b3b4d3a6 100644 --- a/src/main/java/com/projectg/geyserupdater/spigot/util/bstats/Metrics.java +++ b/src/main/java/com/projectg/geyserupdater/spigot/util/bstats/Metrics.java @@ -4,7 +4,6 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.JsonPrimitive; - import org.bukkit.Bukkit; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; @@ -13,26 +12,13 @@ import org.bukkit.plugin.ServicePriority; import javax.net.ssl.HttpsURLConnection; -import java.io.BufferedReader; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; +import java.io.*; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URL; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.Callable; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; +import java.util.*; +import java.util.concurrent.*; import java.util.logging.Level; import java.util.zip.GZIPOutputStream; @@ -72,7 +58,7 @@ public class Metrics { private static final String URL = "https://bStats.org/submitData/bukkit"; // Is bStats enabled on this server? - private boolean enabled; + private final boolean enabled; // Should failed requests be logged? private static boolean logFailedRequests; diff --git a/src/main/java/com/projectg/geyserupdater/velocity/bstats/Metrics.java b/src/main/java/com/projectg/geyserupdater/velocity/bstats/Metrics.java index e469e31c..8f42d367 100644 --- a/src/main/java/com/projectg/geyserupdater/velocity/bstats/Metrics.java +++ b/src/main/java/com/projectg/geyserupdater/velocity/bstats/Metrics.java @@ -1,36 +1,18 @@ package com.projectg.geyserupdater.velocity.bstats; +import com.google.inject.Inject; import com.velocitypowered.api.plugin.PluginContainer; import com.velocitypowered.api.plugin.PluginDescription; import com.velocitypowered.api.plugin.annotation.DataDirectory; import com.velocitypowered.api.proxy.ProxyServer; - -import com.google.inject.Inject; - import org.slf4j.Logger; import javax.net.ssl.HttpsURLConnection; -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStreamReader; +import java.io.*; import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; +import java.util.*; import java.util.concurrent.Callable; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -955,7 +937,7 @@ private void writeConfig() throws IOException { "# There is no performance penalty associated with having metrics enabled, and data sent to"); configContent.add("# bStats is fully anonymous."); configContent.add("enabled=" + defaultEnabled); - configContent.add("server-uuid=" + UUID.randomUUID().toString()); + configContent.add("server-uuid=" + UUID.randomUUID()); configContent.add("log-errors=false"); configContent.add("log-sent-data=false"); configContent.add("log-response-status-text=false"); 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 533db8f7..dd2e10e2 100644 --- a/src/main/java/com/projectg/geyserupdater/velocity/command/GeyserUpdateCommand.java +++ b/src/main/java/com/projectg/geyserupdater/velocity/command/GeyserUpdateCommand.java @@ -1,18 +1,14 @@ package com.projectg.geyserupdater.velocity.command; -import com.projectg.geyserupdater.common.Messages; - -import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.command.RawCommand; -import net.kyori.adventure.text.Component; - -import java.io.IOException; - public class GeyserUpdateCommand implements RawCommand { @Override public void execute(final Invocation invocation) { + + //todo: velocity command + /* CommandSource source = invocation.source(); From eadbb4c5e110620c91eed301a69fcc7789e2686f Mon Sep 17 00:00:00 2001 From: Konicai <71294714+konicai@users.noreply.github.com> Date: Sat, 21 Aug 2021 22:19:52 -0400 Subject: [PATCH 23/42] fix velocity --- .../velocity/VelocityUpdater.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java b/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java index 22326884..5c2279a9 100644 --- a/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java +++ b/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java @@ -27,35 +27,39 @@ public class VelocityUpdater implements UpdaterBootstrap { public static final String VERSION = "1.6.0"; - private final GeyserUpdater updater; + private GeyserUpdater updater; private final ProxyServer server; + private final Path dataDirectory; + private final Logger logger; private final Metrics.Factory metricsFactory; @Inject - public VelocityUpdater(ProxyServer server, Logger baseLogger, @DataDirectory final Path dataDirectory, Metrics.Factory metricsFactory) throws IOException { + public VelocityUpdater(ProxyServer server, Logger baseLogger, @DataDirectory final Path dataDirectory, Metrics.Factory metricsFactory) { this.server = server; + this.dataDirectory = dataDirectory; + this.logger = baseLogger; this.metricsFactory = metricsFactory; + } + + @Subscribe + public void onProxyInitialization(ProxyInitializeEvent event) throws IOException { updater = new GeyserUpdater( dataDirectory, dataDirectory.resolve("BuildUpdate"), dataDirectory.getParent(), this, - new Slf4jUpdaterLogger(baseLogger), + new Slf4jUpdaterLogger(logger), new VelocityScheduler(this), new VelocityPlayerHandler(server), VERSION, "/artifact/bootstrap/velocity/target/Geyser-Velocity.jar", "/artifact/bootstrap/velocity/target/floodgate-velocity.jar" ); - } - - @Subscribe - public void onProxyInitialization(ProxyInitializeEvent event) { - metricsFactory.make(this, 10673); // Register our only command server.getCommandManager().register("geyserupdate", new GeyserUpdateCommand()); + metricsFactory.make(this, 10673); } @Subscribe(order = PostOrder.LAST) From 04b41608d573b9e5f60c54e84281855df8d37934 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+konicai@users.noreply.github.com> Date: Sat, 21 Aug 2021 22:32:47 -0400 Subject: [PATCH 24/42] add jackson core and annotations --- pom.xml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pom.xml b/pom.xml index 9df7e906..1a597ad0 100644 --- a/pom.xml +++ b/pom.xml @@ -80,6 +80,18 @@ provided + + com.fasterxml.jackson.core + jackson-annotations + ${jackson.version} + compile + + + com.fasterxml.jackson.core + jackson-core + ${jackson.version} + compile + com.fasterxml.jackson.core jackson-databind From 51872c0066b63c06c1d36a55fe4cb6796104e209 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Sun, 22 Aug 2021 20:51:55 -0400 Subject: [PATCH 25/42] shade jackson, transfer to dev.projectg Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- pom.xml | 23 ++++++++++++++++++- .../geyserupdater/common/scheduler/Task.java | 6 ----- .../bungee/BungeePlayerHandler.java | 4 ++-- .../geyserupdater/bungee/BungeeScheduler.java | 6 ++--- .../geyserupdater/bungee/BungeeUpdater.java | 16 ++++++------- .../geyserupdater/bungee/bstats/Metrics.java | 2 +- .../bungee/command/GeyserUpdateCommand.java | 10 ++------ .../geyserupdater/common/GeyserUpdater.java | 18 +++++++-------- .../geyserupdater/common/Messages.java | 2 +- .../geyserupdater/common/PlayerHandler.java | 2 +- .../common/UpdaterBootstrap.java | 2 +- .../common/config/UpdaterConfiguration.java | 2 +- .../common/logger/JavaUtilUpdaterLogger.java | 2 +- .../common/logger/UpdaterLogger.java | 2 +- .../common/logger/UpdaterLoggerHolder.java | 2 +- .../geyserupdater/common/scheduler/Task.java | 6 +++++ .../common/scheduler/UpdaterScheduler.java | 2 +- .../common/update/DownloadManager.java | 10 ++++---- .../common/update/DownloadResult.java | 2 +- .../geyserupdater/common/update/PluginId.java | 4 ++-- .../update/RecursiveDownloadManager.java | 12 +++++----- .../common/update/Updatable.java | 4 ++-- .../common/update/UpdateManager.java | 22 +++++++++--------- .../common/update/UpdateStatus.java | 2 +- .../common/update/age/IdentityComparer.java | 6 ++--- .../update/age/provider/FileHashProvider.java | 6 ++--- .../update/age/provider/IdentityProvider.java | 4 ++-- .../age/provider/JenkinsBuildProvider.java | 8 +++---- .../age/provider/JenkinsHashProvider.java | 6 ++--- .../common/update/age/type/BuildNumber.java | 2 +- .../common/update/age/type/Identity.java | 2 +- .../common/update/age/type/Md5FileHash.java | 2 +- .../geyserupdater/common/util/FileUtils.java | 4 ++-- .../geyserupdater/common/util/OsUtils.java | 2 +- .../common/util/ScriptCreator.java | 4 ++-- .../util/SpigotResourceUpdateChecker.java | 4 ++-- .../geyserupdater/common/util/WebUtils.java | 6 ++--- .../spigot/SpigotPlayerHandler.java | 5 ++-- .../geyserupdater/spigot/SpigotScheduler.java | 6 ++--- .../geyserupdater/spigot/SpigotUpdater.java | 16 ++++++------- .../spigot/command/GeyserUpdateCommand.java | 10 ++------ .../spigot/util/CheckSpigotRestart.java | 8 +++---- .../spigot/util/bstats/Metrics.java | 2 +- .../velocity/VelocityPlayerHandler.java | 4 ++-- .../velocity/VelocityScheduler.java | 6 ++--- .../velocity/VelocityUpdater.java | 16 ++++++------- .../velocity/bstats/Metrics.java | 2 +- .../velocity/command/GeyserUpdateCommand.java | 2 +- .../velocity/logger/Slf4jUpdaterLogger.java | 4 ++-- src/main/resources/bungee.yml | 2 +- src/main/resources/plugin.yml | 2 +- 51 files changed, 155 insertions(+), 149 deletions(-) delete mode 100644 src/main/java/com/projectg/geyserupdater/common/scheduler/Task.java rename src/main/java/{com => dev}/projectg/geyserupdater/bungee/BungeePlayerHandler.java (88%) rename src/main/java/{com => dev}/projectg/geyserupdater/bungee/BungeeScheduler.java (87%) rename src/main/java/{com => dev}/projectg/geyserupdater/bungee/BungeeUpdater.java (77%) rename src/main/java/{com => dev}/projectg/geyserupdater/bungee/bstats/Metrics.java (99%) rename src/main/java/{com => dev}/projectg/geyserupdater/bungee/command/GeyserUpdateCommand.java (85%) rename src/main/java/{com => dev}/projectg/geyserupdater/common/GeyserUpdater.java (91%) rename src/main/java/{com => dev}/projectg/geyserupdater/common/Messages.java (92%) rename src/main/java/{com => dev}/projectg/geyserupdater/common/PlayerHandler.java (86%) rename src/main/java/{com => dev}/projectg/geyserupdater/common/UpdaterBootstrap.java (77%) rename src/main/java/{com => dev}/projectg/geyserupdater/common/config/UpdaterConfiguration.java (98%) rename src/main/java/{com => dev}/projectg/geyserupdater/common/logger/JavaUtilUpdaterLogger.java (96%) rename src/main/java/{com => dev}/projectg/geyserupdater/common/logger/UpdaterLogger.java (96%) rename src/main/java/{com => dev}/projectg/geyserupdater/common/logger/UpdaterLoggerHolder.java (59%) create mode 100644 src/main/java/dev/projectg/geyserupdater/common/scheduler/Task.java rename src/main/java/{com => dev}/projectg/geyserupdater/common/scheduler/UpdaterScheduler.java (97%) rename src/main/java/{com => dev}/projectg/geyserupdater/common/update/DownloadManager.java (93%) rename src/main/java/{com => dev}/projectg/geyserupdater/common/update/DownloadResult.java (60%) rename src/main/java/{com => dev}/projectg/geyserupdater/common/update/PluginId.java (96%) rename src/main/java/{com => dev}/projectg/geyserupdater/common/update/RecursiveDownloadManager.java (92%) rename src/main/java/{com => dev}/projectg/geyserupdater/common/update/Updatable.java (95%) rename src/main/java/{com => dev}/projectg/geyserupdater/common/update/UpdateManager.java (93%) rename src/main/java/{com => dev}/projectg/geyserupdater/common/update/UpdateStatus.java (90%) rename src/main/java/{com => dev}/projectg/geyserupdater/common/update/age/IdentityComparer.java (92%) rename src/main/java/{com => dev}/projectg/geyserupdater/common/update/age/provider/FileHashProvider.java (83%) rename src/main/java/{com => dev}/projectg/geyserupdater/common/update/age/provider/IdentityProvider.java (51%) rename src/main/java/{com => dev}/projectg/geyserupdater/common/update/age/provider/JenkinsBuildProvider.java (86%) rename src/main/java/{com => dev}/projectg/geyserupdater/common/update/age/provider/JenkinsHashProvider.java (91%) rename src/main/java/{com => dev}/projectg/geyserupdater/common/update/age/type/BuildNumber.java (81%) rename src/main/java/{com => dev}/projectg/geyserupdater/common/update/age/type/Identity.java (75%) rename src/main/java/{com => dev}/projectg/geyserupdater/common/update/age/type/Md5FileHash.java (79%) rename src/main/java/{com => dev}/projectg/geyserupdater/common/util/FileUtils.java (92%) rename src/main/java/{com => dev}/projectg/geyserupdater/common/util/OsUtils.java (95%) rename src/main/java/{com => dev}/projectg/geyserupdater/common/util/ScriptCreator.java (96%) rename src/main/java/{com => dev}/projectg/geyserupdater/common/util/SpigotResourceUpdateChecker.java (92%) rename src/main/java/{com => dev}/projectg/geyserupdater/common/util/WebUtils.java (95%) rename src/main/java/{com => dev}/projectg/geyserupdater/spigot/SpigotPlayerHandler.java (86%) rename src/main/java/{com => dev}/projectg/geyserupdater/spigot/SpigotScheduler.java (92%) rename src/main/java/{com => dev}/projectg/geyserupdater/spigot/SpigotUpdater.java (78%) rename src/main/java/{com => dev}/projectg/geyserupdater/spigot/command/GeyserUpdateCommand.java (87%) rename src/main/java/{com => dev}/projectg/geyserupdater/spigot/util/CheckSpigotRestart.java (90%) rename src/main/java/{com => dev}/projectg/geyserupdater/spigot/util/bstats/Metrics.java (99%) rename src/main/java/{com => dev}/projectg/geyserupdater/velocity/VelocityPlayerHandler.java (89%) rename src/main/java/{com => dev}/projectg/geyserupdater/velocity/VelocityScheduler.java (88%) rename src/main/java/{com => dev}/projectg/geyserupdater/velocity/VelocityUpdater.java (85%) rename src/main/java/{com => dev}/projectg/geyserupdater/velocity/bstats/Metrics.java (99%) rename src/main/java/{com => dev}/projectg/geyserupdater/velocity/command/GeyserUpdateCommand.java (95%) rename src/main/java/{com => dev}/projectg/geyserupdater/velocity/logger/Slf4jUpdaterLogger.java (91%) diff --git a/pom.xml b/pom.xml index 1a597ad0..78da6000 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - com.projectg + dev.projectg GeyserUpdater GeyserUpdater 1.6.0 @@ -129,6 +129,27 @@ 1.8 + + org.apache.maven.plugins + maven-shade-plugin + 3.2.4 + + + package + + shade + + + + + com.fasterxml.jackson + dev.projectg.geyserupdater.shaded + + + + + + diff --git a/src/main/java/com/projectg/geyserupdater/common/scheduler/Task.java b/src/main/java/com/projectg/geyserupdater/common/scheduler/Task.java deleted file mode 100644 index e98d59ee..00000000 --- a/src/main/java/com/projectg/geyserupdater/common/scheduler/Task.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.projectg.geyserupdater.common.scheduler; - -public interface Task { - - void cancel(); -} diff --git a/src/main/java/com/projectg/geyserupdater/bungee/BungeePlayerHandler.java b/src/main/java/dev/projectg/geyserupdater/bungee/BungeePlayerHandler.java similarity index 88% rename from src/main/java/com/projectg/geyserupdater/bungee/BungeePlayerHandler.java rename to src/main/java/dev/projectg/geyserupdater/bungee/BungeePlayerHandler.java index 7c2c30fd..eb78979d 100644 --- a/src/main/java/com/projectg/geyserupdater/bungee/BungeePlayerHandler.java +++ b/src/main/java/dev/projectg/geyserupdater/bungee/BungeePlayerHandler.java @@ -1,6 +1,6 @@ -package com.projectg.geyserupdater.bungee; +package dev.projectg.geyserupdater.bungee; -import com.projectg.geyserupdater.common.PlayerHandler; +import dev.projectg.geyserupdater.common.PlayerHandler; import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.connection.ProxiedPlayer; diff --git a/src/main/java/com/projectg/geyserupdater/bungee/BungeeScheduler.java b/src/main/java/dev/projectg/geyserupdater/bungee/BungeeScheduler.java similarity index 87% rename from src/main/java/com/projectg/geyserupdater/bungee/BungeeScheduler.java rename to src/main/java/dev/projectg/geyserupdater/bungee/BungeeScheduler.java index 3f2c9177..94387678 100644 --- a/src/main/java/com/projectg/geyserupdater/bungee/BungeeScheduler.java +++ b/src/main/java/dev/projectg/geyserupdater/bungee/BungeeScheduler.java @@ -1,7 +1,7 @@ -package com.projectg.geyserupdater.bungee; +package dev.projectg.geyserupdater.bungee; -import com.projectg.geyserupdater.common.scheduler.Task; -import com.projectg.geyserupdater.common.scheduler.UpdaterScheduler; +import dev.projectg.geyserupdater.common.scheduler.Task; +import dev.projectg.geyserupdater.common.scheduler.UpdaterScheduler; import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.api.scheduler.ScheduledTask; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/projectg/geyserupdater/bungee/BungeeUpdater.java b/src/main/java/dev/projectg/geyserupdater/bungee/BungeeUpdater.java similarity index 77% rename from src/main/java/com/projectg/geyserupdater/bungee/BungeeUpdater.java rename to src/main/java/dev/projectg/geyserupdater/bungee/BungeeUpdater.java index 34d4c8ce..50ed31b4 100644 --- a/src/main/java/com/projectg/geyserupdater/bungee/BungeeUpdater.java +++ b/src/main/java/dev/projectg/geyserupdater/bungee/BungeeUpdater.java @@ -1,13 +1,13 @@ -package com.projectg.geyserupdater.bungee; +package dev.projectg.geyserupdater.bungee; -import com.projectg.geyserupdater.bungee.command.GeyserUpdateCommand; -import com.projectg.geyserupdater.bungee.bstats.Metrics; -import com.projectg.geyserupdater.common.GeyserUpdater; -import com.projectg.geyserupdater.common.UpdaterBootstrap; -import com.projectg.geyserupdater.common.logger.JavaUtilUpdaterLogger; -import com.projectg.geyserupdater.common.logger.UpdaterLogger; +import dev.projectg.geyserupdater.bungee.command.GeyserUpdateCommand; +import dev.projectg.geyserupdater.bungee.bstats.Metrics; +import dev.projectg.geyserupdater.common.GeyserUpdater; +import dev.projectg.geyserupdater.common.UpdaterBootstrap; +import dev.projectg.geyserupdater.common.logger.JavaUtilUpdaterLogger; +import dev.projectg.geyserupdater.common.logger.UpdaterLogger; -import com.projectg.geyserupdater.common.util.ScriptCreator; +import dev.projectg.geyserupdater.common.util.ScriptCreator; import net.md_5.bungee.api.plugin.Plugin; import java.io.IOException; diff --git a/src/main/java/com/projectg/geyserupdater/bungee/bstats/Metrics.java b/src/main/java/dev/projectg/geyserupdater/bungee/bstats/Metrics.java similarity index 99% rename from src/main/java/com/projectg/geyserupdater/bungee/bstats/Metrics.java rename to src/main/java/dev/projectg/geyserupdater/bungee/bstats/Metrics.java index 3b33a157..e1ac07c6 100644 --- a/src/main/java/com/projectg/geyserupdater/bungee/bstats/Metrics.java +++ b/src/main/java/dev/projectg/geyserupdater/bungee/bstats/Metrics.java @@ -1,4 +1,4 @@ -package com.projectg.geyserupdater.bungee.bstats; +package dev.projectg.geyserupdater.bungee.bstats; import com.google.gson.JsonArray; import com.google.gson.JsonObject; diff --git a/src/main/java/com/projectg/geyserupdater/bungee/command/GeyserUpdateCommand.java b/src/main/java/dev/projectg/geyserupdater/bungee/command/GeyserUpdateCommand.java similarity index 85% rename from src/main/java/com/projectg/geyserupdater/bungee/command/GeyserUpdateCommand.java rename to src/main/java/dev/projectg/geyserupdater/bungee/command/GeyserUpdateCommand.java index d583a6d5..f2ea76b6 100644 --- a/src/main/java/com/projectg/geyserupdater/bungee/command/GeyserUpdateCommand.java +++ b/src/main/java/dev/projectg/geyserupdater/bungee/command/GeyserUpdateCommand.java @@ -1,16 +1,10 @@ -package com.projectg.geyserupdater.bungee.command; +package dev.projectg.geyserupdater.bungee.command; -import com.projectg.geyserupdater.common.Messages; -import com.projectg.geyserupdater.common.logger.UpdaterLogger; +import dev.projectg.geyserupdater.common.logger.UpdaterLogger; -import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.CommandSender; -import net.md_5.bungee.api.chat.TextComponent; -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 { diff --git a/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java b/src/main/java/dev/projectg/geyserupdater/common/GeyserUpdater.java similarity index 91% rename from src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java rename to src/main/java/dev/projectg/geyserupdater/common/GeyserUpdater.java index e9900814..7f53ec63 100644 --- a/src/main/java/com/projectg/geyserupdater/common/GeyserUpdater.java +++ b/src/main/java/dev/projectg/geyserupdater/common/GeyserUpdater.java @@ -1,12 +1,12 @@ -package com.projectg.geyserupdater.common; - -import com.projectg.geyserupdater.common.config.UpdaterConfiguration; -import com.projectg.geyserupdater.common.logger.UpdaterLogger; -import com.projectg.geyserupdater.common.scheduler.UpdaterScheduler; -import com.projectg.geyserupdater.common.update.PluginId; -import com.projectg.geyserupdater.common.update.UpdateManager; -import com.projectg.geyserupdater.common.util.FileUtils; -import com.projectg.geyserupdater.common.util.SpigotResourceUpdateChecker; +package dev.projectg.geyserupdater.common; + +import dev.projectg.geyserupdater.common.config.UpdaterConfiguration; +import dev.projectg.geyserupdater.common.logger.UpdaterLogger; +import dev.projectg.geyserupdater.common.scheduler.UpdaterScheduler; +import dev.projectg.geyserupdater.common.update.PluginId; +import dev.projectg.geyserupdater.common.update.UpdateManager; +import dev.projectg.geyserupdater.common.util.FileUtils; +import dev.projectg.geyserupdater.common.util.SpigotResourceUpdateChecker; import java.io.IOException; import java.nio.file.Files; diff --git a/src/main/java/com/projectg/geyserupdater/common/Messages.java b/src/main/java/dev/projectg/geyserupdater/common/Messages.java similarity index 92% rename from src/main/java/com/projectg/geyserupdater/common/Messages.java rename to src/main/java/dev/projectg/geyserupdater/common/Messages.java index 72d0faae..4aa965a9 100644 --- a/src/main/java/com/projectg/geyserupdater/common/Messages.java +++ b/src/main/java/dev/projectg/geyserupdater/common/Messages.java @@ -1,4 +1,4 @@ -package com.projectg.geyserupdater.common; +package dev.projectg.geyserupdater.common; public class Messages { diff --git a/src/main/java/com/projectg/geyserupdater/common/PlayerHandler.java b/src/main/java/dev/projectg/geyserupdater/common/PlayerHandler.java similarity index 86% rename from src/main/java/com/projectg/geyserupdater/common/PlayerHandler.java rename to src/main/java/dev/projectg/geyserupdater/common/PlayerHandler.java index 448c24e7..29a29ac1 100644 --- a/src/main/java/com/projectg/geyserupdater/common/PlayerHandler.java +++ b/src/main/java/dev/projectg/geyserupdater/common/PlayerHandler.java @@ -1,4 +1,4 @@ -package com.projectg.geyserupdater.common; +package dev.projectg.geyserupdater.common; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/projectg/geyserupdater/common/UpdaterBootstrap.java b/src/main/java/dev/projectg/geyserupdater/common/UpdaterBootstrap.java similarity index 77% rename from src/main/java/com/projectg/geyserupdater/common/UpdaterBootstrap.java rename to src/main/java/dev/projectg/geyserupdater/common/UpdaterBootstrap.java index 524baa96..fd14d194 100644 --- a/src/main/java/com/projectg/geyserupdater/common/UpdaterBootstrap.java +++ b/src/main/java/dev/projectg/geyserupdater/common/UpdaterBootstrap.java @@ -1,4 +1,4 @@ -package com.projectg.geyserupdater.common; +package dev.projectg.geyserupdater.common; import java.io.IOException; diff --git a/src/main/java/com/projectg/geyserupdater/common/config/UpdaterConfiguration.java b/src/main/java/dev/projectg/geyserupdater/common/config/UpdaterConfiguration.java similarity index 98% rename from src/main/java/com/projectg/geyserupdater/common/config/UpdaterConfiguration.java rename to src/main/java/dev/projectg/geyserupdater/common/config/UpdaterConfiguration.java index 19223afa..788a0373 100644 --- a/src/main/java/com/projectg/geyserupdater/common/config/UpdaterConfiguration.java +++ b/src/main/java/dev/projectg/geyserupdater/common/config/UpdaterConfiguration.java @@ -1,4 +1,4 @@ -package com.projectg.geyserupdater.common.config; +package dev.projectg.geyserupdater.common.config; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; diff --git a/src/main/java/com/projectg/geyserupdater/common/logger/JavaUtilUpdaterLogger.java b/src/main/java/dev/projectg/geyserupdater/common/logger/JavaUtilUpdaterLogger.java similarity index 96% rename from src/main/java/com/projectg/geyserupdater/common/logger/JavaUtilUpdaterLogger.java rename to src/main/java/dev/projectg/geyserupdater/common/logger/JavaUtilUpdaterLogger.java index a7cde593..0f392c80 100644 --- a/src/main/java/com/projectg/geyserupdater/common/logger/JavaUtilUpdaterLogger.java +++ b/src/main/java/dev/projectg/geyserupdater/common/logger/JavaUtilUpdaterLogger.java @@ -1,4 +1,4 @@ -package com.projectg.geyserupdater.common.logger; +package dev.projectg.geyserupdater.common.logger; import java.util.logging.Level; import java.util.logging.Logger; diff --git a/src/main/java/com/projectg/geyserupdater/common/logger/UpdaterLogger.java b/src/main/java/dev/projectg/geyserupdater/common/logger/UpdaterLogger.java similarity index 96% rename from src/main/java/com/projectg/geyserupdater/common/logger/UpdaterLogger.java rename to src/main/java/dev/projectg/geyserupdater/common/logger/UpdaterLogger.java index db610f46..0fcd25e8 100644 --- a/src/main/java/com/projectg/geyserupdater/common/logger/UpdaterLogger.java +++ b/src/main/java/dev/projectg/geyserupdater/common/logger/UpdaterLogger.java @@ -1,4 +1,4 @@ -package com.projectg.geyserupdater.common.logger; +package dev.projectg.geyserupdater.common.logger; public interface UpdaterLogger { diff --git a/src/main/java/com/projectg/geyserupdater/common/logger/UpdaterLoggerHolder.java b/src/main/java/dev/projectg/geyserupdater/common/logger/UpdaterLoggerHolder.java similarity index 59% rename from src/main/java/com/projectg/geyserupdater/common/logger/UpdaterLoggerHolder.java rename to src/main/java/dev/projectg/geyserupdater/common/logger/UpdaterLoggerHolder.java index 046a8f95..ba26b18e 100644 --- a/src/main/java/com/projectg/geyserupdater/common/logger/UpdaterLoggerHolder.java +++ b/src/main/java/dev/projectg/geyserupdater/common/logger/UpdaterLoggerHolder.java @@ -1,4 +1,4 @@ -package com.projectg.geyserupdater.common.logger; +package dev.projectg.geyserupdater.common.logger; class UpdaterLoggerHolder { diff --git a/src/main/java/dev/projectg/geyserupdater/common/scheduler/Task.java b/src/main/java/dev/projectg/geyserupdater/common/scheduler/Task.java new file mode 100644 index 00000000..09cf0ac2 --- /dev/null +++ b/src/main/java/dev/projectg/geyserupdater/common/scheduler/Task.java @@ -0,0 +1,6 @@ +package dev.projectg.geyserupdater.common.scheduler; + +public interface Task { + + void cancel(); +} diff --git a/src/main/java/com/projectg/geyserupdater/common/scheduler/UpdaterScheduler.java b/src/main/java/dev/projectg/geyserupdater/common/scheduler/UpdaterScheduler.java similarity index 97% rename from src/main/java/com/projectg/geyserupdater/common/scheduler/UpdaterScheduler.java rename to src/main/java/dev/projectg/geyserupdater/common/scheduler/UpdaterScheduler.java index 950defbb..61a97d75 100644 --- a/src/main/java/com/projectg/geyserupdater/common/scheduler/UpdaterScheduler.java +++ b/src/main/java/dev/projectg/geyserupdater/common/scheduler/UpdaterScheduler.java @@ -1,4 +1,4 @@ -package com.projectg.geyserupdater.common.scheduler; +package dev.projectg.geyserupdater.common.scheduler; import javax.annotation.Nonnull; import java.util.Objects; diff --git a/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java b/src/main/java/dev/projectg/geyserupdater/common/update/DownloadManager.java similarity index 93% rename from src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java rename to src/main/java/dev/projectg/geyserupdater/common/update/DownloadManager.java index 400c36c8..754974ad 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/DownloadManager.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/DownloadManager.java @@ -1,9 +1,9 @@ -package com.projectg.geyserupdater.common.update; +package dev.projectg.geyserupdater.common.update; -import com.projectg.geyserupdater.common.logger.UpdaterLogger; -import com.projectg.geyserupdater.common.scheduler.Task; -import com.projectg.geyserupdater.common.scheduler.UpdaterScheduler; -import com.projectg.geyserupdater.common.util.WebUtils; +import dev.projectg.geyserupdater.common.logger.UpdaterLogger; +import dev.projectg.geyserupdater.common.scheduler.Task; +import dev.projectg.geyserupdater.common.scheduler.UpdaterScheduler; +import dev.projectg.geyserupdater.common.util.WebUtils; import javax.annotation.Nullable; import java.io.IOException; diff --git a/src/main/java/com/projectg/geyserupdater/common/update/DownloadResult.java b/src/main/java/dev/projectg/geyserupdater/common/update/DownloadResult.java similarity index 60% rename from src/main/java/com/projectg/geyserupdater/common/update/DownloadResult.java rename to src/main/java/dev/projectg/geyserupdater/common/update/DownloadResult.java index 43e2ecb3..8aedb020 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/DownloadResult.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/DownloadResult.java @@ -1,4 +1,4 @@ -package com.projectg.geyserupdater.common.update; +package dev.projectg.geyserupdater.common.update; public enum DownloadResult { SUCCESS, diff --git a/src/main/java/com/projectg/geyserupdater/common/update/PluginId.java b/src/main/java/dev/projectg/geyserupdater/common/update/PluginId.java similarity index 96% rename from src/main/java/com/projectg/geyserupdater/common/update/PluginId.java rename to src/main/java/dev/projectg/geyserupdater/common/update/PluginId.java index 7b4878a9..12795274 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/PluginId.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/PluginId.java @@ -1,6 +1,6 @@ -package com.projectg.geyserupdater.common.update; +package dev.projectg.geyserupdater.common.update; -import com.projectg.geyserupdater.common.config.UpdaterConfiguration; +import dev.projectg.geyserupdater.common.config.UpdaterConfiguration; public enum PluginId { GEYSER("https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/", "org.geysermc.connector.GeyserConnector"), diff --git a/src/main/java/com/projectg/geyserupdater/common/update/RecursiveDownloadManager.java b/src/main/java/dev/projectg/geyserupdater/common/update/RecursiveDownloadManager.java similarity index 92% rename from src/main/java/com/projectg/geyserupdater/common/update/RecursiveDownloadManager.java rename to src/main/java/dev/projectg/geyserupdater/common/update/RecursiveDownloadManager.java index 7fcabec4..62562ae4 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/RecursiveDownloadManager.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/RecursiveDownloadManager.java @@ -1,10 +1,10 @@ -package com.projectg.geyserupdater.common.update; +package dev.projectg.geyserupdater.common.update; -import com.projectg.geyserupdater.common.GeyserUpdater; -import com.projectg.geyserupdater.common.logger.UpdaterLogger; -import com.projectg.geyserupdater.common.scheduler.Task; -import com.projectg.geyserupdater.common.scheduler.UpdaterScheduler; -import com.projectg.geyserupdater.common.util.WebUtils; +import dev.projectg.geyserupdater.common.GeyserUpdater; +import dev.projectg.geyserupdater.common.logger.UpdaterLogger; +import dev.projectg.geyserupdater.common.scheduler.Task; +import dev.projectg.geyserupdater.common.scheduler.UpdaterScheduler; +import dev.projectg.geyserupdater.common.util.WebUtils; import javax.annotation.Nullable; import java.io.IOException; diff --git a/src/main/java/com/projectg/geyserupdater/common/update/Updatable.java b/src/main/java/dev/projectg/geyserupdater/common/update/Updatable.java similarity index 95% rename from src/main/java/com/projectg/geyserupdater/common/update/Updatable.java rename to src/main/java/dev/projectg/geyserupdater/common/update/Updatable.java index 285f91e9..61e93290 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/Updatable.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/Updatable.java @@ -1,6 +1,6 @@ -package com.projectg.geyserupdater.common.update; +package dev.projectg.geyserupdater.common.update; -import com.projectg.geyserupdater.common.update.age.IdentityComparer; +import dev.projectg.geyserupdater.common.update.age.IdentityComparer; import javax.annotation.Nonnull; import javax.annotation.Nullable; diff --git a/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java b/src/main/java/dev/projectg/geyserupdater/common/update/UpdateManager.java similarity index 93% rename from src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java rename to src/main/java/dev/projectg/geyserupdater/common/update/UpdateManager.java index fac10033..451be801 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/UpdateManager.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/UpdateManager.java @@ -1,14 +1,14 @@ -package com.projectg.geyserupdater.common.update; - -import com.projectg.geyserupdater.common.config.UpdaterConfiguration; -import com.projectg.geyserupdater.common.logger.UpdaterLogger; -import com.projectg.geyserupdater.common.scheduler.UpdaterScheduler; -import com.projectg.geyserupdater.common.update.age.IdentityComparer; -import com.projectg.geyserupdater.common.update.age.provider.FileHashProvider; -import com.projectg.geyserupdater.common.update.age.provider.JenkinsBuildProvider; -import com.projectg.geyserupdater.common.update.age.provider.JenkinsHashProvider; -import com.projectg.geyserupdater.common.update.age.type.BuildNumber; -import com.projectg.geyserupdater.common.util.FileUtils; +package dev.projectg.geyserupdater.common.update; + +import dev.projectg.geyserupdater.common.config.UpdaterConfiguration; +import dev.projectg.geyserupdater.common.logger.UpdaterLogger; +import dev.projectg.geyserupdater.common.scheduler.UpdaterScheduler; +import dev.projectg.geyserupdater.common.update.age.IdentityComparer; +import dev.projectg.geyserupdater.common.update.age.provider.FileHashProvider; +import dev.projectg.geyserupdater.common.update.age.provider.JenkinsBuildProvider; +import dev.projectg.geyserupdater.common.update.age.provider.JenkinsHashProvider; +import dev.projectg.geyserupdater.common.update.age.type.BuildNumber; +import dev.projectg.geyserupdater.common.util.FileUtils; import java.io.IOException; import java.io.InputStream; diff --git a/src/main/java/com/projectg/geyserupdater/common/update/UpdateStatus.java b/src/main/java/dev/projectg/geyserupdater/common/update/UpdateStatus.java similarity index 90% rename from src/main/java/com/projectg/geyserupdater/common/update/UpdateStatus.java rename to src/main/java/dev/projectg/geyserupdater/common/update/UpdateStatus.java index a09ed3d6..60390bef 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/UpdateStatus.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/UpdateStatus.java @@ -1,4 +1,4 @@ -package com.projectg.geyserupdater.common.update; +package dev.projectg.geyserupdater.common.update; public enum UpdateStatus { /** diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/IdentityComparer.java b/src/main/java/dev/projectg/geyserupdater/common/update/age/IdentityComparer.java similarity index 92% rename from src/main/java/com/projectg/geyserupdater/common/update/age/IdentityComparer.java rename to src/main/java/dev/projectg/geyserupdater/common/update/age/IdentityComparer.java index cd19cb9d..b6ac7d97 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/age/IdentityComparer.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/age/IdentityComparer.java @@ -1,7 +1,7 @@ -package com.projectg.geyserupdater.common.update.age; +package dev.projectg.geyserupdater.common.update.age; -import com.projectg.geyserupdater.common.update.age.provider.IdentityProvider; -import com.projectg.geyserupdater.common.update.age.type.Identity; +import dev.projectg.geyserupdater.common.update.age.provider.IdentityProvider; +import dev.projectg.geyserupdater.common.update.age.type.Identity; import javax.annotation.Nonnull; import java.util.Objects; diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/provider/FileHashProvider.java b/src/main/java/dev/projectg/geyserupdater/common/update/age/provider/FileHashProvider.java similarity index 83% rename from src/main/java/com/projectg/geyserupdater/common/update/age/provider/FileHashProvider.java rename to src/main/java/dev/projectg/geyserupdater/common/update/age/provider/FileHashProvider.java index 577689ee..9f52e3e1 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/age/provider/FileHashProvider.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/age/provider/FileHashProvider.java @@ -1,10 +1,10 @@ -package com.projectg.geyserupdater.common.update.age.provider; +package dev.projectg.geyserupdater.common.update.age.provider; import com.google.common.hash.Hashing; import com.google.common.io.ByteSource; import com.google.common.io.Files; -import com.projectg.geyserupdater.common.logger.UpdaterLogger; -import com.projectg.geyserupdater.common.update.age.type.Md5FileHash; +import dev.projectg.geyserupdater.common.logger.UpdaterLogger; +import dev.projectg.geyserupdater.common.update.age.type.Md5FileHash; import java.io.IOException; import java.nio.file.Path; diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/provider/IdentityProvider.java b/src/main/java/dev/projectg/geyserupdater/common/update/age/provider/IdentityProvider.java similarity index 51% rename from src/main/java/com/projectg/geyserupdater/common/update/age/provider/IdentityProvider.java rename to src/main/java/dev/projectg/geyserupdater/common/update/age/provider/IdentityProvider.java index 5136449c..a0245a91 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/age/provider/IdentityProvider.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/age/provider/IdentityProvider.java @@ -1,6 +1,6 @@ -package com.projectg.geyserupdater.common.update.age.provider; +package dev.projectg.geyserupdater.common.update.age.provider; -import com.projectg.geyserupdater.common.update.age.type.Identity; +import dev.projectg.geyserupdater.common.update.age.type.Identity; import javax.annotation.Nullable; diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/provider/JenkinsBuildProvider.java b/src/main/java/dev/projectg/geyserupdater/common/update/age/provider/JenkinsBuildProvider.java similarity index 86% rename from src/main/java/com/projectg/geyserupdater/common/update/age/provider/JenkinsBuildProvider.java rename to src/main/java/dev/projectg/geyserupdater/common/update/age/provider/JenkinsBuildProvider.java index 443a4770..89de0e21 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/age/provider/JenkinsBuildProvider.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/age/provider/JenkinsBuildProvider.java @@ -1,8 +1,8 @@ -package com.projectg.geyserupdater.common.update.age.provider; +package dev.projectg.geyserupdater.common.update.age.provider; -import com.projectg.geyserupdater.common.logger.UpdaterLogger; -import com.projectg.geyserupdater.common.update.age.type.BuildNumber; -import com.projectg.geyserupdater.common.util.WebUtils; +import dev.projectg.geyserupdater.common.logger.UpdaterLogger; +import dev.projectg.geyserupdater.common.update.age.type.BuildNumber; +import dev.projectg.geyserupdater.common.util.WebUtils; import java.io.IOException; import java.net.MalformedURLException; diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/provider/JenkinsHashProvider.java b/src/main/java/dev/projectg/geyserupdater/common/update/age/provider/JenkinsHashProvider.java similarity index 91% rename from src/main/java/com/projectg/geyserupdater/common/update/age/provider/JenkinsHashProvider.java rename to src/main/java/dev/projectg/geyserupdater/common/update/age/provider/JenkinsHashProvider.java index acbd9751..eeacb098 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/age/provider/JenkinsHashProvider.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/age/provider/JenkinsHashProvider.java @@ -1,7 +1,7 @@ -package com.projectg.geyserupdater.common.update.age.provider; +package dev.projectg.geyserupdater.common.update.age.provider; -import com.projectg.geyserupdater.common.logger.UpdaterLogger; -import com.projectg.geyserupdater.common.update.age.type.Md5FileHash; +import dev.projectg.geyserupdater.common.logger.UpdaterLogger; +import dev.projectg.geyserupdater.common.update.age.type.Md5FileHash; import java.io.BufferedReader; import java.io.IOException; diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/type/BuildNumber.java b/src/main/java/dev/projectg/geyserupdater/common/update/age/type/BuildNumber.java similarity index 81% rename from src/main/java/com/projectg/geyserupdater/common/update/age/type/BuildNumber.java rename to src/main/java/dev/projectg/geyserupdater/common/update/age/type/BuildNumber.java index 477797a6..7f245ba8 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/age/type/BuildNumber.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/age/type/BuildNumber.java @@ -1,4 +1,4 @@ -package com.projectg.geyserupdater.common.update.age.type; +package dev.projectg.geyserupdater.common.update.age.type; public class BuildNumber implements Identity { diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/type/Identity.java b/src/main/java/dev/projectg/geyserupdater/common/update/age/type/Identity.java similarity index 75% rename from src/main/java/com/projectg/geyserupdater/common/update/age/type/Identity.java rename to src/main/java/dev/projectg/geyserupdater/common/update/age/type/Identity.java index 7115f7ff..0e6c4909 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/age/type/Identity.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/age/type/Identity.java @@ -1,4 +1,4 @@ -package com.projectg.geyserupdater.common.update.age.type; +package dev.projectg.geyserupdater.common.update.age.type; /** * Provides implementation for something that can be quantified as an age of something. diff --git a/src/main/java/com/projectg/geyserupdater/common/update/age/type/Md5FileHash.java b/src/main/java/dev/projectg/geyserupdater/common/update/age/type/Md5FileHash.java similarity index 79% rename from src/main/java/com/projectg/geyserupdater/common/update/age/type/Md5FileHash.java rename to src/main/java/dev/projectg/geyserupdater/common/update/age/type/Md5FileHash.java index 0c27b40f..6c6c3541 100644 --- a/src/main/java/com/projectg/geyserupdater/common/update/age/type/Md5FileHash.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/age/type/Md5FileHash.java @@ -1,4 +1,4 @@ -package com.projectg.geyserupdater.common.update.age.type; +package dev.projectg.geyserupdater.common.update.age.type; public class Md5FileHash implements Identity { diff --git a/src/main/java/com/projectg/geyserupdater/common/util/FileUtils.java b/src/main/java/dev/projectg/geyserupdater/common/util/FileUtils.java similarity index 92% rename from src/main/java/com/projectg/geyserupdater/common/util/FileUtils.java rename to src/main/java/dev/projectg/geyserupdater/common/util/FileUtils.java index 3e114590..3be1606c 100644 --- a/src/main/java/com/projectg/geyserupdater/common/util/FileUtils.java +++ b/src/main/java/dev/projectg/geyserupdater/common/util/FileUtils.java @@ -1,8 +1,8 @@ -package com.projectg.geyserupdater.common.util; +package dev.projectg.geyserupdater.common.util; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; -import com.projectg.geyserupdater.common.config.UpdaterConfiguration; +import dev.projectg.geyserupdater.common.config.UpdaterConfiguration; import java.io.IOException; import java.io.InputStream; diff --git a/src/main/java/com/projectg/geyserupdater/common/util/OsUtils.java b/src/main/java/dev/projectg/geyserupdater/common/util/OsUtils.java similarity index 95% rename from src/main/java/com/projectg/geyserupdater/common/util/OsUtils.java rename to src/main/java/dev/projectg/geyserupdater/common/util/OsUtils.java index 473d7739..c5275e37 100644 --- a/src/main/java/com/projectg/geyserupdater/common/util/OsUtils.java +++ b/src/main/java/dev/projectg/geyserupdater/common/util/OsUtils.java @@ -1,4 +1,4 @@ -package com.projectg.geyserupdater.common.util; +package dev.projectg.geyserupdater.common.util; public class OsUtils { diff --git a/src/main/java/com/projectg/geyserupdater/common/util/ScriptCreator.java b/src/main/java/dev/projectg/geyserupdater/common/util/ScriptCreator.java similarity index 96% rename from src/main/java/com/projectg/geyserupdater/common/util/ScriptCreator.java rename to src/main/java/dev/projectg/geyserupdater/common/util/ScriptCreator.java index c5883dcc..f18be179 100644 --- a/src/main/java/com/projectg/geyserupdater/common/util/ScriptCreator.java +++ b/src/main/java/dev/projectg/geyserupdater/common/util/ScriptCreator.java @@ -1,6 +1,6 @@ -package com.projectg.geyserupdater.common.util; +package dev.projectg.geyserupdater.common.util; -import com.projectg.geyserupdater.common.logger.UpdaterLogger; +import dev.projectg.geyserupdater.common.logger.UpdaterLogger; import java.io.DataOutputStream; import java.io.File; diff --git a/src/main/java/com/projectg/geyserupdater/common/util/SpigotResourceUpdateChecker.java b/src/main/java/dev/projectg/geyserupdater/common/util/SpigotResourceUpdateChecker.java similarity index 92% rename from src/main/java/com/projectg/geyserupdater/common/util/SpigotResourceUpdateChecker.java rename to src/main/java/dev/projectg/geyserupdater/common/util/SpigotResourceUpdateChecker.java index 08e02db0..652ea972 100644 --- a/src/main/java/com/projectg/geyserupdater/common/util/SpigotResourceUpdateChecker.java +++ b/src/main/java/dev/projectg/geyserupdater/common/util/SpigotResourceUpdateChecker.java @@ -1,6 +1,6 @@ -package com.projectg.geyserupdater.common.util; +package dev.projectg.geyserupdater.common.util; -import com.projectg.geyserupdater.common.logger.UpdaterLogger; +import dev.projectg.geyserupdater.common.logger.UpdaterLogger; import java.io.IOException; import java.io.InputStream; diff --git a/src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java b/src/main/java/dev/projectg/geyserupdater/common/util/WebUtils.java similarity index 95% rename from src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java rename to src/main/java/dev/projectg/geyserupdater/common/util/WebUtils.java index 33be47a3..ad807701 100644 --- a/src/main/java/com/projectg/geyserupdater/common/util/WebUtils.java +++ b/src/main/java/dev/projectg/geyserupdater/common/util/WebUtils.java @@ -1,14 +1,12 @@ -package com.projectg.geyserupdater.common.util; +package dev.projectg.geyserupdater.common.util; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.projectg.geyserupdater.common.GeyserUpdater; +import dev.projectg.geyserupdater.common.GeyserUpdater; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; diff --git a/src/main/java/com/projectg/geyserupdater/spigot/SpigotPlayerHandler.java b/src/main/java/dev/projectg/geyserupdater/spigot/SpigotPlayerHandler.java similarity index 86% rename from src/main/java/com/projectg/geyserupdater/spigot/SpigotPlayerHandler.java rename to src/main/java/dev/projectg/geyserupdater/spigot/SpigotPlayerHandler.java index c1f3c270..bf80f00e 100644 --- a/src/main/java/com/projectg/geyserupdater/spigot/SpigotPlayerHandler.java +++ b/src/main/java/dev/projectg/geyserupdater/spigot/SpigotPlayerHandler.java @@ -1,7 +1,6 @@ -package com.projectg.geyserupdater.spigot; +package dev.projectg.geyserupdater.spigot; -import com.projectg.geyserupdater.common.PlayerHandler; -import org.bukkit.Bukkit; +import dev.projectg.geyserupdater.common.PlayerHandler; import org.bukkit.Server; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/projectg/geyserupdater/spigot/SpigotScheduler.java b/src/main/java/dev/projectg/geyserupdater/spigot/SpigotScheduler.java similarity index 92% rename from src/main/java/com/projectg/geyserupdater/spigot/SpigotScheduler.java rename to src/main/java/dev/projectg/geyserupdater/spigot/SpigotScheduler.java index b1dfbda8..2cf37149 100644 --- a/src/main/java/com/projectg/geyserupdater/spigot/SpigotScheduler.java +++ b/src/main/java/dev/projectg/geyserupdater/spigot/SpigotScheduler.java @@ -1,7 +1,7 @@ -package com.projectg.geyserupdater.spigot; +package dev.projectg.geyserupdater.spigot; -import com.projectg.geyserupdater.common.scheduler.Task; -import com.projectg.geyserupdater.common.scheduler.UpdaterScheduler; +import dev.projectg.geyserupdater.common.scheduler.Task; +import dev.projectg.geyserupdater.common.scheduler.UpdaterScheduler; import org.bukkit.plugin.Plugin; import org.bukkit.scheduler.BukkitScheduler; import org.bukkit.scheduler.BukkitTask; diff --git a/src/main/java/com/projectg/geyserupdater/spigot/SpigotUpdater.java b/src/main/java/dev/projectg/geyserupdater/spigot/SpigotUpdater.java similarity index 78% rename from src/main/java/com/projectg/geyserupdater/spigot/SpigotUpdater.java rename to src/main/java/dev/projectg/geyserupdater/spigot/SpigotUpdater.java index 877ce49b..2c30c91a 100644 --- a/src/main/java/com/projectg/geyserupdater/spigot/SpigotUpdater.java +++ b/src/main/java/dev/projectg/geyserupdater/spigot/SpigotUpdater.java @@ -1,12 +1,12 @@ -package com.projectg.geyserupdater.spigot; +package dev.projectg.geyserupdater.spigot; -import com.projectg.geyserupdater.common.GeyserUpdater; -import com.projectg.geyserupdater.common.UpdaterBootstrap; -import com.projectg.geyserupdater.common.logger.JavaUtilUpdaterLogger; -import com.projectg.geyserupdater.common.logger.UpdaterLogger; -import com.projectg.geyserupdater.spigot.command.GeyserUpdateCommand; -import com.projectg.geyserupdater.spigot.util.CheckSpigotRestart; -import com.projectg.geyserupdater.spigot.util.bstats.Metrics; +import dev.projectg.geyserupdater.common.GeyserUpdater; +import dev.projectg.geyserupdater.common.UpdaterBootstrap; +import dev.projectg.geyserupdater.common.logger.JavaUtilUpdaterLogger; +import dev.projectg.geyserupdater.common.logger.UpdaterLogger; +import dev.projectg.geyserupdater.spigot.command.GeyserUpdateCommand; +import dev.projectg.geyserupdater.spigot.util.CheckSpigotRestart; +import dev.projectg.geyserupdater.spigot.util.bstats.Metrics; import org.bukkit.Server; import org.bukkit.plugin.java.JavaPlugin; diff --git a/src/main/java/com/projectg/geyserupdater/spigot/command/GeyserUpdateCommand.java b/src/main/java/dev/projectg/geyserupdater/spigot/command/GeyserUpdateCommand.java similarity index 87% rename from src/main/java/com/projectg/geyserupdater/spigot/command/GeyserUpdateCommand.java rename to src/main/java/dev/projectg/geyserupdater/spigot/command/GeyserUpdateCommand.java index c6aa0276..a01e0d4a 100644 --- a/src/main/java/com/projectg/geyserupdater/spigot/command/GeyserUpdateCommand.java +++ b/src/main/java/dev/projectg/geyserupdater/spigot/command/GeyserUpdateCommand.java @@ -1,19 +1,13 @@ -package com.projectg.geyserupdater.spigot.command; +package dev.projectg.geyserupdater.spigot.command; -import com.projectg.geyserupdater.common.Messages; -import com.projectg.geyserupdater.common.logger.UpdaterLogger; +import dev.projectg.geyserupdater.common.logger.UpdaterLogger; -import org.bukkit.ChatColor; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; -import org.bukkit.command.ConsoleCommandSender; -import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import java.io.IOException; - public class GeyserUpdateCommand implements CommandExecutor { @Override diff --git a/src/main/java/com/projectg/geyserupdater/spigot/util/CheckSpigotRestart.java b/src/main/java/dev/projectg/geyserupdater/spigot/util/CheckSpigotRestart.java similarity index 90% rename from src/main/java/com/projectg/geyserupdater/spigot/util/CheckSpigotRestart.java rename to src/main/java/dev/projectg/geyserupdater/spigot/util/CheckSpigotRestart.java index 3c85fdcd..66f829c4 100644 --- a/src/main/java/com/projectg/geyserupdater/spigot/util/CheckSpigotRestart.java +++ b/src/main/java/dev/projectg/geyserupdater/spigot/util/CheckSpigotRestart.java @@ -1,8 +1,8 @@ -package com.projectg.geyserupdater.spigot.util; +package dev.projectg.geyserupdater.spigot.util; -import com.projectg.geyserupdater.common.logger.UpdaterLogger; -import com.projectg.geyserupdater.common.util.OsUtils; -import com.projectg.geyserupdater.common.util.ScriptCreator; +import dev.projectg.geyserupdater.common.logger.UpdaterLogger; +import dev.projectg.geyserupdater.common.util.OsUtils; +import dev.projectg.geyserupdater.common.util.ScriptCreator; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; diff --git a/src/main/java/com/projectg/geyserupdater/spigot/util/bstats/Metrics.java b/src/main/java/dev/projectg/geyserupdater/spigot/util/bstats/Metrics.java similarity index 99% rename from src/main/java/com/projectg/geyserupdater/spigot/util/bstats/Metrics.java rename to src/main/java/dev/projectg/geyserupdater/spigot/util/bstats/Metrics.java index b3b4d3a6..c58c626c 100644 --- a/src/main/java/com/projectg/geyserupdater/spigot/util/bstats/Metrics.java +++ b/src/main/java/dev/projectg/geyserupdater/spigot/util/bstats/Metrics.java @@ -1,4 +1,4 @@ -package com.projectg.geyserupdater.spigot.util.bstats; +package dev.projectg.geyserupdater.spigot.util.bstats; import com.google.gson.JsonArray; import com.google.gson.JsonObject; diff --git a/src/main/java/com/projectg/geyserupdater/velocity/VelocityPlayerHandler.java b/src/main/java/dev/projectg/geyserupdater/velocity/VelocityPlayerHandler.java similarity index 89% rename from src/main/java/com/projectg/geyserupdater/velocity/VelocityPlayerHandler.java rename to src/main/java/dev/projectg/geyserupdater/velocity/VelocityPlayerHandler.java index 9a958c83..597182fb 100644 --- a/src/main/java/com/projectg/geyserupdater/velocity/VelocityPlayerHandler.java +++ b/src/main/java/dev/projectg/geyserupdater/velocity/VelocityPlayerHandler.java @@ -1,6 +1,6 @@ -package com.projectg.geyserupdater.velocity; +package dev.projectg.geyserupdater.velocity; -import com.projectg.geyserupdater.common.PlayerHandler; +import dev.projectg.geyserupdater.common.PlayerHandler; import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.ProxyServer; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/projectg/geyserupdater/velocity/VelocityScheduler.java b/src/main/java/dev/projectg/geyserupdater/velocity/VelocityScheduler.java similarity index 88% rename from src/main/java/com/projectg/geyserupdater/velocity/VelocityScheduler.java rename to src/main/java/dev/projectg/geyserupdater/velocity/VelocityScheduler.java index 0fd6bff2..2e0999ac 100644 --- a/src/main/java/com/projectg/geyserupdater/velocity/VelocityScheduler.java +++ b/src/main/java/dev/projectg/geyserupdater/velocity/VelocityScheduler.java @@ -1,7 +1,7 @@ -package com.projectg.geyserupdater.velocity; +package dev.projectg.geyserupdater.velocity; -import com.projectg.geyserupdater.common.scheduler.Task; -import com.projectg.geyserupdater.common.scheduler.UpdaterScheduler; +import dev.projectg.geyserupdater.common.scheduler.Task; +import dev.projectg.geyserupdater.common.scheduler.UpdaterScheduler; import com.velocitypowered.api.scheduler.ScheduledTask; import javax.annotation.Nonnull; diff --git a/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java b/src/main/java/dev/projectg/geyserupdater/velocity/VelocityUpdater.java similarity index 85% rename from src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java rename to src/main/java/dev/projectg/geyserupdater/velocity/VelocityUpdater.java index 5c2279a9..5c40a017 100644 --- a/src/main/java/com/projectg/geyserupdater/velocity/VelocityUpdater.java +++ b/src/main/java/dev/projectg/geyserupdater/velocity/VelocityUpdater.java @@ -1,13 +1,13 @@ -package com.projectg.geyserupdater.velocity; +package dev.projectg.geyserupdater.velocity; import com.google.inject.Inject; -import com.projectg.geyserupdater.common.GeyserUpdater; -import com.projectg.geyserupdater.common.UpdaterBootstrap; -import com.projectg.geyserupdater.common.logger.UpdaterLogger; -import com.projectg.geyserupdater.common.util.ScriptCreator; -import com.projectg.geyserupdater.velocity.command.GeyserUpdateCommand; -import com.projectg.geyserupdater.velocity.logger.Slf4jUpdaterLogger; -import com.projectg.geyserupdater.velocity.bstats.Metrics; +import dev.projectg.geyserupdater.common.GeyserUpdater; +import dev.projectg.geyserupdater.common.UpdaterBootstrap; +import dev.projectg.geyserupdater.common.logger.UpdaterLogger; +import dev.projectg.geyserupdater.common.util.ScriptCreator; +import dev.projectg.geyserupdater.velocity.command.GeyserUpdateCommand; +import dev.projectg.geyserupdater.velocity.logger.Slf4jUpdaterLogger; +import dev.projectg.geyserupdater.velocity.bstats.Metrics; import com.velocitypowered.api.event.PostOrder; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; diff --git a/src/main/java/com/projectg/geyserupdater/velocity/bstats/Metrics.java b/src/main/java/dev/projectg/geyserupdater/velocity/bstats/Metrics.java similarity index 99% rename from src/main/java/com/projectg/geyserupdater/velocity/bstats/Metrics.java rename to src/main/java/dev/projectg/geyserupdater/velocity/bstats/Metrics.java index 8f42d367..4884ae47 100644 --- a/src/main/java/com/projectg/geyserupdater/velocity/bstats/Metrics.java +++ b/src/main/java/dev/projectg/geyserupdater/velocity/bstats/Metrics.java @@ -1,4 +1,4 @@ -package com.projectg.geyserupdater.velocity.bstats; +package dev.projectg.geyserupdater.velocity.bstats; import com.google.inject.Inject; import com.velocitypowered.api.plugin.PluginContainer; diff --git a/src/main/java/com/projectg/geyserupdater/velocity/command/GeyserUpdateCommand.java b/src/main/java/dev/projectg/geyserupdater/velocity/command/GeyserUpdateCommand.java similarity index 95% rename from src/main/java/com/projectg/geyserupdater/velocity/command/GeyserUpdateCommand.java rename to src/main/java/dev/projectg/geyserupdater/velocity/command/GeyserUpdateCommand.java index dd2e10e2..51b3196b 100644 --- a/src/main/java/com/projectg/geyserupdater/velocity/command/GeyserUpdateCommand.java +++ b/src/main/java/dev/projectg/geyserupdater/velocity/command/GeyserUpdateCommand.java @@ -1,4 +1,4 @@ -package com.projectg.geyserupdater.velocity.command; +package dev.projectg.geyserupdater.velocity.command; import com.velocitypowered.api.command.RawCommand; diff --git a/src/main/java/com/projectg/geyserupdater/velocity/logger/Slf4jUpdaterLogger.java b/src/main/java/dev/projectg/geyserupdater/velocity/logger/Slf4jUpdaterLogger.java similarity index 91% rename from src/main/java/com/projectg/geyserupdater/velocity/logger/Slf4jUpdaterLogger.java rename to src/main/java/dev/projectg/geyserupdater/velocity/logger/Slf4jUpdaterLogger.java index d8fbb5f5..9bfc2fde 100644 --- a/src/main/java/com/projectg/geyserupdater/velocity/logger/Slf4jUpdaterLogger.java +++ b/src/main/java/dev/projectg/geyserupdater/velocity/logger/Slf4jUpdaterLogger.java @@ -1,6 +1,6 @@ -package com.projectg.geyserupdater.velocity.logger; +package dev.projectg.geyserupdater.velocity.logger; -import com.projectg.geyserupdater.common.logger.UpdaterLogger; +import dev.projectg.geyserupdater.common.logger.UpdaterLogger; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.config.Configurator; import org.slf4j.Logger; diff --git a/src/main/resources/bungee.yml b/src/main/resources/bungee.yml index a6c8df87..a55d0c0e 100644 --- a/src/main/resources/bungee.yml +++ b/src/main/resources/bungee.yml @@ -1,5 +1,5 @@ name: ${project.name} -main: com.projectg.geyserupdater.bungee.BungeeUpdater +main: dev.projectg.geyserupdater.bungee.BungeeUpdater version: ${project.version} description: Automatically or manually downloads new builds of Geyser and applies them on server restart. author: Jens, Konicai \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index a3a20926..441c8e9f 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,5 +1,5 @@ name: ${project.name} -main: com.projectg.geyserupdater.spigot.SpigotUpdater +main: dev.projectg.geyserupdater.spigot.SpigotUpdater version: ${project.version} api-version: 1.13 description: Automatically or manually downloads new builds of Geyser and applies them on server restart. From 1d501849619a76e1ec3e9ee9a293523067b12568 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Sun, 22 Aug 2021 21:04:04 -0400 Subject: [PATCH 26/42] fix getting git.properties Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../dev/projectg/geyserupdater/common/update/UpdateManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dev/projectg/geyserupdater/common/update/UpdateManager.java b/src/main/java/dev/projectg/geyserupdater/common/update/UpdateManager.java index 451be801..9fe56cf6 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/update/UpdateManager.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/UpdateManager.java @@ -43,7 +43,7 @@ public UpdateManager(Path defaultDownloadLocation, UpdaterScheduler scheduler, U for (PluginId pluginId : PluginId.values()) { if (pluginId.isEnable()) { // Get the git.properties - InputStream is = pluginId.getPluginClass().getResourceAsStream("git.properties"); + InputStream is = pluginId.getPluginClass().getClassLoader().getResourceAsStream("git.properties"); if (is == null) { throw new AssertionError("Unable to find resource 'git.properties' for plugin: " + pluginId.name()); } From 1046d20c5423efa8aef59258cfc21b977d5f54f6 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Sun, 22 Aug 2021 21:13:42 -0400 Subject: [PATCH 27/42] fix floodgate and geyser artifact links Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../java/dev/projectg/geyserupdater/bungee/BungeeUpdater.java | 4 ++-- .../java/dev/projectg/geyserupdater/spigot/SpigotUpdater.java | 4 ++-- .../dev/projectg/geyserupdater/velocity/VelocityUpdater.java | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/dev/projectg/geyserupdater/bungee/BungeeUpdater.java b/src/main/java/dev/projectg/geyserupdater/bungee/BungeeUpdater.java index 50ed31b4..2cf93d45 100644 --- a/src/main/java/dev/projectg/geyserupdater/bungee/BungeeUpdater.java +++ b/src/main/java/dev/projectg/geyserupdater/bungee/BungeeUpdater.java @@ -30,8 +30,8 @@ public void onEnable() { new BungeeScheduler(this), new BungeePlayerHandler(), this.getDescription().getVersion(), - "/artifact/bootstrap/bungeecord/target/Geyser-BungeeCord.jar", - "/artifact/bootstrap/bungee/target/floodgate-bungee.jar" + "bootstrap/bungeecord/target/Geyser-BungeeCord.jar", + "bootstrap/bungee/target/floodgate-bungee.jar" ); } catch (IOException e) { getLogger().severe("Failed to start GeyserUpdater! Disabling..."); diff --git a/src/main/java/dev/projectg/geyserupdater/spigot/SpigotUpdater.java b/src/main/java/dev/projectg/geyserupdater/spigot/SpigotUpdater.java index 2c30c91a..e9bbe821 100644 --- a/src/main/java/dev/projectg/geyserupdater/spigot/SpigotUpdater.java +++ b/src/main/java/dev/projectg/geyserupdater/spigot/SpigotUpdater.java @@ -34,8 +34,8 @@ public void onEnable() { new SpigotScheduler(this), new SpigotPlayerHandler(server), this.getDescription().getVersion(), - "/artifact/bootstrap/spigot/target/Geyser-Spigot.jar", - "/artifact/bootstrap/spigot/target/floodgate-spigot.jar" + "bootstrap/spigot/target/Geyser-Spigot.jar", + "bootstrap/spigot/target/floodgate-spigot.jar" ); } catch (IOException e) { getLogger().severe("Failed to start GeyserUpdater! Disabling..."); diff --git a/src/main/java/dev/projectg/geyserupdater/velocity/VelocityUpdater.java b/src/main/java/dev/projectg/geyserupdater/velocity/VelocityUpdater.java index 5c40a017..407e5c19 100644 --- a/src/main/java/dev/projectg/geyserupdater/velocity/VelocityUpdater.java +++ b/src/main/java/dev/projectg/geyserupdater/velocity/VelocityUpdater.java @@ -53,8 +53,8 @@ public void onProxyInitialization(ProxyInitializeEvent event) throws IOException new VelocityScheduler(this), new VelocityPlayerHandler(server), VERSION, - "/artifact/bootstrap/velocity/target/Geyser-Velocity.jar", - "/artifact/bootstrap/velocity/target/floodgate-velocity.jar" + "bootstrap/velocity/target/Geyser-Velocity.jar", + "bootstrap/velocity/target/floodgate-velocity.jar" ); // Register our only command From 37c344222bfd9f2c9f7b54e544e426c59fddaf51 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Sun, 22 Aug 2021 21:37:43 -0400 Subject: [PATCH 28/42] fix getting build number from jenkins Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../common/update/age/IdentityComparer.java | 9 +++++++-- .../update/age/provider/JenkinsBuildProvider.java | 10 ++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/main/java/dev/projectg/geyserupdater/common/update/age/IdentityComparer.java b/src/main/java/dev/projectg/geyserupdater/common/update/age/IdentityComparer.java index b6ac7d97..b3149326 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/update/age/IdentityComparer.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/age/IdentityComparer.java @@ -46,10 +46,15 @@ public IdentityComparer(@Nonnull S localIdentity, @Nonnull T externalIdentityPro * @return True if the local identity {@link Object#equals(Object)} the external identity */ public boolean checkIfEquals() { + // todo: return an enum if (localIdentity == null) { - return false; + return true; + } + S externalIdentity = externalIdentityProvider.getValue(); + if (externalIdentity == null) { + return true; } - return localIdentity.value().equals(externalIdentityProvider.getValue()); + return localIdentity.value().equals(externalIdentity.value()); } } diff --git a/src/main/java/dev/projectg/geyserupdater/common/update/age/provider/JenkinsBuildProvider.java b/src/main/java/dev/projectg/geyserupdater/common/update/age/provider/JenkinsBuildProvider.java index 89de0e21..ebe284f4 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/update/age/provider/JenkinsBuildProvider.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/age/provider/JenkinsBuildProvider.java @@ -26,20 +26,22 @@ public JenkinsBuildProvider(String link) throws MalformedURLException { @Override public BuildNumber getValue() { + BuildNumber buildNumber = null; try { String body = WebUtils.getBody(url); + String number = body.substring(0, body.length() - 1); //fixme: getBody() adds a newline char at the end try { - return new BuildNumber(Integer.parseInt(body)); + buildNumber = new BuildNumber(Integer.parseInt(number)); } catch (NumberFormatException e) { UpdaterLogger.getLogger().error("Failed to get a build number from a Jenkins server because an integer was not returned."); - UpdaterLogger.getLogger().error("Body returned: " + body); + UpdaterLogger.getLogger().error("Body returned: <" + number + "> (excluding the angle brackets)"); e.printStackTrace(); - return null; } } catch (IOException e) { UpdaterLogger.getLogger().error("Failed to get a build number from a Jenkins server:"); e.printStackTrace(); - return null; } + + return buildNumber; } } From 140f2ed10d48afa4a3030c201ea9ab6de44c2c65 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Sun, 22 Aug 2021 21:43:16 -0400 Subject: [PATCH 29/42] make sure to flag updatable as DOWNLOADING before downloading Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../projectg/geyserupdater/common/update/UpdateManager.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/dev/projectg/geyserupdater/common/update/UpdateManager.java b/src/main/java/dev/projectg/geyserupdater/common/update/UpdateManager.java index 9fe56cf6..9d85142d 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/update/UpdateManager.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/UpdateManager.java @@ -194,6 +194,7 @@ private void scheduleUpdateChecker(UpdaterScheduler scheduler, long interval) { registry.put(updatable, UpdateStatus.OUTDATED); outdatedOnes.add(updatable.toString()); if (updatable.autoUpdate) { + registry.put(updatable, UpdateStatus.DOWNLOADING); downloadManager.queue(updatable); autoDownloads.add(updatable.toString()); } @@ -204,9 +205,9 @@ private void scheduleUpdateChecker(UpdaterScheduler scheduler, long interval) { // todo: also send messages to players with the permission if (!outdatedOnes.isEmpty()) { UpdaterLogger logger = UpdaterLogger.getLogger(); - logger.info("The following updatables are outdated: " + outdatedOnes.toString().substring(0, outdatedOnes.size())); + logger.info("The following updatables are outdated: " + outdatedOnes); if (!autoDownloads.isEmpty()) { - logger.info("The following updatables are set to download automatically and have been queued for download: " + autoDownloads.toString().substring(0, autoDownloads.size())); + logger.info("The following updatables are set to download automatically and have been queued for download: " + autoDownloads); } } From cf8c3ad1a739c066a7b2b456e235cd48af5d19fe Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Sun, 22 Aug 2021 21:47:02 -0400 Subject: [PATCH 30/42] fix update manager when reaching end of queue Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../common/update/DownloadManager.java | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/main/java/dev/projectg/geyserupdater/common/update/DownloadManager.java b/src/main/java/dev/projectg/geyserupdater/common/update/DownloadManager.java index 754974ad..a5311686 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/update/DownloadManager.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/DownloadManager.java @@ -9,6 +9,7 @@ import java.io.IOException; import java.util.LinkedList; import java.util.List; +import java.util.Objects; import java.util.concurrent.TimeUnit; public class DownloadManager { @@ -47,28 +48,24 @@ private void downloadAll() { // Run the download on a new thread this.downloader = scheduler.run(() -> { - while (true) { - Updatable updatable = queue.get(0); - if (updatable == null) { - break; - } - currentUpdate = updatable; + while (!queue.isEmpty()) { + currentUpdate = Objects.requireNonNull(queue.get(0)); // Create a timer to stop this download from running too long. Either the hang checker is cancelled or the hang checker cancels this. - Task hangChecker = scheduleHangChecker(updatable); + Task hangChecker = scheduleHangChecker(currentUpdate); try { - WebUtils.downloadFile(updatable.downloadUrl, updatable.outputFile); + WebUtils.downloadFile(currentUpdate.downloadUrl, currentUpdate.outputFile); } catch (IOException e) { - UpdaterLogger.getLogger().error("Caught exception while downloading file " + updatable.outputFile + " with URL: " + updatable.downloadUrl); + UpdaterLogger.getLogger().error("Caught exception while downloading file " + currentUpdate.outputFile + " with URL: " + currentUpdate.downloadUrl); e.printStackTrace(); - updateManager.finish(updatable, DownloadResult.UNKNOWN_FAIL); + updateManager.finish(currentUpdate, DownloadResult.UNKNOWN_FAIL); continue; } hangChecker.cancel(); queue.remove(0); - updateManager.finish(updatable, DownloadResult.SUCCESS); + updateManager.finish(currentUpdate, DownloadResult.SUCCESS); } // Revert everything while having it locked so that the state is always correctly read by a different thread From 989567fecdc8377080818e749ea9f7b2b2edd31a Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Mon, 23 Aug 2021 12:13:35 -0400 Subject: [PATCH 31/42] Create devconfig.yml --- devconfig.yml | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 devconfig.yml diff --git a/devconfig.yml b/devconfig.yml new file mode 100644 index 00000000..4462cd7a --- /dev/null +++ b/devconfig.yml @@ -0,0 +1,38 @@ +# GeyserUpdater configuration with more settings enabled +# Made by Jens & YHDiamond + +# NOTICE: Please read the README on our github page for full information regarding these options! +# https://github.com/ProjectG-Plugins/GeyserUpdater + +default-updates: + geyser: + enable: true + auto-check: true + auto-update: true + floodgate: + enable: false + auto-check: true + auto-update: false + +# The interval in hours between each auto update check. +auto-update-interval: 24 +# The maximum amount of seconds that a download is allowed to run for. Increase if you are running into issues on a slow internet connection. +download-time-limit: 300 +# Delete the downloaded file if the file hash of the downloaded file did not match what the download server provided. +# Or if the file hash was not checked and the download time limit was reached, or an exception occurred. +# If the file hash is not correct the downloaded file is likely corrupt or unfinished. +delete-on-fail: true + +# If enabled, GeyserUpdater will attempt to restart the server 10 seconds after a new version of Geyser has been successfully downloaded. +# If you aren't using a hosting provider or a server wrapper, you will need a restart script. +auto-restart-server: true +# When enabled, GeyserUpdater will automatically generate a restart script for you. If you are using CraftBukkit or a proxy +# you will need to use the generated script to start your server! If you are using a hosting provider or a server wrapper you probably don't need this. +auto-script-generating: true +# Configure the message that is sent to all online players warning them that the server will be restarting in 10 seconds. +restart-message-players: "§2This server will be restarting in 10 seconds!" + +# Enable debug logging +enable-debug: true +# Please do not change this version value! +config-version: 3 From ea0e4b35939e050c33ef65c91cb24dab3c1c5d03 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Mon, 23 Aug 2021 12:40:09 -0400 Subject: [PATCH 32/42] update deploy script Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- guDeploy.sh | 65 +++++++++++++++++++++-------------------------------- 1 file changed, 26 insertions(+), 39 deletions(-) diff --git a/guDeploy.sh b/guDeploy.sh index 19ffe375..f6f20b2e 100644 --- a/guDeploy.sh +++ b/guDeploy.sh @@ -14,14 +14,14 @@ waterDir="Waterfall-guDeploy" velocityDir="Velocity-guDeploy" #Links -guLink="https://ci.projectg.dev/job/GeyserUpdater/job/1.5.0/lastSuccessfulBuild/artifact/target/GeyserUpdater-1.5.0.jar" -geyserLink="https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/master/720/artifact/bootstrap/" +guLink="https://ci.projectg.dev/job/GeyserUpdater/job/1.6.0/lastSuccessfulBuild/artifact/target/GeyserUpdater-1.6.0.jar" +geyserLink="https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/master/821/artifact/bootstrap/" buildToolsLink="https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar" -paperLink="https://papermc.io/api/v2/projects/paper/versions/1.16.5/builds/750/downloads/paper-1.16.5-750.jar" +paperLink="https://papermc.io/api/v2/projects/paper/versions/1.17.1/builds/209/downloads/paper-1.17.1-209.jar" bungeeLink="https://ci.md-5.net/job/BungeeCord/lastSuccessfulBuild/artifact/bootstrap/target/BungeeCord.jar" -waterLink="https://papermc.io/api/v2/projects/waterfall/versions/1.16/builds/425/downloads/waterfall-1.16-425.jar" -velocityLink="https://versions.velocitypowered.com/download/1.1.5.jar" +waterLink="https://papermc.io/api/v2/projects/waterfall/versions/1.17/builds/448/downloads/waterfall-1.17-448.jar" +velocityLink="https://versions.velocitypowered.com/download/3.0.0.jar" echo "[WARN] This script can generate up to 500MB of data!" @@ -40,12 +40,20 @@ else fi # Download file for a given link +# first arg is link, second arg is output file name (optional) download () { - jarURL="$1" if [[ "$downloadCmd" == "curl" ]]; then - curl "$jarURL" -O + if [[ -z "$2" ]]; then + curl "$1" -O + else + curl "$1" --output "$2" + fi else - wget "$jarURL" + if [[ -z "$2" ]]; then + wget "$1" + else + curl "$1" --output-document "$2" + fi fi } @@ -57,8 +65,14 @@ getAllPlugins () { mkdir "$pluginCache" cd "$pluginCache" || exit - mkdir Common - cd Common || exit + mkdir "Common" + cd "Common" || exit + mkdir "GeyserUpdater" + cd "GeyserUpdater" || exit + echo + echo "[INFO] Downloading GeyserUpdater config" + download "https://raw.githubusercontent.com/ProjectG-Plugins/GeyserUpdater/1.6.0/devconfig.yml" "config.yml" + cd ../ echo echo "[INFO] Downloading GeyserUpdater" download "$guLink" @@ -66,31 +80,13 @@ getAllPlugins () { mkdir "Spigot" cd "Spigot" || exit - mkdir "GeyserUpdater" - cd "GeyserUpdater" || exit - echo "Auto-Update-Geyser: true -Auto-Restart-Server: true -Restart-Message-Players: '&2This server will be restarting in 10 seconds!' -Auto-Script-Generating: true -Enable-Debug: true -Config-Version: 2" > config.yml - cd ../ echo echo "[INFO] Downloading Geyser-Spigot.jar" download "$geyserLink"spigot/target/Geyser-Spigot.jar cd ../ - mkdir BungeeCord - cd BungeeCord || exit - mkdir GeyserUpdater - cd GeyserUpdater || exit - echo "Auto-Update-Geyser: true -Auto-Restart-Server: true -Restart-Message-Players: '&2This server will be restarting in 10 seconds!' -Auto-Script-Generating: true -Enable-Debug: true -Config-Version: 2" > config.yml - cd ../ + mkdir "BungeeCord" + cd "BungeeCord" || exit echo echo "[INFO] Downloading Geyser-BungeeCord.jar" download "$geyserLink"bungeecord/target/Geyser-BungeeCord.jar @@ -98,15 +94,6 @@ Config-Version: 2" > config.yml mkdir "Velocity" cd "Velocity" || exit - mkdir "geyserupdater" - cd "geyserupdater" || exit - echo "Auto-Update-Geyser=true -Auto-Restart-Server=true -Restart-Message-Players='&2This server will be restarting in 10 seconds!' -Auto-Script-Generating=true -Enable-Debug=true -Config-Version=2" > config.toml - cd ../ echo echo "[INFO] Downloading Geyser-Velocity" download "$geyserLink"velocity/target/Geyser-Velocity.jar From c62bfbbacbbaba3cdfe2bfd86b5d71c608ff26a8 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Mon, 23 Aug 2021 15:52:02 -0400 Subject: [PATCH 33/42] fix downloading, hash checking, other improvements Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../geyserupdater/bungee/BungeeUpdater.java | 1 + .../geyserupdater/common/GeyserUpdater.java | 46 ++++++---- .../common/config/UpdaterConfiguration.java | 2 +- .../common/update/DownloadManager.java | 6 ++ .../common/update/Updatable.java | 20 ++--- .../common/update/UpdateManager.java | 71 ++++++++------- .../common/update/age/IdentityComparer.java | 60 ------------- .../update/age/provider/IdentityProvider.java | 11 --- .../common/update/age/type/Md5FileHash.java | 15 ---- .../update/identity/IdentityComparer.java | 86 +++++++++++++++++++ .../provider/FileHashProvider.java | 4 +- .../identity/provider/IdentityProvider.java | 11 +++ .../provider/JenkinsBuildProvider.java | 4 +- .../provider/JenkinsHashProvider.java | 6 +- .../{age => identity}/type/BuildNumber.java | 6 +- .../{age => identity}/type/Identity.java | 5 +- .../update/identity/type/Md5FileHash.java | 20 +++++ .../geyserupdater/common/util/WebUtils.java | 8 ++ .../geyserupdater/spigot/SpigotUpdater.java | 1 + src/main/resources/config.yml | 2 +- 20 files changed, 228 insertions(+), 157 deletions(-) delete mode 100644 src/main/java/dev/projectg/geyserupdater/common/update/age/IdentityComparer.java delete mode 100644 src/main/java/dev/projectg/geyserupdater/common/update/age/provider/IdentityProvider.java delete mode 100644 src/main/java/dev/projectg/geyserupdater/common/update/age/type/Md5FileHash.java create mode 100644 src/main/java/dev/projectg/geyserupdater/common/update/identity/IdentityComparer.java rename src/main/java/dev/projectg/geyserupdater/common/update/{age => identity}/provider/FileHashProvider.java (87%) create mode 100644 src/main/java/dev/projectg/geyserupdater/common/update/identity/provider/IdentityProvider.java rename src/main/java/dev/projectg/geyserupdater/common/update/{age => identity}/provider/JenkinsBuildProvider.java (92%) rename src/main/java/dev/projectg/geyserupdater/common/update/{age => identity}/provider/JenkinsHashProvider.java (90%) rename src/main/java/dev/projectg/geyserupdater/common/update/{age => identity}/type/BuildNumber.java (61%) rename src/main/java/dev/projectg/geyserupdater/common/update/{age => identity}/type/Identity.java (61%) create mode 100644 src/main/java/dev/projectg/geyserupdater/common/update/identity/type/Md5FileHash.java diff --git a/src/main/java/dev/projectg/geyserupdater/bungee/BungeeUpdater.java b/src/main/java/dev/projectg/geyserupdater/bungee/BungeeUpdater.java index 2cf93d45..0a90abc4 100644 --- a/src/main/java/dev/projectg/geyserupdater/bungee/BungeeUpdater.java +++ b/src/main/java/dev/projectg/geyserupdater/bungee/BungeeUpdater.java @@ -36,6 +36,7 @@ public void onEnable() { } catch (IOException e) { getLogger().severe("Failed to start GeyserUpdater! Disabling..."); e.printStackTrace(); + return; } this.getProxy().getPluginManager().registerCommand(this, new GeyserUpdateCommand()); diff --git a/src/main/java/dev/projectg/geyserupdater/common/GeyserUpdater.java b/src/main/java/dev/projectg/geyserupdater/common/GeyserUpdater.java index 7f53ec63..8b8329a5 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/GeyserUpdater.java +++ b/src/main/java/dev/projectg/geyserupdater/common/GeyserUpdater.java @@ -4,6 +4,7 @@ import dev.projectg.geyserupdater.common.logger.UpdaterLogger; import dev.projectg.geyserupdater.common.scheduler.UpdaterScheduler; import dev.projectg.geyserupdater.common.update.PluginId; +import dev.projectg.geyserupdater.common.update.Updatable; import dev.projectg.geyserupdater.common.update.UpdateManager; import dev.projectg.geyserupdater.common.util.FileUtils; import dev.projectg.geyserupdater.common.util.SpigotResourceUpdateChecker; @@ -56,7 +57,7 @@ public GeyserUpdater(Path dataFolder, if (latestVersion.equals(version)) { logger.info("You are using the latest version of GeyserUpdater!"); } else { - logger.info("Your version: " + version + ". Latest version: " + latestVersion + ". Download the newer version at https://www.spigotmc.org/resources/geyserupdater.88555/."); + logger.info("Your version: " + version + ". Latest version: " + latestVersion + ". Download the newer version at https://www.spigotmc.org/resources/geyserupdater.88555/"); } } }, true); @@ -100,27 +101,36 @@ public GeyserUpdater(Path dataFolder, * @throws IOException If there was a failure moving ALL updates. */ public void shutdown() throws IOException { - try { - if (Files.isSameFile(installFolder, downloadFolder)) { - // We don't need to copy anything around - return; - } - } catch (IOException e) { - logger.error("Failed to check if the installFolder is the same as the downloadFolder. Attempting to move files from the downloadFolder to the installFolder anyway..."); - e.printStackTrace(); - } + UpdaterLogger.getLogger().debug("Installing plugins from the cache."); + Files.createDirectories(installFolder); // todo: find a way to make sure we are shutdown last (to not modify files still being used) - UpdaterLogger.getLogger().debug("Installing plugins from the cache."); - Files.walk(downloadFolder, 1).forEach((file) -> { - try { - Files.move(file, installFolder, StandardCopyOption.REPLACE_EXISTING); - } catch (IOException e) { - UpdaterLogger.getLogger().error("Failed to copy update " + file + " to the plugins folder."); - e.printStackTrace(); + // Only move files that we have tracked + for (Updatable updatable : updateManager.getTrackedUpdatables()) { + Path update = updatable.outputFile; + if (Files.exists(update)) { + try { + if (Files.isSameFile(update.getParent(), installFolder)) { + // it is already where it should be, don't move it + continue; + } + } catch (IOException e) { + logger.warn("Failed to check if the install folder is the same as the download folder for " + updatable + ". Attempting to move files from the downloadFolder to the installFolder anyway..."); + if (logger.isDebug()) { + e.printStackTrace(); + } + } + + try { + Files.move(update, installFolder.resolve(update.getFileName()), StandardCopyOption.REPLACE_EXISTING); + logger.debug("Moved " + updatable.outputFile + " to " + installFolder); + } catch (IOException e) { + UpdaterLogger.getLogger().error("Failed to copy update file " + updatable + " to directory " + installFolder); + e.printStackTrace(); + } } - }); + } } public static GeyserUpdater getInstance() { diff --git a/src/main/java/dev/projectg/geyserupdater/common/config/UpdaterConfiguration.java b/src/main/java/dev/projectg/geyserupdater/common/config/UpdaterConfiguration.java index 788a0373..6324f053 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/config/UpdaterConfiguration.java +++ b/src/main/java/dev/projectg/geyserupdater/common/config/UpdaterConfiguration.java @@ -50,7 +50,7 @@ public String getRestartMessage() { } @JsonProperty(value = "download-time-limit") - private int downloadTimeLimit = 300; + private int downloadTimeLimit = 180; public int getDownloadTimeLimit() { return downloadTimeLimit; } diff --git a/src/main/java/dev/projectg/geyserupdater/common/update/DownloadManager.java b/src/main/java/dev/projectg/geyserupdater/common/update/DownloadManager.java index a5311686..de7257da 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/update/DownloadManager.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/DownloadManager.java @@ -7,6 +7,7 @@ import javax.annotation.Nullable; import java.io.IOException; +import java.nio.file.Files; import java.util.LinkedList; import java.util.List; import java.util.Objects; @@ -55,6 +56,7 @@ private void downloadAll() { Task hangChecker = scheduleHangChecker(currentUpdate); try { + Files.createDirectories(currentUpdate.outputFile.getParent()); WebUtils.downloadFile(currentUpdate.downloadUrl, currentUpdate.outputFile); } catch (IOException e) { UpdaterLogger.getLogger().error("Caught exception while downloading file " + currentUpdate.outputFile + " with URL: " + currentUpdate.downloadUrl); @@ -105,4 +107,8 @@ private Task scheduleHangChecker(Updatable updatable) { } }, true, downloadTimeLimit, TimeUnit.SECONDS); } + + private void shutdown() { + //todo finish this + } } diff --git a/src/main/java/dev/projectg/geyserupdater/common/update/Updatable.java b/src/main/java/dev/projectg/geyserupdater/common/update/Updatable.java index 61e93290..0a51b9a1 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/update/Updatable.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/Updatable.java @@ -1,18 +1,20 @@ package dev.projectg.geyserupdater.common.update; -import dev.projectg.geyserupdater.common.update.age.IdentityComparer; +import dev.projectg.geyserupdater.common.update.identity.IdentityComparer; +import dev.projectg.geyserupdater.common.util.WebUtils; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Objects; public class Updatable { @Nonnull public final String pluginIdentity; - @Nonnull public final IdentityComparer identityComparer; - @Nullable public final IdentityComparer hashComparer; + @Nonnull public final IdentityComparer identityComparer; + @Nullable public final IdentityComparer hashComparer; @Nonnull public final String downloadUrl; @Nonnull public final Path outputFile; public final boolean autoCheck; @@ -27,8 +29,8 @@ public class Updatable { * @param file If the Path is a file, the download will be written to that file. If the Path is a directory, the file will be written to that directory, and the filename will deduced from the link provided. */ public Updatable(@Nonnull String name, - @Nonnull IdentityComparer identityComparer, - @Nullable IdentityComparer hashComparer, + @Nonnull IdentityComparer identityComparer, + @Nullable IdentityComparer hashComparer, @Nonnull String downloadUrl, @Nonnull Path file, boolean autoCheck, @@ -42,7 +44,6 @@ public Updatable(@Nonnull String name, this.autoCheck = autoCheck; this.autoUpdate = autoUpdate; - // Remove / from the end of the link if necessary if (downloadUrl.endsWith("/")) { this.downloadUrl = downloadUrl.substring(0, downloadUrl.length() - 1); @@ -50,14 +51,9 @@ public Updatable(@Nonnull String name, this.downloadUrl = downloadUrl; } - // Make sure the file linked is a jar - if (!downloadUrl.endsWith(".jar")) { - throw new IllegalArgumentException("Download URL provided for plugin '" + name + "' must direct to a file that ends in '.jar'"); - } - // Figure out the output file name if necessary if (Files.isDirectory(file)) { - this.outputFile = file.resolve(downloadUrl.substring(downloadUrl.lastIndexOf("/") + 1)); + this.outputFile = Paths.get(WebUtils.getFileName(downloadUrl)); } else { this.outputFile = file; } diff --git a/src/main/java/dev/projectg/geyserupdater/common/update/UpdateManager.java b/src/main/java/dev/projectg/geyserupdater/common/update/UpdateManager.java index 9d85142d..592314e8 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/update/UpdateManager.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/UpdateManager.java @@ -1,21 +1,22 @@ package dev.projectg.geyserupdater.common.update; +import com.google.common.collect.ImmutableMap; import dev.projectg.geyserupdater.common.config.UpdaterConfiguration; import dev.projectg.geyserupdater.common.logger.UpdaterLogger; import dev.projectg.geyserupdater.common.scheduler.UpdaterScheduler; -import dev.projectg.geyserupdater.common.update.age.IdentityComparer; -import dev.projectg.geyserupdater.common.update.age.provider.FileHashProvider; -import dev.projectg.geyserupdater.common.update.age.provider.JenkinsBuildProvider; -import dev.projectg.geyserupdater.common.update.age.provider.JenkinsHashProvider; -import dev.projectg.geyserupdater.common.update.age.type.BuildNumber; -import dev.projectg.geyserupdater.common.util.FileUtils; +import dev.projectg.geyserupdater.common.update.identity.IdentityComparer; +import dev.projectg.geyserupdater.common.update.identity.provider.FileHashProvider; +import dev.projectg.geyserupdater.common.update.identity.provider.JenkinsBuildProvider; +import dev.projectg.geyserupdater.common.update.identity.provider.JenkinsHashProvider; +import dev.projectg.geyserupdater.common.update.identity.type.BuildNumber; +import dev.projectg.geyserupdater.common.util.WebUtils; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; -import java.net.URISyntaxException; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.*; import java.util.concurrent.TimeUnit; @@ -38,8 +39,6 @@ public UpdateManager(Path defaultDownloadLocation, UpdaterScheduler scheduler, U this.downloadManager = new DownloadManager(this, scheduler, config.getDownloadTimeLimit()); UpdaterLogger logger = UpdaterLogger.getLogger(); - // If we must schedule a checker to check for updates on an interval - boolean updateCheckerRequired = false; for (PluginId pluginId : PluginId.values()) { if (pluginId.isEnable()) { // Get the git.properties @@ -66,6 +65,9 @@ public UpdateManager(Path defaultDownloadLocation, UpdaterScheduler scheduler, U pluginId.setBranch(branch); + // The download location, used for both downloading and hash checking + Path downloadLocation = defaultDownloadLocation.resolve(Paths.get(WebUtils.getFileName(pluginId.getLatestFileLink()))); + // For age comparer BuildNumber buildNumber = new BuildNumber(Integer.parseInt(buildNumberString)); JenkinsBuildProvider buildProvider; @@ -78,38 +80,28 @@ public UpdateManager(Path defaultDownloadLocation, UpdaterScheduler scheduler, U } // File hash comparer - IdentityComparer hashComparer = null; + IdentityComparer hashComparer = null; try { - FileHashProvider localHashProvider = new FileHashProvider(FileUtils.getCodeSourceLocation(pluginId.getClass())); + FileHashProvider localHashProvider = new FileHashProvider(downloadLocation); JenkinsHashProvider jenkinsHashProvider = new JenkinsHashProvider(pluginId.getLatestFileLink() + "/*fingerprint*/"); hashComparer = new IdentityComparer<>(localHashProvider, jenkinsHashProvider); - } catch (URISyntaxException | MalformedURLException e) { + } catch (MalformedURLException e) { UpdaterLogger.getLogger().error("Failure while getting location of file for " + pluginId.name() + ". It will be possible to update it, but not to compare file hashes."); e.printStackTrace(); } - boolean autoCheck = pluginId.isAutoCheck(); - if (autoCheck) { - updateCheckerRequired = true; - } - register(new Updatable( pluginId.name(), new IdentityComparer<>(buildNumber, buildProvider), hashComparer, pluginId.getLatestFileLink(), - defaultDownloadLocation, - autoCheck, + downloadLocation, + pluginId.isAutoCheck(), pluginId.isAutoUpdate())); } } // Load extra stuff from the config if we wanted, I guess - - // Check for updates on a schedule, if at least one updatable requires it - if (updateCheckerRequired) { - scheduleUpdateChecker(scheduler, config.getAutoUpdateInterval()); - } } /** @@ -159,18 +151,32 @@ protected void finish(Updatable updatable, DownloadResult result) { if (updatable.hashComparer == null) { if (result == DownloadResult.SUCCESS) { // cant check hash, but the download result is success + logger.info("Successfully downloaded update for: " + updatable); registry.put(updatable, UpdateStatus.DOWNLOADED); return; } - } else if (updatable.hashComparer.checkIfEquals()) { - // hash is correct - registry.put(updatable, UpdateStatus.DOWNLOADED); - return; + } else { + Object downloadHash = updatable.hashComparer.callLocalValue(); + Object anticipatedHash = updatable.hashComparer.callExternalValue(); + if (downloadHash == null) { + logger.error("Failed to find hash for downloaded update of: " + updatable); + } else if (anticipatedHash == null) { + logger.error("Failed to find anticipated hash for downloaded update of: " + updatable); + } else if (downloadHash.equals(anticipatedHash)) { + // hash is "correct" + logger.info("Successfully downloaded update for: " + updatable); + logger.debug("Downloaded file hash: <" + downloadHash + ">. Anticipated hash: <" + anticipatedHash + ">"); + registry.put(updatable, UpdateStatus.DOWNLOADED); + return; + } else { + logger.warn("The file hash of the downloaded file did not match the hash provided online for " + updatable); + logger.warn("Downloaded file hash: <" + downloadHash + ">. Anticipated hash: <" + anticipatedHash + ">"); + } } // Hash is not correct, or cannot check hash and there was a fail if (config.isDeleteOnFail()) { - UpdaterLogger.getLogger().warn("The file hash of the downloaded file did not match the hash provided online for " + updatable + ". Deleting file."); + logger.warn("Deleting failed download."); try { Files.deleteIfExists(updatable.outputFile); } catch (IOException e) { @@ -215,4 +221,11 @@ private void scheduleUpdateChecker(UpdaterScheduler scheduler, long interval) { isAutoChecking = true; } + + /** + * @return a {@link Map#keySet()} of the tracked Updatable registry + */ + public Set getTrackedUpdatables() { + return registry.keySet(); + } } diff --git a/src/main/java/dev/projectg/geyserupdater/common/update/age/IdentityComparer.java b/src/main/java/dev/projectg/geyserupdater/common/update/age/IdentityComparer.java deleted file mode 100644 index b3149326..00000000 --- a/src/main/java/dev/projectg/geyserupdater/common/update/age/IdentityComparer.java +++ /dev/null @@ -1,60 +0,0 @@ -package dev.projectg.geyserupdater.common.update.age; - -import dev.projectg.geyserupdater.common.update.age.provider.IdentityProvider; -import dev.projectg.geyserupdater.common.update.age.type.Identity; - -import javax.annotation.Nonnull; -import java.util.Objects; - -/** - * @param The external {@link IdentityProvider} implementation - * @param The {@link Identity} implementation - */ -public class IdentityComparer, S extends Identity> { - - S localIdentity; - T externalIdentityProvider; - - /** - * Create an identity comparer, which stores a local identity and way to check an external identity. Both params should provide the same {@link Identity} implementation. - * @param localIdentityProvider The local identity provider. {@link IdentityProvider#getValue()} will be called once and stored forever. - * @param externalIdentityProvider The external identity provider. {@link IdentityProvider#getValue()} will be called every time {@link IdentityComparer#checkIfEquals()} is called. - */ - public > IdentityComparer(@Nonnull U localIdentityProvider, @Nonnull T externalIdentityProvider) { - Objects.requireNonNull(localIdentityProvider); - Objects.requireNonNull(externalIdentityProvider); - - this.localIdentity = localIdentityProvider.getValue(); - this.externalIdentityProvider = externalIdentityProvider; - } - - /** - * Create an identity comparer, which stores a local identity and way to check an external identity - * @param localIdentity The local identity. - * @param externalIdentityProvider The external identity provider. {@link IdentityProvider#getValue()} will be called every time {@link IdentityComparer#checkIfEquals()} is called. - */ - public IdentityComparer(@Nonnull S localIdentity, @Nonnull T externalIdentityProvider) { - Objects.requireNonNull(localIdentity); - Objects.requireNonNull(externalIdentityProvider); - - this.localIdentity = localIdentity; - this.externalIdentityProvider = externalIdentityProvider; - } - - /** - * Request the {@link Identity} from the external {@link IdentityProvider} and compare it to the stored local {@link Identity}. Should be regarded as a blocking operation. - * @return True if the local identity {@link Object#equals(Object)} the external identity - */ - public boolean checkIfEquals() { - // todo: return an enum - if (localIdentity == null) { - return true; - } - S externalIdentity = externalIdentityProvider.getValue(); - if (externalIdentity == null) { - return true; - } - - return localIdentity.value().equals(externalIdentity.value()); - } -} diff --git a/src/main/java/dev/projectg/geyserupdater/common/update/age/provider/IdentityProvider.java b/src/main/java/dev/projectg/geyserupdater/common/update/age/provider/IdentityProvider.java deleted file mode 100644 index a0245a91..00000000 --- a/src/main/java/dev/projectg/geyserupdater/common/update/age/provider/IdentityProvider.java +++ /dev/null @@ -1,11 +0,0 @@ -package dev.projectg.geyserupdater.common.update.age.provider; - -import dev.projectg.geyserupdater.common.update.age.type.Identity; - -import javax.annotation.Nullable; - -public interface IdentityProvider> { - - @Nullable - S getValue(); -} diff --git a/src/main/java/dev/projectg/geyserupdater/common/update/age/type/Md5FileHash.java b/src/main/java/dev/projectg/geyserupdater/common/update/age/type/Md5FileHash.java deleted file mode 100644 index 6c6c3541..00000000 --- a/src/main/java/dev/projectg/geyserupdater/common/update/age/type/Md5FileHash.java +++ /dev/null @@ -1,15 +0,0 @@ -package dev.projectg.geyserupdater.common.update.age.type; - -public class Md5FileHash implements Identity { - - private final String hash; - - public Md5FileHash(String md5Hash) { - hash = md5Hash; - } - - @Override - public String value() { - return hash; - } -} diff --git a/src/main/java/dev/projectg/geyserupdater/common/update/identity/IdentityComparer.java b/src/main/java/dev/projectg/geyserupdater/common/update/identity/IdentityComparer.java new file mode 100644 index 00000000..c922ad70 --- /dev/null +++ b/src/main/java/dev/projectg/geyserupdater/common/update/identity/IdentityComparer.java @@ -0,0 +1,86 @@ +package dev.projectg.geyserupdater.common.update.identity; + +import dev.projectg.geyserupdater.common.update.identity.provider.IdentityProvider; +import dev.projectg.geyserupdater.common.update.identity.type.Identity; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Objects; + +/** + * @param The external {@link IdentityProvider} implementation + * @param The {@link Identity} implementation + */ +public class IdentityComparer, T extends IdentityProvider, S extends Identity> { + + private final @Nullable S localIdentity; + private final @Nullable U localIdentityProvider; + private final @Nonnull T externalIdentityProvider; + + /** + * Create an identity comparer, which stores a way to check a local identity and way to check an external identity. Both params should provide the same {@link Identity} implementation. + * @param localIdentityProvider The local identity provider. {@link IdentityProvider#getValue()} + * @param externalIdentityProvider The external identity provider. {@link IdentityProvider#getValue()} + */ + public IdentityComparer(@Nonnull U localIdentityProvider, @Nonnull T externalIdentityProvider) { + Objects.requireNonNull(localIdentityProvider); + Objects.requireNonNull(externalIdentityProvider); + + this.localIdentity = null; + this.localIdentityProvider = localIdentityProvider; + this.externalIdentityProvider = externalIdentityProvider; + } + + /** + * Create an identity comparer, which stores a local identity and way to check an external identity. + * @param localIdentity The local identity. + * @param externalIdentityProvider The external identity provider. {@link IdentityProvider#getValue()} will be called every time {@link IdentityComparer#checkIfEquals()} is called. + */ + public IdentityComparer(@Nonnull S localIdentity, @Nonnull T externalIdentityProvider) { + Objects.requireNonNull(localIdentity); + Objects.requireNonNull(externalIdentityProvider); + + this.localIdentity = localIdentity; + this.localIdentityProvider = null; + this.externalIdentityProvider = externalIdentityProvider; + } + + /** + * Request the {@link Identity} from the external {@link IdentityProvider} and compare it to the stored local {@link Identity}. Should be regarded as a blocking operation. + * @return True if the local identity {@link Object#equals(Object)} the external identity. Also returns true if either are null. + */ + public boolean checkIfEquals() { + // todo: return an enum or wrapper, to better deal with null values + Object localValue = callLocalValue(); + Object externalValue = callExternalValue(); + if (localValue == null || externalValue == null) { + return true; + } + + return localValue.equals(externalValue); + } + + @Nullable + public Object callLocalValue() { + if (localIdentity == null) { + S localId = Objects.requireNonNull(localIdentityProvider).getValue(); + if (localId == null) { + return null; + } else { + return localId.value(); + } + } else { + return localIdentity.value(); + } + } + + @Nullable + public Object callExternalValue() { + S externalId = externalIdentityProvider.getValue(); + if (externalId == null) { + return null; + } else { + return externalId.value(); + } + } +} diff --git a/src/main/java/dev/projectg/geyserupdater/common/update/age/provider/FileHashProvider.java b/src/main/java/dev/projectg/geyserupdater/common/update/identity/provider/FileHashProvider.java similarity index 87% rename from src/main/java/dev/projectg/geyserupdater/common/update/age/provider/FileHashProvider.java rename to src/main/java/dev/projectg/geyserupdater/common/update/identity/provider/FileHashProvider.java index 9f52e3e1..b68eac9f 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/update/age/provider/FileHashProvider.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/identity/provider/FileHashProvider.java @@ -1,10 +1,10 @@ -package dev.projectg.geyserupdater.common.update.age.provider; +package dev.projectg.geyserupdater.common.update.identity.provider; import com.google.common.hash.Hashing; import com.google.common.io.ByteSource; import com.google.common.io.Files; import dev.projectg.geyserupdater.common.logger.UpdaterLogger; -import dev.projectg.geyserupdater.common.update.age.type.Md5FileHash; +import dev.projectg.geyserupdater.common.update.identity.type.Md5FileHash; import java.io.IOException; import java.nio.file.Path; diff --git a/src/main/java/dev/projectg/geyserupdater/common/update/identity/provider/IdentityProvider.java b/src/main/java/dev/projectg/geyserupdater/common/update/identity/provider/IdentityProvider.java new file mode 100644 index 00000000..4046996b --- /dev/null +++ b/src/main/java/dev/projectg/geyserupdater/common/update/identity/provider/IdentityProvider.java @@ -0,0 +1,11 @@ +package dev.projectg.geyserupdater.common.update.identity.provider; + +import dev.projectg.geyserupdater.common.update.identity.type.Identity; + +import javax.annotation.Nullable; + +public interface IdentityProvider> { + + @Nullable + S getValue(); +} diff --git a/src/main/java/dev/projectg/geyserupdater/common/update/age/provider/JenkinsBuildProvider.java b/src/main/java/dev/projectg/geyserupdater/common/update/identity/provider/JenkinsBuildProvider.java similarity index 92% rename from src/main/java/dev/projectg/geyserupdater/common/update/age/provider/JenkinsBuildProvider.java rename to src/main/java/dev/projectg/geyserupdater/common/update/identity/provider/JenkinsBuildProvider.java index ebe284f4..6c5ffe52 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/update/age/provider/JenkinsBuildProvider.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/identity/provider/JenkinsBuildProvider.java @@ -1,7 +1,7 @@ -package dev.projectg.geyserupdater.common.update.age.provider; +package dev.projectg.geyserupdater.common.update.identity.provider; import dev.projectg.geyserupdater.common.logger.UpdaterLogger; -import dev.projectg.geyserupdater.common.update.age.type.BuildNumber; +import dev.projectg.geyserupdater.common.update.identity.type.BuildNumber; import dev.projectg.geyserupdater.common.util.WebUtils; import java.io.IOException; diff --git a/src/main/java/dev/projectg/geyserupdater/common/update/age/provider/JenkinsHashProvider.java b/src/main/java/dev/projectg/geyserupdater/common/update/identity/provider/JenkinsHashProvider.java similarity index 90% rename from src/main/java/dev/projectg/geyserupdater/common/update/age/provider/JenkinsHashProvider.java rename to src/main/java/dev/projectg/geyserupdater/common/update/identity/provider/JenkinsHashProvider.java index eeacb098..5f737cbe 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/update/age/provider/JenkinsHashProvider.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/identity/provider/JenkinsHashProvider.java @@ -1,7 +1,7 @@ -package dev.projectg.geyserupdater.common.update.age.provider; +package dev.projectg.geyserupdater.common.update.identity.provider; import dev.projectg.geyserupdater.common.logger.UpdaterLogger; -import dev.projectg.geyserupdater.common.update.age.type.Md5FileHash; +import dev.projectg.geyserupdater.common.update.identity.type.Md5FileHash; import java.io.BufferedReader; import java.io.IOException; @@ -38,7 +38,7 @@ public Md5FileHash getValue() { while ((inputLine = in.readLine()) != null) { if (inputLine.contains("MD5")) { con.disconnect(); - return new Md5FileHash(inputLine.substring(inputLine.indexOf("MD5: ") + 4, inputLine.indexOf(""))); + return new Md5FileHash(inputLine.substring(inputLine.indexOf("MD5: ") + 5, inputLine.indexOf(""))); } } con.disconnect(); diff --git a/src/main/java/dev/projectg/geyserupdater/common/update/age/type/BuildNumber.java b/src/main/java/dev/projectg/geyserupdater/common/update/identity/type/BuildNumber.java similarity index 61% rename from src/main/java/dev/projectg/geyserupdater/common/update/age/type/BuildNumber.java rename to src/main/java/dev/projectg/geyserupdater/common/update/identity/type/BuildNumber.java index 7f245ba8..0f1cd600 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/update/age/type/BuildNumber.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/identity/type/BuildNumber.java @@ -1,4 +1,6 @@ -package dev.projectg.geyserupdater.common.update.age.type; +package dev.projectg.geyserupdater.common.update.identity.type; + +import org.jetbrains.annotations.NotNull; public class BuildNumber implements Identity { @@ -9,7 +11,7 @@ public BuildNumber(int buildNumber) { } @Override - public Integer value() { + public @NotNull Integer value() { return buildNumber; } } diff --git a/src/main/java/dev/projectg/geyserupdater/common/update/age/type/Identity.java b/src/main/java/dev/projectg/geyserupdater/common/update/identity/type/Identity.java similarity index 61% rename from src/main/java/dev/projectg/geyserupdater/common/update/age/type/Identity.java rename to src/main/java/dev/projectg/geyserupdater/common/update/identity/type/Identity.java index 0e6c4909..5e8e269b 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/update/age/type/Identity.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/identity/type/Identity.java @@ -1,4 +1,6 @@ -package dev.projectg.geyserupdater.common.update.age.type; +package dev.projectg.geyserupdater.common.update.identity.type; + +import javax.annotation.Nonnull; /** * Provides implementation for something that can be quantified as an age of something. @@ -6,5 +8,6 @@ */ public interface Identity { + @Nonnull T value(); } diff --git a/src/main/java/dev/projectg/geyserupdater/common/update/identity/type/Md5FileHash.java b/src/main/java/dev/projectg/geyserupdater/common/update/identity/type/Md5FileHash.java new file mode 100644 index 00000000..ba45e2e5 --- /dev/null +++ b/src/main/java/dev/projectg/geyserupdater/common/update/identity/type/Md5FileHash.java @@ -0,0 +1,20 @@ +package dev.projectg.geyserupdater.common.update.identity.type; + +import org.jetbrains.annotations.NotNull; + +import javax.annotation.Nonnull; +import java.util.Objects; + +public class Md5FileHash implements Identity { + + private final String hash; + + public Md5FileHash(@Nonnull String md5Hash) { + hash = Objects.requireNonNull(md5Hash); + } + + @Override + public @NotNull String value() { + return hash; + } +} diff --git a/src/main/java/dev/projectg/geyserupdater/common/util/WebUtils.java b/src/main/java/dev/projectg/geyserupdater/common/util/WebUtils.java index ad807701..9223f9da 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/util/WebUtils.java +++ b/src/main/java/dev/projectg/geyserupdater/common/util/WebUtils.java @@ -93,4 +93,12 @@ private static String connectionToString(HttpURLConnection con) throws IOExcepti return content.toString(); } + + /** + * Get the filename at the end of a url + * @param url The url to get the filename at the end from. Should not end with a / + */ + public static String getFileName(String url) { + return url.substring(url.lastIndexOf("/") + 1); + } } diff --git a/src/main/java/dev/projectg/geyserupdater/spigot/SpigotUpdater.java b/src/main/java/dev/projectg/geyserupdater/spigot/SpigotUpdater.java index e9bbe821..7b9a4a8d 100644 --- a/src/main/java/dev/projectg/geyserupdater/spigot/SpigotUpdater.java +++ b/src/main/java/dev/projectg/geyserupdater/spigot/SpigotUpdater.java @@ -40,6 +40,7 @@ public void onEnable() { } catch (IOException e) { getLogger().severe("Failed to start GeyserUpdater! Disabling..."); e.printStackTrace(); + return; } Objects.requireNonNull(getCommand("geyserupdate")).setExecutor(new GeyserUpdateCommand()); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 916b642b..8a4f5d27 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -17,7 +17,7 @@ default-updates: # The interval in hours between each auto update check. auto-update-interval: 24 # The maximum amount of seconds that a download is allowed to run for. Increase if you are running into issues on a slow internet connection. -download-time-limit: 300 +download-time-limit: 180 # Delete the downloaded file if the file hash of the downloaded file did not match what the download server provided. # Or if the file hash was not checked and the download time limit was reached, or an exception occurred. # If the file hash is not correct the downloaded file is likely corrupt or unfinished. From abae8734019f1c7131d840ee3ec382fe1ba39c63 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Mon, 23 Aug 2021 20:08:53 -0400 Subject: [PATCH 34/42] improve WebUtils#connectionToString Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../identity/provider/JenkinsBuildProvider.java | 5 ++--- .../geyserupdater/common/util/WebUtils.java | 13 +++---------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/main/java/dev/projectg/geyserupdater/common/update/identity/provider/JenkinsBuildProvider.java b/src/main/java/dev/projectg/geyserupdater/common/update/identity/provider/JenkinsBuildProvider.java index 6c5ffe52..219fa482 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/update/identity/provider/JenkinsBuildProvider.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/identity/provider/JenkinsBuildProvider.java @@ -29,12 +29,11 @@ public BuildNumber getValue() { BuildNumber buildNumber = null; try { String body = WebUtils.getBody(url); - String number = body.substring(0, body.length() - 1); //fixme: getBody() adds a newline char at the end try { - buildNumber = new BuildNumber(Integer.parseInt(number)); + buildNumber = new BuildNumber(Integer.parseInt(body)); } catch (NumberFormatException e) { UpdaterLogger.getLogger().error("Failed to get a build number from a Jenkins server because an integer was not returned."); - UpdaterLogger.getLogger().error("Body returned: <" + number + "> (excluding the angle brackets)"); + UpdaterLogger.getLogger().error("Body returned: <" + body + "> (excluding the angle brackets)"); e.printStackTrace(); } } catch (IOException e) { diff --git a/src/main/java/dev/projectg/geyserupdater/common/util/WebUtils.java b/src/main/java/dev/projectg/geyserupdater/common/util/WebUtils.java index 9223f9da..7d7de5ed 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/util/WebUtils.java +++ b/src/main/java/dev/projectg/geyserupdater/common/util/WebUtils.java @@ -10,6 +10,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; +import java.util.stream.Collectors; // Full credit to GeyserMC // https://github.com/GeyserMC/Geyser/blob/master/connector/src/main/java/org/geysermc/connector/utils/WebUtils.java @@ -79,19 +80,11 @@ private static String connectionToString(HttpURLConnection con) throws IOExcepti inputStream = con.getInputStream(); } - StringBuilder content = new StringBuilder(); try (BufferedReader in = new BufferedReader(new InputStreamReader(inputStream))) { - String inputLine; - - while ((inputLine = in.readLine()) != null) { - content.append(inputLine); - content.append("\n"); - } - + String content = in.lines().collect(Collectors.joining("\n")); con.disconnect(); + return content; } - - return content.toString(); } /** From 3771d7bb6d4b57d510e4fcf477fe2de07b75c29c Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Mon, 23 Aug 2021 21:39:29 -0400 Subject: [PATCH 35/42] add some safety to shutting down while downloads are happening Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../geyserupdater/common/GeyserUpdater.java | 2 ++ .../common/update/DownloadManager.java | 27 +++++++++++-------- .../common/update/UpdateManager.java | 8 ++++++ 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/main/java/dev/projectg/geyserupdater/common/GeyserUpdater.java b/src/main/java/dev/projectg/geyserupdater/common/GeyserUpdater.java index 8b8329a5..258c3033 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/GeyserUpdater.java +++ b/src/main/java/dev/projectg/geyserupdater/common/GeyserUpdater.java @@ -101,6 +101,8 @@ public GeyserUpdater(Path dataFolder, * @throws IOException If there was a failure moving ALL updates. */ public void shutdown() throws IOException { + updateManager.shutdown(); //fixme: wait for the last download to finish, or cancel it and delete the unfinished file before copying files + UpdaterLogger.getLogger().debug("Installing plugins from the cache."); Files.createDirectories(installFolder); diff --git a/src/main/java/dev/projectg/geyserupdater/common/update/DownloadManager.java b/src/main/java/dev/projectg/geyserupdater/common/update/DownloadManager.java index de7257da..074869ad 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/update/DownloadManager.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/DownloadManager.java @@ -8,6 +8,7 @@ import javax.annotation.Nullable; import java.io.IOException; import java.nio.file.Files; +import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Objects; @@ -21,9 +22,6 @@ public class DownloadManager { private final List queue = new LinkedList<>(); - // Used for making sure one download is ever running - private boolean isDownloading = false; - // Used by the hang checker to check if the current download is the same as when it was scheduled @Nullable private Updatable currentUpdate = null; @@ -38,14 +36,12 @@ public DownloadManager(UpdateManager updateManager, UpdaterScheduler scheduler, public void queue(Updatable updatable) { queue.add(updatable); - if (!isDownloading) { + if (downloader == null) { downloadAll(); } } private void downloadAll() { - isDownloading = true; - // Run the download on a new thread this.downloader = scheduler.run(() -> { @@ -72,7 +68,6 @@ private void downloadAll() { // Revert everything while having it locked so that the state is always correctly read by a different thread synchronized (this) { - isDownloading = false; currentUpdate = null; downloader = null; } @@ -86,7 +81,7 @@ private Task scheduleHangChecker(Updatable updatable) { // The time to allow the download to take, in seconds return scheduler.runDelayed(() -> { - if (!isDownloading || downloader == null) { + if (downloader == null) { throw new AssertionError("HangChecker should not execute while nothing is downloading."); } @@ -94,7 +89,6 @@ private Task scheduleHangChecker(Updatable updatable) { // Revert everything while having it locked so that the state is always correctly read by a different thread synchronized (this) { queue.clear(); - isDownloading = false; currentUpdate = null; downloader.cancel(); downloader = null; @@ -108,7 +102,18 @@ private Task scheduleHangChecker(Updatable updatable) { }, true, downloadTimeLimit, TimeUnit.SECONDS); } - private void shutdown() { - //todo finish this + /** + * Shuts down any running download queues. The queue will be cleared, however the current download will be allowed to finish. + * @return A list of {@link Updatable} that had their download cancelled. + */ + public List shutdown() { + List cancelled = new ArrayList<>(); + + // Allow the current download to finish and cancel everything else + while (queue.size() > 1) { + cancelled.add(queue.remove(1)); + } + + return cancelled; } } diff --git a/src/main/java/dev/projectg/geyserupdater/common/update/UpdateManager.java b/src/main/java/dev/projectg/geyserupdater/common/update/UpdateManager.java index 592314e8..5e08e6b9 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/update/UpdateManager.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/UpdateManager.java @@ -19,6 +19,7 @@ import java.nio.file.Paths; import java.util.*; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; public class UpdateManager { @@ -228,4 +229,11 @@ private void scheduleUpdateChecker(UpdaterScheduler scheduler, long interval) { public Set getTrackedUpdatables() { return registry.keySet(); } + + public void shutdown() { + List cancelled = downloadManager.shutdown(); + if (!cancelled.isEmpty()) { + UpdaterLogger.getLogger().info("Cancelled the following downloads because of a shutdown: " + cancelled.stream().map(Updatable::toString).collect(Collectors.joining(", "))); + } + } } From cb9a4bab2b489083c012a16d9ff6e2b048a79a2d Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Tue, 24 Aug 2021 20:06:45 -0400 Subject: [PATCH 36/42] implement hack to improve shutdown safety on bungeecord Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- pom.xml | 42 ++++------- .../geyserupdater/bungee/BungeeUpdater.java | 15 ++-- .../bungee/PluginMapModifier.java | 72 +++++++++++++++++++ .../geyserupdater/common/GeyserUpdater.java | 15 +++- .../common/util/ReflectionUtils.java | 25 +++++++ .../geyserupdater/spigot/SpigotUpdater.java | 13 ++-- .../velocity/VelocityUpdater.java | 15 ++-- 7 files changed, 152 insertions(+), 45 deletions(-) create mode 100644 src/main/java/dev/projectg/geyserupdater/bungee/PluginMapModifier.java create mode 100644 src/main/java/dev/projectg/geyserupdater/common/util/ReflectionUtils.java diff --git a/pom.xml b/pom.xml index 78da6000..ba50075a 100644 --- a/pom.xml +++ b/pom.xml @@ -18,37 +18,17 @@ - - bungeecord-repo - https://oss.sonatype.org/content/repositories/snapshots - - - velocity - https://nexus.velocitypowered.com/repository/maven-public/ - spigot-repo https://hub.spigotmc.org/nexus/content/repositories/snapshots/ - opencollab-release-repo - https://repo.opencollab.dev/maven-releases/ - - true - - - false - + jitpack.io + https://jitpack.io - opencollab-snapshot-repo - https://repo.opencollab.dev/maven-snapshots/ - - false - - - true - + velocity + https://nexus.velocitypowered.com/repository/maven-public/ @@ -60,10 +40,16 @@ provided - net.md-5 + com.github.SpigotMC.BungeeCord bungeecord-api - 1.16-R0.5-SNAPSHOT - jar + bda1605627 + provided + + + com.github.SpigotMC.BungeeCord + bungeecord-proxy + + a7c6ede provided @@ -72,10 +58,10 @@ 3.0.0 provided - org.apache.logging.log4j log4j-core + 2.13.2 provided diff --git a/src/main/java/dev/projectg/geyserupdater/bungee/BungeeUpdater.java b/src/main/java/dev/projectg/geyserupdater/bungee/BungeeUpdater.java index 0a90abc4..2875e37f 100644 --- a/src/main/java/dev/projectg/geyserupdater/bungee/BungeeUpdater.java +++ b/src/main/java/dev/projectg/geyserupdater/bungee/BungeeUpdater.java @@ -39,17 +39,22 @@ public void onEnable() { return; } + // Ensure we get disabled last + new PluginMapModifier().run(updater.getLogger(), this); + this.getProxy().getPluginManager().registerCommand(this, new GeyserUpdateCommand()); new Metrics(this, 10203); } @Override public void onDisable() { - try { - updater.shutdown(); - } catch (IOException e) { - UpdaterLogger.getLogger().error("Failed to install ALL updates:"); - e.printStackTrace(); + if (updater != null) { + try { + updater.shutdown(); + } catch (IOException e) { + UpdaterLogger.getLogger().error("Failed to install ALL updates:"); + e.printStackTrace(); + } } } diff --git a/src/main/java/dev/projectg/geyserupdater/bungee/PluginMapModifier.java b/src/main/java/dev/projectg/geyserupdater/bungee/PluginMapModifier.java new file mode 100644 index 00000000..67ef3e9b --- /dev/null +++ b/src/main/java/dev/projectg/geyserupdater/bungee/PluginMapModifier.java @@ -0,0 +1,72 @@ +package dev.projectg.geyserupdater.bungee; + +import dev.projectg.geyserupdater.common.logger.UpdaterLogger; +import dev.projectg.geyserupdater.common.util.ReflectionUtils; +import net.md_5.bungee.BungeeCord; +import net.md_5.bungee.api.plugin.Plugin; +import net.md_5.bungee.api.plugin.PluginManager; +import net.md_5.bungee.api.scheduler.ScheduledTask; + +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.concurrent.TimeUnit; + +/** + * A wrapper class for {@link this#run(UpdaterLogger, Plugin)}. + * It is wrapped to hide a {@link ScheduledTask} field, which is required for a Task which modifies the Plugin LinkedHashMap at the right moment to cancel itself. + */ +public class PluginMapModifier { + + private ScheduledTask task = null; + + /** + * Place a {@link Plugin} at the top of BungeeCord's LinkedHashMap of plugins. This will result in the plugin starting in the normal order, but being disabled last. + * This method is meant to be called within {@link Plugin#onEnable()} + * @param logger The Logger to use for messages + * @param plugin The Plugin to place at the top + */ + protected void run(UpdaterLogger logger, Plugin plugin) { + // https://github.com/SpigotMC/BungeeCord/blob/master/proxy/src/main/java/net/md_5/bungee/BungeeCord.java + BungeeCord bungeeCord = BungeeCord.getInstance(); + PluginManager pluginManager = bungeeCord.getPluginManager(); + + Collection listeners; + LinkedHashMap plugins; + try { + listeners = ReflectionUtils.getFieldValue(bungeeCord, Collection.class, "listeners"); + plugins = ReflectionUtils.getFieldValue(pluginManager, LinkedHashMap.class, "plugins"); + } catch (IllegalAccessException | NoSuchFieldException | ClassCastException e) { + logger.error("Failed to get necessary private fields to modify BungeeCord's plugin list order"); + logger.error("This may result in errors and inability to apply updates during the shutdown process."); + e.printStackTrace(); + return; + } + + // modify the plugin map once it is no longer being iterated over by BungeeCord to avoid ConcurrentModificationException. + // onEnable() is called by BungeeCord when iterating over the plugin list, so we must modify it after bungeecord is done enabling ALL plugins + // the listeners List is populated after all plugin enabling is finished. + task = bungeeCord.getScheduler().schedule(plugin, new Runnable() { + @Override + public void run() { + if (bungeeCord.isRunning) { + if (!listeners.isEmpty()) { + LinkedHashMap sortedPlugins = new LinkedHashMap<>(); + String updaterName = plugin.getDescription().getName(); + sortedPlugins.put(updaterName, plugins.get(updaterName)); // put ourselves at the very start, which means we disable last + sortedPlugins.putAll(plugins); // put the rest of the plugins in the default order + + synchronized (plugins) { + plugins.clear(); + plugins.putAll(sortedPlugins); + } + + logger.info("Successfully modified the order of BungeeCord's plugin Map."); + task.cancel(); + } + } else { + throw new IllegalStateException("BungeeCord shutdown before we were able to modify the plugin list order"); + } + } + }, 2, 5, TimeUnit.SECONDS); + } +} diff --git a/src/main/java/dev/projectg/geyserupdater/common/GeyserUpdater.java b/src/main/java/dev/projectg/geyserupdater/common/GeyserUpdater.java index 258c3033..89e2c688 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/GeyserUpdater.java +++ b/src/main/java/dev/projectg/geyserupdater/common/GeyserUpdater.java @@ -29,6 +29,19 @@ public class GeyserUpdater { private final UpdateManager updateManager; private final UpdaterConfiguration config; + /** + * @param dataFolder The data folder for GeyserUpdater + * @param downloadFolder The default directory to download updates to. Updatables may override it. + * @param installFolder The default directory to move downloads to whenever GeyserUpdater is shown down. Updatables may override it. + * @param bootstrap The {@link UpdaterBootstrap} platform implemenetation + * @param logger The {@link UpdaterLogger} platform implemenetation + * @param scheduler The {@link UpdaterScheduler} platform implemenetation + * @param playerHandler The {@link PlayerHandler} platform implemenetation + * @param version The version of GeyserUpdater + * @param geyserArtifact The artifact link for Geyser. For example: "bootstrap/velocity/target/Geyser-Velocity.jar" + * @param floodgateArtifact The artifact link for Floodgate. For example: "bootstrap/velocity/target/floodgate-velocity.jar" + * @throws IOException If there was an exception loading the config. {@link this#shutdown()} Should not be called if this exception is thrown. + */ public GeyserUpdater(Path dataFolder, Path downloadFolder, Path installFolder, @@ -106,8 +119,6 @@ public void shutdown() throws IOException { UpdaterLogger.getLogger().debug("Installing plugins from the cache."); Files.createDirectories(installFolder); - // todo: find a way to make sure we are shutdown last (to not modify files still being used) - // Only move files that we have tracked for (Updatable updatable : updateManager.getTrackedUpdatables()) { Path update = updatable.outputFile; diff --git a/src/main/java/dev/projectg/geyserupdater/common/util/ReflectionUtils.java b/src/main/java/dev/projectg/geyserupdater/common/util/ReflectionUtils.java new file mode 100644 index 00000000..9002dfd3 --- /dev/null +++ b/src/main/java/dev/projectg/geyserupdater/common/util/ReflectionUtils.java @@ -0,0 +1,25 @@ +package dev.projectg.geyserupdater.common.util; + +import javax.annotation.Nonnull; +import java.lang.reflect.Field; + +public class ReflectionUtils { + + /** + * Get the value of a {@link Field} in a {@link Object} + * @param obj The Object which contains the Field + * @param fieldClass The expected Class of the Field + * @param fieldName The name of the Field + * @param The expected Type of the Field's value + * @return The value of the field as Type T. + * @throws IllegalAccessException If the value was inaccessible, regardless of Field#setAccessible(true) + * @throws NoSuchFieldException If the Object does not contain the Field specified + * @throws ClassCastException If the Type of the Field found does not match the fieldClass given + */ + @Nonnull + public static T getFieldValue(Object obj, Class fieldClass, String fieldName) throws IllegalAccessException, NoSuchFieldException, ClassCastException { + Field field = obj.getClass().getDeclaredField(fieldName); // get the field from the object + field.setAccessible(true); // allow getting the field's value regardless of accessibility + return fieldClass.cast(field.get(obj)); // get the value and cast it to the desired type + } +} diff --git a/src/main/java/dev/projectg/geyserupdater/spigot/SpigotUpdater.java b/src/main/java/dev/projectg/geyserupdater/spigot/SpigotUpdater.java index 7b9a4a8d..76488bb0 100644 --- a/src/main/java/dev/projectg/geyserupdater/spigot/SpigotUpdater.java +++ b/src/main/java/dev/projectg/geyserupdater/spigot/SpigotUpdater.java @@ -50,11 +50,14 @@ public void onEnable() { @Override public void onDisable() { - try { - updater.shutdown(); - } catch (IOException e) { - UpdaterLogger.getLogger().error("Failed to install ALL updates:"); - e.printStackTrace(); + // bukkit has the native update folder to update jars on startup, which means we don't need to worry about modifying jars in use and when we shutdown + if (updater != null) { + try { + updater.shutdown(); + } catch (IOException e) { + UpdaterLogger.getLogger().error("Failed to install ALL updates:"); + e.printStackTrace(); + } } } diff --git a/src/main/java/dev/projectg/geyserupdater/velocity/VelocityUpdater.java b/src/main/java/dev/projectg/geyserupdater/velocity/VelocityUpdater.java index 407e5c19..4cb8cde3 100644 --- a/src/main/java/dev/projectg/geyserupdater/velocity/VelocityUpdater.java +++ b/src/main/java/dev/projectg/geyserupdater/velocity/VelocityUpdater.java @@ -64,16 +64,21 @@ public void onProxyInitialization(ProxyInitializeEvent event) throws IOException @Subscribe(order = PostOrder.LAST) public void onShutdown(ProxyShutdownEvent event) { + // PostOrder.LAST ensures that we don't modify plugin jars while they are being used. + // Hopefully plugins that are being updated don't also use PostOrder.LAST onDisable(); } @Override public void onDisable() { - try { - updater.shutdown(); - } catch (IOException e) { - UpdaterLogger.getLogger().error("Failed to install ALL updates:"); - e.printStackTrace(); + + if (updater != null) { + try { + updater.shutdown(); + } catch (IOException e) { + UpdaterLogger.getLogger().error("Failed to install ALL updates:"); + e.printStackTrace(); + } } } From 8baf80ea7454dc4fa299e67ceb8d1a6b9823d58f Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Tue, 24 Aug 2021 21:21:13 -0400 Subject: [PATCH 37/42] improve bungee hack, don't disable plugin on certain plugin info loading errors Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../bungee/PluginMapModifier.java | 47 ++++++++++++------- .../geyserupdater/common/update/PluginId.java | 10 ++-- .../common/update/UpdateManager.java | 34 ++++++++++---- 3 files changed, 57 insertions(+), 34 deletions(-) diff --git a/src/main/java/dev/projectg/geyserupdater/bungee/PluginMapModifier.java b/src/main/java/dev/projectg/geyserupdater/bungee/PluginMapModifier.java index 67ef3e9b..e6f0eabb 100644 --- a/src/main/java/dev/projectg/geyserupdater/bungee/PluginMapModifier.java +++ b/src/main/java/dev/projectg/geyserupdater/bungee/PluginMapModifier.java @@ -9,6 +9,7 @@ import java.util.Collection; import java.util.LinkedHashMap; +import java.util.Set; import java.util.concurrent.TimeUnit; /** @@ -19,6 +20,8 @@ public class PluginMapModifier { private ScheduledTask task = null; + private final String resultMessage = "This may result in errors and inability to apply updates during the shutdown process."; + /** * Place a {@link Plugin} at the top of BungeeCord's LinkedHashMap of plugins. This will result in the plugin starting in the normal order, but being disabled last. * This method is meant to be called within {@link Plugin#onEnable()} @@ -37,7 +40,7 @@ protected void run(UpdaterLogger logger, Plugin plugin) { plugins = ReflectionUtils.getFieldValue(pluginManager, LinkedHashMap.class, "plugins"); } catch (IllegalAccessException | NoSuchFieldException | ClassCastException e) { logger.error("Failed to get necessary private fields to modify BungeeCord's plugin list order"); - logger.error("This may result in errors and inability to apply updates during the shutdown process."); + logger.error(resultMessage); e.printStackTrace(); return; } @@ -45,27 +48,35 @@ protected void run(UpdaterLogger logger, Plugin plugin) { // modify the plugin map once it is no longer being iterated over by BungeeCord to avoid ConcurrentModificationException. // onEnable() is called by BungeeCord when iterating over the plugin list, so we must modify it after bungeecord is done enabling ALL plugins // the listeners List is populated after all plugin enabling is finished. - task = bungeeCord.getScheduler().schedule(plugin, new Runnable() { - @Override - public void run() { - if (bungeeCord.isRunning) { - if (!listeners.isEmpty()) { - LinkedHashMap sortedPlugins = new LinkedHashMap<>(); - String updaterName = plugin.getDescription().getName(); - sortedPlugins.put(updaterName, plugins.get(updaterName)); // put ourselves at the very start, which means we disable last - sortedPlugins.putAll(plugins); // put the rest of the plugins in the default order + task = bungeeCord.getScheduler().schedule(plugin, () -> { + if (bungeeCord.isRunning) { + if (!listeners.isEmpty()) { + LinkedHashMap sortedPlugins = new LinkedHashMap<>(); + String updaterName = plugin.getDescription().getName(); + sortedPlugins.put(updaterName, plugins.get(updaterName)); // put ourselves at the very start, which means we disable last + sortedPlugins.putAll(plugins); // put the rest of the plugins in the default order + + Set originalOrder = null; + if (logger.isDebug()) { + originalOrder = plugins.keySet(); + } - synchronized (plugins) { - plugins.clear(); - plugins.putAll(sortedPlugins); - } + synchronized (plugins) { + plugins.clear(); + plugins.putAll(sortedPlugins); + } - logger.info("Successfully modified the order of BungeeCord's plugin Map."); - task.cancel(); + logger.info("Successfully modified the order of BungeeCord's plugin Map."); + if (logger.isDebug()) { + logger.debug("Original order: " + originalOrder); + logger.debug("New order: " + plugins.keySet()); } - } else { - throw new IllegalStateException("BungeeCord shutdown before we were able to modify the plugin list order"); + task.cancel(); } + } else { + logger.error("BungeeCord began shutdown before we were able to modify the plugin list order!"); + logger.error(resultMessage); + task.cancel(); } }, 2, 5, TimeUnit.SECONDS); } diff --git a/src/main/java/dev/projectg/geyserupdater/common/update/PluginId.java b/src/main/java/dev/projectg/geyserupdater/common/update/PluginId.java index 12795274..8455d8c0 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/update/PluginId.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/PluginId.java @@ -63,14 +63,10 @@ public void setArtifact(String artifactLink) { } /** - * @return A class from the plugin. Will throw an {@link AssertionError} if the class is not available, i.e. the plugin is not loaded. + * @return A class from the plugin. Will throw an {@link ClassNotFoundException} if the class is not available, i.e. the plugin is not loaded. */ - public Class getPluginClass() { - try { - return Class.forName(pluginClassName); - } catch (ClassNotFoundException e) { - throw new AssertionError("Failed to find Class '" + pluginClassName + "' for plugin: " + this.name() + ". Is the plugin loaded?"); - } + public Class getPluginClass() throws ClassNotFoundException { + return Class.forName(pluginClassName); } /** diff --git a/src/main/java/dev/projectg/geyserupdater/common/update/UpdateManager.java b/src/main/java/dev/projectg/geyserupdater/common/update/UpdateManager.java index 5e08e6b9..34d556ee 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/update/UpdateManager.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/UpdateManager.java @@ -42,25 +42,41 @@ public UpdateManager(Path defaultDownloadLocation, UpdaterScheduler scheduler, U for (PluginId pluginId : PluginId.values()) { if (pluginId.isEnable()) { - // Get the git.properties - InputStream is = pluginId.getPluginClass().getClassLoader().getResourceAsStream("git.properties"); - if (is == null) { - throw new AssertionError("Unable to find resource 'git.properties' for plugin: " + pluginId.name()); + String name = pluginId.name(); + + // todo: move getting the local build number and branch into PluginId + + // Get the inputstream of the git.properties + InputStream is; + try { + Class clazz = pluginId.getPluginClass(); + + is = clazz.getClassLoader().getResourceAsStream("git.properties"); + if (is == null) { + logger.error("Unable to find resource 'git.properties' for plugin: " + name); + continue; + } + } catch (ClassNotFoundException e) { + logger.error("Unable to find class for " + name + ", is it loaded? Unable to update."); + continue; } + // load the inputstream into a Properties Properties gitProperties = new Properties(); try { gitProperties.load(is); is.close(); } catch (IOException e) { - logger.error("Failed to get git.properties for plugin: " + pluginId.name() + ". Unable to update."); + logger.error("Failed to get git.properties for plugin: " + name + ". Unable to update."); e.printStackTrace(); + continue; } + // Get the build number and branch String buildNumberString = gitProperties.getProperty("git.build.number"); String branch = gitProperties.getProperty("git.branch"); if (buildNumberString == null || branch == null) { - UpdaterLogger.getLogger().error("Failed to find build number or branch in git Properties '" + gitProperties + "' of plugin '" + pluginId.name() + "'. Not updating."); + UpdaterLogger.getLogger().error("Failed to find build number or branch in git Properties '" + gitProperties + "' of plugin '" + name + "'. Not updating."); continue; } @@ -75,7 +91,7 @@ public UpdateManager(Path defaultDownloadLocation, UpdaterScheduler scheduler, U try { buildProvider = new JenkinsBuildProvider(pluginId.getLatestBuildNumber()); } catch (MalformedURLException e) { - UpdaterLogger.getLogger().error("Failed to create build number checker for " + pluginId + ". Not updating."); + UpdaterLogger.getLogger().error("Failed to create build number checker for " + name + ". Not updating."); e.printStackTrace(); continue; } @@ -87,12 +103,12 @@ public UpdateManager(Path defaultDownloadLocation, UpdaterScheduler scheduler, U JenkinsHashProvider jenkinsHashProvider = new JenkinsHashProvider(pluginId.getLatestFileLink() + "/*fingerprint*/"); hashComparer = new IdentityComparer<>(localHashProvider, jenkinsHashProvider); } catch (MalformedURLException e) { - UpdaterLogger.getLogger().error("Failure while getting location of file for " + pluginId.name() + ". It will be possible to update it, but not to compare file hashes."); + UpdaterLogger.getLogger().error("Failure while getting location of file for " + name + ". It will be possible to update it, but not to compare file hashes."); e.printStackTrace(); } register(new Updatable( - pluginId.name(), + name, new IdentityComparer<>(buildNumber, buildProvider), hashComparer, pluginId.getLatestFileLink(), From 0b294fa86d46e7a3fdb9a08e9c33cf3ce74c94f1 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Tue, 24 Aug 2021 21:45:53 -0400 Subject: [PATCH 38/42] fix debug logging on bungee Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../java/dev/projectg/geyserupdater/common/GeyserUpdater.java | 2 +- .../geyserupdater/common/logger/JavaUtilUpdaterLogger.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/dev/projectg/geyserupdater/common/GeyserUpdater.java b/src/main/java/dev/projectg/geyserupdater/common/GeyserUpdater.java index 89e2c688..f22de3dc 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/GeyserUpdater.java +++ b/src/main/java/dev/projectg/geyserupdater/common/GeyserUpdater.java @@ -70,7 +70,7 @@ public GeyserUpdater(Path dataFolder, if (latestVersion.equals(version)) { logger.info("You are using the latest version of GeyserUpdater!"); } else { - logger.info("Your version: " + version + ". Latest version: " + latestVersion + ". Download the newer version at https://www.spigotmc.org/resources/geyserupdater.88555/"); + logger.warn("Your version: " + version + ". Latest version: " + latestVersion + ". Download the newer version at https://www.spigotmc.org/resources/geyserupdater.88555/"); } } }, true); diff --git a/src/main/java/dev/projectg/geyserupdater/common/logger/JavaUtilUpdaterLogger.java b/src/main/java/dev/projectg/geyserupdater/common/logger/JavaUtilUpdaterLogger.java index 0f392c80..b3268e13 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/logger/JavaUtilUpdaterLogger.java +++ b/src/main/java/dev/projectg/geyserupdater/common/logger/JavaUtilUpdaterLogger.java @@ -30,12 +30,12 @@ public void info(String message) { @Override public void debug(String message) { - logger.fine(message); + logger.info(message); } @Override public void trace(String message) { - logger.finer(message); + logger.info(message); } @Override From 184cac5aee91b6f67f9fc6ad6b19ff03fe485b9d Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Wed, 25 Aug 2021 00:47:53 -0400 Subject: [PATCH 39/42] add todo Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../geyserupdater/common/logger/JavaUtilUpdaterLogger.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/dev/projectg/geyserupdater/common/logger/JavaUtilUpdaterLogger.java b/src/main/java/dev/projectg/geyserupdater/common/logger/JavaUtilUpdaterLogger.java index b3268e13..00d1c2c8 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/logger/JavaUtilUpdaterLogger.java +++ b/src/main/java/dev/projectg/geyserupdater/common/logger/JavaUtilUpdaterLogger.java @@ -33,6 +33,8 @@ public void debug(String message) { logger.info(message); } + // todo: try to making debug/trace logging labbeled correctly. check how floodgate does it + @Override public void trace(String message) { logger.info(message); From 37ed4ad0479046f62600493ba3ef1c9987c1fc71 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Sat, 28 Aug 2021 19:59:14 -0400 Subject: [PATCH 40/42] update bukkit 1.8 to spigot 1.12 Geyser no longer supports versions below 1.12 The minecraft community has also moved on from 1.12 significantly Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- pom.xml | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/pom.xml b/pom.xml index ba50075a..9c8297c9 100644 --- a/pom.xml +++ b/pom.xml @@ -34,21 +34,15 @@ - org.bukkit - bukkit - 1.8-R0.1-SNAPSHOT - provided - - - com.github.SpigotMC.BungeeCord - bungeecord-api - bda1605627 + org.spigotmc + spigot-api + 1.12.2-R0.1-SNAPSHOT provided com.github.SpigotMC.BungeeCord bungeecord-proxy - + a7c6ede provided @@ -129,7 +123,7 @@ com.fasterxml.jackson - dev.projectg.geyserupdater.shaded + dev.projectg.geyserupdater.shaded.jackson From f092ce3c5281fcc220875144cd45885b5986cbdc Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Sat, 2 Oct 2021 10:02:32 -0400 Subject: [PATCH 41/42] update some names Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../geyserupdater/bungee/BungeePlayerHandler.java | 4 ++-- .../geyserupdater/common/GeyserUpdater.java | 12 ++++++++---- .../{PlayerHandler.java => PlayerManager.java} | 2 +- .../common/command/CommandManager.java | 14 ++++++++++++++ .../common/command/CommandSender.java | 12 ++++++++++++ .../common/command/UpdaterCommand.java | 6 ++++++ .../geyserupdater/spigot/SpigotPlayerHandler.java | 4 ++-- .../velocity/VelocityPlayerHandler.java | 4 ++-- 8 files changed, 47 insertions(+), 11 deletions(-) rename src/main/java/dev/projectg/geyserupdater/common/{PlayerHandler.java => PlayerManager.java} (89%) create mode 100644 src/main/java/dev/projectg/geyserupdater/common/command/CommandManager.java create mode 100644 src/main/java/dev/projectg/geyserupdater/common/command/CommandSender.java create mode 100644 src/main/java/dev/projectg/geyserupdater/common/command/UpdaterCommand.java diff --git a/src/main/java/dev/projectg/geyserupdater/bungee/BungeePlayerHandler.java b/src/main/java/dev/projectg/geyserupdater/bungee/BungeePlayerHandler.java index eb78979d..3f426d26 100644 --- a/src/main/java/dev/projectg/geyserupdater/bungee/BungeePlayerHandler.java +++ b/src/main/java/dev/projectg/geyserupdater/bungee/BungeePlayerHandler.java @@ -1,6 +1,6 @@ package dev.projectg.geyserupdater.bungee; -import dev.projectg.geyserupdater.common.PlayerHandler; +import dev.projectg.geyserupdater.common.PlayerManager; import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.connection.ProxiedPlayer; @@ -10,7 +10,7 @@ import java.util.List; import java.util.UUID; -public class BungeePlayerHandler implements PlayerHandler { +public class BungeePlayerHandler implements PlayerManager { @Override public @NotNull List getOnlinePlayers() { diff --git a/src/main/java/dev/projectg/geyserupdater/common/GeyserUpdater.java b/src/main/java/dev/projectg/geyserupdater/common/GeyserUpdater.java index f22de3dc..d77affc7 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/GeyserUpdater.java +++ b/src/main/java/dev/projectg/geyserupdater/common/GeyserUpdater.java @@ -25,7 +25,7 @@ public class GeyserUpdater { private final Path installFolder; private final UpdaterLogger logger; private final UpdaterScheduler scheduler; - private final PlayerHandler playerHandler; + private final PlayerManager playerManager; private final UpdateManager updateManager; private final UpdaterConfiguration config; @@ -36,7 +36,7 @@ public class GeyserUpdater { * @param bootstrap The {@link UpdaterBootstrap} platform implemenetation * @param logger The {@link UpdaterLogger} platform implemenetation * @param scheduler The {@link UpdaterScheduler} platform implemenetation - * @param playerHandler The {@link PlayerHandler} platform implemenetation + * @param playerManager The {@link PlayerManager} platform implemenetation * @param version The version of GeyserUpdater * @param geyserArtifact The artifact link for Geyser. For example: "bootstrap/velocity/target/Geyser-Velocity.jar" * @param floodgateArtifact The artifact link for Floodgate. For example: "bootstrap/velocity/target/floodgate-velocity.jar" @@ -48,7 +48,7 @@ public GeyserUpdater(Path dataFolder, UpdaterBootstrap bootstrap, UpdaterLogger logger, UpdaterScheduler scheduler, - PlayerHandler playerHandler, + PlayerManager playerManager, String version, String geyserArtifact, String floodgateArtifact) throws IOException { @@ -56,7 +56,7 @@ public GeyserUpdater(Path dataFolder, this.installFolder = installFolder; this.logger = logger; this.scheduler = scheduler; - this.playerHandler = playerHandler; + this.playerManager = playerManager; this.version = version; INSTANCE = this; @@ -158,4 +158,8 @@ public UpdaterLogger getLogger() { public UpdaterScheduler getScheduler() { return scheduler; } + + public PlayerManager getPlayerHandler() { + return playerManager; + } } diff --git a/src/main/java/dev/projectg/geyserupdater/common/PlayerHandler.java b/src/main/java/dev/projectg/geyserupdater/common/PlayerManager.java similarity index 89% rename from src/main/java/dev/projectg/geyserupdater/common/PlayerHandler.java rename to src/main/java/dev/projectg/geyserupdater/common/PlayerManager.java index 29a29ac1..44d3d79d 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/PlayerHandler.java +++ b/src/main/java/dev/projectg/geyserupdater/common/PlayerManager.java @@ -6,7 +6,7 @@ import java.util.List; import java.util.UUID; -public interface PlayerHandler { +public interface PlayerManager { @Nonnull List getOnlinePlayers(); diff --git a/src/main/java/dev/projectg/geyserupdater/common/command/CommandManager.java b/src/main/java/dev/projectg/geyserupdater/common/command/CommandManager.java new file mode 100644 index 00000000..ab688e9b --- /dev/null +++ b/src/main/java/dev/projectg/geyserupdater/common/command/CommandManager.java @@ -0,0 +1,14 @@ +package dev.projectg.geyserupdater.common.command; + +public class CommandManager { + + + + public CommandManager() { + + } + + public boolean process(CommandSender sender, String cmd, String[] args) { + return false; + } +} diff --git a/src/main/java/dev/projectg/geyserupdater/common/command/CommandSender.java b/src/main/java/dev/projectg/geyserupdater/common/command/CommandSender.java new file mode 100644 index 00000000..8612838c --- /dev/null +++ b/src/main/java/dev/projectg/geyserupdater/common/command/CommandSender.java @@ -0,0 +1,12 @@ +package dev.projectg.geyserupdater.common.command; + +import dev.projectg.geyserupdater.common.GeyserUpdater; +import dev.projectg.geyserupdater.common.PlayerManager; + +public class CommandSender { + + public void sendMessage() { + PlayerManager handler = GeyserUpdater.getInstance().getPlayerHandler(); + + } +} diff --git a/src/main/java/dev/projectg/geyserupdater/common/command/UpdaterCommand.java b/src/main/java/dev/projectg/geyserupdater/common/command/UpdaterCommand.java new file mode 100644 index 00000000..7c2bc181 --- /dev/null +++ b/src/main/java/dev/projectg/geyserupdater/common/command/UpdaterCommand.java @@ -0,0 +1,6 @@ +package dev.projectg.geyserupdater.common.command; + +public interface UpdaterCommand { + + boolean process(CommandSender sender, String cmd, String[] args); +} diff --git a/src/main/java/dev/projectg/geyserupdater/spigot/SpigotPlayerHandler.java b/src/main/java/dev/projectg/geyserupdater/spigot/SpigotPlayerHandler.java index bf80f00e..41f3a6f4 100644 --- a/src/main/java/dev/projectg/geyserupdater/spigot/SpigotPlayerHandler.java +++ b/src/main/java/dev/projectg/geyserupdater/spigot/SpigotPlayerHandler.java @@ -1,6 +1,6 @@ package dev.projectg.geyserupdater.spigot; -import dev.projectg.geyserupdater.common.PlayerHandler; +import dev.projectg.geyserupdater.common.PlayerManager; import org.bukkit.Server; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; @@ -9,7 +9,7 @@ import java.util.List; import java.util.UUID; -public class SpigotPlayerHandler implements PlayerHandler { +public class SpigotPlayerHandler implements PlayerManager { private final Server server; diff --git a/src/main/java/dev/projectg/geyserupdater/velocity/VelocityPlayerHandler.java b/src/main/java/dev/projectg/geyserupdater/velocity/VelocityPlayerHandler.java index 597182fb..acb04caf 100644 --- a/src/main/java/dev/projectg/geyserupdater/velocity/VelocityPlayerHandler.java +++ b/src/main/java/dev/projectg/geyserupdater/velocity/VelocityPlayerHandler.java @@ -1,6 +1,6 @@ package dev.projectg.geyserupdater.velocity; -import dev.projectg.geyserupdater.common.PlayerHandler; +import dev.projectg.geyserupdater.common.PlayerManager; import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.ProxyServer; import org.jetbrains.annotations.NotNull; @@ -10,7 +10,7 @@ import java.util.List; import java.util.UUID; -public class VelocityPlayerHandler implements PlayerHandler { +public class VelocityPlayerHandler implements PlayerManager { private final ProxyServer proxyServer; From 0c7d0fb58d4ebdc41dc3daabe0a05448c1c5f45f Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Sun, 2 Jan 2022 01:59:46 -0500 Subject: [PATCH 42/42] Dump dirty, broken config changes Signed-off-by: Konicai <71294714+Konicai@users.noreply.github.com> --- pom.xml | 38 +++----- .../geyserupdater/bungee/BungeeUpdater.java | 3 +- .../geyserupdater/common/GeyserUpdater.java | 19 ++-- .../common/config/Configurator.java | 19 ++++ .../common/config/UpdaterConfiguration.java | 92 ++++--------------- .../geyserupdater/common/config/lombok.config | 1 + .../common/config/module/DefinedModule.java | 23 +++++ .../common/config/module/IModule.java | 14 +++ .../common/config/module/PresetModule.java | 30 ++++++ .../config/module/project/JenkinsProject.java | 16 ++++ .../common/config/module/project/Project.java | 4 + .../config/module/project/SpigotProject.java | 8 ++ .../geyserupdater/common/update/PluginId.java | 11 +-- .../geyserupdater/common/util/FileUtils.java | 21 ----- ...rceUpdateChecker.java => SpigotUtils.java} | 22 +++-- .../geyserupdater/spigot/SpigotUpdater.java | 3 +- .../velocity/VelocityUpdater.java | 3 +- src/main/resources/config.yml | 51 +++++++--- 18 files changed, 218 insertions(+), 160 deletions(-) create mode 100644 src/main/java/dev/projectg/geyserupdater/common/config/Configurator.java create mode 100644 src/main/java/dev/projectg/geyserupdater/common/config/lombok.config create mode 100644 src/main/java/dev/projectg/geyserupdater/common/config/module/DefinedModule.java create mode 100644 src/main/java/dev/projectg/geyserupdater/common/config/module/IModule.java create mode 100644 src/main/java/dev/projectg/geyserupdater/common/config/module/PresetModule.java create mode 100644 src/main/java/dev/projectg/geyserupdater/common/config/module/project/JenkinsProject.java create mode 100644 src/main/java/dev/projectg/geyserupdater/common/config/module/project/Project.java create mode 100644 src/main/java/dev/projectg/geyserupdater/common/config/module/project/SpigotProject.java rename src/main/java/dev/projectg/geyserupdater/common/util/{SpigotResourceUpdateChecker.java => SpigotUtils.java} (65%) diff --git a/pom.xml b/pom.xml index 9c8297c9..745c0cf7 100644 --- a/pom.xml +++ b/pom.xml @@ -52,37 +52,18 @@ 3.0.0 provided + org.apache.logging.log4j log4j-core - 2.13.2 provided - com.fasterxml.jackson.core - jackson-annotations - ${jackson.version} - compile - - - com.fasterxml.jackson.core - jackson-core - ${jackson.version} - compile - - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - compile - - - com.fasterxml.jackson.dataformat - jackson-dataformat-yaml - ${jackson.version} - compile + org.spongepowered + configurate-yaml + 4.1.2 @@ -90,6 +71,13 @@ jsr305 3.0.2 + + + org.projectlombok + lombok + 1.18.22 + provided + @@ -122,8 +110,8 @@ - com.fasterxml.jackson - dev.projectg.geyserupdater.shaded.jackson + org.spongepowered.configurate + dev.projectg.geyserupdater.shaded.configurate diff --git a/src/main/java/dev/projectg/geyserupdater/bungee/BungeeUpdater.java b/src/main/java/dev/projectg/geyserupdater/bungee/BungeeUpdater.java index 2875e37f..2d29e49c 100644 --- a/src/main/java/dev/projectg/geyserupdater/bungee/BungeeUpdater.java +++ b/src/main/java/dev/projectg/geyserupdater/bungee/BungeeUpdater.java @@ -9,6 +9,7 @@ import dev.projectg.geyserupdater.common.util.ScriptCreator; import net.md_5.bungee.api.plugin.Plugin; +import space.arim.dazzleconf.error.InvalidConfigException; import java.io.IOException; import java.nio.file.Path; @@ -33,7 +34,7 @@ public void onEnable() { "bootstrap/bungeecord/target/Geyser-BungeeCord.jar", "bootstrap/bungee/target/floodgate-bungee.jar" ); - } catch (IOException e) { + } catch (IOException | InvalidConfigException e) { getLogger().severe("Failed to start GeyserUpdater! Disabling..."); e.printStackTrace(); return; diff --git a/src/main/java/dev/projectg/geyserupdater/common/GeyserUpdater.java b/src/main/java/dev/projectg/geyserupdater/common/GeyserUpdater.java index d77affc7..177c1740 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/GeyserUpdater.java +++ b/src/main/java/dev/projectg/geyserupdater/common/GeyserUpdater.java @@ -1,13 +1,14 @@ package dev.projectg.geyserupdater.common; +import dev.projectg.geyserupdater.common.config.Configurator; import dev.projectg.geyserupdater.common.config.UpdaterConfiguration; import dev.projectg.geyserupdater.common.logger.UpdaterLogger; import dev.projectg.geyserupdater.common.scheduler.UpdaterScheduler; import dev.projectg.geyserupdater.common.update.PluginId; import dev.projectg.geyserupdater.common.update.Updatable; import dev.projectg.geyserupdater.common.update.UpdateManager; -import dev.projectg.geyserupdater.common.util.FileUtils; -import dev.projectg.geyserupdater.common.util.SpigotResourceUpdateChecker; +import dev.projectg.geyserupdater.common.util.SpigotUtils; +import space.arim.dazzleconf.error.InvalidConfigException; import java.io.IOException; import java.nio.file.Files; @@ -51,7 +52,7 @@ public GeyserUpdater(Path dataFolder, PlayerManager playerManager, String version, String geyserArtifact, - String floodgateArtifact) throws IOException { + String floodgateArtifact) throws IOException, InvalidConfigException { this.downloadFolder = downloadFolder; this.installFolder = installFolder; this.logger = logger; @@ -63,7 +64,7 @@ public GeyserUpdater(Path dataFolder, // Meta version checking scheduler.run(() -> { - String latestVersion = SpigotResourceUpdateChecker.getVersion(88555); + String latestVersion = SpigotUtils.getVersion(88555); if (latestVersion == null || latestVersion.isEmpty()) { logger.error("Failed to determine the latest GeyserUpdater version!"); } else { @@ -76,16 +77,16 @@ public GeyserUpdater(Path dataFolder, }, true); // Load the config - config = FileUtils.loadConfig(dataFolder.resolve("config.yml")); - if (config.isIncorrectVersion()) { - throw new IllegalStateException("Your copy of config.yml is outdated (your version: " + config.getConfigVersion() + ", latest version: " + UpdaterConfiguration.DEFAULT_CONFIG_VERSION + "). Please delete it and let a fresh copy of config.yml be regenerated!"); + config = Configurator.loadConfig(dataFolder.resolve("config.yml")); + if (UpdaterConfiguration.DEFAULT_VERSION != config.version()) { + throw new IllegalStateException("Your copy of config.yml is outdated (your version: " + config.version() + ", latest version: " + UpdaterConfiguration.DEFAULT_VERSION + "). Please delete it and let a fresh copy of config.yml be regenerated!"); } - if (config.isEnableDebug()) { + if (config.enableDebug()) { logger.enableDebug(); } // Make startup script if enabled - if (config.isGenerateRestartScript()) { + if (config.generateRestartScript()) { try { logger.debug("Attempting to create restart script"); bootstrap.createRestartScript(); diff --git a/src/main/java/dev/projectg/geyserupdater/common/config/Configurator.java b/src/main/java/dev/projectg/geyserupdater/common/config/Configurator.java new file mode 100644 index 00000000..8dac2cf4 --- /dev/null +++ b/src/main/java/dev/projectg/geyserupdater/common/config/Configurator.java @@ -0,0 +1,19 @@ +package dev.projectg.geyserupdater.common.config; + +import space.arim.dazzleconf.ConfigurationOptions; +import space.arim.dazzleconf.ext.snakeyaml.CommentMode; +import space.arim.dazzleconf.ext.snakeyaml.SnakeYamlConfigurationFactory; +import space.arim.dazzleconf.ext.snakeyaml.SnakeYamlOptions; + +import java.util.Map; + +public class Configurator { + + Map + + + static { + + } + +} diff --git a/src/main/java/dev/projectg/geyserupdater/common/config/UpdaterConfiguration.java b/src/main/java/dev/projectg/geyserupdater/common/config/UpdaterConfiguration.java index 6324f053..30c0cc3a 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/config/UpdaterConfiguration.java +++ b/src/main/java/dev/projectg/geyserupdater/common/config/UpdaterConfiguration.java @@ -1,94 +1,40 @@ package dev.projectg.geyserupdater.common.config; -import com.fasterxml.jackson.annotation.JsonFormat; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.Map; - -@JsonIgnoreProperties(ignoreUnknown = true) -@JsonFormat(with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES) -@SuppressWarnings("FieldMayBeFinal") // Must be non-final for Jackson to work +import lombok.Getter; +import org.spongepowered.configurate.objectmapping.ConfigSerializable; +import org.spongepowered.configurate.objectmapping.meta.Required; +import org.spongepowered.configurate.objectmapping.meta.Setting; + +@Getter +@ConfigSerializable +@SuppressWarnings("FieldMayBeFinal") public class UpdaterConfiguration { - public static int DEFAULT_CONFIG_VERSION = 3; + public static int DEFAULT_VERSION = 3; - @JsonProperty(value = "default-updates") - private Map defaultUpdates; - public Map getDefaultUpdates() { - return defaultUpdates; - } - - @JsonProperty(value = "Auto-Update-Interval") + @Setting("auto-check-interval") private int autoUpdateInterval = 24; - public int getAutoUpdateInterval() { - return autoUpdateInterval; - } - @JsonProperty(value = "delete-on-fail") + @Setting("delete-on-fail") private boolean deleteOnFail = true; - public boolean isDeleteOnFail() { - return deleteOnFail; - } - @JsonProperty(value = "Auto-Restart-Server") + @Setting("restart-server") private boolean restartServer = false; - public boolean isRestartServer() { - return restartServer; - } - @JsonProperty(value = "Auto-Script-Generating") + @Setting("restart-script") private boolean generateRestartScript = false; - public boolean isGenerateRestartScript() { - return generateRestartScript; - } - @JsonProperty(value = "Restart-Message-Players") + @Setting("restart-message") private String restartMessage = "§2This server will be restarting in 10 seconds!"; - public String getRestartMessage() { - return restartMessage; - } - @JsonProperty(value = "download-time-limit") + @Setting("download-time-limit") private int downloadTimeLimit = 180; - public int getDownloadTimeLimit() { - return downloadTimeLimit; - } - @JsonProperty(value = "Enable-Debug") + @Setting("debug") private boolean enableDebug = false; - public boolean isEnableDebug() { - return enableDebug; - } - - @JsonProperty(value = "Config-Version", required = true) - private int configVersion = 3; - public int getConfigVersion() { - return configVersion; - } - - public boolean isIncorrectVersion() { - return getConfigVersion() != DEFAULT_CONFIG_VERSION; - } - - public static final class DefaultUpdate { - - @JsonProperty(value = "enable", required = true) - private boolean enable = false; - public boolean isEnable() { - return enable; - } - @JsonProperty(value = "auto-check", required = true) - private boolean autoCheck = false; - public boolean isAutoCheck() { - return autoCheck; - } + @Required + @Setting("config-version") + private int version = 3; - @JsonProperty(value = "auto-update", required = true) - private boolean autoUpdate = false; - public boolean isAutoUpdate() { - return autoUpdate; - } - } } diff --git a/src/main/java/dev/projectg/geyserupdater/common/config/lombok.config b/src/main/java/dev/projectg/geyserupdater/common/config/lombok.config new file mode 100644 index 00000000..18f74be1 --- /dev/null +++ b/src/main/java/dev/projectg/geyserupdater/common/config/lombok.config @@ -0,0 +1 @@ +lombok.accessors.fluent = true \ No newline at end of file diff --git a/src/main/java/dev/projectg/geyserupdater/common/config/module/DefinedModule.java b/src/main/java/dev/projectg/geyserupdater/common/config/module/DefinedModule.java new file mode 100644 index 00000000..fb390801 --- /dev/null +++ b/src/main/java/dev/projectg/geyserupdater/common/config/module/DefinedModule.java @@ -0,0 +1,23 @@ +package dev.projectg.geyserupdater.common.config.module; + +import dev.projectg.geyserupdater.common.config.module.project.Project; +import lombok.Getter; +import org.spongepowered.configurate.objectmapping.ConfigSerializable; +import org.spongepowered.configurate.objectmapping.meta.Setting; + +@ConfigSerializable +@SuppressWarnings("FieldMayBeFinal") +@Getter +public class DefinedModule extends PresetModule implements IModule { + + @Setting("enable") + private boolean enable = true; + + @Setting("auto-check") + private boolean autoCheck = true; + + @Setting("auto-update") + private boolean autoUpdate = false; + + private Project project = null; +} diff --git a/src/main/java/dev/projectg/geyserupdater/common/config/module/IModule.java b/src/main/java/dev/projectg/geyserupdater/common/config/module/IModule.java new file mode 100644 index 00000000..ec305f49 --- /dev/null +++ b/src/main/java/dev/projectg/geyserupdater/common/config/module/IModule.java @@ -0,0 +1,14 @@ +package dev.projectg.geyserupdater.common.config.module; + +import dev.projectg.geyserupdater.common.config.module.project.Project; + +public interface IModule { + + boolean enable(); + + boolean autoCheck(); + + boolean autoUpdate(); + + Project project(); +} diff --git a/src/main/java/dev/projectg/geyserupdater/common/config/module/PresetModule.java b/src/main/java/dev/projectg/geyserupdater/common/config/module/PresetModule.java new file mode 100644 index 00000000..5413bbff --- /dev/null +++ b/src/main/java/dev/projectg/geyserupdater/common/config/module/PresetModule.java @@ -0,0 +1,30 @@ +package dev.projectg.geyserupdater.common.config.module; + +import dev.projectg.geyserupdater.common.config.module.project.Project; +import lombok.Getter; +import org.spongepowered.configurate.objectmapping.ConfigSerializable; +import org.spongepowered.configurate.objectmapping.meta.NodeKey; +import org.spongepowered.configurate.objectmapping.meta.Setting; + +@ConfigSerializable +@SuppressWarnings("FieldMayBeFinal") +@Getter +public class PresetModule implements IModule { + + @NodeKey + private String preset; + + @Setting("enable") + private boolean enable = true; + + @Setting("auto-check") + private boolean autoCheck = true; + + @Setting("auto-update") + private boolean autoUpdate = false; + + @Override + public Project project() { + + } +} diff --git a/src/main/java/dev/projectg/geyserupdater/common/config/module/project/JenkinsProject.java b/src/main/java/dev/projectg/geyserupdater/common/config/module/project/JenkinsProject.java new file mode 100644 index 00000000..3b4daec0 --- /dev/null +++ b/src/main/java/dev/projectg/geyserupdater/common/config/module/project/JenkinsProject.java @@ -0,0 +1,16 @@ +package dev.projectg.geyserupdater.common.config.module.project; + +import space.arim.dazzleconf.annote.ConfKey; +import space.arim.dazzleconf.annote.ConfSerialisers; +import space.arim.dazzleconf.serialiser.URLValueSerialiser; + +import java.net.URL; + +@ConfSerialisers(URLValueSerialiser.class) +public interface JenkinsProject { + @ConfKey("project") + String projectLink(); + + @ConfKey("download") + URL downloadLink(); +} diff --git a/src/main/java/dev/projectg/geyserupdater/common/config/module/project/Project.java b/src/main/java/dev/projectg/geyserupdater/common/config/module/project/Project.java new file mode 100644 index 00000000..aa9a4608 --- /dev/null +++ b/src/main/java/dev/projectg/geyserupdater/common/config/module/project/Project.java @@ -0,0 +1,4 @@ +package dev.projectg.geyserupdater.common.config.module.project; + +public interface Project { +} diff --git a/src/main/java/dev/projectg/geyserupdater/common/config/module/project/SpigotProject.java b/src/main/java/dev/projectg/geyserupdater/common/config/module/project/SpigotProject.java new file mode 100644 index 00000000..daa01cd5 --- /dev/null +++ b/src/main/java/dev/projectg/geyserupdater/common/config/module/project/SpigotProject.java @@ -0,0 +1,8 @@ +package dev.projectg.geyserupdater.common.config.module.project; + +import space.arim.dazzleconf.annote.ConfKey; + +public interface SpigotProject { + @ConfKey("resource") + int resourceId(); +} diff --git a/src/main/java/dev/projectg/geyserupdater/common/update/PluginId.java b/src/main/java/dev/projectg/geyserupdater/common/update/PluginId.java index 8455d8c0..3d5dc48f 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/update/PluginId.java +++ b/src/main/java/dev/projectg/geyserupdater/common/update/PluginId.java @@ -71,17 +71,10 @@ public Class getPluginClass() throws ClassNotFoundException { /** * Load the enable, autoCheck, and autoUpdate configuration settings into the enum values. - * {@link UpdaterConfiguration#getDefaultUpdates()} should contain entries whose keys are equal an enum value's name in lowercase + * {@link JacksonConfiguration#getUpdateEntries()} should contain entries whose keys are equal an enum value's name in lowercase * @param config The config to load from */ public static void loadSettings(UpdaterConfiguration config) { - for (PluginId plugin : PluginId.values()) { - UpdaterConfiguration.DefaultUpdate settings = config.getDefaultUpdates().get(plugin.name().toLowerCase()); - if (settings != null) { - plugin.enable = settings.isEnable(); - plugin.autoCheck = settings.isAutoCheck(); - plugin.autoUpdate = settings.isAutoUpdate(); - } - } + throw new UnsupportedOperationException(); } } diff --git a/src/main/java/dev/projectg/geyserupdater/common/util/FileUtils.java b/src/main/java/dev/projectg/geyserupdater/common/util/FileUtils.java index 3be1606c..06573bc4 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/util/FileUtils.java +++ b/src/main/java/dev/projectg/geyserupdater/common/util/FileUtils.java @@ -1,32 +1,11 @@ package dev.projectg.geyserupdater.common.util; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; -import dev.projectg.geyserupdater.common.config.UpdaterConfiguration; - -import java.io.IOException; -import java.io.InputStream; import java.net.URISyntaxException; -import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.Objects; public class FileUtils { - public static UpdaterConfiguration loadConfig(Path userConfig) throws IOException { - if (!Files.exists(userConfig)) { - Files.createDirectories(userConfig.getParent()); - try (InputStream inputStream = FileUtils.class.getResourceAsStream("/config.yml")) { - Objects.requireNonNull(inputStream); - Files.copy(inputStream, userConfig); - } - } - - ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory()); - return yamlMapper.readValue(userConfig.toFile(), UpdaterConfiguration.class); - } - /** * Get the file that a class resides in. * @param clazz The class diff --git a/src/main/java/dev/projectg/geyserupdater/common/util/SpigotResourceUpdateChecker.java b/src/main/java/dev/projectg/geyserupdater/common/util/SpigotUtils.java similarity index 65% rename from src/main/java/dev/projectg/geyserupdater/common/util/SpigotResourceUpdateChecker.java rename to src/main/java/dev/projectg/geyserupdater/common/util/SpigotUtils.java index 652ea972..2b20d16c 100644 --- a/src/main/java/dev/projectg/geyserupdater/common/util/SpigotResourceUpdateChecker.java +++ b/src/main/java/dev/projectg/geyserupdater/common/util/SpigotUtils.java @@ -4,12 +4,13 @@ import java.io.IOException; import java.io.InputStream; +import java.net.MalformedURLException; import java.net.URL; import java.util.Scanner; -public class SpigotResourceUpdateChecker { +public class SpigotUtils { - private static final String VERSION_REGEX = "(\\d+.){1,2}\\d+(-SNAPSHOT){0,1}"; + private static final String VERSION_REGEX = "(\\d+.){1,2}\\d+(-SNAPSHOT|-RC\\d{1,2}){0,1}"; /** * Get the latest version of GeyserUpdater from the spigot resource page @@ -23,15 +24,22 @@ public static String getVersion(int resourceId) { builder.append(scanner.next()); } String version = builder.toString(); - if (version.matches(VERSION_REGEX)) { - return version; - } else { - UpdaterLogger.getLogger().warn("Got unexpected string when checking Spigot resource page version: " + version); - return null; + if (!version.matches(VERSION_REGEX)) { + UpdaterLogger.getLogger().warn("Got unexpected string when checking version of Spigot resource " + resourceId + ": " + version); } + + return version; } catch (IOException exception) { UpdaterLogger.getLogger().error("Failed to check for updates: " + exception.getMessage()); return null; } } + + public static URL getDownloadUrl(int resourceId) { + try { + return new URL("https://api.spiget.org/v2/resources/" + resourceId + "/download"); + } catch (MalformedURLException e) { + throw new AssertionError("Unexpected MalformedURLException when getting download link for spigot resource"); + } + } } diff --git a/src/main/java/dev/projectg/geyserupdater/spigot/SpigotUpdater.java b/src/main/java/dev/projectg/geyserupdater/spigot/SpigotUpdater.java index 76488bb0..8cfedd6e 100644 --- a/src/main/java/dev/projectg/geyserupdater/spigot/SpigotUpdater.java +++ b/src/main/java/dev/projectg/geyserupdater/spigot/SpigotUpdater.java @@ -10,6 +10,7 @@ import org.bukkit.Server; import org.bukkit.plugin.java.JavaPlugin; +import space.arim.dazzleconf.error.InvalidConfigException; import java.io.IOException; import java.nio.file.Path; @@ -37,7 +38,7 @@ public void onEnable() { "bootstrap/spigot/target/Geyser-Spigot.jar", "bootstrap/spigot/target/floodgate-spigot.jar" ); - } catch (IOException e) { + } catch (IOException | InvalidConfigException e) { getLogger().severe("Failed to start GeyserUpdater! Disabling..."); e.printStackTrace(); return; diff --git a/src/main/java/dev/projectg/geyserupdater/velocity/VelocityUpdater.java b/src/main/java/dev/projectg/geyserupdater/velocity/VelocityUpdater.java index 4cb8cde3..0775f770 100644 --- a/src/main/java/dev/projectg/geyserupdater/velocity/VelocityUpdater.java +++ b/src/main/java/dev/projectg/geyserupdater/velocity/VelocityUpdater.java @@ -16,6 +16,7 @@ import com.velocitypowered.api.plugin.annotation.DataDirectory; import com.velocitypowered.api.proxy.ProxyServer; import org.slf4j.Logger; +import space.arim.dazzleconf.error.InvalidConfigException; import java.io.IOException; import java.nio.file.Path; @@ -42,7 +43,7 @@ public VelocityUpdater(ProxyServer server, Logger baseLogger, @DataDirectory fin } @Subscribe - public void onProxyInitialization(ProxyInitializeEvent event) throws IOException { + public void onProxyInitialization(ProxyInitializeEvent event) throws IOException, InvalidConfigException { updater = new GeyserUpdater( dataDirectory, diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 8a4f5d27..41436ade 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -4,18 +4,8 @@ # NOTICE: Please read the README on our github page for full information regarding these options! # https://github.com/ProjectG-Plugins/GeyserUpdater -default-updates: - geyser: - enable: true - auto-check: true - auto-update: false - floodgate: - enable: false - auto-check: true - auto-update: false - # The interval in hours between each auto update check. -auto-update-interval: 24 +auto-check-interval: 24 # The maximum amount of seconds that a download is allowed to run for. Increase if you are running into issues on a slow internet connection. download-time-limit: 180 # Delete the downloaded file if the file hash of the downloaded file did not match what the download server provided. @@ -25,7 +15,7 @@ delete-on-fail: true # If enabled, GeyserUpdater will attempt to restart the server 10 seconds after a new version of Geyser has been successfully downloaded. # If you aren't using a hosting provider or a server wrapper, you will need a restart script. -auto-restart-server: false +restart-server: false # When enabled, GeyserUpdater will automatically generate a restart script for you. If you are using CraftBukkit or a proxy # you will need to use the generated script to start your server! If you are using a hosting provider or a server wrapper you probably don't need this. auto-script-generating: false @@ -35,4 +25,39 @@ restart-message-players: "§2This server will be restarting in 10 seconds!" # Enable debug logging enable-debug: false # Please do not change this version value! -config-version: 3 \ No newline at end of file +config-version: 3 + + +modules: + GeyserHub: + enable: true + auto-check: true + auto-update: false + version: + jenkins: + # Requires plugin to have a git.properties containing a git.build.number value + project: "https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/master" + spigot: + # Compares version of plugin that the platform provides vs the latest version on SpigotMC + resource: 88555 + github: + id: + + download: + literal: + # Allows specifying a static download location and file + file: "https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/master/lastSuccessfulBuild/artifact/bootstrap/spigot/target/Geyser-Spigot.jar" + spigot: + # Downloads file from a SpigotMC listing. The download link provided on SpigotMC must lead to an immediate file download. + resource: 88555 + +presets: + geyser: + enable: true + auto-check: true + auto-update: true + custom: + # Certain presets may require or allow additional data + branch: master + compare-hash: true +