Expose a means to implement the plugin's MessagingService via the API

This commit is contained in:
Luck 2018-01-19 23:35:41 +00:00
parent 612712f015
commit 821dc4ef56
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
38 changed files with 1469 additions and 442 deletions

View File

@ -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<MessagingService> getMessagingService();
/**
* Registers a {@link MessengerProvider} for use by the platform.
*
* <p>Note that the mere action of registering a provider doesn't
* necessarily mean that it will be used.</p>
*
* @param messengerProvider the messenger provider.
* @since 4.1
*/
void registerMessengerProvider(@Nonnull MessengerProvider messengerProvider);
/**
* Gets the {@link ActionLogger}.
*

View File

@ -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.
*
* <p>The standard response by other servers will be to execute a overall
* sync of all live data, equivalent to calling
* {@link LuckPermsApi#runUpdateTask()}.</p>
*
* <p>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.</p>
* immediately. Note that this method will not cause an update to be
* processed on the local server.</p>
*/
void pushUpdate();
/**
* Uses the messaging service to inform other servers about a change to a
* specific user.
*
* <p>The standard response by other servers is undefined, however the
* current implementation will reload the corresponding users data if they
* are online.</p>
*
* <p>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.</p>
*
* @param user the user to push the update for
* @since 4.1
*/
void pushUserUpdate(@Nonnull User user);
}

View File

@ -0,0 +1,78 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.
*
* <p>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.</p>
*
* <p>The implementation will usually return <code>false</code> if a message
* with the same ping id has already been processed.</p>
*
* @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.
*
* <p>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.</p>
*
* <p>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.</p>
*
* <p>The implementation will usually return <code>false</code> if a message
* with the same ping id has already been processed.</p>
*
* @param encodedString the encoded string
* @return true if the message was accepted by the plugin
*/
boolean consumeIncomingMessageAsString(@Nonnull String encodedString);
}

View File

@ -0,0 +1,58 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.
*
* <p>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.</p>
*
* <p>This call is always made async.</p>
*
* @param outgoingMessage the outgoing message
*/
void sendOutgoingMessage(@Nonnull OutgoingMessage outgoingMessage);
@Override
default void close() {
}
}

View File

@ -0,0 +1,65 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.
*
* <p>Users wishing to provide their own implementation for the plugins
* "Messaging Service" should implement and register this interface.</p>
*
* @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}.
*
* <p>As the agent should pass incoming messages to the given consumer,
* this method should always return a new object.</p>
*
* @param incomingMessageConsumer the consumer the new instance should pass
* incoming messages to
* @return a new messenger agent instance
*/
@Nonnull
Messenger obtain(@Nonnull IncomingMessageConsumer incomingMessageConsumer);
}

View File

@ -0,0 +1,52 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.
*
* <p>This ID is used to ensure a single server instance doesn't process
* the same message twice.</p>
*
* @return the id of the message
*/
@Nonnull
UUID getId();
}

View File

@ -0,0 +1,62 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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}.
*
* <p>Outgoing messages are ones which have been generated by this instance.
* (in other words, they are implemented by LuckPerms)</p>
*
* <p>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.</p>
*
* @since 4.1
*/
public interface OutgoingMessage extends Message {
/**
* Gets an encoded string form of this message.
*
* <p>The format of this string is likely to change between versions and
* should not be depended on.</p>
*
* <p>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)}.</p>
*
* @return an encoded string form of the message
*/
@Nonnull
String asEncodedString();
}

View File

@ -0,0 +1,50 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.
*
* <p>Used to dispatch live log updates to other servers.</p>
*
* @since 4.1
*/
public interface LogMessage extends Message {
/**
* Gets the log entry being sent
*
* @return the log entry
*/
@Nonnull
LogEntry getLogEntry();
}

View File

@ -0,0 +1,39 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.
*
* <p>Used to notify other servers of general changes.</p>
*
* @since 4.1
*/
public interface UpdateMessage extends Message {
}

View File

@ -0,0 +1,51 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.
*
* <p>Used to notify other servers of a change to a specific user.</p>
*
* @since 4.1
*/
public interface UserUpdateMessage extends Message {
/**
* Gets the user the message is for.
*
* @return the user
*/
@Nonnull
UUID getUser();
}

View File

@ -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<ExtendedMessagingService> getMessagingService() {
public Optional<InternalMessagingService> getMessagingService() {
return Optional.ofNullable(this.messagingService);
}
@Override
public void setMessagingService(InternalMessagingService messagingService) {
if (this.messagingService == null) {
this.messagingService = messagingService;
}
}
@Override
public Optional<FileWatcher> getFileWatcher() {
return Optional.ofNullable(this.fileWatcher);

View File

@ -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<LPBukkitPlugin> {
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;
}
}
}

View File

@ -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<? extends Player> players = BungeeMessagingService.this.plugin.getServer().getOnlinePlayers();
Collection<? extends Player> 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);
}
}

