Cleanup verbose handler & only send sponge OP command notification if the sender has permission

This commit is contained in:
Luck 2017-10-16 18:55:17 +01:00
parent 04d5310c04
commit aa0be40124
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
8 changed files with 117 additions and 105 deletions

View File

@ -327,8 +327,8 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
started = false;
defaultsProvider.close();
permissionVault.setShutdown(true);
verboseHandler.setShutdown(true);
permissionVault.shutdown();
verboseHandler.shutdown();
for (Player player : getServer().getOnlinePlayers()) {
try {

View File

@ -212,8 +212,8 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
@Override
public void onDisable() {
permissionVault.setShutdown(true);
verboseHandler.setShutdown(true);
permissionVault.shutdown();
verboseHandler.shutdown();
getLog().info("Closing storage...");
storage.shutdown();

View File

@ -27,7 +27,6 @@ package me.lucko.luckperms.common.treeview;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
@ -55,7 +54,7 @@ public class PermissionVault implements Runnable {
// a queue of permission strings to be processed by the tree
private final Queue<String> queue;
@Setter
// if the handler should shutdown
private boolean shutdown = false;
public PermissionVault(Executor executor) {
@ -114,4 +113,8 @@ public class PermissionVault implements Runnable {
}
}
public void shutdown() {
shutdown = true;
}
}

View File

@ -25,8 +25,6 @@
package me.lucko.luckperms.common.verbose;
import lombok.Setter;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.commands.sender.Sender;
@ -54,7 +52,6 @@ public class VerboseHandler implements Runnable {
private boolean listening = false;
// if the handler should shutdown
@Setter
private boolean shutdown = false;
public VerboseHandler(Executor executor, String pluginVersion) {
@ -98,8 +95,8 @@ public class VerboseHandler implements Runnable {
* @param notify if the sender should be notified in chat on each check
*/
public void registerListener(Sender sender, String filter, boolean notify) {
listening = true;
listeners.put(sender.getUuid(), new VerboseListener(pluginVersion, sender, filter, notify));
listening = true;
}
/**
@ -112,33 +109,29 @@ public class VerboseHandler implements Runnable {
// immediately flush, so the listener gets all current data
flush();
VerboseListener ret = listeners.remove(uuid);
// stop listening if there are no listeners left
if (listeners.isEmpty()) {
listening = false;
}
return ret;
return listeners.remove(uuid);
}
@Override
public void run() {
while (true) {
// remove listeners where the sender is no longer valid
listeners.values().removeIf(l -> !l.getNotifiedSender().isValid());
if (listeners.isEmpty()) {
listening = false;
}
// handle all checks in the queue
flush();
// break the loop if the handler has been shutdown
if (shutdown) {
return;
}
// update listening state
listening = !listeners.isEmpty();
try {
Thread.sleep(200);
Thread.sleep(100);
} catch (InterruptedException ignored) {}
}
}
@ -153,4 +146,8 @@ public class VerboseHandler implements Runnable {
}
}
}
public void shutdown() {
shutdown = true;
}
}

View File

@ -49,6 +49,7 @@ import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.stream.Collectors;
/**
@ -96,16 +97,23 @@ public class VerboseListener {
* @param data the data to process
*/
public void acceptData(CheckData data) {
// increment handled counter
counter.incrementAndGet();
// check if the data passes our filters
if (!VerboseFilter.passesFilter(data, filter)) {
return;
}
// increment the matched filter
matchedCounter.incrementAndGet();
// record the check, if we have space for it
if (results.size() < DATA_TRUNCATION) {
results.add(data);
}
// handle notifications
if (notify) {
StringBuilder msgContent = new StringBuilder();
@ -124,49 +132,25 @@ public class VerboseListener {
.append(data.getResult().name().toLowerCase());
if (notifiedSender.isConsole()) {
// just send as a raw message
Message.VERBOSE_LOG.send(notifiedSender, msgContent.toString());
} else {
// form a hoverevent from the check trace
TextComponent textComponent = TextUtils.fromLegacy(Message.VERBOSE_LOG.asString(notifiedSender.getPlatform().getLocaleManager(), msgContent.toString()));
// build the text
List<String> hover = new ArrayList<>();
hover.add("&bOrigin: &2" + data.getCheckOrigin().name());
hover.add("&bContext: &r" + Util.contextSetToString(data.getCheckContext()));
hover.add("&bTrace: &r");
StackTraceElement[] checkTrace = data.getCheckTrace();
// how many lines have been printed
int count = 0;
// if we're printing elements yet
boolean printing = false;
for (StackTraceElement e : checkTrace) {
// start printing when we escape LP internals code
boolean shouldStartPrinting = !printing && (
(data.getCheckOrigin() == CheckOrigin.API || data.getCheckOrigin() == CheckOrigin.INTERNAL) || (
!e.getClassName().startsWith("me.lucko.luckperms.") &&
// all used within the checking impl somewhere
!e.getClassName().equals("java.util.concurrent.CompletableFuture") &&
!e.getClassName().startsWith("com.github.benmanes.caffeine") &&
!e.getClassName().equals("java.util.concurrent.ConcurrentHashMap")
)
);
if (shouldStartPrinting) {
printing = true;
}
if (!printing) continue;
if (count >= 15) break;
hover.add("&7" + e.getClassName() + "." + e.getMethodName() + (e.getLineNumber() >= 0 ? ":" + e.getLineNumber() : ""));
count++;
}
if (checkTrace.length > 15) {
int remain = checkTrace.length - 15;
hover.add("&f... and " + remain + " more");
int overflow = readStack(data, 15, e -> hover.add("&7" + e.getClassName() + "." + e.getMethodName() + (e.getLineNumber() >= 0 ? ":" + e.getLineNumber() : "")));
if (overflow != 0) {
hover.add("&f... and " + overflow + " more");
}
// send the message
HoverEvent e = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(TextUtils.joinNewline(hover.stream()), Constants.FORMAT_CHAR));
TextComponent msg = textComponent.toBuilder().applyDeep(comp -> comp.hoverEvent(e)).build();
notifiedSender.sendMessage(msg);
@ -183,6 +167,8 @@ public class VerboseListener {
* @see PasteUtils#paste(String, List)
*/
public String uploadPasteData(boolean showTraces, boolean attachRaw) {
// retrieve variables
long now = System.currentTimeMillis();
String startDate = DATE_FORMAT.format(new Date(startTime));
String endDate = DATE_FORMAT.format(new Date(now));
@ -196,6 +182,7 @@ public class VerboseListener {
filter = "`" + filter + "`";
}
// start building the message output
ImmutableList.Builder<String> prettyOutput = ImmutableList.<String>builder()
.add("## Verbose Checking Output")
.add("#### This file was automatically generated by [LuckPerms](https://github.com/lucko/LuckPerms) " + pluginVersion)
@ -212,98 +199,123 @@ public class VerboseListener {
.add("| Include traces | " + showTraces + " |")
.add("");
// warn if data was truncated
if (matchedCounter.get() > results.size()) {
prettyOutput.add("**WARN:** Result set exceeded max size of " + DATA_TRUNCATION + ". The output below was truncated to " + DATA_TRUNCATION + " entries.");
prettyOutput.add("");
}
// explain why some traces may be missing
if (showTraces && results.size() > TRACE_DATA_TRUNCATION) {
prettyOutput.add("**WARN:** Result set exceeded size of " + TRACE_DATA_TRUNCATION + ". The traced output below was truncated to " + TRACE_DATA_TRUNCATION + " entries. ");
prettyOutput.add("Either refine the query using a more specific filter, or disable tracing by adding '--slim' to the end of the paste command.");
prettyOutput.add("");
}
// print the format of the output
prettyOutput.add("### Output")
.add("Format: `<checked>` `<permission>` `<value>`")
.add("")
.add("___")
.add("");
// build the csv output - will only be appended to if this is enabled.
ImmutableList.Builder<String> csvOutput = ImmutableList.<String>builder()
.add("User,Permission,Result");
// how many instances have been printed so far
AtomicInteger printedCount = new AtomicInteger(0);
results.forEach(c -> {
for (CheckData c : results) {
if (!showTraces) {
// if traces aren't being shown, just append using raw markdown
prettyOutput.add("`" + c.getCheckTarget() + "` - " + c.getPermission() + " - " + getTristateSymbol(c.getResult()) + " ");
} else if (printedCount.incrementAndGet() > TRACE_DATA_TRUNCATION) {
// if we've gone over the trace truncation, just append the raw info.
// we still have to use html, as the rest of this section is still using it.
prettyOutput.add("<br><code>" + c.getCheckTarget() + "</code> - " + c.getPermission() + " - " + getTristateSymbol(c.getResult()));
} else {
// append the full output.
prettyOutput.add("<details><summary><code>" + c.getCheckTarget() + "</code> - " + c.getPermission() + " - " + getTristateSymbol(c.getResult()) + "</summary><p>");
// append the spoiler text
prettyOutput.add("<br><b>Origin:</b> <code>" + c.getCheckOrigin().name() + "</code>");
prettyOutput.add("<br><b>Context:</b> <code>" + Util.stripColor(Util.contextSetToString(c.getCheckContext())) + "</code>");
prettyOutput.add("<br><b>Trace:</b><pre>");
// add trace
StackTraceElement[] checkTrace = c.getCheckTrace();
// how many lines have been printed
int count = 0;
// if we're printing elements yet
boolean printing = false;
for (StackTraceElement e : checkTrace) {
// start printing when we escape LP internals code
boolean shouldStartPrinting = !printing && (
(c.getCheckOrigin() == CheckOrigin.API || c.getCheckOrigin() == CheckOrigin.INTERNAL) || (
!e.getClassName().startsWith("me.lucko.luckperms.") &&
// all used within the checking impl somewhere
!e.getClassName().equals("java.util.concurrent.CompletableFuture") &&
!e.getClassName().startsWith("com.github.benmanes.caffeine") &&
!e.getClassName().equals("java.util.concurrent.ConcurrentHashMap")
)
);
if (shouldStartPrinting) {
printing = true;
}
if (!printing) continue;
if (count >= 30) break;
prettyOutput.add(e.getClassName() + "." + e.getMethodName() + (e.getLineNumber() >= 0 ? ":" + e.getLineNumber() : ""));
count++;
}
if (checkTrace.length > 30) {
int remain = checkTrace.length - 30;
prettyOutput.add("... and " + remain + " more");
int overflow = readStack(c, 30, e -> prettyOutput.add(e.getClassName() + "." + e.getMethodName() + (e.getLineNumber() >= 0 ? ":" + e.getLineNumber() : "")));
if (overflow != 0) {
prettyOutput.add("... and " + overflow + " more");
}
prettyOutput.add("</pre></p></details>");
}
// if we're including a raw csv output, append that too
if (attachRaw) {
csvOutput.add(escapeCommas(c.getCheckTarget()) + "," + escapeCommas(c.getPermission()) + "," + c.getResult().name().toLowerCase());
}
});
}
results.clear();
List<Map.Entry<String, String>> content;
ImmutableList.Builder<Map.Entry<String, String>> content = ImmutableList.builder();
content.add(Maps.immutableEntry("luckperms-verbose.md", prettyOutput.build().stream().collect(Collectors.joining("\n"))));
if (attachRaw) {
content = ImmutableList.of(
Maps.immutableEntry("luckperms-verbose.md", prettyOutput.build().stream().collect(Collectors.joining("\n"))),
Maps.immutableEntry("raw-data.csv", csvOutput.build().stream().collect(Collectors.joining("\n")))
);
} else {
content = ImmutableList.of(
Maps.immutableEntry("luckperms-verbose.md", prettyOutput.build().stream().collect(Collectors.joining("\n")))
);
content.add(Maps.immutableEntry("raw-data.csv", csvOutput.build().stream().collect(Collectors.joining("\n"))));
}
return PasteUtils.paste("LuckPerms Verbose Checking Output", content);
return PasteUtils.paste("LuckPerms Verbose Checking Output", content.build());
}
/**
* Reads a stack trace from a {@link CheckData} instance.
*
* @param data the data to read from
* @param truncateLength the length when we should stop reading the stack
* @param consumer the element consumer
* @return how many elements were left unread, or 0 if everything was read
*/
private static int readStack(CheckData data, int truncateLength, Consumer<StackTraceElement> consumer) {
StackTraceElement[] stack = data.getCheckTrace();
// how many lines have been printed
int count = 0;
// if we're printing elements yet
boolean printing = false;
for (StackTraceElement e : stack) {
// start printing when we escape LP internals code
boolean shouldStartPrinting = !printing && (
(data.getCheckOrigin() == CheckOrigin.API || data.getCheckOrigin() == CheckOrigin.INTERNAL) || (
!e.getClassName().startsWith("me.lucko.luckperms.") &&
// all used within the checking impl somewhere
!e.getClassName().equals("java.util.concurrent.CompletableFuture") &&
!e.getClassName().startsWith("com.github.benmanes.caffeine") &&
!e.getClassName().equals("java.util.concurrent.ConcurrentHashMap")
)
);
if (shouldStartPrinting) {
printing = true;
}
if (!printing) continue;
if (count >= truncateLength) break;
consumer.accept(e);
count++;
}
if (stack.length > truncateLength) {
return stack.length - truncateLength;
}
return 0;
}
private static String escapeCommas(String s) {

View File

@ -296,8 +296,8 @@ public class LPSpongePlugin implements LuckPermsPlugin {
@Listener
public void onDisable(GameStoppingServerEvent event) {
permissionVault.setShutdown(true);
verboseHandler.setShutdown(true);
permissionVault.shutdown();
verboseHandler.shutdown();
getLog().info("Closing storage...");
storage.shutdown();

View File

@ -196,7 +196,7 @@ public class SpongeListener {
if (source == null) return;
final String name = e.getCommand().toLowerCase();
if (name.equals("op") || name.equals("deop")) {
if (((name.equals("op") || name.equals("minecraft:op")) && source.hasPermission("minecraft.command.op")) || ((name.equals("deop") || name.equals("minecraft:deop")) && source.hasPermission("minecraft.command.deop"))) {
Message.OP_DISABLED_SPONGE.send(plugin.getSenderFactory().wrap(source));
}
}

View File

@ -257,7 +257,7 @@ public class PersistedSubject implements LPSubject {
@Override
public Tristate getPermissionValue(@NonNull ImmutableContextSet contexts, @NonNull String node) {
Tristate t = permissionLookupCache.get(PermissionLookup.of(node, contexts));
service.getPlugin().getVerboseHandler().offerCheckData(CheckOrigin.INTERNAL, "local:" + getParentCollection().getIdentifier() + "/" + identifier, contexts, node, t);
service.getPlugin().getVerboseHandler().offerCheckData(CheckOrigin.INTERNAL, getParentCollection().getIdentifier() + "/" + identifier, contexts, node, t);
return t;
}