From 23d53d39b42cee218089cfe848ca56210cc3ff62 Mon Sep 17 00:00:00 2001 From: Luck Date: Sat, 17 Sep 2016 23:15:07 +0100 Subject: [PATCH] Refactor permission calculation --- .../lucko/luckperms/inject/LPPermissible.java | 115 +++++++--------- .../me/lucko/luckperms/BungeePlayerCache.java | 72 +++------- .../luckperms/utils/PermissionCalculator.java | 126 ++++++++++++++++++ .../api/sponge/LuckPermsUserSubject.java | 111 ++++++++------- 4 files changed, 249 insertions(+), 175 deletions(-) create mode 100644 common/src/main/java/me/lucko/luckperms/utils/PermissionCalculator.java diff --git a/bukkit/src/main/java/me/lucko/luckperms/inject/LPPermissible.java b/bukkit/src/main/java/me/lucko/luckperms/inject/LPPermissible.java index db4021423..e543c5032 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/inject/LPPermissible.java +++ b/bukkit/src/main/java/me/lucko/luckperms/inject/LPPermissible.java @@ -22,11 +22,12 @@ package me.lucko.luckperms.inject; -import com.google.common.base.Splitter; +import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NonNull; import me.lucko.luckperms.LuckPermsPlugin; import me.lucko.luckperms.api.Tristate; +import me.lucko.luckperms.utils.PermissionCalculator; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.permissions.*; @@ -34,6 +35,7 @@ import org.bukkit.plugin.Plugin; import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; import java.util.logging.Level; import java.util.stream.Collectors; @@ -44,82 +46,29 @@ public class LPPermissible extends PermissibleBase { @Getter private final CommandSender parent; - private final LuckPermsPlugin plugin; + + private final PermissionCalculator calculator; @Getter private final Map luckPermsPermissions = new ConcurrentHashMap<>(); private final List attachments = new LinkedList<>(); private final Map attachmentPermissions = new HashMap<>(); - private final Map lookupCache = new HashMap<>(); - public LPPermissible(@NonNull CommandSender sender, LuckPermsPlugin plugin) { super(sender); this.parent = sender; - this.plugin = plugin; + + List processors = new ArrayList<>(4); + processors.add(new PermissionCalculator.MapProcessor(luckPermsPermissions)); + processors.add(new AttachmentProcessor(attachmentPermissions)); + processors.add(new PermissionCalculator.WildcardProcessor(luckPermsPermissions)); + processors.add(new BukkitDefaultsProcessor(parent::isOp)); + + calculator = new PermissionCalculator(plugin, parent.getName(), plugin.getConfiguration().getDebugPermissionChecks(), processors); } public void invalidateCache() { - synchronized (lookupCache) { - lookupCache.clear(); - } - } - - private Tristate getPermissionValue(String permission) { - if (plugin.getConfiguration().getDebugPermissionChecks()) { - plugin.getLog().info("Checking if " + parent.getName() + " has permission: " + permission); - } - - permission = permission.toLowerCase(); - synchronized (lookupCache) { - if (lookupCache.containsKey(permission)) { - return lookupCache.get(permission); - } else { - Tristate t = lookupPermissionValue(permission); - lookupCache.put(permission, t); - return t; - } - } - } - - private Tristate lookupPermissionValue(String permission) { - if (luckPermsPermissions.containsKey(permission)) { - return Tristate.fromBoolean(luckPermsPermissions.get(permission)); - } - - if (attachmentPermissions.containsKey(permission)) { - return Tristate.fromBoolean(attachmentPermissions.get(permission).getValue()); - } - - if (plugin.getConfiguration().getApplyWildcards()) { - if (luckPermsPermissions.containsKey("*")) { - return Tristate.fromBoolean(luckPermsPermissions.get("*")); - } - if (luckPermsPermissions.containsKey("'*'")) { - return Tristate.fromBoolean(luckPermsPermissions.get("'*'")); - } - - String node = ""; - Iterable permParts = Splitter.on('.').split(permission); - for (String s : permParts) { - if (node.equals("")) { - node = s; - } else { - node = node + "." + s; - } - - if (luckPermsPermissions.containsKey(node + ".*")) { - return Tristate.fromBoolean(luckPermsPermissions.get(node + ".*")); - } - } - } - - Permission defPerm = Bukkit.getServer().getPluginManager().getPermission(permission); - if (defPerm != null) { - return Tristate.fromBoolean(defPerm.getDefault().getValue(isOp())); - } - - return Tristate.UNDEFINED; + calculator.invalidateCache(); } @Override @@ -144,7 +93,7 @@ public class LPPermissible extends PermissibleBase { @Override public boolean hasPermission(@NonNull String name) { - Tristate ts = getPermissionValue(name); + Tristate ts = calculator.getPermissionValue(name); if (ts != Tristate.UNDEFINED) { return ts.asBoolean(); } @@ -154,7 +103,7 @@ public class LPPermissible extends PermissibleBase { @Override public boolean hasPermission(@NonNull Permission perm) { - Tristate ts = getPermissionValue(perm.getName()); + Tristate ts = calculator.getPermissionValue(perm.getName()); if (ts != Tristate.UNDEFINED) { return ts.asBoolean(); } @@ -313,4 +262,36 @@ public class LPPermissible extends PermissibleBase { attachment.remove(); } } + + @AllArgsConstructor + private static class AttachmentProcessor implements PermissionCalculator.PermissionProcessor { + + @Getter + private final Map map; + + @Override + public Tristate hasPermission(String permission) { + if (map.containsKey(permission)) { + return Tristate.fromBoolean(map.get(permission).getValue()); + } + + return Tristate.UNDEFINED; + } + + } + + @AllArgsConstructor + private static class BukkitDefaultsProcessor implements PermissionCalculator.PermissionProcessor { + private final Supplier isOp; + + @Override + public Tristate hasPermission(String permission) { + Permission defPerm = Bukkit.getServer().getPluginManager().getPermission(permission); + if (defPerm != null) { + return Tristate.fromBoolean(defPerm.getDefault().getValue(isOp.get())); + } else { + return Tristate.UNDEFINED; + } + } + } } diff --git a/bungee/src/main/java/me/lucko/luckperms/BungeePlayerCache.java b/bungee/src/main/java/me/lucko/luckperms/BungeePlayerCache.java index 456a6043f..a32f1fb53 100644 --- a/bungee/src/main/java/me/lucko/luckperms/BungeePlayerCache.java +++ b/bungee/src/main/java/me/lucko/luckperms/BungeePlayerCache.java @@ -22,76 +22,34 @@ package me.lucko.luckperms; -import com.google.common.base.Splitter; import lombok.Getter; -import lombok.RequiredArgsConstructor; +import me.lucko.luckperms.utils.PermissionCalculator; -import java.util.HashMap; +import java.util.ArrayList; +import java.util.List; import java.util.Map; -import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; -@RequiredArgsConstructor public class BungeePlayerCache { - private final LuckPermsPlugin plugin; - private final UUID uuid; - private final String name; + + private final PermissionCalculator calculator; @Getter private final Map permissions = new ConcurrentHashMap<>(); - private final Map lookupCache = new HashMap<>(); + + public BungeePlayerCache(LuckPermsPlugin plugin, String name) { + List processors = new ArrayList<>(2); + processors.add(new PermissionCalculator.MapProcessor(permissions)); + processors.add(new PermissionCalculator.WildcardProcessor(permissions)); + + calculator = new PermissionCalculator(plugin, name, plugin.getConfiguration().getDebugPermissionChecks(), processors); + } public void invalidateCache() { - synchronized (lookupCache) { - lookupCache.clear(); - } + calculator.invalidateCache(); } public boolean getPermissionValue(String permission) { - if (plugin.getConfiguration().getDebugPermissionChecks()) { - plugin.getLog().info("Checking if " + name + " has permission: " + permission); - } - - permission = permission.toLowerCase(); - synchronized (lookupCache) { - if (lookupCache.containsKey(permission)) { - return lookupCache.get(permission); - } else { - boolean t = lookupPermissionValue(permission); - lookupCache.put(permission, t); - return t; - } - } - } - - private boolean lookupPermissionValue(String permission) { - if (permissions.containsKey(permission)) { - return permissions.get(permission); - } - - if (plugin.getConfiguration().getApplyWildcards()) { - if (permissions.containsKey("*")) { - return permissions.get("*"); - } - if (permissions.containsKey("'*'")) { - return permissions.get("'*'"); - } - - String node = ""; - Iterable permParts = Splitter.on('.').split(permission); - for (String s : permParts) { - if (node.equals("")) { - node = s; - } else { - node = node + "." + s; - } - - if (permissions.containsKey(node + ".*")) { - return permissions.get(node + ".*"); - } - } - } - - return false; + return calculator.getPermissionValue(permission).asBoolean(); } } diff --git a/common/src/main/java/me/lucko/luckperms/utils/PermissionCalculator.java b/common/src/main/java/me/lucko/luckperms/utils/PermissionCalculator.java new file mode 100644 index 000000000..b8d2b0089 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/utils/PermissionCalculator.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * 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.utils; + +import com.google.common.base.Splitter; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.api.Tristate; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Calculates and caches permissions + */ +@RequiredArgsConstructor +public class PermissionCalculator { + private final LuckPermsPlugin plugin; + private final String objectName; + private final boolean debug; + private final List processors; + private final Map cache = new ConcurrentHashMap<>(); + + public void invalidateCache() { + cache.clear(); + } + + public Tristate getPermissionValue(String permission) { + if (debug) { + plugin.getLog().info("Checking if " + objectName + " has permission: " + permission); + } + + permission = permission.toLowerCase(); + return cache.computeIfAbsent(permission, this::lookupPermissionValue); + } + + private Tristate lookupPermissionValue(String permission) { + for (PermissionProcessor processor : processors) { + Tristate v = processor.hasPermission(permission); + if (v == Tristate.UNDEFINED) { + continue; + } + + return v; + } + + return Tristate.UNDEFINED; + } + + @AllArgsConstructor + public static class MapProcessor implements PermissionProcessor { + + @Getter + private final Map map; + + @Override + public Tristate hasPermission(String permission) { + if (map.containsKey(permission)) { + return Tristate.fromBoolean(map.get(permission)); + } + + return Tristate.UNDEFINED; + } + } + + @AllArgsConstructor + public static class WildcardProcessor implements PermissionCalculator.PermissionProcessor { + + @Getter + private final Map map; + + @Override + public Tristate hasPermission(String permission) { + if (map.containsKey("*")) { + return Tristate.fromBoolean(map.get("*")); + } + if (map.containsKey("'*'")) { + return Tristate.fromBoolean(map.get("'*'")); + } + + String node = ""; + Iterable permParts = Splitter.on('.').split(permission); + for (String s : permParts) { + if (node.equals("")) { + node = s; + } else { + node = node + "." + s; + } + + if (map.containsKey(node + ".*")) { + return Tristate.fromBoolean(map.get(node + ".*")); + } + } + + return Tristate.UNDEFINED; + } + } + + public interface PermissionProcessor { + Tristate hasPermission(String permission); + } + +} diff --git a/sponge/src/main/java/me/lucko/luckperms/api/sponge/LuckPermsUserSubject.java b/sponge/src/main/java/me/lucko/luckperms/api/sponge/LuckPermsUserSubject.java index 6976f1bb3..e02b7a5f4 100644 --- a/sponge/src/main/java/me/lucko/luckperms/api/sponge/LuckPermsUserSubject.java +++ b/sponge/src/main/java/me/lucko/luckperms/api/sponge/LuckPermsUserSubject.java @@ -23,9 +23,11 @@ package me.lucko.luckperms.api.sponge; import com.google.common.base.Splitter; +import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NonNull; import me.lucko.luckperms.users.User; +import me.lucko.luckperms.utils.PermissionCalculator; import org.spongepowered.api.Sponge; import org.spongepowered.api.command.CommandSource; import org.spongepowered.api.entity.living.player.Player; @@ -43,72 +45,37 @@ public class LuckPermsUserSubject extends LuckPermsSubject { @Getter private final User user; - @Getter - private final Map permissionCache = new ConcurrentHashMap<>(); + private final PermissionCalculator calculator; @Getter - private final Map lookupCache = new HashMap<>(); + private final Map permissionCache = new ConcurrentHashMap<>(); private LuckPermsUserSubject(User user, LuckPermsService service) { super(user, service); this.user = user; + + List processors = new ArrayList<>(4); + processors.add(new PermissionCalculator.MapProcessor(permissionCache)); + processors.add(new SpongeWildcardProcessor(permissionCache)); + processors.add(new PermissionCalculator.WildcardProcessor(permissionCache)); + processors.add(new SpongeDefaultsProcessor(service)); + + calculator = new PermissionCalculator(service.getPlugin(), user.getName(), service.getPlugin().getConfiguration().getDebugPermissionChecks(), processors); } public void invalidateCache() { - synchronized (lookupCache) { - lookupCache.clear(); - } + calculator.invalidateCache(); } // TODO don't ignore context @Override public Tristate getPermissionValue(@NonNull Set contexts, @NonNull String permission) { - if (service.getPlugin().getConfiguration().getDebugPermissionChecks()) { - service.getPlugin().getLog().info("Checking if " + user.getName() + " has permission: " + permission); + me.lucko.luckperms.api.Tristate t = calculator.getPermissionValue(permission); + if (t != me.lucko.luckperms.api.Tristate.UNDEFINED) { + return Tristate.fromBoolean(t.asBoolean()); + } else { + return Tristate.UNDEFINED; } - - permission = permission.toLowerCase(); - synchronized (lookupCache) { - if (lookupCache.containsKey(permission)) { - return lookupCache.get(permission); - } else { - Tristate t = lookupPermissionValue(contexts, permission); - lookupCache.put(permission, t); - return t; - } - } - } - - private Tristate lookupPermissionValue(Set contexts, String permission) { - if (permissionCache.containsKey(permission)) { - return Tristate.fromBoolean(permissionCache.get(permission)); - } - - if (service.getPlugin().getConfiguration().getApplyWildcards()) { - if (permissionCache.containsKey("*")) { - return Tristate.fromBoolean(permissionCache.get("*")); - } - if (permissionCache.containsKey("'*'")) { - return Tristate.fromBoolean(permissionCache.get("'*'")); - } - - String node = ""; - Iterable permParts = Splitter.on('.').split(permission); - for (String s : permParts) { - if (node.equals("")) { - node = s; - } else { - node = node + "." + s; - } - - if (permissionCache.containsKey(node + ".*")) { - return Tristate.fromBoolean(permissionCache.get(node + ".*")); - } - } - } - - - return service.getDefaults().getPermissionValue(contexts, permission); } @Override @@ -127,4 +94,46 @@ public class LuckPermsUserSubject extends LuckPermsSubject { return Optional.empty(); } + + // TODO proper implementation. + @AllArgsConstructor + private static class SpongeWildcardProcessor implements PermissionCalculator.PermissionProcessor { + + @Getter + private final Map map; + + @Override + public me.lucko.luckperms.api.Tristate hasPermission(String permission) { + String node = ""; + Iterable permParts = Splitter.on('.').split(permission); + for (String s : permParts) { + if (node.equals("")) { + node = s; + } else { + node = node + "." + s; + } + + if (map.containsKey(node)) { + return me.lucko.luckperms.api.Tristate.fromBoolean(map.get(node)); + } + } + + return me.lucko.luckperms.api.Tristate.UNDEFINED; + } + } + + @AllArgsConstructor + private static class SpongeDefaultsProcessor implements PermissionCalculator.PermissionProcessor { + private final LuckPermsService service; + + @Override + public me.lucko.luckperms.api.Tristate hasPermission(String permission) { + Tristate t = service.getDefaults().getPermissionValue(Collections.emptySet(), permission); + if (t != Tristate.UNDEFINED) { + return me.lucko.luckperms.api.Tristate.fromBoolean(t.asBoolean()); + } else { + return me.lucko.luckperms.api.Tristate.UNDEFINED; + } + } + } }