StatusAPI/src/main/java/net/viper/status/UpdateChecker.java aktualisiert
This commit is contained in:
@@ -1,9 +1,6 @@
|
|||||||
package net.viper.status;
|
package net.viper.status;
|
||||||
|
|
||||||
import net.md_5.bungee.api.plugin.Plugin;
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
|
||||||
import net.md_5.bungee.api.chat.TextComponent;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
@@ -13,31 +10,23 @@ import java.util.logging.Level;
|
|||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
public class UpdateChecker {
|
||||||
* UpdateChecker:
|
|
||||||
* - Fragt die Gitea Releases API ab
|
|
||||||
* - Sucht in den Releases nach dem Asset "StatusAPI.jar"
|
|
||||||
* - Extrahiert die Version (tag_name bevorzugt, name als Fallback)
|
|
||||||
* - Cache die gefundene Version + URL (volatile fields)
|
|
||||||
*/
|
|
||||||
public class UpdateChecker implements Runnable {
|
|
||||||
|
|
||||||
private final Plugin plugin;
|
private final Plugin plugin;
|
||||||
private final String currentVersion;
|
private final String currentVersion;
|
||||||
private final int intervalHours;
|
private final int intervalHours;
|
||||||
|
|
||||||
// Gitea Releases API für dein Repo
|
|
||||||
private final String apiUrl = "https://git.viper.ipv64.net/api/v1/repos/M_Viper/Minecraft-BungeeCord-Status/releases";
|
private final String apiUrl = "https://git.viper.ipv64.net/api/v1/repos/M_Viper/Minecraft-BungeeCord-Status/releases";
|
||||||
|
|
||||||
// cached results (volatile für Thread-Sichtbarkeit)
|
|
||||||
private volatile String latestVersion = "";
|
private volatile String latestVersion = "";
|
||||||
private volatile String latestUrl = "";
|
private volatile String latestUrl = "";
|
||||||
|
|
||||||
// Patterns for quick parse (we parse JSON as text; this is lightweight and robust for our needs)
|
// Pattern für Dateinamen im Assets-Array
|
||||||
private static final Pattern ASSET_NAME_PATTERN = Pattern.compile("\"name\"\\s*:\\s*\"([^\"]+)\"", Pattern.CASE_INSENSITIVE);
|
private static final Pattern ASSET_NAME_PATTERN = Pattern.compile("\"name\"\\s*:\\s*\"([^\"]+)\"", Pattern.CASE_INSENSITIVE);
|
||||||
|
// Pattern für Download-URL
|
||||||
private static final Pattern DOWNLOAD_PATTERN = Pattern.compile("\"browser_download_url\"\\s*:\\s*\"([^\"]+)\"", Pattern.CASE_INSENSITIVE);
|
private static final Pattern DOWNLOAD_PATTERN = Pattern.compile("\"browser_download_url\"\\s*:\\s*\"([^\"]+)\"", Pattern.CASE_INSENSITIVE);
|
||||||
|
// Pattern für Tag Version (WICHTIG: Wir suchen global, um das Haupt-Release zu finden)
|
||||||
private static final Pattern TAG_NAME_PATTERN = Pattern.compile("\"tag_name\"\\s*:\\s*\"([^\"]+)\"", Pattern.CASE_INSENSITIVE);
|
private static final Pattern TAG_NAME_PATTERN = Pattern.compile("\"tag_name\"\\s*:\\s*\"([^\"]+)\"", Pattern.CASE_INSENSITIVE);
|
||||||
private static final Pattern NAME_FIELD_PATTERN = Pattern.compile("\"name\"\\s*:\\s*\"([^\"]+)\"", Pattern.CASE_INSENSITIVE);
|
|
||||||
|
|
||||||
public UpdateChecker(Plugin plugin, String currentVersion, int intervalHours) {
|
public UpdateChecker(Plugin plugin, String currentVersion, int intervalHours) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
@@ -45,23 +34,12 @@ public class UpdateChecker implements Runnable {
|
|||||||
this.intervalHours = Math.max(1, intervalHours);
|
this.intervalHours = Math.max(1, intervalHours);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
// scheduled task calls checkNow
|
|
||||||
checkNow();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Führt einen sofortigen Check aus und updated cache (synchron for the calling thread).
|
|
||||||
*/
|
|
||||||
public void checkNow() {
|
public void checkNow() {
|
||||||
try {
|
try {
|
||||||
plugin.getLogger().info("Prüfe StatusAPI Releases via Gitea API...");
|
|
||||||
|
|
||||||
HttpURLConnection conn = (HttpURLConnection) new URL(apiUrl).openConnection();
|
HttpURLConnection conn = (HttpURLConnection) new URL(apiUrl).openConnection();
|
||||||
conn.setRequestMethod("GET");
|
conn.setRequestMethod("GET");
|
||||||
conn.setRequestProperty("Accept", "application/json");
|
conn.setRequestProperty("Accept", "application/json");
|
||||||
conn.setRequestProperty("User-Agent", "StatusAPI-UpdateChecker/1.0");
|
conn.setRequestProperty("User-Agent", "StatusAPI-UpdateChecker/2.0");
|
||||||
conn.setConnectTimeout(5000);
|
conn.setConnectTimeout(5000);
|
||||||
conn.setReadTimeout(5000);
|
conn.setReadTimeout(5000);
|
||||||
|
|
||||||
@@ -74,25 +52,37 @@ public class UpdateChecker implements Runnable {
|
|||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"))) {
|
try (BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"))) {
|
||||||
String line;
|
String line;
|
||||||
while ((line = br.readLine()) != null) {
|
while ((line = br.readLine()) != null) sb.append(line).append("\n");
|
||||||
sb.append(line).append("\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String body = sb.toString();
|
String body = sb.toString();
|
||||||
|
|
||||||
// Suche Release mit Asset "StatusAPI.jar"
|
// 1. Die LATEST Version (Tag) finden
|
||||||
|
// Wir suchen das erste "tag_name" im gesamten JSON, das ist meistens das neueste Release.
|
||||||
String foundVersion = null;
|
String foundVersion = null;
|
||||||
|
Matcher tagM = TAG_NAME_PATTERN.matcher(body);
|
||||||
|
if (tagM.find()) {
|
||||||
|
foundVersion = tagM.group(1).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foundVersion == null) {
|
||||||
|
plugin.getLogger().warning("Keine Version (Tag) im Release gefunden.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version säubern (v vorne entfernen)
|
||||||
|
if (foundVersion.startsWith("v") || foundVersion.startsWith("V")) {
|
||||||
|
foundVersion = foundVersion.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Download URL für StatusAPI.jar finden
|
||||||
|
// Wir suchen das Asset "StatusAPI.jar"
|
||||||
String foundUrl = null;
|
String foundUrl = null;
|
||||||
|
|
||||||
// Split releases by top-level objects: we simply find repeating {...} blocks and inspect them
|
|
||||||
// This is robust enough for Gitea JSON responses.
|
|
||||||
Pattern releasePattern = Pattern.compile("(?s)\\{.*?\\}");
|
Pattern releasePattern = Pattern.compile("(?s)\\{.*?\\}");
|
||||||
Matcher releaseMatcher = releasePattern.matcher(body);
|
Matcher releaseMatcher = releasePattern.matcher(body);
|
||||||
while (releaseMatcher.find()) {
|
while (releaseMatcher.find()) {
|
||||||
String block = releaseMatcher.group();
|
String block = releaseMatcher.group();
|
||||||
|
|
||||||
// extract asset names & download urls inside the block
|
|
||||||
java.util.List<String> names = new java.util.ArrayList<>();
|
java.util.List<String> names = new java.util.ArrayList<>();
|
||||||
java.util.List<String> downloads = new java.util.ArrayList<>();
|
java.util.List<String> downloads = new java.util.ArrayList<>();
|
||||||
|
|
||||||
@@ -107,37 +97,20 @@ public class UpdateChecker implements Runnable {
|
|||||||
String name = names.get(i);
|
String name = names.get(i);
|
||||||
String dl = downloads.get(i);
|
String dl = downloads.get(i);
|
||||||
if ("StatusAPI.jar".equalsIgnoreCase(name.trim())) {
|
if ("StatusAPI.jar".equalsIgnoreCase(name.trim())) {
|
||||||
// find tag_name or name field in the same block
|
|
||||||
Matcher tagM = TAG_NAME_PATTERN.matcher(block);
|
|
||||||
if (tagM.find()) {
|
|
||||||
foundVersion = tagM.group(1).trim();
|
|
||||||
} else {
|
|
||||||
Matcher nameFieldM = NAME_FIELD_PATTERN.matcher(block);
|
|
||||||
if (nameFieldM.find()) {
|
|
||||||
foundVersion = nameFieldM.group(1).trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foundUrl = dl;
|
foundUrl = dl;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (foundUrl != null) break;
|
if (foundUrl != null) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (foundVersion == null || foundUrl == null) {
|
if (foundUrl == null) {
|
||||||
plugin.getLogger().info("Kein Release mit Asset 'StatusAPI.jar' gefunden.");
|
plugin.getLogger().warning("Keine JAR-Datei für dieses Release gefunden.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normalize version
|
plugin.getLogger().info("Gefundene Version: " + foundVersion + " (Aktuell: " + currentVersion + ")");
|
||||||
if (foundVersion.startsWith("v") || foundVersion.startsWith("V")) {
|
|
||||||
foundVersion = foundVersion.substring(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
plugin.getLogger().info("Gefundene Version: " + foundVersion + " (aktuell: " + currentVersion + ")");
|
|
||||||
|
|
||||||
// set cache
|
|
||||||
latestVersion = foundVersion;
|
latestVersion = foundVersion;
|
||||||
latestUrl = foundUrl;
|
latestUrl = foundUrl;
|
||||||
|
|
||||||
@@ -146,32 +119,20 @@ public class UpdateChecker implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gibt die zuletzt gecachte Version (oder empty string).
|
|
||||||
*/
|
|
||||||
public String getLatestVersion() {
|
public String getLatestVersion() {
|
||||||
return latestVersion != null ? latestVersion : "";
|
return latestVersion != null ? latestVersion : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gibt die zuletzt gecachte download-URL (oder empty string).
|
|
||||||
*/
|
|
||||||
public String getLatestUrl() {
|
public String getLatestUrl() {
|
||||||
return latestUrl != null ? latestUrl : "";
|
return latestUrl != null ? latestUrl : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Prüft ob die gecachte latestVersion größer ist als übergebene version.
|
|
||||||
*/
|
|
||||||
public boolean isUpdateAvailable(String currentVer) {
|
public boolean isUpdateAvailable(String currentVer) {
|
||||||
String lv = getLatestVersion();
|
String lv = getLatestVersion();
|
||||||
if (lv.isEmpty()) return false;
|
if (lv.isEmpty()) return false;
|
||||||
return compareVersions(lv, currentVer) > 0;
|
return compareVersions(lv, currentVer) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Einfacher SemVer-Vergleich (1.2.3). Liefert >0 wenn a>b, 0 wenn gleich, <0 wenn a<b.
|
|
||||||
*/
|
|
||||||
private int compareVersions(String a, String b) {
|
private int compareVersions(String a, String b) {
|
||||||
try {
|
try {
|
||||||
String[] aa = a.split("\\.");
|
String[] aa = a.split("\\.");
|
||||||
@@ -187,25 +148,4 @@ public class UpdateChecker implements Runnable {
|
|||||||
return a.compareTo(b);
|
return a.compareTo(b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience: prüft cached state und falls update vorhanden, notifies online players with given permission(s).
|
|
||||||
*/
|
|
||||||
public void notifyOnlineOpsIfAvailable(String[] perms) {
|
|
||||||
String lv = getLatestVersion();
|
|
||||||
String url = getLatestUrl();
|
|
||||||
if (lv.isEmpty()) return;
|
|
||||||
|
|
||||||
for (ProxiedPlayer p : ProxyServer.getInstance().getPlayers()) {
|
|
||||||
try {
|
|
||||||
for (String perm : perms) {
|
|
||||||
if (p.hasPermission(perm)) {
|
|
||||||
p.sendMessage(new TextComponent("§6[StatusAPI] §eNeue Version verfügbar: §a" + lv));
|
|
||||||
p.sendMessage(new TextComponent("§eDownload: §b" + url));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception ignored) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user