From 0489e9a6dff604e2e10f1b2db1fa40b0c1348eb5 Mon Sep 17 00:00:00 2001 From: paulkczw <44299323+paulkczw@users.noreply.github.com> Date: Wed, 3 Jun 2026 19:17:29 +0200 Subject: [PATCH 1/8] refactor: merge database, packets, events, cache into core module --- .../api}/cache/IClusterCacheObject.kt | 2 +- cache/.gitignore | 42 ------------------- cache/build.gradle.kts | 13 ------ connectors/bukkit-connector/build.gradle.kts | 5 +-- .../bungeecord-connector/build.gradle.kts | 5 +-- .../minestom-connector/build.gradle.kts | 5 +-- .../velocity-connector/build.gradle.kts | 5 +-- {database => core}/build.gradle.kts | 3 +- .../dev/redicloud/cache/ClusterCache.kt | 1 + .../cache/packets/CacheMultiUpdatePacket.kt | 0 .../redicloud/cache/packets/CachePacket.kt | 2 +- .../cache/packets/CacheResetPacket.kt | 0 .../cache/packets/CacheUpdatePacket.kt | 0 .../redicloud/cache/tasks/InvalidCacheTask.kt | 0 .../redicloud/database/DatabaseConnection.kt | 0 .../dev/redicloud/database/codec/GsonCodec.kt | 0 .../communication/CommunicationChannel.kt | 0 .../database/config/DatabaseConfiguration.kt | 0 .../redicloud/database/config/DatabaseNode.kt | 0 .../database/grid/bucket/DataBucket.kt | 0 .../database/grid/list/SyncedList.kt | 0 .../database/grid/list/SyncedMutableList.kt | 0 .../database/grid/lock/SyncedLock.kt | 0 .../redicloud/database/grid/map/SyncedMap.kt | 0 .../database/grid/map/SyncedMutableMap.kt | 0 .../database/grid/map/cache/SyncedCacheMap.kt | 0 .../grid/map/cache/SyncedCacheMutableMap.kt | 0 .../repository/DatabaseBucketRepository.kt | 0 .../database/repository/DatabaseRepository.kt | 0 .../dev/redicloud/event/CloudEventPacket.kt | 0 .../dev/redicloud/event/EventHandlerMethod.kt | 0 .../dev/redicloud/event/EventManager.kt | 0 .../dev/redicloud/packets/PackedPacket.kt | 0 .../dev/redicloud/packets/PacketManager.kt | 0 .../dev/redicloud/packets/PacketResponse.kt | 0 events/build.gradle.kts | 19 --------- file-cluster/build.gradle.kts | 5 +-- .../dev/redicloud/cluster/file/FileNode.kt | 2 +- migrations/build.gradle.kts | 2 +- modules/module-handler/build.gradle.kts | 4 +- modules/papermc-updater/build.gradle.kts | 2 +- modules/reset-module/build.gradle.kts | 2 +- packets/build.gradle.kts | 18 -------- repositories/build.gradle.kts | 5 +-- .../java/version/CloudJavaVersion.kt | 2 +- .../redicloud/repository/node/CloudNode.kt | 2 +- .../repository/player/CloudPlayer.kt | 2 +- .../server/version/CloudServerVersion.kt | 2 +- .../server/version/CloudServerVersionType.kt | 2 +- .../repository/service/CloudService.kt | 2 +- .../configuration/ConfigurationTemplate.kt | 2 +- .../repository/template/file/FileTemplate.kt | 2 +- .../node-server-factory/build.gradle.kts | 5 +-- .../remote-server-factory/build.gradle.kts | 5 +-- services/base-service/build.gradle.kts | 5 +-- .../minecraft-server-service/build.gradle.kts | 5 +-- services/node-service/build.gradle.kts | 5 +-- .../proxy-server-service/build.gradle.kts | 5 +-- settings.gradle.kts | 5 +-- 59 files changed, 31 insertions(+), 162 deletions(-) rename {cache/src/main/kotlin/dev/redicloud => apis/base-api/src/main/kotlin/dev/redicloud/api}/cache/IClusterCacheObject.kt (70%) delete mode 100644 cache/.gitignore delete mode 100644 cache/build.gradle.kts rename {database => core}/build.gradle.kts (88%) rename {cache => core}/src/main/kotlin/dev/redicloud/cache/ClusterCache.kt (98%) rename {cache => core}/src/main/kotlin/dev/redicloud/cache/packets/CacheMultiUpdatePacket.kt (100%) rename {cache => core}/src/main/kotlin/dev/redicloud/cache/packets/CachePacket.kt (91%) rename {cache => core}/src/main/kotlin/dev/redicloud/cache/packets/CacheResetPacket.kt (100%) rename {cache => core}/src/main/kotlin/dev/redicloud/cache/packets/CacheUpdatePacket.kt (100%) rename {cache => core}/src/main/kotlin/dev/redicloud/cache/tasks/InvalidCacheTask.kt (100%) rename {database => core}/src/main/kotlin/dev/redicloud/database/DatabaseConnection.kt (100%) rename {database => core}/src/main/kotlin/dev/redicloud/database/codec/GsonCodec.kt (100%) rename {database => core}/src/main/kotlin/dev/redicloud/database/communication/CommunicationChannel.kt (100%) rename {database => core}/src/main/kotlin/dev/redicloud/database/config/DatabaseConfiguration.kt (100%) rename {database => core}/src/main/kotlin/dev/redicloud/database/config/DatabaseNode.kt (100%) rename {database => core}/src/main/kotlin/dev/redicloud/database/grid/bucket/DataBucket.kt (100%) rename {database => core}/src/main/kotlin/dev/redicloud/database/grid/list/SyncedList.kt (100%) rename {database => core}/src/main/kotlin/dev/redicloud/database/grid/list/SyncedMutableList.kt (100%) rename {database => core}/src/main/kotlin/dev/redicloud/database/grid/lock/SyncedLock.kt (100%) rename {database => core}/src/main/kotlin/dev/redicloud/database/grid/map/SyncedMap.kt (100%) rename {database => core}/src/main/kotlin/dev/redicloud/database/grid/map/SyncedMutableMap.kt (100%) rename {database => core}/src/main/kotlin/dev/redicloud/database/grid/map/cache/SyncedCacheMap.kt (100%) rename {database => core}/src/main/kotlin/dev/redicloud/database/grid/map/cache/SyncedCacheMutableMap.kt (100%) rename {database => core}/src/main/kotlin/dev/redicloud/database/repository/DatabaseBucketRepository.kt (100%) rename {database => core}/src/main/kotlin/dev/redicloud/database/repository/DatabaseRepository.kt (100%) rename {events => core}/src/main/kotlin/dev/redicloud/event/CloudEventPacket.kt (100%) rename {events => core}/src/main/kotlin/dev/redicloud/event/EventHandlerMethod.kt (100%) rename {events => core}/src/main/kotlin/dev/redicloud/event/EventManager.kt (100%) rename {packets => core}/src/main/kotlin/dev/redicloud/packets/PackedPacket.kt (100%) rename {packets => core}/src/main/kotlin/dev/redicloud/packets/PacketManager.kt (100%) rename {packets => core}/src/main/kotlin/dev/redicloud/packets/PacketResponse.kt (100%) delete mode 100644 events/build.gradle.kts delete mode 100644 packets/build.gradle.kts diff --git a/cache/src/main/kotlin/dev/redicloud/cache/IClusterCacheObject.kt b/apis/base-api/src/main/kotlin/dev/redicloud/api/cache/IClusterCacheObject.kt similarity index 70% rename from cache/src/main/kotlin/dev/redicloud/cache/IClusterCacheObject.kt rename to apis/base-api/src/main/kotlin/dev/redicloud/api/cache/IClusterCacheObject.kt index e1bf7e3f..3381e26e 100644 --- a/cache/src/main/kotlin/dev/redicloud/cache/IClusterCacheObject.kt +++ b/apis/base-api/src/main/kotlin/dev/redicloud/api/cache/IClusterCacheObject.kt @@ -1,4 +1,4 @@ -package dev.redicloud.cache +package dev.redicloud.api.cache import java.io.Serializable diff --git a/cache/.gitignore b/cache/.gitignore deleted file mode 100644 index b63da455..00000000 --- a/cache/.gitignore +++ /dev/null @@ -1,42 +0,0 @@ -.gradle -build/ -!gradle/wrapper/gradle-wrapper.jar -!**/src/main/**/build/ -!**/src/test/**/build/ - -### IntelliJ IDEA ### -.idea/modules.xml -.idea/jarRepositories.xml -.idea/compiler.xml -.idea/libraries/ -*.iws -*.iml -*.ipr -out/ -!**/src/main/**/out/ -!**/src/test/**/out/ - -### Eclipse ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache -bin/ -!**/src/main/**/bin/ -!**/src/test/**/bin/ - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ - -### VS Code ### -.vscode/ - -### Mac OS ### -.DS_Store \ No newline at end of file diff --git a/cache/build.gradle.kts b/cache/build.gradle.kts deleted file mode 100644 index d81fe718..00000000 --- a/cache/build.gradle.kts +++ /dev/null @@ -1,13 +0,0 @@ -plugins { - id("redicloud-conventions") -} - -group = "dev.redicloud" - -dependencies { - compileOnly(project(":apis:base-api")) - compileOnly(project(":logging")) - compileOnly(project(":database")) - compileOnly(project(":utils")) - compileOnly(project(":tasks")) -} \ No newline at end of file diff --git a/connectors/bukkit-connector/build.gradle.kts b/connectors/bukkit-connector/build.gradle.kts index bbd243fe..cc2ccfd1 100644 --- a/connectors/bukkit-connector/build.gradle.kts +++ b/connectors/bukkit-connector/build.gradle.kts @@ -14,15 +14,12 @@ repositories { } dependencies { - shade(project(":cache")) + shade(project(":core")) shade(project(":apis:base-api")) shade(project(":services:base-service")) shade(project(":services:minecraft-server-service")) shade(project(":repositories")) - shade(project(":database")) shade(project(":utils")) - shade(project(":events")) - shade(project(":packets")) shade(project(":commands:command-api")) shade(project(":logging")) shade(project(":console")) diff --git a/connectors/bungeecord-connector/build.gradle.kts b/connectors/bungeecord-connector/build.gradle.kts index f29969d9..4f850b66 100644 --- a/connectors/bungeecord-connector/build.gradle.kts +++ b/connectors/bungeecord-connector/build.gradle.kts @@ -10,16 +10,13 @@ repositories { } dependencies { - shade(project(":cache")) + shade(project(":core")) shade(project(":apis:base-api")) shade(project(":services:base-service")) shade(project(":services:minecraft-server-service")) shade(project(":services:proxy-server-service")) shade(project(":repositories")) - shade(project(":database")) shade(project(":utils")) - shade(project(":events")) - shade(project(":packets")) shade(project(":commands:command-api")) shade(project(":logging")) shade(project(":console")) diff --git a/connectors/minestom-connector/build.gradle.kts b/connectors/minestom-connector/build.gradle.kts index 2e4e0ee5..f31dadc8 100644 --- a/connectors/minestom-connector/build.gradle.kts +++ b/connectors/minestom-connector/build.gradle.kts @@ -5,16 +5,13 @@ plugins { group = "dev.redicloud.connector" dependencies { - shade(project(":cache")) + shade(project(":core")) shade(project(":apis:base-api")) shade(project(":services:base-service")) shade(project(":services:minecraft-server-service")) shade(project(":services:proxy-server-service")) shade(project(":repositories")) - shade(project(":database")) shade(project(":utils")) - shade(project(":events")) - shade(project(":packets")) shade(project(":commands:command-api")) shade(project(":logging")) shade(project(":console")) diff --git a/connectors/velocity-connector/build.gradle.kts b/connectors/velocity-connector/build.gradle.kts index f4fb51c6..aa9b68af 100644 --- a/connectors/velocity-connector/build.gradle.kts +++ b/connectors/velocity-connector/build.gradle.kts @@ -37,15 +37,12 @@ repositories { dependencies { shade(project(":apis:base-api")) - shade(project(":cache")) + shade(project(":core")) shade(project(":services:base-service")) shade(project(":services:minecraft-server-service")) shade(project(":services:proxy-server-service")) shade(project(":repositories")) - shade(project(":database")) shade(project(":utils")) - shade(project(":events")) - shade(project(":packets")) shade(project(":commands:command-api")) shade(project(":logging")) shade(project(":console")) diff --git a/database/build.gradle.kts b/core/build.gradle.kts similarity index 88% rename from database/build.gradle.kts rename to core/build.gradle.kts index cc8d02bb..5846bde0 100644 --- a/database/build.gradle.kts +++ b/core/build.gradle.kts @@ -16,4 +16,5 @@ dependencies { dependency(libs.redisson) dependency(libs.gson) -} \ No newline at end of file + dependency(libs.kotlinx.coroutines) +} diff --git a/cache/src/main/kotlin/dev/redicloud/cache/ClusterCache.kt b/core/src/main/kotlin/dev/redicloud/cache/ClusterCache.kt similarity index 98% rename from cache/src/main/kotlin/dev/redicloud/cache/ClusterCache.kt rename to core/src/main/kotlin/dev/redicloud/cache/ClusterCache.kt index e1ea1e68..446f098d 100644 --- a/cache/src/main/kotlin/dev/redicloud/cache/ClusterCache.kt +++ b/core/src/main/kotlin/dev/redicloud/cache/ClusterCache.kt @@ -1,5 +1,6 @@ package dev.redicloud.cache +import dev.redicloud.api.cache.IClusterCacheObject import dev.redicloud.api.packets.IPacketManager import dev.redicloud.api.service.ServiceId import dev.redicloud.api.service.ServiceType diff --git a/cache/src/main/kotlin/dev/redicloud/cache/packets/CacheMultiUpdatePacket.kt b/core/src/main/kotlin/dev/redicloud/cache/packets/CacheMultiUpdatePacket.kt similarity index 100% rename from cache/src/main/kotlin/dev/redicloud/cache/packets/CacheMultiUpdatePacket.kt rename to core/src/main/kotlin/dev/redicloud/cache/packets/CacheMultiUpdatePacket.kt diff --git a/cache/src/main/kotlin/dev/redicloud/cache/packets/CachePacket.kt b/core/src/main/kotlin/dev/redicloud/cache/packets/CachePacket.kt similarity index 91% rename from cache/src/main/kotlin/dev/redicloud/cache/packets/CachePacket.kt rename to core/src/main/kotlin/dev/redicloud/cache/packets/CachePacket.kt index 300aa81f..ad20c279 100644 --- a/cache/src/main/kotlin/dev/redicloud/cache/packets/CachePacket.kt +++ b/core/src/main/kotlin/dev/redicloud/cache/packets/CachePacket.kt @@ -1,10 +1,10 @@ package dev.redicloud.cache.packets import com.google.gson.annotations.Expose +import dev.redicloud.api.cache.IClusterCacheObject import dev.redicloud.api.packets.AbstractPacket import dev.redicloud.api.packets.IPacketManager import dev.redicloud.cache.ClusterCache -import dev.redicloud.cache.IClusterCacheObject abstract class CachePacket( val cacheName: String diff --git a/cache/src/main/kotlin/dev/redicloud/cache/packets/CacheResetPacket.kt b/core/src/main/kotlin/dev/redicloud/cache/packets/CacheResetPacket.kt similarity index 100% rename from cache/src/main/kotlin/dev/redicloud/cache/packets/CacheResetPacket.kt rename to core/src/main/kotlin/dev/redicloud/cache/packets/CacheResetPacket.kt diff --git a/cache/src/main/kotlin/dev/redicloud/cache/packets/CacheUpdatePacket.kt b/core/src/main/kotlin/dev/redicloud/cache/packets/CacheUpdatePacket.kt similarity index 100% rename from cache/src/main/kotlin/dev/redicloud/cache/packets/CacheUpdatePacket.kt rename to core/src/main/kotlin/dev/redicloud/cache/packets/CacheUpdatePacket.kt diff --git a/cache/src/main/kotlin/dev/redicloud/cache/tasks/InvalidCacheTask.kt b/core/src/main/kotlin/dev/redicloud/cache/tasks/InvalidCacheTask.kt similarity index 100% rename from cache/src/main/kotlin/dev/redicloud/cache/tasks/InvalidCacheTask.kt rename to core/src/main/kotlin/dev/redicloud/cache/tasks/InvalidCacheTask.kt diff --git a/database/src/main/kotlin/dev/redicloud/database/DatabaseConnection.kt b/core/src/main/kotlin/dev/redicloud/database/DatabaseConnection.kt similarity index 100% rename from database/src/main/kotlin/dev/redicloud/database/DatabaseConnection.kt rename to core/src/main/kotlin/dev/redicloud/database/DatabaseConnection.kt diff --git a/database/src/main/kotlin/dev/redicloud/database/codec/GsonCodec.kt b/core/src/main/kotlin/dev/redicloud/database/codec/GsonCodec.kt similarity index 100% rename from database/src/main/kotlin/dev/redicloud/database/codec/GsonCodec.kt rename to core/src/main/kotlin/dev/redicloud/database/codec/GsonCodec.kt diff --git a/database/src/main/kotlin/dev/redicloud/database/communication/CommunicationChannel.kt b/core/src/main/kotlin/dev/redicloud/database/communication/CommunicationChannel.kt similarity index 100% rename from database/src/main/kotlin/dev/redicloud/database/communication/CommunicationChannel.kt rename to core/src/main/kotlin/dev/redicloud/database/communication/CommunicationChannel.kt diff --git a/database/src/main/kotlin/dev/redicloud/database/config/DatabaseConfiguration.kt b/core/src/main/kotlin/dev/redicloud/database/config/DatabaseConfiguration.kt similarity index 100% rename from database/src/main/kotlin/dev/redicloud/database/config/DatabaseConfiguration.kt rename to core/src/main/kotlin/dev/redicloud/database/config/DatabaseConfiguration.kt diff --git a/database/src/main/kotlin/dev/redicloud/database/config/DatabaseNode.kt b/core/src/main/kotlin/dev/redicloud/database/config/DatabaseNode.kt similarity index 100% rename from database/src/main/kotlin/dev/redicloud/database/config/DatabaseNode.kt rename to core/src/main/kotlin/dev/redicloud/database/config/DatabaseNode.kt diff --git a/database/src/main/kotlin/dev/redicloud/database/grid/bucket/DataBucket.kt b/core/src/main/kotlin/dev/redicloud/database/grid/bucket/DataBucket.kt similarity index 100% rename from database/src/main/kotlin/dev/redicloud/database/grid/bucket/DataBucket.kt rename to core/src/main/kotlin/dev/redicloud/database/grid/bucket/DataBucket.kt diff --git a/database/src/main/kotlin/dev/redicloud/database/grid/list/SyncedList.kt b/core/src/main/kotlin/dev/redicloud/database/grid/list/SyncedList.kt similarity index 100% rename from database/src/main/kotlin/dev/redicloud/database/grid/list/SyncedList.kt rename to core/src/main/kotlin/dev/redicloud/database/grid/list/SyncedList.kt diff --git a/database/src/main/kotlin/dev/redicloud/database/grid/list/SyncedMutableList.kt b/core/src/main/kotlin/dev/redicloud/database/grid/list/SyncedMutableList.kt similarity index 100% rename from database/src/main/kotlin/dev/redicloud/database/grid/list/SyncedMutableList.kt rename to core/src/main/kotlin/dev/redicloud/database/grid/list/SyncedMutableList.kt diff --git a/database/src/main/kotlin/dev/redicloud/database/grid/lock/SyncedLock.kt b/core/src/main/kotlin/dev/redicloud/database/grid/lock/SyncedLock.kt similarity index 100% rename from database/src/main/kotlin/dev/redicloud/database/grid/lock/SyncedLock.kt rename to core/src/main/kotlin/dev/redicloud/database/grid/lock/SyncedLock.kt diff --git a/database/src/main/kotlin/dev/redicloud/database/grid/map/SyncedMap.kt b/core/src/main/kotlin/dev/redicloud/database/grid/map/SyncedMap.kt similarity index 100% rename from database/src/main/kotlin/dev/redicloud/database/grid/map/SyncedMap.kt rename to core/src/main/kotlin/dev/redicloud/database/grid/map/SyncedMap.kt diff --git a/database/src/main/kotlin/dev/redicloud/database/grid/map/SyncedMutableMap.kt b/core/src/main/kotlin/dev/redicloud/database/grid/map/SyncedMutableMap.kt similarity index 100% rename from database/src/main/kotlin/dev/redicloud/database/grid/map/SyncedMutableMap.kt rename to core/src/main/kotlin/dev/redicloud/database/grid/map/SyncedMutableMap.kt diff --git a/database/src/main/kotlin/dev/redicloud/database/grid/map/cache/SyncedCacheMap.kt b/core/src/main/kotlin/dev/redicloud/database/grid/map/cache/SyncedCacheMap.kt similarity index 100% rename from database/src/main/kotlin/dev/redicloud/database/grid/map/cache/SyncedCacheMap.kt rename to core/src/main/kotlin/dev/redicloud/database/grid/map/cache/SyncedCacheMap.kt diff --git a/database/src/main/kotlin/dev/redicloud/database/grid/map/cache/SyncedCacheMutableMap.kt b/core/src/main/kotlin/dev/redicloud/database/grid/map/cache/SyncedCacheMutableMap.kt similarity index 100% rename from database/src/main/kotlin/dev/redicloud/database/grid/map/cache/SyncedCacheMutableMap.kt rename to core/src/main/kotlin/dev/redicloud/database/grid/map/cache/SyncedCacheMutableMap.kt diff --git a/database/src/main/kotlin/dev/redicloud/database/repository/DatabaseBucketRepository.kt b/core/src/main/kotlin/dev/redicloud/database/repository/DatabaseBucketRepository.kt similarity index 100% rename from database/src/main/kotlin/dev/redicloud/database/repository/DatabaseBucketRepository.kt rename to core/src/main/kotlin/dev/redicloud/database/repository/DatabaseBucketRepository.kt diff --git a/database/src/main/kotlin/dev/redicloud/database/repository/DatabaseRepository.kt b/core/src/main/kotlin/dev/redicloud/database/repository/DatabaseRepository.kt similarity index 100% rename from database/src/main/kotlin/dev/redicloud/database/repository/DatabaseRepository.kt rename to core/src/main/kotlin/dev/redicloud/database/repository/DatabaseRepository.kt diff --git a/events/src/main/kotlin/dev/redicloud/event/CloudEventPacket.kt b/core/src/main/kotlin/dev/redicloud/event/CloudEventPacket.kt similarity index 100% rename from events/src/main/kotlin/dev/redicloud/event/CloudEventPacket.kt rename to core/src/main/kotlin/dev/redicloud/event/CloudEventPacket.kt diff --git a/events/src/main/kotlin/dev/redicloud/event/EventHandlerMethod.kt b/core/src/main/kotlin/dev/redicloud/event/EventHandlerMethod.kt similarity index 100% rename from events/src/main/kotlin/dev/redicloud/event/EventHandlerMethod.kt rename to core/src/main/kotlin/dev/redicloud/event/EventHandlerMethod.kt diff --git a/events/src/main/kotlin/dev/redicloud/event/EventManager.kt b/core/src/main/kotlin/dev/redicloud/event/EventManager.kt similarity index 100% rename from events/src/main/kotlin/dev/redicloud/event/EventManager.kt rename to core/src/main/kotlin/dev/redicloud/event/EventManager.kt diff --git a/packets/src/main/kotlin/dev/redicloud/packets/PackedPacket.kt b/core/src/main/kotlin/dev/redicloud/packets/PackedPacket.kt similarity index 100% rename from packets/src/main/kotlin/dev/redicloud/packets/PackedPacket.kt rename to core/src/main/kotlin/dev/redicloud/packets/PackedPacket.kt diff --git a/packets/src/main/kotlin/dev/redicloud/packets/PacketManager.kt b/core/src/main/kotlin/dev/redicloud/packets/PacketManager.kt similarity index 100% rename from packets/src/main/kotlin/dev/redicloud/packets/PacketManager.kt rename to core/src/main/kotlin/dev/redicloud/packets/PacketManager.kt diff --git a/packets/src/main/kotlin/dev/redicloud/packets/PacketResponse.kt b/core/src/main/kotlin/dev/redicloud/packets/PacketResponse.kt similarity index 100% rename from packets/src/main/kotlin/dev/redicloud/packets/PacketResponse.kt rename to core/src/main/kotlin/dev/redicloud/packets/PacketResponse.kt diff --git a/events/build.gradle.kts b/events/build.gradle.kts deleted file mode 100644 index 0afde937..00000000 --- a/events/build.gradle.kts +++ /dev/null @@ -1,19 +0,0 @@ -plugins { - id("redicloud-conventions") -} - -group = "dev.redicloud" - -repositories { - mavenCentral() -} - -dependencies { - compileOnly(project(":apis:base-api")) - compileOnly(project(":utils")) - compileOnly(project(":packets")) - compileOnly(project(":logging")) - - dependency(libs.kotlinx.coroutines) - dependency(libs.gson) -} \ No newline at end of file diff --git a/file-cluster/build.gradle.kts b/file-cluster/build.gradle.kts index 00ab0883..fde2a1ae 100644 --- a/file-cluster/build.gradle.kts +++ b/file-cluster/build.gradle.kts @@ -8,11 +8,8 @@ dependencies { compileOnly(project(":utils")) compileOnly(project(":apis:base-api")) compileOnly(project(":logging")) - compileOnly(project(":events")) + compileOnly(project(":core")) compileOnly(project(":services:base-service")) - compileOnly(project(":database")) - compileOnly(project(":packets")) - compileOnly(project(":cache")) compileOnly(project(":repositories")) dependency(libs.sshd) diff --git a/file-cluster/src/main/kotlin/dev/redicloud/cluster/file/FileNode.kt b/file-cluster/src/main/kotlin/dev/redicloud/cluster/file/FileNode.kt index 22b1529b..24faf492 100644 --- a/file-cluster/src/main/kotlin/dev/redicloud/cluster/file/FileNode.kt +++ b/file-cluster/src/main/kotlin/dev/redicloud/cluster/file/FileNode.kt @@ -1,8 +1,8 @@ package dev.redicloud.cluster.file +import dev.redicloud.api.cache.IClusterCacheObject import dev.redicloud.api.service.ServiceId import dev.redicloud.api.service.file.IFileNode -import dev.redicloud.cache.IClusterCacheObject import dev.redicloud.repository.service.CloudService import dev.redicloud.repository.service.ServiceSessions diff --git a/migrations/build.gradle.kts b/migrations/build.gradle.kts index d64dac2e..8d6a400c 100644 --- a/migrations/build.gradle.kts +++ b/migrations/build.gradle.kts @@ -10,7 +10,7 @@ repositories { dependencies { compileOnly(project(":apis:base-api")) - compileOnly(project(":database")) + compileOnly(project(":core")) compileOnly(project(":utils")) compileOnly(project(":logging")) diff --git a/modules/module-handler/build.gradle.kts b/modules/module-handler/build.gradle.kts index d9c69f7f..7a0de984 100644 --- a/modules/module-handler/build.gradle.kts +++ b/modules/module-handler/build.gradle.kts @@ -12,9 +12,7 @@ dependencies { compileOnly(project(":apis:base-api")) compileOnly(project(":utils")) compileOnly(project(":logging")) - compileOnly(project(":events")) - compileOnly(project(":packets")) + compileOnly(project(":core")) compileOnly(project(":commands:command-api")) - compileOnly(project(":database")) compileOnly(libs.kotlin.reflect) } \ No newline at end of file diff --git a/modules/papermc-updater/build.gradle.kts b/modules/papermc-updater/build.gradle.kts index 829d4ca9..470e96f6 100644 --- a/modules/papermc-updater/build.gradle.kts +++ b/modules/papermc-updater/build.gradle.kts @@ -19,7 +19,7 @@ dependencies { testImplementation(kotlin("test")) testImplementation(project(":repositories")) testImplementation(project(":apis:base-api")) - testImplementation(project(":cache")) + testImplementation(project(":core")) testImplementation(project(":utils")) testImplementation(project(":logging")) testImplementation(libs.kotlinx.coroutines) diff --git a/modules/reset-module/build.gradle.kts b/modules/reset-module/build.gradle.kts index d6e983b0..e86f13b1 100644 --- a/modules/reset-module/build.gradle.kts +++ b/modules/reset-module/build.gradle.kts @@ -9,7 +9,7 @@ dependencies { compileOnly(project(":console")) compileOnly(project(":logging")) compileOnly(project(":utils")) - compileOnly(project(":database")) + compileOnly(project(":core")) dependency(libs.javalin) } \ No newline at end of file diff --git a/packets/build.gradle.kts b/packets/build.gradle.kts deleted file mode 100644 index 7f27b0aa..00000000 --- a/packets/build.gradle.kts +++ /dev/null @@ -1,18 +0,0 @@ -plugins { - id("redicloud-conventions") -} - -group = "dev.redicloud" - -repositories { - mavenCentral() -} - -dependencies { - compileOnly(project(":apis:base-api")) - compileOnly(project(":database")) - compileOnly(project(":utils")) - compileOnly(project(":logging")) - - dependency(libs.gson) -} \ No newline at end of file diff --git a/repositories/build.gradle.kts b/repositories/build.gradle.kts index 6b704be8..6f7e3e3a 100644 --- a/repositories/build.gradle.kts +++ b/repositories/build.gradle.kts @@ -7,10 +7,7 @@ group = "dev.redicloud.repository" dependencies { compileOnly(project(":apis:base-api")) compileOnly(project(":utils")) - compileOnly(project(":database")) - compileOnly(project(":packets")) - compileOnly(project(":cache")) - compileOnly(project(":events")) + compileOnly(project(":core")) compileOnly(project(":logging")) compileOnly(project(":tasks")) compileOnly(project(":console")) diff --git a/repositories/src/main/kotlin/dev/redicloud/repository/java/version/CloudJavaVersion.kt b/repositories/src/main/kotlin/dev/redicloud/repository/java/version/CloudJavaVersion.kt index d390016d..5f51946b 100644 --- a/repositories/src/main/kotlin/dev/redicloud/repository/java/version/CloudJavaVersion.kt +++ b/repositories/src/main/kotlin/dev/redicloud/repository/java/version/CloudJavaVersion.kt @@ -1,8 +1,8 @@ package dev.redicloud.repository.java.version +import dev.redicloud.api.cache.IClusterCacheObject import dev.redicloud.api.java.ICloudJavaVersion import dev.redicloud.api.service.ServiceId -import dev.redicloud.cache.IClusterCacheObject import dev.redicloud.utils.OSType import dev.redicloud.utils.getOperatingSystemType import java.io.File diff --git a/repositories/src/main/kotlin/dev/redicloud/repository/node/CloudNode.kt b/repositories/src/main/kotlin/dev/redicloud/repository/node/CloudNode.kt index ee9869b9..09545b5c 100644 --- a/repositories/src/main/kotlin/dev/redicloud/repository/node/CloudNode.kt +++ b/repositories/src/main/kotlin/dev/redicloud/repository/node/CloudNode.kt @@ -1,8 +1,8 @@ package dev.redicloud.repository.node +import dev.redicloud.api.cache.IClusterCacheObject import dev.redicloud.api.service.ServiceId import dev.redicloud.api.service.node.ICloudNode -import dev.redicloud.cache.IClusterCacheObject import dev.redicloud.repository.service.CloudService import dev.redicloud.repository.service.ServiceSessions diff --git a/repositories/src/main/kotlin/dev/redicloud/repository/player/CloudPlayer.kt b/repositories/src/main/kotlin/dev/redicloud/repository/player/CloudPlayer.kt index 4f3248b4..1470c184 100644 --- a/repositories/src/main/kotlin/dev/redicloud/repository/player/CloudPlayer.kt +++ b/repositories/src/main/kotlin/dev/redicloud/repository/player/CloudPlayer.kt @@ -1,8 +1,8 @@ package dev.redicloud.repository.player +import dev.redicloud.api.cache.IClusterCacheObject import dev.redicloud.api.player.ICloudPlayer import dev.redicloud.api.service.ServiceId -import dev.redicloud.cache.IClusterCacheObject import java.util.UUID class CloudPlayer( diff --git a/repositories/src/main/kotlin/dev/redicloud/repository/server/version/CloudServerVersion.kt b/repositories/src/main/kotlin/dev/redicloud/repository/server/version/CloudServerVersion.kt index 0eb88898..5d81103e 100644 --- a/repositories/src/main/kotlin/dev/redicloud/repository/server/version/CloudServerVersion.kt +++ b/repositories/src/main/kotlin/dev/redicloud/repository/server/version/CloudServerVersion.kt @@ -1,8 +1,8 @@ package dev.redicloud.repository.server.version +import dev.redicloud.api.cache.IClusterCacheObject import dev.redicloud.api.version.ICloudServerVersion import dev.redicloud.api.version.IServerVersion -import dev.redicloud.cache.IClusterCacheObject import dev.redicloud.console.utils.toConsoleValue import dev.redicloud.logging.LogManager import dev.redicloud.repository.server.version.serverversion.ServerVersion diff --git a/repositories/src/main/kotlin/dev/redicloud/repository/server/version/CloudServerVersionType.kt b/repositories/src/main/kotlin/dev/redicloud/repository/server/version/CloudServerVersionType.kt index fe7cf7d8..c4bccb18 100644 --- a/repositories/src/main/kotlin/dev/redicloud/repository/server/version/CloudServerVersionType.kt +++ b/repositories/src/main/kotlin/dev/redicloud/repository/server/version/CloudServerVersionType.kt @@ -1,8 +1,8 @@ package dev.redicloud.repository.server.version +import dev.redicloud.api.cache.IClusterCacheObject import dev.redicloud.api.utils.CONNECTORS_FOLDER import dev.redicloud.api.version.ICloudServerVersionType -import dev.redicloud.cache.IClusterCacheObject import dev.redicloud.console.utils.toConsoleValue import dev.redicloud.logging.LogManager import dev.redicloud.utils.* diff --git a/repositories/src/main/kotlin/dev/redicloud/repository/service/CloudService.kt b/repositories/src/main/kotlin/dev/redicloud/repository/service/CloudService.kt index da03840a..f5cb9ee3 100644 --- a/repositories/src/main/kotlin/dev/redicloud/repository/service/CloudService.kt +++ b/repositories/src/main/kotlin/dev/redicloud/repository/service/CloudService.kt @@ -1,9 +1,9 @@ package dev.redicloud.repository.service +import dev.redicloud.api.cache.IClusterCacheObject import dev.redicloud.api.service.ICloudService import dev.redicloud.api.service.ICloudServiceSession import dev.redicloud.api.service.ServiceId -import dev.redicloud.cache.IClusterCacheObject import dev.redicloud.utils.isIpv4 import dev.redicloud.utils.isIpv6 diff --git a/repositories/src/main/kotlin/dev/redicloud/repository/template/configuration/ConfigurationTemplate.kt b/repositories/src/main/kotlin/dev/redicloud/repository/template/configuration/ConfigurationTemplate.kt index 802c6e79..bace7990 100644 --- a/repositories/src/main/kotlin/dev/redicloud/repository/template/configuration/ConfigurationTemplate.kt +++ b/repositories/src/main/kotlin/dev/redicloud/repository/template/configuration/ConfigurationTemplate.kt @@ -1,8 +1,8 @@ package dev.redicloud.repository.template.configuration +import dev.redicloud.api.cache.IClusterCacheObject import dev.redicloud.api.service.ServiceId import dev.redicloud.api.template.configuration.ICloudConfigurationTemplate -import dev.redicloud.cache.IClusterCacheObject import java.util.* import kotlin.time.Duration.Companion.seconds diff --git a/repositories/src/main/kotlin/dev/redicloud/repository/template/file/FileTemplate.kt b/repositories/src/main/kotlin/dev/redicloud/repository/template/file/FileTemplate.kt index f1d25209..a3e98989 100644 --- a/repositories/src/main/kotlin/dev/redicloud/repository/template/file/FileTemplate.kt +++ b/repositories/src/main/kotlin/dev/redicloud/repository/template/file/FileTemplate.kt @@ -1,8 +1,8 @@ package dev.redicloud.repository.template.file +import dev.redicloud.api.cache.IClusterCacheObject import dev.redicloud.api.template.file.ICloudFileTemplate import dev.redicloud.api.utils.TEMPLATE_FOLDER -import dev.redicloud.cache.IClusterCacheObject import java.io.File import java.util.* diff --git a/server-factories/node-server-factory/build.gradle.kts b/server-factories/node-server-factory/build.gradle.kts index 8f6ffc8d..694a760c 100644 --- a/server-factories/node-server-factory/build.gradle.kts +++ b/server-factories/node-server-factory/build.gradle.kts @@ -9,14 +9,11 @@ dependencies { compileOnly(project(":apis:node-api")) compileOnly(project(":utils")) compileOnly(project(":tasks")) - compileOnly(project(":cache")) - compileOnly(project(":database")) + compileOnly(project(":core")) compileOnly(project(":logging")) compileOnly(project(":console")) - compileOnly(project(":packets")) compileOnly(project(":commands:command-api")) compileOnly(project(":services:base-service")) - compileOnly(project(":events")) compileOnly(project(":file-cluster")) compileOnly(project(":repositories")) compileOnly(project(":server-factories:remote-server-factory")) diff --git a/server-factories/remote-server-factory/build.gradle.kts b/server-factories/remote-server-factory/build.gradle.kts index 490dd1eb..2f390848 100644 --- a/server-factories/remote-server-factory/build.gradle.kts +++ b/server-factories/remote-server-factory/build.gradle.kts @@ -9,14 +9,11 @@ dependencies { compileOnly(project(":apis:node-api")) compileOnly(project(":utils")) compileOnly(project(":tasks")) - compileOnly(project(":cache")) - compileOnly(project(":database")) + compileOnly(project(":core")) compileOnly(project(":logging")) compileOnly(project(":console")) - compileOnly(project(":packets")) compileOnly(project(":commands:command-api")) compileOnly(project(":services:base-service")) - compileOnly(project(":events")) compileOnly(project(":file-cluster")) compileOnly(project(":repositories")) } \ No newline at end of file diff --git a/services/base-service/build.gradle.kts b/services/base-service/build.gradle.kts index 64c419ea..8751b1e4 100644 --- a/services/base-service/build.gradle.kts +++ b/services/base-service/build.gradle.kts @@ -10,12 +10,9 @@ repositories { dependencies { compileOnly(project(":apis:base-api")) - compileOnly(project(":database")) - compileOnly(project(":packets")) + compileOnly(project(":core")) compileOnly(project(":utils")) - compileOnly(project(":cache")) compileOnly(project(":repositories")) - compileOnly(project(":events")) compileOnly(project(":tasks")) compileOnly(project(":console")) compileOnly(project(":modules:module-handler")) diff --git a/services/minecraft-server-service/build.gradle.kts b/services/minecraft-server-service/build.gradle.kts index 05ced176..ddc31603 100644 --- a/services/minecraft-server-service/build.gradle.kts +++ b/services/minecraft-server-service/build.gradle.kts @@ -6,14 +6,11 @@ group = "dev.redicloud.service" dependencies { compileOnly(project(":apis:base-api")) - compileOnly(project(":database")) + compileOnly(project(":core")) compileOnly(project(":server-factories:remote-server-factory")) - compileOnly(project(":packets")) compileOnly(project(":utils")) - compileOnly(project(":cache")) compileOnly(project(":modules:module-handler")) compileOnly(project(":repositories")) - compileOnly(project(":events")) compileOnly(project(":tasks")) compileOnly(project(":console")) compileOnly(project(":logging")) diff --git a/services/node-service/build.gradle.kts b/services/node-service/build.gradle.kts index 5163eed6..4c58e213 100644 --- a/services/node-service/build.gradle.kts +++ b/services/node-service/build.gradle.kts @@ -13,16 +13,13 @@ repositories { } dependencies { - shade(project(":cache")) + shade(project(":core")) shade(project(":apis:base-api")) shade(project(":apis:node-api")) shade(project(":services:base-service")) shade(project(":repositories")) - shade(project(":database")) shade(project(":utils")) - shade(project(":events")) shade(project(":console")) - shade(project(":packets")) shade(project(":commands:command-api")) shade(project(":logging")) shade(project(":tasks")) diff --git a/services/proxy-server-service/build.gradle.kts b/services/proxy-server-service/build.gradle.kts index d95fee76..6576bfd2 100644 --- a/services/proxy-server-service/build.gradle.kts +++ b/services/proxy-server-service/build.gradle.kts @@ -6,12 +6,9 @@ group = "dev.redicloud.service" dependencies { compileOnly(project(":apis:base-api")) - compileOnly(project(":database")) - compileOnly(project(":packets")) - compileOnly(project(":cache")) + compileOnly(project(":core")) compileOnly(project(":utils")) compileOnly(project(":repositories")) - compileOnly(project(":events")) compileOnly(project(":tasks")) compileOnly(project(":console")) compileOnly(project(":logging")) diff --git a/settings.gradle.kts b/settings.gradle.kts index 235eb6dc..995b815b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -18,15 +18,12 @@ pluginManagement { includeBuild("gradle/build-logic") -include("database") -include("packets") +include("core") include("utils") -include("events") include("console") include("logging") include("tasks") include("file-cluster") -include("cache") include("server-factories:node-server-factory") From de19b6b58e2c31015e643cabddfdbdfb5eef891e Mon Sep 17 00:00:00 2001 From: paulkczw <44299323+paulkczw@users.noreply.github.com> Date: Thu, 4 Jun 2026 12:32:06 +0200 Subject: [PATCH 2/8] refactor: extract task interfaces into base-api --- .../dev/redicloud/api/tasks/ICloudTask.kt | 18 +++++++++ .../api/tasks/ICloudTaskExecutorBuilder.kt | 27 ++++++++++++++ .../redicloud/api/tasks/ICloudTaskManager.kt | 16 ++++++++ .../dev/redicloud/service/base/BaseService.kt | 2 + tasks/build.gradle.kts | 2 - .../kotlin/dev/redicloud/tasks/CloudTask.kt | 15 ++++---- .../dev/redicloud/tasks/CloudTaskManager.kt | 37 +++++++++++-------- 7 files changed, 92 insertions(+), 25 deletions(-) create mode 100644 apis/base-api/src/main/kotlin/dev/redicloud/api/tasks/ICloudTask.kt create mode 100644 apis/base-api/src/main/kotlin/dev/redicloud/api/tasks/ICloudTaskExecutorBuilder.kt create mode 100644 apis/base-api/src/main/kotlin/dev/redicloud/api/tasks/ICloudTaskManager.kt diff --git a/apis/base-api/src/main/kotlin/dev/redicloud/api/tasks/ICloudTask.kt b/apis/base-api/src/main/kotlin/dev/redicloud/api/tasks/ICloudTask.kt new file mode 100644 index 00000000..2fba4de5 --- /dev/null +++ b/apis/base-api/src/main/kotlin/dev/redicloud/api/tasks/ICloudTask.kt @@ -0,0 +1,18 @@ +package dev.redicloud.api.tasks + +import java.util.UUID + +interface ICloudTask { + + val id: UUID + + suspend fun execute(): Boolean + + fun isCanceled(): Boolean + + fun isStarted(): Boolean + + fun cancel() + + fun onFinished(block: () -> Unit) +} diff --git a/apis/base-api/src/main/kotlin/dev/redicloud/api/tasks/ICloudTaskExecutorBuilder.kt b/apis/base-api/src/main/kotlin/dev/redicloud/api/tasks/ICloudTaskExecutorBuilder.kt new file mode 100644 index 00000000..b1cfc845 --- /dev/null +++ b/apis/base-api/src/main/kotlin/dev/redicloud/api/tasks/ICloudTaskExecutorBuilder.kt @@ -0,0 +1,27 @@ +package dev.redicloud.api.tasks + +import dev.redicloud.api.events.CloudEvent +import dev.redicloud.api.packets.AbstractPacket +import kotlin.reflect.KClass +import kotlin.time.Duration + +interface ICloudTaskExecutorBuilder { + + fun task(task: ICloudTask): ICloudTaskExecutorBuilder + + fun instant(): ICloudTaskExecutorBuilder + + fun atTime(atTime: Long): ICloudTaskExecutorBuilder + + fun delay(delay: Long): ICloudTaskExecutorBuilder + + fun delay(duration: Duration): ICloudTaskExecutorBuilder + + fun period(period: Duration, maxExecutions: Int = -1): ICloudTaskExecutorBuilder + + fun event(eventClazz: KClass): ICloudTaskExecutorBuilder + + fun packet(packetClazz: KClass): ICloudTaskExecutorBuilder + + fun register(): ICloudTask +} diff --git a/apis/base-api/src/main/kotlin/dev/redicloud/api/tasks/ICloudTaskManager.kt b/apis/base-api/src/main/kotlin/dev/redicloud/api/tasks/ICloudTaskManager.kt new file mode 100644 index 00000000..34650f0f --- /dev/null +++ b/apis/base-api/src/main/kotlin/dev/redicloud/api/tasks/ICloudTaskManager.kt @@ -0,0 +1,16 @@ +package dev.redicloud.api.tasks + +import java.util.UUID + +interface ICloudTaskManager { + + fun register(task: ICloudTask): UUID + + fun unregister(id: UUID): ICloudTask? + + fun unregister(task: ICloudTask): ICloudTask? + + fun getTasks(): List + + fun builder(): ICloudTaskExecutorBuilder +} diff --git a/services/base-service/src/main/kotlin/dev/redicloud/service/base/BaseService.kt b/services/base-service/src/main/kotlin/dev/redicloud/service/base/BaseService.kt index 56ae3f70..b0604cf3 100644 --- a/services/base-service/src/main/kotlin/dev/redicloud/service/base/BaseService.kt +++ b/services/base-service/src/main/kotlin/dev/redicloud/service/base/BaseService.kt @@ -14,6 +14,7 @@ import dev.redicloud.api.service.ServiceId import dev.redicloud.api.service.ServiceType import dev.redicloud.api.service.node.ICloudNodeRepository import dev.redicloud.api.service.server.ICloudServerRepository +import dev.redicloud.api.tasks.ICloudTaskManager import dev.redicloud.api.template.configuration.ICloudConfigurationTemplateRepository import dev.redicloud.api.template.file.ICloudFileTemplateRepository import dev.redicloud.api.utils.injector @@ -275,6 +276,7 @@ abstract class BaseService( bind(java.util.logging.Logger::class).annotatedWith(Names.named("root")).toInstance(LogManager.rootLogger()) bind(java.util.logging.Logger::class).annotatedWith(Names.named("service")).toInstance(LOGGER) bind(CloudTaskManager::class).toInstance(taskManager) + bind(ICloudTaskManager::class.java).toInstance(taskManager) if (System.getProperty("redicloud.inject.redisson", "true").toBooleanStrictOrNull() == true) { bind(RedissonClient::class).toInstance(databaseConnection.client) } diff --git a/tasks/build.gradle.kts b/tasks/build.gradle.kts index 9eae4744..800c7daa 100644 --- a/tasks/build.gradle.kts +++ b/tasks/build.gradle.kts @@ -4,8 +4,6 @@ plugins { group = "dev.redicloud" -val publishToRepository by extra(true) - repositories { mavenCentral() } diff --git a/tasks/src/main/kotlin/dev/redicloud/tasks/CloudTask.kt b/tasks/src/main/kotlin/dev/redicloud/tasks/CloudTask.kt index 78c82382..c1da608c 100644 --- a/tasks/src/main/kotlin/dev/redicloud/tasks/CloudTask.kt +++ b/tasks/src/main/kotlin/dev/redicloud/tasks/CloudTask.kt @@ -1,5 +1,6 @@ package dev.redicloud.tasks +import dev.redicloud.api.tasks.ICloudTask import dev.redicloud.tasks.executor.CloudTaskExecutor import kotlinx.coroutines.Job import kotlinx.coroutines.launch @@ -8,9 +9,9 @@ import kotlinx.coroutines.sync.withLock import java.util.* import java.util.logging.Level -abstract class CloudTask(private val useLock: Boolean = true) { +abstract class CloudTask(private val useLock: Boolean = true) : ICloudTask { - val id: UUID = UUID.randomUUID() + override val id: UUID = UUID.randomUUID() private var canceled = false private var executors: MutableList = mutableListOf() private var executeCount: Int = 0 @@ -19,7 +20,7 @@ abstract class CloudTask(private val useLock: Boolean = true) { private val finishListener = mutableListOf<() -> Unit>() private val mutex = Mutex() - abstract suspend fun execute(): Boolean + abstract override suspend fun execute(): Boolean internal fun preExecute(source: CloudTaskExecutor): Job? { if (canceled) return null @@ -66,10 +67,10 @@ abstract class CloudTask(private val useLock: Boolean = true) { executors.add(executor) } - fun isCanceled(): Boolean = canceled - fun isStarted(): Boolean = started + override fun isCanceled(): Boolean = canceled + override fun isStarted(): Boolean = started - fun cancel() { + override fun cancel() { canceled = true executors.forEach { it.cancel() } finish() @@ -81,7 +82,7 @@ abstract class CloudTask(private val useLock: Boolean = true) { finishListener.forEach { it() } } - fun onFinished(block: () -> Unit) { + override fun onFinished(block: () -> Unit) { finishListener.add(block) } } diff --git a/tasks/src/main/kotlin/dev/redicloud/tasks/CloudTaskManager.kt b/tasks/src/main/kotlin/dev/redicloud/tasks/CloudTaskManager.kt index 3f20f20c..0183ee0d 100644 --- a/tasks/src/main/kotlin/dev/redicloud/tasks/CloudTaskManager.kt +++ b/tasks/src/main/kotlin/dev/redicloud/tasks/CloudTaskManager.kt @@ -4,6 +4,9 @@ import dev.redicloud.api.events.CloudEvent import dev.redicloud.api.events.IEventManager import dev.redicloud.api.packets.AbstractPacket import dev.redicloud.api.packets.IPacketManager +import dev.redicloud.api.tasks.ICloudTask +import dev.redicloud.api.tasks.ICloudTaskExecutorBuilder +import dev.redicloud.api.tasks.ICloudTaskManager import dev.redicloud.logging.LogManager import dev.redicloud.tasks.executor.AtTimeCloudExecutor import dev.redicloud.tasks.executor.CloudTaskExecutor @@ -25,7 +28,7 @@ class CloudTaskManager( internal val eventManager: IEventManager, internal val packetManager: IPacketManager, threads: Int -) { +) : ICloudTaskManager { companion object { val LOGGER = LogManager.logger(CloudTaskManager::class) @@ -38,27 +41,28 @@ class CloudTaskManager( SupervisorJob() + newFixedThreadPoolContext(threads, "CloudTaskManager") + coroutineExceptionHandler ) - fun register(task: CloudTask): UUID { + override fun register(task: ICloudTask): UUID { + require(task is CloudTask) { "Task must be an instance of CloudTask" } require(!tasks.containsKey(task.id)) { "Task with id ${task.id} is already registered" } tasks[task.id] = task task.start(this) return task.id } - fun unregister(id: UUID): CloudTask? { + override fun unregister(id: UUID): ICloudTask? { val task = tasks.remove(id) task?.cancel() return task } - fun unregister(task: CloudTask): CloudTask? = unregister(task.id) + override fun unregister(task: ICloudTask): ICloudTask? = unregister(task.id) - fun builder(): CloudTaskExecutorBuilder = CloudTaskExecutorBuilder(this) + override fun builder(): ICloudTaskExecutorBuilder = CloudTaskExecutorBuilder(this) - fun getTasks(): List = tasks.values.toList() + override fun getTasks(): List = tasks.values.toList() } -class CloudTaskExecutorBuilder internal constructor(val manager: CloudTaskManager) { +class CloudTaskExecutorBuilder internal constructor(val manager: CloudTaskManager) : ICloudTaskExecutorBuilder { private var task: CloudTask? = null private var executors: MutableList = mutableListOf() @@ -66,51 +70,52 @@ class CloudTaskExecutorBuilder internal constructor(val manager: CloudTaskManage private var packets: MutableList> = mutableListOf() private var instant: Boolean = false - fun task(task: CloudTask): CloudTaskExecutorBuilder { + override fun task(task: ICloudTask): ICloudTaskExecutorBuilder { + require(task is CloudTask) { "Task must be an instance of CloudTask" } this.task = task return this } - fun instant(): CloudTaskExecutorBuilder { + override fun instant(): ICloudTaskExecutorBuilder { this.instant = true return this } - fun atTime(atTime: Long): CloudTaskExecutorBuilder { + override fun atTime(atTime: Long): ICloudTaskExecutorBuilder { require(atTime >= System.currentTimeMillis()) { "At time must be in the future" } executors.add(AtTimeCloudExecutor(this.task!!, atTime)) return this } - fun delay(delay: Long): CloudTaskExecutorBuilder { + override fun delay(delay: Long): ICloudTaskExecutorBuilder { require(delay >= 0) { "Delay must be positive" } executors.add(AtTimeCloudExecutor(this.task!!, System.currentTimeMillis() + delay)) return this } - fun delay(duration: Duration): CloudTaskExecutorBuilder { + override fun delay(duration: Duration): ICloudTaskExecutorBuilder { require(duration.inWholeMilliseconds >= 0) { "Delay must be positive" } executors.add(AtTimeCloudExecutor(this.task!!, System.currentTimeMillis() + duration.inWholeMilliseconds)) return this } - fun period(period: Duration, maxExecutions: Int = -1): CloudTaskExecutorBuilder { + override fun period(period: Duration, maxExecutions: Int): ICloudTaskExecutorBuilder { require(period.inWholeMilliseconds >= 0) { "Period must be positive" } executors.add(PeriodicallyCloudTaskExecutor(this.task!!, period, maxExecutions)) return this } - fun event(eventClazz: KClass): CloudTaskExecutorBuilder { + override fun event(eventClazz: KClass): ICloudTaskExecutorBuilder { events.add(eventClazz) return this } - fun packet(packetClazz: KClass): CloudTaskExecutorBuilder { + override fun packet(packetClazz: KClass): ICloudTaskExecutorBuilder { packets.add(packetClazz) return this } - fun register(): CloudTask { + override fun register(): ICloudTask { checkNotNull(this.task) { "Task must be set" } check(this.executors.isNotEmpty() || this.events.isNotEmpty() || this.packets.isNotEmpty() || instant) { "At least one executor must be set" From acb1ad3845588fde4f4d6fc1be06be197a04a89a Mon Sep 17 00:00:00 2001 From: paulkczw <44299323+paulkczw@users.noreply.github.com> Date: Thu, 4 Jun 2026 12:33:10 +0200 Subject: [PATCH 3/8] refactor: add ICloudConsole interface to base-api --- .../redicloud/api/console/ICloudConsole.kt | 20 +++++++++++++++++++ console/build.gradle.kts | 2 -- .../dev/redicloud/console/jline/IConsole.kt | 17 ++++++++++------ .../dev/redicloud/service/node/NodeService.kt | 13 +++++++++--- 4 files changed, 41 insertions(+), 11 deletions(-) create mode 100644 apis/base-api/src/main/kotlin/dev/redicloud/api/console/ICloudConsole.kt diff --git a/apis/base-api/src/main/kotlin/dev/redicloud/api/console/ICloudConsole.kt b/apis/base-api/src/main/kotlin/dev/redicloud/api/console/ICloudConsole.kt new file mode 100644 index 00000000..911c6ae0 --- /dev/null +++ b/apis/base-api/src/main/kotlin/dev/redicloud/api/console/ICloudConsole.kt @@ -0,0 +1,20 @@ +package dev.redicloud.api.console + +import dev.redicloud.api.commands.ICommandManager + +interface ICloudConsole { + + val commandManager: ICommandManager<*> + + fun writeLine(text: String): ICloudConsole + + fun forceWriteLine(text: String): ICloudConsole + + fun clearScreen() + + fun enableCommands() + + fun disableCommands() + + fun hasColorSupport(): Boolean +} diff --git a/console/build.gradle.kts b/console/build.gradle.kts index 9407ba61..3d23ff91 100644 --- a/console/build.gradle.kts +++ b/console/build.gradle.kts @@ -2,8 +2,6 @@ plugins { id("redicloud-conventions") } -val publishToRepository by extra(true) - group = "dev.redicloud" repositories { diff --git a/console/src/main/kotlin/dev/redicloud/console/jline/IConsole.kt b/console/src/main/kotlin/dev/redicloud/console/jline/IConsole.kt index a8524b19..2932453a 100644 --- a/console/src/main/kotlin/dev/redicloud/console/jline/IConsole.kt +++ b/console/src/main/kotlin/dev/redicloud/console/jline/IConsole.kt @@ -1,5 +1,6 @@ package dev.redicloud.console.jline +import dev.redicloud.api.console.ICloudConsole import dev.redicloud.console.Console import dev.redicloud.console.animation.AbstractConsoleAnimation import dev.redicloud.console.commands.ConsoleCommandManager @@ -7,12 +8,12 @@ import dev.redicloud.console.utils.Screen import org.fusesource.jansi.Ansi @Suppress("TooManyFunctions") -interface IConsole { +interface IConsole : ICloudConsole { var printingEnabled: Boolean var matchingHistorySearch: Boolean var prompt: String - val commandManager: ConsoleCommandManager + override val commandManager: ConsoleCommandManager var lineFormat: String val saveLogToFile: Boolean val uninstallAnsiOnClose: Boolean @@ -57,9 +58,9 @@ interface IConsole { fun commandInputValue(commandInputValue: String) - fun enableCommands() + override fun enableCommands() - fun disableCommands() + override fun disableCommands() @Suppress("LongParameterList") fun writeRaw( @@ -76,9 +77,13 @@ interface IConsole { fun forceWriteLine(text: String, source: Screen? = null, history: Boolean = true): Console + override fun forceWriteLine(text: String): ICloudConsole = forceWriteLine(text, null, true) + fun writeLine(text: String, source: Screen? = null, history: Boolean = true): Console - fun hasColorSupport(): Boolean + override fun writeLine(text: String): ICloudConsole = writeLine(text, null, true) + + override fun hasColorSupport(): Boolean fun resetPrompt() @@ -86,7 +91,7 @@ interface IConsole { fun emptyPrompt() - fun clearScreen() + override fun clearScreen() fun close(processExit: Boolean = false) } diff --git a/services/node-service/src/main/kotlin/dev/redicloud/service/node/NodeService.kt b/services/node-service/src/main/kotlin/dev/redicloud/service/node/NodeService.kt index d8155492..0bd781b0 100644 --- a/services/node-service/src/main/kotlin/dev/redicloud/service/node/NodeService.kt +++ b/services/node-service/src/main/kotlin/dev/redicloud/service/node/NodeService.kt @@ -2,6 +2,7 @@ package dev.redicloud.service.node import dev.redicloud.api.commands.ICommand import dev.redicloud.api.commands.ICommandManager +import dev.redicloud.api.console.ICloudConsole import dev.redicloud.api.events.internal.module.ModuleHandlerInitializedEvent import dev.redicloud.api.events.internal.node.NodeConnectEvent import dev.redicloud.api.events.internal.node.NodeDisconnectEvent @@ -10,9 +11,11 @@ import dev.redicloud.api.events.internal.server.CloudServerDisconnectedEvent import dev.redicloud.api.service.server.factory.ICloudRemoteServerFactory import dev.redicloud.api.utils.TEMP_FOLDER import dev.redicloud.api.version.IServerVersionHandler +import dev.redicloud.api.version.IVersionHandlerListener import dev.redicloud.cluster.file.FileCluster import dev.redicloud.cluster.file.FileNodeRepository import dev.redicloud.console.Console +import dev.redicloud.console.utils.ConsoleVersionHandlerListener import dev.redicloud.database.DatabaseConnection import dev.redicloud.database.config.DatabaseConfiguration import dev.redicloud.migration.MigrationResult @@ -62,6 +65,7 @@ class NodeService( override val moduleHandler: ModuleHandler override val playerExecutor: NodePlayerExecutor val console: NodeConsole + val versionHandlerListener: ConsoleVersionHandlerListener val fileNodeRepository: FileNodeRepository val fileCluster: FileCluster val serverFactory: ServerFactory @@ -71,7 +75,8 @@ class NodeService( fileNodeRepository = FileNodeRepository(databaseConnection, packetManager, scope) fileCluster = FileCluster(serviceId, configuration.hostAddress, fileNodeRepository, packetManager, nodeRepository, eventManager) fileTemplateRepository = NodeFileTemplateRepository(databaseConnection, nodeRepository, fileCluster, packetManager, scope) - serverVersionTypeRepository = CloudServerVersionTypeRepository(databaseConnection, console, packetManager, scope) + versionHandlerListener = ConsoleVersionHandlerListener(console) + serverVersionTypeRepository = CloudServerVersionTypeRepository(databaseConnection, versionHandlerListener, packetManager, scope) serverFactory = ServerFactory( databaseConnection, nodeRepository, serverRepository, serverVersionRepository, serverVersionTypeRepository, @@ -117,8 +122,8 @@ class NodeService( serverVersionRepository, serverVersionTypeRepository, nodeRepository, - console, - javaVersionRepository + javaVersionRepository, + listener = versionHandlerListener ) ) @@ -488,6 +493,8 @@ class NodeService( super.configure() bind(ICommandManager::class).toInstance(console.commandManager) bind(Console::class).toInstance(console) + bind(ICloudConsole::class.java).toInstance(console) + bind(IVersionHandlerListener::class.java).toInstance(versionHandlerListener) bind(ICloudRemoteServerFactory::class).toInstance(serverFactory) } } From 0cccb0e9bf3d9615e115a17d1623e611f0d47f78 Mon Sep 17 00:00:00 2001 From: paulkczw <44299323+paulkczw@users.noreply.github.com> Date: Thu, 4 Jun 2026 12:36:00 +0200 Subject: [PATCH 4/8] refactor: move toConsoleValue from console to utils --- .../papermc/PaperMcServerVersionHandler.kt | 57 +++---------------- .../server/version/CloudServerVersion.kt | 4 +- .../version/CloudServerVersionRepository.kt | 2 +- .../server/version/CloudServerVersionType.kt | 2 +- .../CloudServerVersionTypeRepository.kt | 34 ++--------- .../defaults/URLServerVersionHandler.kt | 51 +++-------------- .../task/CloudServerVersionUpdateTask.kt | 2 +- .../redicloud/server/factory/ServerProcess.kt | 2 +- .../task/CloudServerQueueCleanerTask.kt | 2 +- .../factory/task/CloudServerStartTask.kt | 2 +- .../commands/CloudServerVersionCommand.kt | 10 ++-- .../commands/CloudServerVersionTypeCommand.kt | 6 +- .../service/node/commands/ClusterCommand.kt | 2 +- .../commands/ConfigurationTemplateCommand.kt | 6 +- .../node/commands/FileTemplateCommand.kt | 2 +- .../node/commands/JavaVersionCommand.kt | 2 +- .../service/node/commands/ModuleCommand.kt | 2 +- .../service/node/commands/ScreenCommand.kt | 2 +- .../service/node/commands/ServerCommand.kt | 2 +- .../service/node/commands/VersionCommand.kt | 2 +- .../service/node/console/NodeConsole.kt | 2 +- .../redicloud}/utils/CommandStringUtils.kt | 2 +- 22 files changed, 50 insertions(+), 148 deletions(-) rename {console/src/main/kotlin/dev/redicloud/console => utils/src/main/kotlin/dev/redicloud}/utils/CommandStringUtils.kt (82%) diff --git a/modules/papermc-updater/src/main/kotlin/dev/redicloud/module/papermc/PaperMcServerVersionHandler.kt b/modules/papermc-updater/src/main/kotlin/dev/redicloud/module/papermc/PaperMcServerVersionHandler.kt index 85a8dde5..37347461 100644 --- a/modules/papermc-updater/src/main/kotlin/dev/redicloud/module/papermc/PaperMcServerVersionHandler.kt +++ b/modules/papermc-updater/src/main/kotlin/dev/redicloud/module/papermc/PaperMcServerVersionHandler.kt @@ -6,12 +6,9 @@ import dev.redicloud.api.java.ICloudJavaVersionRepository import dev.redicloud.api.utils.ProcessConfiguration import dev.redicloud.api.utils.TEMP_SERVER_VERSION_FOLDER import dev.redicloud.api.version.* -import dev.redicloud.console.Console -import dev.redicloud.console.animation.impl.line.AnimatedLineAnimation -import dev.redicloud.console.utils.ScreenProcessHandler -import dev.redicloud.console.utils.toConsoleValue import dev.redicloud.logging.Logger import dev.redicloud.utils.* +import dev.redicloud.utils.toConsoleValue import io.ktor.client.request.* import io.ktor.client.statement.* import io.ktor.client.statement.readRawBytes @@ -31,12 +28,11 @@ class PaperMcServerVersionHandler( private val serverVersionTypeRepository: ICloudServerVersionTypeRepository, private val javaVersionRepository: ICloudJavaVersionRepository, private val requester: PaperMcApiRequester, - private val console: Console?, - private val logger: Logger + private val logger: Logger, + private val listener: IVersionHandlerListener? = null ) : IServerVersionHandler { companion object { - private const val ANIMATION_TICK_MS = 200L private const val PATCH_PORT_RANGE_START = 40000 private const val PATCH_PORT_RANGE_END = 60000 } @@ -46,25 +42,8 @@ class PaperMcServerVersionHandler( private val lastUpdateChecks = mutableMapOf() override suspend fun download(version: ICloudServerVersion, force: Boolean, lock: Boolean): File { - var canceled = false - var downloaded = false + listener?.onDownloadStart(version) var error = false - console?.let { - val animation = AnimatedLineAnimation( - console, - ANIMATION_TICK_MS - ) { - if (canceled) { - null - } else if (downloaded) { - canceled = true - "Downloaded version %hc%${version.displayName}§8: ${if (error) "§4✘" else "§2✓"}" - } else { - "Downloading version %hc%${version.displayName}§8: %tc%%loading%" - } - } - console.startAnimation(animation) - } return getLock(version).withOptionalLock(lock) { val jar = getJar(version) @Suppress("TooGenericExceptionCaught") @@ -80,7 +59,7 @@ class PaperMcServerVersionHandler( error = true throw CloudVersionException("Failed to download version ${version.displayName}", e) } finally { - downloaded = true + listener?.onDownloadComplete(version, error) } jar } @@ -244,25 +223,8 @@ class PaperMcServerVersionHandler( override suspend fun patch(version: ICloudServerVersion, lock: Boolean) { if (!version.patch) return - var canceled = false - var patched = false + listener?.onPatchStart(version) var error = false - console?.let { - val animation = AnimatedLineAnimation( - console, - ANIMATION_TICK_MS - ) { - if (canceled) { - null - } else if (patched) { - canceled = true - "Patching version %tc%${toConsoleValue(version.displayName)}§8: ${if (error) "§4✘" else "§2✓"}" - } else { - "Patching version %tc%${toConsoleValue(version.displayName)}§8: %tc%%loading%" - } - } - console.startAnimation(animation) - } getLock(version).withOptionalLock(lock) { @Suppress("TooGenericExceptionCaught") try { @@ -297,7 +259,7 @@ class PaperMcServerVersionHandler( error = true throw CloudVersionException("Failed to patch version ${version.displayName}", e) } finally { - patched = true + listener?.onPatchComplete(version, error) } } } @@ -330,10 +292,7 @@ class PaperMcServerVersionHandler( processBuilder.directory(tempDir) withContext(Dispatchers.IO) { val process = processBuilder.start() - console?.let { - val screen = console.createScreen("patch_${version.displayName}") - ScreenProcessHandler(process, screen) - } + listener?.onProcessStart("patch_${version.displayName}", process) process.waitFor(5.minutes.inWholeMilliseconds, TimeUnit.MILLISECONDS) } } diff --git a/repositories/src/main/kotlin/dev/redicloud/repository/server/version/CloudServerVersion.kt b/repositories/src/main/kotlin/dev/redicloud/repository/server/version/CloudServerVersion.kt index 5d81103e..05393dca 100644 --- a/repositories/src/main/kotlin/dev/redicloud/repository/server/version/CloudServerVersion.kt +++ b/repositories/src/main/kotlin/dev/redicloud/repository/server/version/CloudServerVersion.kt @@ -3,11 +3,11 @@ package dev.redicloud.repository.server.version import dev.redicloud.api.cache.IClusterCacheObject import dev.redicloud.api.version.ICloudServerVersion import dev.redicloud.api.version.IServerVersion -import dev.redicloud.console.utils.toConsoleValue import dev.redicloud.logging.LogManager import dev.redicloud.repository.server.version.serverversion.ServerVersion import dev.redicloud.utils.ConfigurationFileEditor import dev.redicloud.utils.gson.GsonInterface +import dev.redicloud.utils.toConsoleValue import java.io.File import java.util.UUID @@ -33,7 +33,7 @@ class CloudServerVersion( ) : Comparable, IClusterCacheObject, ICloudServerVersion { companion object { - private val logger = LogManager.Companion.logger(CloudServerVersion::class) + private val logger = LogManager.logger(CloudServerVersion::class) } override val displayName: String diff --git a/repositories/src/main/kotlin/dev/redicloud/repository/server/version/CloudServerVersionRepository.kt b/repositories/src/main/kotlin/dev/redicloud/repository/server/version/CloudServerVersionRepository.kt index b20a692d..2fabb445 100644 --- a/repositories/src/main/kotlin/dev/redicloud/repository/server/version/CloudServerVersionRepository.kt +++ b/repositories/src/main/kotlin/dev/redicloud/repository/server/version/CloudServerVersionRepository.kt @@ -2,7 +2,6 @@ package dev.redicloud.repository.server.version import dev.redicloud.api.service.ServiceType import dev.redicloud.api.version.* -import dev.redicloud.console.utils.toConsoleValue import dev.redicloud.database.DatabaseConnection import dev.redicloud.logging.LogManager import dev.redicloud.packets.PacketManager @@ -13,6 +12,7 @@ import dev.redicloud.utils.getTextFromGitHub import dev.redicloud.utils.gson.fromJsonToList import dev.redicloud.utils.gson.gson import dev.redicloud.utils.gson.gsonInterfaceFactory +import dev.redicloud.utils.toConsoleValue import kotlinx.coroutines.CoroutineScope import java.util.* import kotlin.time.Duration.Companion.minutes diff --git a/repositories/src/main/kotlin/dev/redicloud/repository/server/version/CloudServerVersionType.kt b/repositories/src/main/kotlin/dev/redicloud/repository/server/version/CloudServerVersionType.kt index c4bccb18..ba6f3e1f 100644 --- a/repositories/src/main/kotlin/dev/redicloud/repository/server/version/CloudServerVersionType.kt +++ b/repositories/src/main/kotlin/dev/redicloud/repository/server/version/CloudServerVersionType.kt @@ -3,9 +3,9 @@ package dev.redicloud.repository.server.version import dev.redicloud.api.cache.IClusterCacheObject import dev.redicloud.api.utils.CONNECTORS_FOLDER import dev.redicloud.api.version.ICloudServerVersionType -import dev.redicloud.console.utils.toConsoleValue import dev.redicloud.logging.LogManager import dev.redicloud.utils.* +import dev.redicloud.utils.toConsoleValue import java.io.File import java.net.URL import java.util.* diff --git a/repositories/src/main/kotlin/dev/redicloud/repository/server/version/CloudServerVersionTypeRepository.kt b/repositories/src/main/kotlin/dev/redicloud/repository/server/version/CloudServerVersionTypeRepository.kt index cd05b444..debfc402 100644 --- a/repositories/src/main/kotlin/dev/redicloud/repository/server/version/CloudServerVersionTypeRepository.kt +++ b/repositories/src/main/kotlin/dev/redicloud/repository/server/version/CloudServerVersionTypeRepository.kt @@ -2,9 +2,6 @@ package dev.redicloud.repository.server.version import dev.redicloud.api.service.ServiceType import dev.redicloud.api.version.* -import dev.redicloud.console.Console -import dev.redicloud.console.animation.impl.line.AnimatedLineAnimation -import dev.redicloud.console.utils.toConsoleValue import dev.redicloud.database.DatabaseConnection import dev.redicloud.logging.LogManager import dev.redicloud.packets.PacketManager @@ -14,6 +11,7 @@ import dev.redicloud.utils.* import dev.redicloud.utils.gson.fromJsonToList import dev.redicloud.utils.gson.gson import dev.redicloud.utils.gson.gsonInterfaceFactory +import dev.redicloud.utils.toConsoleValue import dev.redicloud.utils.withOptionalLock import io.ktor.client.request.* import io.ktor.client.statement.* @@ -29,7 +27,7 @@ import kotlin.time.Duration.Companion.minutes @Suppress("TooManyFunctions") // Repository with CRUD + sync + download operations class CloudServerVersionTypeRepository( databaseConnection: DatabaseConnection, - private val console: Console?, + private val listener: IVersionHandlerListener? = null, packetManager: PacketManager, scope: CoroutineScope ) : CachedDatabaseBucketRepository( @@ -51,7 +49,6 @@ class CloudServerVersionTypeRepository( private val locks = mutableMapOf() companion object { - private const val ANIMATION_TICK_MS = 200L val LOGGER = LogManager.logger(CloudServerVersionTypeRepository::class) val DEFAULT_TYPES_CACHE = SingleCache(1.minutes) { gsonInterfaceFactory.register(IServerVersion::class, ServerVersion::class) @@ -117,29 +114,10 @@ class CloudServerVersionTypeRepository( return } - var canceled = false - var downloaded = false + listener?.onConnectorDownloadStart(serverVersionType) var error = false - val animation = if (console != null) { - AnimatedLineAnimation( - console, - ANIMATION_TICK_MS - ) { - if (canceled) { - null - } else if (downloaded) { - canceled = true - "Downloaded connector ${toConsoleValue(serverVersionType.name)}§8: ${if (error) "§4✘" else "§2✓"}" - } else { - "Downloading connector ${toConsoleValue(serverVersionType.name)}§8: %tc%%loading%" - } - } - } else { - null - } - console?.startAnimation(animation!!) LOGGER.log( - if (console == null) Level.INFO else Level.FINE, + if (listener == null) Level.INFO else Level.FINE, "Downloading connector for ${toConsoleValue(serverVersionType.name)}..." ) getLock(serverVersionType).withOptionalLock(lock) { @@ -162,14 +140,14 @@ class CloudServerVersionTypeRepository( verifyConnectorIfPossible(serverVersionType, connectorFile) LOGGER.log( - if (console == null) Level.FINE else Level.INFO, + if (listener == null) Level.FINE else Level.INFO, "Successfully downloaded connector for ${toConsoleValue(serverVersionType.name)}!" ) } catch (e: Exception) { LOGGER.severe("§cFailed to download connector ${toConsoleValue(connectorFile.name, false)}!", e) error = true } finally { - downloaded = true + listener?.onConnectorDownloadComplete(serverVersionType, error) } } } diff --git a/repositories/src/main/kotlin/dev/redicloud/repository/server/version/handler/defaults/URLServerVersionHandler.kt b/repositories/src/main/kotlin/dev/redicloud/repository/server/version/handler/defaults/URLServerVersionHandler.kt index ea7f40ba..90ed8e8e 100644 --- a/repositories/src/main/kotlin/dev/redicloud/repository/server/version/handler/defaults/URLServerVersionHandler.kt +++ b/repositories/src/main/kotlin/dev/redicloud/repository/server/version/handler/defaults/URLServerVersionHandler.kt @@ -8,12 +8,9 @@ import dev.redicloud.api.service.node.ICloudNodeRepository import dev.redicloud.api.utils.ProcessConfiguration import dev.redicloud.api.utils.TEMP_SERVER_VERSION_FOLDER import dev.redicloud.api.version.* -import dev.redicloud.console.Console -import dev.redicloud.console.animation.impl.line.AnimatedLineAnimation -import dev.redicloud.console.utils.ScreenProcessHandler -import dev.redicloud.console.utils.toConsoleValue import dev.redicloud.logging.LogManager import dev.redicloud.utils.* +import dev.redicloud.utils.toConsoleValue import io.ktor.client.request.* import io.ktor.client.statement.* import io.ktor.client.statement.readRawBytes @@ -33,15 +30,14 @@ open class URLServerVersionHandler( protected val serverVersionRepository: ICloudServerVersionRepository, protected val serverVersionTypeRepository: ICloudServerVersionTypeRepository, protected val nodeRepository: ICloudNodeRepository, - protected val console: Console, protected val javaVersionRepository: ICloudJavaVersionRepository, override val default: Boolean = true, - override val name: String = "urldownloader" + override val name: String = "urldownloader", + protected val listener: IVersionHandlerListener? = null ) : IServerVersionHandler { companion object { private val logger = LogManager.logger(URLServerVersionHandler::class) - private const val ANIMATION_TICK_MS = 200L private const val PATCH_PORT_RANGE_START = 40000 private const val PATCH_PORT_RANGE_END = 60000 } @@ -53,23 +49,8 @@ open class URLServerVersionHandler( } override suspend fun download(version: ICloudServerVersion, force: Boolean, lock: Boolean): File { - var canceled = false - var downloaded = false + listener?.onDownloadStart(version) var error = false - val animation = AnimatedLineAnimation( - console, - ANIMATION_TICK_MS - ) { - if (canceled) { - null - } else if (downloaded) { - canceled = true - "Downloaded version %hc%${version.displayName}§8: ${if (error) "§4✘" else "§2✓"}" - } else { - "Downloading version %hc%${version.displayName}§8: %tc%%loading%" - } - } - console.startAnimation(animation) return getLock(version).withOptionalLock(lock) { val jar = getJar(version) @Suppress("TooGenericExceptionCaught") @@ -84,7 +65,7 @@ open class URLServerVersionHandler( error = true throw CloudVersionException("Failed to download version ${version.displayName}", e) } finally { - downloaded = true + listener?.onDownloadComplete(version, error) } jar } @@ -232,23 +213,8 @@ open class URLServerVersionHandler( override suspend fun patch(version: ICloudServerVersion, lock: Boolean) { if (!version.patch) return - var canceled = false - var patched = false + listener?.onPatchStart(version) var error = false - val animation = AnimatedLineAnimation( - console, - ANIMATION_TICK_MS - ) { - if (canceled) { - null - } else if (patched) { - canceled = true - "Patching version %tc%${toConsoleValue(version.displayName)}§8: ${if (error) "§4✘" else "§2✓"}" - } else { - "Patching version %tc%${toConsoleValue(version.displayName)}§8: %tc%%loading%" - } - } - console.startAnimation(animation) getLock(version).withOptionalLock(lock) { @Suppress("TooGenericExceptionCaught") try { @@ -283,7 +249,7 @@ open class URLServerVersionHandler( error = true throw CloudVersionException("Failed to patch version ${version.displayName}", e) } finally { - patched = true + listener?.onPatchComplete(version, error) } } } @@ -320,8 +286,7 @@ open class URLServerVersionHandler( processBuilder.directory(tempDir) withContext(Dispatchers.IO) { val process = processBuilder.start() - val screen = console.createScreen("patch_${version.displayName}") - ScreenProcessHandler(process, screen) + listener?.onProcessStart("patch_${version.displayName}", process) process.waitFor(5.minutes.inWholeMilliseconds, TimeUnit.MILLISECONDS) } } diff --git a/repositories/src/main/kotlin/dev/redicloud/repository/server/version/task/CloudServerVersionUpdateTask.kt b/repositories/src/main/kotlin/dev/redicloud/repository/server/version/task/CloudServerVersionUpdateTask.kt index eb9ac49b..56ccccca 100644 --- a/repositories/src/main/kotlin/dev/redicloud/repository/server/version/task/CloudServerVersionUpdateTask.kt +++ b/repositories/src/main/kotlin/dev/redicloud/repository/server/version/task/CloudServerVersionUpdateTask.kt @@ -1,11 +1,11 @@ package dev.redicloud.repository.server.version.task import dev.redicloud.api.version.IServerVersionHandler -import dev.redicloud.console.utils.toConsoleValue import dev.redicloud.logging.LogManager import dev.redicloud.repository.server.version.CloudServerVersionRepository import dev.redicloud.repository.server.version.CloudServerVersionTypeRepository import dev.redicloud.tasks.CloudTask +import dev.redicloud.utils.toConsoleValue class CloudServerVersionUpdateTask( private val silent: Boolean, diff --git a/server-factories/node-server-factory/src/main/kotlin/dev/redicloud/server/factory/ServerProcess.kt b/server-factories/node-server-factory/src/main/kotlin/dev/redicloud/server/factory/ServerProcess.kt index f0af3305..740902b1 100644 --- a/server-factories/node-server-factory/src/main/kotlin/dev/redicloud/server/factory/ServerProcess.kt +++ b/server-factories/node-server-factory/src/main/kotlin/dev/redicloud/server/factory/ServerProcess.kt @@ -11,7 +11,6 @@ import dev.redicloud.api.utils.ProcessConfiguration import dev.redicloud.api.utils.ProcessHandler import dev.redicloud.api.version.IServerVersionHandler import dev.redicloud.console.utils.ScreenProcessHandler -import dev.redicloud.console.utils.toConsoleValue import dev.redicloud.event.EventManager import dev.redicloud.logging.LogManager import dev.redicloud.logging.getDefaultLogLevel @@ -26,6 +25,7 @@ import dev.redicloud.service.base.utils.ClusterConfiguration import dev.redicloud.utils.blockPort import dev.redicloud.utils.findFreePort import dev.redicloud.utils.freePort +import dev.redicloud.utils.toConsoleValue import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay diff --git a/server-factories/node-server-factory/src/main/kotlin/dev/redicloud/server/factory/task/CloudServerQueueCleanerTask.kt b/server-factories/node-server-factory/src/main/kotlin/dev/redicloud/server/factory/task/CloudServerQueueCleanerTask.kt index 8d078c43..d620342a 100644 --- a/server-factories/node-server-factory/src/main/kotlin/dev/redicloud/server/factory/task/CloudServerQueueCleanerTask.kt +++ b/server-factories/node-server-factory/src/main/kotlin/dev/redicloud/server/factory/task/CloudServerQueueCleanerTask.kt @@ -1,13 +1,13 @@ package dev.redicloud.server.factory.task import dev.redicloud.api.service.server.CloudServerState -import dev.redicloud.console.utils.toConsoleValue import dev.redicloud.logging.LogManager import dev.redicloud.repository.node.NodeRepository import dev.redicloud.repository.server.CloudServer import dev.redicloud.repository.server.ServerRepository import dev.redicloud.server.factory.ServerFactory import dev.redicloud.tasks.CloudTask +import dev.redicloud.utils.toConsoleValue import kotlin.time.Duration.Companion.minutes class CloudServerQueueCleanerTask( diff --git a/server-factories/node-server-factory/src/main/kotlin/dev/redicloud/server/factory/task/CloudServerStartTask.kt b/server-factories/node-server-factory/src/main/kotlin/dev/redicloud/server/factory/task/CloudServerStartTask.kt index ddfc09f4..671f8d8e 100644 --- a/server-factories/node-server-factory/src/main/kotlin/dev/redicloud/server/factory/task/CloudServerStartTask.kt +++ b/server-factories/node-server-factory/src/main/kotlin/dev/redicloud/server/factory/task/CloudServerStartTask.kt @@ -5,7 +5,6 @@ import dev.redicloud.api.events.internal.node.NodeDisconnectEvent import dev.redicloud.api.events.internal.node.NodeSuspendedEvent import dev.redicloud.api.events.listen import dev.redicloud.api.utils.factory.* -import dev.redicloud.console.utils.toConsoleValue import dev.redicloud.event.EventManager import dev.redicloud.logging.LogManager import dev.redicloud.repository.node.NodeRepository @@ -15,6 +14,7 @@ import dev.redicloud.server.factory.utils.* import dev.redicloud.tasks.CloudTask import dev.redicloud.utils.ConcurrentBatch import dev.redicloud.utils.coroutineExceptionHandler +import dev.redicloud.utils.toConsoleValue import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.SupervisorJob diff --git a/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/CloudServerVersionCommand.kt b/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/CloudServerVersionCommand.kt index a442bafc..4ecb95b2 100644 --- a/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/CloudServerVersionCommand.kt +++ b/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/CloudServerVersionCommand.kt @@ -4,7 +4,6 @@ import dev.redicloud.api.commands.* import dev.redicloud.api.exceptions.CloudVersionException import dev.redicloud.api.version.IServerVersionHandler import dev.redicloud.console.commands.ConsoleActor -import dev.redicloud.console.utils.toConsoleValue import dev.redicloud.repository.java.version.CloudJavaVersion import dev.redicloud.repository.java.version.JavaVersionRepository import dev.redicloud.repository.server.ServerRepository @@ -18,6 +17,7 @@ import dev.redicloud.service.base.suggester.* import dev.redicloud.service.node.repository.node.LOGGER import dev.redicloud.utils.fileName import dev.redicloud.utils.isValidUrl +import dev.redicloud.utils.toConsoleValue import dev.redicloud.utils.toSymbol import java.net.URL import java.util.* @@ -130,9 +130,9 @@ class CloudServerVersionCommand( return } if (version.version.versionTypes.isNotEmpty() && - version.version.versionTypes.none { it.lowercase() == type.name.lowercase() } && + version.version.versionTypes.none { it.equals(type.name, ignoreCase = true) } && version.version.versionTypes.filter { it.startsWith("!") } - .any { it.replaceFirst("!", "").lowercase() == type.name.lowercase() } + .any { it.replaceFirst("!", "").equals(type.name, ignoreCase = true) } ) { actor.sendMessage( "§cThe type ${ @@ -368,7 +368,7 @@ class CloudServerVersionCommand( return } val file = path ?: URL(url).fileName - if (version.defaultFiles.any { it.value.lowercase() == file.lowercase() }) { + if (version.defaultFiles.any { it.value.equals(file, ignoreCase = true) }) { actor.sendMessage( "§cThe file with the url '$url' is already added to the version ${ toConsoleValue( @@ -401,7 +401,7 @@ class CloudServerVersionCommand( ) return } - if (version.defaultFiles.none { it.value.lowercase() == url.lowercase() }) { + if (version.defaultFiles.none { it.value.equals(url, ignoreCase = true) }) { actor.sendMessage( "§cThe file with the url '$url' is not added to the version ${toConsoleValue(version.displayName)}!" ) diff --git a/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/CloudServerVersionTypeCommand.kt b/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/CloudServerVersionTypeCommand.kt index 171d696b..bd1be240 100644 --- a/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/CloudServerVersionTypeCommand.kt +++ b/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/CloudServerVersionTypeCommand.kt @@ -4,7 +4,6 @@ import dev.redicloud.api.commands.* import dev.redicloud.api.utils.CONNECTORS_FOLDER import dev.redicloud.api.version.IServerVersionHandler import dev.redicloud.console.commands.ConsoleActor -import dev.redicloud.console.utils.toConsoleValue import dev.redicloud.repository.server.version.CloudServerVersionRepository import dev.redicloud.repository.server.version.CloudServerVersionType import dev.redicloud.repository.server.version.CloudServerVersionTypeRepository @@ -13,6 +12,7 @@ import dev.redicloud.service.base.suggester.CloudConnectorFileNameSelector import dev.redicloud.service.base.suggester.CloudServerVersionTypeSuggester import dev.redicloud.service.base.suggester.ServerVersionHandlerSuggester import dev.redicloud.utils.* +import dev.redicloud.utils.toConsoleValue import java.io.File import java.net.URL import java.util.* @@ -154,7 +154,7 @@ class CloudServerVersionTypeCommand( return } val file = path ?: URL(url).fileName - if (type.defaultFiles.any { it.value.lowercase() == file.lowercase() }) { + if (type.defaultFiles.any { it.value.equals(file, ignoreCase = true) }) { actor.sendMessage( "§cThe file with the url ${ toConsoleValue( @@ -193,7 +193,7 @@ class CloudServerVersionTypeCommand( @CommandParameter("type", true, CloudServerVersionTypeSuggester::class) type: CloudServerVersionType, @CommandParameter("url") url: String ) { - if (type.defaultFiles.none { it.value.lowercase() == url.lowercase() }) { + if (type.defaultFiles.none { it.value.equals(url, ignoreCase = true) }) { actor.sendMessage( "§cThe file with the url '$url' is not added to the version ${toConsoleValue(type.name)}!" ) diff --git a/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/ClusterCommand.kt b/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/ClusterCommand.kt index 90a46eac..967646b4 100644 --- a/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/ClusterCommand.kt +++ b/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/ClusterCommand.kt @@ -4,7 +4,6 @@ import dev.redicloud.api.commands.* import dev.redicloud.api.service.ServiceId import dev.redicloud.console.animation.impl.line.AnimatedLineAnimation import dev.redicloud.console.commands.ConsoleActor -import dev.redicloud.console.utils.toConsoleValue import dev.redicloud.repository.node.CloudNode import dev.redicloud.repository.server.CloudServer import dev.redicloud.service.base.repository.pingService @@ -13,6 +12,7 @@ import dev.redicloud.service.node.NodeService import dev.redicloud.service.node.repository.node.LOGGER import dev.redicloud.service.node.repository.node.suspendNode import dev.redicloud.utils.* +import dev.redicloud.utils.toConsoleValue import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlin.time.Duration.Companion.milliseconds diff --git a/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/ConfigurationTemplateCommand.kt b/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/ConfigurationTemplateCommand.kt index f599c34d..55372487 100644 --- a/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/ConfigurationTemplateCommand.kt +++ b/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/ConfigurationTemplateCommand.kt @@ -2,7 +2,6 @@ package dev.redicloud.service.node.commands import dev.redicloud.api.commands.* import dev.redicloud.console.commands.ConsoleActor -import dev.redicloud.console.utils.toConsoleValue import dev.redicloud.repository.node.CloudNode import dev.redicloud.repository.node.NodeRepository import dev.redicloud.repository.server.ServerRepository @@ -18,6 +17,7 @@ import dev.redicloud.service.base.suggester.FileTemplateSuggester import dev.redicloud.service.base.suggester.RegisteredCloudNodeSuggester import dev.redicloud.utils.fileName import dev.redicloud.utils.isValidUrl +import dev.redicloud.utils.toConsoleValue import dev.redicloud.utils.toSymbol import java.net.URL import java.util.* @@ -293,7 +293,7 @@ class ConfigurationTemplateCommand( return } val file = path ?: URL(url).fileName - if (template.defaultFiles.any { it.value.lowercase() == file.lowercase() }) { + if (template.defaultFiles.any { it.value.equals(file, ignoreCase = true) }) { actor.sendMessage( "§cThe file with the url ${toConsoleValue( url, @@ -316,7 +316,7 @@ class ConfigurationTemplateCommand( @CommandParameter("name", true, ConfigurationTemplateSuggester::class) template: ConfigurationTemplate, @CommandParameter("url") url: String ) { - if (template.defaultFiles.none { it.value.lowercase() == url.lowercase() }) { + if (template.defaultFiles.none { it.value.equals(url, ignoreCase = true) }) { actor.sendMessage( "§cThe file with the url ${toConsoleValue( url diff --git a/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/FileTemplateCommand.kt b/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/FileTemplateCommand.kt index 13b7ea7f..fc8d586b 100644 --- a/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/FileTemplateCommand.kt +++ b/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/FileTemplateCommand.kt @@ -2,12 +2,12 @@ package dev.redicloud.service.node.commands import dev.redicloud.api.commands.* import dev.redicloud.console.commands.ConsoleActor -import dev.redicloud.console.utils.toConsoleValue import dev.redicloud.repository.node.CloudNode import dev.redicloud.repository.template.file.AbstractFileTemplateRepository import dev.redicloud.repository.template.file.FileTemplate import dev.redicloud.service.base.suggester.ConnectedCloudNodeSuggester import dev.redicloud.service.base.suggester.FileTemplateSuggester +import dev.redicloud.utils.toConsoleValue import java.util.* @Command("filetemplate") diff --git a/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/JavaVersionCommand.kt b/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/JavaVersionCommand.kt index b3a9f19c..65813f95 100644 --- a/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/JavaVersionCommand.kt +++ b/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/JavaVersionCommand.kt @@ -2,7 +2,6 @@ package dev.redicloud.service.node.commands import dev.redicloud.api.commands.* import dev.redicloud.console.commands.ConsoleActor -import dev.redicloud.console.utils.toConsoleValue import dev.redicloud.repository.java.version.CloudJavaVersion import dev.redicloud.repository.java.version.JavaVersionRepository import dev.redicloud.repository.java.version.getVersionInfo @@ -10,6 +9,7 @@ import dev.redicloud.repository.server.version.CloudServerVersionRepository import dev.redicloud.service.base.suggester.JavaVersionSuggester import dev.redicloud.utils.OSType import dev.redicloud.utils.getOperatingSystemType +import dev.redicloud.utils.toConsoleValue import dev.redicloud.utils.toSymbol import java.io.File import java.util.* diff --git a/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/ModuleCommand.kt b/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/ModuleCommand.kt index 8cc53a2d..99f9fbf5 100644 --- a/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/ModuleCommand.kt +++ b/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/ModuleCommand.kt @@ -3,12 +3,12 @@ package dev.redicloud.service.node.commands import dev.redicloud.api.commands.* import dev.redicloud.api.modules.ModuleLifeCycle import dev.redicloud.console.commands.ConsoleActor -import dev.redicloud.console.utils.toConsoleValue import dev.redicloud.modules.ModuleHandler import dev.redicloud.modules.repository.ModuleWebRepository import dev.redicloud.modules.suggesters.* import dev.redicloud.service.base.utils.ClusterConfiguration import dev.redicloud.utils.mapTo +import dev.redicloud.utils.toConsoleValue import dev.redicloud.utils.toSymbol @Command("module") diff --git a/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/ScreenCommand.kt b/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/ScreenCommand.kt index ba6296b6..0e0c4939 100644 --- a/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/ScreenCommand.kt +++ b/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/ScreenCommand.kt @@ -4,9 +4,9 @@ import dev.redicloud.api.commands.* import dev.redicloud.console.Console import dev.redicloud.console.commands.ConsoleActor import dev.redicloud.console.utils.Screen -import dev.redicloud.console.utils.toConsoleValue import dev.redicloud.server.factory.screens.ServerScreen import dev.redicloud.server.factory.screens.ServerScreenSuggester +import dev.redicloud.utils.toConsoleValue @Command("screen") @CommandAlias(["scr"]) diff --git a/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/ServerCommand.kt b/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/ServerCommand.kt index 97fef55b..3982ebf3 100644 --- a/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/ServerCommand.kt +++ b/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/ServerCommand.kt @@ -4,7 +4,6 @@ import dev.redicloud.api.commands.* import dev.redicloud.api.commands.BooleanSuggester import dev.redicloud.api.service.server.CloudServerState import dev.redicloud.console.commands.ConsoleActor -import dev.redicloud.console.utils.toConsoleValue import dev.redicloud.repository.node.CloudNode import dev.redicloud.repository.node.NodeRepository import dev.redicloud.repository.server.CloudServer @@ -14,6 +13,7 @@ import dev.redicloud.server.factory.ServerFactory import dev.redicloud.service.base.suggester.CloudServerSuggester import dev.redicloud.service.base.suggester.ConfigurationTemplateSuggester import dev.redicloud.service.base.suggester.RegisteredCloudNodeSuggester +import dev.redicloud.utils.toConsoleValue import dev.redicloud.utils.toSymbol @Command("server") diff --git a/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/VersionCommand.kt b/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/VersionCommand.kt index 47c79d74..6f396746 100644 --- a/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/VersionCommand.kt +++ b/services/node-service/src/main/kotlin/dev/redicloud/service/node/commands/VersionCommand.kt @@ -9,7 +9,6 @@ import dev.redicloud.api.service.node.ICloudNodeRepository import dev.redicloud.console.Console import dev.redicloud.console.animation.impl.line.AnimatedLineAnimation import dev.redicloud.console.commands.ConsoleActor -import dev.redicloud.console.utils.toConsoleValue import dev.redicloud.service.node.UpgradeOrchestrator import dev.redicloud.service.node.packets.upgrade.ClusterUpgradePacket import dev.redicloud.service.node.packets.upgrade.ClusterUpgradeResponsePacket @@ -18,6 +17,7 @@ import dev.redicloud.updater.Updater import dev.redicloud.updater.suggest.ChannelSuggester import dev.redicloud.updater.suggest.VersionSuggester import dev.redicloud.utils.* +import dev.redicloud.utils.toConsoleValue import dev.redicloud.utils.version.CloudVersion import dev.redicloud.utils.version.VersionChannel import kotlinx.coroutines.delay diff --git a/services/node-service/src/main/kotlin/dev/redicloud/service/node/console/NodeConsole.kt b/services/node-service/src/main/kotlin/dev/redicloud/service/node/console/NodeConsole.kt index bc46c706..af90c338 100644 --- a/services/node-service/src/main/kotlin/dev/redicloud/service/node/console/NodeConsole.kt +++ b/services/node-service/src/main/kotlin/dev/redicloud/service/node/console/NodeConsole.kt @@ -15,12 +15,12 @@ import dev.redicloud.commands.api.PARSERS import dev.redicloud.console.Console import dev.redicloud.console.utils.Screen import dev.redicloud.console.utils.ScreenParser -import dev.redicloud.console.utils.toConsoleValue import dev.redicloud.event.EventManager import dev.redicloud.repository.node.NodeRepository import dev.redicloud.repository.server.CloudServer import dev.redicloud.repository.server.ServerRepository import dev.redicloud.service.node.NodeConfiguration +import dev.redicloud.utils.toConsoleValue import kotlinx.coroutines.launch @Suppress("LongMethod") diff --git a/console/src/main/kotlin/dev/redicloud/console/utils/CommandStringUtils.kt b/utils/src/main/kotlin/dev/redicloud/utils/CommandStringUtils.kt similarity index 82% rename from console/src/main/kotlin/dev/redicloud/console/utils/CommandStringUtils.kt rename to utils/src/main/kotlin/dev/redicloud/utils/CommandStringUtils.kt index de86fdac..a14059c5 100644 --- a/console/src/main/kotlin/dev/redicloud/console/utils/CommandStringUtils.kt +++ b/utils/src/main/kotlin/dev/redicloud/utils/CommandStringUtils.kt @@ -1,4 +1,4 @@ -package dev.redicloud.console.utils +package dev.redicloud.utils fun toConsoleValue(value: Any, colored: Boolean = true): String { return if (colored) { From f03614d4fa133758321338193926d96bdfda3e36 Mon Sep 17 00:00:00 2001 From: paulkczw <44299323+paulkczw@users.noreply.github.com> Date: Thu, 4 Jun 2026 12:36:17 +0200 Subject: [PATCH 5/8] refactor: decouple data layer from console presentation layer --- .../api/version/IVersionHandlerListener.kt | 18 +++ .../utils/ConsoleVersionHandlerListener.kt | 106 ++++++++++++++++++ modules/papermc-updater/build.gradle.kts | 1 - .../module/papermc/PaperMcUpdaterModule.kt | 8 +- repositories/build.gradle.kts | 1 - 5 files changed, 128 insertions(+), 6 deletions(-) create mode 100644 apis/base-api/src/main/kotlin/dev/redicloud/api/version/IVersionHandlerListener.kt create mode 100644 console/src/main/kotlin/dev/redicloud/console/utils/ConsoleVersionHandlerListener.kt diff --git a/apis/base-api/src/main/kotlin/dev/redicloud/api/version/IVersionHandlerListener.kt b/apis/base-api/src/main/kotlin/dev/redicloud/api/version/IVersionHandlerListener.kt new file mode 100644 index 00000000..845ad94d --- /dev/null +++ b/apis/base-api/src/main/kotlin/dev/redicloud/api/version/IVersionHandlerListener.kt @@ -0,0 +1,18 @@ +package dev.redicloud.api.version + +interface IVersionHandlerListener { + + fun onDownloadStart(version: ICloudServerVersion) + + fun onDownloadComplete(version: ICloudServerVersion, error: Boolean) + + fun onPatchStart(version: ICloudServerVersion) + + fun onPatchComplete(version: ICloudServerVersion, error: Boolean) + + fun onProcessStart(name: String, process: Process) + + fun onConnectorDownloadStart(versionType: ICloudServerVersionType) + + fun onConnectorDownloadComplete(versionType: ICloudServerVersionType, error: Boolean) +} diff --git a/console/src/main/kotlin/dev/redicloud/console/utils/ConsoleVersionHandlerListener.kt b/console/src/main/kotlin/dev/redicloud/console/utils/ConsoleVersionHandlerListener.kt new file mode 100644 index 00000000..04b355c9 --- /dev/null +++ b/console/src/main/kotlin/dev/redicloud/console/utils/ConsoleVersionHandlerListener.kt @@ -0,0 +1,106 @@ +package dev.redicloud.console.utils + +import dev.redicloud.api.version.ICloudServerVersion +import dev.redicloud.api.version.ICloudServerVersionType +import dev.redicloud.api.version.IVersionHandlerListener +import dev.redicloud.console.Console +import dev.redicloud.console.animation.impl.line.AnimatedLineAnimation +import dev.redicloud.utils.toConsoleValue + +class ConsoleVersionHandlerListener( + private val console: Console +) : IVersionHandlerListener { + + companion object { + private const val ANIMATION_TICK_MS = 200L + } + + private var downloadCanceled = false + private var downloadDone = false + private var downloadError = false + private var currentDownloadVersion: ICloudServerVersion? = null + + private var patchCanceled = false + private var patchDone = false + private var patchError = false + private var currentPatchVersion: ICloudServerVersion? = null + + private var connectorCanceled = false + private var connectorDone = false + private var connectorError = false + private var currentConnectorType: ICloudServerVersionType? = null + + override fun onDownloadStart(version: ICloudServerVersion) { + downloadCanceled = false + downloadDone = false + downloadError = false + currentDownloadVersion = version + val animation = AnimatedLineAnimation(console, ANIMATION_TICK_MS) { + if (downloadCanceled) { + null + } else if (downloadDone) { + downloadCanceled = true + "Downloaded version %hc%${version.displayName}§8: ${if (downloadError) "§4✘" else "§2✓"}" + } else { + "Downloading version %hc%${version.displayName}§8: %tc%%loading%" + } + } + console.startAnimation(animation) + } + + override fun onDownloadComplete(version: ICloudServerVersion, error: Boolean) { + downloadError = error + downloadDone = true + } + + override fun onPatchStart(version: ICloudServerVersion) { + patchCanceled = false + patchDone = false + patchError = false + currentPatchVersion = version + val animation = AnimatedLineAnimation(console, ANIMATION_TICK_MS) { + if (patchCanceled) { + null + } else if (patchDone) { + patchCanceled = true + "Patching version %tc%${toConsoleValue(version.displayName)}§8: ${if (patchError) "§4✘" else "§2✓"}" + } else { + "Patching version %tc%${toConsoleValue(version.displayName)}§8: %tc%%loading%" + } + } + console.startAnimation(animation) + } + + override fun onPatchComplete(version: ICloudServerVersion, error: Boolean) { + patchError = error + patchDone = true + } + + override fun onProcessStart(name: String, process: Process) { + val screen = console.createScreen(name) + ScreenProcessHandler(process, screen) + } + + override fun onConnectorDownloadStart(versionType: ICloudServerVersionType) { + connectorCanceled = false + connectorDone = false + connectorError = false + currentConnectorType = versionType + val animation = AnimatedLineAnimation(console, ANIMATION_TICK_MS) { + if (connectorCanceled) { + null + } else if (connectorDone) { + connectorCanceled = true + "Downloaded connector ${toConsoleValue(versionType.name)}§8: ${if (connectorError) "§4✘" else "§2✓"}" + } else { + "Downloading connector ${toConsoleValue(versionType.name)}§8: %tc%%loading%" + } + } + console.startAnimation(animation) + } + + override fun onConnectorDownloadComplete(versionType: ICloudServerVersionType, error: Boolean) { + connectorError = error + connectorDone = true + } +} diff --git a/modules/papermc-updater/build.gradle.kts b/modules/papermc-updater/build.gradle.kts index 470e96f6..ab819095 100644 --- a/modules/papermc-updater/build.gradle.kts +++ b/modules/papermc-updater/build.gradle.kts @@ -7,7 +7,6 @@ group = "dev.redicloud.module" dependencies { compileOnly(project(":apis:base-api")) - compileOnly(project(":console")) compileOnly(project(":logging")) compileOnly(project(":utils")) dependency(libs.ktor.client.cio) diff --git a/modules/papermc-updater/src/main/kotlin/dev/redicloud/module/papermc/PaperMcUpdaterModule.kt b/modules/papermc-updater/src/main/kotlin/dev/redicloud/module/papermc/PaperMcUpdaterModule.kt index 1b4febb3..e453bb8d 100644 --- a/modules/papermc-updater/src/main/kotlin/dev/redicloud/module/papermc/PaperMcUpdaterModule.kt +++ b/modules/papermc-updater/src/main/kotlin/dev/redicloud/module/papermc/PaperMcUpdaterModule.kt @@ -10,8 +10,8 @@ import dev.redicloud.api.utils.CloudInjectable import dev.redicloud.api.version.ICloudServerVersionRepository import dev.redicloud.api.version.ICloudServerVersionTypeRepository import dev.redicloud.api.version.IServerVersionHandler +import dev.redicloud.api.version.IVersionHandlerListener import dev.redicloud.api.version.IVersionRepository -import dev.redicloud.console.Console import dev.redicloud.logging.LogManager class PaperMcUpdaterModule : CloudModule(), CloudInjectable { @@ -31,7 +31,7 @@ class PaperMcUpdaterModule : CloudModule(), CloudInjectable { serverVersionTypeRepository: ICloudServerVersionTypeRepository, javaVersionRepository: ICloudJavaVersionRepository, versionRepository: IVersionRepository, - console: Console + listener: IVersionHandlerListener ) { requester = PaperMcApiRequester(versionRepository) handler = PaperMcServerVersionHandler( @@ -39,8 +39,8 @@ class PaperMcUpdaterModule : CloudModule(), CloudInjectable { serverVersionTypeRepository, javaVersionRepository, requester, - console, - logger + logger, + listener = listener ) IServerVersionHandler.registerHandler(handler) } diff --git a/repositories/build.gradle.kts b/repositories/build.gradle.kts index 6f7e3e3a..fa6c54ef 100644 --- a/repositories/build.gradle.kts +++ b/repositories/build.gradle.kts @@ -10,7 +10,6 @@ dependencies { compileOnly(project(":core")) compileOnly(project(":logging")) compileOnly(project(":tasks")) - compileOnly(project(":console")) compileOnly(libs.redisson) dependency(libs.kotlinx.coroutines) From ab4d5d9d44f742ed944c37f55c868bbefca91fa7 Mon Sep 17 00:00:00 2001 From: paulkczw <44299323+paulkczw@users.noreply.github.com> Date: Thu, 4 Jun 2026 12:50:08 +0200 Subject: [PATCH 6/8] docs: add KDoc docstrings to new and refactored files --- .../api/cache/IClusterCacheObject.kt | 6 ++ .../redicloud/api/console/ICloudConsole.kt | 24 +++++++ .../dev/redicloud/api/tasks/ICloudTask.kt | 21 ++++++ .../api/tasks/ICloudTaskExecutorBuilder.kt | 68 +++++++++++++++++++ .../redicloud/api/tasks/ICloudTaskManager.kt | 27 ++++++++ .../api/version/IVersionHandlerListener.kt | 51 ++++++++++++++ .../utils/ConsoleVersionHandlerListener.kt | 8 +++ .../dev/redicloud/cache/ClusterCache.kt | 54 +++++++++++++++ .../cache/packets/CacheMultiUpdatePacket.kt | 8 +++ .../redicloud/cache/packets/CachePacket.kt | 9 +++ .../cache/packets/CacheResetPacket.kt | 5 ++ .../cache/packets/CacheUpdatePacket.kt | 9 +++ .../redicloud/cache/tasks/InvalidCacheTask.kt | 5 ++ .../redicloud/database/DatabaseConnection.kt | 15 ++++ .../dev/redicloud/database/codec/GsonCodec.kt | 14 ++++ .../communication/CommunicationChannel.kt | 9 +++ .../database/config/DatabaseConfiguration.kt | 40 +++++++++++ .../redicloud/database/config/DatabaseNode.kt | 12 ++++ .../database/grid/bucket/DataBucket.kt | 10 +++ .../database/grid/list/SyncedList.kt | 10 +++ .../database/grid/list/SyncedMutableList.kt | 10 +++ .../database/grid/lock/SyncedLock.kt | 9 +++ .../redicloud/database/grid/map/SyncedMap.kt | 11 +++ .../database/grid/map/SyncedMutableMap.kt | 11 +++ .../database/grid/map/cache/SyncedCacheMap.kt | 10 +++ .../grid/map/cache/SyncedCacheMutableMap.kt | 11 +++ .../repository/DatabaseBucketRepository.kt | 55 +++++++++++++++ .../database/repository/DatabaseRepository.kt | 16 +++++ .../dev/redicloud/event/CloudEventPacket.kt | 10 +++ .../dev/redicloud/event/EventHandlerMethod.kt | 8 +++ .../dev/redicloud/event/EventManager.kt | 25 +++++++ .../dev/redicloud/packets/PackedPacket.kt | 6 ++ .../dev/redicloud/packets/PacketManager.kt | 30 ++++++++ .../dev/redicloud/packets/PacketResponse.kt | 9 +++ .../dev/redicloud/utils/CommandStringUtils.kt | 11 +++ 35 files changed, 637 insertions(+) diff --git a/apis/base-api/src/main/kotlin/dev/redicloud/api/cache/IClusterCacheObject.kt b/apis/base-api/src/main/kotlin/dev/redicloud/api/cache/IClusterCacheObject.kt index 3381e26e..dba6060b 100644 --- a/apis/base-api/src/main/kotlin/dev/redicloud/api/cache/IClusterCacheObject.kt +++ b/apis/base-api/src/main/kotlin/dev/redicloud/api/cache/IClusterCacheObject.kt @@ -2,4 +2,10 @@ package dev.redicloud.api.cache import java.io.Serializable +/** + * Marker interface for objects that can be stored in a cluster-wide cache. + * + * Entity classes in the repository layer implement this interface to indicate + * they support cross-node caching with TTL-based invalidation. + */ interface IClusterCacheObject : Serializable diff --git a/apis/base-api/src/main/kotlin/dev/redicloud/api/console/ICloudConsole.kt b/apis/base-api/src/main/kotlin/dev/redicloud/api/console/ICloudConsole.kt index 911c6ae0..42f0ab54 100644 --- a/apis/base-api/src/main/kotlin/dev/redicloud/api/console/ICloudConsole.kt +++ b/apis/base-api/src/main/kotlin/dev/redicloud/api/console/ICloudConsole.kt @@ -2,19 +2,43 @@ package dev.redicloud.api.console import dev.redicloud.api.commands.ICommandManager +/** + * Simplified console interface for cloud modules. + * + * Provides basic console output and command management. Obtain an instance + * via Guice injection. The concrete implementation uses JLine3 for + * terminal I/O and is only active on node services. + */ interface ICloudConsole { + /** The command manager for registering and handling console commands. */ val commandManager: ICommandManager<*> + /** + * Writes a line to the console if printing is enabled. + * + * @param text the text to write (supports color codes with `§`) + * @return this console instance + */ fun writeLine(text: String): ICloudConsole + /** + * Writes a line to the console regardless of the printing state. + * + * @param text the text to write (supports color codes with `§`) + * @return this console instance + */ fun forceWriteLine(text: String): ICloudConsole + /** Clears the console screen. */ fun clearScreen() + /** Enables command input processing. */ fun enableCommands() + /** Disables command input processing. */ fun disableCommands() + /** Returns whether the console supports ANSI color codes. */ fun hasColorSupport(): Boolean } diff --git a/apis/base-api/src/main/kotlin/dev/redicloud/api/tasks/ICloudTask.kt b/apis/base-api/src/main/kotlin/dev/redicloud/api/tasks/ICloudTask.kt index 2fba4de5..0873fbb9 100644 --- a/apis/base-api/src/main/kotlin/dev/redicloud/api/tasks/ICloudTask.kt +++ b/apis/base-api/src/main/kotlin/dev/redicloud/api/tasks/ICloudTask.kt @@ -2,17 +2,38 @@ package dev.redicloud.api.tasks import java.util.UUID +/** + * Represents a schedulable cloud task that can be registered with [ICloudTaskManager]. + * + * Tasks define work to be executed on various triggers (instant, delayed, periodic, + * event-based, or packet-based) via [ICloudTaskExecutorBuilder]. + */ interface ICloudTask { + /** Unique identifier for this task. */ val id: UUID + /** + * Executes the task logic. + * + * @return `true` if the task should be automatically canceled after execution, + * `false` to keep the task active for further executions. + */ suspend fun execute(): Boolean + /** Returns whether this task has been canceled. */ fun isCanceled(): Boolean + /** Returns whether this task has been started by a [ICloudTaskManager]. */ fun isStarted(): Boolean + /** Cancels this task and all its executors. */ fun cancel() + /** + * Registers a callback that is invoked when the task finishes. + * + * @param block the callback to invoke on finish + */ fun onFinished(block: () -> Unit) } diff --git a/apis/base-api/src/main/kotlin/dev/redicloud/api/tasks/ICloudTaskExecutorBuilder.kt b/apis/base-api/src/main/kotlin/dev/redicloud/api/tasks/ICloudTaskExecutorBuilder.kt index b1cfc845..554a8848 100644 --- a/apis/base-api/src/main/kotlin/dev/redicloud/api/tasks/ICloudTaskExecutorBuilder.kt +++ b/apis/base-api/src/main/kotlin/dev/redicloud/api/tasks/ICloudTaskExecutorBuilder.kt @@ -5,23 +5,91 @@ import dev.redicloud.api.packets.AbstractPacket import kotlin.reflect.KClass import kotlin.time.Duration +/** + * Builder for configuring execution triggers on a [ICloudTask]. + * + * Supports multiple trigger types that can be combined: + * - [instant] -- execute immediately + * - [delay] -- execute after a delay + * - [atTime] -- execute at a specific timestamp + * - [period] -- execute periodically + * - [event] -- execute when a [CloudEvent] fires + * - [packet] -- execute when a packet is received + * + * Call [register] to finalize and start the task. + */ interface ICloudTaskExecutorBuilder { + /** + * Sets the task to be executed. + * + * @param task the task instance + * @return this builder + */ fun task(task: ICloudTask): ICloudTaskExecutorBuilder + /** + * Adds an instant executor that runs the task immediately upon registration. + * + * @return this builder + */ fun instant(): ICloudTaskExecutorBuilder + /** + * Adds an executor that runs the task at a specific timestamp. + * + * @param atTime the Unix timestamp (milliseconds) at which to execute + * @return this builder + * @throws IllegalArgumentException if [atTime] is in the past + */ fun atTime(atTime: Long): ICloudTaskExecutorBuilder + /** + * Adds an executor that runs the task after a delay. + * + * @param delay the delay in milliseconds + * @return this builder + */ fun delay(delay: Long): ICloudTaskExecutorBuilder + /** + * Adds an executor that runs the task after a delay. + * + * @param duration the delay duration + * @return this builder + */ fun delay(duration: Duration): ICloudTaskExecutorBuilder + /** + * Adds a periodic executor that runs the task at a fixed interval. + * + * @param period the interval between executions + * @param maxExecutions the maximum number of executions, or `-1` for unlimited + * @return this builder + */ fun period(period: Duration, maxExecutions: Int = -1): ICloudTaskExecutorBuilder + /** + * Adds an event-based executor that runs the task when the specified event fires. + * + * @param eventClazz the event class to listen for + * @return this builder + */ fun event(eventClazz: KClass): ICloudTaskExecutorBuilder + /** + * Adds a packet-based executor that runs the task when the specified packet is received. + * + * @param packetClazz the packet class to listen for + * @return this builder + */ fun packet(packetClazz: KClass): ICloudTaskExecutorBuilder + /** + * Registers the task with all configured executors and starts execution. + * + * @return the registered task + * @throws IllegalStateException if no task or executors have been set + */ fun register(): ICloudTask } diff --git a/apis/base-api/src/main/kotlin/dev/redicloud/api/tasks/ICloudTaskManager.kt b/apis/base-api/src/main/kotlin/dev/redicloud/api/tasks/ICloudTaskManager.kt index 34650f0f..817a368f 100644 --- a/apis/base-api/src/main/kotlin/dev/redicloud/api/tasks/ICloudTaskManager.kt +++ b/apis/base-api/src/main/kotlin/dev/redicloud/api/tasks/ICloudTaskManager.kt @@ -2,15 +2,42 @@ package dev.redicloud.api.tasks import java.util.UUID +/** + * Manages the lifecycle of [ICloudTask] instances. + * + * Provides registration, unregistration, and a builder API for configuring + * task execution triggers. Obtain an instance via Guice injection. + */ interface ICloudTaskManager { + /** + * Registers and starts a task. + * + * @param task the task to register + * @return the unique ID of the registered task + * @throws IllegalArgumentException if a task with the same ID is already registered + */ fun register(task: ICloudTask): UUID + /** + * Unregisters and cancels a task by its ID. + * + * @param id the unique ID of the task + * @return the unregistered task, or `null` if not found + */ fun unregister(id: UUID): ICloudTask? + /** + * Unregisters and cancels a task. + * + * @param task the task to unregister + * @return the unregistered task, or `null` if not found + */ fun unregister(task: ICloudTask): ICloudTask? + /** Returns all currently registered tasks. */ fun getTasks(): List + /** Creates a new builder for configuring and registering a task with executors. */ fun builder(): ICloudTaskExecutorBuilder } diff --git a/apis/base-api/src/main/kotlin/dev/redicloud/api/version/IVersionHandlerListener.kt b/apis/base-api/src/main/kotlin/dev/redicloud/api/version/IVersionHandlerListener.kt index 845ad94d..693bb6ae 100644 --- a/apis/base-api/src/main/kotlin/dev/redicloud/api/version/IVersionHandlerListener.kt +++ b/apis/base-api/src/main/kotlin/dev/redicloud/api/version/IVersionHandlerListener.kt @@ -1,18 +1,69 @@ package dev.redicloud.api.version +/** + * Listener for server version handler lifecycle events. + * + * Implementations receive callbacks during download, patch, and connector + * operations. This decouples the data/repository layer from the presentation + * layer -- the console module provides a concrete implementation that + * displays progress animations. + * + * Obtain an instance via Guice injection on node services. + */ interface IVersionHandlerListener { + /** + * Called when a server version download starts. + * + * @param version the version being downloaded + */ fun onDownloadStart(version: ICloudServerVersion) + /** + * Called when a server version download completes. + * + * @param version the version that was downloaded + * @param error `true` if the download failed + */ fun onDownloadComplete(version: ICloudServerVersion, error: Boolean) + /** + * Called when a server version patch starts. + * + * @param version the version being patched + */ fun onPatchStart(version: ICloudServerVersion) + /** + * Called when a server version patch completes. + * + * @param version the version that was patched + * @param error `true` if the patch failed + */ fun onPatchComplete(version: ICloudServerVersion, error: Boolean) + /** + * Called when a subprocess is started during patching. + * + * Implementations may capture the process output for display. + * + * @param name a descriptive name for the process (e.g. `"patch_paper-1.20"`) + * @param process the running subprocess + */ fun onProcessStart(name: String, process: Process) + /** + * Called when a connector download starts. + * + * @param versionType the server version type whose connector is being downloaded + */ fun onConnectorDownloadStart(versionType: ICloudServerVersionType) + /** + * Called when a connector download completes. + * + * @param versionType the server version type whose connector was downloaded + * @param error `true` if the download failed + */ fun onConnectorDownloadComplete(versionType: ICloudServerVersionType, error: Boolean) } diff --git a/console/src/main/kotlin/dev/redicloud/console/utils/ConsoleVersionHandlerListener.kt b/console/src/main/kotlin/dev/redicloud/console/utils/ConsoleVersionHandlerListener.kt index 04b355c9..48c2698a 100644 --- a/console/src/main/kotlin/dev/redicloud/console/utils/ConsoleVersionHandlerListener.kt +++ b/console/src/main/kotlin/dev/redicloud/console/utils/ConsoleVersionHandlerListener.kt @@ -7,6 +7,14 @@ import dev.redicloud.console.Console import dev.redicloud.console.animation.impl.line.AnimatedLineAnimation import dev.redicloud.utils.toConsoleValue +/** + * Console-based implementation of [IVersionHandlerListener]. + * + * Displays animated progress indicators and captures subprocess output + * in console screens during version download, patch, and connector operations. + * + * @param console the console instance for rendering animations and screens + */ class ConsoleVersionHandlerListener( private val console: Console ) : IVersionHandlerListener { diff --git a/core/src/main/kotlin/dev/redicloud/cache/ClusterCache.kt b/core/src/main/kotlin/dev/redicloud/cache/ClusterCache.kt index 446f098d..64d86032 100644 --- a/core/src/main/kotlin/dev/redicloud/cache/ClusterCache.kt +++ b/core/src/main/kotlin/dev/redicloud/cache/ClusterCache.kt @@ -15,6 +15,22 @@ import kotlin.reflect.KClass import kotlin.reflect.full.isSubclassOf import kotlin.time.Duration +/** + * Cluster-wide in-memory cache with time-based expiration and cross-node synchronization. + * + * Cached values are kept locally in a [ConcurrentHashMap] and changes are broadcast + * to other nodes via [CacheUpdatePacket], [CacheMultiUpdatePacket], and [CacheResetPacket]. + * Only service types listed in [serviceTypes] will participate in caching. + * + * @param V the cached value type, must implement [IClusterCacheObject] + * @param name a unique name identifying this cache across the cluster + * @param serviceId the identity of the owning service + * @param cacheClass the KClass of the cached value type + * @param cacheDuration how long cached entries remain valid + * @param packetManager the packet manager used to broadcast cache updates + * @param scope the coroutine scope for launching broadcast operations + * @param serviceTypes the service types that should participate in this cache + */ class ClusterCache( val name: String, val serviceId: ServiceId, @@ -42,16 +58,30 @@ class ClusterCache( } companion object { + /** Global registry of all active cluster caches, keyed by cache name. */ val CACHES = mutableMapOf>() } private val cache = ConcurrentHashMap>() + /** + * Retrieves a cached value by key. + * + * @param key the cache key + * @return the cached value, or null if not cached or service type doesn't match + */ fun get(key: String): V? { if (serviceTypes.none { it == serviceId.type }) return null return cache[key]?.second } + /** + * Retrieves a cached value by key, populating the cache via [block] on a miss. + * + * @param key the cache key + * @param block supplier invoked to compute the value if not cached + * @return the cached or freshly computed value, or null + */ fun get(key: String, block: () -> V?): V? { if (serviceTypes.none { it == serviceId.type }) return null if (!isCached(key)) { @@ -60,6 +90,12 @@ class ClusterCache( return get(key) } + /** + * Updates a single cache entry and broadcasts the change to other nodes. + * + * @param key the cache key + * @param value the new value, or null to remove the entry + */ fun updateCache(key: String, value: Any?) { if (value == null) { if (!isCached(key)) return @@ -79,6 +115,11 @@ class ClusterCache( } } + /** + * Updates multiple cache entries at once and broadcasts the changes to other nodes. + * + * @param toUpdate a map of cache keys to their new values (null to remove) + */ fun updateCache(toUpdate: Map) { if (toUpdate.isEmpty()) return toUpdate.forEach { @@ -92,6 +133,7 @@ class ClusterCache( } } + /** Clears all local cache entries and broadcasts a reset to other nodes. */ fun clearCache() { cache.clear() scope.launch { @@ -101,10 +143,22 @@ class ClusterCache( } } + /** + * Returns a snapshot of all cached entries as a simple key-to-value map. + * + * @return an immutable view of the current cache contents + */ fun getCache(): Map { return cache.mapValues { it.value.second } } + /** + * Checks whether a key is cached, optionally validating expiration. + * + * @param key the cache key + * @param validCheck if true (default), also checks that the entry has not expired + * @return true if the key is present (and valid, if [validCheck] is true) + */ fun isCached(key: String, validCheck: Boolean = true): Boolean { if (serviceTypes.none { it == serviceId.type }) return false return if (validCheck) isCacheValid(key) else isCached(key) diff --git a/core/src/main/kotlin/dev/redicloud/cache/packets/CacheMultiUpdatePacket.kt b/core/src/main/kotlin/dev/redicloud/cache/packets/CacheMultiUpdatePacket.kt index 9edb4291..a7f4ee69 100644 --- a/core/src/main/kotlin/dev/redicloud/cache/packets/CacheMultiUpdatePacket.kt +++ b/core/src/main/kotlin/dev/redicloud/cache/packets/CacheMultiUpdatePacket.kt @@ -3,6 +3,14 @@ package dev.redicloud.cache.packets import dev.redicloud.api.packets.IPacketManager import dev.redicloud.utils.gson.gson +/** + * Packet that updates multiple entries in a cluster cache in a single operation. + * + * When received, deserializes each value from JSON and applies all updates to the local cache. + * Null values in [toUpdate] remove the corresponding entries. + * + * @property toUpdate a map of cache keys to their JSON-serialized new values (null to remove) + */ class CacheMultiUpdatePacket( name: String, val toUpdate: Map diff --git a/core/src/main/kotlin/dev/redicloud/cache/packets/CachePacket.kt b/core/src/main/kotlin/dev/redicloud/cache/packets/CachePacket.kt index ad20c279..291b5896 100644 --- a/core/src/main/kotlin/dev/redicloud/cache/packets/CachePacket.kt +++ b/core/src/main/kotlin/dev/redicloud/cache/packets/CachePacket.kt @@ -6,10 +6,19 @@ import dev.redicloud.api.packets.AbstractPacket import dev.redicloud.api.packets.IPacketManager import dev.redicloud.cache.ClusterCache +/** + * Base packet for cluster cache operations. + * + * Resolves the target [ClusterCache] by [cacheName] upon reception. + * Subclasses implement the specific cache mutation logic. + * + * @property cacheName the name of the target cluster cache + */ abstract class CachePacket( val cacheName: String ) : AbstractPacket() { + /** The resolved cache instance, populated on [received]. Null if no matching cache is registered. */ @Expose(deserialize = false, serialize = false) var cache: ClusterCache? = null diff --git a/core/src/main/kotlin/dev/redicloud/cache/packets/CacheResetPacket.kt b/core/src/main/kotlin/dev/redicloud/cache/packets/CacheResetPacket.kt index 4444aa7c..fec5dbe0 100644 --- a/core/src/main/kotlin/dev/redicloud/cache/packets/CacheResetPacket.kt +++ b/core/src/main/kotlin/dev/redicloud/cache/packets/CacheResetPacket.kt @@ -2,6 +2,11 @@ package dev.redicloud.cache.packets import dev.redicloud.api.packets.IPacketManager +/** + * Packet that clears all entries in a cluster cache. + * + * When received, resets the entire local cache identified by the cache name. + */ class CacheResetPacket( name: String ) : CachePacket(name) { diff --git a/core/src/main/kotlin/dev/redicloud/cache/packets/CacheUpdatePacket.kt b/core/src/main/kotlin/dev/redicloud/cache/packets/CacheUpdatePacket.kt index febdd736..2dd3a21b 100644 --- a/core/src/main/kotlin/dev/redicloud/cache/packets/CacheUpdatePacket.kt +++ b/core/src/main/kotlin/dev/redicloud/cache/packets/CacheUpdatePacket.kt @@ -3,6 +3,15 @@ package dev.redicloud.cache.packets import dev.redicloud.api.packets.IPacketManager import dev.redicloud.utils.gson.gson +/** + * Packet that updates a single entry in a cluster cache. + * + * When received, deserializes the value from JSON and updates the local cache. + * A null [valueJson] removes the entry from the cache. + * + * @property key the cache key to update + * @property valueJson the JSON-serialized new value, or null to remove the entry + */ class CacheUpdatePacket( name: String, val key: String, diff --git a/core/src/main/kotlin/dev/redicloud/cache/tasks/InvalidCacheTask.kt b/core/src/main/kotlin/dev/redicloud/cache/tasks/InvalidCacheTask.kt index 19a68fe9..a7d02357 100644 --- a/core/src/main/kotlin/dev/redicloud/cache/tasks/InvalidCacheTask.kt +++ b/core/src/main/kotlin/dev/redicloud/cache/tasks/InvalidCacheTask.kt @@ -3,6 +3,11 @@ package dev.redicloud.cache.tasks import dev.redicloud.cache.ClusterCache import dev.redicloud.tasks.CloudTask +/** + * Periodic task that evicts expired entries from all registered cluster caches. + * + * Iterates over every [ClusterCache] and removes entries whose cache duration has elapsed. + */ class InvalidCacheTask : CloudTask() { override suspend fun execute(): Boolean { diff --git a/core/src/main/kotlin/dev/redicloud/database/DatabaseConnection.kt b/core/src/main/kotlin/dev/redicloud/database/DatabaseConnection.kt index a472fcf2..8ceed977 100644 --- a/core/src/main/kotlin/dev/redicloud/database/DatabaseConnection.kt +++ b/core/src/main/kotlin/dev/redicloud/database/DatabaseConnection.kt @@ -29,6 +29,20 @@ import org.redisson.Redisson import org.redisson.api.RedissonClient import org.redisson.config.Config +/** + * Redisson-based implementation of [IDatabaseConnection]. + * + * Manages connection to a Redis instance (single or cluster mode) and provides + * factory methods for distributed data structures such as maps, lists, locks, and buckets. + * Connection pool sizes are automatically halved for Minecraft server service types. + * + * @param config the database configuration containing nodes, credentials, and mode + * @param serviceId the identity of the service owning this connection + * @param connectionPoolSize maximum number of connections in the pool + * @param connectionMinimumIdleSize minimum number of idle connections maintained + * @param subscriptionConnectionPoolSize maximum number of subscription connections + * @param subscriptionConnectionMinimumIdleSize minimum number of idle subscription connections + */ class DatabaseConnection( config: DatabaseConfiguration, override val serviceId: ServiceId, @@ -174,6 +188,7 @@ class DatabaseConnection( return DataBucket(key, this) } + /** The underlying Redisson client. Throws if not connected. */ val client: RedissonClient get() = _client ?: error("Not connected to redis!") } diff --git a/core/src/main/kotlin/dev/redicloud/database/codec/GsonCodec.kt b/core/src/main/kotlin/dev/redicloud/database/codec/GsonCodec.kt index 435cb202..bd78732e 100644 --- a/core/src/main/kotlin/dev/redicloud/database/codec/GsonCodec.kt +++ b/core/src/main/kotlin/dev/redicloud/database/codec/GsonCodec.kt @@ -11,6 +11,13 @@ import org.redisson.client.protocol.Decoder import org.redisson.client.protocol.Encoder import java.nio.charset.Charset +/** + * Redisson codec that uses Gson for serialization and deserialization. + * + * Each value is wrapped in a [GsonPackage] containing the fully-qualified class name + * and the JSON representation, enabling type-safe deserialization without prior + * knowledge of the stored type. + */ object GsonCodec : BaseCodec() { private val charset: Charset = Charsets.UTF_8 @@ -44,6 +51,13 @@ object GsonCodec : BaseCodec() { override fun getValueDecoder() = decoder } +/** + * Wrapper that pairs a serialized JSON value with its originating class name + * for type-safe deserialization by [GsonCodec]. + * + * @property clazz the fully-qualified class name of the serialized object + * @property json the JSON representation of the object + */ data class GsonPackage( val clazz: String, val json: JsonElement diff --git a/core/src/main/kotlin/dev/redicloud/database/communication/CommunicationChannel.kt b/core/src/main/kotlin/dev/redicloud/database/communication/CommunicationChannel.kt index ae800788..3f5891aa 100644 --- a/core/src/main/kotlin/dev/redicloud/database/communication/CommunicationChannel.kt +++ b/core/src/main/kotlin/dev/redicloud/database/communication/CommunicationChannel.kt @@ -4,6 +4,15 @@ import dev.redicloud.api.database.communication.IChannelListener import dev.redicloud.api.database.communication.ICommunicationChannel import dev.redicloud.database.DatabaseConnection +/** + * Pub/Sub communication channel backed by a Redisson topic. + * + * Allows publishing messages and subscribing/unsubscribing listeners + * on a named Redis topic. + * + * @param name the name of the Redis topic + * @param databaseConnection the database connection providing the Redisson client + */ class CommunicationChannel( override val name: String, databaseConnection: DatabaseConnection diff --git a/core/src/main/kotlin/dev/redicloud/database/config/DatabaseConfiguration.kt b/core/src/main/kotlin/dev/redicloud/database/config/DatabaseConfiguration.kt index 80c8c905..5dbd3ec9 100644 --- a/core/src/main/kotlin/dev/redicloud/database/config/DatabaseConfiguration.kt +++ b/core/src/main/kotlin/dev/redicloud/database/config/DatabaseConfiguration.kt @@ -3,6 +3,17 @@ package dev.redicloud.database.config import dev.redicloud.utils.gson.gson import java.io.File +/** + * Configuration for connecting to a Redis database. + * + * Supports both single-node and cluster mode. The mode is determined + * automatically based on the number of [nodes] provided. + * + * @property username optional Redis username for authentication + * @property password optional Redis password for authentication + * @property nodes the list of Redis nodes to connect to + * @property databaseId the Redis database index (single-node mode only) + */ data class DatabaseConfiguration( val username: String? = "", val password: String? = "", @@ -10,11 +21,24 @@ data class DatabaseConfiguration( val databaseId: Int = 0 ) { + /** + * Determines whether this configuration targets a Redis cluster. + * + * @return true if more than one node is configured + */ fun isCluster(): Boolean = nodes.size > 1 companion object { private const val DEFAULT_REDIS_PORT = 6379 + /** + * Creates a [DatabaseConfiguration] from environment variables. + * + * Reads `RC_DATABASE_PASSWORD`, `RC_DATABASE_ID`, `RC_DATABASE_USERNAME`, + * and `RC_DATABASE_NODES` (semicolon-separated `host:port` pairs). + * + * @return the configuration built from environment variables + */ fun fromEnv(): DatabaseConfiguration { val password = System.getenv("RC_DATABASE_PASSWORD") ?: "" val databaseId = System.getenv("RC_DATABASE_ID")?.toInt() ?: 0 @@ -26,12 +50,23 @@ data class DatabaseConfiguration( return DatabaseConfiguration(username, password, nodes, databaseId) } + /** + * Deserializes a [DatabaseConfiguration] from a JSON file. + * + * @param file the JSON file to read + * @return the parsed configuration + */ fun fromFile(file: File): DatabaseConfiguration { return gson.fromJson(file.readText(Charsets.UTF_8), DatabaseConfiguration::class.java) } } } +/** + * Exports this configuration to environment variables on the given [ProcessBuilder]. + * + * @param processBuilder the process builder whose environment will be populated + */ fun DatabaseConfiguration.toEnv(processBuilder: ProcessBuilder) { processBuilder.environment()["RC_DATABASE_PASSWORD"] = password processBuilder.environment()["RC_DATABASE_ID"] = databaseId.toString() @@ -39,6 +74,11 @@ fun DatabaseConfiguration.toEnv(processBuilder: ProcessBuilder) { processBuilder.environment()["RC_DATABASE_USERNAME"] = username } +/** + * Serializes this configuration to a JSON file, replacing it if it already exists. + * + * @param file the target file to write to + */ fun DatabaseConfiguration.toFile(file: File) { if (file.exists()) file.delete() file.createNewFile() diff --git a/core/src/main/kotlin/dev/redicloud/database/config/DatabaseNode.kt b/core/src/main/kotlin/dev/redicloud/database/config/DatabaseNode.kt index 9ce0fcf7..431681b8 100644 --- a/core/src/main/kotlin/dev/redicloud/database/config/DatabaseNode.kt +++ b/core/src/main/kotlin/dev/redicloud/database/config/DatabaseNode.kt @@ -1,9 +1,21 @@ package dev.redicloud.database.config +/** + * Represents a single Redis node endpoint. + * + * @property hostname the hostname or IP address of the Redis node + * @property port the port number of the Redis node + * @property ssl whether to use SSL/TLS for the connection + */ data class DatabaseNode( val hostname: String, val port: Int, val ssl: Boolean = false ) { + /** + * Builds a Redis connection URI string. + * + * @return a URI in the format `redis://host:port` or `rediss://host:port` if SSL is enabled + */ fun toConnectionString(): String = "redis${if (ssl) "s" else ""}://$hostname:$port" } diff --git a/core/src/main/kotlin/dev/redicloud/database/grid/bucket/DataBucket.kt b/core/src/main/kotlin/dev/redicloud/database/grid/bucket/DataBucket.kt index c3151f65..c003908e 100644 --- a/core/src/main/kotlin/dev/redicloud/database/grid/bucket/DataBucket.kt +++ b/core/src/main/kotlin/dev/redicloud/database/grid/bucket/DataBucket.kt @@ -4,6 +4,16 @@ import dev.redicloud.api.database.grid.bucket.IDataBucket import dev.redicloud.database.DatabaseConnection import kotlin.time.Duration +/** + * A data bucket backed by a Redisson bucket, providing atomic get/set/delete + * operations on a single Redis key. + * + * Supports expiration, conditional set (if-exists / if-absent), and get-and-modify operations. + * + * @param V the value type stored in this bucket + * @param key the Redis key identifying this bucket + * @param databaseConnection the database connection providing the Redisson client + */ class DataBucket( override val key: String, databaseConnection: DatabaseConnection diff --git a/core/src/main/kotlin/dev/redicloud/database/grid/list/SyncedList.kt b/core/src/main/kotlin/dev/redicloud/database/grid/list/SyncedList.kt index f6fc5cc3..fbb7d332 100644 --- a/core/src/main/kotlin/dev/redicloud/database/grid/list/SyncedList.kt +++ b/core/src/main/kotlin/dev/redicloud/database/grid/list/SyncedList.kt @@ -4,11 +4,21 @@ import dev.redicloud.api.database.grid.list.ISyncedList import dev.redicloud.database.DatabaseConnection import org.redisson.api.RList +/** + * Read-only list backed by a Redisson [RList], synchronized with Redis. + * + * All read operations delegate directly to the distributed list identified by [key]. + * + * @param E the element type + * @param key the Redis key identifying this list + * @param databaseConnection the database connection providing the Redisson client + */ open class SyncedList( final override val key: String, databaseConnection: DatabaseConnection ) : ISyncedList { + /** The underlying Redisson list handle. */ protected val handle: RList = databaseConnection.client.getList(key) override val size: Int diff --git a/core/src/main/kotlin/dev/redicloud/database/grid/list/SyncedMutableList.kt b/core/src/main/kotlin/dev/redicloud/database/grid/list/SyncedMutableList.kt index 611abd48..932dd978 100644 --- a/core/src/main/kotlin/dev/redicloud/database/grid/list/SyncedMutableList.kt +++ b/core/src/main/kotlin/dev/redicloud/database/grid/list/SyncedMutableList.kt @@ -3,6 +3,16 @@ package dev.redicloud.database.grid.list import dev.redicloud.api.database.grid.list.ISyncedMutableList import dev.redicloud.database.DatabaseConnection +/** + * Mutable list backed by a Redisson [org.redisson.api.RList], synchronized with Redis. + * + * Extends [SyncedList] with write operations (add, remove, set, clear) that are + * reflected in the distributed Redis store. + * + * @param E the element type + * @param key the Redis key identifying this list + * @param databaseConnection the database connection providing the Redisson client + */ class SyncedMutableList( key: String, databaseConnection: DatabaseConnection diff --git a/core/src/main/kotlin/dev/redicloud/database/grid/lock/SyncedLock.kt b/core/src/main/kotlin/dev/redicloud/database/grid/lock/SyncedLock.kt index 7e20fcd1..b0f0e58a 100644 --- a/core/src/main/kotlin/dev/redicloud/database/grid/lock/SyncedLock.kt +++ b/core/src/main/kotlin/dev/redicloud/database/grid/lock/SyncedLock.kt @@ -5,6 +5,15 @@ import dev.redicloud.database.DatabaseConnection import java.util.concurrent.TimeUnit import kotlin.time.Duration +/** + * Distributed lock backed by a Redisson lock, synchronized across the Redis cluster. + * + * Provides locking, unlocking, and introspection operations on a named lock + * identified by [key]. + * + * @param key the Redis key identifying this lock + * @param databaseConnection the database connection providing the Redisson client + */ class SyncedLock( override val key: String, databaseConnection: DatabaseConnection diff --git a/core/src/main/kotlin/dev/redicloud/database/grid/map/SyncedMap.kt b/core/src/main/kotlin/dev/redicloud/database/grid/map/SyncedMap.kt index 4db737ec..dbbc3d04 100644 --- a/core/src/main/kotlin/dev/redicloud/database/grid/map/SyncedMap.kt +++ b/core/src/main/kotlin/dev/redicloud/database/grid/map/SyncedMap.kt @@ -4,11 +4,22 @@ import dev.redicloud.api.database.grid.map.ISyncedMap import dev.redicloud.database.DatabaseConnection import org.redisson.api.RMap +/** + * Read-only map backed by a Redisson [RMap], synchronized with Redis. + * + * All read operations delegate directly to the distributed map identified by [key]. + * + * @param K the key type + * @param V the value type + * @param key the Redis key identifying this map + * @param databaseConnection the database connection providing the Redisson client + */ open class SyncedMap( final override val key: String, databaseConnection: DatabaseConnection ) : ISyncedMap { + /** The underlying Redisson map handle. */ protected val handle: RMap = databaseConnection.client.getMap(key) override val size: Int diff --git a/core/src/main/kotlin/dev/redicloud/database/grid/map/SyncedMutableMap.kt b/core/src/main/kotlin/dev/redicloud/database/grid/map/SyncedMutableMap.kt index 229cdabb..a16a3355 100644 --- a/core/src/main/kotlin/dev/redicloud/database/grid/map/SyncedMutableMap.kt +++ b/core/src/main/kotlin/dev/redicloud/database/grid/map/SyncedMutableMap.kt @@ -3,6 +3,17 @@ package dev.redicloud.database.grid.map import dev.redicloud.api.database.grid.map.ISyncedMutableMap import dev.redicloud.database.DatabaseConnection +/** + * Mutable map backed by a Redisson [org.redisson.api.RMap], synchronized with Redis. + * + * Extends [SyncedMap] with write operations (put, remove, clear) that are + * reflected in the distributed Redis store. + * + * @param K the key type + * @param V the value type + * @param key the Redis key identifying this map + * @param databaseConnection the database connection providing the Redisson client + */ class SyncedMutableMap( key: String, databaseConnection: DatabaseConnection diff --git a/core/src/main/kotlin/dev/redicloud/database/grid/map/cache/SyncedCacheMap.kt b/core/src/main/kotlin/dev/redicloud/database/grid/map/cache/SyncedCacheMap.kt index 8078bfe6..500c2087 100644 --- a/core/src/main/kotlin/dev/redicloud/database/grid/map/cache/SyncedCacheMap.kt +++ b/core/src/main/kotlin/dev/redicloud/database/grid/map/cache/SyncedCacheMap.kt @@ -4,6 +4,16 @@ import dev.redicloud.api.database.grid.map.cache.ISyncedCacheMap import dev.redicloud.database.DatabaseConnection import dev.redicloud.database.grid.map.SyncedMap +/** + * Read-only cached map backed by a Redisson map, synchronized with Redis. + * + * Combines [SyncedMap] read semantics with the [ISyncedCacheMap] cache contract. + * + * @param K the key type + * @param V the value type + * @param key the Redis key identifying this map + * @param databaseConnection the database connection providing the Redisson client + */ open class SyncedCacheMap( key: String, databaseConnection: DatabaseConnection diff --git a/core/src/main/kotlin/dev/redicloud/database/grid/map/cache/SyncedCacheMutableMap.kt b/core/src/main/kotlin/dev/redicloud/database/grid/map/cache/SyncedCacheMutableMap.kt index a85931af..5937627f 100644 --- a/core/src/main/kotlin/dev/redicloud/database/grid/map/cache/SyncedCacheMutableMap.kt +++ b/core/src/main/kotlin/dev/redicloud/database/grid/map/cache/SyncedCacheMutableMap.kt @@ -3,6 +3,17 @@ package dev.redicloud.database.grid.map.cache import dev.redicloud.api.database.grid.map.cache.ISyncedCacheMutableMap import dev.redicloud.database.DatabaseConnection +/** + * Mutable cached map backed by a Redisson map, synchronized with Redis. + * + * Extends [SyncedCacheMap] with write operations that propagate to the + * distributed Redis store. + * + * @param K the key type + * @param V the value type + * @param key the Redis key identifying this map + * @param databaseConnection the database connection providing the Redisson client + */ class SyncedCacheMutableMap( key: String, databaseConnection: DatabaseConnection diff --git a/core/src/main/kotlin/dev/redicloud/database/repository/DatabaseBucketRepository.kt b/core/src/main/kotlin/dev/redicloud/database/repository/DatabaseBucketRepository.kt index 108aea4e..6208a4b6 100644 --- a/core/src/main/kotlin/dev/redicloud/database/repository/DatabaseBucketRepository.kt +++ b/core/src/main/kotlin/dev/redicloud/database/repository/DatabaseBucketRepository.kt @@ -7,6 +7,20 @@ import kotlin.reflect.KClass import kotlin.reflect.cast import kotlin.reflect.full.isSubclassOf +/** + * A repository that stores entities as Redis buckets, mapping an interface type [I] + * to its implementation type [K]. + * + * Automatically registers the interface-to-implementation mapping with the Gson + * interface factory for proper deserialization. All keys are prefixed with `cloud::`. + * + * @param I the interface type used for bucket storage + * @param K the implementation type (must be a subclass of [I]) + * @param connection the active database connection + * @param name the repository key prefix + * @param interfaceClass the KClass of the interface type + * @param implementationClass the KClass of the implementation type + */ open class DatabaseBucketRepository( connection: IDatabaseConnection, name: String, @@ -23,6 +37,12 @@ open class DatabaseBucketRepository( } private val unsafe get() = UnsafeDatabaseBucketRepository(this) + + /** + * Returns an unsafe accessor that exposes all CRUD operations publicly. + * + * @return an [UnsafeDatabaseBucketRepository] wrapping this repository + */ fun unsafe() = unsafe protected open suspend fun set(identifier: String, value: I): K { @@ -61,18 +81,53 @@ open class DatabaseBucketRepository( return connection.getBucket(databaseIdentifier) } + /** + * Publicly exposes all CRUD operations of a [DatabaseBucketRepository]. + * + * Use with caution since it bypasses any access restrictions defined + * by the enclosing repository's protected methods. + * + * @param I the interface type + * @param K the implementation type + * @param repository the underlying repository to delegate to + */ class UnsafeDatabaseBucketRepository( val repository: DatabaseBucketRepository ) { + /** Stores the given [value] under the specified [identifier]. */ suspend fun set(identifier: String, value: I) = repository.set(identifier, value) + + /** Retrieves the value for the given [identifier], or null if not found. */ suspend fun get(identifier: String): K? = repository.get(identifier) + + /** Deletes the entry for the given [identifier]. Returns true if it existed. */ suspend fun delete(identifier: String): Boolean = repository.delete(identifier) + + /** Returns all entries, optionally filtered by a custom Redis key [customPattern]. */ suspend fun getAll(customPattern: String? = null): List = repository.getAll(customPattern) + + /** Checks whether an entry with the given [identifier] exists. */ suspend fun exists(identifier: String): Boolean = repository.exists(identifier) + + /** + * Returns the raw [IDataBucket] handle for the given [identifier]. + * + * @param identifier the entity identifier + * @param customIdentifier if true, uses the identifier as-is without prefixing + * @return the data bucket handle typed to the interface [I] + */ fun getHandle( identifier: String, customIdentifier: Boolean = false ): IDataBucket = repository.getHandle(identifier, customIdentifier) + + /** + * Returns an unsafe [IDataBucket] handle with the implementation type [K]. + * + * @param identifier the entity identifier + * @param customIdentifier if true, uses the identifier as-is without prefixing + * @return the data bucket handle typed to the implementation [K] + */ fun getUnsafeHandle( identifier: String, customIdentifier: Boolean = false diff --git a/core/src/main/kotlin/dev/redicloud/database/repository/DatabaseRepository.kt b/core/src/main/kotlin/dev/redicloud/database/repository/DatabaseRepository.kt index 6cc8bc7d..2fa25da4 100644 --- a/core/src/main/kotlin/dev/redicloud/database/repository/DatabaseRepository.kt +++ b/core/src/main/kotlin/dev/redicloud/database/repository/DatabaseRepository.kt @@ -2,6 +2,16 @@ package dev.redicloud.database.repository import dev.redicloud.api.database.IDatabaseConnection +/** + * Base class for database repositories that operate on a named key prefix. + * + * Validates that the database connection is active upon construction and provides + * a helper to build fully-qualified database identifiers. + * + * @param T the type of entity managed by this repository + * @param connection the active database connection + * @param name the key prefix used to namespace entries in the database + */ abstract class DatabaseRepository( val connection: IDatabaseConnection, val name: String @@ -11,5 +21,11 @@ abstract class DatabaseRepository( if (!connection.connected) error("Database connection is not connected") } + /** + * Creates a fully-qualified database key by combining the repository name with the given identifier. + * + * @param identifier the entity-specific identifier + * @return the namespaced database key in the format `name:identifier` + */ fun toDatabaseIdentifier(identifier: String): String = "${this.name}:$identifier" } diff --git a/core/src/main/kotlin/dev/redicloud/event/CloudEventPacket.kt b/core/src/main/kotlin/dev/redicloud/event/CloudEventPacket.kt index ac540c15..4c7c0b0a 100644 --- a/core/src/main/kotlin/dev/redicloud/event/CloudEventPacket.kt +++ b/core/src/main/kotlin/dev/redicloud/event/CloudEventPacket.kt @@ -5,6 +5,16 @@ import dev.redicloud.api.packets.AbstractPacket import dev.redicloud.api.packets.IPacketManager import dev.redicloud.utils.gson.gson +/** + * Packet that carries a serialized [CloudEvent] across the cluster. + * + * When received, it deserializes the event and fires it locally on the + * [EventManager] identified by [managerIdentifier]. + * + * @property eventData the JSON-serialized event payload + * @property eventClazz the fully-qualified class name of the event for deserialization + * @property managerIdentifier the identifier of the target [EventManager] + */ class CloudEventPacket( val eventData: String, val eventClazz: String, diff --git a/core/src/main/kotlin/dev/redicloud/event/EventHandlerMethod.kt b/core/src/main/kotlin/dev/redicloud/event/EventHandlerMethod.kt index 690ddd9e..2ef24f2b 100644 --- a/core/src/main/kotlin/dev/redicloud/event/EventHandlerMethod.kt +++ b/core/src/main/kotlin/dev/redicloud/event/EventHandlerMethod.kt @@ -2,6 +2,14 @@ package dev.redicloud.event import kotlin.reflect.KFunction +/** + * Represents a single event handler binding: a listener instance, the annotated + * function to invoke, and its dispatch priority. + * + * @property listener the object instance containing the handler function + * @property function the Kotlin function reference to call when the event fires + * @property priority the handler priority (higher values are invoked first) + */ data class EventHandlerMethod( val listener: Any, val function: KFunction<*>, diff --git a/core/src/main/kotlin/dev/redicloud/event/EventManager.kt b/core/src/main/kotlin/dev/redicloud/event/EventManager.kt index 30385731..a2fe6ad7 100644 --- a/core/src/main/kotlin/dev/redicloud/event/EventManager.kt +++ b/core/src/main/kotlin/dev/redicloud/event/EventManager.kt @@ -16,19 +16,39 @@ import kotlin.reflect.full.callSuspend import kotlin.reflect.full.declaredMemberFunctions import kotlin.reflect.full.findAnnotation +/** + * Central event dispatcher that supports both local and distributed event firing. + * + * Events can be published globally, to specific service types, or fired locally only. + * Distributed events are delivered via [PacketManager] using [CloudEventPacket]. + * Listeners are registered by scanning for [CloudEventListener]-annotated functions. + * + * @param identifier a unique identifier for this event manager instance + * @param packetManager optional packet manager for distributed event delivery; null for local-only + */ class EventManager( override val identifier: String, val packetManager: PacketManager? ) : IEventManager { companion object { + /** Logger for the event subsystem. */ val LOGGER = LogManager.logger(EventManager::class) private val MANAGERS = mutableMapOf() + /** + * Retrieves a registered [EventManager] by its identifier. + * + * @param identifier the manager identifier + * @return the manager instance, or null if not found + */ fun getManager(identifier: String): EventManager? = MANAGERS[identifier] } + /** Map of event types to their registered handler methods. */ val handlers: MutableMap, MutableList> = HashMap() + + /** Fair reentrant lock guarding handler registration and removal. */ val lock = ReentrantLock(true) init { @@ -38,6 +58,11 @@ class EventManager( } } + /** + * Removes all event handlers loaded by the given [classLoader]. + * + * @param classLoader the class loader whose handlers should be unregistered + */ fun unregister(classLoader: ClassLoader) { lock.withLock { handlers.values.forEach { list -> diff --git a/core/src/main/kotlin/dev/redicloud/packets/PackedPacket.kt b/core/src/main/kotlin/dev/redicloud/packets/PackedPacket.kt index 50fb8f9c..469a685d 100644 --- a/core/src/main/kotlin/dev/redicloud/packets/PackedPacket.kt +++ b/core/src/main/kotlin/dev/redicloud/packets/PackedPacket.kt @@ -1,3 +1,9 @@ package dev.redicloud.packets +/** + * Serialized envelope for transmitting packets over Redis pub/sub channels. + * + * @property data the JSON-serialized packet payload + * @property clazz the fully-qualified class name of the packet for deserialization + */ data class PackedPacket(val data: String, val clazz: String) diff --git a/core/src/main/kotlin/dev/redicloud/packets/PacketManager.kt b/core/src/main/kotlin/dev/redicloud/packets/PacketManager.kt index 6fcf7c94..f245e5e8 100644 --- a/core/src/main/kotlin/dev/redicloud/packets/PacketManager.kt +++ b/core/src/main/kotlin/dev/redicloud/packets/PacketManager.kt @@ -22,6 +22,17 @@ import kotlinx.coroutines.launch import kotlin.reflect.KClass import kotlin.time.Duration.Companion.seconds +/** + * Core packet manager that handles pub/sub communication between cloud services. + * + * Manages packet registration, listener dispatch, and publishing to service-specific, + * broadcast, typed, and category communication channels via Redisson topics. + * Incoming packets are deserialized using Gson and dispatched to registered listeners + * and response handlers on a dedicated coroutine scope. + * + * @param databaseConnection the active database connection for topic access + * @param serviceId the identity of the owning service + */ @Suppress("TooManyFunctions") class PacketManager( private val databaseConnection: DatabaseConnection, @@ -55,6 +66,10 @@ class PacketManager( } } + /** + * Subscribes to all communication channels (service, broadcast, and typed topics). + * Must be called after construction to start receiving packets. + */ suspend fun connect() { serviceTopic.subscribe(PackedPacket::class.java, messageListener) broadcastTopic.subscribe(PackedPacket::class.java, messageListener) @@ -104,6 +119,9 @@ class PacketManager( } } + /** + * Unsubscribes from all channels and cancels the packet coroutine scope. + */ suspend fun disconnect() { serviceTopic.unsubscribeAll() broadcastTopic.unsubscribeAll() @@ -112,6 +130,13 @@ class PacketManager( packetScope.cancel() } + /** + * Registers a category-specific communication channel. + * + * Can only be called once. Subsequent calls will throw an [IllegalStateException]. + * + * @param name the category channel name to register + */ suspend fun registerCategoryChannel(name: String) { check(this.categoryChannelName == null) { "Category channel is already registered!" } this.categoryChannelName = name @@ -148,6 +173,11 @@ class PacketManager( listeners.remove(listener) } + /** + * Unregisters all listeners and packet classes loaded by the given [classLoader]. + * + * @param classLoader the class loader whose registrations should be removed + */ fun unregister(classLoader: ClassLoader) { listeners.removeIf { it.javaClass.classLoader == classLoader } registeredPackets.removeIf { it.java.classLoader == classLoader } diff --git a/core/src/main/kotlin/dev/redicloud/packets/PacketResponse.kt b/core/src/main/kotlin/dev/redicloud/packets/PacketResponse.kt index 8cb7a25d..ad7c7dc3 100644 --- a/core/src/main/kotlin/dev/redicloud/packets/PacketResponse.kt +++ b/core/src/main/kotlin/dev/redicloud/packets/PacketResponse.kt @@ -10,6 +10,15 @@ import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds +/** + * Tracks and dispatches responses to a previously published packet. + * + * Supports both callback-based ([waitForResponse]) and suspending ([waitBlocking]) + * response collection, with a configurable timeout (default 15 seconds). + * + * @param manager the packet manager that owns this response tracker + * @param packet the original packet awaiting responses + */ class PacketResponse( override val manager: PacketManager, override val packet: AbstractPacket diff --git a/utils/src/main/kotlin/dev/redicloud/utils/CommandStringUtils.kt b/utils/src/main/kotlin/dev/redicloud/utils/CommandStringUtils.kt index a14059c5..2b5c5d56 100644 --- a/utils/src/main/kotlin/dev/redicloud/utils/CommandStringUtils.kt +++ b/utils/src/main/kotlin/dev/redicloud/utils/CommandStringUtils.kt @@ -1,5 +1,16 @@ package dev.redicloud.utils +/** + * Wraps a value in single quotes for console display. + * + * When [colored] is `true`, the value is wrapped with color codes + * (`%hc%` for highlight color, `%tc%` for text color). When `false`, + * plain single quotes are used. + * + * @param value the value to format + * @param colored whether to apply color codes (default: `true`) + * @return the formatted string + */ fun toConsoleValue(value: Any, colored: Boolean = true): String { return if (colored) { "§8'%hc%$value§8'%tc%" From 8a7071492ab48f950a1ab41d367a73280b50deb3 Mon Sep 17 00:00:00 2001 From: paulkczw <44299323+paulkczw@users.noreply.github.com> Date: Thu, 4 Jun 2026 12:57:09 +0200 Subject: [PATCH 7/8] fix: add branch fallback for GitHub API file fetching --- .../dev/redicloud/utils/RestAPIUtils.kt | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/utils/src/main/kotlin/dev/redicloud/utils/RestAPIUtils.kt b/utils/src/main/kotlin/dev/redicloud/utils/RestAPIUtils.kt index c0d5ca42..63b74b59 100644 --- a/utils/src/main/kotlin/dev/redicloud/utils/RestAPIUtils.kt +++ b/utils/src/main/kotlin/dev/redicloud/utils/RestAPIUtils.kt @@ -7,15 +7,27 @@ import io.ktor.http.* /** * Fetches a text file from the GitHub repository's raw content URL. * + * Tries the commit-pinned URL first. If that returns a 404 (e.g. local + * dev builds with unpushed commits), falls back to the branch-based URL. + * * Used by version repositories to load api-files (server-versions.json, etc.) - * from the repository at the configured branch. + * from the repository. */ suspend fun getTextFromGitHub(path: String): String { - val response = httpClient.get { - url("${getRawUserContentUrl()}/$path") + val baseUrl = "https://raw.githubusercontent.com/${getGithubUser()}/${getGithubRepository()}" + val commitRef = GIT.takeIf { it != "unknown" } + val branchRef = getGithubBranch() + + if (commitRef != null) { + val response = httpClient.get { url("$baseUrl/$commitRef/$path") } + if (response.status.isSuccess()) return response.bodyAsText() + } + + val fallbackResponse = httpClient.get { url("$baseUrl/$branchRef/$path") } + check(fallbackResponse.status.isSuccess()) { + "Failed to fetch $path from GitHub: HTTP ${fallbackResponse.status}" } - check(response.status.isSuccess()) { "Failed to fetch $path from GitHub: HTTP ${response.status}" } - return response.bodyAsText() + return fallbackResponse.bodyAsText() } /** From 31d070b1082ca4db4cdb9fcf5780041662d0787e Mon Sep 17 00:00:00 2001 From: paulkczw <44299323+paulkczw@users.noreply.github.com> Date: Thu, 4 Jun 2026 13:02:55 +0200 Subject: [PATCH 8/8] fix: migrate default file urls from api.redicloud.dev to github --- api-files/server-version-types.json | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/api-files/server-version-types.json b/api-files/server-version-types.json index 345a95bb..f77e5479 100644 --- a/api-files/server-version-types.json +++ b/api-files/server-version-types.json @@ -14,10 +14,10 @@ ], "environmentVariables": {}, "defaultFiles": { - "config/paper-global.yml": "https://api.redicloud.dev/v2/files/%branch%/%build%/api-files/defaultFiles/paper-global.yml", - "server.properties": "https://api.redicloud.dev/v2/files/%branch%/%build%/api-files/defaultFiles/server.properties", - "bukkit.yml": "https://api.redicloud.dev/v2/files/%branch%/%build%/api-files/defaultFiles/bukkit.yml", - "spigot.yml": "https://api.redicloud.dev/v2/files/%branch%/%build%/api-files/defaultFiles/spigot.yml" + "config/paper-global.yml": "https://raw.githubusercontent.com/RediCloud/cloud-v2/%branch%/api-files/defaultFiles/paper-global.yml", + "server.properties": "https://raw.githubusercontent.com/RediCloud/cloud-v2/%branch%/api-files/defaultFiles/server.properties", + "bukkit.yml": "https://raw.githubusercontent.com/RediCloud/cloud-v2/%branch%/api-files/defaultFiles/bukkit.yml", + "spigot.yml": "https://raw.githubusercontent.com/RediCloud/cloud-v2/%branch%/api-files/defaultFiles/spigot.yml" }, "fileEdits": { "server.properties": { @@ -49,9 +49,9 @@ ], "environmentVariables": {}, "defaultFiles": { - "server.properties": "https://api.redicloud.dev/v2/files/%branch%/%build%/api-files/defaultFiles/server.properties", - "bukkit.yml": "https://api.redicloud.dev/v2/files/%branch%/%build%/api-files/defaultFiles/bukkit.yml", - "spigot.yml": "https://api.redicloud.dev/v2/files/%branch%/%build%/api-files/defaultFiles/spigot.yml" + "server.properties": "https://raw.githubusercontent.com/RediCloud/cloud-v2/%branch%/api-files/defaultFiles/server.properties", + "bukkit.yml": "https://raw.githubusercontent.com/RediCloud/cloud-v2/%branch%/api-files/defaultFiles/bukkit.yml", + "spigot.yml": "https://raw.githubusercontent.com/RediCloud/cloud-v2/%branch%/api-files/defaultFiles/spigot.yml" }, "fileEdits": { "server.properties": { @@ -75,8 +75,8 @@ "programParameters": [], "environmentVariables": {}, "defaultFiles": { - "velocity.toml": "https://api.redicloud.dev/v2/files/%branch%/%build%/api-files/defaultFiles/velocity.toml", - "forwarding.secret": "https://api.redicloud.dev/v2/files/%branch%/%build%/api-files/defaultFiles/forwarding.secret" + "velocity.toml": "https://raw.githubusercontent.com/RediCloud/cloud-v2/%branch%/api-files/defaultFiles/velocity.toml", + "forwarding.secret": "https://raw.githubusercontent.com/RediCloud/cloud-v2/%branch%/api-files/defaultFiles/forwarding.secret" }, "fileEdits": { "velocity.toml": { @@ -102,7 +102,7 @@ "programParameters": [], "environmentVariables": {}, "defaultFiles": { - "config.yml": "https://api.redicloud.dev/v2/files/%branch%/%build%/api-files/defaultFiles/config.yml" + "config.yml": "https://raw.githubusercontent.com/RediCloud/cloud-v2/%branch%/api-files/defaultFiles/config.yml" }, "fileEdits": { "config.yml": { @@ -124,7 +124,7 @@ "programParameters": [], "environmentVariables": {}, "defaultFiles": { - "config.yml": "https://api.redicloud.dev/v2/files/%branch%/%build%/api-files/defaultFiles/config.yml" + "config.yml": "https://raw.githubusercontent.com/RediCloud/cloud-v2/%branch%/api-files/defaultFiles/config.yml" }, "fileEdits": { "config.yml": { @@ -152,7 +152,7 @@ ], "environmentVariables": {}, "defaultFiles": { - "server.properties": "https://api.redicloud.dev/v2/files/%branch%/%build%/api-files/defaultFiles/server.properties" + "server.properties": "https://raw.githubusercontent.com/RediCloud/cloud-v2/%branch%/api-files/defaultFiles/server.properties" }, "fileEdits": { "server.properties": {