Ensure caches are invalidated when Bukkit/Nukkit's Permission#getChildren map is modified (#1378)
This commit is contained in:
@@ -61,4 +61,9 @@ public class ChildProcessor extends AbstractPermissionProcessor implements Permi
|
||||
}
|
||||
this.childPermissions = builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidate() {
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,6 +95,8 @@ public final class LPDefaultsMap implements Map<Boolean, Set<Permission>> {
|
||||
|
||||
private void invalidate(boolean op) {
|
||||
getCache(op).invalidate();
|
||||
this.plugin.getUserManager().invalidateAllPermissionCalculators();
|
||||
this.plugin.getGroupManager().invalidateAllPermissionCalculators();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -176,6 +178,13 @@ public final class LPDefaultsMap implements Map<Boolean, Set<Permission>> {
|
||||
invalidate(this.op);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(@NonNull Object object) {
|
||||
boolean ret = super.remove(object);
|
||||
invalidate(this.op);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.bukkit.plugin.PluginManager;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -49,7 +50,8 @@ import java.util.function.Function;
|
||||
*
|
||||
* This instance allows LuckPerms to intercept calls to
|
||||
* {@link PluginManager#addPermission(Permission)} and record permissions in the
|
||||
* {@link PermissionRegistry}.
|
||||
* {@link PermissionRegistry}. It also lets us monitor changes to child permission
|
||||
* relationships.
|
||||
*
|
||||
* It also allows us to pre-determine child permission relationships.
|
||||
*
|
||||
@@ -57,6 +59,17 @@ import java.util.function.Function;
|
||||
*/
|
||||
public final class LPPermissionMap extends ForwardingMap<String, Permission> {
|
||||
|
||||
private static final Field PERMISSION_CHILDREN_FIELD;
|
||||
|
||||
static {
|
||||
try {
|
||||
PERMISSION_CHILDREN_FIELD = Permission.class.getDeclaredField("children");
|
||||
PERMISSION_CHILDREN_FIELD.setAccessible(true);
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new ExceptionInInitializerError(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Uses perm.getName().toLowerCase(java.util.Locale.ENGLISH); to determine the key
|
||||
private final Map<String, Permission> delegate = new ConcurrentHashMap<>();
|
||||
|
||||
@@ -81,6 +94,8 @@ public final class LPPermissionMap extends ForwardingMap<String, Permission> {
|
||||
private void update() {
|
||||
this.trueChildPermissions.clear();
|
||||
this.falseChildPermissions.clear();
|
||||
this.plugin.getUserManager().invalidateAllPermissionCalculators();
|
||||
this.plugin.getGroupManager().invalidateAllPermissionCalculators();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -94,7 +109,7 @@ public final class LPPermissionMap extends ForwardingMap<String, Permission> {
|
||||
Objects.requireNonNull(value, "value");
|
||||
|
||||
this.plugin.getPermissionRegistry().insert(key);
|
||||
Permission ret = super.put(key, value);
|
||||
Permission ret = super.put(key, inject(value));
|
||||
update();
|
||||
return ret;
|
||||
}
|
||||
@@ -106,32 +121,21 @@ public final class LPPermissionMap extends ForwardingMap<String, Permission> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Permission putIfAbsent(String key, Permission value) {
|
||||
Objects.requireNonNull(key, "key");
|
||||
Objects.requireNonNull(value, "value");
|
||||
|
||||
this.plugin.getPermissionRegistry().insert(key);
|
||||
Permission ret = super.putIfAbsent(key, value);
|
||||
update();
|
||||
return ret;
|
||||
}
|
||||
|
||||
// null-safe - the plugin manager uses hashmap
|
||||
|
||||
@Override
|
||||
public Permission remove(@Nullable Object object) {
|
||||
if (object == null) {
|
||||
return null;
|
||||
}
|
||||
return super.remove(object);
|
||||
return uninject(super.remove(object));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object key, Object value) {
|
||||
return key != null && value != null && super.remove(key, value);
|
||||
return key != null && value != null && super.remove(key, uninject(((Permission) value)));
|
||||
}
|
||||
|
||||
// check for null
|
||||
|
||||
@Override
|
||||
public boolean containsKey(@Nullable Object key) {
|
||||
return key != null && super.containsKey(key);
|
||||
@@ -186,4 +190,81 @@ public final class LPPermissionMap extends ForwardingMap<String, Permission> {
|
||||
}
|
||||
}
|
||||
|
||||
private Permission inject(Permission permission) {
|
||||
if (permission == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
//noinspection unchecked
|
||||
Map<String, Boolean> children = (Map<String, Boolean>) PERMISSION_CHILDREN_FIELD.get(permission);
|
||||
while (children instanceof PermissionNotifyingChildrenMap) {
|
||||
children = ((PermissionNotifyingChildrenMap) children).delegate;
|
||||
}
|
||||
|
||||
PermissionNotifyingChildrenMap notifyingChildren = new PermissionNotifyingChildrenMap(children);
|
||||
PERMISSION_CHILDREN_FIELD.set(permission, notifyingChildren);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return permission;
|
||||
}
|
||||
|
||||
private Permission uninject(Permission permission) {
|
||||
if (permission == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
//noinspection unchecked
|
||||
Map<String, Boolean> children = (Map<String, Boolean>) PERMISSION_CHILDREN_FIELD.get(permission);
|
||||
while (children instanceof PermissionNotifyingChildrenMap) {
|
||||
children = ((PermissionNotifyingChildrenMap) children).delegate;
|
||||
}
|
||||
PERMISSION_CHILDREN_FIELD.set(permission, children);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return permission;
|
||||
}
|
||||
|
||||
private final class PermissionNotifyingChildrenMap extends ForwardingMap<String, Boolean> {
|
||||
private final Map<String, Boolean> delegate;
|
||||
|
||||
PermissionNotifyingChildrenMap(Map<String, Boolean> delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Boolean> delegate() {
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean put(@NonNull String key, @NonNull Boolean value) {
|
||||
Boolean ret = super.put(key, value);
|
||||
LPPermissionMap.this.update();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(@NonNull Map<? extends String, ? extends Boolean> map) {
|
||||
super.putAll(map);
|
||||
LPPermissionMap.this.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean remove(@NonNull Object object) {
|
||||
Boolean ret = super.remove(object);
|
||||
LPPermissionMap.this.update();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
super.clear();
|
||||
LPPermissionMap.this.update();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user