Dispatch log entries via the messaging service

This commit is contained in:
Luck 2017-08-20 13:32:52 +02:00
parent f0ad40825b
commit ae8be97db7
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
29 changed files with 696 additions and 101 deletions

View File

@ -1,3 +1,28 @@
/*
* 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;
import me.lucko.luckperms.api.caching.MetaContexts;

View File

@ -44,4 +44,31 @@ public interface LogBroadcastEvent extends LuckPermsEvent, Cancellable {
@Nonnull
LogEntry getEntry();
/**
* Gets where the log entry originated from.
*
* @return the origin of the log
* @since 3.3
*/
@Nonnull
Origin getOrigin();
/**
* Represents where a log entry is from
*
* @since 3.3
*/
enum Origin {
/**
* Represents a log entry which originated from the current server instance
*/
LOCAL,
/**
* Represents a log entry which was sent to this server via the messaging service
*/
REMOTE
}
}

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.api.event.log;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.api.event.Cancellable;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import java.util.UUID;
import javax.annotation.Nonnull;
/**
* Called when a log is about to be published to the network via the MessagingService
*
* @since 3.3
*/
public interface LogNetworkPublishEvent extends LuckPermsEvent, Cancellable {
/**
* Gets the ID of the log entry being published
*
* @return the id of the log entry being published
*/
@Nonnull
UUID getLogId();
/**
* Gets the log entry to be published
*
* @return the log entry to be published
*/
@Nonnull
LogEntry getEntry();
}

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.event.log;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import java.util.UUID;
import javax.annotation.Nonnull;
/**
* Called when a log entry is received via the MessagingService
*
* @since 3.3
*/
public interface LogReceiveEvent extends LuckPermsEvent {
/**
* Gets the ID of the log entry being received
*
* @return the id of the log entry being received
*/
@Nonnull
UUID getLogId();
/**
* Gets the log entry being received
*
* @return the log entry being received
*/
@Nonnull
LogEntry getEntry();
}

View File

