From 1153c00ed4d528c1fbc325f238152271e36abfaf Mon Sep 17 00:00:00 2001 From: Julian Siebert Date: Sun, 3 Aug 2025 09:11:17 +0000 Subject: [PATCH 1/4] feat: Reimplemented octopus sdk --- .devcontainer/devcontainer.json | 2 +- README.md | 2 +- api/build.gradle.kts | 2 +- .../studio/o7/octopus/plugin/api/Octopus.java | 49 +++++++++--- .../plugin/api/client/OctopusClient.java | 12 +-- .../plugin/api/events/OctopusActionEvent.java | 13 ++- ...nt.java => OctopusEntryMutationEvent.java} | 17 ++-- .../OctopusPlayerNotificationEvent.java | 12 ++- .../studio/o7/octopus/plugin/OctopusImpl.java | 70 +++++++++++----- .../o7/octopus/plugin/OctopusPlugin.java | 1 - .../octopus/plugin/OctopusSubscriptions.java | 79 +++++++++++++++++++ .../plugin/client/OctopusClientImpl.java | 59 -------------- .../octopus/plugin/client/ServerClient.java | 25 ------ .../plugin/client/SubscriptionClient.java | 45 ----------- .../plugin/client/SubscriptionObserver.java | 46 ----------- plugin/src/main/resources/plugin.yml | 1 + .../o7/octopus/test/OctopusTestPlugin.java | 10 +-- .../octopus/test/command/MessageCommand.java | 10 +-- .../test/listeners/OctopusListener.java | 10 +-- test-plugin/src/main/resources/plugin.yml | 2 +- 20 files changed, 216 insertions(+), 251 deletions(-) rename api/src/main/java/studio/o7/octopus/plugin/api/events/{OctopusEntryChangeEvent.java => OctopusEntryMutationEvent.java} (57%) create mode 100644 plugin/src/main/java/studio/o7/octopus/plugin/OctopusSubscriptions.java delete mode 100644 plugin/src/main/java/studio/o7/octopus/plugin/client/OctopusClientImpl.java delete mode 100644 plugin/src/main/java/studio/o7/octopus/plugin/client/ServerClient.java delete mode 100644 plugin/src/main/java/studio/o7/octopus/plugin/client/SubscriptionClient.java delete mode 100644 plugin/src/main/java/studio/o7/octopus/plugin/client/SubscriptionObserver.java diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index fc1b7ea..d35845d 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -12,7 +12,7 @@ "features": { "ghcr.io/devcontainers/features/git" : {}, "ghcr.io/devcontainers/features/java:1": { - "version": "21.0.7", + "version": "23", "installGradle": true } }, diff --git a/README.md b/README.md index b98eddc..082a48a 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Please use it for being able to tell "It works on my machine". - Select `From VCS Project` - Select and connect with `Docker` - Select `IntelliJ IDEA` -- Enter `Git Repository`: `https://github.com/o7studios/cheetah` +- Enter `Git Repository`: `https://github.com/o7studios/octopus-plugin` - Select `Detection for devcontainer.json file` `Automatic` - Press `Build Container and Continue` diff --git a/api/build.gradle.kts b/api/build.gradle.kts index 493e2aa..7da1aa2 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -1,5 +1,5 @@ dependencies { - api("studio.o7:octopus-sdk:0.0.2") + api("studio.o7:octopus-sdk:0.1.2") } information { diff --git a/api/src/main/java/studio/o7/octopus/plugin/api/Octopus.java b/api/src/main/java/studio/o7/octopus/plugin/api/Octopus.java index b40d0bd..9426540 100644 --- a/api/src/main/java/studio/o7/octopus/plugin/api/Octopus.java +++ b/api/src/main/java/studio/o7/octopus/plugin/api/Octopus.java @@ -1,9 +1,14 @@ package studio.o7.octopus.plugin.api; -import org.bukkit.plugin.java.JavaPlugin; +import lombok.NonNull; +import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.NullMarked; -import studio.o7.octopus.plugin.api.client.OctopusClient; import studio.o7.octopus.plugin.Unsafe; +import studio.o7.octopus.sdk.gen.api.v1.Entry; +import studio.o7.octopus.sdk.gen.api.v1.Event; + +import java.util.Collection; +import java.util.List; @NullMarked public interface Octopus { @@ -12,13 +17,37 @@ static Octopus get() { return Unsafe.getInstance().get(); } - OctopusClient getClient(); - - JavaPlugin getLibraryPlugin(); - + /** + * Returns true if event has been published successfully. + */ + boolean publishEvent(@NonNull Event event); + + /** + * Get entries by key, optionally filtered. + */ + @NotNull List getEntry(@NonNull String key); + + /** + * Adds list of keys that should be subscribed. + */ + void addSubscriptions(@NonNull Collection subscriptions); + + + /** + * Removes list of keys that shouldn't be subscribed. + */ + void removeSubscriptions(@NonNull Collection subscriptions); + + /** + * Resets list of keys that should be subscribed completely. + * @apiNote Also resets all subscribed/unsubscribed keys + * which have been added by {@link Octopus#addSubscriptions} + * or removed by {@link Octopus#removeSubscriptions} + */ + void setSubscriptions(@NonNull Collection subscriptions); + + /** + * Returns the identifier of this service (e.g. service-name) + */ String getIdentifier(); - - String getHost(); - - int getPort(); } diff --git a/api/src/main/java/studio/o7/octopus/plugin/api/client/OctopusClient.java b/api/src/main/java/studio/o7/octopus/plugin/api/client/OctopusClient.java index 1060bc6..bdc1c19 100644 --- a/api/src/main/java/studio/o7/octopus/plugin/api/client/OctopusClient.java +++ b/api/src/main/java/studio/o7/octopus/plugin/api/client/OctopusClient.java @@ -1,17 +1,17 @@ package studio.o7.octopus.plugin.api.client; -import studio.o7.octopus.sdk.gen.api.v1.EntryResponse; +import lombok.NonNull; +import studio.o7.octopus.sdk.gen.api.v1.Entry; import studio.o7.octopus.sdk.gen.api.v1.Event; +import java.util.Collection; import java.util.List; public interface OctopusClient { - boolean emitEvent(Event event); + boolean publishEvent(@NonNull Event event); - EntryResponse getEntry(String key); + List getEntry(@NonNull String key); - void initializeSubscription(List subscriptions); - - void updateSubscriptions(List subscriptions); + void updateSubscriptions(@NonNull Collection subscriptions); } diff --git a/api/src/main/java/studio/o7/octopus/plugin/api/events/OctopusActionEvent.java b/api/src/main/java/studio/o7/octopus/plugin/api/events/OctopusActionEvent.java index ef8170a..ac458a4 100644 --- a/api/src/main/java/studio/o7/octopus/plugin/api/events/OctopusActionEvent.java +++ b/api/src/main/java/studio/o7/octopus/plugin/api/events/OctopusActionEvent.java @@ -1,19 +1,24 @@ package studio.o7.octopus.plugin.api.events; import lombok.Getter; -import lombok.RequiredArgsConstructor; +import lombok.NonNull; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; import org.jetbrains.annotations.NotNull; import studio.o7.octopus.sdk.gen.api.v1.Action; -@RequiredArgsConstructor @Getter public class OctopusActionEvent extends Event { - private static final HandlerList HANDLER_LIST = new HandlerList(); - private final Action action; + private final String key; + private final Action action; + + public OctopusActionEvent(@NonNull String key, @NonNull Action action) { + super(true); + this.key = key; + this.action = action; + } @Override public @NotNull HandlerList getHandlers() { diff --git a/api/src/main/java/studio/o7/octopus/plugin/api/events/OctopusEntryChangeEvent.java b/api/src/main/java/studio/o7/octopus/plugin/api/events/OctopusEntryMutationEvent.java similarity index 57% rename from api/src/main/java/studio/o7/octopus/plugin/api/events/OctopusEntryChangeEvent.java rename to api/src/main/java/studio/o7/octopus/plugin/api/events/OctopusEntryMutationEvent.java index fcd11b5..6e54026 100644 --- a/api/src/main/java/studio/o7/octopus/plugin/api/events/OctopusEntryChangeEvent.java +++ b/api/src/main/java/studio/o7/octopus/plugin/api/events/OctopusEntryMutationEvent.java @@ -1,19 +1,25 @@ package studio.o7.octopus.plugin.api.events; import lombok.Getter; +import lombok.NonNull; import lombok.RequiredArgsConstructor; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; import org.jetbrains.annotations.NotNull; -import studio.o7.octopus.sdk.gen.api.v1.EntryEdit; +import studio.o7.octopus.sdk.gen.api.v1.EntryMutation; -@RequiredArgsConstructor @Getter -public class OctopusEntryChangeEvent extends Event { - +public final class OctopusEntryMutationEvent extends Event { private static final HandlerList HANDLER_LIST = new HandlerList(); - private final EntryEdit entry; + private final String key; + private final EntryMutation entryMutation; + + public OctopusEntryMutationEvent(@NonNull String key, @NonNull EntryMutation entryMutation) { + super(true); + this.key = key; + this.entryMutation = entryMutation; + } @Override public @NotNull HandlerList getHandlers() { @@ -23,5 +29,4 @@ public class OctopusEntryChangeEvent extends Event { public static HandlerList getHandlerList() { return HANDLER_LIST; } - } diff --git a/api/src/main/java/studio/o7/octopus/plugin/api/events/OctopusPlayerNotificationEvent.java b/api/src/main/java/studio/o7/octopus/plugin/api/events/OctopusPlayerNotificationEvent.java index a0bcc06..01c6834 100644 --- a/api/src/main/java/studio/o7/octopus/plugin/api/events/OctopusPlayerNotificationEvent.java +++ b/api/src/main/java/studio/o7/octopus/plugin/api/events/OctopusPlayerNotificationEvent.java @@ -1,18 +1,24 @@ package studio.o7.octopus.plugin.api.events; import lombok.Getter; -import lombok.RequiredArgsConstructor; +import lombok.NonNull; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; import org.jetbrains.annotations.NotNull; import studio.o7.octopus.sdk.gen.api.v1.PlayerNotification; -@RequiredArgsConstructor @Getter public class OctopusPlayerNotificationEvent extends Event { private static final HandlerList HANDLER_LIST = new HandlerList(); - private final PlayerNotification playerNotification; + private final String key; + private final PlayerNotification playerNotification; + + public OctopusPlayerNotificationEvent(@NonNull String key, @NonNull PlayerNotification playerNotification) { + super(true); + this.key = key; + this.playerNotification = playerNotification; + } @Override public @NotNull HandlerList getHandlers() { diff --git a/plugin/src/main/java/studio/o7/octopus/plugin/OctopusImpl.java b/plugin/src/main/java/studio/o7/octopus/plugin/OctopusImpl.java index eb083bb..37009d3 100644 --- a/plugin/src/main/java/studio/o7/octopus/plugin/OctopusImpl.java +++ b/plugin/src/main/java/studio/o7/octopus/plugin/OctopusImpl.java @@ -1,49 +1,77 @@ package studio.o7.octopus.plugin; +import it.unimi.dsi.fastutil.objects.ObjectArraySet; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.java.JavaPlugin; import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; import studio.o7.octopus.plugin.api.Octopus; -import studio.o7.octopus.plugin.api.client.OctopusClient; -import studio.o7.octopus.plugin.client.OctopusClientImpl; +import studio.o7.octopus.sdk.OctopusSDK; +import studio.o7.octopus.sdk.gen.api.v1.Entry; +import studio.o7.octopus.sdk.gen.api.v1.EntryRequest; +import studio.o7.octopus.sdk.gen.api.v1.Event; +import studio.o7.octopus.sdk.gen.api.v1.OctopusServiceGrpc; + +import java.util.Collection; +import java.util.List; public final class OctopusImpl implements Octopus { + private final Plugin plugin; + + private final OctopusServiceGrpc.OctopusServiceStub stub = OctopusSDK.stub(); + private final OctopusServiceGrpc.OctopusServiceBlockingStub blockingStub = OctopusSDK.blockingStub(); + + private final OctopusSubscriptions subscriptions; - private final OctopusClient client; - private final String identifier; - private final String host; - private final int port; + private String identifier; + + private final Collection subscriptionList = new ObjectArraySet<>(); public OctopusImpl(Plugin plugin) { - this.identifier = "test-minecraft-plugin"; - this.host = "127.0.0.1"; - this.port = 50051; - this.client = new OctopusClientImpl(host, port, plugin, identifier); + this.plugin = plugin; + subscriptions = new OctopusSubscriptions(plugin, stub); } @Override - public @NotNull OctopusClient getClient() { - return client; + public boolean publishEvent(@NonNull Event event) { + var publishEventResponse = blockingStub.publishEvent(event); + plugin.getSLF4JLogger().info("Published event on key {}", event.getKey()); + return publishEventResponse.getSuccess(); } @Override - public @NotNull JavaPlugin getLibraryPlugin() { - return JavaPlugin.getPlugin(OctopusPlugin.class); + public @NotNull List getEntry(@NonNull String key) {; + return blockingStub.getEntry(EntryRequest.newBuilder().setKey(key).build()).getEntriesList(); } @Override - public @NotNull String getIdentifier() { - return identifier; + public void addSubscriptions(@NonNull Collection subscriptions) { + this.subscriptionList.addAll(subscriptions); + this.subscriptions.updateSubscriptions(subscriptionList); } @Override - public @NotNull String getHost() { - return host; + public void removeSubscriptions(@NonNull Collection subscriptions) { + this.subscriptionList.removeAll(subscriptions); + this.subscriptions.updateSubscriptions(subscriptionList); } @Override - public int getPort() { - return port; + public synchronized void setSubscriptions(@NonNull Collection subscriptions) { + this.subscriptionList.clear(); + this.subscriptionList.addAll(subscriptions); + this.subscriptions.updateSubscriptions(subscriptionList); } + @Override + public @NotNull String getIdentifier() { + if (this.identifier != null) return identifier; + identifier = System.getProperty("octopus.identifier"); + if (identifier == null || identifier.isEmpty()) + identifier = System.getenv("OCTOPUS_IDENTIFIER"); + if (identifier == null || identifier.isEmpty()) + identifier = "default"; + return identifier; + } } \ No newline at end of file diff --git a/plugin/src/main/java/studio/o7/octopus/plugin/OctopusPlugin.java b/plugin/src/main/java/studio/o7/octopus/plugin/OctopusPlugin.java index 5f01ecc..4a1a5ab 100644 --- a/plugin/src/main/java/studio/o7/octopus/plugin/OctopusPlugin.java +++ b/plugin/src/main/java/studio/o7/octopus/plugin/OctopusPlugin.java @@ -5,7 +5,6 @@ import org.bukkit.plugin.java.JavaPlugin; import studio.o7.octopus.plugin.api.Octopus; -@SuppressWarnings("UnstableApiUsage") @Getter public final class OctopusPlugin extends JavaPlugin implements PluginInstance { diff --git a/plugin/src/main/java/studio/o7/octopus/plugin/OctopusSubscriptions.java b/plugin/src/main/java/studio/o7/octopus/plugin/OctopusSubscriptions.java new file mode 100644 index 0000000..e20b3d0 --- /dev/null +++ b/plugin/src/main/java/studio/o7/octopus/plugin/OctopusSubscriptions.java @@ -0,0 +1,79 @@ +package studio.o7.octopus.plugin; + +import io.grpc.stub.StreamObserver; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.bukkit.Bukkit; +import org.bukkit.plugin.Plugin; +import org.slf4j.Logger; +import studio.o7.octopus.plugin.api.Octopus; +import studio.o7.octopus.plugin.api.events.OctopusActionEvent; +import studio.o7.octopus.plugin.api.events.OctopusEntryMutationEvent; +import studio.o7.octopus.plugin.api.events.OctopusPlayerNotificationEvent; +import studio.o7.octopus.sdk.gen.api.v1.Event; +import studio.o7.octopus.sdk.gen.api.v1.EventPublication; +import studio.o7.octopus.sdk.gen.api.v1.EventSubscriptionUpdate; +import studio.o7.octopus.sdk.gen.api.v1.OctopusServiceGrpc; + +import java.util.Collection; + +@RequiredArgsConstructor +public final class OctopusSubscriptions { + private final Plugin plugin; + private final OctopusServiceGrpc.OctopusServiceStub stub; + + private StreamObserver subscriptionObserver; + + private synchronized void init() { + var logger = plugin.getSLF4JLogger(); + logger.info("Initializing event subscription observer"); + subscriptionObserver = stub.subscription(new Observer(logger)); + } + + public void updateSubscriptions(@NonNull Collection subscriptions) { + if (subscriptionObserver == null) { + init(); + updateSubscriptions(subscriptions); + return; + } + + var update = EventSubscriptionUpdate.newBuilder() + .setIdentifier(Octopus.get().getIdentifier()) + .addAllKeys(subscriptions) + .build(); + + subscriptionObserver.onNext(update); + plugin.getSLF4JLogger().debug("Updated event subscriptions"); + } + + @RequiredArgsConstructor + static class Observer implements StreamObserver { + private final Logger logger; + + @Override + public void onNext(EventPublication pub) { + var pm = Bukkit.getPluginManager(); + + for (Event event : pub.getEventsList()) { + var key = event.getKey(); + logger.debug("Event publication on key {}", key); + switch (event.getBodyCase()) { + case PLAYER_NOTIFICATION -> pm.callEvent(new OctopusPlayerNotificationEvent(key, event.getPlayerNotification())); + case ENTRY_MUTATION -> pm.callEvent(new OctopusEntryMutationEvent(key, event.getEntryMutation())); + case ACTION -> pm.callEvent(new OctopusActionEvent(key, event.getAction())); + case BODY_NOT_SET -> logger.error("Event subscription on key {} without body", key); + } + } + } + + @Override + public void onError(Throwable throwable) { + logger.error("Event subscription error", throwable); + } + + @Override + public void onCompleted() { + logger.info("Event subscription observer completed"); + } + } +} diff --git a/plugin/src/main/java/studio/o7/octopus/plugin/client/OctopusClientImpl.java b/plugin/src/main/java/studio/o7/octopus/plugin/client/OctopusClientImpl.java deleted file mode 100644 index 0e9bdba..0000000 --- a/plugin/src/main/java/studio/o7/octopus/plugin/client/OctopusClientImpl.java +++ /dev/null @@ -1,59 +0,0 @@ -package studio.o7.octopus.plugin.client; - -import io.grpc.ManagedChannel; -import io.grpc.okhttp.OkHttpChannelBuilder; -import org.bukkit.plugin.Plugin; -import studio.o7.octopus.plugin.api.client.OctopusClient; -import studio.o7.octopus.sdk.gen.api.v1.EntryResponse; -import studio.o7.octopus.sdk.gen.api.v1.Event; - -import java.util.List; - -public class OctopusClientImpl implements OctopusClient { - - private final ServerClient serverClient; - private final SubscriptionClient subscriptionClient; - - public OctopusClientImpl(String host, int port, Plugin plugin, String identifier) { - - System.out.println("DEBUG: Creating channel with host='" + host + "', port=" + port); - System.out.println("DEBUG: host.getClass()=" + host.getClass().getName()); - System.out.println("DEBUG: Host equals localhost: " + "localhost".equals(host)); - - try { - ManagedChannel channel = OkHttpChannelBuilder.forAddress(host, port) - .usePlaintext() - .build(); - - System.out.println("DEBUG: Channel created successfully"); - - this.serverClient = new ServerClient(channel); - this.subscriptionClient = new SubscriptionClient(plugin, channel, identifier); - } catch (Exception e) { - System.err.println("DEBUG: Channel creation failed: " + e.getMessage()); - e.printStackTrace(); - throw e; - } - - } - - @Override - public boolean emitEvent(Event event) { - return serverClient.emitEvent(event); - } - - @Override - public EntryResponse getEntry(String key) { - return serverClient.getEntry(key); - } - - @Override - public void initializeSubscription(List subscriptions) { - subscriptionClient.initializeSubscription(subscriptions); - } - - @Override - public void updateSubscriptions(List subscriptions) { - subscriptionClient.updateSubscriptions(subscriptions); - } -} diff --git a/plugin/src/main/java/studio/o7/octopus/plugin/client/ServerClient.java b/plugin/src/main/java/studio/o7/octopus/plugin/client/ServerClient.java deleted file mode 100644 index fc27e52..0000000 --- a/plugin/src/main/java/studio/o7/octopus/plugin/client/ServerClient.java +++ /dev/null @@ -1,25 +0,0 @@ -package studio.o7.octopus.plugin.client; - -import io.grpc.Channel; -import studio.o7.octopus.sdk.gen.api.v1.*; - -public class ServerClient { - - //TODO: Switch To Async - EventServiceGrpc.EventServiceBlockingStub blockingStub; - - public ServerClient(Channel channel) { - blockingStub = EventServiceGrpc.newBlockingStub(channel); - } - - public boolean emitEvent(Event event) { - EmitEventResponse response = blockingStub.emitEvent(event); - System.out.println("EmitEvent success: " + response.getSuccess()); - return response.getSuccess(); - } - - public EntryResponse getEntry(String key) { - EntryRequest request = EntryRequest.newBuilder().setKey(key).build(); - return blockingStub.getEntry(request); - } -} diff --git a/plugin/src/main/java/studio/o7/octopus/plugin/client/SubscriptionClient.java b/plugin/src/main/java/studio/o7/octopus/plugin/client/SubscriptionClient.java deleted file mode 100644 index 1494c86..0000000 --- a/plugin/src/main/java/studio/o7/octopus/plugin/client/SubscriptionClient.java +++ /dev/null @@ -1,45 +0,0 @@ -package studio.o7.octopus.plugin.client; - -import io.grpc.Channel; -import io.grpc.stub.StreamObserver; -import org.bukkit.plugin.Plugin; -import studio.o7.octopus.sdk.gen.api.v1.SubscriptionRequest; -import studio.o7.octopus.sdk.gen.api.v1.SubscriptionServiceGrpc; - -import java.util.List; - -public class SubscriptionClient { - - private final Plugin plugin; - private final String identifier; - private StreamObserver subscriptionObserver; - - private final SubscriptionServiceGrpc.SubscriptionServiceStub asyncStub; - - public SubscriptionClient(Plugin plugin, Channel channel, String identifier) { - this.plugin = plugin; - this.identifier = identifier; - - this.asyncStub = SubscriptionServiceGrpc.newStub(channel); - } - - public void initializeSubscription(List subscriptions) { - this.subscriptionObserver = asyncStub.subscription(new SubscriptionObserver(plugin)); - var request = SubscriptionRequest.newBuilder() - .setIdentifier(identifier) - .addAllKeys(subscriptions) - .build(); - - subscriptionObserver.onNext(request); - } - - public void updateSubscriptions(List subscriptions) { - if (subscriptionObserver == null) return; - var request = SubscriptionRequest.newBuilder() - .setIdentifier(identifier) - .addAllKeys(subscriptions) - .build(); - - subscriptionObserver.onNext(request); - } -} diff --git a/plugin/src/main/java/studio/o7/octopus/plugin/client/SubscriptionObserver.java b/plugin/src/main/java/studio/o7/octopus/plugin/client/SubscriptionObserver.java deleted file mode 100644 index 1b32aff..0000000 --- a/plugin/src/main/java/studio/o7/octopus/plugin/client/SubscriptionObserver.java +++ /dev/null @@ -1,46 +0,0 @@ -package studio.o7.octopus.plugin.client; - - -import lombok.RequiredArgsConstructor; -import org.bukkit.Bukkit; -import org.bukkit.plugin.Plugin; -import studio.o7.octopus.plugin.api.events.OctopusActionEvent; -import studio.o7.octopus.plugin.api.events.OctopusEntryChangeEvent; -import studio.o7.octopus.plugin.api.events.OctopusPlayerNotificationEvent; -import studio.o7.octopus.sdk.gen.api.v1.Event; -import studio.o7.octopus.sdk.gen.api.v1.SubscriptionResponse; - -@RequiredArgsConstructor -public class SubscriptionObserver implements io.grpc.stub.StreamObserver { - private final Plugin plugin; - - @Override - public void onNext(SubscriptionResponse response) { - for (Event event : response.getEventsList()) { - Bukkit.getScheduler().runTask(plugin, () -> { - switch (event.getBodyCase()) { - case PLAYER_NOTIFICATION -> Bukkit.getPluginManager().callEvent( - new OctopusPlayerNotificationEvent(event.getPlayerNotification(), event.getKey()) - ); - case BODY_NOT_SET -> Bukkit.getLogger().severe("No Body"); - case ACTION -> Bukkit.getPluginManager().callEvent( - new OctopusActionEvent(event.getAction(), event.getKey()) - ); - case ENTRY -> Bukkit.getPluginManager().callEvent( - new OctopusEntryChangeEvent(event.getEntry(), event.getKey()) - ); - } - }); - } - } - - @Override - public void onError(Throwable t) { - Bukkit.getLogger().severe("Subscription error: " + t.getMessage()); - } - - @Override - public void onCompleted() { - Bukkit.getLogger().info("Subscription completed."); - } -} \ No newline at end of file diff --git a/plugin/src/main/resources/plugin.yml b/plugin/src/main/resources/plugin.yml index 1403821..1ce623a 100644 --- a/plugin/src/main/resources/plugin.yml +++ b/plugin/src/main/resources/plugin.yml @@ -3,6 +3,7 @@ version: 0.0.0 description: Octopus paper plugin author: o7studios prefix: octopus +api-version: "1.21.8" main: studio.o7.octopus.plugin.OctopusPlugin load: STARTUP \ No newline at end of file diff --git a/test-plugin/src/main/java/studio/o7/octopus/test/OctopusTestPlugin.java b/test-plugin/src/main/java/studio/o7/octopus/test/OctopusTestPlugin.java index e7e8a45..d8aec7c 100644 --- a/test-plugin/src/main/java/studio/o7/octopus/test/OctopusTestPlugin.java +++ b/test-plugin/src/main/java/studio/o7/octopus/test/OctopusTestPlugin.java @@ -4,7 +4,6 @@ import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; import studio.o7.octopus.plugin.api.Octopus; -import studio.o7.octopus.plugin.api.client.OctopusClient; import studio.o7.octopus.test.command.MessageCommand; import studio.o7.octopus.test.listeners.OctopusListener; @@ -28,19 +27,16 @@ public void onEnable() { // Remember to depend on Octopus Octopus octopus = Octopus.get(); - // Access the client - OctopusClient client = octopus.getClient(); - PluginManager pluginManager = Bukkit.getPluginManager(); // Here is the action event (when a server emits an action) - pluginManager.registerEvents(new OctopusListener(client), this); + pluginManager.registerEvents(new OctopusListener(), this); // The action gets emitted in this command - getCommand("msg").setExecutor(new MessageCommand(client)); + getCommand("msg").setExecutor(new MessageCommand()); // When using subscriptions. You need to initialize it first - client.initializeSubscription(List.of("test")); + octopus.setSubscriptions(List.of("test")); } } diff --git a/test-plugin/src/main/java/studio/o7/octopus/test/command/MessageCommand.java b/test-plugin/src/main/java/studio/o7/octopus/test/command/MessageCommand.java index 5e72588..0ba645e 100644 --- a/test-plugin/src/main/java/studio/o7/octopus/test/command/MessageCommand.java +++ b/test-plugin/src/main/java/studio/o7/octopus/test/command/MessageCommand.java @@ -7,18 +7,12 @@ import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import studio.o7.octopus.plugin.api.client.OctopusClient; +import studio.o7.octopus.plugin.api.Octopus; import studio.o7.octopus.sdk.gen.api.v1.Action; import studio.o7.octopus.sdk.gen.api.v1.Event; public class MessageCommand implements CommandExecutor { - private final OctopusClient client; - - public MessageCommand(OctopusClient client) { - this.client = client; - } - @Override public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] strings) { @@ -41,7 +35,7 @@ public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command var event = Event.newBuilder().setKey(key).setAction(action).build(); player.sendMessage("Sent private message to " + playerName); - client.emitEvent(event); + Octopus.get().publishEvent(event); return false; } diff --git a/test-plugin/src/main/java/studio/o7/octopus/test/listeners/OctopusListener.java b/test-plugin/src/main/java/studio/o7/octopus/test/listeners/OctopusListener.java index f33a3d6..a21820c 100644 --- a/test-plugin/src/main/java/studio/o7/octopus/test/listeners/OctopusListener.java +++ b/test-plugin/src/main/java/studio/o7/octopus/test/listeners/OctopusListener.java @@ -3,7 +3,7 @@ import org.bukkit.Bukkit; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; -import studio.o7.octopus.plugin.api.client.OctopusClient; +import studio.o7.octopus.plugin.api.Octopus; import studio.o7.octopus.plugin.api.events.OctopusActionEvent; import java.util.ArrayList; @@ -11,10 +11,8 @@ public class OctopusListener implements Listener { private final List keys; - private final OctopusClient client; - public OctopusListener(OctopusClient client) { - this.client = client; + public OctopusListener() { this.keys = new ArrayList<>(); } @@ -51,7 +49,7 @@ public void onJoin(org.bukkit.event.player.PlayerJoinEvent event) { System.out.println("Subscribing to " + key); keys.add(key); - client.updateSubscriptions(keys); + Octopus.get().setSubscriptions(keys); } /* @@ -63,6 +61,6 @@ public void onQuit(org.bukkit.event.player.PlayerQuitEvent event) { System.out.println("Unsubscribing from " + key); keys.remove(key); - client.updateSubscriptions(keys); + Octopus.get().setSubscriptions(keys); } } diff --git a/test-plugin/src/main/resources/plugin.yml b/test-plugin/src/main/resources/plugin.yml index 45e9771..0fe0ad5 100644 --- a/test-plugin/src/main/resources/plugin.yml +++ b/test-plugin/src/main/resources/plugin.yml @@ -2,7 +2,7 @@ name: OctopusTest description: "A huge Minecraft library's test plugin." author: "o7studios" prefix: "octopus-test" -api-version: 1.21 +api-version: "1.21.8" version: 0.0.0 main: "studio.o7.octopus.test.OctopusTestPlugin" From 8fc235b875e5573fcb3e0600fe4e908f1a17a3ec Mon Sep 17 00:00:00 2001 From: Julian Siebert Date: Sun, 3 Aug 2025 09:23:54 +0000 Subject: [PATCH 2/4] fix: cleanup --- .../src/main/java/studio/o7/octopus/plugin/OctopusImpl.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugin/src/main/java/studio/o7/octopus/plugin/OctopusImpl.java b/plugin/src/main/java/studio/o7/octopus/plugin/OctopusImpl.java index 37009d3..f90ee70 100644 --- a/plugin/src/main/java/studio/o7/octopus/plugin/OctopusImpl.java +++ b/plugin/src/main/java/studio/o7/octopus/plugin/OctopusImpl.java @@ -14,6 +14,7 @@ import studio.o7.octopus.sdk.gen.api.v1.OctopusServiceGrpc; import java.util.Collection; +import java.util.Collections; import java.util.List; public final class OctopusImpl implements Octopus { @@ -26,7 +27,7 @@ public final class OctopusImpl implements Octopus { private String identifier; - private final Collection subscriptionList = new ObjectArraySet<>(); + private final Collection subscriptionList = Collections.synchronizedSet(new ObjectArraySet<>()); public OctopusImpl(Plugin plugin) { this.plugin = plugin; @@ -41,7 +42,7 @@ public boolean publishEvent(@NonNull Event event) { } @Override - public @NotNull List getEntry(@NonNull String key) {; + public @NotNull List getEntry(@NonNull String key) { return blockingStub.getEntry(EntryRequest.newBuilder().setKey(key).build()).getEntriesList(); } From e12ad018eb380fa7b2d7a28247e4decc0f6af92c Mon Sep 17 00:00:00 2001 From: Julian Siebert Date: Sun, 3 Aug 2025 09:28:35 +0000 Subject: [PATCH 3/4] Added experimental flag to setSubscriptions --- api/src/main/java/studio/o7/octopus/plugin/api/Octopus.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api/src/main/java/studio/o7/octopus/plugin/api/Octopus.java b/api/src/main/java/studio/o7/octopus/plugin/api/Octopus.java index 9426540..905e3e0 100644 --- a/api/src/main/java/studio/o7/octopus/plugin/api/Octopus.java +++ b/api/src/main/java/studio/o7/octopus/plugin/api/Octopus.java @@ -1,6 +1,7 @@ package studio.o7.octopus.plugin.api; import lombok.NonNull; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.NullMarked; import studio.o7.octopus.plugin.Unsafe; @@ -44,6 +45,7 @@ static Octopus get() { * which have been added by {@link Octopus#addSubscriptions} * or removed by {@link Octopus#removeSubscriptions} */ + @ApiStatus.Experimental void setSubscriptions(@NonNull Collection subscriptions); /** From c07146a9b5802154858120f34a0372fe2e2452f6 Mon Sep 17 00:00:00 2001 From: Julian Siebert Date: Sun, 3 Aug 2025 09:33:57 +0000 Subject: [PATCH 4/4] Added try/catches --- .../studio/o7/octopus/plugin/OctopusImpl.java | 22 +++++++++++---- .../octopus/plugin/OctopusSubscriptions.java | 28 +++++++++++-------- 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/plugin/src/main/java/studio/o7/octopus/plugin/OctopusImpl.java b/plugin/src/main/java/studio/o7/octopus/plugin/OctopusImpl.java index f90ee70..4ac88d0 100644 --- a/plugin/src/main/java/studio/o7/octopus/plugin/OctopusImpl.java +++ b/plugin/src/main/java/studio/o7/octopus/plugin/OctopusImpl.java @@ -23,6 +23,7 @@ public final class OctopusImpl implements Octopus { private final OctopusServiceGrpc.OctopusServiceStub stub = OctopusSDK.stub(); private final OctopusServiceGrpc.OctopusServiceBlockingStub blockingStub = OctopusSDK.blockingStub(); + private final Logger logger; private final OctopusSubscriptions subscriptions; private String identifier; @@ -31,19 +32,30 @@ public final class OctopusImpl implements Octopus { public OctopusImpl(Plugin plugin) { this.plugin = plugin; - subscriptions = new OctopusSubscriptions(plugin, stub); + logger = plugin.getSLF4JLogger(); + subscriptions = new OctopusSubscriptions(plugin, logger, stub); } @Override public boolean publishEvent(@NonNull Event event) { - var publishEventResponse = blockingStub.publishEvent(event); - plugin.getSLF4JLogger().info("Published event on key {}", event.getKey()); - return publishEventResponse.getSuccess(); + try { + var publishEventResponse = blockingStub.publishEvent(event); + logger.info("Published event on key {}", event.getKey()); + return publishEventResponse.getSuccess(); + } catch (Exception e) { + logger.error("Failed to publish event on key {}", event.getKey(), e); + return false; + } } @Override public @NotNull List getEntry(@NonNull String key) { - return blockingStub.getEntry(EntryRequest.newBuilder().setKey(key).build()).getEntriesList(); + try { + return blockingStub.getEntry(EntryRequest.newBuilder().setKey(key).build()).getEntriesList(); + } catch (Exception e) { + logger.error("Failed to retrieve entry on key {}", key, e); + return Collections.emptyList(); + } } @Override diff --git a/plugin/src/main/java/studio/o7/octopus/plugin/OctopusSubscriptions.java b/plugin/src/main/java/studio/o7/octopus/plugin/OctopusSubscriptions.java index e20b3d0..ea4be10 100644 --- a/plugin/src/main/java/studio/o7/octopus/plugin/OctopusSubscriptions.java +++ b/plugin/src/main/java/studio/o7/octopus/plugin/OctopusSubscriptions.java @@ -20,30 +20,34 @@ @RequiredArgsConstructor public final class OctopusSubscriptions { private final Plugin plugin; + private final Logger logger; private final OctopusServiceGrpc.OctopusServiceStub stub; private StreamObserver subscriptionObserver; private synchronized void init() { - var logger = plugin.getSLF4JLogger(); logger.info("Initializing event subscription observer"); subscriptionObserver = stub.subscription(new Observer(logger)); } public void updateSubscriptions(@NonNull Collection subscriptions) { - if (subscriptionObserver == null) { - init(); - updateSubscriptions(subscriptions); - return; - } + try { + if (subscriptionObserver == null) { + init(); + updateSubscriptions(subscriptions); + return; + } - var update = EventSubscriptionUpdate.newBuilder() - .setIdentifier(Octopus.get().getIdentifier()) - .addAllKeys(subscriptions) - .build(); + var update = EventSubscriptionUpdate.newBuilder() + .setIdentifier(Octopus.get().getIdentifier()) + .addAllKeys(subscriptions) + .build(); - subscriptionObserver.onNext(update); - plugin.getSLF4JLogger().debug("Updated event subscriptions"); + subscriptionObserver.onNext(update); + logger.debug("Updated event subscriptions"); + } catch (Exception exception) { + logger.error("Failed to update event subscriptions", exception); + } } @RequiredArgsConstructor