feat: 自动检测 Jenkins 更新

This commit is contained in:
2024-03-17 00:08:50 +08:00
parent 401fb60cea
commit 0fd72513be
5 changed files with 169 additions and 3 deletions

View File

@@ -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.hook.VaultAPI;
import cn.hamster3.mc.plugin.core.bukkit.listener.CallbackListener; 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.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.handler.PageHandler;
import cn.hamster3.mc.plugin.core.bukkit.page.listener.PageListener; 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.bukkit.util.MinecraftVersion;
import cn.hamster3.mc.plugin.core.common.api.CoreAPI; 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 lombok.Getter;
import net.kyori.adventure.platform.bukkit.BukkitAudiences; import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryView; import org.bukkit.inventory.InventoryView;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitTask; import org.bukkit.scheduler.BukkitTask;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.io.File; 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.Files;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
import java.util.Objects; import java.util.Objects;
@@ -58,6 +67,38 @@ public class HamsterCorePlugin extends JavaPlugin {
return Bukkit.getScheduler().runTaskAsynchronously(instance, runnable); 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 @Override
public void onLoad() { public void onLoad() {
instance = this; instance = this;
@@ -107,10 +148,13 @@ public class HamsterCorePlugin extends JavaPlugin {
logger.info("已注册 CallbackListener"); logger.info("已注册 CallbackListener");
Bukkit.getPluginManager().registerEvents(DebugListener.INSTANCE, this); Bukkit.getPluginManager().registerEvents(DebugListener.INSTANCE, this);
logger.info("已注册 DebugListener"); logger.info("已注册 DebugListener");
Bukkit.getPluginManager().registerEvents(JenkinsUpdateListener.INSTANCE, this);
logger.info("已注册 JenkinsUpdateListener");
long time = System.currentTimeMillis() - start; long time = System.currentTimeMillis() - start;
sync(() -> { sync(() -> {
PointAPI.reloadPlayerPointAPIHook(); PointAPI.reloadPlayerPointAPIHook();
VaultAPI.reloadVaultHook(); VaultAPI.reloadVaultHook();
showUpdate(Bukkit.getConsoleSender());
}); });
logger.info("仓鼠核心启动完成,总计耗时 " + time + " ms"); logger.info("仓鼠核心启动完成,总计耗时 " + time + " ms");
} }

View File

@@ -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<UUID> 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);
}
}

View File

@@ -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.bungee.api.CoreBungeeAPI;
import cn.hamster3.mc.plugin.core.common.api.CoreAPI; 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 lombok.Getter;
import net.kyori.adventure.platform.bungeecord.BungeeAudiences; 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 net.md_5.bungee.api.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import java.io.File; 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.Files;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
import java.util.logging.Logger; import java.util.logging.Logger;
@@ -56,6 +66,7 @@ public class HamsterCorePlugin extends Plugin {
logger.info("已创建 AudienceProvider"); logger.info("已创建 AudienceProvider");
long time = System.currentTimeMillis() - start; long time = System.currentTimeMillis() - start;
logger.info("仓鼠核心启动完成,总计耗时 " + time + " ms"); logger.info("仓鼠核心启动完成,总计耗时 " + time + " ms");
showUpdate(ProxyServer.getInstance().getConsole());
} }
@Override @Override
@@ -73,4 +84,40 @@ public class HamsterCorePlugin extends Plugin {
long time = System.currentTimeMillis() - start; long time = System.currentTimeMillis() - start;
logger.info("仓鼠核心已关闭,总计耗时 " + time + " ms"); 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) {
}
}
});
}
} }

View File

@@ -7,7 +7,7 @@ import java.io.*;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Map; import java.util.Map;
@SuppressWarnings("unused") @SuppressWarnings({"unused", "VulnerableCodeUsages"})
public class YamlConfig extends ConfigSection { public class YamlConfig extends ConfigSection {
public static final Yaml YAML_LOADER = new Yaml(); 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 { public static YamlConfig load(@NotNull File file) throws IOException {
try (FileInputStream stream = new FileInputStream(file)) { try (FileInputStream stream = new FileInputStream(file)) {
try (InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) { try (InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) {
Map<String, Object> load = YAML_LOADER.load(reader); return load(reader);
return new YamlConfig(load);
} }
} }
} }
public static YamlConfig load(@NotNull Reader reader) {
Map<String, Object> load = YAML_LOADER.load(reader);
return new YamlConfig(load);
}
public void save(@NotNull File file) throws IOException { public void save(@NotNull File file) throws IOException {
try (FileOutputStream stream = new FileOutputStream(file)) { try (FileOutputStream stream = new FileOutputStream(file)) {
try (OutputStreamWriter writer = new OutputStreamWriter(stream, StandardCharsets.UTF_8)) { try (OutputStreamWriter writer = new OutputStreamWriter(stream, StandardCharsets.UTF_8)) {

View File

@@ -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();
}
}
}
}