@ -33,7 +33,7 @@ import java.util.UUID;
import javax.annotation.Nonnull;
/**
* Called before a network sync task runs
* Called before a received network sync task runs
*/
public interface PreNetworkSyncEvent extends LuckPermsEvent, Cancellable {

View File

@ -43,6 +43,7 @@ import me.lucko.luckperms.bukkit.model.LPPermissible;
import me.lucko.luckperms.bukkit.processors.ChildPermissionProvider;
import me.lucko.luckperms.bukkit.processors.DefaultsProvider;
import me.lucko.luckperms.bukkit.vault.VaultHookManager;
import me.lucko.luckperms.common.actionlog.LogDispatcher;
import me.lucko.luckperms.common.api.ApiHandler;
import me.lucko.luckperms.common.api.ApiProvider;
import me.lucko.luckperms.common.buffers.BufferedRequest;
@ -109,8 +110,7 @@ import java.util.stream.Collectors;
@Getter
public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
private Set<UUID> ignoringLogs;
private Set<UUID> uniqueConnections;
private long startTime;
private LPBukkitScheduler scheduler;
private BukkitCommand commandManager;
@ -139,6 +139,8 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
private VerboseHandler verboseHandler;
private BukkitSenderFactory senderFactory;
private PermissionVault permissionVault;
private LogDispatcher logDispatcher;
private Set<UUID> uniqueConnections = ConcurrentHashMap.newKeySet();
@Override
public void onLoad() {
@ -182,11 +184,9 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
private void enable() {
startTime = System.currentTimeMillis();
LuckPermsPlugin.sendStartupBanner(getConsoleSender(), this);
ignoringLogs = ConcurrentHashMap.newKeySet();
uniqueConnections = ConcurrentHashMap.newKeySet();
verboseHandler = new VerboseHandler(scheduler.getAsyncBukkitExecutor(), getVersion());
permissionVault = new PermissionVault(scheduler.getAsyncBukkitExecutor());
verboseHandler = new VerboseHandler(scheduler.asyncBukkit(), getVersion());
permissionVault = new PermissionVault(scheduler.asyncBukkit());
logDispatcher = new LogDispatcher(this);
getLog().info("Loading configuration...");
configuration = new BukkitConfig(this);
@ -448,7 +448,6 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
HandlerList.unregisterAll(this);
// Null everything
ignoringLogs = null;
vaultHookManager = null;
configuration = null;
userManager = null;
@ -472,6 +471,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
verboseHandler = null;
senderFactory = null;
permissionVault = null;
logDispatcher = null;
}
public void tryVaultHook(boolean force) {

View File

@ -27,6 +27,7 @@ package me.lucko.luckperms.bukkit;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import me.lucko.luckperms.common.plugin.LuckPermsScheduler;
@ -43,10 +44,16 @@ public class LPBukkitScheduler implements LuckPermsScheduler {
private final LPBukkitPlugin plugin;
@Getter
private ExecutorService asyncLpExecutor;
@Accessors(fluent = true)
private ExecutorService asyncLp;
@Getter
private Executor asyncBukkitExecutor;
private Executor syncExecutor;
@Accessors(fluent = true)
private Executor asyncBukkit;
@Getter
@Accessors(fluent = true)
private Executor sync;
@Getter
@Setter
@ -57,19 +64,14 @@ public class LPBukkitScheduler implements LuckPermsScheduler {
public LPBukkitScheduler(LPBukkitPlugin plugin) {
this.plugin = plugin;
this.asyncLpExecutor = Executors.newCachedThreadPool();
this.asyncBukkitExecutor = r -> plugin.getServer().getScheduler().runTaskAsynchronously(plugin, r);
this.syncExecutor = r -> plugin.getServer().getScheduler().runTask(plugin, r);
this.asyncLp = Executors.newCachedThreadPool();
this.asyncBukkit = r -> plugin.getServer().getScheduler().runTaskAsynchronously(plugin, r);
this.sync = r -> plugin.getServer().getScheduler().runTask(plugin, r);
}
@Override
public Executor async() {
return useBukkitAsync ? asyncBukkitExecutor : asyncLpExecutor;
}
@Override
public Executor sync() {
return syncExecutor;
return useBukkitAsync ? asyncBukkit : asyncLp;
}
@Override
@ -108,9 +110,9 @@ public class LPBukkitScheduler implements LuckPermsScheduler {
public void shutdown() {
tasks.forEach(BukkitTask::cancel);
// wait for executor
asyncLpExecutor.shutdown();
asyncLp.shutdown();
try {
asyncLpExecutor.awaitTermination(30, TimeUnit.SECONDS);
asyncLp.awaitTermination(30, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}

View File

@ -328,6 +328,16 @@ messaging-service: none
# If LuckPerms should automatically push updates after a change has been made with a command.
auto-push-updates: true
# If LuckPerms should push logging entries to connected servers via the messaging service.
push-log-entries: true
# If LuckPerms should broadcast received logging entries to players on this platform.
#
# If you have LuckPerms installed on your backend servers as well as a BungeeCord proxy, you should
# set this option to false on either your backends or your proxies, to avoid players being messaged
# twice about log entries.
broadcast-received-log-entries: true
# Settings for Redis.
# Port 6379 is used by default; set address to "host:port" if differs
redis:

View File

@ -37,6 +37,7 @@ import me.lucko.luckperms.bungee.contexts.BackendServerCalculator;
import me.lucko.luckperms.bungee.messaging.BungeeMessagingService;
import me.lucko.luckperms.bungee.messaging.RedisBungeeMessagingService;
import me.lucko.luckperms.bungee.util.RedisBungeeUtil;
import me.lucko.luckperms.common.actionlog.LogDispatcher;
import me.lucko.luckperms.common.api.ApiHandler;
import me.lucko.luckperms.common.api.ApiProvider;
import me.lucko.luckperms.common.buffers.BufferedRequest;
@ -93,8 +94,7 @@ import java.util.stream.Collectors;
@Getter
public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
private final Set<UUID> ignoringLogs = ConcurrentHashMap.newKeySet();
private Set<UUID> uniqueConnections = ConcurrentHashMap.newKeySet();
private long startTime;
private LuckPermsScheduler scheduler;
private CommandManager commandManager;
@ -116,6 +116,8 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
private VerboseHandler verboseHandler;
private BungeeSenderFactory senderFactory;
private PermissionVault permissionVault;
private LogDispatcher logDispatcher;
private Set<UUID> uniqueConnections = ConcurrentHashMap.newKeySet();
@Override
public void onLoad() {
@ -134,6 +136,7 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
LuckPermsPlugin.sendStartupBanner(getConsoleSender(), this);
verboseHandler = new VerboseHandler(scheduler.async(), getVersion());
permissionVault = new PermissionVault(scheduler.async());
logDispatcher = new LogDispatcher(this);
getLog().info("Loading configuration...");
configuration = new BungeeConfig(this);

View File

@ -89,7 +89,7 @@ public class BungeeMessagingService extends AbstractMessagingService implements
onMessage(e.getTag(), msg, u -> {
// Forward to other servers
plugin.doAsync(() -> sendMessage(CHANNEL, "update:" + u.toString()));
plugin.doAsync(() -> sendMessage(CHANNEL, u));
});
}
}

View File

@ -263,6 +263,16 @@ messaging-service: none
# If LuckPerms should automatically push updates after a change has been made with a command.
auto-push-updates: true
# If LuckPerms should push logging entries to connected servers via the messaging service.
push-log-entries: true
# If LuckPerms should broadcast received logging entries to players on this platform.
#
# If you have LuckPerms installed on your backend servers as well as a BungeeCord proxy, you should
# set this option to false on either your backends or your proxies, to avoid players being messaged
# twice about log entries.
broadcast-received-log-entries: false
# Settings for Redis.
# Port 6379 is used by default; set address to "host:port" if differs
redis:

View File

@ -25,11 +25,12 @@
package me.lucko.luckperms.common.actionlog;
import com.google.common.collect.Maps;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.constants.CommandPermission;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.model.Track;
@ -37,7 +38,8 @@ import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.utils.DateUtil;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* An extended version of {@link LogEntry}, with helper methods for
@ -52,36 +54,41 @@ public class ExtendedLogEntry extends LogEntry {
return (ExtendedLogEntry) super.copy();
}
public void submit(LuckPermsPlugin plugin) {
submit(plugin, null);
public void submit(LuckPermsPlugin plugin, Sender sender) {
plugin.getLogDispatcher().dispatch(this, sender);
}
public void submit(LuckPermsPlugin plugin, Sender sender) {
if (!plugin.getApiProvider().getEventFactory().handleLogPublish(false, this)) {
plugin.getStorage().logAction(this);
public static JsonObject serializeWithId(UUID id, LogEntry entry) {
JsonObject data = new JsonObject();
data.add("id", new JsonPrimitive(id.toString()));
data.add("actor", new JsonPrimitive(entry.getActor().toString()));
data.add("actorName", new JsonPrimitive(entry.getActorName()));
data.add("type", new JsonPrimitive(entry.getEntryType().name()));
if (entry.getActed() != null) {
data.add("acted", new JsonPrimitive(entry.getActed().toString()));
}
data.add("actedName", new JsonPrimitive(entry.getActedName()));
data.add("action", new JsonPrimitive(entry.getAction()));
if (plugin.getApiProvider().getEventFactory().handleLogBroadcast(!plugin.getConfiguration().get(ConfigKeys.LOG_NOTIFY), this)) {
return;
return data;
}
public static Map.Entry<UUID, LogEntry> deserialize(JsonObject object) {
LogEntry.LogEntryBuilder builder = LogEntry.builder();
UUID id = UUID.fromString(object.get("id").getAsString());
builder.actor(UUID.fromString(object.get("actor").getAsString()));
builder.actorName(object.get("actorName").getAsString());
builder.entryType(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());
final String msg = super.getFormatted();
List<Sender> senders = plugin.getOnlineSenders();
senders.add(plugin.getConsoleSender());
if (sender == null) {
senders.stream()
.filter(CommandPermission.LOG_NOTIFY::isAuthorized)
.filter(s -> !plugin.getIgnoringLogs().contains(s.getUuid()))
.forEach(s -> Message.LOG.send(s, msg));
} else {
senders.stream()
.filter(CommandPermission.LOG_NOTIFY::isAuthorized)
.filter(s -> !plugin.getIgnoringLogs().contains(s.getUuid()))
.filter(s -> !s.getUuid().equals(sender.getUuid()))
.forEach(s -> Message.LOG.send(s, msg));
}
return Maps.immutableEntry(id, builder.build());
}
public static class ExtendedLogEntryBuilder extends AbstractLogEntryBuilder<ExtendedLogEntry, ExtendedLogEntryBuilder> {

View File

@ -0,0 +1,88 @@
/*
* 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.actionlog;
import lombok.RequiredArgsConstructor;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.api.event.log.LogBroadcastEvent;
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.constants.CommandPermission;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.messaging.InternalMessagingService;
import me.lucko.luckperms.common.messaging.NoopMessagingService;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import java.util.List;
@RequiredArgsConstructor
public class LogDispatcher {
private final LuckPermsPlugin plugin;
public void dispatch(LogEntry entry, Sender sender) {
if (!plugin.getApiProvider().getEventFactory().handleLogPublish(false, entry)) {
plugin.getStorage().logAction(entry);
}
InternalMessagingService messagingService = plugin.getMessagingService();
if (!sender.isImport() && !(messagingService instanceof NoopMessagingService)) {
messagingService.pushLog(entry);
}
if (!plugin.getApiProvider().getEventFactory().handleLogBroadcast(!plugin.getConfiguration().get(ConfigKeys.LOG_NOTIFY), entry, LogBroadcastEvent.Origin.LOCAL)) {
final String msg = entry.getFormatted();
List<Sender> senders = plugin.getOnlineSenders();
senders.add(plugin.getConsoleSender());
senders.stream()
.filter(CommandPermission.LOG_NOTIFY::isAuthorized)
.filter(s -> !LogNotify.isIgnoring(plugin, s.getUuid()))
.filter(s -> !s.getUuid().equals(sender.getUuid()))
.forEach(s -> Message.LOG.send(s, msg));
}
}
public void dispatchFromRemote(LogEntry entry) {
if (!plugin.getConfiguration().get(ConfigKeys.BROADCAST_RECEIVED_LOG_ENTRIES)) {
return;
}
if (!plugin.getApiProvider().getEventFactory().handleLogBroadcast(!plugin.getConfiguration().get(ConfigKeys.LOG_NOTIFY), entry, LogBroadcastEvent.Origin.REMOTE)) {
final String msg = entry.getFormatted();
List<Sender> senders = plugin.getOnlineSenders();
senders.add(plugin.getConsoleSender());
senders.stream()
.filter(CommandPermission.LOG_NOTIFY::isAuthorized)
.filter(s -> !LogNotify.isIgnoring(plugin, s.getUuid()))
.forEach(s -> Message.LOG.send(s, msg));
}
}
}

View File

@ -25,6 +25,7 @@
package me.lucko.luckperms.common.commands.impl.log;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.common.actionlog.Log;
import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult;
@ -34,11 +35,13 @@ import me.lucko.luckperms.common.constants.CommandPermission;
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.model.User;
import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.utils.Predicates;
import java.util.List;
import java.util.Set;
import java.util.Optional;
import java.util.UUID;
public class LogNotify extends SubCommand<Log> {
@ -46,45 +49,81 @@ public class LogNotify extends SubCommand<Log> {
super(CommandSpec.LOG_NOTIFY.spec(locale), "notify", CommandPermission.LOG_NOTIFY, Predicates.notInRange(0, 1));
}
public static boolean isIgnoring(LuckPermsPlugin plugin, UUID uuid) {
User user = plugin.getUserManager().getIfLoaded(plugin.getUuidCache().getUUID(uuid));
if (user == null) {
return false;
}
Optional<Node> ret = user.getOwnNodes().stream()
.filter(n -> n.getPermission().equalsIgnoreCase("luckperms.log.notify.ignoring"))
.findFirst();
// if they don't have the perm, they're not ignoring
// if set to false, ignore it, return false
return ret.map(Node::getValue).orElse(false);
}
private static void setIgnoring(LuckPermsPlugin plugin, UUID uuid, boolean state) {
User user = plugin.getUserManager().getIfLoaded(plugin.getUuidCache().getUUID(uuid));
if (user == null) {
return;
}
if (state) {
// add the perm
user.setPermission(NodeFactory.make("luckperms.log.notify.ignoring"));
} else {
// remove the perm
user.removeIf(n -> n.getPermission().equalsIgnoreCase("luckperms.log.notify.ignoring"));
}
plugin.getStorage().force().saveUser(user).join();
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Log log, List<String> args, String label) throws CommandException {
final Set<UUID> ignoring = plugin.getIgnoringLogs();
if (sender.isConsole() || sender.isImport()) {
Message.LOG_NOTIFY_CONSOLE.send(sender);
return CommandResult.SUCCESS;
}
final UUID uuid = sender.getUuid();
if (args.size() == 0) {
if (ignoring.contains(uuid)) {
if (isIgnoring(plugin, uuid)) {
// toggle on
ignoring.remove(uuid);
setIgnoring(plugin, uuid, false);
Message.LOG_NOTIFY_TOGGLE_ON.send(sender);
return CommandResult.SUCCESS;
}
// toggle off
ignoring.add(uuid);
setIgnoring(plugin, uuid, true);
Message.LOG_NOTIFY_TOGGLE_OFF.send(sender);
return CommandResult.SUCCESS;
}
if (args.get(0).equalsIgnoreCase("on")) {
if (!ignoring.contains(uuid)) {
if (!isIgnoring(plugin, uuid)) {
// already on
Message.LOG_NOTIFY_ALREADY_ON.send(sender);
return CommandResult.STATE_ERROR;
}
// toggle on
ignoring.remove(uuid);
setIgnoring(plugin, uuid, false);
Message.LOG_NOTIFY_TOGGLE_ON.send(sender);
return CommandResult.SUCCESS;
}
if (args.get(0).equalsIgnoreCase("off")) {
if (ignoring.contains(uuid)) {
if (isIgnoring(plugin, uuid)) {
// already off
Message.LOG_NOTIFY_ALREADY_OFF.send(sender);
return CommandResult.STATE_ERROR;
}
// toggle off
ignoring.add(uuid);
setIgnoring(plugin, uuid, true);
Message.LOG_NOTIFY_TOGGLE_OFF.send(sender);
return CommandResult.SUCCESS;
}

View File

@ -392,7 +392,7 @@ public class ConfigKeys {
}));
/**
* The name of the messaging service in use, or "none" if not enabled.
* The name of the messaging service in use, or "none" if not enabled
*/
public static final ConfigKey<String> MESSAGING_SERVICE = EnduringKey.wrap(LowercaseStringKey.of("messaging-service", "none"));
@ -401,6 +401,16 @@ public class ConfigKeys {
*/
public static final ConfigKey<Boolean> AUTO_PUSH_UPDATES = EnduringKey.wrap(BooleanKey.of("auto-push-updates", true));
/**
* If LuckPerms should push logging entries to connected servers via the messaging service
*/
public static final ConfigKey<Boolean> PUSH_LOG_ENTRIES = EnduringKey.wrap(BooleanKey.of("push-log-entries", true));
/**
* If LuckPerms should broadcast received logging entries to players on this platform
*/
public static final ConfigKey<Boolean> BROADCAST_RECEIVED_LOG_ENTRIES = EnduringKey.wrap(BooleanKey.of("broadcast-received-log-entries", false));
/**
* If redis messaging is enabled
*/

View File

@ -36,13 +36,16 @@ import me.lucko.luckperms.api.caching.UserData;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.cause.CreationCause;
import me.lucko.luckperms.api.event.cause.DeletionCause;
import me.lucko.luckperms.api.event.log.LogBroadcastEvent;
import me.lucko.luckperms.common.event.impl.EventConfigReload;
import me.lucko.luckperms.common.event.impl.EventGroupCreate;
import me.lucko.luckperms.common.event.impl.EventGroupDelete;
import me.lucko.luckperms.common.event.impl.EventGroupLoad;
import me.lucko.luckperms.common.event.impl.EventGroupLoadAll;
import me.lucko.luckperms.common.event.impl.EventLogBroadcast;
import me.lucko.luckperms.common.event.impl.EventLogNetworkPublish;
import me.lucko.luckperms.common.event.impl.EventLogPublish;
import me.lucko.luckperms.common.event.impl.EventLogReceive;
import me.lucko.luckperms.common.event.impl.EventNodeAdd;
import me.lucko.luckperms.common.event.impl.EventNodeClear;
import me.lucko.luckperms.common.event.impl.EventNodeRemove;
@ -100,9 +103,9 @@ public final class EventFactory {
fireEvent(event);
}
public boolean handleLogBroadcast(boolean initialState, LogEntry entry) {
public boolean handleLogBroadcast(boolean initialState, LogEntry entry, LogBroadcastEvent.Origin origin) {
AtomicBoolean cancel = new AtomicBoolean(initialState);
EventLogBroadcast event = new EventLogBroadcast(cancel, entry);
EventLogBroadcast event = new EventLogBroadcast(cancel, entry, origin);
eventBus.fireEvent(event);
return cancel.get();
}
@ -114,6 +117,18 @@ public final class EventFactory {
return cancel.get();
}
public boolean handleLogNetworkPublish(boolean initialState, UUID id, LogEntry entry) {
AtomicBoolean cancel = new AtomicBoolean(initialState);
EventLogNetworkPublish event = new EventLogNetworkPublish(cancel, id, entry);
eventBus.fireEvent(event);
return cancel.get();
}
public void handleLogReceive(UUID id, LogEntry entry) {
EventLogReceive event = new EventLogReceive(id, entry);
fireEvent(event);
}
public void handleNodeAdd(Node node, PermissionHolder target, Collection<Node> before, Collection<Node> after) {
EventNodeAdd event = new EventNodeAdd(node, target.getDelegate(), ImmutableSet.copyOf(before), ImmutableSet.copyOf(after));
fireEvent(event);

View File

@ -42,5 +42,6 @@ public class EventLogBroadcast extends AbstractEvent implements LogBroadcastEven
private final AtomicBoolean cancellationState;
private final LogEntry entry;
private final Origin origin;
}

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.event.impl;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.api.event.log.LogNetworkPublishEvent;
import me.lucko.luckperms.common.event.AbstractEvent;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
@Getter
@ToString
@AllArgsConstructor
public class EventLogNetworkPublish extends AbstractEvent implements LogNetworkPublishEvent {
private final AtomicBoolean cancellationState;
private final UUID logId;
private final LogEntry entry;
}

View File

@ -0,0 +1,46 @@
/*
* 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.event.impl;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.api.event.log.LogReceiveEvent;
import me.lucko.luckperms.common.event.AbstractEvent;
import java.util.UUID;
@Getter
@ToString
@AllArgsConstructor
public class EventLogReceive extends AbstractEvent implements LogReceiveEvent {
private final UUID logId;
private final LogEntry entry;
}

View File

@ -364,6 +364,7 @@ public enum Message {
LOG_NO_ENTRIES("&bNo log entries to show.", true),
LOG_ENTRY("&b#{0} -> &8(&7{1} ago&8) {2}", true),
LOG_NOTIFY_CONSOLE("&cCannot toggle notifications for console.", true),
LOG_NOTIFY_TOGGLE_ON("&aEnabled&b logging output.", true),
LOG_NOTIFY_TOGGLE_OFF("&cDisabled&b logging output.", true),
LOG_NOTIFY_ALREADY_ON("You are already receiving notifications.", true),

View File

@ -28,11 +28,18 @@ package me.lucko.luckperms.common.messaging;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import com.google.gson.Gson;
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.plugin.LuckPermsPlugin;
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;
@ -50,7 +57,8 @@ public abstract class AbstractMessagingService implements InternalMessagingServi
@Getter
private final String name;
private final Set<UUID> receivedMsgs = Collections.synchronizedSet(new HashSet<>());
private final Set<UUID> receivedMessages = Collections.synchronizedSet(new HashSet<>());
private final Gson gson = new Gson();
@Getter
private final BufferedRequest<Void> updateBuffer = new BufferedRequest<Void>(10000L, r -> getPlugin().doAsync(r)) {
@ -63,54 +71,91 @@ public abstract class AbstractMessagingService implements InternalMessagingServi
protected abstract void sendMessage(String channel, String message);
protected void onMessage(String channel, String msg, Consumer<UUID> callback) {
protected void onMessage(String channel, String msg, Consumer<String> callback) {
if (!channel.equals(CHANNEL)) {
return;
}
UUID uuid = parseUpdateMessage(msg);
if (uuid == null) {
return;
if (msg.startsWith("update:") && msg.length() > "update:".length()) {
UUID uuid = parseUpdateMessage(msg);
if (uuid == null) {
return;
}
if (!receivedMessages.add(uuid)) {
return;
}
plugin.getLog().info("[" + name + " Messaging] Received update ping with id: " + uuid.toString());
if (plugin.getApiProvider().getEventFactory().handleNetworkPreSync(false, uuid)) {
return;
}
plugin.getUpdateTaskBuffer().request();
if (callback != null) {
callback.accept(msg);
}
} else if (msg.startsWith("log:") && msg.length() > "log:".length()) {
String logData = msg.substring("log:".length());
Map.Entry<UUID, LogEntry> entry = null;
try {
entry = ExtendedLogEntry.deserialize(gson.fromJson(logData, JsonObject.class));
} catch (Exception e) {
plugin.getLog().warn("Error whilst deserializing log: " + logData);
e.printStackTrace();
}
if (entry == null) {
return;
}
if (!receivedMessages.add(entry.getKey())) {
return;
}
plugin.getApiProvider().getEventFactory().handleLogReceive(entry.getKey(), entry.getValue());
plugin.getLogDispatcher().dispatchFromRemote(entry.getValue());
if (callback != null) {
callback.accept(msg);
}
}
}
if (!receivedMsgs.add(uuid)) {
return;
}
@Override
public void pushLog(LogEntry logEntry) {
plugin.doAsync(() -> {
UUID id = generatePingId();
plugin.getLog().info("[" + name + " Messaging] Received update ping with id: " + uuid.toString());
if (plugin.getApiProvider().getEventFactory().handleLogNetworkPublish(!plugin.getConfiguration().get(ConfigKeys.PUSH_LOG_ENTRIES), id, logEntry)) {
return;
}
if (plugin.getApiProvider().getEventFactory().handleNetworkPreSync(false, uuid)) {
return;
}
plugin.getUpdateTaskBuffer().request();
if (callback != null) {
callback.accept(uuid);
}
plugin.getLog().info("[" + name + " Messaging] Sending log with id: " + id.toString());
sendMessage(CHANNEL, "log:" + gson.toJson(ExtendedLogEntry.serializeWithId(id, logEntry)));
});
}
@Override
public void pushUpdate() {
plugin.doAsync(() -> {
UUID id = generateId();
UUID id = generatePingId();
plugin.getLog().info("[" + name + " Messaging] Sending ping with id: " + id.toString());
sendMessage(CHANNEL, "update:" + id.toString());
});
}
private UUID generateId() {
private UUID generatePingId() {
UUID uuid = UUID.randomUUID();
receivedMsgs.add(uuid);
receivedMessages.add(uuid);
return uuid;
}
private static UUID parseUpdateMessage(String msg) {
if (!msg.startsWith("update:")) {
return null;
}
String requestId = msg.substring("update:".length());
try {
return UUID.fromString(requestId);

View File

@ -25,6 +25,7 @@
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;
@ -49,4 +50,11 @@ public interface InternalMessagingService extends MessagingService {
*/
BufferedRequest<Void> getUpdateBuffer();
/**
* Pushes a log entry to connected servers.
*
* @param logEntry the log entry
*/
void pushLog(LogEntry logEntry);
}

View File

@ -25,6 +25,7 @@
package me.lucko.luckperms.common.messaging;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.common.buffers.BufferedRequest;
public class NoopMessagingService implements InternalMessagingService {
@ -44,6 +45,11 @@ public class NoopMessagingService implements InternalMessagingService {
return null;
}
@Override
public void pushLog(LogEntry logEntry) {
}
@Override
public void pushUpdate() {

View File

@ -28,6 +28,7 @@ package me.lucko.luckperms.common.plugin;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Logger;
import me.lucko.luckperms.api.PlatformType;
import me.lucko.luckperms.common.actionlog.LogDispatcher;
import me.lucko.luckperms.common.api.ApiProvider;
import me.lucko.luckperms.common.buffers.BufferedRequest;
import me.lucko.luckperms.common.caching.handlers.CachedStateManager;
@ -181,6 +182,13 @@ public interface LuckPermsPlugin {
*/
PermissionVault getPermissionVault();
/**
* Gets the log dispatcher running on the platform
*
* @return the log dispatcher
*/
LogDispatcher getLogDispatcher();
/**
* Gets the LuckPerms Scheduler instance
*
@ -380,13 +388,6 @@ public interface LuckPermsPlugin {
return null;
}
/**
* Gets a set of players ignoring logging output
*
* @return a {@link Set} of {@link UUID}s
*/
Set<UUID> getIgnoringLogs();
/**
* Gets the update task buffer of the platform, used for scheduling and running update tasks.
*

View File

@ -1,3 +1,28 @@
/*
* 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.storage.backing.file;
import com.google.common.base.Splitter;

View File

@ -1,3 +1,28 @@
/*
* 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.utils;
import lombok.experimental.UtilityClass;

View File

@ -1,3 +1,28 @@
/*
* 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.verbose;
import lombok.experimental.UtilityClass;

View File

@ -33,6 +33,7 @@ import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.LuckPermsApi;
import me.lucko.luckperms.api.PlatformType;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.common.actionlog.LogDispatcher;
import me.lucko.luckperms.common.api.ApiHandler;
import me.lucko.luckperms.common.api.ApiProvider;
import me.lucko.luckperms.common.backup.ImporterSender;
@ -125,9 +126,6 @@ import java.util.stream.Collectors;
@Plugin(id = "luckperms", name = "LuckPerms", version = VersionData.VERSION, authors = {"Luck"}, description = "A permissions plugin")
public class LPSpongePlugin implements LuckPermsPlugin {
private final Set<UUID> ignoringLogs = ConcurrentHashMap.newKeySet();
private Set<UUID> uniqueConnections = ConcurrentHashMap.newKeySet();
@Inject
private Logger logger;
@ -173,6 +171,8 @@ public class LPSpongePlugin implements LuckPermsPlugin {
private VerboseHandler verboseHandler;
private SpongeSenderFactory senderFactory;
private PermissionVault permissionVault;
private LogDispatcher logDispatcher;
private Set<UUID> uniqueConnections = ConcurrentHashMap.newKeySet();
@Listener(order = Order.FIRST)
public void onEnable(GamePreInitializationEvent event) {
@ -185,6 +185,7 @@ public class LPSpongePlugin implements LuckPermsPlugin {
LuckPermsPlugin.sendStartupBanner(getConsoleSender(), this);
verboseHandler = new VerboseHandler(scheduler.async(), getVersion());
permissionVault = new PermissionVault(scheduler.async());
logDispatcher = new LogDispatcher(this);
timings = new LPTimings(this);
getLog().info("Loading configuration...");

View File

@ -278,6 +278,16 @@ messaging-service="none"
# If LuckPerms should automatically push updates after a change has been made with a command.
auto-push-updates=true
# If LuckPerms should push logging entries to connected servers via the messaging service.
push-log-entries=true
# If LuckPerms should broadcast received logging entries to players on this platform.
#
# If you have LuckPerms installed on your backend servers as well as a BungeeCord proxy, you should
# set this option to false on either your backends or your proxies, to avoid players being messaged
# twice about log entries.
broadcast-received-log-entries=true
# Settings for Redis.
# Port 6379 is used by default; set address to "host:port" if differs
redis {