diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 632ea0bc..ec6c31a7 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -8,8 +8,13 @@ dependencies { api(projects.api) api(libs.base.api) compileOnlyApi(projects.isolation) - api(libs.config.utils) + annotationProcessor(libs.config.utils.ap) + api(libs.config.utils) + + annotationProcessor(libs.database.utils.ap) + api(libs.database.utils) + compileOnlyApi(libs.database.utils.sql) api(libs.bundles.fastutil) api(libs.java.websocket) @@ -28,13 +33,6 @@ dependencies { compileOnlyApi(libs.jakarta.jsonb) annotationProcessor(libs.micronaut.serde.processor) - api(libs.micronaut.data.jdbc) - runtimeOnly(libs.micronaut.hikari) - annotationProcessor(libs.micronaut.data.processor) - compileOnlyApi(libs.jakarta.persistence) - - runtimeOnly("com.h2database:h2") - testImplementation(libs.junit.jupiter) testRuntimeOnly(libs.junit.platform.launcher) } diff --git a/core/src/main/java/org/geysermc/floodgate/core/FloodgatePlatform.java b/core/src/main/java/org/geysermc/floodgate/core/FloodgatePlatform.java index e9dfc829..b9b4b3a7 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/FloodgatePlatform.java +++ b/core/src/main/java/org/geysermc/floodgate/core/FloodgatePlatform.java @@ -28,6 +28,8 @@ import io.micronaut.context.ApplicationContext; import io.micronaut.context.Qualifier; import io.micronaut.core.type.Argument; +import io.micronaut.inject.qualifiers.Qualifiers; +import java.nio.file.Path; import java.util.Map; import java.util.UUID; import org.geysermc.api.Geyser; @@ -39,7 +41,10 @@ import org.geysermc.floodgate.api.inject.PlatformInjector; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.packet.PacketHandlers; +import org.geysermc.floodgate.core.config.ConfigLoader; +import org.geysermc.floodgate.core.config.FloodgateConfig; import org.geysermc.floodgate.core.config.Properties; +import org.geysermc.floodgate.core.database.loader.DatabaseLoader; import org.geysermc.floodgate.core.event.EventBus; import org.geysermc.floodgate.core.event.lifecycle.PostEnableEvent; import org.geysermc.floodgate.core.event.lifecycle.ShutdownEvent; @@ -75,6 +80,12 @@ public void load() { .eagerInitSingletons(true) .build(); onContextCreated(context); + + // load and register config and database related stuff + var dataDirectory = context.getBean(Path.class, Qualifiers.byName("dataDirectory")); + FloodgateConfig config = ConfigLoader.load(dataDirectory, isProxy(), context); + DatabaseLoader.load(config, manager, dataDirectory, context); + context.start(); injector = context.getBean(PlatformInjector.class); diff --git a/core/src/main/java/org/geysermc/floodgate/core/command/TestCommand.java b/core/src/main/java/org/geysermc/floodgate/core/command/TestCommand.java index e970aa54..b8a9c901 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/command/TestCommand.java +++ b/core/src/main/java/org/geysermc/floodgate/core/command/TestCommand.java @@ -27,28 +27,41 @@ import cloud.commandframework.Command; import cloud.commandframework.CommandManager; +import cloud.commandframework.arguments.standard.StringArgument; +import cloud.commandframework.arguments.standard.UUIDArgument; import cloud.commandframework.context.CommandContext; +import jakarta.inject.Inject; import jakarta.inject.Singleton; -import org.geysermc.api.Geyser; +import java.util.concurrent.ExecutionException; import org.geysermc.floodgate.core.config.FloodgateConfig; import org.geysermc.floodgate.core.connection.audience.UserAudience; +import org.geysermc.floodgate.core.link.CommonPlayerLink; import org.geysermc.floodgate.core.platform.command.FloodgateCommand; import org.geysermc.floodgate.core.util.Constants; +import org.geysermc.floodgate.core.util.Utils; @Singleton public class TestCommand implements FloodgateCommand { + @Inject CommonPlayerLink link; + @Override public Command buildCommand(CommandManager commandManager) { return commandManager.commandBuilder("floodgate-test") - .senderType(UserAudience.class) + .senderType(UserAudience.ConsoleAudience.class) .handler(this::execute) + .argument(StringArgument.of("xuid")) + .argument(UUIDArgument.of("uuid")) + .argument(StringArgument.of("name")) .build(); } @Override public void execute(CommandContext context) { - int players = Geyser.api().onlineConnectionsCount(); - context.getSender().sendMessage(String.valueOf(players)); + try { + link.addLink(context.get("uuid"), context.get("name"), Utils.getJavaUuid(context.get("xuid"))).get(); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } } @Override diff --git a/core/src/main/java/org/geysermc/floodgate/core/config/ConfigAsProperties.java b/core/src/main/java/org/geysermc/floodgate/core/config/ConfigAsPropertySource.java similarity index 50% rename from core/src/main/java/org/geysermc/floodgate/core/config/ConfigAsProperties.java rename to core/src/main/java/org/geysermc/floodgate/core/config/ConfigAsPropertySource.java index d579ea04..5f349028 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/config/ConfigAsProperties.java +++ b/core/src/main/java/org/geysermc/floodgate/core/config/ConfigAsPropertySource.java @@ -25,76 +25,34 @@ package org.geysermc.floodgate.core.config; -import io.micronaut.context.annotation.BootstrapContextCompatible; -import io.micronaut.context.env.BootstrapPropertySourceLocator; -import io.micronaut.context.env.Environment; import io.micronaut.context.env.PropertySource; -import io.micronaut.context.exceptions.ConfigurationException; -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.inject.Singleton; import java.lang.reflect.Proxy; -import java.nio.file.Path; -import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import org.geysermc.configutils.node.codec.strategy.object.ProxyEmbodimentStrategy; -import org.geysermc.floodgate.core.database.loader.DatabaseType; -import org.geysermc.floodgate.core.util.GlobalBeanCache; -import org.geysermc.floodgate.isolation.library.LibraryManager; -@Singleton -@BootstrapContextCompatible -public class ConfigAsProperties implements BootstrapPropertySourceLocator { - @Inject - @Named("dataDirectory") - Path dataDirectory; +public final class ConfigAsPropertySource { + private ConfigAsPropertySource() {} - @Inject FloodgateConfig config; - - @Override - public Iterable findPropertySources(Environment environment) - throws ConfigurationException { - loadDatabase(); - - var flat = flattern(Map.of("config", config)); - flat.forEach((key, value) -> System.out.println(key + ": " + value)); - - return Collections.singleton(PropertySource.of(flat)); - } - - private void loadDatabase() { - LibraryManager manager = GlobalBeanCache.get("libraryManager"); - - var databaseConfig = config.database(); - if (!databaseConfig.enabled()) { - return; - } - - var type = DatabaseType.byId(databaseConfig.type()); - if (type == null) { - throw new IllegalStateException( - "Unable to find database type that matches: " + databaseConfig.type() - ); - } - - type.libraries().forEach(manager::addLibrary); - manager.apply(); + public static PropertySource toPropertySource(FloodgateConfig config) { + Objects.requireNonNull(config); + return PropertySource.of(flatten(Map.of("config", config))); } - private Map flattern(Map map) { - return flattern0(Map.of("", map).get("")); + private static Map flatten(Map map) { + return flatten0(Map.of("", map).get("")); } @SuppressWarnings("unchecked") - private Map flattern0(Map map) { + private static Map flatten0(Map map) { var result = new HashMap(); map.forEach((key, value) -> { if (Proxy.isProxyClass(value.getClass())) { value = new ProxyEmbodimentStrategy().disembody(value); } if (value instanceof Map) { - flattern0((Map) value).forEach( + flatten0((Map) value).forEach( (key1, value1) -> result.put(key + "." + key1, value1) ); return; diff --git a/core/src/main/java/org/geysermc/floodgate/core/config/ConfigLoader.java b/core/src/main/java/org/geysermc/floodgate/core/config/ConfigLoader.java index 19507259..5ed49499 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/config/ConfigLoader.java +++ b/core/src/main/java/org/geysermc/floodgate/core/config/ConfigLoader.java @@ -25,49 +25,20 @@ package org.geysermc.floodgate.core.config; -import io.micronaut.context.annotation.Bean; -import io.micronaut.context.annotation.BootstrapContextCompatible; -import io.micronaut.context.annotation.Factory; -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.inject.Singleton; +import io.micronaut.context.ApplicationContext; import java.nio.file.Path; import java.util.UUID; -import lombok.Getter; import org.geysermc.configutils.ConfigUtilities; import org.geysermc.configutils.file.codec.PathFileCodec; import org.geysermc.configutils.updater.change.Changes; -import org.geysermc.floodgate.core.scope.ProxyOnly; -import org.geysermc.floodgate.core.scope.ServerOnly; -import org.geysermc.floodgate.core.util.GlobalBeanCache; -@Factory -@Getter -@BootstrapContextCompatible public final class ConfigLoader { - private final Path dataDirectory; - - @Inject - ConfigLoader(@Named("dataDirectory") Path dataDirectory) { - this.dataDirectory = dataDirectory; - } - - @Bean - @ServerOnly - @Singleton - FloodgateConfig config() { - return GlobalBeanCache.cacheIfAbsent("config", () -> load(FloodgateConfig.class)); - } - - @Bean - @ProxyOnly - @Singleton - ProxyFloodgateConfig proxyConfig() { - return GlobalBeanCache.cacheIfAbsent("config", () -> load(ProxyFloodgateConfig.class)); - } + private ConfigLoader() {} @SuppressWarnings("unchecked") - private T load(Class configClass) { + public static T load(Path dataDirectory, boolean isProxy, ApplicationContext context) { + var configClass = isProxy ? ProxyFloodgateConfig.class : FloodgateConfig.class; + // it would also be nice to have sections in versionBuilder so that you don't have to // provide the path all the time @@ -85,15 +56,24 @@ private T load(Class conf .keyRenamed("playerLink.type", "database.type")) .build()) .definePlaceholder("metrics.uuid", UUID::randomUUID) - .postInitializeCallbackArgument(this) + .postInitializeCallbackArgument(dataDirectory) .build(); + + T config; try { - return (T) utilities.executeOn(configClass); + config = (T) utilities.executeOn(configClass); } catch (Throwable throwable) { throw new RuntimeException( "Failed to load the config! Try to delete the config file if this error persists", throwable ); } + + // make sure the proxy and the normal config types are registered + context.registerSingleton(config); + context.registerSingleton(FloodgateConfig.class, config); + // make @Requires etc. work + context.getEnvironment().addPropertySource(ConfigAsPropertySource.toPropertySource(config)); + return config; } } diff --git a/core/src/main/java/org/geysermc/floodgate/core/config/FloodgateConfig.java b/core/src/main/java/org/geysermc/floodgate/core/config/FloodgateConfig.java index 9483b248..3af22e76 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/config/FloodgateConfig.java +++ b/core/src/main/java/org/geysermc/floodgate/core/config/FloodgateConfig.java @@ -45,14 +45,14 @@ * addition to the global configuration like {@link ProxyFloodgateConfig} for the proxies. */ @ConfigVersion(3) -public interface FloodgateConfig extends GenericPostInitializeCallback { +public interface FloodgateConfig extends GenericPostInitializeCallback { default boolean proxy() { return this instanceof ProxyFloodgateConfig; } @Override - default CallbackResult postInitialize(ConfigLoader loader) { - Path keyPath = loader.getDataDirectory().resolve(keyFileName()); + default CallbackResult postInitialize(Path dataDirectory) { + Path keyPath = dataDirectory.resolve(keyFileName()); // don't assume that the key always exists with the existence of a config if (!Files.exists(keyPath)) { diff --git a/core/src/main/java/org/geysermc/floodgate/core/database/PendingLinkRepository.java b/core/src/main/java/org/geysermc/floodgate/core/database/PendingLinkRepository.java index 93050e7f..013b02a3 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/database/PendingLinkRepository.java +++ b/core/src/main/java/org/geysermc/floodgate/core/database/PendingLinkRepository.java @@ -25,15 +25,16 @@ package org.geysermc.floodgate.core.database; -import io.micronaut.context.annotation.Requires; -import io.micronaut.data.jdbc.annotation.JdbcRepository; -import io.micronaut.data.model.query.builder.sql.Dialect; -import io.micronaut.data.repository.CrudRepository; -import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import org.geysermc.databaseutils.IRepository; +import org.geysermc.databaseutils.meta.Repository; import org.geysermc.floodgate.core.database.entity.LinkRequest; -@JdbcRepository(dialect = Dialect.ANSI) -@Requires(property = "config.database.enabled", value = "true") -public interface PendingLinkRepository extends CrudRepository { - LinkRequest findByJavaUsername(String javaUsername); +@Repository +public interface PendingLinkRepository extends IRepository { + CompletableFuture findByJavaUsername(String javaUsername); + + CompletableFuture insert(LinkRequest request); + + CompletableFuture delete(LinkRequest request); } diff --git a/core/src/main/java/org/geysermc/floodgate/core/database/PlayerLinkRepository.java b/core/src/main/java/org/geysermc/floodgate/core/database/PlayerLinkRepository.java index 2b641e3b..624b47c8 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/database/PlayerLinkRepository.java +++ b/core/src/main/java/org/geysermc/floodgate/core/database/PlayerLinkRepository.java @@ -25,32 +25,23 @@ package org.geysermc.floodgate.core.database; -import io.micronaut.context.annotation.Requires; -import io.micronaut.data.jdbc.annotation.JdbcRepository; -import io.micronaut.data.model.query.builder.sql.Dialect; -import io.micronaut.data.repository.CrudRepository; -import jakarta.validation.constraints.NotNull; -import java.util.Optional; import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import org.geysermc.databaseutils.IRepository; +import org.geysermc.databaseutils.meta.Repository; import org.geysermc.floodgate.core.database.entity.LinkedPlayer; -@JdbcRepository(dialect = Dialect.ANSI) -@Requires(property = "config.database.enabled", value = "true") -public interface PlayerLinkRepository extends CrudRepository { - Optional findByBedrockId(@NotNull UUID bedrockId); +@Repository +public interface PlayerLinkRepository extends IRepository { - Optional findByJavaUniqueId(@NotNull UUID javaUniqueId); - - Optional findByBedrockIdOrJavaUniqueId( + CompletableFuture findByBedrockIdOrJavaUniqueId( UUID bedrockId, UUID javaUniqueId ); - Boolean existsByBedrockId(@NotNull UUID bedrockId); - - Boolean existsByJavaUniqueId(@NotNull UUID javaUniqueId); + CompletableFuture existsByBedrockIdOrJavaUniqueId(UUID bedrockId, UUID javaUniqueId); - Boolean existsByBedrockIdOrJavaUniqueId(UUID bedrockId, UUID javaUniqueId); + CompletableFuture deleteByBedrockIdOrJavaUniqueId(UUID bedrockId, UUID javaUniqueId); - void deleteByBedrockIdOrJavaUniqueId(UUID bedrockId, UUID javaUniqueId); + CompletableFuture insert(LinkedPlayer player); } diff --git a/core/src/main/java/org/geysermc/floodgate/core/database/entity/LinkRequest.java b/core/src/main/java/org/geysermc/floodgate/core/database/entity/LinkRequest.java index 35160a16..87f9d2e3 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/database/entity/LinkRequest.java +++ b/core/src/main/java/org/geysermc/floodgate/core/database/entity/LinkRequest.java @@ -25,103 +25,19 @@ package org.geysermc.floodgate.core.database.entity; -import io.micronaut.core.annotation.AccessorsStyle; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.Transient; import java.time.Instant; -import java.util.Objects; import java.util.UUID; +import org.geysermc.databaseutils.meta.Entity; +import org.geysermc.databaseutils.meta.Key; -@Entity -@AccessorsStyle(readPrefixes = "", writePrefixes = "") -public class LinkRequest { - @Id - private UUID javaUniqueId; - private String javaUsername; - private String bedrockUsername; - private String linkCode; - private long requestTime = Instant.now().getEpochSecond(); - - public UUID javaUniqueId() { - return javaUniqueId; - } - - public LinkRequest javaUniqueId(UUID javaUniqueId) { - this.javaUniqueId = javaUniqueId; - return this; - } - - public String javaUsername() { - return javaUsername; - } - - public LinkRequest javaUsername(String javaUsername) { - this.javaUsername = javaUsername; - return this; - } - - public String bedrockUsername() { - return bedrockUsername; - } - - public LinkRequest bedrockUsername(String bedrockUsername) { - this.bedrockUsername = bedrockUsername; - return this; - } - - public String linkCode() { - return linkCode; +@Entity("LinkRequests") +public record LinkRequest(@Key UUID javaUniqueId, String javaUsername, String bedrockUsername, String linkCode, long requestTime) { + public LinkRequest(UUID javaUniqueId, String javaUsername, String bedrockUsername, String linkCode) { + this(javaUniqueId, javaUsername, bedrockUsername, linkCode, Instant.now().getEpochSecond()); } - public LinkRequest linkCode(String linkCode) { - this.linkCode = linkCode; - return this; - } - - public long requestTime() { - return requestTime; - } - - public LinkRequest requestTime(long requestTime) { - this.requestTime = requestTime; - return this; - } - - @Transient public boolean isExpired(long linkTimeout) { long timePassed = Instant.now().getEpochSecond() - requestTime; return timePassed > linkTimeout; } - - @Override - @Transient - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - LinkRequest that = (LinkRequest) o; - return Objects.equals(javaUniqueId, that.javaUniqueId); - } - - @Override - @Transient - public int hashCode() { - return Objects.hash(javaUniqueId); - } - - @Override - @Transient - public String toString() { - return "LinkRequest{" + - "javaUniqueId=" + javaUniqueId + - ", javaUsername='" + javaUsername + '\'' + - ", bedrockUsername='" + bedrockUsername + '\'' + - ", linkCode='" + linkCode + '\'' + - ", requestTime=" + requestTime + - '}'; - } } diff --git a/core/src/main/java/org/geysermc/floodgate/core/database/entity/LinkedPlayer.java b/core/src/main/java/org/geysermc/floodgate/core/database/entity/LinkedPlayer.java index a67ee81c..dee4bc31 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/database/entity/LinkedPlayer.java +++ b/core/src/main/java/org/geysermc/floodgate/core/database/entity/LinkedPlayer.java @@ -25,75 +25,9 @@ package org.geysermc.floodgate.core.database.entity; -import io.micronaut.core.annotation.AccessorsStyle; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.Transient; -import java.util.Objects; import java.util.UUID; +import org.geysermc.databaseutils.meta.Entity; +import org.geysermc.databaseutils.meta.Key; -@Entity -@AccessorsStyle(readPrefixes = "", writePrefixes = "") -public class LinkedPlayer { - @Id - private UUID bedrockId; - private UUID javaUniqueId; - private String javaUsername; - - public UUID bedrockId() { - return bedrockId; - } - - public LinkedPlayer bedrockId(UUID bedrockId) { - this.bedrockId = bedrockId; - return this; - } - - public UUID javaUniqueId() { - return javaUniqueId; - } - - public LinkedPlayer javaUniqueId(UUID javaUniqueId) { - this.javaUniqueId = javaUniqueId; - return this; - } - - public String javaUsername() { - return javaUsername; - } - - public LinkedPlayer javaUsername(String javaUsername) { - this.javaUsername = javaUsername; - return this; - } - - @Override - @Transient - public boolean equals(Object obj) { - if (obj == this) { - return true; - } - if (obj == null || obj.getClass() != this.getClass()) { - return false; - } - var that = (LinkedPlayer) obj; - return Objects.equals(this.bedrockId, that.bedrockId) && - Objects.equals(this.javaUniqueId, that.javaUniqueId); - } - - @Override - @Transient - public int hashCode() { - return Objects.hash(bedrockId, javaUniqueId); - } - - @Override - @Transient - public String toString() { - return "LinkedPlayer[" + - "bedrockId=" + bedrockId + ", " + - "javaUniqueId=" + javaUniqueId + ", " + - "javaUsername=" + javaUsername + ']'; - } - -} +@Entity("LinkedPlayers") +public record LinkedPlayer(@Key UUID bedrockId, UUID javaUniqueId, String javaUsername) { } diff --git a/core/src/main/java/org/geysermc/floodgate/core/database/loader/DatabaseLoader.java b/core/src/main/java/org/geysermc/floodgate/core/database/loader/DatabaseLoader.java new file mode 100644 index 00000000..de289349 --- /dev/null +++ b/core/src/main/java/org/geysermc/floodgate/core/database/loader/DatabaseLoader.java @@ -0,0 +1,44 @@ +package org.geysermc.floodgate.core.database.loader; + +import io.micronaut.context.ApplicationContext; +import java.nio.file.Path; +import org.geysermc.databaseutils.DatabaseUtils; +import org.geysermc.databaseutils.IRepository; +import org.geysermc.databaseutils.sql.SqlDialect; +import org.geysermc.floodgate.core.config.FloodgateConfig; +import org.geysermc.floodgate.isolation.library.LibraryManager; + +public final class DatabaseLoader { + private DatabaseLoader() {} + + public static void load(FloodgateConfig config, LibraryManager manager, Path dataDirectory, ApplicationContext context) { + var databaseConfig = config.database(); + if (databaseConfig.enabled()) { + var type = DatabaseType.byId(databaseConfig.type()); + if (type == null) { + throw new IllegalStateException( + "Unable to find database type that matches: " + databaseConfig.type() + ); + } + + type.libraries().forEach(manager::addLibrary); + manager.apply(); + + try { + Class.forName("org.h2.Driver", true, manager.classLoader()); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + + var databaseUtils = DatabaseUtils.builder() + .credentialsFile(dataDirectory.resolve("database-config.properties")) + .poolName("floodgate") + .dialect(SqlDialect.requireByName(config.database().type())) + .build(); + context.registerSingleton(databaseUtils); + for (IRepository repository : databaseUtils.start()) { + context.registerSingleton(repository); + } + } + } +} diff --git a/core/src/main/java/org/geysermc/floodgate/core/database/loader/DatabaseType.java b/core/src/main/java/org/geysermc/floodgate/core/database/loader/DatabaseType.java index 77e886db..fc6e3526 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/database/loader/DatabaseType.java +++ b/core/src/main/java/org/geysermc/floodgate/core/database/loader/DatabaseType.java @@ -26,37 +26,23 @@ package org.geysermc.floodgate.core.database.loader; import java.util.Locale; -import java.util.Objects; import java.util.Set; import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.floodgate.core.util.Constants; import org.geysermc.floodgate.isolation.library.Library; import org.geysermc.floodgate.isolation.library.Repository; public enum DatabaseType { - H2( - DriverCategory.HIBERNATE, -// databaseModule(), - library("h2", Repository.MAVEN_CENTRAL, "com.h2database", "h2", "1.4.200") - ); + H2(hikariCp(), library("h2", Repository.MAVEN_CENTRAL, "com.h2database", "h2", "2.2.224")); private static final DatabaseType[] VALUES = values(); - private final DriverCategory category; private final Set libraries; - DatabaseType(@NonNull DriverCategory category, @NonNull Library... libraries) { - this.category = Objects.requireNonNull(category); - this.libraries = Set.of(Objects.requireNonNull(libraries)); + DatabaseType(@NonNull Library... libraries) { + this.libraries = Set.of(libraries); } - static Library databaseModule() { - return library( - "database", - Repository.OPEN_COLLAB, - "org.geysermc.floodgate", - "database", - Constants.VERSION - ); + static Library hikariCp() { + return library("HikariCP", Repository.MAVEN_CENTRAL, "com.zaxxer", "HikariCP", "5.1.0"); } static Library library( @@ -85,10 +71,6 @@ public static DatabaseType byId(String id) { return null; } - public DriverCategory category() { - return category; - } - public Set libraries() { return libraries; } diff --git a/core/src/main/java/org/geysermc/floodgate/core/http/link/LinkedPlayer.java b/core/src/main/java/org/geysermc/floodgate/core/http/link/LinkedPlayer.java index f0dbcc16..bf65fce9 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/http/link/LinkedPlayer.java +++ b/core/src/main/java/org/geysermc/floodgate/core/http/link/LinkedPlayer.java @@ -56,9 +56,6 @@ public org.geysermc.floodgate.core.database.entity.LinkedPlayer toDatabase() { return null; } - return new org.geysermc.floodgate.core.database.entity.LinkedPlayer() - .bedrockId(Utils.getJavaUuid(xuid)) - .javaUniqueId(uuid) - .javaUsername(username); + return new org.geysermc.floodgate.core.database.entity.LinkedPlayer(Utils.getJavaUuid(xuid), uuid, username); } } diff --git a/core/src/main/java/org/geysermc/floodgate/core/link/PlayerLinkJdbc.java b/core/src/main/java/org/geysermc/floodgate/core/link/LocalPlayerLinking.java similarity index 71% rename from core/src/main/java/org/geysermc/floodgate/core/link/PlayerLinkJdbc.java rename to core/src/main/java/org/geysermc/floodgate/core/link/LocalPlayerLinking.java index 33675ade..e2b677f7 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/link/PlayerLinkJdbc.java +++ b/core/src/main/java/org/geysermc/floodgate/core/link/LocalPlayerLinking.java @@ -34,7 +34,6 @@ import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; -import java.util.function.Supplier; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.floodgate.core.database.PendingLinkRepository; import org.geysermc.floodgate.core.database.PlayerLinkRepository; @@ -47,7 +46,7 @@ @Replaces(DisabledPlayerLink.class) @Named("localLinking") @Singleton -public class PlayerLinkJdbc extends CommonPlayerLink { +public class LocalPlayerLinking extends CommonPlayerLink { @Inject PlayerLinkRepository linkRepository; @Inject PendingLinkRepository pendingLinkRepository; @@ -60,26 +59,22 @@ public CompletableFuture addLink( @NonNull UUID javaUniqueId, @NonNull String javaUsername, @NonNull UUID bedrockId) { - return async(() -> linkRepository.save( - new LinkedPlayer() - .javaUniqueId(javaUniqueId) - .javaUsername(javaUsername) - .bedrockId(bedrockId))); + return linkRepository.insert(new LinkedPlayer(bedrockId, javaUniqueId, javaUsername)); } @Override public CompletableFuture fetchLink(@NonNull UUID uuid) { - return async(() -> linkRepository.findByBedrockIdOrJavaUniqueId(uuid, uuid).orElse(null)); + return linkRepository.findByBedrockIdOrJavaUniqueId(uuid, uuid); } @Override public CompletableFuture isLinked(@NonNull UUID uuid) { - return async(() -> linkRepository.existsByBedrockIdOrJavaUniqueId(uuid, uuid)); + return linkRepository.existsByBedrockIdOrJavaUniqueId(uuid, uuid); } @Override public CompletableFuture unlink(@NonNull UUID uuid) { - return run(() -> linkRepository.deleteByBedrockIdOrJavaUniqueId(uuid, uuid)); + return linkRepository.deleteByBedrockIdOrJavaUniqueId(uuid, uuid); } @Override @@ -88,29 +83,16 @@ public CompletableFuture createLinkRequest( @NonNull String javaUsername, @NonNull String bedrockUsername, @NonNull String code) { - return async(() -> pendingLinkRepository.save( - new LinkRequest() - .javaUniqueId(javaUniqueId) - .javaUsername(javaUsername) - .bedrockUsername(bedrockUsername) - .linkCode(code))); + return pendingLinkRepository.insert(new LinkRequest(javaUniqueId, javaUsername, bedrockUsername, code)); } @Override public CompletableFuture linkRequest(@NonNull String javaUsername) { - return async(() -> pendingLinkRepository.findByJavaUsername(javaUsername)); + return pendingLinkRepository.findByJavaUsername(javaUsername); } @Override public CompletableFuture invalidateLinkRequest(@NonNull LinkRequest request) { - return run(() -> pendingLinkRepository.delete(request)); - } - - private CompletableFuture async(Supplier toExecute) { - return CompletableFuture.supplyAsync(toExecute, executor); - } - - private CompletableFuture run(Runnable toExecute) { - return CompletableFuture.runAsync(toExecute); + return pendingLinkRepository.delete(request); } } diff --git a/core/src/main/java/org/geysermc/floodgate/core/module/CommonModule.java b/core/src/main/java/org/geysermc/floodgate/core/module/CommonModule.java index 187376fb..57400e04 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/module/CommonModule.java +++ b/core/src/main/java/org/geysermc/floodgate/core/module/CommonModule.java @@ -26,13 +26,10 @@ package org.geysermc.floodgate.core.module; import io.micronaut.context.annotation.Bean; -import io.micronaut.context.annotation.BootstrapContextCompatible; import io.micronaut.context.annotation.Factory; import io.netty.util.AttributeKey; import jakarta.inject.Named; import jakarta.inject.Singleton; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -44,10 +41,8 @@ import org.geysermc.floodgate.core.crypto.topping.Base64Topping; import org.geysermc.floodgate.core.crypto.topping.Topping; import org.geysermc.floodgate.core.util.Constants; -import org.geysermc.floodgate.core.util.GlobalBeanCache; @Factory -@BootstrapContextCompatible public class CommonModule { @Bean(preDestroy = "shutdown") @Singleton @@ -64,29 +59,16 @@ public ScheduledExecutorService commonScheduledPool() { } @Bean - @BootstrapContextCompatible - @Singleton - @Named("dataDirectory") - public Path dataDirectory() { - // todo discussion asking how you can register bootstrap context beans - // https://github.com/micronaut-projects/micronaut-core/discussions/9191 - return Paths.get("plugins", "floodgate"); - } - - @Bean - @BootstrapContextCompatible @Singleton public DataCodecType codecType() { //todo make it a config option and remove this one - // just like the topping it shouldn't need BootstrapContextCompatible - return GlobalBeanCache.cacheIfAbsent("codecType", () -> DataCodecType.AES); + return DataCodecType.AES; } @Bean - @BootstrapContextCompatible @Singleton public Topping topping() { - return GlobalBeanCache.cacheIfAbsent("topping", Base64Topping::new); + return new Base64Topping(); } @Bean diff --git a/core/src/main/resources/dependencyInfo.txt b/core/src/main/resources/dependencyInfo.txt deleted file mode 100644 index 4c0079d2..00000000 --- a/core/src/main/resources/dependencyInfo.txt +++ /dev/null @@ -1,16 +0,0 @@ -org.geysermc.configutils:configutils:2.0-SNAPSHOT:HiYf2qgXat5WOQOScSXPk8FBIKZDWYowCJPVJ+Uuv+0= -com.google.inject:guice:5.1.0:QTDlC/rEgJnIYPDZA7kYYMgaJJyQ84JF+P7Vj8gXvCY= -com.nukkitx.fastutil:fastutil-short-object-maps:8.5.3:nTF5o2PCLMeBm8gaPeU4Q41FG2CNpmC9PxeJVHZot+U= -com.nukkitx.fastutil:fastutil-int-object-maps:8.5.3:Z0iKxf9OmoIcQtmqV9Lo9Z39XSpBXKjL8tavAdVCKBY= -org.java-websocket:Java-WebSocket:1.5.2:/4adGYqNxdAJZzkuGHrtqTuDO3zdO8zvs9f7WDQJi4U= -cloud.commandframework:cloud-core:1.5.0:+hDJlLwU84P6sf0gkDq+xStIqAHhMXUCI+Wb8VsD1Zk= -io.micronaut.data:micronaut-data-model:3.9.6:Hdt2G2LRuAtIs1K2DayRz7OoiqZcbIfCUEstVIpQnUE= -io.micronaut.sql:micronaut-jdbc-hikari:4.7.2:w2N1dH4vY/QjjQGsViMOwgVYxAnZNGgMm1doCa19wOA= -io.micronaut.data:micronaut-data-hibernate-jpa:3.9.6:kFYugtQeXfLjqUCWrf3MFFDoUdYhXrPQmSh0pu2Zxzo= -io.micronaut:micronaut-context:3.8.7:ir020Tq3UavnPZhXOUNHCl/XdGcVrOzhM1lU5NT6YEc= -io.micronaut:micronaut-inject-java:3.8.7:V7Dxe3ctZ8+c7ZUDQ3Cwtsqc6S7l2SE8+qTVhvhTHQs= -io.micronaut:micronaut-inject:3.8.7:6C+sHfQBffYWV/LnD+Vc5WhqRbkWZIgJXqxThca2tXE= -org.yaml:snakeyaml:2.0:iAydiW5LdKBsVJwVyklkUBZdaQn6FdfmYr7o9qZtevo= -org.bstats:bstats-base:3.0.1:vdyqrd84GBpK0MnfDnSXXMTauyzL9nkMSfAiMOrVU2Q= -com.google.guava:guava:31.1-jre:pC7cnKt5Ljn+ObuU8/ymVe0Vf/h6iveOHWulsHxKAKs= -com.h2database:h2:1.4.200:OtmsS2qunNnTrBxEdGXh7QYBm4UbiT3WqNdt222FvKY= \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a33695d0..c6cbe0c1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,6 +12,7 @@ gson = "2.8.5" # core base-api = "feature-floodgate-merge-1.1.0-SNAPSHOT" config-utils = "development-2.0-SNAPSHOT" +database-utils = "1.0-SNAPSHOT" fastutil = "8.5.3" java-websocket = "1.5.2" cloud = "1.5.0" @@ -48,6 +49,10 @@ netty-transport = { module = "io.netty:netty-transport", version.ref = "netty" } base-api = { module = "org.geysermc.api:base-api", version.ref = "base-api" } config-utils = { module = "org.geysermc.configutils:core", version.ref = "config-utils" } config-utils-ap = { module = "org.geysermc.configutils:ap", version.ref = "config-utils" } +database-utils = { module = "org.geysermc.databaseutils:core", version.ref = "database-utils" } +database-utils-sql = { module = "org.geysermc.databaseutils:database-sql", version.ref = "database-utils" } +database-utils-mongo = { module = "org.geysermc.databaseutils:database-mongo", version.ref = "database-utils" } +database-utils-ap = { module = "org.geysermc.databaseutils:ap", version.ref = "database-utils" } fastutil-short-object-maps = { module = "com.nukkitx.fastutil:fastutil-short-object-maps", version.ref = "fastutil" } fastutil-int-object-maps = { module = "com.nukkitx.fastutil:fastutil-int-object-maps", version.ref = "fastutil" } java-websocket = { module = "org.java-websocket:Java-WebSocket", version.ref = "java-websocket" }