From d9c86d206ff34c43534e3d9a59c506f4bb515ccd Mon Sep 17 00:00:00 2001 From: Polyana Date: Thu, 21 Dec 2023 20:05:45 -0300 Subject: [PATCH] PC-1070 initial structure (partial) --- .../minecity/api/server/MineCityServer.kt | 2 + persistence/base/build.gradle.kts | 16 +++++ .../persistence/base/MineCityPersistence.kt | 5 ++ .../base/MineCityPersistenceException.kt | 5 ++ .../InternalMineCityPersistenceApi.kt | 16 +++++ persistence/sql/build.gradle.kts | 14 ++++ .../persistence/sql/MineCitySqlPersistence.kt | 64 +++++++++++++++++++ platform/fabric/build.gradle.kts | 5 ++ .../fabric/server/MineCityFabricServer.kt | 3 +- settings.gradle.kts | 6 +- 10 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 persistence/base/build.gradle.kts create mode 100644 persistence/base/src/main/kotlin/br/com/gamemods/minecity/persistence/base/MineCityPersistence.kt create mode 100644 persistence/base/src/main/kotlin/br/com/gamemods/minecity/persistence/base/MineCityPersistenceException.kt create mode 100644 persistence/base/src/main/kotlin/br/com/gamemods/minecity/persistence/base/annotation/InternalMineCityPersistenceApi.kt create mode 100644 persistence/sql/build.gradle.kts create mode 100644 persistence/sql/src/main/kotlin/br/com/gamemods/minecity/persistence/sql/MineCitySqlPersistence.kt diff --git a/api/src/main/kotlin/br/com/gamemods/minecity/api/server/MineCityServer.kt b/api/src/main/kotlin/br/com/gamemods/minecity/api/server/MineCityServer.kt index d51ad8c..2d35677 100644 --- a/api/src/main/kotlin/br/com/gamemods/minecity/api/server/MineCityServer.kt +++ b/api/src/main/kotlin/br/com/gamemods/minecity/api/server/MineCityServer.kt @@ -7,9 +7,11 @@ import kotlinx.coroutines.CoroutineScope * Server side instance that handles all server features * * @property platform The platform where MineCity is running + * @property serverIp The IP being used to host the server */ public interface MineCityServer: CoroutineScope { public val platform: MineCityPlatform + public val serverIp: String /** * Checks if the current thread is the main thread diff --git a/persistence/base/build.gradle.kts b/persistence/base/build.gradle.kts new file mode 100644 index 0000000..86f90cd --- /dev/null +++ b/persistence/base/build.gradle.kts @@ -0,0 +1,16 @@ +plugins { + id("maven-publish") + kotlin("jvm") + kotlin("plugin.serialization") +} + +kotlin { + explicitApi() +} + +val inlineLoggerVersion: String by rootProject + +dependencies { + api(project(":core")) + compileOnly("com.michael-bull.kotlin-inline-logger:kotlin-inline-logger:$inlineLoggerVersion") +} diff --git a/persistence/base/src/main/kotlin/br/com/gamemods/minecity/persistence/base/MineCityPersistence.kt b/persistence/base/src/main/kotlin/br/com/gamemods/minecity/persistence/base/MineCityPersistence.kt new file mode 100644 index 0000000..8174e08 --- /dev/null +++ b/persistence/base/src/main/kotlin/br/com/gamemods/minecity/persistence/base/MineCityPersistence.kt @@ -0,0 +1,5 @@ +package br.com.gamemods.minecity.persistence.base + +import kotlinx.coroutines.CoroutineScope + +public interface MineCityPersistence: CoroutineScope diff --git a/persistence/base/src/main/kotlin/br/com/gamemods/minecity/persistence/base/MineCityPersistenceException.kt b/persistence/base/src/main/kotlin/br/com/gamemods/minecity/persistence/base/MineCityPersistenceException.kt new file mode 100644 index 0000000..a4216bd --- /dev/null +++ b/persistence/base/src/main/kotlin/br/com/gamemods/minecity/persistence/base/MineCityPersistenceException.kt @@ -0,0 +1,5 @@ +package br.com.gamemods.minecity.persistence.base + +import java.io.IOException + +public class MineCityPersistenceException(message: String? = null, cause: Throwable? = null): IOException(message, cause) diff --git a/persistence/base/src/main/kotlin/br/com/gamemods/minecity/persistence/base/annotation/InternalMineCityPersistenceApi.kt b/persistence/base/src/main/kotlin/br/com/gamemods/minecity/persistence/base/annotation/InternalMineCityPersistenceApi.kt new file mode 100644 index 0000000..3ee8d51 --- /dev/null +++ b/persistence/base/src/main/kotlin/br/com/gamemods/minecity/persistence/base/annotation/InternalMineCityPersistenceApi.kt @@ -0,0 +1,16 @@ +package br.com.gamemods.minecity.persistence.base.annotation + +/** + * Indicates that the annotated element should only be used by MineCity Persistence API implementation, not API users. + */ +@Retention(value = AnnotationRetention.BINARY) +@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.TYPEALIAS, AnnotationTarget.PROPERTY, + AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.CONSTRUCTOR +) +@RequiresOptIn( + level = RequiresOptIn.Level.ERROR, message = "This is an internal MineCity API that " + + "should not be used from outside of br.com.gamemods.minecity.persistence. No compatibility guarantees are provided. " + + "It is recommended to report your use-case of internal API to MineCity2 issue tracker, " + + "so stable API could be provided instead" +) +public annotation class InternalMineCityPersistenceApi diff --git a/persistence/sql/build.gradle.kts b/persistence/sql/build.gradle.kts new file mode 100644 index 0000000..d7a1a8b --- /dev/null +++ b/persistence/sql/build.gradle.kts @@ -0,0 +1,14 @@ +plugins { + id("maven-publish") + kotlin("jvm") + kotlin("plugin.serialization") +} + +val inlineLoggerVersion: String by rootProject + +dependencies { + implementation(project(":persistence:base")) + implementation("org.flywaydb:flyway-core:10.1.0") + implementation("org.jdbi:jdbi3-core:3.41.3") + compileOnly("com.michael-bull.kotlin-inline-logger:kotlin-inline-logger:$inlineLoggerVersion") +} diff --git a/persistence/sql/src/main/kotlin/br/com/gamemods/minecity/persistence/sql/MineCitySqlPersistence.kt b/persistence/sql/src/main/kotlin/br/com/gamemods/minecity/persistence/sql/MineCitySqlPersistence.kt new file mode 100644 index 0000000..fc002ed --- /dev/null +++ b/persistence/sql/src/main/kotlin/br/com/gamemods/minecity/persistence/sql/MineCitySqlPersistence.kt @@ -0,0 +1,64 @@ +package br.com.gamemods.minecity.persistence.sql + +import br.com.gamemods.minecity.api.server.MineCityServer +import br.com.gamemods.minecity.persistence.base.MineCityPersistence +import br.com.gamemods.minecity.persistence.base.MineCityPersistenceException +import br.com.gamemods.minecity.persistence.base.annotation.InternalMineCityPersistenceApi +import com.github.michaelbull.logging.InlineLogger +import kotlinx.coroutines.CoroutineName +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.job +import org.flywaydb.core.Flyway +import javax.sql.DataSource + +@InternalMineCityPersistenceApi +class MineCitySqlPersistence( + private val server: MineCityServer, + private val dataSource: DataSource, +): MineCityPersistence { + override val coroutineContext = SupervisorJob(server.coroutineContext.job) + Dispatchers.IO + CoroutineName("MineCitySqlPersistence ${server.serverIp}") + private val log = InlineLogger() + + @Throws(MineCityPersistenceException::class) + fun upgrade() { + val flyway = Flyway.configure() + .dataSource(dataSource) + .locations("classpath:br/com/gamemods/minecity/persistence/sql/migration") + .load() + + val result = try { + flyway.migrate() + } catch (e: Throwable) { + log.error(e) { + "SQL migration failed with an exception!" + } + throw MineCityPersistenceException("SQL migration failed with an exception!", e) + } + if (!result.success) { + log.error { + "SQL migration failed." + } + } else if (result.migrationsExecuted > 0) { + log.info { + "SQL databased migrated from ${result.initialSchemaVersion} to ${result.targetSchemaVersion} (${result.migrationsExecuted} migrations executed) in ${result.totalMigrationTime}ms." + } + } else { + log.info { "SQL database is up to date." } + } + if (result.warnings.isNotEmpty()) { + log.warn { + buildString { + append("SQL database migration raised ${result.warnings.size} warning(s):") + appendLine() + result.warnings.forEach { + append(it) + appendLine() + appendLine() + } + } + } + } + if (result.success) + } +} diff --git a/platform/fabric/build.gradle.kts b/platform/fabric/build.gradle.kts index 5796dee..07b61c3 100644 --- a/platform/fabric/build.gradle.kts +++ b/platform/fabric/build.gradle.kts @@ -31,6 +31,8 @@ loom { } } +val persistenceProject = project(":persistence") + dependencies { // To change the versions see the gradle.properties file minecraft("com.mojang:minecraft:$minecraftVersion") @@ -46,6 +48,9 @@ dependencies { // modImplementation("net.fabricmc.fabric-api:fabric-api-deprecated:${project.findProperty("fabric_version")}") implementation(include(project(":core"))!!) + persistenceProject.subprojects.forEach { persistenceImpl -> + implementation(include(project(persistenceImpl.path))!!) + } compileOnly("com.michael-bull.kotlin-inline-logger:kotlin-inline-logger:$inlineLoggerVersion") } diff --git a/platform/fabric/src/main/kotlin/br/com/gamemods/minecity/fabric/server/MineCityFabricServer.kt b/platform/fabric/src/main/kotlin/br/com/gamemods/minecity/fabric/server/MineCityFabricServer.kt index 3e83e4e..690df39 100644 --- a/platform/fabric/src/main/kotlin/br/com/gamemods/minecity/fabric/server/MineCityFabricServer.kt +++ b/platform/fabric/src/main/kotlin/br/com/gamemods/minecity/fabric/server/MineCityFabricServer.kt @@ -17,9 +17,10 @@ import kotlin.coroutines.CoroutineContext */ @InternalMineCityApi class MineCityFabricServer(val mcServer: FabricMinecraftServerWrapper): MineCityServer { - override val coroutineContext: CoroutineContext = Dispatchers.Sync + CoroutineName("${mcServer.serverIp} (Sync)") + override val coroutineContext: CoroutineContext = SupervisorJob() + Dispatchers.Sync + CoroutineName("MineCityFabricServer ${mcServer.serverIp} (Sync)") private val log = InlineLogger() override val platform: MineCityFabric get() = MineCityFabric + override val serverIp: String get() = mcServer.serverIp @ServerSideOnly fun onServerStarting() { diff --git a/settings.gradle.kts b/settings.gradle.kts index 59e1235..d324842 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -9,4 +9,8 @@ pluginManagement { } } -include(":api", ":core", ":platform:fabric") +include( + ":api", ":core", + ":persistence:base", ":persistence:sql", + ":platform:fabric" +)