From 26bf4bfd97c868b6a666d1960094dec8384c6e99 Mon Sep 17 00:00:00 2001 From: Neu <38368299+Neuheit@users.noreply.github.com> Date: Mon, 9 Dec 2024 21:52:34 -0500 Subject: [PATCH 1/3] add plugin checker --- LavalinkServer/build.gradle.kts | 1 + .../server/bootstrap/PluginManager.kt | 33 +++++++++++++++++++ settings.gradle.kts | 1 + 3 files changed, 35 insertions(+) diff --git a/LavalinkServer/build.gradle.kts b/LavalinkServer/build.gradle.kts index ddb62b35a..c9eaea080 100644 --- a/LavalinkServer/build.gradle.kts +++ b/LavalinkServer/build.gradle.kts @@ -65,6 +65,7 @@ dependencies { implementation(libs.kotlin.reflect) implementation(libs.logback) implementation(libs.sentry.logback) + implementation(libs.semver) implementation(libs.oshi) { // This version of SLF4J does not recognise Logback 1.2.3 exclude(group = "org.slf4j", module = "slf4j-api") diff --git a/LavalinkServer/src/main/java/lavalink/server/bootstrap/PluginManager.kt b/LavalinkServer/src/main/java/lavalink/server/bootstrap/PluginManager.kt index c3ed4cb73..be432ae2d 100644 --- a/LavalinkServer/src/main/java/lavalink/server/bootstrap/PluginManager.kt +++ b/LavalinkServer/src/main/java/lavalink/server/bootstrap/PluginManager.kt @@ -9,9 +9,11 @@ import java.io.FileOutputStream import java.io.InputStream import java.net.URL import java.net.URLClassLoader +import java.net.HttpURLConnection import java.nio.channels.Channels import java.util.* import java.util.jar.JarFile +import io.github.z4kn4fein.semver.toVersion @SpringBootApplication class PluginManager(val config: PluginsConfig) { @@ -83,6 +85,37 @@ class PluginManager(val config: PluginsConfig) { val file = File(directory, declaration.canonicalJarName) downloadJar(file, url) } + + checkPluginForUpdates(declaration) + } + } + + private fun checkPluginForUpdates(declaration: Declaration) { + val splitPath = declaration.url.split('/') + + val baseSplitPath = splitPath.dropLast(2) + val basePath = baseSplitPath.joinToString("/") + "/maven-metadata.xml" + + val connection = URL(basePath).openConnection() as HttpURLConnection + connection.inputStream.bufferedReader().use { + val lines = it.readLines() + for (line in lines) { + val regex = "(.*?)".toRegex() + val match = regex.find(line) + val latest = match?.groups?.get(1)?.value + if (latest != null) { + val latestVersion = latest.toVersion() + val currentVersion = declaration.version.toVersion() + + if(latestVersion > currentVersion) { + log.warn("A newer version of ${declaration.name} was found: $latestVersion. " + + "The current version is $currentVersion.") + } else { + log.info("Plugin ${declaration.name} is up to date") + } + break + } + } } } diff --git a/settings.gradle.kts b/settings.gradle.kts index 14cbf4aa8..68eb7f315 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -76,6 +76,7 @@ fun VersionCatalogBuilder.common() { library("logback", "ch.qos.logback", "logback-classic").version("1.5.6") library("sentry-logback", "io.sentry", "sentry-logback").version("7.10.0") library("oshi", "com.github.oshi", "oshi-core").version("6.4.11") + library("semver", "io.github.z4kn4fein", "semver").version("2.0.0") } fun VersionCatalogBuilder.other() { From a7e27d145044a3c42315d12615385177bf576e7a Mon Sep 17 00:00:00 2001 From: Neu <38368299+Neuheit@users.noreply.github.com> Date: Wed, 25 Dec 2024 17:09:42 -0500 Subject: [PATCH 2/3] remove 3rd party plugin and make semver checks local --- LavalinkServer/build.gradle.kts | 1 - .../server/bootstrap/PluginManager.kt | 11 ++-- .../dev/arbjerg/lavalink/protocol/v4/info.kt | 64 +++++++++++++++++++ settings.gradle.kts | 1 - 4 files changed, 69 insertions(+), 8 deletions(-) diff --git a/LavalinkServer/build.gradle.kts b/LavalinkServer/build.gradle.kts index c9eaea080..ddb62b35a 100644 --- a/LavalinkServer/build.gradle.kts +++ b/LavalinkServer/build.gradle.kts @@ -65,7 +65,6 @@ dependencies { implementation(libs.kotlin.reflect) implementation(libs.logback) implementation(libs.sentry.logback) - implementation(libs.semver) implementation(libs.oshi) { // This version of SLF4J does not recognise Logback 1.2.3 exclude(group = "org.slf4j", module = "slf4j-api") diff --git a/LavalinkServer/src/main/java/lavalink/server/bootstrap/PluginManager.kt b/LavalinkServer/src/main/java/lavalink/server/bootstrap/PluginManager.kt index be432ae2d..7958c7e8e 100644 --- a/LavalinkServer/src/main/java/lavalink/server/bootstrap/PluginManager.kt +++ b/LavalinkServer/src/main/java/lavalink/server/bootstrap/PluginManager.kt @@ -13,7 +13,7 @@ import java.net.HttpURLConnection import java.nio.channels.Channels import java.util.* import java.util.jar.JarFile -import io.github.z4kn4fein.semver.toVersion +import dev.arbjerg.lavalink.protocol.v4.Version @SpringBootApplication class PluginManager(val config: PluginsConfig) { @@ -104,12 +104,11 @@ class PluginManager(val config: PluginsConfig) { val match = regex.find(line) val latest = match?.groups?.get(1)?.value if (latest != null) { - val latestVersion = latest.toVersion() - val currentVersion = declaration.version.toVersion() - + val latestVersion = Version.fromSemver(latest) + val currentVersion = Version.fromSemver(declaration.version) if(latestVersion > currentVersion) { - log.warn("A newer version of ${declaration.name} was found: $latestVersion. " + - "The current version is $currentVersion.") + log.warn("A newer version of ${declaration.name} was found: $latestVersion, " + + "The current version is $currentVersion") } else { log.info("Plugin ${declaration.name} is up to date") } diff --git a/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/info.kt b/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/info.kt index d739c53e3..2040c25cc 100644 --- a/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/info.kt +++ b/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/info.kt @@ -62,6 +62,70 @@ data class Version( return Version(semver, major.toInt(), minor.toInt(), patch.toInt(), preRelease) } } + + override fun toString(): String { + var baseSemver = "${major}.${minor}.${patch}" + + if(!preRelease.isNullOrEmpty()) + baseSemver += "-${preRelease}" + + return baseSemver + } + + operator fun compareTo(other: Version): Int { + // Compare major, minor, and patch + val majorDiff = major - other.major + if (majorDiff != 0) return majorDiff + + val minorDiff = minor - other.minor + if (minorDiff != 0) return minorDiff + + val patchDiff = patch - other.patch + if (patchDiff != 0) return patchDiff + + // Compare prerelease (null means no prerelease and is greater) + return when { + preRelease.isNullOrEmpty() && other.preRelease.isNullOrEmpty() -> 0 + preRelease.isNullOrEmpty() && !other.preRelease.isNullOrEmpty() -> 1 + !preRelease.isNullOrEmpty() && other.preRelease.isNullOrEmpty() -> -1 + !preRelease.isNullOrEmpty() && !other.preRelease.isNullOrEmpty() -> comparePreRelease(preRelease, other.preRelease) + else -> 0 + } + } + + private fun comparePreRelease(part1: String, part2: String): Int { + val components1 = part1.split(".") + val components2 = part2.split(".") + val maxLength = maxOf(components1.size, components2.size) + + for (i in 0 until maxLength) { + val comp1 = components1.getOrNull(i) + val comp2 = components2.getOrNull(i) + + if (comp1 == null) return -1 // `part1` is shorter and considered smaller + if (comp2 == null) return 1 // `part2` is shorter and considered smaller + + val isNumeric1 = comp1.all { it.isDigit() } + val isNumeric2 = comp2.all { it.isDigit() } + + when { + isNumeric1 && isNumeric2 -> { + // Compare numerically + val diff = comp1.toInt() - comp2.toInt() + if (diff != 0) return diff + } + isNumeric1 -> return -1 // Numeric parts come before string parts + isNumeric2 -> return 1 // String parts come after numeric parts + else -> { + // Compare lexicographically + val diff = comp1.compareTo(comp2) + if (diff != 0) return diff + } + } + } + + return 0 // Parts are equal + } } @Serializable diff --git a/settings.gradle.kts b/settings.gradle.kts index 68eb7f315..14cbf4aa8 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -76,7 +76,6 @@ fun VersionCatalogBuilder.common() { library("logback", "ch.qos.logback", "logback-classic").version("1.5.6") library("sentry-logback", "io.sentry", "sentry-logback").version("7.10.0") library("oshi", "com.github.oshi", "oshi-core").version("6.4.11") - library("semver", "io.github.z4kn4fein", "semver").version("2.0.0") } fun VersionCatalogBuilder.other() { From 1dfaddd9d5f59ee12ce825b6b4767dd9b267c32a Mon Sep 17 00:00:00 2001 From: Neu <38368299+Neuheit@users.noreply.github.com> Date: Wed, 25 Dec 2024 19:35:19 -0500 Subject: [PATCH 3/3] remove regex and use xml parsing --- .../server/bootstrap/PluginManager.kt | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/LavalinkServer/src/main/java/lavalink/server/bootstrap/PluginManager.kt b/LavalinkServer/src/main/java/lavalink/server/bootstrap/PluginManager.kt index 7958c7e8e..d6d138e8b 100644 --- a/LavalinkServer/src/main/java/lavalink/server/bootstrap/PluginManager.kt +++ b/LavalinkServer/src/main/java/lavalink/server/bootstrap/PluginManager.kt @@ -13,6 +13,7 @@ import java.net.HttpURLConnection import java.nio.channels.Channels import java.util.* import java.util.jar.JarFile +import javax.xml.parsers.DocumentBuilderFactory import dev.arbjerg.lavalink.protocol.v4.Version @SpringBootApplication @@ -95,25 +96,23 @@ class PluginManager(val config: PluginsConfig) { val baseSplitPath = splitPath.dropLast(2) val basePath = baseSplitPath.joinToString("/") + "/maven-metadata.xml" + val documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder() + val document = documentBuilder.parse(basePath) - val connection = URL(basePath).openConnection() as HttpURLConnection - connection.inputStream.bufferedReader().use { - val lines = it.readLines() - for (line in lines) { - val regex = "(.*?)".toRegex() - val match = regex.find(line) - val latest = match?.groups?.get(1)?.value - if (latest != null) { - val latestVersion = Version.fromSemver(latest) - val currentVersion = Version.fromSemver(declaration.version) - if(latestVersion > currentVersion) { - log.warn("A newer version of ${declaration.name} was found: $latestVersion, " + - "The current version is $currentVersion") - } else { - log.info("Plugin ${declaration.name} is up to date") - } - break - } + var elements = document.getElementsByTagName("latest") + if(elements.length == 0) { + elements = document.getElementsByTagName("release") + } + + if (elements.length > 0) { + val latest = elements.item(0).textContent + val latestVersion = Version.fromSemver(latest) + val currentVersion = Version.fromSemver(declaration.version) + if(latestVersion > currentVersion) { + log.warn("A newer version of ${declaration.name} was found: $latestVersion, " + + "The current version is $currentVersion") + } else { + log.info("Plugin ${declaration.name} is up to date") } } }