From 821dc4ef56cd286fcc3912f38d81f7eb0a81de5f Mon Sep 17 00:00:00 2001 From: Luck Date: Fri, 19 Jan 2018 23:35:41 +0000 Subject: [PATCH] Expose a means to implement the plugin's MessagingService via the API --- .../me/lucko/luckperms/api/LuckPermsApi.java | 12 + .../lucko/luckperms/api/MessagingService.java | 38 ++- .../messenger/IncomingMessageConsumer.java | 78 +++++ .../luckperms/api/messenger/Messenger.java | 58 ++++ .../api/messenger/MessengerProvider.java | 65 +++++ .../api/messenger/message/Message.java | 52 ++++ .../messenger/message/OutgoingMessage.java | 62 ++++ .../messenger/message/type/LogMessage.java | 50 ++++ .../messenger/message/type/UpdateMessage.java | 39 +++ .../message/type/UserUpdateMessage.java | 51 ++++ .../luckperms/bukkit/LPBukkitPlugin.java | 13 +- .../messaging/BukkitMessagingFactory.java | 60 +++- ...agingService.java => BungeeMessenger.java} | 34 ++- ...gingService.java => LilyPadMessenger.java} | 26 +- .../luckperms/bungee/LPBungeePlugin.java | 13 +- .../messaging/BungeeMessagingFactory.java | 60 +++- ...agingService.java => BungeeMessenger.java} | 43 +-- ...Service.java => RedisBungeeMessenger.java} | 24 +- .../common/actionlog/ExtendedLogEntry.java | 36 --- .../common/actionlog/LogDispatcher.java | 4 +- .../common/api/LuckPermsApiProvider.java | 14 +- .../delegates/misc/ApiMessagingService.java | 59 ++++ .../commands/abstraction/SubCommand.java | 8 +- .../commands/impl/misc/InfoCommand.java | 4 +- .../impl/misc/NetworkSyncCommand.java | 4 +- .../messaging/AbstractMessagingService.java | 271 ------------------ ...ice.java => InternalMessagingService.java} | 9 +- .../messaging/LuckPermsMessagingService.java | 209 ++++++++++++++ .../common/messaging/MessagingFactory.java | 34 ++- .../messaging/message/AbstractMessage.java | 48 ++++ .../messaging/message/LogMessageImpl.java | 138 +++++++++ .../messaging/message/UpdateMessageImpl.java | 74 +++++ .../message/UserUpdateMessageImpl.java | 87 ++++++ .../RedisMessenger.java} | 43 +-- .../common/plugin/LuckPermsPlugin.java | 18 +- .../luckperms/sponge/LPSpongePlugin.java | 13 +- ...agingService.java => BungeeMessenger.java} | 24 +- .../messaging/SpongeMessagingFactory.java | 36 ++- 38 files changed, 1469 insertions(+), 442 deletions(-) create mode 100644 api/src/main/java/me/lucko/luckperms/api/messenger/IncomingMessageConsumer.java create mode 100644 api/src/main/java/me/lucko/luckperms/api/messenger/Messenger.java create mode 100644 api/src/main/java/me/lucko/luckperms/api/messenger/MessengerProvider.java create mode 100644 api/src/main/java/me/lucko/luckperms/api/messenger/message/Message.java create mode 100644 api/src/main/java/me/lucko/luckperms/api/messenger/message/OutgoingMessage.java create mode 100644 api/src/main/java/me/lucko/luckperms/api/messenger/message/type/LogMessage.java create mode 100644 api/src/main/java/me/lucko/luckperms/api/messenger/message/type/UpdateMessage.java create mode 100644 api/src/main/java/me/lucko/luckperms/api/messenger/message/type/UserUpdateMessage.java rename bukkit/src/main/java/me/lucko/luckperms/bukkit/messaging/{BungeeMessagingService.java => BungeeMessenger.java} (76%) rename bukkit/src/main/java/me/lucko/luckperms/bukkit/messaging/{LilyPadMessagingService.java => LilyPadMessenger.java} (79%) rename bungee/src/main/java/me/lucko/luckperms/bungee/messaging/{BungeeMessagingService.java => BungeeMessenger.java} (70%) rename bungee/src/main/java/me/lucko/luckperms/bungee/messaging/{RedisBungeeMessagingService.java => RedisBungeeMessenger.java} (74%) create mode 100644 common/src/main/java/me/lucko/luckperms/common/api/delegates/misc/ApiMessagingService.java delete mode 100644 common/src/main/java/me/lucko/luckperms/common/messaging/AbstractMessagingService.java rename common/src/main/java/me/lucko/luckperms/common/messaging/{ExtendedMessagingService.java => InternalMessagingService.java} (92%) create mode 100644 common/src/main/java/me/lucko/luckperms/common/messaging/LuckPermsMessagingService.java create mode 100644 common/src/main/java/me/lucko/luckperms/common/messaging/message/AbstractMessage.java create mode 100644 common/src/main/java/me/lucko/luckperms/common/messaging/message/LogMessageImpl.java create mode 100644 common/src/main/java/me/lucko/luckperms/common/messaging/message/UpdateMessageImpl.java create mode 100644 common/src/main/java/me/lucko/luckperms/common/messaging/message/UserUpdateMessageImpl.java rename common/src/main/java/me/lucko/luckperms/common/messaging/{RedisMessagingService.java => redis/RedisMessenger.java} (76%) rename sponge/src/main/java/me/lucko/luckperms/sponge/messaging/{BungeeMessagingService.java => BungeeMessenger.java} (79%) diff --git a/api/src/main/java/me/lucko/luckperms/api/LuckPermsApi.java b/api/src/main/java/me/lucko/luckperms/api/LuckPermsApi.java index 3d97be97..a8fe6d6d 100644 --- a/api/src/main/java/me/lucko/luckperms/api/LuckPermsApi.java +++ b/api/src/main/java/me/lucko/luckperms/api/LuckPermsApi.java @@ -33,6 +33,7 @@ import me.lucko.luckperms.api.event.EventBus; import me.lucko.luckperms.api.manager.GroupManager; import me.lucko.luckperms.api.manager.TrackManager; import me.lucko.luckperms.api.manager.UserManager; +import me.lucko.luckperms.api.messenger.MessengerProvider; import me.lucko.luckperms.api.metastacking.MetaStackFactory; import me.lucko.luckperms.api.platform.PlatformInfo; @@ -172,6 +173,17 @@ public interface LuckPermsApi { @Nonnull Optional getMessagingService(); + /** + * Registers a {@link MessengerProvider} for use by the platform. + * + *

Note that the mere action of registering a provider doesn't + * necessarily mean that it will be used.

