diff --git a/controller-runtime/build.gradle.kts b/controller-runtime/build.gradle.kts index e23d62d..33ab999 100644 --- a/controller-runtime/build.gradle.kts +++ b/controller-runtime/build.gradle.kts @@ -9,6 +9,7 @@ dependencies { api(libs.bundles.jooq) api(libs.sqlite.jdbc) + implementation(libs.mysql.connector) implementation(libs.simplecloud.metrics) implementation(libs.bundles.log4j) implementation(libs.clikt) @@ -62,7 +63,7 @@ jooq { // - ? matches a single character in a directory / file name property { key = "scripts" - value = "src/main/db/schema.sql" + value = "src/main/db/schema/default.sql" } // The sort order of the scripts within a directory, where: diff --git a/controller-runtime/src/main/db/schema.sql b/controller-runtime/src/main/db/schema/default.sql similarity index 100% rename from controller-runtime/src/main/db/schema.sql rename to controller-runtime/src/main/db/schema/default.sql diff --git a/controller-runtime/src/main/db/schema/mysql.sql b/controller-runtime/src/main/db/schema/mysql.sql new file mode 100644 index 0000000..450f4ea --- /dev/null +++ b/controller-runtime/src/main/db/schema/mysql.sql @@ -0,0 +1,70 @@ +/** + MySQL-spezifisches Schema für den v3 Backend. + Diese Datei enthält Anpassungen für MySQL/MariaDB. + Wird automatisch verwendet, wenn MySQL als Datenbank konfiguriert ist. +*/ + +CREATE TABLE IF NOT EXISTS cloud_servers ( + unique_id VARCHAR(36) NOT NULL PRIMARY KEY, + group_name VARCHAR(255) NOT NULL, + host_id VARCHAR(36) NOT NULL, + numerical_id INT NOT NULL, + ip VARCHAR(45) NOT NULL, + port INT NOT NULL, + minimum_memory INT NOT NULL, + maximum_memory INT NOT NULL, + max_players INT NOT NULL, + player_count INT NOT NULL, + state VARCHAR(50) NOT NULL, + type VARCHAR(50) NOT NULL, + created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + updated_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS cloud_server_properties ( + server_id VARCHAR(36) NOT NULL, + `key` VARCHAR(255) NOT NULL, + value TEXT, + PRIMARY KEY (server_id, `key`), + CONSTRAINT fk_server_props_server FOREIGN KEY (server_id) + REFERENCES cloud_servers(unique_id) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS oauth2_client_details ( + client_id VARCHAR(36) PRIMARY KEY, + client_secret VARCHAR(255), + redirect_uri VARCHAR(512), + grant_types TEXT, + scope TEXT +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS oauth2_users ( + user_id VARCHAR(36) PRIMARY KEY, + scopes TEXT, + username VARCHAR(255) UNIQUE NOT NULL, + hashed_password VARCHAR(255) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS oauth2_tokens ( + token_id VARCHAR(36) PRIMARY KEY, + client_id VARCHAR(36), + access_token TEXT, + scope TEXT, + expires_in TIMESTAMP NULL DEFAULT NULL, + user_id VARCHAR(36), + CONSTRAINT fk_token_user FOREIGN KEY (user_id) + REFERENCES oauth2_users(user_id) ON DELETE CASCADE, + CONSTRAINT fk_token_client FOREIGN KEY (client_id) + REFERENCES oauth2_client_details(client_id) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS oauth2_groups ( + group_name VARCHAR(255) PRIMARY KEY, + scopes TEXT +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS oauth2_user_groups ( + user_id VARCHAR(36), + group_name VARCHAR(255), + PRIMARY KEY (user_id, group_name) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/controller-runtime/src/main/kotlin/app/simplecloud/controller/runtime/database/Database.kt b/controller-runtime/src/main/kotlin/app/simplecloud/controller/runtime/database/Database.kt index 99266b9..a0d6e3b 100644 --- a/controller-runtime/src/main/kotlin/app/simplecloud/controller/runtime/database/Database.kt +++ b/controller-runtime/src/main/kotlin/app/simplecloud/controller/runtime/database/Database.kt @@ -1,22 +1,40 @@ package app.simplecloud.controller.runtime.database +import org.apache.logging.log4j.LogManager import org.jooq.DSLContext +import org.jooq.SQLDialect +import org.jooq.impl.DSL class Database( val context: DSLContext ) { + private val logger = LogManager.getLogger(Database::class.java) + fun setup() { System.setProperty("org.jooq.no-logo", "true") System.setProperty("org.jooq.no-tips", "true") - val setupInputStream = Database::class.java.getResourceAsStream("/schema.sql") - ?: throw IllegalArgumentException("Database schema not found.") - val setupCommands = setupInputStream.bufferedReader().use { it.readText() }.split(";") - setupCommands.forEach { - val trimmed = it.trim() - if (trimmed.isNotEmpty()) - context.execute(org.jooq.impl.DSL.sql(trimmed)) + + val schemaFile = when (context.dialect().family()) { + SQLDialect.MARIADB, SQLDialect.MYSQL -> "/schema/mysql.sql" + else -> "/schema/default.sql" + } + + val setupInputStream = Database::class.java.getResourceAsStream(schemaFile) + ?: throw IllegalArgumentException("Database schema not found: $schemaFile") + + val setupCommands = setupInputStream.bufferedReader().use { it.readText() } + .split(";") + .map { it.trim() } + .filter { it.isNotEmpty() } + + setupCommands.forEach { command -> + try { + context.execute(DSL.using(context.dialect()).parser().parseQuery(command)) + } catch (e: Exception) { + logger.error("Error executing SQL command: {}", command, e) + throw e + } } } - } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index da698d3..de52a09 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,6 +14,7 @@ sonatype-central-portal-publisher = "1.2.3" spotify-completablefutures = "0.3.6" spring-crypto = "6.3.4" envoy = "1.0.46" +mysql-connector = "8.0.33" [libraries] kotlin-jvm = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk8", version.ref = "kotlin" } @@ -45,6 +46,8 @@ spotify-completablefutures = { module = "com.spotify:completable-futures", versi spring-crypto = { module = "org.springframework.security:spring-security-crypto", version.ref = "spring-crypto" } envoy-controlplane = { module = "io.envoyproxy.controlplane:server", version.ref = "envoy" } +mysql-connector = { module = "mysql:mysql-connector-java", version.ref = "mysql-connector" } + [bundles] log4j = [