Final bits of API refactoring, add group data caches, fix issue with LPPermissionAttachment fake map injection

This commit is contained in:
Luck
2017-11-08 22:55:05 +00:00
Unverified
parent d75b29f51d
commit a115ff8ce2
51 changed files with 1267 additions and 579 deletions
@@ -34,7 +34,6 @@ import me.lucko.luckperms.common.calculators.AbstractCalculatorFactory;
import me.lucko.luckperms.common.calculators.PermissionCalculator;
import me.lucko.luckperms.common.calculators.PermissionCalculatorMetadata;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.processors.MapProcessor;
import me.lucko.luckperms.common.processors.PermissionProcessor;
import me.lucko.luckperms.common.processors.RegexProcessor;
@@ -50,7 +49,7 @@ public class SpongeCalculatorFactory extends AbstractCalculatorFactory {
private final LPSpongePlugin plugin;
@Override
public PermissionCalculator build(Contexts contexts, User user) {
public PermissionCalculator build(Contexts contexts, PermissionCalculatorMetadata metadata) {
ImmutableList.Builder<PermissionProcessor> processors = ImmutableList.builder();
processors.add(new MapProcessor());
@@ -71,8 +70,7 @@ public class SpongeCalculatorFactory extends AbstractCalculatorFactory {
processors.add(new DefaultsProcessor(plugin.getService(), contexts.getContexts().makeImmutable()));
}
PermissionCalculatorMetadata meta = PermissionCalculatorMetadata.of(user.getFriendlyName(), contexts.getContexts());
return registerCalculator(new PermissionCalculator(plugin, meta, processors.build()));
return registerCalculator(new PermissionCalculator(plugin, metadata, processors.build()));
}
@Override
@@ -171,12 +171,6 @@ public class SpongeConnectionListener {
}
}
@Listener(order = Order.EARLY)
public void onClientJoin(ClientConnectionEvent.Join e) {
// Refresh permissions again
plugin.getScheduler().doAsync(() -> LoginHelper.refreshPlayer(plugin, e.getTargetEntity().getUniqueId()));
}
@Listener(order = Order.POST)
public void onClientLeave(ClientConnectionEvent.Disconnect e) {
/* We don't actually remove the user instance here, as Sponge likes to keep performing checks
@@ -27,38 +27,27 @@ package me.lucko.luckperms.sponge.model;
import lombok.Getter;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.ImmutableSet;
import me.lucko.luckperms.api.ChatMetaType;
import me.lucko.luckperms.api.LocalizedNode;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.caching.MetaData;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.common.caching.MetaAccumulator;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.verbose.CheckOrigin;
import me.lucko.luckperms.sponge.LPSpongePlugin;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import me.lucko.luckperms.sponge.service.LuckPermsSubjectData;
import me.lucko.luckperms.sponge.service.ProxyFactory;
import me.lucko.luckperms.sponge.service.model.CompatibilityUtil;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectCollection;
import me.lucko.luckperms.sponge.service.model.SubjectReference;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.service.permission.NodeTree;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.service.permission.Subject;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
public class SpongeGroup extends Group {
@@ -74,11 +63,7 @@ public class SpongeGroup extends Group {
}
public static class GroupSubject implements LPSubject {
@Getter
private final SpongeGroup parent;
@Getter
private final LPSpongePlugin plugin;
@Getter
@@ -87,61 +72,11 @@ public class SpongeGroup extends Group {
@Getter
private final LuckPermsSubjectData transientSubjectData;
private final LoadingCache<ImmutableContextSet, NodeTree> permissionCache = Caffeine.newBuilder()
.expireAfterAccess(10, TimeUnit.MINUTES)
.build(contexts -> {
// TODO move this away from NodeTree
Map<String, Boolean> permissions = getParent().getAllNodes(getPlugin().getService().calculateContexts(contexts)).stream()
.map(LocalizedNode::getNode)
.collect(Collectors.toMap(Node::getPermission, Node::getValuePrimitive));
return NodeTree.of(permissions);
});
private final LoadingCache<ImmutableContextSet, ImmutableList<SubjectReference>> parentCache = Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.build(contexts -> {
Set<SubjectReference> subjects = getParent().getAllNodes(getPlugin().getService().calculateContexts(contexts)).stream()
.map(LocalizedNode::getNode)
.filter(Node::isGroupNode)
.map(Node::getGroupName)
.distinct()
.map(n -> Optional.ofNullable(getPlugin().getGroupManager().getIfLoaded(n)))
.filter(Optional::isPresent)
.map(Optional::get)
.map(SpongeGroup::sponge)
.map(LPSubject::toReference)
.collect(Collectors.toSet());
subjects.addAll(getPlugin().getService().getGroupSubjects().getDefaults().getParents(contexts));
subjects.addAll(getPlugin().getService().getDefaults().getParents(contexts));
return getService().sortSubjects(subjects);
});
private GroupSubject(LPSpongePlugin plugin, SpongeGroup parent) {
this.parent = parent;
this.plugin = plugin;
this.subjectData = new LuckPermsSubjectData(true, plugin.getService(), parent, this);
this.transientSubjectData = new LuckPermsSubjectData(false, plugin.getService(), parent, this);
parent.getStateListeners().add(() -> invalidateCaches(CacheLevel.PERMISSION));
}
@Override
public void invalidateCaches(CacheLevel type) {
if (type == CacheLevel.OPTION) {
return; // don't invalidate for option changes
}
permissionCache.invalidateAll();
parentCache.invalidateAll();
}
@Override
public void performCleanup() {
permissionCache.cleanUp();
parentCache.cleanUp();
}
@Override
@@ -176,19 +111,7 @@ public class SpongeGroup extends Group {
@Override
public Tristate getPermissionValue(ImmutableContextSet contexts, String permission) {
NodeTree nt = permissionCache.get(contexts);
Tristate t = CompatibilityUtil.convertTristate(nt.get(permission));
if (t != Tristate.UNDEFINED) {
return t;
}
t = plugin.getService().getGroupSubjects().getDefaults().getPermissionValue(contexts, permission);
if (t != Tristate.UNDEFINED) {
return t;
}
t = plugin.getService().getDefaults().getPermissionValue(contexts, permission);
return t;
return parent.getCachedData().getPermissionData(plugin.getContextManager().formContexts(contexts)).getPermissionValue(permission, CheckOrigin.PLATFORM_LOOKUP_CHECK);
}
@Override
@@ -198,29 +121,48 @@ public class SpongeGroup extends Group {
@Override
public ImmutableList<SubjectReference> getParents(ImmutableContextSet contexts) {
return parentCache.get(contexts);
ImmutableSet.Builder<SubjectReference> subjects = ImmutableSet.builder();
for (String perm : parent.getCachedData().getPermissionData(plugin.getContextManager().formContexts(contexts)).getImmutableBacking().keySet()) {
if (!perm.startsWith("group.")) {
continue;
}
String groupName = perm.substring("group.".length());
if (plugin.getGroupManager().isLoaded(groupName)) {
subjects.add(plugin.getService().getGroupSubjects().loadSubject(groupName).join().toReference());
}
}
subjects.addAll(plugin.getService().getGroupSubjects().getDefaults().getParents(contexts));
subjects.addAll(plugin.getService().getDefaults().getParents(contexts));
return getService().sortSubjects(subjects.build());
}
@Override
public Optional<String> getOption(ImmutableContextSet contexts, String s) {
Optional<String> option;
MetaData data = parent.getCachedData().getMetaData(plugin.getContextManager().formContexts(contexts));
if (s.equalsIgnoreCase("prefix")) {
option = getChatMeta(contexts, ChatMetaType.PREFIX);
} else if (s.equalsIgnoreCase("suffix")) {
option = getChatMeta(contexts, ChatMetaType.SUFFIX);
} else {
option = getMeta(contexts, s);
if (data.getPrefix() != null) {
return Optional.of(data.getPrefix());
}
}
if (option.isPresent()) {
return option;
if (s.equalsIgnoreCase("suffix")) {
if (data.getSuffix() != null) {
return Optional.of(data.getSuffix());
}
}
option = plugin.getService().getGroupSubjects().getDefaults().getOption(contexts, s);
if (option.isPresent()) {
return option;
String val = data.getMeta().get(s);
if (val != null) {
return Optional.of(val);
}
Optional<String> v = plugin.getService().getGroupSubjects().getDefaults().getOption(contexts, s);
if (v.isPresent()) {
return v;
}
return plugin.getService().getDefaults().getOption(contexts, s);
@@ -231,16 +173,11 @@ public class SpongeGroup extends Group {
return plugin.getContextManager().getApplicableContext(this.sponge());
}
private Optional<String> getChatMeta(ImmutableContextSet contexts, ChatMetaType type) {
MetaAccumulator metaAccumulator = parent.accumulateMeta(null, null, plugin.getService().calculateContexts(contexts));
return Optional.ofNullable(metaAccumulator.getStack(type).toFormattedString());
}
private Optional<String> getMeta(ImmutableContextSet contexts, String key) {
MetaAccumulator metaAccumulator = parent.accumulateMeta(null, null, plugin.getService().calculateContexts(contexts));
ListMultimap<String, String> meta = metaAccumulator.getMeta();
List<String> ret = meta.get(key);
return ret.isEmpty() ? Optional.empty() : Optional.of(ret.get(0));
@Override
public void invalidateCaches(CacheLevel cacheLevel) {
// invalidate for all changes
parent.getCachedData().invalidateCaches();
}
}
}
@@ -45,12 +45,12 @@ import me.lucko.luckperms.sponge.service.model.SubjectReference;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.service.permission.Subject;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Function;
public class SpongeUser extends User {
@@ -100,13 +100,7 @@ public class SpongeUser extends User {
@Override
public Optional<CommandSource> getCommandSource() {
final UUID uuid = plugin.getUuidCache().getExternalUUID(parent.getUuid());
Optional<Player> p = Sponge.getServer().getPlayer(uuid);
if (p.isPresent()) {
return Optional.of(p.get());
}
return Optional.empty();
return Sponge.getServer().getPlayer(uuid).map(Function.identity());
}
@Override
@@ -126,7 +120,7 @@ public class SpongeUser extends User {
@Override
public Tristate getPermissionValue(ImmutableContextSet contexts, String permission) {
return parent.getUserData().getPermissionData(plugin.getService().calculateContexts(contexts)).getPermissionValue(permission, CheckOrigin.PLATFORM_LOOKUP_CHECK);
return parent.getCachedData().getPermissionData(plugin.getContextManager().formContexts(contexts)).getPermissionValue(permission, CheckOrigin.PLATFORM_LOOKUP_CHECK);
}
@Override
@@ -138,7 +132,7 @@ public class SpongeUser extends User {
public ImmutableList<SubjectReference> getParents(ImmutableContextSet contexts) {
ImmutableSet.Builder<SubjectReference> subjects = ImmutableSet.builder();
for (String perm : parent.getUserData().getPermissionData(plugin.getService().calculateContexts(contexts)).getImmutableBacking().keySet()) {
for (String perm : parent.getCachedData().getPermissionData(plugin.getContextManager().formContexts(contexts)).getImmutableBacking().keySet()) {
if (!perm.startsWith("group.")) {
continue;
}
@@ -157,7 +151,7 @@ public class SpongeUser extends User {
@Override
public Optional<String> getOption(ImmutableContextSet contexts, String s) {
MetaData data = parent.getUserData().getMetaData(plugin.getService().calculateContexts(contexts));
MetaData data = parent.getCachedData().getMetaData(plugin.getContextManager().formContexts(contexts));
if (s.equalsIgnoreCase("prefix")) {
if (data.getPrefix() != null) {
return Optional.of(data.getPrefix());
@@ -191,7 +185,7 @@ public class SpongeUser extends User {
@Override
public void invalidateCaches(CacheLevel cacheLevel) {
// invalidate for all changes
parent.getUserData().invalidateCaches();
parent.getCachedData().invalidateCaches();
}
}
@@ -35,8 +35,6 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.sponge.LPSpongePlugin;
@@ -230,11 +228,6 @@ public class LuckPermsService implements LPPermissionService {
return ImmutableList.copyOf(ret);
}
@Override
public Contexts calculateContexts(ImmutableContextSet contextSet) {
return plugin.getContextManager().formContexts(null, contextSet);
}
@Override
public void invalidateAllCaches(LPSubject.CacheLevel cacheLevel) {
for (LPSubjectCollection collection : collections.asMap().values()) {
@@ -353,7 +353,7 @@ public class LuckPermsSubjectData implements LPSubjectData {
toRemove.forEach(makeUnsetConsumer(enduring));
MetaAccumulator metaAccumulator = holder.accumulateMeta(null, null, service.calculateContexts(context));
MetaAccumulator metaAccumulator = holder.accumulateMeta(null, null, service.getPlugin().getContextManager().formContexts(context));
int priority = metaAccumulator.getChatMeta(type).keySet().stream().mapToInt(e -> e).max().orElse(0);
priority += 10;
@@ -451,23 +451,21 @@ public class LuckPermsSubjectData implements LPSubjectData {
} else {
if (t instanceof User) {
User user = ((User) t);
return service.getPlugin().getStorage().saveUser(user).thenApplyAsync(success -> {
return service.getPlugin().getStorage().saveUser(user).thenComposeAsync(success -> {
if (!success) {
return null;
return CompletableFuture.completedFuture(null);
}
user.getRefreshBuffer().request().join();
return null;
return user.getRefreshBuffer().request();
}, service.getPlugin().getScheduler().async());
} else {
Group group = ((Group) t);
return service.getPlugin().getStorage().saveGroup(group).thenApplyAsync(success -> {
return service.getPlugin().getStorage().saveGroup(group).thenComposeAsync(success -> {
if (!success) {
return null;
return CompletableFuture.completedFuture(null);
}
service.getPlugin().getUpdateTaskBuffer().request().join();
return null;
return service.getPlugin().getUpdateTaskBuffer().request();
}, service.getPlugin().getScheduler().async());
}
}