View File

@ -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();
}

View File

@ -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<ExtendedMessagingService> getMessagingService() {
public Optional<InternalMessagingService> getMessagingService() {
return Optional.ofNullable(this.messagingService);
}
@Override
public void setMessagingService(InternalMessagingService messagingService) {
if (this.messagingService == null) {
this.messagingService = messagingService;
}
}
@Override
public Optional<FileWatcher> getFileWatcher() {
return Optional.ofNullable(this.fileWatcher);

View File

@ -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<LPBungeePlugin> {
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;
}
}
}

View File

@ -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);
}
});
}
}
}

View File

@ -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());
}
}

View File

@ -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<String, ExtendedLogEntry> 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());
}
}

View File

@ -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<ExtendedMessagingService> messagingService = this.plugin.getMessagingService();
Optional<InternalMessagingService> messagingService = this.plugin.getMessagingService();
if (!sender.isImport() && messagingService.isPresent()) {
messagingService.get().pushLog(entry);
}

View File

@ -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<MessagingService> 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

View File

@ -0,0 +1,59 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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));
}
}

View File

@ -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<T> extends Command<T, Void> {
}
if (!sender.isImport()) {
Optional<ExtendedMessagingService> messagingService = plugin.getMessagingService();
Optional<InternalMessagingService> 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<T> extends Command<T, Void> {
}
if (!sender.isImport()) {
Optional<ExtendedMessagingService> messagingService = plugin.getMessagingService();
Optional<InternalMessagingService> 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<T> extends Command<T, Void> {
}
if (!sender.isImport()) {
Optional<ExtendedMessagingService> messagingService = plugin.getMessagingService();
Optional<InternalMessagingService> messagingService = plugin.getMessagingService();
if (messagingService.isPresent() && plugin.getConfiguration().get(ConfigKeys.AUTO_PUSH_UPDATES)) {
messagingService.get().getUpdateBuffer().request();
}

View File

@ -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(),

View File

@ -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<ExtendedMessagingService> messagingService = plugin.getMessagingService();
Optional<InternalMessagingService> messagingService = plugin.getMessagingService();
if (!messagingService.isPresent()) {
Message.UPDATE_TASK_PUSH_FAILURE_NOT_SETUP.send(sender);
return CommandResult.FAILURE;

View File

@ -1,271 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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<UUID> receivedMessages;
private final Gson gson;
private final BufferedRequest<Void> 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<Void> getUpdateBuffer() {
return this.updateBuffer;
}
protected abstract void sendMessage(String message);
protected void onMessage(String msg, Consumer<String> 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<UUID, UUID> 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<String, ExtendedLogEntry> 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<UUID, UUID> 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<Void> {
public PushUpdateBuffer(LuckPermsPlugin plugin) {
super(2000L, 200L, plugin.getScheduler().async());
}
@Override
protected Void perform() {
pushUpdate();
return null;
}
}
}

View File

@ -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<Void> getUpdateBuffer();
/**
* Uses the messaging service to inform other servers about a general
* change.
*/
void pushUpdate();
/**
* Pushes an update for a specific user.
*

View File

@ -0,0 +1,209 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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<UUID> receivedMessages;
private final BufferedRequest<Void> 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<Void> 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<Void> {
public PushUpdateBuffer(LuckPermsPlugin plugin) {
super(2000L, 200L, plugin.getScheduler().async());
}
@Override
protected Void perform() {
pushUpdate();
return null;
}
}
}

View File

@ -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<P extends LuckPermsPlugin> {
private final P plugin;
@ -39,7 +45,7 @@ public class MessagingFactory<P extends LuckPermsPlugin> {
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<P extends LuckPermsPlugin> {
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<P extends LuckPermsPlugin> {
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<P extends LuckPermsPlugin> {
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;
}
}
}

View File

@ -0,0 +1,48 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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;
}
}

View File

@ -0,0 +1,138 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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());
}
}

View File

@ -0,0 +1,74 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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;
}
}
}

View File

@ -0,0 +1,87 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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;
}
}
}

View File

@ -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);
}
}

View File

@ -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<ExtendedMessagingService> getMessagingService();
Optional<InternalMessagingService> getMessagingService();
/**
* Sets the messaging service.
*
* @param service the service
*/
void setMessagingService(InternalMessagingService service);
/**
* Gets a wrapped logger instance for the platform.

View File

@ -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<ExtendedMessagingService> getMessagingService() {
public Optional<InternalMessagingService> getMessagingService() {
return Optional.ofNullable(this.messagingService);
}
@Override
public void setMessagingService(InternalMessagingService messagingService) {
if (this.messagingService == null) {
this.messagingService = messagingService;
}
}
@Override
public Optional<FileWatcher> getFileWatcher() {
return Optional.ofNullable(this.fileWatcher);

View File

@ -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);
}
}

View File

@ -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<LPSpongePlugin> {
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;
}
}
}