From 0fd72513bef7e1f67fdaa738ac7ba52187460771 Mon Sep 17 00:00:00 2001 From: MiniDay <372403923@qq.com> Date: Sun, 17 Mar 2024 00:08:50 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=87=AA=E5=8A=A8=E6=A3=80=E6=B5=8B=20?= =?UTF-8?q?Jenkins=20=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/core/bukkit/HamsterCorePlugin.java | 44 +++++++++++++++++ .../listener/JenkinsUpdateListener.java | 30 ++++++++++++ .../plugin/core/bungee/HamsterCorePlugin.java | 47 +++++++++++++++++++ .../plugin/core/common/config/YamlConfig.java | 10 ++-- .../plugin/core/common/util/JenkinsUtils.java | 41 ++++++++++++++++ 5 files changed, 169 insertions(+), 3 deletions(-) create mode 100644 core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/listener/JenkinsUpdateListener.java create mode 100644 core-common/src/main/java/cn/hamster3/mc/plugin/core/common/util/JenkinsUtils.java diff --git a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/HamsterCorePlugin.java b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/HamsterCorePlugin.java index ab19a80..059f459 100644 --- a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/HamsterCorePlugin.java +++ b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/HamsterCorePlugin.java @@ -9,21 +9,30 @@ import cn.hamster3.mc.plugin.core.bukkit.hook.PointAPI; import cn.hamster3.mc.plugin.core.bukkit.hook.VaultAPI; import cn.hamster3.mc.plugin.core.bukkit.listener.CallbackListener; import cn.hamster3.mc.plugin.core.bukkit.listener.DebugListener; +import cn.hamster3.mc.plugin.core.bukkit.listener.JenkinsUpdateListener; import cn.hamster3.mc.plugin.core.bukkit.page.handler.PageHandler; import cn.hamster3.mc.plugin.core.bukkit.page.listener.PageListener; import cn.hamster3.mc.plugin.core.bukkit.util.MinecraftVersion; import cn.hamster3.mc.plugin.core.common.api.CoreAPI; +import cn.hamster3.mc.plugin.core.common.config.YamlConfig; +import cn.hamster3.mc.plugin.core.common.util.JenkinsUtils; import lombok.Getter; import net.kyori.adventure.platform.bukkit.BukkitAudiences; import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryView; +import org.bukkit.plugin.Plugin; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitTask; import org.jetbrains.annotations.NotNull; import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.StandardCopyOption; import java.util.Objects; @@ -58,6 +67,38 @@ public class HamsterCorePlugin extends JavaPlugin { return Bukkit.getScheduler().runTaskAsynchronously(instance, runnable); } + public static void showUpdate(@NotNull CommandSender sender) { + HamsterCorePlugin.async(() -> { + for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) { + InputStream resource = plugin.getResource("jenkins.yml"); + if (resource == null) { + continue; + } + try (InputStreamReader reader = new InputStreamReader(resource, StandardCharsets.UTF_8)) { + YamlConfig jenkinsConfig = YamlConfig.load(reader); + String jobUrl = jenkinsConfig.getString("JOB_URL"); + if (jobUrl == null || jobUrl.equalsIgnoreCase("NONE")) { + continue; + } + String buildNumberString = jenkinsConfig.getString("BUILD_NUMBER"); + if (buildNumberString == null || buildNumberString.equalsIgnoreCase("NONE")) { + continue; + } + int lastStableBuild = JenkinsUtils.getLastStableBuild(jobUrl, null, null); + int buildNumber = Integer.parseInt(buildNumberString); + int version = lastStableBuild - buildNumber; + if (version <= 0) { + continue; + } + String pluginName = plugin.getName(); + sender.sendMessage(String.format("§a检测到服务器内安装的 %s 插件有 %d 个版本更新", pluginName, version)); + sender.sendMessage(String.format("§b下载链接: &b&n&l%s", jobUrl)); + } catch (IOException ignored) { + } + } + }); + } + @Override public void onLoad() { instance = this; @@ -107,10 +148,13 @@ public class HamsterCorePlugin extends JavaPlugin { logger.info("已注册 CallbackListener"); Bukkit.getPluginManager().registerEvents(DebugListener.INSTANCE, this); logger.info("已注册 DebugListener"); + Bukkit.getPluginManager().registerEvents(JenkinsUpdateListener.INSTANCE, this); + logger.info("已注册 JenkinsUpdateListener"); long time = System.currentTimeMillis() - start; sync(() -> { PointAPI.reloadPlayerPointAPIHook(); VaultAPI.reloadVaultHook(); + showUpdate(Bukkit.getConsoleSender()); }); logger.info("仓鼠核心启动完成,总计耗时 " + time + " ms"); } diff --git a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/listener/JenkinsUpdateListener.java b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/listener/JenkinsUpdateListener.java new file mode 100644 index 0000000..c1ec4e1 --- /dev/null +++ b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/listener/JenkinsUpdateListener.java @@ -0,0 +1,30 @@ +package cn.hamster3.mc.plugin.core.bukkit.listener; + +import cn.hamster3.mc.plugin.core.bukkit.HamsterCorePlugin; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; + +import java.util.HashSet; +import java.util.UUID; + +public class JenkinsUpdateListener implements Listener { + public static final JenkinsUpdateListener INSTANCE = new JenkinsUpdateListener(); + public static HashSet SHOWED = new HashSet<>(); + + private JenkinsUpdateListener() { + } + + @EventHandler(ignoreCancelled = true) + public void onPlayerJoin(PlayerJoinEvent event) { + Player player = event.getPlayer(); + if (!player.hasPermission("hamster.core.admin")) { + return; + } + if (!SHOWED.add(player.getUniqueId())) { + return; + } + HamsterCorePlugin.showUpdate(player); + } +} diff --git a/core-bungee/src/main/java/cn/hamster3/mc/plugin/core/bungee/HamsterCorePlugin.java b/core-bungee/src/main/java/cn/hamster3/mc/plugin/core/bungee/HamsterCorePlugin.java index e8b8c65..cbaa6e4 100644 --- a/core-bungee/src/main/java/cn/hamster3/mc/plugin/core/bungee/HamsterCorePlugin.java +++ b/core-bungee/src/main/java/cn/hamster3/mc/plugin/core/bungee/HamsterCorePlugin.java @@ -2,11 +2,21 @@ package cn.hamster3.mc.plugin.core.bungee; import cn.hamster3.mc.plugin.core.bungee.api.CoreBungeeAPI; import cn.hamster3.mc.plugin.core.common.api.CoreAPI; +import cn.hamster3.mc.plugin.core.common.config.YamlConfig; +import cn.hamster3.mc.plugin.core.common.util.JenkinsUtils; import lombok.Getter; import net.kyori.adventure.platform.bungeecord.BungeeAudiences; +import net.md_5.bungee.api.CommandSender; +import net.md_5.bungee.api.ProxyServer; +import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.plugin.Plugin; +import org.jetbrains.annotations.NotNull; import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.StandardCopyOption; import java.util.logging.Logger; @@ -56,6 +66,7 @@ public class HamsterCorePlugin extends Plugin { logger.info("已创建 AudienceProvider"); long time = System.currentTimeMillis() - start; logger.info("仓鼠核心启动完成,总计耗时 " + time + " ms"); + showUpdate(ProxyServer.getInstance().getConsole()); } @Override @@ -73,4 +84,40 @@ public class HamsterCorePlugin extends Plugin { long time = System.currentTimeMillis() - start; logger.info("仓鼠核心已关闭,总计耗时 " + time + " ms"); } + + private void showUpdate(@NotNull CommandSender sender) { + ProxyServer.getInstance().getScheduler().runAsync(HamsterCorePlugin.getInstance(), () -> { + for (Plugin plugin : ProxyServer.getInstance().getPluginManager().getPlugins()) { + InputStream resource = plugin.getResourceAsStream("jenkins.yml"); + if (resource == null) { + continue; + } + try (InputStreamReader reader = new InputStreamReader(resource, StandardCharsets.UTF_8)) { + YamlConfig jenkinsConfig = YamlConfig.load(reader); + String jobUrl = jenkinsConfig.getString("JOB_URL"); + if (jobUrl == null || jobUrl.equalsIgnoreCase("NONE")) { + continue; + } + String buildNumberString = jenkinsConfig.getString("BUILD_NUMBER"); + if (buildNumberString == null || buildNumberString.equalsIgnoreCase("NONE")) { + continue; + } + int lastStableBuild = JenkinsUtils.getLastStableBuild(jobUrl, null, null); + int buildNumber = Integer.parseInt(buildNumberString); + int version = lastStableBuild - buildNumber; + if (version <= 0) { + continue; + } + String pluginName = plugin.getDescription().getName(); + sender.sendMessage(TextComponent.fromLegacyText( + String.format("§a检测到服务器内安装的 %s 插件有 %d 个版本更新", pluginName, version) + )); + sender.sendMessage(TextComponent.fromLegacyText( + String.format("§b下载链接: &b&n&l%s", jobUrl) + )); + } catch (IOException ignored) { + } + } + }); + } } diff --git a/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/config/YamlConfig.java b/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/config/YamlConfig.java index 28d8311..a8724ab 100644 --- a/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/config/YamlConfig.java +++ b/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/config/YamlConfig.java @@ -7,7 +7,7 @@ import java.io.*; import java.nio.charset.StandardCharsets; import java.util.Map; -@SuppressWarnings("unused") +@SuppressWarnings({"unused", "VulnerableCodeUsages"}) public class YamlConfig extends ConfigSection { public static final Yaml YAML_LOADER = new Yaml(); @@ -22,12 +22,16 @@ public class YamlConfig extends ConfigSection { public static YamlConfig load(@NotNull File file) throws IOException { try (FileInputStream stream = new FileInputStream(file)) { try (InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) { - Map load = YAML_LOADER.load(reader); - return new YamlConfig(load); + return load(reader); } } } + public static YamlConfig load(@NotNull Reader reader) { + Map load = YAML_LOADER.load(reader); + return new YamlConfig(load); + } + public void save(@NotNull File file) throws IOException { try (FileOutputStream stream = new FileOutputStream(file)) { try (OutputStreamWriter writer = new OutputStreamWriter(stream, StandardCharsets.UTF_8)) { diff --git a/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/util/JenkinsUtils.java b/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/util/JenkinsUtils.java new file mode 100644 index 0000000..440a859 --- /dev/null +++ b/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/util/JenkinsUtils.java @@ -0,0 +1,41 @@ +package cn.hamster3.mc.plugin.core.common.util; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +public final class JenkinsUtils { + private static final JsonParser JSON_PARSER = new JsonParser(); + + private JenkinsUtils() { + } + + public static int getLastStableBuild(@NotNull String jobUrl, @Nullable String username, @Nullable String apiToken) throws IOException { + URL url = new URL(jobUrl + "api/json"); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setDoInput(true); + connection.setRequestMethod("GET"); + if (username != null && apiToken != null) { + String token = username + ":" + apiToken; + String base64 = Base64.getEncoder().encodeToString(token.getBytes(StandardCharsets.UTF_8)); + connection.setRequestProperty("Authorization", "Basic " + base64); + } + connection.connect(); + try (InputStream stream = connection.getInputStream()) { + try (InputStreamReader reader = new InputStreamReader(stream)) { + JsonObject object = JSON_PARSER.parse(reader).getAsJsonObject(); + JsonObject lastStableBuild = object.getAsJsonObject("lastStableBuild"); + return lastStableBuild.get("number").getAsInt(); + } + } + } +}