diff --git a/README.md b/README.md index 67b927f..58e293b 100644 --- a/README.md +++ b/README.md @@ -8,20 +8,23 @@ docker run -d --network scrow -e ME_CONFIG_MONGODB_SERVER=mongo -e ME_CONFIG_MON docker run -d --network scrow -p 4222:4222 --name nats nats ``` -acce**ss the mongo-db web interface at http://localhost:8081; username `a`, password `1234`** +access the mongo-db web interface at http://localhost:8081; username `a`, password `1234`** -modules -------- +## ENV -* APIs - ---- +- HOST_NATS e.g `nats://127.17.0.1:4222` +- HOST_MONGO e.g `mongodb://localhost:27017/scrow` + +## modules + +### APIs * core-api contains api for all java development * core-bukkit-api contains api for bukkit development * depends on core-api -* implementations - --------------- - the `-impl` suffix indicates that this module implements the API with the same prefix. - So `core-impl` implements `core-api`. - * core-bukkit-impl is a spigot plugin. It shades core-impl. \ No newline at end of file +### implementations + +the `-impl` suffix indicates that this module implements the API with the same prefix. +So `core-impl` implements `core-api`. +* core-bukkit-impl is a spigot plugin. It shades core-impl. \ No newline at end of file diff --git a/core-bukkit-api/build.gradle.kts b/core-bukkit-api/build.gradle.kts index 56d3d67..25c7882 100644 --- a/core-bukkit-api/build.gradle.kts +++ b/core-bukkit-api/build.gradle.kts @@ -39,9 +39,9 @@ dependencies { implementation("io.nats:jnats:2.25.2") api("io.nats:jnats:2.25.2") - api("de.kentoj.scrow:kencommandapi-core:0.2") - implementation("de.kentoj.scrow:kencommandapi-bukkit:0.2") - api("de.kentoj.scrow:kencommandapi-bukkit:0.2") + api("de.kentoj.scrow:kencommandapi-core:0.4") + implementation("de.kentoj.scrow:kencommandapi-bukkit:0.4") + api("de.kentoj.scrow:kencommandapi-bukkit:0.4") } publishing { diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/ScrowAPI.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/ScrowAPI.java index 53d6522..ea1d494 100644 --- a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/ScrowAPI.java +++ b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/ScrowAPI.java @@ -4,7 +4,6 @@ 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.scrow.bukkit.message.NatsDocumentRepository; import io.nats.client.Connection; import lombok.AccessLevel; import lombok.Getter; @@ -31,7 +30,7 @@ public class ScrowAPI { @Getter private static Connection nats; @Getter - private static NatsDocumentRepository natsRepository; + private static ServerManager serverManager; @ApiStatus.Internal public static void setDatabase(@Nullable MongoDatabase database) { @@ -69,8 +68,8 @@ public class ScrowAPI { } @ApiStatus.Internal - public static void setNatsRepository(NatsDocumentRepository natsRepository) { - ScrowAPI.natsRepository = natsRepository; + public static void setServerManager(ServerManager serverManager) { + ScrowAPI.serverManager = serverManager; } } diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/ServerManager.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/ServerManager.java new file mode 100644 index 0000000..08eedb1 --- /dev/null +++ b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/ServerManager.java @@ -0,0 +1,25 @@ +package de.kentoj.scrow.bukkit; + +import org.jetbrains.annotations.NotNull; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +public interface ServerManager { + + /** + * @return Mono with handle of deployed server + */ + Mono<@NotNull String> deployServer(String template); + + /** + * @return Flux with handles of running servers + */ + Flux<@NotNull String> getRunningServers(); + + /** + * Attempts a clean shutdown, if that doesn't succeed, kills the server. + */ + Mono<@NotNull Void> destroyServer(String handle); + + Mono<@NotNull Void> updateState(String handle, String state); +} diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/CoreImplPlugin.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/CoreImplPlugin.java index 234ae00..d28f67e 100644 --- a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/CoreImplPlugin.java +++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/CoreImplPlugin.java @@ -1,10 +1,8 @@ package de.kentoj.scrow.bukkit; +import de.kentoj.scrow.bukkit.crown.command.CrownCommand; import de.kentoj.scrow.bukkit.economy.CoinsCommand; import de.kentoj.scrow.bukkit.friends.command.FriendCommand; -import io.nats.client.Message; -import io.nats.client.Nats; -import org.bson.Document; import org.bukkit.plugin.java.JavaPlugin; import reactor.core.publisher.Mono; @@ -21,33 +19,14 @@ public class CoreImplPlugin extends JavaPlugin { { ScrowAPI.getCommandManager().register(new FriendCommand().getRootNode()); ScrowAPI.getCommandManager().register(new CoinsCommand().getRootNode()); + ScrowAPI.getCommandManager().register(new CrownCommand().getRootNode()); } - { - var playerId = UUID.randomUUID(); - var economyService = ScrowAPI.getEconomyService(); - Mono.when( - economyService.setCoins(playerId, 120), - economyService.depositCoins(playerId, 100) - ) - .then(economyService.tryWithdrawCoins(playerId, 300)) - .doOnNext(a -> System.out.println("withdraw 1 success " + a)) - .then(economyService.tryWithdrawCoins(playerId, 50)) - .doOnNext(a -> System.out.println("withdraw 2 success " + a)) - .then(economyService.getCoins(playerId)) - .doOnNext(a -> System.out.println("coins: " + a)) - .block(); - } + registerServer(); } private void registerServer() { - ScrowAPI.getNatsRepository().publish("crown.status", new Document() - .append("state", "up")); - ScrowAPI.getNatsRepository().subscribe("crown.status", doc -> { - doc. - }); - ScrowAPI.getNats().reqpublish("crown.status", new Document() - .append("state", "up").toJson()); + ScrowAPI.getServerManager().updateState(System.getenv("SERVER_HANDLE"), "UP"); } @Override diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/ScrowAPISurface.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/ScrowAPISurface.java index 6049268..e8bcd1b 100644 --- a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/ScrowAPISurface.java +++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/ScrowAPISurface.java @@ -5,6 +5,7 @@ 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.crown.CrownServerManager; import de.kentoj.scrow.bukkit.economy.InMemoryEconomyService; import de.kentoj.scrow.bukkit.economy.MongoEconomyService; import de.kentoj.scrow.bukkit.friends.friendship.InMemoryFriendshipService; @@ -12,6 +13,7 @@ import de.kentoj.scrow.bukkit.friends.friendship.MongoFriendshipService; import de.kentoj.scrow.bukkit.friends.request.InMemoryFriendRequestService; import de.kentoj.scrow.bukkit.friends.request.MongoFriendRequestService; import io.nats.client.Nats; +import io.nats.client.Options; import lombok.AccessLevel; import lombok.NoArgsConstructor; import org.bson.UuidRepresentation; @@ -35,7 +37,12 @@ public class ScrowAPISurface { })); try { - ScrowAPI.setMessageBroker(Nats.connect()); + String natsHost = System.getenv("HOST_NATS"); + var options = Options.builder() + .server(natsHost) + .pedantic() + .build(); + ScrowAPI.setNats(Nats.connect(options)); } catch (IOException | InterruptedException e) { throw new RuntimeException(e); } @@ -46,18 +53,21 @@ public class ScrowAPISurface { MongoClientSettings.getDefaultCodecRegistry(), CodecRegistries.fromProviders(pojoCodecProvider) ); + String mongoHost = System.getenv("HOST_MONGO"); var settings = MongoClientSettings.builder() .codecRegistry(codecRegistry) .uuidRepresentation(UuidRepresentation.STANDARD) - .applyConnectionString(new ConnectionString("mongodb://localhost:27017/scrow")) + .applyConnectionString(new ConnectionString(mongoHost)) .build(); mongoClient = MongoClients.create(settings); ScrowAPI.setDatabase(mongoClient.getDatabase("scrow")); } + ScrowAPI.setServerManager(new CrownServerManager(ScrowAPI.getNats())); + ScrowAPI.setEconomyService(ScrowAPI.getDatabase() != null ? - new MongoEconomyService(ScrowAPI.getDatabase()) : new InMemoryEconomyService()); + new MongoEconomyService(ScrowAPI.getDatabase()) : new InMemoryEconomyService()); ScrowAPI.setFriendRequestService(ScrowAPI.getDatabase() != null ? new MongoFriendRequestService(ScrowAPI.getDatabase()) : new InMemoryFriendRequestService()); diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/CrownServerManager.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/CrownServerManager.java new file mode 100644 index 0000000..ee2814a --- /dev/null +++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/CrownServerManager.java @@ -0,0 +1,47 @@ +package de.kentoj.scrow.bukkit.crown; + +import com.google.common.base.Preconditions; +import de.kentoj.scrow.bukkit.ScrowAPI; +import de.kentoj.scrow.bukkit.ServerManager; +import io.nats.client.Connection; +import lombok.RequiredArgsConstructor; +import org.jetbrains.annotations.NotNull; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.Arrays; + +@RequiredArgsConstructor +public class CrownServerManager implements ServerManager { + + private final Connection nats; + + @Override + public Mono<@NotNull String> deployServer(String template) { + return Mono.fromFuture(nats.request("crown.deploy-server", template.getBytes())) + .map(msg -> new String(msg.getData())); + } + + @Override + public Flux<@NotNull String> getRunningServers() { + return Mono.fromFuture(nats.request("crown.deploy-server", new byte[0])) + .flatMapMany(msg -> { + var ids = new String(msg.getData()).split("\u001F"); + return Flux.fromStream(Arrays.stream(ids)); + }); + } + + @Override + public Mono<@NotNull Void> destroyServer(String handle) { + return Mono.fromFuture(nats.request("crown.destroy-server",handle.getBytes())) + .then(); + } + + @Override + public Mono<@NotNull Void> updateState(String handle, String state) { + Preconditions.checkArgument(!state.contains(" "), "state may not contain spaces"); + var payload = (handle + " " + state).getBytes(); + return Mono.fromFuture(nats.request("crown.update-state", payload)) + .then(); + } +} diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/command/CrownCommand.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/command/CrownCommand.java new file mode 100644 index 0000000..82e8db6 --- /dev/null +++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/command/CrownCommand.java @@ -0,0 +1,20 @@ +package de.kentoj.scrow.bukkit.crown.command; + +import de.kentoj.kencommandapi.BukkitCommandContext; +import de.kentoj.kencommandapi.api.structure.node.CommandNode; +import de.kentoj.scrow.bukkit.ScrowAPI; +import lombok.Getter; +import org.bukkit.command.CommandSender; + +public class CrownCommand { + + @Getter + private final CommandNode rootNode; + + public CrownCommand() { + this.rootNode = ScrowAPI.getCommandManager().createNode("crown", "server-manager"); + this.rootNode.addLiteral(new CrownListServersLiteral().getNode()); + this.rootNode.addLiteral(new CrownDeployServerLiteral().getNode()); + this.rootNode.addLiteral(new CrownDestroyServerLiteral().getNode()); + } +} diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/command/CrownDeployServerLiteral.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/command/CrownDeployServerLiteral.java new file mode 100644 index 0000000..e47054a --- /dev/null +++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/command/CrownDeployServerLiteral.java @@ -0,0 +1,35 @@ +package de.kentoj.scrow.bukkit.crown.command; + +import de.kentoj.kencommandapi.BukkitCommandContext; +import de.kentoj.kencommandapi.api.processing.CommandExecutor; +import de.kentoj.kencommandapi.api.structure.argument.CommandArgument; +import de.kentoj.kencommandapi.api.structure.argument.types.StringArgumentType; +import de.kentoj.kencommandapi.api.structure.node.CommandNode; +import de.kentoj.scrow.bukkit.ScrowAPI; +import lombok.Getter; +import org.bukkit.command.CommandSender; + +public class CrownDeployServerLiteral implements CommandExecutor { + + @Getter + private final CommandNode node; + private final CommandArgument templateArg; + + public CrownDeployServerLiteral() { + this.node = ScrowAPI.getCommandManager().createNode("deploy-server"); + this.node.setExecutor(this); + { + this.templateArg = ScrowAPI.getCommandManager().createArgument("template", new StringArgumentType<>()); + this.node.addArgument(templateArg); + } + } + + @Override + public void execute(BukkitCommandContext ctx) { + var template = ctx.getArg(templateArg); + ScrowAPI.getServerManager().deployServer(template) + .subscribe(handle -> { + ctx.getSender().sendMessage("Deployed instance of " + template + " with handle " + handle); + }); + } +} diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/command/CrownDestroyServerLiteral.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/command/CrownDestroyServerLiteral.java new file mode 100644 index 0000000..053e5b5 --- /dev/null +++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/command/CrownDestroyServerLiteral.java @@ -0,0 +1,41 @@ +package de.kentoj.scrow.bukkit.crown.command; + +import de.kentoj.kencommandapi.BukkitCommandContext; +import de.kentoj.kencommandapi.api.processing.CommandExecutor; +import de.kentoj.kencommandapi.api.structure.argument.CommandArgument; +import de.kentoj.kencommandapi.api.structure.argument.types.StringArgumentType; +import de.kentoj.kencommandapi.api.structure.node.CommandNode; +import de.kentoj.scrow.bukkit.ScrowAPI; +import lombok.Getter; +import org.bukkit.command.CommandSender; + +import java.util.stream.Collectors; + +public class CrownDestroyServerLiteral implements CommandExecutor { + + @Getter + private final CommandNode node; + private final CommandArgument handleArg; + + public CrownDestroyServerLiteral() { + this.node = ScrowAPI.getCommandManager().createNode("destroy-server"); + this.node.setExecutor(this); + { + this.handleArg = ScrowAPI.getCommandManager().createArgument("template", new StringArgumentType<>()); + this.handleArg.setSuggestionProvider(ctx -> { + //noinspection CodeBlock2Expr + return ScrowAPI.getServerManager().getRunningServers().collect(Collectors.toSet()).toFuture(); + }); + this.node.addArgument(handleArg); + } + } + + @Override + public void execute(BukkitCommandContext ctx) { + var handle = ctx.getArg(handleArg); + ScrowAPI.getServerManager().destroyServer(handle) + .subscribe(__ -> { + ctx.getSender().sendMessage("Destroyed server with handle " + handle); + }); + } +} diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/command/CrownListServersLiteral.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/command/CrownListServersLiteral.java new file mode 100644 index 0000000..cb12096 --- /dev/null +++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/command/CrownListServersLiteral.java @@ -0,0 +1,31 @@ +package de.kentoj.scrow.bukkit.crown.command; + +import de.kentoj.kencommandapi.BukkitCommandContext; +import de.kentoj.kencommandapi.api.processing.CommandExecutor; +import de.kentoj.kencommandapi.api.structure.node.CommandNode; +import de.kentoj.scrow.bukkit.ScrowAPI; +import lombok.Getter; +import org.bukkit.command.CommandSender; + +public class CrownListServersLiteral implements CommandExecutor { + + @Getter + private final CommandNode node; + + public CrownListServersLiteral() { + this.node = ScrowAPI.getCommandManager().createNode("list-servers"); + this.node.setExecutor(this); + } + + @Override + public void execute(BukkitCommandContext ctx) { + ScrowAPI.getServerManager().getRunningServers() + .collectList() + .subscribe(uids -> { + var msg = new StringBuilder().append('\n'); + uids.forEach(uid -> msg.append(" > ").append(uid)); + msg.append('\n'); + ctx.getPlayerSender().sendMessage(msg.toString()); + }); + } +} diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/economy/CoinsCommand.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/economy/CoinsCommand.java index d0f477c..b04f0f3 100644 --- a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/economy/CoinsCommand.java +++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/economy/CoinsCommand.java @@ -23,7 +23,7 @@ public class CoinsCommand { private final CommandArgument amountArg; public CoinsCommand() { - this.rootNode = ScrowAPI.getCommandManager().createNode("coins"); + this.rootNode = ScrowAPI.getCommandManager().createNode("coins", "eco"); this.playerArg = ScrowAPI.getCommandManager().createArgument("player", OfflinePlayerArgumentType.getInstance()); this.amountArg = ScrowAPI.getCommandManager().createArgument("amount", new IntegerArgumentType<>());