gradle sucks etc

This commit is contained in:
kento2 2026-06-27 16:46:30 +02:00
parent 72b4edf48b
commit b0d4a7d061
25 changed files with 463 additions and 123 deletions

View file

@ -1,4 +1,5 @@
TODO
- cleanup nats
- timeout/error handling with reactive
- djb's multilogd for logging(?)

View file

@ -7,7 +7,7 @@ plugins {
}
group = "de.kentoj.scrow"
version = "1.0-SNAPSHOT"
version = "1.0.0"
repositories {
mavenCentral()
@ -18,6 +18,8 @@ subprojects {
apply(plugin = "java")
apply(plugin = "io.freefair.lombok")
version = rootProject.version
java {
withSourcesJar()
withJavadocJar()
@ -49,6 +51,14 @@ subprojects {
// https://www.mongodb.com/docs/languages/java/reactive-streams-driver/current/get-started/download-and-install/
implementation(platform("org.mongodb:mongodb-driver-bom:5.6.1"))
implementation("org.mongodb:mongodb-driver-reactivestreams")
// https://mvnrepository.com/artifact/org.postgresql/r2dbc-postgresql
// TODO remove or fully switch to postgres
implementation("org.postgresql:r2dbc-postgresql:1.1.1.RELEASE")
// https://mvnrepository.com/artifact/org.springframework.data/spring-data-r2dbc
implementation("org.springframework.data:spring-data-r2dbc:4.1.0-RC1")
// https://mvnrepository.com/artifact/io.r2dbc/r2dbc-pool
implementation("io.r2dbc:r2dbc-pool:1.0.2.RELEASE")
}
}

View file

@ -5,7 +5,6 @@ plugins {
}
group = "de.kentoj.scrow"
version = "1.0-SNAPSHOT"
repositories {
mavenCentral()

View file

@ -1,9 +1,9 @@
package de.kentoj.scrow.bukkit;
import com.mongodb.reactivestreams.client.MongoDatabase;
import de.kentoj.kencommandapi.BukkitKenCommandApi;
import de.kentoj.scrow.bukkit.friends.FriendRequestService;
import de.kentoj.scrow.bukkit.friends.FriendshipService;
import de.kentoj.scrowlib.connection.DatabaseConnectionFactory;
import de.kentoj.scrowlib.servermanager.ServerManager;
import io.nats.client.Connection;
import lombok.AccessLevel;
@ -17,7 +17,7 @@ import reactor.core.scheduler.Scheduler;
public class ScrowAPI {
@Getter
private static @Nullable MongoDatabase database;
private static DatabaseConnectionFactory dbConFactory;
@Getter
private static BukkitKenCommandApi commandApi;
@Getter
@ -33,11 +33,6 @@ public class ScrowAPI {
@Getter
private static ServerManager serverManager;
@ApiStatus.Internal
public static void setDatabase(@Nullable MongoDatabase database) {
ScrowAPI.database = database;
}
@ApiStatus.Internal
public static void setEconomyService(EconomyService economyService) {
ScrowAPI.economyService = economyService;
@ -72,5 +67,10 @@ public class ScrowAPI {
public static void setServerManager(ServerManager serverManager) {
ScrowAPI.serverManager = serverManager;
}
@ApiStatus.Internal
public static void setDbConFactory(@Nullable DatabaseConnectionFactory dbConFactory) {
ScrowAPI.dbConFactory = dbConFactory;
}
}

View file

@ -0,0 +1,12 @@
package de.kentoj.scrow.bukkit.minigame;
import de.kentoj.scrowlib.servermanager.ServerInstance;
public interface MinigameInfo {
String getName();
int getPlayerCount();
ServerInstance getServerInstance();
}

View file

@ -6,7 +6,6 @@ plugins {
}
group = "de.kentoj.scrow"
version = "1.0-SNAPSHOT"
repositories {
mavenCentral()
@ -16,9 +15,6 @@ dependencies {
implementation(project(":core-bukkit-api"))
implementation(kotlin("stdlib-jdk8"))
//implementation("org.spigotmc:spigot-api:1.21.11-R0.1-SNAPSHOT")
//implementation("de.kentoj.scrow:kencommandapi-bukkit:0.8")
}
tasks {
@ -31,6 +27,14 @@ tasks {
}
}
tasks.processResources {
filesMatching("plugin.yml") {
expand(mapOf(
"version" to project.version.toString()
))
}
}
tasks.build {
dependsOn("shadowJar")
}
}

View file

@ -1,27 +1,23 @@
package de.kentoj.scrow.bukkit;
import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import com.mongodb.reactivestreams.client.MongoClient;
import com.mongodb.reactivestreams.client.MongoClients;
import de.kentoj.kencommandapi.BukkitKenCommandApi;
import de.kentoj.scrow.bukkit.economy.InMemoryEconomyService;
import de.kentoj.scrow.bukkit.economy.MongoEconomyService;
import de.kentoj.scrow.bukkit.economy.PostgresEconomyService;
import de.kentoj.scrow.bukkit.friends.friendship.InMemoryFriendshipService;
import de.kentoj.scrow.bukkit.friends.friendship.MongoFriendshipService;
import de.kentoj.scrow.bukkit.friends.friendship.PostgresFriendshipService;
import de.kentoj.scrow.bukkit.friends.request.InMemoryFriendRequestService;
import de.kentoj.scrow.bukkit.friends.request.MongoFriendRequestService;
import de.kentoj.scrow.bukkit.friends.request.PostgresFriendRequestService;
import de.kentoj.scrowlib.connection.DatabaseConnectionFactoryImpl;
import de.kentoj.scrowlib.servermanager.ServerManagerImpl;
import io.nats.client.Nats;
import io.nats.client.Options;
import io.r2dbc.spi.ConnectionFactories;
import io.r2dbc.spi.ConnectionFactory;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.bson.UuidRepresentation;
import org.bson.codecs.configuration.CodecRegistries;
import org.bson.codecs.pojo.PojoCodecProvider;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.Nullable;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
import java.io.IOException;
@ -29,8 +25,6 @@ import java.io.IOException;
@NoArgsConstructor(access = AccessLevel.NONE)
public class ScrowAPISurface {
private static @Nullable MongoClient mongoClient;
public static void initScrowAPI(Plugin plugin, boolean enableDatabase) {
ScrowAPI.setMinecraftScheduler(Schedulers.fromExecutor(cmd -> {
Bukkit.getScheduler().runTask(plugin, cmd);
@ -48,39 +42,25 @@ public class ScrowAPISurface {
}
if (enableDatabase) {
var pojoCodecProvider = PojoCodecProvider.builder().automatic(true).build();
var codecRegistry = CodecRegistries.fromRegistries(
MongoClientSettings.getDefaultCodecRegistry(),
CodecRegistries.fromProviders(pojoCodecProvider)
);
String mongoHost = System.getenv("HOST_MONGO");
var settings = MongoClientSettings.builder()
.codecRegistry(codecRegistry)
.uuidRepresentation(UuidRepresentation.STANDARD)
.applyConnectionString(new ConnectionString(mongoHost))
.build();
mongoClient = MongoClients.create(settings);
ScrowAPI.setDatabase(mongoClient.getDatabase("scrow"));
ConnectionFactory factory = ConnectionFactories.get(System.getenv("HOST_POSTGRES"));
ScrowAPI.setDbConFactory(new DatabaseConnectionFactoryImpl(factory));
}
ScrowAPI.setServerManager(new ServerManagerImpl(ScrowAPI.getNats()));
ScrowAPI.setEconomyService(ScrowAPI.getDatabase() != null ?
new MongoEconomyService(ScrowAPI.getDatabase()) : new InMemoryEconomyService());
ScrowAPI.setFriendRequestService(ScrowAPI.getDatabase() != null ?
new MongoFriendRequestService(ScrowAPI.getDatabase()) : new InMemoryFriendRequestService());
ScrowAPI.setFriendshipService(ScrowAPI.getDatabase() != null ?
new MongoFriendshipService(ScrowAPI.getDatabase()) : new InMemoryFriendshipService());
ScrowAPI.setEconomyService(ScrowAPI.getDbConFactory() != null ?
new PostgresEconomyService(ScrowAPI.getDbConFactory()) : new InMemoryEconomyService());
ScrowAPI.setFriendRequestService(ScrowAPI.getDbConFactory() != null ?
new PostgresFriendRequestService(ScrowAPI.getDbConFactory()) : new InMemoryFriendRequestService());
ScrowAPI.setFriendshipService(ScrowAPI.getDbConFactory() != null ?
new PostgresFriendshipService(ScrowAPI.getDbConFactory()) : new InMemoryFriendshipService());
ScrowAPI.setCommandApi(new BukkitKenCommandApi());
}
public static void destroyScrowAPI() {
if (mongoClient != null) {
mongoClient.close();
try {
ScrowAPI.getDbConFactory().close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View file

@ -0,0 +1,86 @@
package de.kentoj.scrow.bukkit.economy;
import com.google.common.base.Preconditions;
import de.kentoj.scrow.bukkit.EconomyService;
import de.kentoj.scrowlib.connection.DatabaseConnectionFactory;
import org.jetbrains.annotations.NotNull;
import reactor.core.publisher.Mono;
import java.util.UUID;
// TODO log operations to separate table
public class PostgresEconomyService implements EconomyService {
private final DatabaseConnectionFactory conFactory;
public PostgresEconomyService(DatabaseConnectionFactory conFactory) {
this.conFactory = conFactory;
conFactory.create().sql("""
CREATE TABLE IF NOT EXISTS economy (
playerId UUID NOT NULL,
balance INTEGER NOT NULL DEFAULT 0,
PRIMARY KEY(playerId)
)
""").then().block();
}
@Override
public Mono<@NotNull Integer> getCoins(UUID playerId) {
return conFactory.create()
.sql("""
SELECT balance
FROM economy
WHERE playerId = :playerId
""")
.bind("playerId", playerId)
.map(row -> row.get("balance", Integer.class))
.one();
}
@Override
public Mono<@NotNull Void> setCoins(UUID playerId, int amount) {
Preconditions.checkArgument(amount >= 0, "amount can not be negative");
return conFactory.create().sql("""
INSERT INTO economy (playerId, balance)
VALUES (:playerId, :amount)
ON CONFLICT (playerId)
DO UPDATE
SET balance = :amount
WHERE economy.playerId = :playerId
""")
.bind("playerId", playerId)
.bind("amount", amount)
.then();
}
@Override
public Mono<@NotNull Void> depositCoins(UUID playerId, int amount) {
Preconditions.checkArgument(amount >= 0, "amount can not be negative");
return conFactory.create().sql("""
INSERT INTO economy (playerId, balance)
VALUES (:playerId, :amount)
ON CONFLICT (playerId)
DO UPDATE
SET balance = economy.balance + EXCLUDED.balance
WHERE economy.playerId = :playerId
""")
.bind("playerId", playerId)
.bind("amount", amount)
.then();
}
@Override
public Mono<@NotNull Boolean> tryWithdrawCoins(UUID playerId, int amount) {
Preconditions.checkArgument(amount >= 0, "amount can not be negative");
return conFactory.create().sql("""
UPDATE economy
SET balance = balance - :amount
WHERE playerId = :playerId
""")
.bind("playerId", playerId)
.bind("amount", amount)
.fetch()
.rowsUpdated()
.map(updated -> updated > 0);
}
}

View file

@ -19,11 +19,10 @@ public class FriendAddLiteral implements CommandExecutor<CommandSender, BukkitCo
public FriendAddLiteral() {
var cmds = ScrowAPI.getCommandApi();
this.playerArg = cmds.createArgument("player", OfflinePlayerArgumentType.getInstance());
this.rootNode = cmds.createNode("add");
this.rootNode.addArgument(playerArg);
this.rootNode.setExecutor(this);
playerArg = cmds.createArgument("player", OfflinePlayerArgumentType.getInstance());
rootNode = cmds.createNode("add");
rootNode.addArgument(playerArg);
rootNode.setExecutor(this);
}
@Override

View file

@ -0,0 +1,96 @@
package de.kentoj.scrow.bukkit.friends.friendship;
import de.kentoj.scrow.bukkit.friends.Friendship;
import de.kentoj.scrow.bukkit.friends.FriendshipService;
import de.kentoj.scrow.bukkit.friends.OrderedUUIDPair;
import de.kentoj.scrowlib.connection.DatabaseConnectionFactory;
import org.jetbrains.annotations.NotNull;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.Instant;
import java.util.UUID;
public class PostgresFriendshipService implements FriendshipService {
private final DatabaseConnectionFactory dbConFactory;
public PostgresFriendshipService(DatabaseConnectionFactory dbConFactory) {
this.dbConFactory = dbConFactory;
this.dbConFactory.create().sql("""
CREATE TABLE IF NOT EXISTS friendships (
first_uuid UUID NOT NULL,
second_uuid UUID NOT NULL,
created_at TIMESTAMPTZ NOT NULL,
PRIMARY KEY (first_uuid, second_uuid),
CONSTRAINT friendship_no_self_friendship
CHECK (first_uuid <> second_uuid)
)
""").then().block();
}
@Override
public Mono<@NotNull Friendship> getFriendship(UUID uuid1, UUID uuid2) {
var uuids = new OrderedUUIDPair(uuid1, uuid2);
return dbConFactory.create().sql("""
SELECT first_uuid, second_uuid, created_at
FROM friendships
WHERE first_uuid = :first AND second_uuid = :second
""")
.bind("first", uuids.getFirst())
.bind("second", uuids.getSecond())
.map(row -> (Friendship) new FriendshipImpl(
row.get("first_uuid", UUID.class),
row.get("second_uuid", UUID.class),
row.get("created_at", Instant.class)
))
.one();
}
@Override
public Flux<@NotNull Friendship> getFriendships(UUID playerId) {
return dbConFactory.create().sql("""
SELECT first_uuid, second_uuid, created_at
FROM friendships
WHERE first_uuid = :playerId OR second_uuid = :playerId
""")
.bind("playerId", playerId)
.map((row, meta) -> (Friendship) new FriendshipImpl(
row.get("first_uuid", UUID.class),
row.get("second_uuid", UUID.class),
row.get("created_at", Instant.class)
))
.all();
}
@Override
public Mono<@NotNull Boolean> saveFriendship(Friendship friendship) {
return dbConFactory.create().sql("""
INSERT INTO friendships (first_uuid, second_uuid, created_at)
VALUES (:first, :second, :createdAt)
ON CONFLICT (first_uuid, second_uuid) DO NOTHING
""")
.bind("first", friendship.getUuids().getFirst())
.bind("second", friendship.getUuids().getSecond())
.bind("createdAt", friendship.getCreatedAt())
.fetch()
.rowsUpdated()
.map(rows -> rows > 0);
}
@Override
public Mono<@NotNull Boolean> deleteFriendship(UUID uuid1, UUID uuid2) {
var uuids = new OrderedUUIDPair(uuid1, uuid2);
return dbConFactory.create().sql("""
DELETE FROM friendships
WHERE first_uuid = :first AND second_uuid = :second
""")
.bind("first", uuids.getFirst())
.bind("second", uuids.getSecond())
.fetch()
.rowsUpdated()
.map(rows -> rows > 0);
}
}

View file

@ -0,0 +1,104 @@
package de.kentoj.scrow.bukkit.friends.request;
import de.kentoj.scrow.bukkit.friends.FriendRequest;
import de.kentoj.scrow.bukkit.friends.FriendRequestService;
import de.kentoj.scrowlib.connection.DatabaseConnectionFactory;
import io.r2dbc.spi.Readable;
import org.jetbrains.annotations.NotNull;
import org.springframework.r2dbc.core.DatabaseClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.Instant;
import java.util.UUID;
public class PostgresFriendRequestService implements FriendRequestService {
private final DatabaseConnectionFactory conFactory;
public PostgresFriendRequestService(DatabaseConnectionFactory conFactory) {
this.conFactory = conFactory;
conFactory.create().sql("""
CREATE TABLE IF NOT EXISTS friend-requests (
from_uuid UUID NOT NULL,
to_uuid UUID NOT NULL,
created_at TIMESTAMPTZ NOT NULL,
PRIMARY KEY (first_uuid, second_uuid),
CONSTRAINT friendship_no_self_friendship
CHECK (first_uuid <> second_uuid)
)
""").then().block();
}
@Override
public Mono<@NotNull FriendRequest> getFriendRequest(UUID from, UUID to) {
return conFactory.create().sql("""
SELECT *
FROM friend-requests
WHERE from_uuid = :from AND to_uuid = :to
""")
.bind("from", from)
.bind("to", to)
.map(this::parseFriendRequest)
.one();
}
@Override
public Mono<@NotNull Boolean> saveFriendRequest(FriendRequest friendRequest) {
return conFactory.create().sql("""
INSERT INTO friend-requests (from_uuid, to_uuid, created_at)
VALUES (:from, :to, :created_at)
""")
.bind("from", friendRequest.getFrom())
.bind("to", friendRequest.getTo())
.fetch()
.rowsUpdated()
.map(cnt -> cnt > 0);
}
@Override
public Flux<@NotNull FriendRequest> getFriendRequestsTo(UUID playerId) {
return conFactory.create().sql("""
SELECT *
FROM friend-requests
WHERE to_uuid = :to
""")
.bind("to", playerId)
.map(this::parseFriendRequest)
.all();
}
@Override
public Flux<@NotNull FriendRequest> getFriendRequestsFrom(UUID playerId) {
return conFactory.create().sql("""
SELECT *
FROM friend-requests
WHERE from_uuid = :from
""")
.bind("from", playerId)
.map(this::parseFriendRequest)
.all();
}
@Override
public Mono<@NotNull Boolean> deleteFriendRequest(UUID from, UUID to) {
return conFactory.create().sql("""
DELETE
FROM friend-requests
WHERE from_uuid = :from AND to_uuid = :to
""")
.bind("from", from)
.bind("to", to)
.fetch()
.rowsUpdated()
.map(deleted -> deleted > 0);
}
private FriendRequest parseFriendRequest(Readable row) {
return new FriendRequestImpl(
row.get("from_uuid", UUID.class),
row.get("to_uuid", UUID.class),
row.get("created_at", Instant.class)
);
}
}

View file

@ -1,5 +1,5 @@
name: "CoreBukkit"
version: "1.0"
version: "${version}"
main: "de.kentoj.scrow.bukkit.CoreImplPlugin"
api-version: "1.21"
author: "Kento2 <kento@placeq.com>"
author: "Kento2"

View file

@ -8,7 +8,6 @@ plugins {
}
group = "de.kentoj.scrow"
version = "0.4"
repositories {
mavenCentral()

View file

@ -0,0 +1,8 @@
package de.kentoj.scrowlib.connection;
import org.springframework.r2dbc.core.DatabaseClient;
public interface DatabaseConnectionFactory extends AutoCloseable {
DatabaseClient create();
}

View file

@ -0,0 +1,31 @@
package de.kentoj.scrowlib.connection;
import io.r2dbc.pool.ConnectionPool;
import io.r2dbc.pool.ConnectionPoolConfiguration;
import io.r2dbc.spi.ConnectionFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.r2dbc.core.DatabaseClient;
@RequiredArgsConstructor
public class DatabaseConnectionFactoryImpl implements DatabaseConnectionFactory {
private final ConnectionPool backingFactory;
public DatabaseConnectionFactoryImpl(ConnectionFactory connectionFactory) {
this(new ConnectionPool(ConnectionPoolConfiguration.builder()
.connectionFactory(connectionFactory)
.build()));
}
// FIXME
// its been a while and i no longer remember what had to be fixed
@Override
public DatabaseClient create() {
return DatabaseClient.create(backingFactory);
}
@Override
public void close() {
backingFactory.close();
}
}

View file

@ -6,9 +6,12 @@ import io.nats.client.Dispatcher;
import io.nats.client.Message;
import org.bson.Document;
import org.jetbrains.annotations.NotNull;
import reactor.core.Disposable;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.concurrent.atomic.AtomicBoolean;
public class NatsRepository {
private final Connection nats;
@ -34,15 +37,13 @@ public class NatsRepository {
public Flux<@NotNull SubscriptionContext> subscribe(String subject) {
return Flux.create(sink -> {
var handler = dispatcher.subscribe(subject, msg -> {
dispatcher.subscribe(subject, msg -> {
try {
sink.next(new SubscriptionContext(msg));
} catch (Throwable e) {
sink.error(e);
}
});
sink.onCancel(handler::unsubscribe);
sink.onDispose(handler::unsubscribe);
});
}

View file

@ -1,6 +1,5 @@
package de.kentoj.scrowlib.messaging;
import de.kentoj.scrowlib.messaging.respose.SafeResult;
import io.nats.client.Message;
import lombok.AllArgsConstructor;
import lombok.Value;
@ -13,6 +12,6 @@ public class SubscriptionContext {
Document document;
public SubscriptionContext(Message msg) {
this(msg, SafeResult.fromMessage(msg).unwrap());
this(msg, DocumentRepository.fromMessage(msg));
}
}

View file

@ -3,6 +3,8 @@ package de.kentoj.scrowlib.messaging.respose;
import de.kentoj.scrowlib.messaging.DocumentRepository;
import io.nats.client.Message;
import org.bson.Document;
import org.jetbrains.annotations.NotNull;
import reactor.core.publisher.Mono;
public abstract sealed class SafeResult permits SafeErrorResult, SafeSuccessResult {
@ -61,4 +63,9 @@ public abstract sealed class SafeResult permits SafeErrorResult, SafeSuccessResu
}
throw new IllegalArgumentException("document does not conform to SafeDocument format");
}
public static Mono<@NotNull SafeResult> mono(Mono<@NotNull Document> mono) {
return mono.map(SafeResult::wrap)
.onErrorResume(err -> Mono.just(SafeResult.wrap(err)));
}
}

View file

@ -5,7 +5,6 @@ plugins {
}
group = "de.kentoj.scrow"
version = "0.1"
repositories {
mavenCentral()

View file

@ -1,7 +1,7 @@
package de.kentoj.scrow.velocity;
import com.mongodb.reactivestreams.client.MongoDatabase;
import de.kentoj.kencommandapi.VelocityKenCommandApi;
import de.kentoj.scrowlib.connection.DatabaseConnectionFactory;
import de.kentoj.scrowlib.servermanager.ServerManager;
import io.nats.client.Connection;
import lombok.AccessLevel;
@ -14,7 +14,7 @@ import org.jetbrains.annotations.Nullable;
public class ScrowAPI {
@Getter
private static @Nullable MongoDatabase database;
private static DatabaseConnectionFactory dbConFactory;
@Getter
private static VelocityKenCommandApi commandApi;
@Getter
@ -22,11 +22,6 @@ public class ScrowAPI {
@Getter
private static ServerManager serverManager;
@ApiStatus.Internal
public static void setDatabase(@Nullable MongoDatabase database) {
ScrowAPI.database = database;
}
@ApiStatus.Internal
public static void setCommandApi(VelocityKenCommandApi commandApi) {
ScrowAPI.commandApi = commandApi;
@ -41,5 +36,10 @@ public class ScrowAPI {
public static void setServerManager(ServerManager serverManager) {
ScrowAPI.serverManager = serverManager;
}
@ApiStatus.Internal
public static void setDbConFactory(@Nullable DatabaseConnectionFactory dbConFactory) {
ScrowAPI.dbConFactory = dbConFactory;
}
}

View file

@ -4,7 +4,6 @@ plugins {
}
group = "de.kentoj.scrow"
version = "0.1"
repositories {
mavenCentral()
@ -25,4 +24,27 @@ dependencies {
// http://forge.kentoj.de/scrow/-/packages/maven/de.kentoj.scrow:kencommandapi-velocity
implementation("de.kentoj.scrow:kencommandapi-velocity")
}
val generateBuildInfo by tasks.registering {
val outputDir = layout.buildDirectory.dir("generated/sources/buildInfo")
outputs.dir(outputDir)
doLast {
val file = outputDir.get()
.file("de/kentoj/scrow/generated/BuildInfo.java")
.asFile
file.parentFile.mkdirs()
file.writeText(
"""
package de.kentoj.scrow.generated;
public final class BuildInfo {
private BuildInfo() {}
public static final String VERSION = "${project.version}";
}
""".trimIndent()
)
}
}
sourceSets.main {
java.srcDir(generateBuildInfo)
}

View file

@ -7,13 +7,16 @@ import de.kentoj.scrow.corevelocity.command.OnlineCommand;
import de.kentoj.scrow.corevelocity.privmsg.LastTargetCache;
import de.kentoj.scrow.corevelocity.privmsg.MsgCommand;
import de.kentoj.scrow.corevelocity.privmsg.ReplyCommand;
import de.kentoj.scrow.corevelocity.server.SendPlayerWatchdog;
import de.kentoj.scrow.corevelocity.server.ServerRegisterWatchdog;
import de.kentoj.scrow.generated.BuildInfo; // may not resolve until building for the first time
import de.kentoj.scrow.velocity.ScrowAPI;
import lombok.extern.java.Log;
@Plugin(
id = "corevelocity",
name = "CoreVelocity",
version = "0.1"
version = BuildInfo.VERSION // may not resolve until building for the first time
)
@Log
public class CoreVelocityPlugin {

View file

@ -1,29 +1,22 @@
package de.kentoj.scrow.corevelocity;
import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import com.mongodb.reactivestreams.client.MongoClient;
import com.mongodb.reactivestreams.client.MongoClients;
import com.velocitypowered.api.proxy.ProxyServer;
import de.kentoj.kencommandapi.VelocityKenCommandApi;
import de.kentoj.scrow.velocity.ScrowAPI;
import de.kentoj.scrowlib.connection.DatabaseConnectionFactoryImpl;
import de.kentoj.scrowlib.servermanager.ServerManagerImpl;
import io.nats.client.Nats;
import io.nats.client.Options;
import io.r2dbc.spi.ConnectionFactories;
import io.r2dbc.spi.ConnectionFactory;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.bson.UuidRepresentation;
import org.bson.codecs.configuration.CodecRegistries;
import org.bson.codecs.pojo.PojoCodecProvider;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
@NoArgsConstructor(access = AccessLevel.NONE)
public class ScrowAPISurface {
private static @Nullable MongoClient mongoClient;
public static void initScrowAPI(ProxyServer server, boolean enableDatabase) {
try {
String natsHost = System.getenv("HOST_NATS");
@ -37,20 +30,8 @@ public class ScrowAPISurface {
}
if (enableDatabase) {
var pojoCodecProvider = PojoCodecProvider.builder().automatic(true).build();
var codecRegistry = CodecRegistries.fromRegistries(
MongoClientSettings.getDefaultCodecRegistry(),
CodecRegistries.fromProviders(pojoCodecProvider)
);
String mongoHost = System.getenv("HOST_MONGO");
var settings = MongoClientSettings.builder()
.codecRegistry(codecRegistry)
.uuidRepresentation(UuidRepresentation.STANDARD)
.applyConnectionString(new ConnectionString(mongoHost))
.build();
mongoClient = MongoClients.create(settings);
ScrowAPI.setDatabase(mongoClient.getDatabase("scrow"));
ConnectionFactory factory = ConnectionFactories.get(System.getenv("HOST_POSTGRES"));
ScrowAPI.setDbConFactory(new DatabaseConnectionFactoryImpl(factory));
}
ScrowAPI.setServerManager(new ServerManagerImpl(ScrowAPI.getNats()));
@ -59,8 +40,10 @@ public class ScrowAPISurface {
}
public static void destroyScrowAPI() {
if (mongoClient != null) {
mongoClient.close();
try {
ScrowAPI.getDbConFactory().close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View file

@ -1,4 +1,4 @@
package de.kentoj.scrow.corevelocity;
package de.kentoj.scrow.corevelocity.server;
import com.velocitypowered.api.proxy.ProxyServer;
import de.kentoj.scrowlib.messaging.NatsRepository;
@ -22,10 +22,8 @@ public class SendPlayerWatchdog {
public void listen() {
natsRepo.subscribe("proxy.send-player")
.flatMap(msg ->
handleSendPlayer(SafeResult.unwrap(msg))
.flatMap(result -> natsRepo.publishSafeResult(msg.getReplyTo(), SafeResult.wrap(result)))
.onErrorResume(err -> natsRepo.publishSafeResult(msg.getReplyTo(), SafeResult.wrap(err)))
.flatMap(ctx ->
SafeResult.mono(handleSendPlayer(ctx.getDocument()))
)
.subscribe();
}

View file

@ -1,13 +1,14 @@
package de.kentoj.scrow.corevelocity;
package de.kentoj.scrow.corevelocity.server;
import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.proxy.server.ServerInfo;
import de.kentoj.scrowlib.messaging.DocumentRepository;
import de.kentoj.scrowlib.messaging.NatsRepository;
import de.kentoj.scrowlib.messaging.SubscriptionContext;
import de.kentoj.scrowlib.messaging.respose.SafeResult;
import de.kentoj.scrowlib.servermanager.ServerManager;
import io.nats.client.Connection;
import lombok.extern.java.Log;
import org.bson.Document;
import org.jetbrains.annotations.NotNull;
import reactor.core.publisher.Mono;
@ -28,28 +29,26 @@ public class ServerRegisterWatchdog {
public void listen() {
natsRepo.subscribe("crown.set-state")
.map(SafeResult::unwrap)
.concatMap(doc -> {
var state = doc.getString("state");
var handle = doc.getString("handle");
return handleStateChange(state, handle);
.flatMap(ctx -> {
var state = ctx.getDocument().getString("state");
var handle = ctx.getDocument().getString("handle");
return handleStateChange(ctx, state, handle)
.then(Mono.fromRunnable(() -> {
natsRepo.publishSafeResult(ctx.getMsg().getReplyTo(), SafeResult.wrap(new Document()));
}));
})
.subscribe(null, e -> log.throwing(getClass().getName(), "listen", e));
}
private @NotNull Mono<@NotNull Void> handleStateChange(String state, String handle) {
private @NotNull Mono<@NotNull Void> handleStateChange(SubscriptionContext ctx, String state, String handle) {
return switch (state) {
case "UP" -> serverManager.getInfo(handle)
.doOnNext(instance -> {
log.info("registering " + handle);
server.registerServer(new ServerInfo(handle, new InetSocketAddress(instance.getPort())));
})
.doOnNext(instance ->
server.registerServer(new ServerInfo(handle, new InetSocketAddress(instance.getPort()))))
.then();
case "DOWN" -> serverManager.getInfo(handle)
.doOnNext(instance -> {
log.info("unregistering " + handle);
server.unregisterServer(new ServerInfo(handle, new InetSocketAddress(instance.getPort())));
})
.doOnNext(instance ->
server.unregisterServer(new ServerInfo(handle, new InetSocketAddress(instance.getPort()))))
.then();
default -> Mono.empty();
};