diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5064d4db..8a652310 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## v0.4.2 - Snapshot
+* Updated dependencies
+* Moving to jitpack
+
## v0.4.1 - Snapshot
* Added custom blossom injector dependency
* Updated dependencies
diff --git a/README.md b/README.md
index 7135a69f..f2bb8b06 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,9 @@
+[](https://jitci.com/gh/TheProgramSrc/SimpleCoreAPI)
+[](https://jitpack.io/#TheProgramSrc/SimpleCoreAPI)
+
# SimpleCoreAPI
_The best way to create a plugin_
-[](https://repo.theprogramsrc.xyz/#browse/browse:maven-releases)
-[](https://repo.theprogramsrc.xyz/#browse/browse:maven-snapshots)
+
[](https://go.theprogramsrc.xyz/discord)
[](https://go.theprogramsrc.xyz/tos)
diff --git a/build.gradle b/build.gradle
index 6f5edb61..db78c314 100644
--- a/build.gradle
+++ b/build.gradle
@@ -6,7 +6,7 @@ plugins {
id 'org.jetbrains.dokka' version '1.7.10'
}
-def projectVersion = (System.getenv("VERSION") ?: '0.4.1-SNAPSHOT').replaceFirst("v", "").replace('/', '')
+def projectVersion = (System.getenv("VERSION") ?: '0.4.2-SNAPSHOT').replaceFirst("v", "").replace('/', '')
group 'xyz.theprogramsrc'
version projectVersion
@@ -15,7 +15,6 @@ description 'The best way to create a plugin'
repositories {
mavenCentral()
- maven { url 'https://repo.theprogramsrc.xyz/repository/maven-public/' }
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
maven { url 'https://oss.sonatype.org/content/repositories/releases/' }
maven { url 'https://oss.sonatype.org/content/groups/public/' }
@@ -34,7 +33,7 @@ dependencies {
implementation 'org.jetbrains:annotations:23.0.0'
implementation 'commons-io:commons-io:2.11.0'
implementation 'com.google.code.gson:gson:2.9.1'
- implementation 'net.lingala.zip4j:zip4j:2.11.1'
+ implementation 'net.lingala.zip4j:zip4j:2.11.2'
annotationProcessor 'com.velocitypowered:velocity-api:3.1.1'
@@ -101,12 +100,6 @@ tasks.named("dokkaHtml") {
publishing {
repositories {
if(System.getenv('env') == 'prod') {
- maven {
- name = 'TheProgramSrc'
- credentials.username = System.getenv('NEXUS_USERNAME')
- credentials.password = System.getenv('NEXUS_PASSWORD')
- url = uri(version.contains('-SNAPSHOT') ? 'https://repo.theprogramsrc.xyz/repository/maven-snapshots/' : 'https://repo.theprogramsrc.xyz/repository/maven-releases/')
- }
maven {
name = 'GitHubPackages'
url = 'https://maven.pkg.github.com/TheProgramSrc/SimpleCoreAPI'
diff --git a/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/global/module/ModuleHelper.kt b/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/global/module/ModuleHelper.kt
index 17609be9..25dcec18 100644
--- a/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/global/module/ModuleHelper.kt
+++ b/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/global/module/ModuleHelper.kt
@@ -1,12 +1,11 @@
package xyz.theprogramsrc.simplecoreapi.global.module
+import com.google.gson.JsonObject
import com.google.gson.JsonParser
import java.io.BufferedReader
import java.io.File
import java.io.InputStreamReader
import java.net.URL
-import java.security.MessageDigest
-import java.util.*
import java.util.jar.JarFile
/**
@@ -14,51 +13,31 @@ import java.util.jar.JarFile
*/
object ModuleHelper {
+ private var lastRepoUpdate = 0L // Used to avoid timeouts
+
/**
* Downloads a Module from the database
- * @param repositoryId Identifier of the artifact inside the repository
+ * @param repository Repository of a module to download. (Must be in GitHub format 'User/Repository'. Example: 'TheProgramSrc/SimpleCore-UIsModule')
+ * @param fileName The name of the file. This can be fetched using the repository metadata.
* @param downloadLocation Location to download the module. (Defaults to plugins/SimpleCoreAPI/modules/)
* @return true if the module was downloaded, false otherwise
*/
- fun downloadModule(repositoryId: String, downloadLocation: File = File("plugins/SimpleCoreAPI/modules/")): Boolean{
+ fun downloadModule(repository: String, fileName: String, downloadLocation: File = File("plugins/SimpleCoreAPI/modules/")): Boolean{
if(!downloadLocation.exists()) downloadLocation.mkdirs()
- validateRepositories()
- val repo = (JsonParser.parseString(File("plugins/SimpleCoreAPI/repositories.json").readText()).asJsonArray.firstOrNull { element ->
- JsonParser.parseString(URL("https://${parseHost(element.asJsonObject.get("url").asString)}/service/rest/v1/search?repository=${element.asJsonObject.get("repo").asString}&format=maven2&maven.artifactId=$repositoryId&maven.extension=jar&sort=version").readText()).asJsonObject.get("items").asJsonArray.size() > 0
- } ?: return false).asJsonObject
- val artifact = ((JsonParser.parseString(URL("https://${parseHost(repo.get("url").asString)}/service/rest/v1/search/?repository=${repo.get("repo").asString}&format=maven2&maven.artifactId=$repositoryId&maven.extension=jar&sort=version").readText()).asJsonObject.get("items").asJsonArray.firstOrNull { it.asJsonObject.get("repository").asString.equals(repo.get("repo").asString) } ?: return false).asJsonObject.get("assets").asJsonArray.firstOrNull {
- if(!it.asJsonObject.get("maven2").asJsonObject.get("extension").asString.equals("jar")){
- return@firstOrNull false // Check that this is a jar file (not checksums or pom)
- }
-
- if(it.asJsonObject.get("maven2").asJsonObject.has("classifier")){
- if(it.asJsonObject.get("maven2").asJsonObject.get("classifier").asString.equals("sources")){
- return@firstOrNull false // Check that this is not a sources jar file
- }
-
- if(it.asJsonObject.get("maven2").asJsonObject.get("classifier").asString.equals("javadoc")){
- return@firstOrNull false // Check that this is not a javadoc jar file
- }
- }
-
- if(!it.asJsonObject.get("maven2").asJsonObject.get("artifactId").asString.equals(repositoryId)) {
- return@firstOrNull false // Check that this is the correct artifact
- }
-
- if(!it.asJsonObject.get("contentType").asString.equals("application/java-archive")){
- return@firstOrNull false // Check that this is a jar file
- }
-
- return@firstOrNull true
- } ?: return false).asJsonObject
- return artifact.get("downloadUrl").asString.let {
- val bytes = URL(it).readBytes()
- val sha512 = MessageDigest.getInstance("SHA-512").digest(bytes)
- val file = File(downloadLocation, "$repositoryId.jar")
- file.writeBytes(bytes)
- val fileSha512 = MessageDigest.getInstance("SHA-512").digest(file.readBytes())
- Arrays.equals(sha512, fileSha512)
+ val releases = JsonParser.parseString(URL("https://api.github.com/repos/$repository/releases").readText()).asJsonArray // Get the repo releases list
+ if(releases.isEmpty) // If empty stop
+ return false
+ val latestRelease = releases[0].asJsonObject
+ val assets = JsonParser.parseString(URL(latestRelease.get("assets_url").asString).readText()).asJsonArray // List all the available assets
+ if(assets.isEmpty)
+ return false
+ assets.find { it.asJsonObject.get("name").asString.endsWith(".jar") }?.asJsonObject?.get("browser_download_url")?.asString.let { // Find the first asset that's a .jar (Should be only one, but let's check just in case)
+ val bytes = URL(it).readBytes() // Read bytes
+ val file = File(downloadLocation, "$fileName.jar") // Create the file
+ if(!file.exists()) file.createNewFile()
+ file.writeBytes(bytes) // Overwrite the bytes with the new data
}
+ return true // At this point everything went well!
}
/**
@@ -87,26 +66,9 @@ object ModuleHelper {
}
/**
- * Ensures that the repositories are up-to-date
- */
- private fun validateRepositories(){
- val file = File("plugins/SimpleCoreAPI/repositories.json")
- val onlineBytes = URL("https://raw.githubusercontent.com/TheProgramSrc/PluginsResources/master/SimpleCoreAPI/repositories.json").readBytes()
- if(!file.exists()) file.createNewFile()
- file.writeBytes(onlineBytes) // Always overwrite the file
- }
-
- /**
- * Parses the host from a URL
- * @param url URL to parse
- * @return Host of the URL
- */
- private fun parseHost(url: String): String = if(url.startsWith("http")) url.split("://")[1].split("/")[0] else url.split("/")[0]
-
- /**
- * Scans the given folder for jar files and then scan
- * every jar file to download the required modules
- */
+ * Scans the given folder for jar files and then scan
+ * every jar file to download the required modules
+ */
fun scanRequiredModules(folder: File = File(".")): Unit = (folder.listFiles() ?: emptyArray()).forEach {
if(it.isDirectory) {
scanRequiredModules(it)
@@ -115,6 +77,35 @@ object ModuleHelper {
}
}
+ /**
+ * Updates the modules repository cache
+ */
+ fun updateRepository(){
+ // To allow the development of modules and testing we'll let devs provide the environment variable 'SCAPI_NO_REPO_UPDATE'
+ if(System.getenv("SCAPI_NO_REPO_UPDATE") != null)
+ return
+
+ val now = System.currentTimeMillis()
+ if(lastRepoUpdate == 0L || (lastRepoUpdate - now) > 30000L){
+ val file = File("plugins/SimpleCoreAPI/modules-repository.json")
+ val onlineBytes = URL("https://github.com/TheProgramSrc/GlobalDatabase/raw/master/SimpleCoreAPI/modules-repository.json").readBytes() // Get the online version
+ if(!file.exists()) file.createNewFile() // Create the file
+ file.writeBytes(onlineBytes) // Overwrite file
+ lastRepoUpdate = now // Update the update time
+ }
+ }
+
+ /**
+ * Gets the module metadata from the repository
+ * @param moduleId The id of the module to fetch the metadata
+ * @return the given module metadata if it's under the modules reposutory, otherwise null.
+ */
+ fun getModuleMeta(moduleId: String): JsonObject? {
+ updateRepository() // First we update the repo
+ val json = JsonParser.parseString(File("plugins/SimpleCoreAPI/modules-repository.json").readText()).asJsonObject
+ return if(json.has(moduleId)) json.getAsJsonObject(moduleId) else null
+ }
+
/**
* Scans the given [File] for the simplecoreapi.modules
* file and loads the required modules if any
@@ -122,17 +113,22 @@ object ModuleHelper {
* @param downloadLocation Location to download the modules. (Defaults to plugins/SimpleCoreAPI/modules/)
*/
fun downloadRequiredModules(file: File, downloadLocation: File = File("plugins/SimpleCoreAPI/modules/")){
+ updateRepository() // First we update the repository
if(file.extension != "jar") return
try {
- JarFile(file).use { jarFile ->
- val jarEntry = jarFile.getJarEntry("simplecoreapi.modules")
+ JarFile(file).use { jarFile -> // Now we check for every file
+ val jarEntry = jarFile.getJarEntry("simplecoreapi.modules") // If we find simplecoreapi.modules
if (jarEntry != null) {
- val inputStream = jarFile.getInputStream(jarEntry)
- val reader = BufferedReader(InputStreamReader(inputStream))
- reader.readLines().forEach {
- if(it.isNotBlank() && it.isNotEmpty() && !it.startsWith("#")) {
- if(!File(downloadLocation, "$it.jar").exists()){
- downloadModule(it)
+ val inputStream = jarFile.getInputStream(jarEntry) // Read the file
+ val reader = BufferedReader(InputStreamReader(inputStream)) // Create the reader
+ reader.readLines().forEach { // Read every line
+ if(it.isNotBlank() && it.isNotEmpty() && !it.startsWith("#")) { // Check that is not a blank line nor a comment
+ val meta = getModuleMeta(it) // Fetch the metadata
+ if(meta != null){
+ if(!File(downloadLocation, "${meta.get("file_name").asString}.jar").exists()){
+ val repo = if(meta.has("repository")) meta.get("repository").asString else "TheProgramSrc/SimpleCore-$it" // Generate default repo if not found
+ downloadModule(repo, meta.get("file_name").asString) // Download the module
+ }
}
}
}
diff --git a/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/global/module/ModuleManager.kt b/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/global/module/ModuleManager.kt
index fd2499fa..f2982334 100644
--- a/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/global/module/ModuleManager.kt
+++ b/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/global/module/ModuleManager.kt
@@ -133,11 +133,17 @@ class ModuleManager(private val logger: ILogger) {
val autoUpdate = config["auto-update"] == "true" // Check if we have enabled the auto updater
if(isAvailable && autoUpdate){ // Download an update if there is one available and the auto updater is enabled
logger.info("An update for the module ${description.name} is available. Downloading and updating...")
- if(ModuleHelper.downloadModule(description.repositoryId, File("plugins/SimpleCoreAPI/update/").apply { if(!exists()) mkdirs() })){
- logger.info("Successfully updated the module ${description.name}")
- updatedModules.add(description.name)
+ val meta = ModuleHelper.getModuleMeta(description.repositoryId)
+ if(meta == null) {
+ logger.error("Failed to update the module ${description.name}. Please download manually from ${if(description.githubRepository.isBlank()) "https://github.com/${description.githubRepository}/releases/latest" else " the module page."}")
} else {
- logger.error("Failed to update the module ${description.name}. Please download manually from https://github.com/${description.githubRepository}/releases/latest")
+ val repo = if(meta.has("repository")) meta.get("repository").asString else "TheProgramSrc/SimpleCore-${description.repositoryId}" // Generate default repo if not found
+ if(ModuleHelper.downloadModule(repo, meta.get("file_name").asString, File("plugins/SimpleCoreAPI/update/").apply { if(!exists()) mkdirs() })){
+ logger.info("Successfully updated the module ${description.name}")
+ updatedModules.add(description.name)
+ } else {
+ logger.error("Failed to update the module ${description.name}. Please download manually from https://github.com/${description.githubRepository}/releases/latest")
+ }
}
} else if(isAvailable){ // Notify the user that an update is available
checker.checkWithPrint()
@@ -171,7 +177,9 @@ class ModuleManager(private val logger: ILogger) {
// Loop through the dependencies and download the missing ones
val downloadedModules: MutableList = ArrayList()
for (dependencyId in dependencies.filter { it.isNotBlank() && !modules.any { entry -> entry.value.repositoryId == it } }) {
- if (ModuleHelper.downloadModule(dependencyId)) {
+ val meta = ModuleHelper.getModuleMeta(dependencyId) ?: throw ModuleDownloadException("Failed to download module with id '$dependencyId'")
+ val repo = if(meta.has("repository")) meta.get("repository").asString else "TheProgramSrc/SimpleCore-${dependencyId}" // Generate default repo if not found
+ if (ModuleHelper.downloadModule(repo, meta.get("file_name").asString)) {
downloadedModules.add(dependencyId)
} else {
throw ModuleDownloadException("Failed to download module with id '$dependencyId'")
diff --git a/src/test/kotlin/xyz/theprogramsrc/simplecoreapi/global/module/ModuleHelperTest.kt b/src/test/kotlin/xyz/theprogramsrc/simplecoreapi/global/module/ModuleHelperTest.kt
index c8abff19..ef15f9ff 100644
--- a/src/test/kotlin/xyz/theprogramsrc/simplecoreapi/global/module/ModuleHelperTest.kt
+++ b/src/test/kotlin/xyz/theprogramsrc/simplecoreapi/global/module/ModuleHelperTest.kt
@@ -9,7 +9,8 @@ internal class ModuleHelperTest {
@Test
fun downloadModule() {
- assertTrue(ModuleHelper.downloadModule("loggingmodule")) // Test the download
+ assertTrue(ModuleHelper.downloadModule("TheProgramSrc/SimpleCore-TasksModule", "TasksModule")) // Test the download
+ assertTrue(File("plugins/SimpleCoreAPI/modules/TasksModule.jar").exists())
File("plugins/").deleteRecursively() // Recursively delete the plugins folder
}