+ * + * @param messengerProvider the messenger provider. + * @since 4.1 + */ + void registerMessengerProvider(@Nonnull MessengerProvider messengerProvider); + /** * Gets the {@link ActionLogger}. * diff --git a/api/src/main/java/me/lucko/luckperms/api/MessagingService.java b/api/src/main/java/me/lucko/luckperms/api/MessagingService.java index 8dda5379..e0b0fa3e 100644 --- a/api/src/main/java/me/lucko/luckperms/api/MessagingService.java +++ b/api/src/main/java/me/lucko/luckperms/api/MessagingService.java @@ -25,6 +25,8 @@ package me.lucko.luckperms.api; +import javax.annotation.Nonnull; + /** * A means to push changes to other servers using the platforms networking * @@ -33,12 +35,42 @@ package me.lucko.luckperms.api; public interface MessagingService { /** - * Uses the messaging service to inform other servers about changes. + * Gets the name of this messaging service + * + * @return the name of this messaging service + * @since 4.1 + */ + String getName(); + + /** + * Uses the messaging service to inform other servers about a general + * change. + * + *

The standard response by other servers will be to execute a overall + * sync of all live data, equivalent to calling + * {@link LuckPermsApi#runUpdateTask()}.

* *

This will push the update asynchronously, and this method will return - * immediately. Calling this method is equivalent to running "/lp networksync", - * except will not sync this server.

+ * immediately. Note that this method will not cause an update to be + * processed on the local server.

*/ void pushUpdate(); + /** + * Uses the messaging service to inform other servers about a change to a + * specific user. + * + *

The standard response by other servers is undefined, however the + * current implementation will reload the corresponding users data if they + * are online.

+ * + *

This will push the update asynchronously, and this method will return + * immediately. Note that this method will not cause an update to be + * processed on the local server.

+ * + * @param user the user to push the update for + * @since 4.1 + */ + void pushUserUpdate(@Nonnull User user); + } diff --git a/api/src/main/java/me/lucko/luckperms/api/messenger/IncomingMessageConsumer.java b/api/src/main/java/me/lucko/luckperms/api/messenger/IncomingMessageConsumer.java new file mode 100644 index 00000000..5de6f04d --- /dev/null +++ b/api/src/main/java/me/lucko/luckperms/api/messenger/IncomingMessageConsumer.java @@ -0,0 +1,78 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.api.messenger; + +import me.lucko.luckperms.api.messenger.message.Message; +import me.lucko.luckperms.api.messenger.message.OutgoingMessage; + +import javax.annotation.Nonnull; + +/** + * Encapsulates the LuckPerms system which accepts incoming {@link Message}s + * from implementations of {@link MessengerProvider}. + * + * @since 4.1 + */ +public interface IncomingMessageConsumer { + + /** + * Consumes a message instance. + * + *

The boolean returned from this method indicates whether or not the + * platform accepted the message. Some implementations which have multiple + * distribution channels may wish to use this result to dispatch the same + * message back to additional receivers.

+ * + *

The implementation will usually return false if a message + * with the same ping id has already been processed.

+ * + * @param message the message + * @return true if the message was accepted by the plugin + */ + boolean consumeIncomingMessage(@Nonnull Message message); + + /** + * Consumes a message in an encoded string format. + * + *

This method will decode strings obtained by calling + * {@link OutgoingMessage#asEncodedString()}. This means that basic + * implementations can successfully implement {@link Messenger} without + * providing their own serialisation.

+ * + *

The boolean returned from this method indicates whether or not the + * platform accepted the message. Some implementations which have multiple + * distribution channels may wish to use this result to dispatch the same + * message back to additional receivers.

+ * + *

The implementation will usually return false if a message + * with the same ping id has already been processed.

+ * + * @param encodedString the encoded string + * @return true if the message was accepted by the plugin + */ + boolean consumeIncomingMessageAsString(@Nonnull String encodedString); + +} diff --git a/api/src/main/java/me/lucko/luckperms/api/messenger/Messenger.java b/api/src/main/java/me/lucko/luckperms/api/messenger/Messenger.java new file mode 100644 index 00000000..3324203a --- /dev/null +++ b/api/src/main/java/me/lucko/luckperms/api/messenger/Messenger.java @@ -0,0 +1,58 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.api.messenger; + +import me.lucko.luckperms.api.messenger.message.Message; +import me.lucko.luckperms.api.messenger.message.OutgoingMessage; + +import javax.annotation.Nonnull; + +/** + * Represents an object which dispatches {@link OutgoingMessage}s. + * + * @since 4.1 + */ +public interface Messenger extends AutoCloseable { + + /** + * Performs the necessary action to dispatch the message using the means + * of the messenger. + * + *

The outgoing message instance is guaranteed to be an instance of one + * of the interfaces extending {@link Message} in the + * 'api.messenger.message.type' package.

+ * + *

This call is always made async.

+ * + * @param outgoingMessage the outgoing message + */ + void sendOutgoingMessage(@Nonnull OutgoingMessage outgoingMessage); + + @Override + default void close() { + + } +} diff --git a/api/src/main/java/me/lucko/luckperms/api/messenger/MessengerProvider.java b/api/src/main/java/me/lucko/luckperms/api/messenger/MessengerProvider.java new file mode 100644 index 00000000..97669c83 --- /dev/null +++ b/api/src/main/java/me/lucko/luckperms/api/messenger/MessengerProvider.java @@ -0,0 +1,65 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.api.messenger; + +import me.lucko.luckperms.api.LuckPermsApi; + +import javax.annotation.Nonnull; + +/** + * Represents a provider for {@link Messenger} instances. + * + *

Users wishing to provide their own implementation for the plugins + * "Messaging Service" should implement and register this interface.

+ * + * @since 4.1 + * @see LuckPermsApi#registerMessengerProvider(MessengerProvider) + */ +public interface MessengerProvider { + + /** + * Gets the name of this provider. + * + * @return the provider name + */ + @Nonnull + String getName(); + + /** + * Creates and returns a new {@link Messenger} instance, which passes + * incoming messages to the provided {@link IncomingMessageConsumer}. + * + *

As the agent should pass incoming messages to the given consumer, + * this method should always return a new object.

+ * + * @param incomingMessageConsumer the consumer the new instance should pass + * incoming messages to + * @return a new messenger agent instance + */ + @Nonnull + Messenger obtain(@Nonnull IncomingMessageConsumer incomingMessageConsumer); + +} diff --git a/api/src/main/java/me/lucko/luckperms/api/messenger/message/Message.java b/api/src/main/java/me/lucko/luckperms/api/messenger/message/Message.java new file mode 100644 index 00000000..55b23b1d --- /dev/null +++ b/api/src/main/java/me/lucko/luckperms/api/messenger/message/Message.java @@ -0,0 +1,52 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.api.messenger.message; + +import me.lucko.luckperms.api.messenger.Messenger; + +import java.util.UUID; + +import javax.annotation.Nonnull; + +/** + * Represents a message sent received via a {@link Messenger}. + * + * @since 4.1 + */ +public interface Message { + + /** + * Gets the unique id associated with this message. + * + *

This ID is used to ensure a single server instance doesn't process + * the same message twice.

+ * + * @return the id of the message + */ + @Nonnull + UUID getId(); + +} diff --git a/api/src/main/java/me/lucko/luckperms/api/messenger/message/OutgoingMessage.java b/api/src/main/java/me/lucko/luckperms/api/messenger/message/OutgoingMessage.java new file mode 100644 index 00000000..86e459b3 --- /dev/null +++ b/api/src/main/java/me/lucko/luckperms/api/messenger/message/OutgoingMessage.java @@ -0,0 +1,62 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.api.messenger.message; + +import me.lucko.luckperms.api.messenger.IncomingMessageConsumer; + +import javax.annotation.Nonnull; + +/** + * Represents an outgoing {@link Message}. + * + *

Outgoing messages are ones which have been generated by this instance. + * (in other words, they are implemented by LuckPerms)

+ * + *

Note that all implementations of this interface are guaranteed to be an + * instance of one of the interfaces extending {@link Message} in the + * 'api.messenger.message.type' package.

+ * + * @since 4.1 + */ +public interface OutgoingMessage extends Message { + + /** + * Gets an encoded string form of this message. + * + *

The format of this string is likely to change between versions and + * should not be depended on.

+ * + *

Implementations which want to use a standard method of serialisation + * can send outgoing messages using the string returned by this method, and + * pass on the message on the "other side" using + * {@link IncomingMessageConsumer#consumeIncomingMessageAsString(String)}.

+ * + * @return an encoded string form of the message + */ + @Nonnull + String asEncodedString(); + +} diff --git a/api/src/main/java/me/lucko/luckperms/api/messenger/message/type/LogMessage.java b/api/src/main/java/me/lucko/luckperms/api/messenger/message/type/LogMessage.java new file mode 100644 index 00000000..8bf93aab --- /dev/null +++ b/api/src/main/java/me/lucko/luckperms/api/messenger/message/type/LogMessage.java @@ -0,0 +1,50 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.api.messenger.message.type; + +import me.lucko.luckperms.api.LogEntry; +import me.lucko.luckperms.api.messenger.message.Message; + +import javax.annotation.Nonnull; + +/** + * Represents an "log" message. + * + *

Used to dispatch live log updates to other servers.

+ * + * @since 4.1 + */ +public interface LogMessage extends Message { + + /** + * Gets the log entry being sent + * + * @return the log entry + */ + @Nonnull + LogEntry getLogEntry(); + +} diff --git a/api/src/main/java/me/lucko/luckperms/api/messenger/message/type/UpdateMessage.java b/api/src/main/java/me/lucko/luckperms/api/messenger/message/type/UpdateMessage.java new file mode 100644 index 00000000..e78ed5ab --- /dev/null +++ b/api/src/main/java/me/lucko/luckperms/api/messenger/message/type/UpdateMessage.java @@ -0,0 +1,39 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.api.messenger.message.type; + +import me.lucko.luckperms.api.messenger.message.Message; + +/** + * Represents an "update" message. + * + *

Used to notify other servers of general changes.

+ * + * @since 4.1 + */ +public interface UpdateMessage extends Message { + +} diff --git a/api/src/main/java/me/lucko/luckperms/api/messenger/message/type/UserUpdateMessage.java b/api/src/main/java/me/lucko/luckperms/api/messenger/message/type/UserUpdateMessage.java new file mode 100644 index 00000000..7d8656d0 --- /dev/null +++ b/api/src/main/java/me/lucko/luckperms/api/messenger/message/type/UserUpdateMessage.java @@ -0,0 +1,51 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.api.messenger.message.type; + +import me.lucko.luckperms.api.messenger.message.Message; + +import java.util.UUID; + +import javax.annotation.Nonnull; + +/** + * Represents an "user update" message. + * + *

Used to notify other servers of a change to a specific user.

+ * + * @since 4.1 + */ +public interface UserUpdateMessage extends Message { + + /** + * Gets the user the message is for. + * + * @return the user + */ + @Nonnull + UUID getUser(); + +} diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java index ca752f08..6abb8b20 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java @@ -69,7 +69,7 @@ import me.lucko.luckperms.common.logging.SenderLogger; import me.lucko.luckperms.common.managers.group.StandardGroupManager; import me.lucko.luckperms.common.managers.track.StandardTrackManager; import me.lucko.luckperms.common.managers.user.StandardUserManager; -import me.lucko.luckperms.common.messaging.ExtendedMessagingService; +import me.lucko.luckperms.common.messaging.InternalMessagingService; import me.lucko.luckperms.common.model.User; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.storage.Storage; @@ -119,7 +119,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin { private StandardTrackManager trackManager; private Storage storage; private FileWatcher fileWatcher = null; - private ExtendedMessagingService messagingService = null; + private InternalMessagingService messagingService = null; private UuidCache uuidCache; private LuckPermsApiProvider apiProvider; private EventFactory eventFactory; @@ -443,10 +443,17 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin { } @Override - public Optional getMessagingService() { + public Optional getMessagingService() { return Optional.ofNullable(this.messagingService); } + @Override + public void setMessagingService(InternalMessagingService messagingService) { + if (this.messagingService == null) { + this.messagingService = messagingService; + } + } + @Override public Optional getFileWatcher() { return Optional.ofNullable(this.fileWatcher); diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/messaging/BukkitMessagingFactory.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/messaging/BukkitMessagingFactory.java index a480a9cb..89c85a05 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/messaging/BukkitMessagingFactory.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/messaging/BukkitMessagingFactory.java @@ -25,31 +25,75 @@ package me.lucko.luckperms.bukkit.messaging; +import me.lucko.luckperms.api.messenger.IncomingMessageConsumer; +import me.lucko.luckperms.api.messenger.Messenger; +import me.lucko.luckperms.api.messenger.MessengerProvider; import me.lucko.luckperms.bukkit.LPBukkitPlugin; -import me.lucko.luckperms.common.messaging.ExtendedMessagingService; +import me.lucko.luckperms.common.messaging.InternalMessagingService; +import me.lucko.luckperms.common.messaging.LuckPermsMessagingService; import me.lucko.luckperms.common.messaging.MessagingFactory; +import javax.annotation.Nonnull; + public class BukkitMessagingFactory extends MessagingFactory { public BukkitMessagingFactory(LPBukkitPlugin plugin) { super(plugin); } @Override - protected ExtendedMessagingService getServiceFor(String messagingType) { + protected InternalMessagingService getServiceFor(String messagingType) { if (messagingType.equals("bungee")) { - BungeeMessagingService bungeeMessaging = new BungeeMessagingService(getPlugin()); - bungeeMessaging.init(); - return bungeeMessaging; + try { + return new LuckPermsMessagingService(getPlugin(), new BungeeMessengerProvider()); + } catch (Exception e) { + e.printStackTrace(); + } } else if (messagingType.equals("lilypad")) { if (getPlugin().getServer().getPluginManager().getPlugin("LilyPad-Connect") == null) { getPlugin().getLog().warn("LilyPad-Connect plugin not present."); } else { - LilyPadMessagingService lilyPadMessaging = new LilyPadMessagingService(getPlugin()); - lilyPadMessaging.init(); - return lilyPadMessaging; + try { + return new LuckPermsMessagingService(getPlugin(), new LilyPadMessengerProvider()); + } catch (Exception e) { + e.printStackTrace(); + } } } return super.getServiceFor(messagingType); } + + private class BungeeMessengerProvider implements MessengerProvider { + + @Nonnull + @Override + public String getName() { + return "Bungee"; + } + + @Nonnull + @Override + public Messenger obtain(@Nonnull IncomingMessageConsumer incomingMessageConsumer) { + BungeeMessenger bungeeMessaging = new BungeeMessenger(getPlugin(), incomingMessageConsumer); + bungeeMessaging.init(); + return bungeeMessaging; + } + } + + private class LilyPadMessengerProvider implements MessengerProvider { + + @Nonnull + @Override + public String getName() { + return "LilyPad"; + } + + @Nonnull + @Override + public Messenger obtain(@Nonnull IncomingMessageConsumer incomingMessageConsumer) { + LilyPadMessenger lilyPadMessaging = new LilyPadMessenger(getPlugin(), incomingMessageConsumer); + lilyPadMessaging.init(); + return lilyPadMessaging; + } + } } diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/messaging/BungeeMessagingService.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/messaging/BungeeMessenger.java similarity index 76% rename from bukkit/src/main/java/me/lucko/luckperms/bukkit/messaging/BungeeMessagingService.java rename to bukkit/src/main/java/me/lucko/luckperms/bukkit/messaging/BungeeMessenger.java index 54a90477..c8279b57 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/messaging/BungeeMessagingService.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/messaging/BungeeMessenger.java @@ -30,9 +30,10 @@ import com.google.common.io.ByteArrayDataInput; import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; +import me.lucko.luckperms.api.messenger.IncomingMessageConsumer; +import me.lucko.luckperms.api.messenger.Messenger; +import me.lucko.luckperms.api.messenger.message.OutgoingMessage; import me.lucko.luckperms.bukkit.LPBukkitPlugin; -import me.lucko.luckperms.common.messaging.AbstractMessagingService; -import me.lucko.luckperms.common.messaging.ExtendedMessagingService; import org.bukkit.entity.Player; import org.bukkit.plugin.messaging.PluginMessageListener; @@ -40,15 +41,20 @@ import org.bukkit.scheduler.BukkitRunnable; import java.util.Collection; -/** - * An implementation of {@link ExtendedMessagingService} using the plugin messaging channels. - */ -public class BungeeMessagingService extends AbstractMessagingService implements PluginMessageListener { - private final LPBukkitPlugin plugin; +import javax.annotation.Nonnull; - public BungeeMessagingService(LPBukkitPlugin plugin) { - super(plugin, "Bungee"); +/** + * An implementation of {@link Messenger} using the plugin messaging channels. + */ +public class BungeeMessenger implements Messenger, PluginMessageListener { + private static final String CHANNEL = "lpuc"; + + private final LPBukkitPlugin plugin; + private final IncomingMessageConsumer consumer; + + public BungeeMessenger(LPBukkitPlugin plugin, IncomingMessageConsumer consumer) { this.plugin = plugin; + this.consumer = consumer; } public void init() { @@ -63,22 +69,22 @@ public class BungeeMessagingService extends AbstractMessagingService implements } @Override - protected void sendMessage(String message) { + public void sendOutgoingMessage(@Nonnull OutgoingMessage outgoingMessage) { new BukkitRunnable() { @Override public void run() { - Collection players = BungeeMessagingService.this.plugin.getServer().getOnlinePlayers(); + Collection players = BungeeMessenger.this.plugin.getServer().getOnlinePlayers(); Player p = Iterables.getFirst(players, null); if (p == null) { return; } ByteArrayDataOutput out = ByteStreams.newDataOutput(); - out.writeUTF(message); + out.writeUTF(outgoingMessage.asEncodedString()); byte[] data = out.toByteArray(); - p.sendPluginMessage(BungeeMessagingService.this.plugin, CHANNEL, data); + p.sendPluginMessage(BungeeMessenger.this.plugin, CHANNEL, data); cancel(); } }.runTaskTimer(this.plugin, 1L, 100L); @@ -93,6 +99,6 @@ public class BungeeMessagingService extends AbstractMessagingService implements ByteArrayDataInput in = ByteStreams.newDataInput(bytes); String msg = in.readUTF(); - onMessage(msg, null); + this.consumer.consumeIncomingMessageAsString(msg); } } diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/messaging/LilyPadMessagingService.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/messaging/LilyPadMessenger.java similarity index 79% rename from bukkit/src/main/java/me/lucko/luckperms/bukkit/messaging/LilyPadMessagingService.java rename to bukkit/src/main/java/me/lucko/luckperms/bukkit/messaging/LilyPadMessenger.java index d6702965..3d85dd57 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/messaging/LilyPadMessagingService.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/messaging/LilyPadMessenger.java @@ -25,9 +25,10 @@ package me.lucko.luckperms.bukkit.messaging; +import me.lucko.luckperms.api.messenger.IncomingMessageConsumer; +import me.lucko.luckperms.api.messenger.Messenger; +import me.lucko.luckperms.api.messenger.message.OutgoingMessage; import me.lucko.luckperms.bukkit.LPBukkitPlugin; -import me.lucko.luckperms.common.messaging.AbstractMessagingService; -import me.lucko.luckperms.common.messaging.ExtendedMessagingService; import lilypad.client.connect.api.Connect; import lilypad.client.connect.api.event.EventListener; @@ -38,16 +39,22 @@ import lilypad.client.connect.api.request.impl.MessageRequest; import java.io.UnsupportedEncodingException; import java.util.Collections; +import javax.annotation.Nonnull; + /** - * An implementation of {@link ExtendedMessagingService} using LilyPad. + * An implementation of {@link Messenger} using LilyPad. */ -public class LilyPadMessagingService extends AbstractMessagingService { +public class LilyPadMessenger implements Messenger { + private static final String CHANNEL = "lpuc"; + private final LPBukkitPlugin plugin; + private final IncomingMessageConsumer consumer; + private Connect connect; - public LilyPadMessagingService(LPBukkitPlugin plugin) { - super(plugin, "LilyPad"); + public LilyPadMessenger(LPBukkitPlugin plugin, IncomingMessageConsumer consumer) { this.plugin = plugin; + this.consumer = consumer; } public void init() { @@ -61,11 +68,11 @@ public class LilyPadMessagingService extends AbstractMessagingService { } @Override - protected void sendMessage(String message) { + public void sendOutgoingMessage(@Nonnull OutgoingMessage outgoingMessage) { MessageRequest request; try { - request = new MessageRequest(Collections.emptyList(), CHANNEL, message); + request = new MessageRequest(Collections.emptyList(), CHANNEL, outgoingMessage.asEncodedString()); } catch (UnsupportedEncodingException e) { e.printStackTrace(); return; @@ -89,8 +96,7 @@ public class LilyPadMessagingService extends AbstractMessagingService { } String message = event.getMessageAsString(); - - onMessage(message, null); + this.consumer.consumeIncomingMessageAsString(message); } catch (Exception e) { e.printStackTrace(); } diff --git a/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java b/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java index 118ac3eb..e54035f7 100644 --- a/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java +++ b/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java @@ -62,7 +62,7 @@ import me.lucko.luckperms.common.logging.SenderLogger; import me.lucko.luckperms.common.managers.group.StandardGroupManager; import me.lucko.luckperms.common.managers.track.StandardTrackManager; import me.lucko.luckperms.common.managers.user.StandardUserManager; -import me.lucko.luckperms.common.messaging.ExtendedMessagingService; +import me.lucko.luckperms.common.messaging.InternalMessagingService; import me.lucko.luckperms.common.model.User; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.plugin.SchedulerAdapter; @@ -105,7 +105,7 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin { private StandardTrackManager trackManager; private Storage storage; private FileWatcher fileWatcher = null; - private ExtendedMessagingService messagingService = null; + private InternalMessagingService messagingService = null; private UuidCache uuidCache; private LuckPermsApiProvider apiProvider; private EventFactory eventFactory; @@ -274,10 +274,17 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin { } @Override - public Optional getMessagingService() { + public Optional getMessagingService() { return Optional.ofNullable(this.messagingService); } + @Override + public void setMessagingService(InternalMessagingService messagingService) { + if (this.messagingService == null) { + this.messagingService = messagingService; + } + } + @Override public Optional getFileWatcher() { return Optional.ofNullable(this.fileWatcher); diff --git a/bungee/src/main/java/me/lucko/luckperms/bungee/messaging/BungeeMessagingFactory.java b/bungee/src/main/java/me/lucko/luckperms/bungee/messaging/BungeeMessagingFactory.java index 4bb355c8..fcf01fd1 100644 --- a/bungee/src/main/java/me/lucko/luckperms/bungee/messaging/BungeeMessagingFactory.java +++ b/bungee/src/main/java/me/lucko/luckperms/bungee/messaging/BungeeMessagingFactory.java @@ -25,31 +25,75 @@ package me.lucko.luckperms.bungee.messaging; +import me.lucko.luckperms.api.messenger.IncomingMessageConsumer; +import me.lucko.luckperms.api.messenger.Messenger; +import me.lucko.luckperms.api.messenger.MessengerProvider; import me.lucko.luckperms.bungee.LPBungeePlugin; -import me.lucko.luckperms.common.messaging.ExtendedMessagingService; +import me.lucko.luckperms.common.messaging.InternalMessagingService; +import me.lucko.luckperms.common.messaging.LuckPermsMessagingService; import me.lucko.luckperms.common.messaging.MessagingFactory; +import javax.annotation.Nonnull; + public class BungeeMessagingFactory extends MessagingFactory { public BungeeMessagingFactory(LPBungeePlugin plugin) { super(plugin); } @Override - protected ExtendedMessagingService getServiceFor(String messagingType) { + protected InternalMessagingService getServiceFor(String messagingType) { if (messagingType.equals("bungee")) { - BungeeMessagingService bungeeMessaging = new BungeeMessagingService(getPlugin()); - bungeeMessaging.init(); - return bungeeMessaging; + try { + return new LuckPermsMessagingService(getPlugin(), new BungeeMessengerProvider()); + } catch (Exception e) { + e.printStackTrace(); + } } else if (messagingType.equals("redisbungee")) { if (getPlugin().getProxy().getPluginManager().getPlugin("RedisBungee") == null) { getPlugin().getLog().warn("RedisBungee plugin not present."); } else { - RedisBungeeMessagingService redisBungeeMessaging = new RedisBungeeMessagingService(getPlugin()); - redisBungeeMessaging.init(); - return redisBungeeMessaging; + try { + return new LuckPermsMessagingService(getPlugin(), new RedisBungeeMessengerProvider()); + } catch (Exception e) { + e.printStackTrace(); + } } } return super.getServiceFor(messagingType); } + + private class BungeeMessengerProvider implements MessengerProvider { + + @Nonnull + @Override + public String getName() { + return "Bungee"; + } + + @Nonnull + @Override + public Messenger obtain(@Nonnull IncomingMessageConsumer incomingMessageConsumer) { + BungeeMessenger bungeeMessaging = new BungeeMessenger(getPlugin(), incomingMessageConsumer); + bungeeMessaging.init(); + return bungeeMessaging; + } + } + + private class RedisBungeeMessengerProvider implements MessengerProvider { + + @Nonnull + @Override + public String getName() { + return "RedisBungee"; + } + + @Nonnull + @Override + public Messenger obtain(@Nonnull IncomingMessageConsumer incomingMessageConsumer) { + RedisBungeeMessenger redisBungeeMessaging = new RedisBungeeMessenger(getPlugin(), incomingMessageConsumer); + redisBungeeMessaging.init(); + return redisBungeeMessaging; + } + } } diff --git a/bungee/src/main/java/me/lucko/luckperms/bungee/messaging/BungeeMessagingService.java b/bungee/src/main/java/me/lucko/luckperms/bungee/messaging/BungeeMessenger.java similarity index 70% rename from bungee/src/main/java/me/lucko/luckperms/bungee/messaging/BungeeMessagingService.java rename to bungee/src/main/java/me/lucko/luckperms/bungee/messaging/BungeeMessenger.java index 3a79069b..36852e31 100644 --- a/bungee/src/main/java/me/lucko/luckperms/bungee/messaging/BungeeMessagingService.java +++ b/bungee/src/main/java/me/lucko/luckperms/bungee/messaging/BungeeMessenger.java @@ -29,9 +29,10 @@ import com.google.common.io.ByteArrayDataInput; import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; +import me.lucko.luckperms.api.messenger.IncomingMessageConsumer; +import me.lucko.luckperms.api.messenger.Messenger; +import me.lucko.luckperms.api.messenger.message.OutgoingMessage; import me.lucko.luckperms.bungee.LPBungeePlugin; -import me.lucko.luckperms.common.messaging.AbstractMessagingService; -import me.lucko.luckperms.common.messaging.ExtendedMessagingService; import net.md_5.bungee.api.config.ServerInfo; import net.md_5.bungee.api.connection.ProxiedPlayer; @@ -39,15 +40,20 @@ import net.md_5.bungee.api.event.PluginMessageEvent; import net.md_5.bungee.api.plugin.Listener; import net.md_5.bungee.event.EventHandler; -/** - * An implementation of {@link ExtendedMessagingService} using the plugin messaging channels. - */ -public class BungeeMessagingService extends AbstractMessagingService implements Listener { - private final LPBungeePlugin plugin; +import javax.annotation.Nonnull; - public BungeeMessagingService(LPBungeePlugin plugin) { - super(plugin, "Bungee"); +/** + * An implementation of {@link Messenger} using the plugin messaging channels. + */ +public class BungeeMessenger implements Messenger, Listener { + private static final String CHANNEL = "lpuc"; + + private final LPBungeePlugin plugin; + private final IncomingMessageConsumer consumer; + + public BungeeMessenger(LPBungeePlugin plugin, IncomingMessageConsumer consumer) { this.plugin = plugin; + this.consumer = consumer; } public void init() { @@ -61,10 +67,9 @@ public class BungeeMessagingService extends AbstractMessagingService implements } @Override - protected void sendMessage(String message) { - + public void sendOutgoingMessage(@Nonnull OutgoingMessage outgoingMessage) { ByteArrayDataOutput out = ByteStreams.newDataOutput(); - out.writeUTF(message); + out.writeUTF(outgoingMessage.asEncodedString()); byte[] data = out.toByteArray(); @@ -85,12 +90,18 @@ public class BungeeMessagingService extends AbstractMessagingService implements return; } - ByteArrayDataInput in = ByteStreams.newDataInput(e.getData()); + byte[] data = e.getData(); + + ByteArrayDataInput in = ByteStreams.newDataInput(data); String msg = in.readUTF(); - onMessage(msg, u -> { + if (this.consumer.consumeIncomingMessageAsString(msg)) { // Forward to other servers - this.plugin.getScheduler().doAsync(() -> sendMessage(u)); - }); + this.plugin.getScheduler().doAsync(() -> { + for (ServerInfo server : this.plugin.getProxy().getServers().values()) { + server.sendData(CHANNEL, data, true); + } + }); + } } } diff --git a/bungee/src/main/java/me/lucko/luckperms/bungee/messaging/RedisBungeeMessagingService.java b/bungee/src/main/java/me/lucko/luckperms/bungee/messaging/RedisBungeeMessenger.java similarity index 74% rename from bungee/src/main/java/me/lucko/luckperms/bungee/messaging/RedisBungeeMessagingService.java rename to bungee/src/main/java/me/lucko/luckperms/bungee/messaging/RedisBungeeMessenger.java index 30d3a9ae..f8c9b698 100644 --- a/bungee/src/main/java/me/lucko/luckperms/bungee/messaging/RedisBungeeMessagingService.java +++ b/bungee/src/main/java/me/lucko/luckperms/bungee/messaging/RedisBungeeMessenger.java @@ -29,23 +29,29 @@ import com.imaginarycode.minecraft.redisbungee.RedisBungee; import com.imaginarycode.minecraft.redisbungee.RedisBungeeAPI; import com.imaginarycode.minecraft.redisbungee.events.PubSubMessageEvent; +import me.lucko.luckperms.api.messenger.IncomingMessageConsumer; +import me.lucko.luckperms.api.messenger.Messenger; +import me.lucko.luckperms.api.messenger.message.OutgoingMessage; import me.lucko.luckperms.bungee.LPBungeePlugin; -import me.lucko.luckperms.common.messaging.AbstractMessagingService; -import me.lucko.luckperms.common.messaging.ExtendedMessagingService; import net.md_5.bungee.api.plugin.Listener; import net.md_5.bungee.event.EventHandler; +import javax.annotation.Nonnull; + /** - * An implementation of {@link ExtendedMessagingService} using Redis, via RedisBungee's API. + * An implementation of {@link Messenger} using Redis, via RedisBungee's API. */ -public class RedisBungeeMessagingService extends AbstractMessagingService implements Listener { +public class RedisBungeeMessenger implements Messenger, Listener { + private static final String CHANNEL = "lpuc"; + private final LPBungeePlugin plugin; + private final IncomingMessageConsumer consumer; private RedisBungeeAPI redisBungee; - public RedisBungeeMessagingService(LPBungeePlugin plugin) { - super(plugin, "RedisBungee"); + public RedisBungeeMessenger(LPBungeePlugin plugin, IncomingMessageConsumer consumer) { this.plugin = plugin; + this.consumer = consumer; } public void init() { @@ -64,8 +70,8 @@ public class RedisBungeeMessagingService extends AbstractMessagingService implem } @Override - protected void sendMessage(String message) { - this.redisBungee.sendChannelMessage(CHANNEL, message); + public void sendOutgoingMessage(@Nonnull OutgoingMessage outgoingMessage) { + this.redisBungee.sendChannelMessage(CHANNEL, outgoingMessage.asEncodedString()); } @EventHandler @@ -74,6 +80,6 @@ public class RedisBungeeMessagingService extends AbstractMessagingService implem return; } - onMessage(e.getMessage(), null); + this.consumer.consumeIncomingMessageAsString(e.getMessage()); } } diff --git a/common/src/main/java/me/lucko/luckperms/common/actionlog/ExtendedLogEntry.java b/common/src/main/java/me/lucko/luckperms/common/actionlog/ExtendedLogEntry.java index 1e779ce9..8616dd68 100644 --- a/common/src/main/java/me/lucko/luckperms/common/actionlog/ExtendedLogEntry.java +++ b/common/src/main/java/me/lucko/luckperms/common/actionlog/ExtendedLogEntry.java @@ -26,9 +26,6 @@ package me.lucko.luckperms.common.actionlog; import com.google.common.base.Strings; -import com.google.common.collect.Maps; -import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; import me.lucko.luckperms.api.Contexts; import me.lucko.luckperms.api.LogEntry; @@ -380,37 +377,4 @@ public class ExtendedLogEntry implements LogEntry { "action=" + this.action + ")"; } } - - public static JsonObject serializeWithId(String id, LogEntry entry) { - JsonObject data = new JsonObject(); - - data.add("id", new JsonPrimitive(id)); - data.add("actor", new JsonPrimitive(entry.getActor().toString())); - data.add("actorName", new JsonPrimitive(entry.getActorName())); - data.add("type", new JsonPrimitive(entry.getType().name())); - if (entry.getActed().isPresent()) { - data.add("acted", new JsonPrimitive(entry.getActed().get().toString())); - } - data.add("actedName", new JsonPrimitive(entry.getActedName())); - data.add("action", new JsonPrimitive(entry.getAction())); - - return data; - } - - public static Map.Entry deserialize(JsonObject object) { - ExtendedLogEntryBuilder builder = build(); - - String id = object.get("id").getAsString(); - - builder.actor(UUID.fromString(object.get("actor").getAsString())); - builder.actorName(object.get("actorName").getAsString()); - builder.type(Type.valueOf(object.get("type").getAsString())); - if (object.has("acted")) { - builder.actor(UUID.fromString(object.get("acted").getAsString())); - } - builder.actedName(object.get("actedName").getAsString()); - builder.action(object.get("action").getAsString()); - - return Maps.immutableEntry(id, builder.build()); - } } diff --git a/common/src/main/java/me/lucko/luckperms/common/actionlog/LogDispatcher.java b/common/src/main/java/me/lucko/luckperms/common/actionlog/LogDispatcher.java index 849ce50a..361edd08 100644 --- a/common/src/main/java/me/lucko/luckperms/common/actionlog/LogDispatcher.java +++ b/common/src/main/java/me/lucko/luckperms/common/actionlog/LogDispatcher.java @@ -31,7 +31,7 @@ import me.lucko.luckperms.common.commands.impl.log.LogNotify; import me.lucko.luckperms.common.commands.sender.Sender; import me.lucko.luckperms.common.config.ConfigKeys; import me.lucko.luckperms.common.locale.Message; -import me.lucko.luckperms.common.messaging.ExtendedMessagingService; +import me.lucko.luckperms.common.messaging.InternalMessagingService; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import java.util.Optional; @@ -69,7 +69,7 @@ public class LogDispatcher { return; } - Optional messagingService = this.plugin.getMessagingService(); + Optional messagingService = this.plugin.getMessagingService(); if (!sender.isImport() && messagingService.isPresent()) { messagingService.get().pushLog(entry); } diff --git a/common/src/main/java/me/lucko/luckperms/common/api/LuckPermsApiProvider.java b/common/src/main/java/me/lucko/luckperms/common/api/LuckPermsApiProvider.java index fcfd9a89..00dfda8d 100644 --- a/common/src/main/java/me/lucko/luckperms/common/api/LuckPermsApiProvider.java +++ b/common/src/main/java/me/lucko/luckperms/common/api/LuckPermsApiProvider.java @@ -37,6 +37,7 @@ import me.lucko.luckperms.api.event.EventBus; import me.lucko.luckperms.api.manager.GroupManager; import me.lucko.luckperms.api.manager.TrackManager; import me.lucko.luckperms.api.manager.UserManager; +import me.lucko.luckperms.api.messenger.MessengerProvider; import me.lucko.luckperms.api.metastacking.MetaStackFactory; import me.lucko.luckperms.api.platform.PlatformInfo; import me.lucko.luckperms.common.api.delegates.manager.ApiContextManager; @@ -44,14 +45,16 @@ import me.lucko.luckperms.common.api.delegates.manager.ApiGroupManager; import me.lucko.luckperms.common.api.delegates.manager.ApiTrackManager; import me.lucko.luckperms.common.api.delegates.manager.ApiUserManager; import me.lucko.luckperms.common.api.delegates.misc.ApiActionLogger; +import me.lucko.luckperms.common.api.delegates.misc.ApiMessagingService; import me.lucko.luckperms.common.api.delegates.misc.ApiMetaStackFactory; import me.lucko.luckperms.common.api.delegates.misc.ApiNodeFactory; import me.lucko.luckperms.common.api.delegates.misc.ApiPlatformInfo; +import me.lucko.luckperms.common.config.ConfigKeys; +import me.lucko.luckperms.common.messaging.LuckPermsMessagingService; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import java.util.Optional; import java.util.concurrent.CompletableFuture; -import java.util.function.Function; import javax.annotation.Nonnull; @@ -133,7 +136,14 @@ public class LuckPermsApiProvider implements LuckPermsApi { @Nonnull @Override public Optional getMessagingService() { - return this.plugin.getMessagingService().map(Function.identity()); + return this.plugin.getMessagingService().map(ApiMessagingService::new); + } + + @Override + public void registerMessengerProvider(@Nonnull MessengerProvider messengerProvider) { + if (this.plugin.getConfiguration().get(ConfigKeys.MESSAGING_SERVICE).equals("custom")) { + this.plugin.setMessagingService(new LuckPermsMessagingService(this.plugin, messengerProvider)); + } } @Override diff --git a/common/src/main/java/me/lucko/luckperms/common/api/delegates/misc/ApiMessagingService.java b/common/src/main/java/me/lucko/luckperms/common/api/delegates/misc/ApiMessagingService.java new file mode 100644 index 00000000..f64f5cee --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/api/delegates/misc/ApiMessagingService.java @@ -0,0 +1,59 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.common.api.delegates.misc; + +import me.lucko.luckperms.api.MessagingService; +import me.lucko.luckperms.api.User; +import me.lucko.luckperms.common.api.delegates.model.ApiUser; +import me.lucko.luckperms.common.messaging.InternalMessagingService; + +import java.util.Objects; + +import javax.annotation.Nonnull; + +public class ApiMessagingService implements MessagingService { + private final InternalMessagingService handle; + + public ApiMessagingService(InternalMessagingService handle) { + this.handle = handle; + } + + @Override + public String getName() { + return this.handle.getName(); + } + + @Override + public void pushUpdate() { + this.handle.pushUpdate(); + } + + @Override + public void pushUserUpdate(@Nonnull User user) { + Objects.requireNonNull(user, "user"); + this.handle.pushUserUpdate(ApiUser.cast(user)); + } +} diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/abstraction/SubCommand.java b/common/src/main/java/me/lucko/luckperms/common/commands/abstraction/SubCommand.java index 0701961f..84c82d49 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/abstraction/SubCommand.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/abstraction/SubCommand.java @@ -34,7 +34,7 @@ import me.lucko.luckperms.common.commands.utils.CommandUtils; import me.lucko.luckperms.common.config.ConfigKeys; import me.lucko.luckperms.common.locale.LocalizedSpec; import me.lucko.luckperms.common.locale.Message; -import me.lucko.luckperms.common.messaging.ExtendedMessagingService; +import me.lucko.luckperms.common.messaging.InternalMessagingService; import me.lucko.luckperms.common.model.Group; import me.lucko.luckperms.common.model.Track; import me.lucko.luckperms.common.model.User; @@ -185,7 +185,7 @@ public abstract class SubCommand extends Command { } if (!sender.isImport()) { - Optional messagingService = plugin.getMessagingService(); + Optional messagingService = plugin.getMessagingService(); if (messagingService.isPresent() && plugin.getConfiguration().get(ConfigKeys.AUTO_PUSH_UPDATES)) { messagingService.get().pushUserUpdate(user); } @@ -208,7 +208,7 @@ public abstract class SubCommand extends Command { } if (!sender.isImport()) { - Optional messagingService = plugin.getMessagingService(); + Optional messagingService = plugin.getMessagingService(); if (messagingService.isPresent() && plugin.getConfiguration().get(ConfigKeys.AUTO_PUSH_UPDATES)) { messagingService.get().getUpdateBuffer().request(); } @@ -231,7 +231,7 @@ public abstract class SubCommand extends Command { } if (!sender.isImport()) { - Optional messagingService = plugin.getMessagingService(); + Optional messagingService = plugin.getMessagingService(); if (messagingService.isPresent() && plugin.getConfiguration().get(ConfigKeys.AUTO_PUSH_UPDATES)) { messagingService.get().getUpdateBuffer().request(); } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/InfoCommand.java b/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/InfoCommand.java index b0a02448..3dc411d0 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/InfoCommand.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/InfoCommand.java @@ -34,7 +34,7 @@ import me.lucko.luckperms.common.config.LuckPermsConfiguration; import me.lucko.luckperms.common.locale.CommandSpec; import me.lucko.luckperms.common.locale.LocaleManager; import me.lucko.luckperms.common.locale.Message; -import me.lucko.luckperms.common.messaging.ExtendedMessagingService; +import me.lucko.luckperms.common.messaging.InternalMessagingService; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.utils.DateUtil; import me.lucko.luckperms.common.utils.Predicates; @@ -68,7 +68,7 @@ public class InfoCommand extends SingleCommand { } Message.INFO_MIDDLE.send(sender, - plugin.getMessagingService().map(ExtendedMessagingService::getName).orElse("None"), + plugin.getMessagingService().map(InternalMessagingService::getName).orElse("None"), plugin.getContextManager().getStaticContextString().orElse("None"), plugin.getPlayerCount(), plugin.getUniqueConnections().size(), diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/NetworkSyncCommand.java b/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/NetworkSyncCommand.java index 9a28ce72..9ba7adf9 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/NetworkSyncCommand.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/NetworkSyncCommand.java @@ -32,7 +32,7 @@ import me.lucko.luckperms.common.commands.sender.Sender; import me.lucko.luckperms.common.locale.CommandSpec; import me.lucko.luckperms.common.locale.LocaleManager; import me.lucko.luckperms.common.locale.Message; -import me.lucko.luckperms.common.messaging.ExtendedMessagingService; +import me.lucko.luckperms.common.messaging.InternalMessagingService; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.utils.Predicates; @@ -50,7 +50,7 @@ public class NetworkSyncCommand extends SingleCommand { plugin.getUpdateTaskBuffer().request().join(); Message.UPDATE_TASK_COMPLETE_NETWORK.send(sender); - Optional messagingService = plugin.getMessagingService(); + Optional messagingService = plugin.getMessagingService(); if (!messagingService.isPresent()) { Message.UPDATE_TASK_PUSH_FAILURE_NOT_SETUP.send(sender); return CommandResult.FAILURE; diff --git a/common/src/main/java/me/lucko/luckperms/common/messaging/AbstractMessagingService.java b/common/src/main/java/me/lucko/luckperms/common/messaging/AbstractMessagingService.java deleted file mode 100644 index 371ee160..00000000 --- a/common/src/main/java/me/lucko/luckperms/common/messaging/AbstractMessagingService.java +++ /dev/null @@ -1,271 +0,0 @@ -/* - * This file is part of LuckPerms, licensed under the MIT License. - * - * Copyright (c) lucko (Luck) - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package me.lucko.luckperms.common.messaging; - -import com.google.common.collect.Maps; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonObject; - -import me.lucko.luckperms.api.LogEntry; -import me.lucko.luckperms.common.actionlog.ExtendedLogEntry; -import me.lucko.luckperms.common.buffers.BufferedRequest; -import me.lucko.luckperms.common.config.ConfigKeys; -import me.lucko.luckperms.common.model.User; -import me.lucko.luckperms.common.plugin.LuckPermsPlugin; - -import java.nio.ByteBuffer; -import java.util.Base64; -import java.util.Collections; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.function.Consumer; - -/** - * An abstract implementation of {@link me.lucko.luckperms.api.MessagingService}. - */ -public abstract class AbstractMessagingService implements ExtendedMessagingService { - protected static final String CHANNEL = "lpuc"; - - private static final String UPDATE_HEADER = "update:"; - private static final String USER_UPDATE_HEADER = "userupdate:"; - private static final String LOG_HEADER = "log"; - - private final LuckPermsPlugin plugin; - private final String name; - private final Set receivedMessages; - private final Gson gson; - private final BufferedRequest updateBuffer; - - public AbstractMessagingService(LuckPermsPlugin plugin, String name) { - this.plugin = plugin; - this.name = name; - this.receivedMessages = Collections.synchronizedSet(new HashSet<>()); - this.gson = new GsonBuilder().disableHtmlEscaping().create(); - this.updateBuffer = new PushUpdateBuffer(plugin); - } - - public LuckPermsPlugin getPlugin() { - return this.plugin; - } - - @Override - public String getName() { - return this.name; - } - - @Override - public BufferedRequest getUpdateBuffer() { - return this.updateBuffer; - } - - protected abstract void sendMessage(String message); - - protected void onMessage(String msg, Consumer callback) { - if (msg.startsWith(UPDATE_HEADER) && msg.length() > UPDATE_HEADER.length()) { - String content = msg.substring(UPDATE_HEADER.length()); - - UUID requestId = uuidFromString(content); - if (requestId == null) { - return; - } - - if (!this.receivedMessages.add(requestId)) { - return; - } - - this.plugin.getLog().info("[" + this.name + " Messaging] Received update ping with id: " + requestId.toString()); - - if (this.plugin.getEventFactory().handleNetworkPreSync(false, requestId)) { - return; - } - - this.plugin.getUpdateTaskBuffer().request(); - - if (callback != null) { - callback.accept(msg); - } - - } else if (msg.startsWith(USER_UPDATE_HEADER) && msg.length() > USER_UPDATE_HEADER.length()) { - String content = msg.substring(USER_UPDATE_HEADER.length()); - - Map.Entry entry = uuidsFromString(content); - if (entry == null) { - return; - } - - UUID requestId = entry.getKey(); - UUID userUuid = entry.getValue(); - - if (!this.receivedMessages.add(requestId)) { - return; - } - - User user = this.plugin.getUserManager().getIfLoaded(userUuid); - if (user == null) { - return; - } - - this.plugin.getLog().info("[" + this.name + " Messaging] Received user update ping for '" + user.getFriendlyName() + "' with id: " + uuidToString(requestId)); - - if (this.plugin.getEventFactory().handleNetworkPreSync(false, requestId)) { - return; - } - - this.plugin.getStorage().loadUser(user.getUuid(), null); - - if (callback != null) { - callback.accept(msg); - } - - } else if (msg.startsWith(LOG_HEADER) && msg.length() > LOG_HEADER.length()) { - String content = msg.substring(LOG_HEADER.length()); - - Map.Entry entry; - try { - entry = ExtendedLogEntry.deserialize(this.gson.fromJson(content, JsonObject.class)); - } catch (Exception e) { - return; - } - - if (entry.getKey() == null) { - return; - } - - UUID requestId = uuidFromString(entry.getKey()); - if (requestId == null) { - return; - } - - if (!this.receivedMessages.add(requestId)) { - return; - } - - this.plugin.getEventFactory().handleLogReceive(requestId, entry.getValue()); - this.plugin.getLogDispatcher().dispatchFromRemote(entry.getValue()); - - if (callback != null) { - callback.accept(msg); - } - } - } - - @Override - public void pushUpdate() { - this.plugin.getScheduler().doAsync(() -> { - UUID requestId = generatePingId(); - String strId = uuidToString(requestId); - - this.plugin.getLog().info("[" + this.name + " Messaging] Sending ping with id: " + strId); - sendMessage(UPDATE_HEADER + strId); - }); - } - - @Override - public void pushUserUpdate(User user) { - this.plugin.getScheduler().doAsync(() -> { - UUID requestId = generatePingId(); - String strId = uuidToString(requestId); - - this.plugin.getLog().info("[" + this.name + " Messaging] Sending user ping for '" + user.getFriendlyName() + "' with id: " + strId); - sendMessage(USER_UPDATE_HEADER + uuidsToString(requestId, user.getUuid())); - }); - } - - @Override - public void pushLog(LogEntry logEntry) { - this.plugin.getScheduler().doAsync(() -> { - UUID requestId = generatePingId(); - String strId = uuidToString(requestId); - - if (this.plugin.getEventFactory().handleLogNetworkPublish(!this.plugin.getConfiguration().get(ConfigKeys.PUSH_LOG_ENTRIES), requestId, logEntry)) { - return; - } - - this.plugin.getLog().info("[" + this.name + " Messaging] Sending log with id: " + strId); - sendMessage(LOG_HEADER + this.gson.toJson(ExtendedLogEntry.serializeWithId(strId, logEntry))); - }); - } - - private UUID generatePingId() { - UUID uuid = UUID.randomUUID(); - this.receivedMessages.add(uuid); - return uuid; - } - - private static String uuidToString(UUID uuid) { - ByteBuffer buf = ByteBuffer.allocate(Long.BYTES * 2); - buf.putLong(uuid.getMostSignificantBits()); - buf.putLong(uuid.getLeastSignificantBits()); - return Base64.getEncoder().encodeToString(buf.array()); - } - - private static UUID uuidFromString(String s) { - try { - byte[] bytes = Base64.getDecoder().decode(s); - ByteBuffer buf = ByteBuffer.wrap(bytes); - return new UUID(buf.getLong(), buf.getLong()); - } catch (IllegalArgumentException e) { - return null; - } - } - - private static String uuidsToString(UUID uuid1, UUID uuid2) { - ByteBuffer buf = ByteBuffer.allocate(Long.BYTES * 4); - buf.putLong(uuid1.getMostSignificantBits()); - buf.putLong(uuid1.getLeastSignificantBits()); - buf.putLong(uuid2.getMostSignificantBits()); - buf.putLong(uuid2.getLeastSignificantBits()); - return Base64.getEncoder().encodeToString(buf.array()); - } - - private static Map.Entry uuidsFromString(String s) { - try { - byte[] bytes = Base64.getDecoder().decode(s); - ByteBuffer buf = ByteBuffer.wrap(bytes); - UUID uuid1 = new UUID(buf.getLong(), buf.getLong()); - UUID uuid2 = new UUID(buf.getLong(), buf.getLong()); - return Maps.immutableEntry(uuid1, uuid2); - } catch (IllegalArgumentException e) { - return null; - } - } - - private final class PushUpdateBuffer extends BufferedRequest { - public PushUpdateBuffer(LuckPermsPlugin plugin) { - super(2000L, 200L, plugin.getScheduler().async()); - } - - @Override - protected Void perform() { - pushUpdate(); - return null; - } - } - -} diff --git a/common/src/main/java/me/lucko/luckperms/common/messaging/ExtendedMessagingService.java b/common/src/main/java/me/lucko/luckperms/common/messaging/InternalMessagingService.java similarity index 92% rename from common/src/main/java/me/lucko/luckperms/common/messaging/ExtendedMessagingService.java rename to common/src/main/java/me/lucko/luckperms/common/messaging/InternalMessagingService.java index e5cfb508..fb27acb5 100644 --- a/common/src/main/java/me/lucko/luckperms/common/messaging/ExtendedMessagingService.java +++ b/common/src/main/java/me/lucko/luckperms/common/messaging/InternalMessagingService.java @@ -26,11 +26,10 @@ package me.lucko.luckperms.common.messaging; import me.lucko.luckperms.api.LogEntry; -import me.lucko.luckperms.api.MessagingService; import me.lucko.luckperms.common.buffers.BufferedRequest; import me.lucko.luckperms.common.model.User; -public interface ExtendedMessagingService extends MessagingService { +public interface InternalMessagingService { /** * Gets the name of this messaging service @@ -51,6 +50,12 @@ public interface ExtendedMessagingService extends MessagingService { */ BufferedRequest getUpdateBuffer(); + /** + * Uses the messaging service to inform other servers about a general + * change. + */ + void pushUpdate(); + /** * Pushes an update for a specific user. * diff --git a/common/src/main/java/me/lucko/luckperms/common/messaging/LuckPermsMessagingService.java b/common/src/main/java/me/lucko/luckperms/common/messaging/LuckPermsMessagingService.java new file mode 100644 index 00000000..666f764b --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/messaging/LuckPermsMessagingService.java @@ -0,0 +1,209 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.common.messaging; + +import me.lucko.luckperms.api.LogEntry; +import me.lucko.luckperms.api.messenger.IncomingMessageConsumer; +import me.lucko.luckperms.api.messenger.Messenger; +import me.lucko.luckperms.api.messenger.MessengerProvider; +import me.lucko.luckperms.api.messenger.message.Message; +import me.lucko.luckperms.api.messenger.message.type.LogMessage; +import me.lucko.luckperms.api.messenger.message.type.UpdateMessage; +import me.lucko.luckperms.api.messenger.message.type.UserUpdateMessage; +import me.lucko.luckperms.common.actionlog.ExtendedLogEntry; +import me.lucko.luckperms.common.buffers.BufferedRequest; +import me.lucko.luckperms.common.config.ConfigKeys; +import me.lucko.luckperms.common.messaging.message.LogMessageImpl; +import me.lucko.luckperms.common.messaging.message.UpdateMessageImpl; +import me.lucko.luckperms.common.messaging.message.UserUpdateMessageImpl; +import me.lucko.luckperms.common.model.User; +import me.lucko.luckperms.common.plugin.LuckPermsPlugin; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; + +import javax.annotation.Nonnull; + +public class LuckPermsMessagingService implements InternalMessagingService, IncomingMessageConsumer { + private final LuckPermsPlugin plugin; + private final Set receivedMessages; + private final BufferedRequest updateBuffer; + + private final MessengerProvider messengerProvider; + private final Messenger messenger; + + public LuckPermsMessagingService(LuckPermsPlugin plugin, MessengerProvider messengerProvider) { + this.plugin = plugin; + + this.messengerProvider = messengerProvider; + this.messenger = messengerProvider.obtain(this); + Objects.requireNonNull(this.messenger, "messenger"); + + this.receivedMessages = Collections.synchronizedSet(new HashSet<>()); + this.updateBuffer = new PushUpdateBuffer(plugin); + } + + @Override + public String getName() { + return this.messengerProvider.getName(); + } + + @Override + public void close() { + this.messenger.close(); + } + + @Override + public BufferedRequest getUpdateBuffer() { + return this.updateBuffer; + } + + private UUID generatePingId() { + UUID uuid = UUID.randomUUID(); + this.receivedMessages.add(uuid); + return uuid; + } + + @Override + public void pushUpdate() { + this.plugin.getScheduler().doAsync(() -> { + UUID requestId = generatePingId(); + this.plugin.getLog().info("[" + getName() + " Messaging] Sending ping with id: " + requestId); + this.messenger.sendOutgoingMessage(new UpdateMessageImpl(requestId)); + }); + } + + @Override + public void pushUserUpdate(User user) { + this.plugin.getScheduler().doAsync(() -> { + UUID requestId = generatePingId(); + this.plugin.getLog().info("[" + getName() + " Messaging] Sending user ping for '" + user.getFriendlyName() + "' with id: " + requestId); + this.messenger.sendOutgoingMessage(new UserUpdateMessageImpl(requestId, user.getUuid())); + }); + } + + @Override + public void pushLog(LogEntry logEntry) { + this.plugin.getScheduler().doAsync(() -> { + UUID requestId = generatePingId(); + + if (this.plugin.getEventFactory().handleLogNetworkPublish(!this.plugin.getConfiguration().get(ConfigKeys.PUSH_LOG_ENTRIES), requestId, logEntry)) { + return; + } + + this.plugin.getLog().info("[" + getName() + " Messaging] Sending log with id: " + requestId); + this.messenger.sendOutgoingMessage(new LogMessageImpl(requestId, logEntry)); + }); + } + + @Override + public boolean consumeIncomingMessage(@Nonnull Message message) { + Objects.requireNonNull(message, "message"); + + if (message instanceof UpdateMessage) { + UpdateMessage msg = (UpdateMessage) message; + if (!this.receivedMessages.add(msg.getId())) { + return false; + } + + this.plugin.getLog().info("[" + getName() + " Messaging] Received update ping with id: " + msg.getId()); + + if (this.plugin.getEventFactory().handleNetworkPreSync(false, msg.getId())) { + return true; + } + + this.plugin.getUpdateTaskBuffer().request(); + return true; + + } else if (message instanceof UserUpdateMessage) { + UserUpdateMessage msg = (UserUpdateMessage) message; + if (!this.receivedMessages.add(msg.getId())) { + return false; + } + + User user = this.plugin.getUserManager().getIfLoaded(msg.getUser()); + if (user == null) { + return true; + } + + this.plugin.getLog().info("[" + getName() + " Messaging] Received user update ping for '" + user.getFriendlyName() + "' with id: " + msg.getId()); + + if (this.plugin.getEventFactory().handleNetworkPreSync(false, msg.getId())) { + return true; + } + + this.plugin.getStorage().loadUser(user.getUuid(), null); + return true; + + } else if (message instanceof LogMessage) { + LogMessage msg = (LogMessage) message; + if (!this.receivedMessages.add(msg.getId())) { + return false; + } + + this.plugin.getEventFactory().handleLogReceive(msg.getId(), msg.getLogEntry()); + this.plugin.getLogDispatcher().dispatchFromRemote((ExtendedLogEntry) msg.getLogEntry()); + return true; + + } else { + this.plugin.getLog().warn("Unable to decode incoming message: " + message + " (" + message.getClass().getName() + ")"); + return false; + } + } + + @Override + public boolean consumeIncomingMessageAsString(@Nonnull String encodedString) { + Objects.requireNonNull(encodedString, "encodedString"); + + Message decoded = UpdateMessageImpl.decode(encodedString); + if (decoded != null) { + return consumeIncomingMessage(decoded); + } + + decoded = UserUpdateMessageImpl.decode(encodedString); + if (decoded != null) { + return consumeIncomingMessage(decoded); + } + + decoded = LogMessageImpl.decode(encodedString); + return decoded != null && consumeIncomingMessage(decoded); + } + + private final class PushUpdateBuffer extends BufferedRequest { + public PushUpdateBuffer(LuckPermsPlugin plugin) { + super(2000L, 200L, plugin.getScheduler().async()); + } + + @Override + protected Void perform() { + pushUpdate(); + return null; + } + } +} diff --git a/common/src/main/java/me/lucko/luckperms/common/messaging/MessagingFactory.java b/common/src/main/java/me/lucko/luckperms/common/messaging/MessagingFactory.java index da27b7b3..0abafd5c 100644 --- a/common/src/main/java/me/lucko/luckperms/common/messaging/MessagingFactory.java +++ b/common/src/main/java/me/lucko/luckperms/common/messaging/MessagingFactory.java @@ -25,9 +25,15 @@ package me.lucko.luckperms.common.messaging; +import me.lucko.luckperms.api.messenger.IncomingMessageConsumer; +import me.lucko.luckperms.api.messenger.Messenger; +import me.lucko.luckperms.api.messenger.MessengerProvider; import me.lucko.luckperms.common.config.ConfigKeys; +import me.lucko.luckperms.common.messaging.redis.RedisMessenger; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; +import javax.annotation.Nonnull; + public class MessagingFactory

{ private final P plugin; @@ -39,7 +45,7 @@ public class MessagingFactory

{ return this.plugin; } - public final ExtendedMessagingService getInstance() { + public final InternalMessagingService getInstance() { String messagingType = this.plugin.getConfiguration().get(ConfigKeys.MESSAGING_SERVICE).toLowerCase(); if (messagingType.equals("none") && this.plugin.getConfiguration().get(ConfigKeys.REDIS_ENABLED)) { messagingType = "redis"; @@ -51,7 +57,7 @@ public class MessagingFactory

{ this.plugin.getLog().info("Loading messaging service... [" + messagingType.toUpperCase() + "]"); - ExtendedMessagingService service = getServiceFor(messagingType); + InternalMessagingService service = getServiceFor(messagingType); if (service != null) { return service; } @@ -60,15 +66,12 @@ public class MessagingFactory

{ return null; } - protected ExtendedMessagingService getServiceFor(String messagingType) { + protected InternalMessagingService getServiceFor(String messagingType) { if (messagingType.equals("redis")) { if (this.plugin.getConfiguration().get(ConfigKeys.REDIS_ENABLED)) { - RedisMessagingService redis = new RedisMessagingService(this.plugin); try { - redis.init(this.plugin.getConfiguration().get(ConfigKeys.REDIS_ADDRESS), this.plugin.getConfiguration().get(ConfigKeys.REDIS_PASSWORD)); - return redis; + return new LuckPermsMessagingService(this.plugin, new RedisMessengerProvider()); } catch (Exception e) { - this.plugin.getLog().warn("Couldn't load redis..."); e.printStackTrace(); } } else { @@ -79,4 +82,21 @@ public class MessagingFactory

{ return null; } + private class RedisMessengerProvider implements MessengerProvider { + + @Nonnull + @Override + public String getName() { + return "Redis"; + } + + @Nonnull + @Override + public Messenger obtain(@Nonnull IncomingMessageConsumer incomingMessageConsumer) { + RedisMessenger redis = new RedisMessenger(getPlugin(), incomingMessageConsumer); + redis.init(getPlugin().getConfiguration().get(ConfigKeys.REDIS_ADDRESS), getPlugin().getConfiguration().get(ConfigKeys.REDIS_PASSWORD)); + return redis; + } + } + } diff --git a/common/src/main/java/me/lucko/luckperms/common/messaging/message/AbstractMessage.java b/common/src/main/java/me/lucko/luckperms/common/messaging/message/AbstractMessage.java new file mode 100644 index 00000000..683d7a8d --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/messaging/message/AbstractMessage.java @@ -0,0 +1,48 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.common.messaging.message; + +import me.lucko.luckperms.api.messenger.message.Message; +import me.lucko.luckperms.api.messenger.message.OutgoingMessage; + +import java.util.UUID; + +import javax.annotation.Nonnull; + +public abstract class AbstractMessage implements Message, OutgoingMessage { + private final UUID id; + + public AbstractMessage(UUID id) { + this.id = id; + } + + @Nonnull + @Override + public UUID getId() { + return this.id; + } + +} diff --git a/common/src/main/java/me/lucko/luckperms/common/messaging/message/LogMessageImpl.java b/common/src/main/java/me/lucko/luckperms/common/messaging/message/LogMessageImpl.java new file mode 100644 index 00000000..ab1e3da9 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/messaging/message/LogMessageImpl.java @@ -0,0 +1,138 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.common.messaging.message; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; + +import me.lucko.luckperms.api.LogEntry; +import me.lucko.luckperms.api.messenger.message.type.LogMessage; +import me.lucko.luckperms.common.actionlog.ExtendedLogEntry; + +import java.nio.ByteBuffer; +import java.util.Base64; +import java.util.UUID; + +import javax.annotation.Nonnull; + +public class LogMessageImpl extends AbstractMessage implements LogMessage { + private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().create(); + private static final String LOG_HEADER = "log"; + + public static LogMessageImpl decode(String msg) { + if (msg.startsWith(LOG_HEADER) && msg.length() > LOG_HEADER.length()) { + String content = msg.substring(LOG_HEADER.length()); + + try { + return decodeContent(GSON.fromJson(content, JsonObject.class)); + } catch (Exception e) { + return null; + } + } + + return null; + } + + private final LogEntry logEntry; + + public LogMessageImpl(UUID id, LogEntry logEntry) { + super(id); + this.logEntry = logEntry; + } + + @Nonnull + @Override + public LogEntry getLogEntry() { + return this.logEntry; + } + + @Nonnull + @Override + public String asEncodedString() { + return LOG_HEADER + GSON.toJson(encodeContent(uuidToString(getId()), this.logEntry)); + } + + private static String uuidToString(UUID uuid) { + ByteBuffer buf = ByteBuffer.allocate(Long.BYTES * 2); + buf.putLong(uuid.getMostSignificantBits()); + buf.putLong(uuid.getLeastSignificantBits()); + return Base64.getEncoder().encodeToString(buf.array()); + } + + private static UUID uuidFromString(String s) { + try { + byte[] bytes = Base64.getDecoder().decode(s); + ByteBuffer buf = ByteBuffer.wrap(bytes); + return new UUID(buf.getLong(), buf.getLong()); + } catch (IllegalArgumentException e) { + return null; + } + } + + private static JsonObject encodeContent(String id, LogEntry entry) { + JsonObject data = new JsonObject(); + + data.add("id", new JsonPrimitive(id)); + data.add("actor", new JsonPrimitive(entry.getActor().toString())); + data.add("actorName", new JsonPrimitive(entry.getActorName())); + data.add("type", new JsonPrimitive(entry.getType().name())); + if (entry.getActed().isPresent()) { + data.add("acted", new JsonPrimitive(entry.getActed().get().toString())); + } + data.add("actedName", new JsonPrimitive(entry.getActedName())); + data.add("action", new JsonPrimitive(entry.getAction())); + + return data; + } + + private static LogMessageImpl decodeContent(JsonObject object) { + ExtendedLogEntry.ExtendedLogEntryBuilder builder = ExtendedLogEntry.build(); + + String id = object.get("id").getAsString(); + if (id == null) { + return null; + } + + UUID uuid = uuidFromString(id); + if (uuid == null) { + return null; + } + + builder.actor(UUID.fromString(object.get("actor").getAsString())); + builder.actorName(object.get("actorName").getAsString()); + builder.type(LogEntry.Type.valueOf(object.get("type").getAsString())); + if (object.has("acted")) { + builder.actor(UUID.fromString(object.get("acted").getAsString())); + } + builder.actedName(object.get("actedName").getAsString()); + builder.action(object.get("action").getAsString()); + + return new LogMessageImpl(uuid, builder.build()); + } + +} diff --git a/common/src/main/java/me/lucko/luckperms/common/messaging/message/UpdateMessageImpl.java b/common/src/main/java/me/lucko/luckperms/common/messaging/message/UpdateMessageImpl.java new file mode 100644 index 00000000..636c0fd5 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/messaging/message/UpdateMessageImpl.java @@ -0,0 +1,74 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.common.messaging.message; + +import me.lucko.luckperms.api.messenger.message.type.UpdateMessage; + +import java.nio.ByteBuffer; +import java.util.Base64; +import java.util.UUID; + +import javax.annotation.Nonnull; + +public class UpdateMessageImpl extends AbstractMessage implements UpdateMessage { + private static final String UPDATE_HEADER = "update:"; + + public static UpdateMessageImpl decode(String msg) { + if (msg.startsWith(UPDATE_HEADER) && msg.length() > UPDATE_HEADER.length()) { + String content = msg.substring(UPDATE_HEADER.length()); + return decodeContent(content); + } + + return null; + } + + public UpdateMessageImpl(UUID id) { + super(id); + } + + @Nonnull + @Override + public String asEncodedString() { + return UPDATE_HEADER + encodeContent(getId()); + } + + private static String encodeContent(UUID uuid) { + ByteBuffer buf = ByteBuffer.allocate(Long.BYTES * 2); + buf.putLong(uuid.getMostSignificantBits()); + buf.putLong(uuid.getLeastSignificantBits()); + return Base64.getEncoder().encodeToString(buf.array()); + } + + private static UpdateMessageImpl decodeContent(String s) { + try { + byte[] bytes = Base64.getDecoder().decode(s); + ByteBuffer buf = ByteBuffer.wrap(bytes); + return new UpdateMessageImpl(new UUID(buf.getLong(), buf.getLong())); + } catch (IllegalArgumentException e) { + return null; + } + } +} diff --git a/common/src/main/java/me/lucko/luckperms/common/messaging/message/UserUpdateMessageImpl.java b/common/src/main/java/me/lucko/luckperms/common/messaging/message/UserUpdateMessageImpl.java new file mode 100644 index 00000000..2db82d33 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/messaging/message/UserUpdateMessageImpl.java @@ -0,0 +1,87 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.common.messaging.message; + +import me.lucko.luckperms.api.messenger.message.type.UserUpdateMessage; + +import java.nio.ByteBuffer; +import java.util.Base64; +import java.util.UUID; + +import javax.annotation.Nonnull; + +public class UserUpdateMessageImpl extends AbstractMessage implements UserUpdateMessage { + private static final String USER_UPDATE_HEADER = "userupdate:"; + + public static UserUpdateMessageImpl decode(String msg) { + if (msg.startsWith(USER_UPDATE_HEADER) && msg.length() > USER_UPDATE_HEADER.length()) { + String content = msg.substring(USER_UPDATE_HEADER.length()); + return decodeContent(content); + } + + return null; + } + + private final UUID userUuid; + + public UserUpdateMessageImpl(UUID id, UUID userUuid) { + super(id); + this.userUuid = userUuid; + } + + @Nonnull + @Override + public UUID getUser() { + return this.userUuid; + } + + @Nonnull + @Override + public String asEncodedString() { + return USER_UPDATE_HEADER + encodeContent(getId(), this.userUuid); + } + + private static String encodeContent(UUID id, UUID userUuid) { + ByteBuffer buf = ByteBuffer.allocate(Long.BYTES * 4); + buf.putLong(id.getMostSignificantBits()); + buf.putLong(id.getLeastSignificantBits()); + buf.putLong(userUuid.getMostSignificantBits()); + buf.putLong(userUuid.getLeastSignificantBits()); + return Base64.getEncoder().encodeToString(buf.array()); + } + + private static UserUpdateMessageImpl decodeContent(String s) { + try { + byte[] bytes = Base64.getDecoder().decode(s); + ByteBuffer buf = ByteBuffer.wrap(bytes); + UUID id = new UUID(buf.getLong(), buf.getLong()); + UUID userUuid = new UUID(buf.getLong(), buf.getLong()); + return new UserUpdateMessageImpl(id, userUuid); + } catch (IllegalArgumentException e) { + return null; + } + } +} diff --git a/common/src/main/java/me/lucko/luckperms/common/messaging/RedisMessagingService.java b/common/src/main/java/me/lucko/luckperms/common/messaging/redis/RedisMessenger.java similarity index 76% rename from common/src/main/java/me/lucko/luckperms/common/messaging/RedisMessagingService.java rename to common/src/main/java/me/lucko/luckperms/common/messaging/redis/RedisMessenger.java index 4a7f7bcb..62d3533a 100644 --- a/common/src/main/java/me/lucko/luckperms/common/messaging/RedisMessagingService.java +++ b/common/src/main/java/me/lucko/luckperms/common/messaging/redis/RedisMessenger.java @@ -23,8 +23,11 @@ * SOFTWARE. */ -package me.lucko.luckperms.common.messaging; +package me.lucko.luckperms.common.messaging.redis; +import me.lucko.luckperms.api.messenger.IncomingMessageConsumer; +import me.lucko.luckperms.api.messenger.Messenger; +import me.lucko.luckperms.api.messenger.message.OutgoingMessage; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import redis.clients.jedis.Jedis; @@ -32,17 +35,23 @@ import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; import redis.clients.jedis.JedisPubSub; +import javax.annotation.Nonnull; + /** - * An implementation of {@link me.lucko.luckperms.api.MessagingService} using Redis. + * An implementation of {@link Messenger} using Redis. */ -public class RedisMessagingService extends AbstractMessagingService { +public class RedisMessenger implements Messenger { + private static final String CHANNEL = "lpuc"; + private final LuckPermsPlugin plugin; + private final IncomingMessageConsumer consumer; + private JedisPool jedisPool; private LPSub sub; - public RedisMessagingService(LuckPermsPlugin plugin) { - super(plugin, "Redis"); + public RedisMessenger(LuckPermsPlugin plugin, IncomingMessageConsumer consumer) { this.plugin = plugin; + this.consumer = consumer; } public void init(String address, String password) { @@ -67,24 +76,24 @@ public class RedisMessagingService extends AbstractMessagingService { } @Override - public void close() { - this.sub.unsubscribe(); - this.jedisPool.destroy(); - } - - @Override - protected void sendMessage(String message) { + public void sendOutgoingMessage(@Nonnull OutgoingMessage outgoingMessage) { try (Jedis jedis = this.jedisPool.getResource()) { - jedis.publish(CHANNEL, message); + jedis.publish(CHANNEL, outgoingMessage.asEncodedString()); } catch (Exception e) { e.printStackTrace(); } } - private static class LPSub extends JedisPubSub { - private final RedisMessagingService parent; + @Override + public void close() { + this.sub.unsubscribe(); + this.jedisPool.destroy(); + } - public LPSub(RedisMessagingService parent) { + private static class LPSub extends JedisPubSub { + private final RedisMessenger parent; + + public LPSub(RedisMessenger parent) { this.parent = parent; } @@ -93,7 +102,7 @@ public class RedisMessagingService extends AbstractMessagingService { if (!channel.equals(CHANNEL)) { return; } - this.parent.onMessage(msg, null); + this.parent.consumer.consumeIncomingMessageAsString(msg); } } diff --git a/common/src/main/java/me/lucko/luckperms/common/plugin/LuckPermsPlugin.java b/common/src/main/java/me/lucko/luckperms/common/plugin/LuckPermsPlugin.java index 603c3a71..988eb28e 100644 --- a/common/src/main/java/me/lucko/luckperms/common/plugin/LuckPermsPlugin.java +++ b/common/src/main/java/me/lucko/luckperms/common/plugin/LuckPermsPlugin.java @@ -46,7 +46,7 @@ import me.lucko.luckperms.common.logging.Logger; import me.lucko.luckperms.common.managers.group.GroupManager; import me.lucko.luckperms.common.managers.track.TrackManager; import me.lucko.luckperms.common.managers.user.UserManager; -import me.lucko.luckperms.common.messaging.ExtendedMessagingService; +import me.lucko.luckperms.common.messaging.InternalMessagingService; import me.lucko.luckperms.common.model.User; import me.lucko.luckperms.common.storage.Storage; import me.lucko.luckperms.common.storage.dao.file.FileWatcher; @@ -65,7 +65,8 @@ import java.util.UUID; import java.util.stream.Stream; /** - * Main internal interface for LuckPerms plugins, providing the base for abstraction throughout the project. + * Main internal interface for LuckPerms plugins, providing the base for + * abstraction throughout the project. * * All plugin platforms implement this interface. */ @@ -107,11 +108,18 @@ public interface LuckPermsPlugin { Storage getStorage(); /** - * Gets the redis messaging instance. + * Gets the messaging service. * - * @return the redis messaging service + * @return the messaging service */ - Optional getMessagingService(); + Optional getMessagingService(); + + /** + * Sets the messaging service. + * + * @param service the service + */ + void setMessagingService(InternalMessagingService service); /** * Gets a wrapped logger instance for the platform. diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongePlugin.java b/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongePlugin.java index ba074ad5..f099b7b7 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongePlugin.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongePlugin.java @@ -55,7 +55,7 @@ import me.lucko.luckperms.common.locale.NoopLocaleManager; import me.lucko.luckperms.common.locale.SimpleLocaleManager; import me.lucko.luckperms.common.logging.SenderLogger; import me.lucko.luckperms.common.managers.track.StandardTrackManager; -import me.lucko.luckperms.common.messaging.ExtendedMessagingService; +import me.lucko.luckperms.common.messaging.InternalMessagingService; import me.lucko.luckperms.common.model.User; import me.lucko.luckperms.common.plugin.SchedulerAdapter; import me.lucko.luckperms.common.storage.Storage; @@ -172,7 +172,7 @@ public class LPSpongePlugin implements LuckPermsSpongePlugin { private StandardTrackManager trackManager; private Storage storage; private FileWatcher fileWatcher = null; - private ExtendedMessagingService messagingService = null; + private InternalMessagingService messagingService = null; private UuidCache uuidCache; private LuckPermsApiProvider apiProvider; private EventFactory eventFactory; @@ -370,10 +370,17 @@ public class LPSpongePlugin implements LuckPermsSpongePlugin { } @Override - public Optional getMessagingService() { + public Optional getMessagingService() { return Optional.ofNullable(this.messagingService); } + @Override + public void setMessagingService(InternalMessagingService messagingService) { + if (this.messagingService == null) { + this.messagingService = messagingService; + } + } + @Override public Optional getFileWatcher() { return Optional.ofNullable(this.fileWatcher); diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/messaging/BungeeMessagingService.java b/sponge/src/main/java/me/lucko/luckperms/sponge/messaging/BungeeMessenger.java similarity index 79% rename from sponge/src/main/java/me/lucko/luckperms/sponge/messaging/BungeeMessagingService.java rename to sponge/src/main/java/me/lucko/luckperms/sponge/messaging/BungeeMessenger.java index 0aff65a4..309c03c6 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/messaging/BungeeMessagingService.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/messaging/BungeeMessenger.java @@ -27,8 +27,9 @@ package me.lucko.luckperms.sponge.messaging; import com.google.common.collect.Iterables; -import me.lucko.luckperms.common.messaging.AbstractMessagingService; -import me.lucko.luckperms.common.messaging.ExtendedMessagingService; +import me.lucko.luckperms.api.messenger.IncomingMessageConsumer; +import me.lucko.luckperms.api.messenger.Messenger; +import me.lucko.luckperms.api.messenger.message.OutgoingMessage; import me.lucko.luckperms.sponge.LPSpongePlugin; import org.spongepowered.api.Platform; @@ -44,15 +45,19 @@ import java.util.concurrent.TimeUnit; import javax.annotation.Nonnull; /** - * An implementation of {@link ExtendedMessagingService} using the plugin messaging channels. + * An implementation of {@link Messenger} using the plugin messaging channels. */ -public class BungeeMessagingService extends AbstractMessagingService implements RawDataListener { +public class BungeeMessenger implements Messenger, RawDataListener { + private static final String CHANNEL = "lpuc"; + private final LPSpongePlugin plugin; + private final IncomingMessageConsumer consumer; + private ChannelBinding.RawDataChannel channel = null; - public BungeeMessagingService(LPSpongePlugin plugin) { - super(plugin, "Bungee"); + public BungeeMessenger(LPSpongePlugin plugin, IncomingMessageConsumer consumer) { this.plugin = plugin; + this.consumer = consumer; } public void init() { @@ -68,7 +73,7 @@ public class BungeeMessagingService extends AbstractMessagingService implements } @Override - protected void sendMessage(String message) { + public void sendOutgoingMessage(@Nonnull OutgoingMessage outgoingMessage) { this.plugin.getSpongeScheduler().createTaskBuilder().interval(10, TimeUnit.SECONDS).execute(task -> { if (!this.plugin.getGame().isServerAvailable()) { return; @@ -80,8 +85,7 @@ public class BungeeMessagingService extends AbstractMessagingService implements return; } - this.channel.sendTo(p, buf -> buf.writeUTF(message)); - + this.channel.sendTo(p, buf -> buf.writeUTF(outgoingMessage.asEncodedString())); task.cancel(); }).submit(this.plugin); } @@ -89,6 +93,6 @@ public class BungeeMessagingService extends AbstractMessagingService implements @Override public void handlePayload(@Nonnull ChannelBuf buf, @Nonnull RemoteConnection connection, @Nonnull Platform.Type type) { String msg = buf.readUTF(); - onMessage(msg, null); + this.consumer.consumeIncomingMessageAsString(msg); } } diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/messaging/SpongeMessagingFactory.java b/sponge/src/main/java/me/lucko/luckperms/sponge/messaging/SpongeMessagingFactory.java index 85e3c3fa..cd47a80d 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/messaging/SpongeMessagingFactory.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/messaging/SpongeMessagingFactory.java @@ -25,23 +25,49 @@ package me.lucko.luckperms.sponge.messaging; -import me.lucko.luckperms.common.messaging.ExtendedMessagingService; +import me.lucko.luckperms.api.messenger.IncomingMessageConsumer; +import me.lucko.luckperms.api.messenger.Messenger; +import me.lucko.luckperms.api.messenger.MessengerProvider; +import me.lucko.luckperms.common.messaging.InternalMessagingService; +import me.lucko.luckperms.common.messaging.LuckPermsMessagingService; import me.lucko.luckperms.common.messaging.MessagingFactory; import me.lucko.luckperms.sponge.LPSpongePlugin; +import javax.annotation.Nonnull; + public class SpongeMessagingFactory extends MessagingFactory { public SpongeMessagingFactory(LPSpongePlugin plugin) { super(plugin); } @Override - protected ExtendedMessagingService getServiceFor(String messagingType) { + protected InternalMessagingService getServiceFor(String messagingType) { if (messagingType.equals("bungee")) { - BungeeMessagingService bungeeMessaging = new BungeeMessagingService(getPlugin()); - bungeeMessaging.init(); - return bungeeMessaging; + try { + return new LuckPermsMessagingService(getPlugin(), new BungeeMessengerProvider()); + } catch (Exception e) { + e.printStackTrace(); + } } return super.getServiceFor(messagingType); } + + private class BungeeMessengerProvider implements MessengerProvider { + + @Nonnull + @Override + public String getName() { + return "Bungee"; + } + + @Nonnull + @Override + public Messenger obtain(@Nonnull IncomingMessageConsumer incomingMessageConsumer) { + BungeeMessenger bungeeMessaging = new BungeeMessenger(getPlugin(), incomingMessageConsumer); + bungeeMessaging.init(); + return bungeeMessaging; + } + } + }