mirror of
https://github.com/LuckPerms/LuckPerms.git
synced 2025-02-05 23:21:22 +01:00
Ensure caches are invalidated when Bukkit/Nukkit's Permission#getChildren map is modified (#1378)
This commit is contained in:
parent
78a74510cf
commit
3c0d1ba7a1
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -130,6 +130,9 @@ public class PermissionCalculator implements Function<String, Tristate> {
|
||||
}
|
||||
|
||||
public void invalidateCache() {
|
||||
for (PermissionProcessor processor : this.processors) {
|
||||
processor.invalidate();
|
||||
}
|
||||
this.lookupCache.clear();
|
||||
}
|
||||
}
|
||||
|
@ -62,4 +62,11 @@ public interface PermissionProcessor {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after the parent calculator has been invalidated
|
||||
*/
|
||||
default void invalidate() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -69,4 +69,9 @@ public abstract class AbstractGroupManager<T extends Group> extends AbstractMana
|
||||
public void invalidateAllGroupCaches() {
|
||||
getAll().values().forEach(PermissionHolder::invalidateCachedData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateAllPermissionCalculators() {
|
||||
getAll().values().forEach(p -> p.getCachedData().invalidatePermissionCalculators());
|
||||
}
|
||||
}
|
@ -25,6 +25,7 @@
|
||||
|
||||
package me.lucko.luckperms.common.model.manager.group;
|
||||
|
||||
import me.lucko.luckperms.common.calculator.PermissionCalculator;
|
||||
import me.lucko.luckperms.common.model.Group;
|
||||
import me.lucko.luckperms.common.model.manager.Manager;
|
||||
|
||||
@ -43,4 +44,9 @@ public interface GroupManager<T extends Group> extends Manager<String, Group, T>
|
||||
*/
|
||||
void invalidateAllGroupCaches();
|
||||
|
||||
/**
|
||||
* Invalidates the {@link PermissionCalculator}s for *loaded* groups.
|
||||
*/
|
||||
void invalidateAllPermissionCalculators();
|
||||
|
||||
}
|
||||
|
@ -162,6 +162,11 @@ public abstract class AbstractUserManager<T extends User> extends AbstractManage
|
||||
getAll().values().forEach(PermissionHolder::invalidateCachedData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateAllPermissionCalculators() {
|
||||
getAll().values().forEach(p -> p.getCachedData().invalidatePermissionCalculators());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the user's state indicates that they should be persisted to storage.
|
||||
*
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
package me.lucko.luckperms.common.model.manager.user;
|
||||
|
||||
import me.lucko.luckperms.common.calculator.PermissionCalculator;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.model.UserIdentifier;
|
||||
import me.lucko.luckperms.common.model.manager.Manager;
|
||||
@ -89,4 +90,9 @@ public interface UserManager<T extends User> extends Manager<UserIdentifier, Use
|
||||
*/
|
||||
void invalidateAllUserCaches();
|
||||
|
||||
/**
|
||||
* Invalidates the {@link PermissionCalculator}s for *loaded* users.
|
||||
*/
|
||||
void invalidateAllPermissionCalculators();
|
||||
|
||||
}
|
||||
|
@ -61,4 +61,9 @@ public class ChildProcessor extends AbstractPermissionProcessor implements Permi
|
||||
}
|
||||
this.childPermissions = builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidate() {
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
@ -88,6 +88,8 @@ public final class LPDefaultsMap {
|
||||
|
||||
private void invalidate(boolean op) {
|
||||
getCache(op).invalidate();
|
||||
this.plugin.getUserManager().invalidateAllPermissionCalculators();
|
||||
this.plugin.getGroupManager().invalidateAllPermissionCalculators();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -136,6 +138,13 @@ public final class LPDefaultsMap {
|
||||
super.putAll(map);
|
||||
invalidate(this.op);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Permission remove(@NonNull Object object) {
|
||||
Permission ret = super.remove(object);
|
||||
invalidate(this.op);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
private final class DefaultsCache extends Cache<Map<String, Boolean>> {
|
||||
|
@ -33,13 +33,16 @@ import me.lucko.luckperms.common.treeview.PermissionRegistry;
|
||||
import me.lucko.luckperms.common.util.LoadingMap;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import cn.nukkit.permission.Permission;
|
||||
import cn.nukkit.plugin.PluginManager;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
|
||||
@ -56,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<>();
|
||||
|
||||
@ -80,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
|
||||
@ -89,8 +105,11 @@ public final class LPPermissionMap extends ForwardingMap<String, Permission> {
|
||||
|
||||
@Override
|
||||
public Permission put(@NonNull String key, @NonNull Permission value) {
|
||||
Objects.requireNonNull(key, "key");
|
||||
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;
|
||||
}
|
||||
@ -103,11 +122,36 @@ public final class LPPermissionMap extends ForwardingMap<String, Permission> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Permission putIfAbsent(String key, Permission value) {
|
||||
this.plugin.getPermissionRegistry().insert(key);
|
||||
Permission ret = super.putIfAbsent(key, value);
|
||||
update();
|
||||
return ret;
|
||||
public Permission remove(@Nullable Object object) {
|
||||
if (object == null) {
|
||||
return null;
|
||||
}
|
||||
return uninject(super.remove(object));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object key, Object 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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(@Nullable Object value) {
|
||||
return value != null && super.containsValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Permission get(@Nullable Object key) {
|
||||
if (key == null) {
|
||||
return null;
|
||||
}
|
||||
return super.get(key);
|
||||
}
|
||||
|
||||
private final class ChildPermissionResolver implements Function<String, Map<String, Boolean>> {
|
||||
@ -146,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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user