WIP: Sponge service refactor

This commit is contained in:
Luck 2016-12-02 17:20:36 +00:00
parent 02ff4a4acb
commit 2b8bbc434f
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
26 changed files with 1151 additions and 618 deletions

View File

@ -34,7 +34,6 @@ import me.lucko.luckperms.common.calculators.processors.WildcardProcessor;
import me.lucko.luckperms.common.core.model.User;
import me.lucko.luckperms.sponge.calculators.DefaultsProcessor;
import me.lucko.luckperms.sponge.calculators.SpongeWildcardProcessor;
import me.lucko.luckperms.sponge.service.LuckPermsService;
@AllArgsConstructor
public class SpongeCalculatorFactory extends AbstractCalculatorFactory {
@ -51,7 +50,7 @@ public class SpongeCalculatorFactory extends AbstractCalculatorFactory {
if (plugin.getConfiguration().isApplyingRegex()) {
processors.add(new RegexProcessor());
}
processors.add(new DefaultsProcessor(plugin.getService(), LuckPermsService.convertContexts(contexts.getContexts())));
processors.add(new DefaultsProcessor(plugin.getService(), contexts.getContexts()));
return registerCalculator(new PermissionCalculator(plugin, user.getName(), processors.build()));
}

View File

@ -23,34 +23,31 @@
package me.lucko.luckperms.sponge.calculators;
import lombok.AllArgsConstructor;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.calculators.PermissionProcessor;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.util.Tristate;
import java.util.Map;
import java.util.Set;
import static me.lucko.luckperms.sponge.service.LuckPermsService.convertTristate;
@AllArgsConstructor
public class DefaultsProcessor implements PermissionProcessor {
private final LuckPermsService service;
private final Set<Context> contexts;
private final ContextSet contexts;
@Override
public me.lucko.luckperms.api.Tristate hasPermission(String permission) {
Tristate t = service.getUserSubjects().getDefaults().getPermissionValue(contexts, permission);
public Tristate hasPermission(String permission) {
Tristate t = service.getUserSubjects().getDefaultSubject().resolve(service).getPermissionValue(contexts, permission);
if (t != Tristate.UNDEFINED) {
return convertTristate(t);
return t;
}
Tristate t2 = service.getDefaults().getPermissionValue(contexts, permission);
if (t2 != Tristate.UNDEFINED) {
return convertTristate(t);
return t;
}
return me.lucko.luckperms.api.Tristate.UNDEFINED;
return Tristate.UNDEFINED;
}
@Override

View File

@ -25,7 +25,7 @@ package me.lucko.luckperms.sponge.contexts;
import lombok.AllArgsConstructor;
import me.lucko.luckperms.api.context.ContextCalculator;
import me.lucko.luckperms.api.context.MutableContextSet;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import me.lucko.luckperms.sponge.service.base.Util;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.Subject;
@ -38,11 +38,11 @@ public class SpongeCalculatorLink extends ContextCalculator<Subject> {
@Override
public MutableContextSet giveApplicableContext(Subject subject, MutableContextSet accumulator) {
Set<Context> contexts = LuckPermsService.convertContexts(accumulator);
Set<Context> contexts = Util.convertContexts(accumulator);
calculator.accumulateContexts(subject, contexts);
accumulator.clear();
accumulator.addAll(LuckPermsService.convertContexts(contexts));
accumulator.addAll(Util.convertContexts(contexts));
return accumulator;
}

View File

@ -30,6 +30,7 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.NonNull;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.core.model.Group;
import me.lucko.luckperms.common.managers.GroupManager;
@ -38,18 +39,16 @@ import me.lucko.luckperms.common.utils.ImmutableCollectors;
import me.lucko.luckperms.sponge.LPSpongePlugin;
import me.lucko.luckperms.sponge.model.SpongeGroup;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import me.lucko.luckperms.sponge.service.base.LPSubject;
import me.lucko.luckperms.sponge.service.base.LPSubjectCollection;
import me.lucko.luckperms.sponge.service.references.SubjectReference;
import me.lucko.luckperms.sponge.timings.LPTiming;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectCollection;
import org.spongepowered.api.service.permission.SubjectData;
import org.spongepowered.api.util.Tristate;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
public class SpongeGroupManager implements GroupManager, SubjectCollection {
public class SpongeGroupManager implements GroupManager, LPSubjectCollection {
private final LPSpongePlugin plugin;
private final LoadingCache<String, SpongeGroup> objects = CacheBuilder.newBuilder()
@ -120,7 +119,12 @@ public class SpongeGroupManager implements GroupManager, SubjectCollection {
}
@Override
public Subject get(@NonNull String id) {
public LuckPermsService getService() {
return plugin.getService();
}
@Override
public LPSubject get(@NonNull String id) {
// Special Sponge method. This call will actually load the group from the datastore if not already present.
try (Timing ignored = plugin.getTimings().time(LPTiming.GROUP_COLLECTION_GET)) {
@ -159,26 +163,20 @@ public class SpongeGroupManager implements GroupManager, SubjectCollection {
}
@Override
public Iterable<Subject> getAllSubjects() {
public Collection<LPSubject> getSubjects() {
return objects.asMap().values().stream().map(SpongeGroup::getSpongeData).collect(ImmutableCollectors.toImmutableList());
}
@Override
public Map<Subject, Boolean> getAllWithPermission(@NonNull String id) {
return getAllWithPermission(SubjectData.GLOBAL_CONTEXT, id);
}
@Override
public Map<Subject, Boolean> getAllWithPermission(@NonNull Set<Context> contexts, @NonNull String node) {
ContextSet cs = LuckPermsService.convertContexts(contexts);
public Map<LPSubject, Boolean> getWithPermission(@NonNull ContextSet contexts, @NonNull String node) {
return objects.asMap().values().stream()
.map(SpongeGroup::getSpongeData)
.filter(sub -> sub.getPermissionValue(cs, node) != Tristate.UNDEFINED)
.collect(ImmutableCollectors.toImmutableMap(sub -> sub, sub -> sub.getPermissionValue(cs, node).asBoolean()));
.filter(sub -> sub.getPermissionValue(contexts, node) != Tristate.UNDEFINED)
.collect(ImmutableCollectors.toImmutableMap(sub -> sub, sub -> sub.getPermissionValue(contexts, node).asBoolean()));
}
@Override
public Subject getDefaults() {
return plugin.getService().getDefaultSubjects().get(getIdentifier());
public SubjectReference getDefaultSubject() {
return SubjectReference.of("defaults", getIdentifier());
}
}

View File

@ -30,6 +30,7 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.NonNull;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.commands.utils.Util;
import me.lucko.luckperms.common.core.UserIdentifier;
@ -40,19 +41,18 @@ import me.lucko.luckperms.common.utils.ImmutableCollectors;
import me.lucko.luckperms.sponge.LPSpongePlugin;
import me.lucko.luckperms.sponge.model.SpongeUser;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import me.lucko.luckperms.sponge.service.base.LPSubject;
import me.lucko.luckperms.sponge.service.base.LPSubjectCollection;
import me.lucko.luckperms.sponge.service.references.SubjectReference;
import me.lucko.luckperms.sponge.timings.LPTiming;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectCollection;
import org.spongepowered.api.service.permission.SubjectData;
import org.spongepowered.api.util.Tristate;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
public class SpongeUserManager implements UserManager, SubjectCollection {
public class SpongeUserManager implements UserManager, LPSubjectCollection {
private final LPSpongePlugin plugin;
private final LoadingCache<UserIdentifier, SpongeUser> objects = CacheBuilder.newBuilder()
@ -170,7 +170,12 @@ public class SpongeUserManager implements UserManager, SubjectCollection {
}
@Override
public Subject get(@NonNull String id) {
public LuckPermsService getService() {
return plugin.getService();
}
@Override
public LPSubject get(@NonNull String id) {
// Special Sponge method. This call will actually load the user from the datastore if not already present.
try (Timing ignored = plugin.getTimings().time(LPTiming.USER_COLLECTION_GET)) {
@ -217,26 +222,20 @@ public class SpongeUserManager implements UserManager, SubjectCollection {
}
@Override
public Iterable<Subject> getAllSubjects() {
public Collection<LPSubject> getSubjects() {
return objects.asMap().values().stream().map(SpongeUser::getSpongeData).collect(ImmutableCollectors.toImmutableList());
}
@Override
public Map<Subject, Boolean> getAllWithPermission(@NonNull String id) {
return getAllWithPermission(SubjectData.GLOBAL_CONTEXT, id);
}
@Override
public Map<Subject, Boolean> getAllWithPermission(@NonNull Set<Context> contexts, @NonNull String node) {
ContextSet cs = LuckPermsService.convertContexts(contexts);
public Map<LPSubject, Boolean> getWithPermission(@NonNull ContextSet contexts, @NonNull String node) {
return objects.asMap().values().stream()
.map(SpongeUser::getSpongeData)
.filter(sub -> sub.getPermissionValue(cs, node) != Tristate.UNDEFINED)
.collect(ImmutableCollectors.toImmutableMap(sub -> sub, sub -> sub.getPermissionValue(cs, node).asBoolean()));
.filter(sub -> sub.getPermissionValue(contexts, node) != Tristate.UNDEFINED)
.collect(ImmutableCollectors.toImmutableMap(sub -> sub, sub -> sub.getPermissionValue(contexts, node).asBoolean()));
}
@Override
public Subject getDefaults() {
return plugin.getService().getDefaultSubjects().get(getIdentifier());
public SubjectReference getDefaultSubject() {
return SubjectReference.of("defaults", getIdentifier());
}
}

View File

@ -29,7 +29,7 @@ import me.lucko.luckperms.common.core.NodeFactory;
import me.lucko.luckperms.common.core.model.PermissionHolder;
import me.lucko.luckperms.common.utils.ExtractedContexts;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import me.lucko.luckperms.sponge.service.base.Util;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.service.permission.Subject;
@ -47,7 +47,7 @@ public class MigrationUtils {
// Migrate permissions
Map<Set<Context>, Map<String, Boolean>> perms = subject.getSubjectData().getAllPermissions();
for (Map.Entry<Set<Context>, Map<String, Boolean>> e : perms.entrySet()) {
ContextSet context = LuckPermsService.convertContexts(e.getKey());
ContextSet context = Util.convertContexts(e.getKey());
ExtractedContexts extractedContexts = ExtractedContexts.generate(context);
ContextSet contexts = extractedContexts.getContextSet();
@ -65,7 +65,7 @@ public class MigrationUtils {
try {
Map<Set<Context>, Map<String, String>> opts = subject.getSubjectData().getAllOptions();
for (Map.Entry<Set<Context>, Map<String, String>> e : opts.entrySet()) {
ContextSet context = LuckPermsService.convertContexts(e.getKey());
ContextSet context = Util.convertContexts(e.getKey());
ExtractedContexts extractedContexts = ExtractedContexts.generate(context);
ContextSet contexts = extractedContexts.getContextSet();
@ -96,7 +96,7 @@ public class MigrationUtils {
// Migrate parents
Map<Set<Context>, List<Subject>> parents = subject.getSubjectData().getAllParents();
for (Map.Entry<Set<Context>, List<Subject>> e : parents.entrySet()) {
ContextSet context = LuckPermsService.convertContexts(e.getKey());
ContextSet context = Util.convertContexts(e.getKey());
ExtractedContexts extractedContexts = ExtractedContexts.generate(context);
ContextSet contexts = extractedContexts.getContextSet();

View File

@ -23,28 +23,30 @@
package me.lucko.luckperms.sponge.model;
import co.aikar.timings.Timing;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import lombok.Getter;
import me.lucko.luckperms.api.LocalizedNode;
import me.lucko.luckperms.api.MetaUtils;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.core.model.Group;
import me.lucko.luckperms.common.utils.ExtractedContexts;
import me.lucko.luckperms.sponge.LPSpongePlugin;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import me.lucko.luckperms.sponge.service.LuckPermsSubject;
import me.lucko.luckperms.sponge.service.LuckPermsSubjectData;
import me.lucko.luckperms.sponge.service.base.LPSubject;
import me.lucko.luckperms.sponge.service.base.Util;
import me.lucko.luckperms.sponge.service.references.SubjectCollectionReference;
import me.lucko.luckperms.sponge.service.references.SubjectReference;
import me.lucko.luckperms.sponge.timings.LPTiming;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.service.permission.NodeTree;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectCollection;
import org.spongepowered.api.util.Tristate;
import org.spongepowered.api.service.permission.PermissionService;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
public class SpongeGroup extends Group {
@ -57,7 +59,7 @@ public class SpongeGroup extends Group {
this.spongeData = new GroupSubject(plugin, this);
}
public static class GroupSubject extends LuckPermsSubject {
public static class GroupSubject implements LPSubject {
private final SpongeGroup parent;
private final LPSpongePlugin plugin;
@ -79,59 +81,71 @@ public class SpongeGroup extends Group {
return parent.getObjectName();
}
@Override
public Optional<String> getFriendlyIdentifier() {
return Optional.of(parent.getFriendlyName());
}
@Override
public Optional<CommandSource> getCommandSource() {
return Optional.empty();
}
@Override
public SubjectCollection getContainingCollection() {
return plugin.getService().getGroupSubjects();
public SubjectCollectionReference getParentCollection() {
return plugin.getService().getGroupSubjects().toReference();
}
@Override
public LuckPermsService getService() {
return plugin.getService();
}
@Override
public Tristate getPermissionValue(ContextSet contexts, String permission) {
try (Timing ignored = plugin.getTimings().time(LPTiming.GROUP_GET_PERMISSION_VALUE)) {
// TODO move this away from NodeTree
Map<String, Boolean> permissions = parent.getAllNodesFiltered(ExtractedContexts.generate(plugin.getService().calculateContexts(contexts))).stream()
.map(LocalizedNode::getNode)
.collect(Collectors.toMap(Node::getPermission, Node::getValue));
Tristate t = NodeTree.of(permissions).get(permission);
Tristate t = Util.convertTristate(NodeTree.of(permissions).get(permission));
if (t != Tristate.UNDEFINED) {
return t;
}
t = plugin.getService().getGroupSubjects().getDefaults().getPermissionValue(LuckPermsService.convertContexts(contexts), permission);
t = plugin.getService().getGroupSubjects().getDefaultSubject().resolve(getService()).getPermissionValue(contexts, permission);
if (t != Tristate.UNDEFINED) {
return t;
}
t = plugin.getService().getDefaults().getPermissionValue(LuckPermsService.convertContexts(contexts), permission);
t = plugin.getService().getDefaults().getPermissionValue(contexts, permission);
return t;
}
}
@Override
public boolean isChildOf(ContextSet contexts, Subject parent) {
public boolean isChildOf(ContextSet contexts, SubjectReference parent) {
try (Timing ignored = plugin.getTimings().time(LPTiming.GROUP_IS_CHILD_OF)) {
return parent instanceof SpongeGroup && getPermissionValue(contexts, "group." + parent.getIdentifier()).asBoolean();
return parent.getCollection().equals(PermissionService.SUBJECTS_GROUP) && getPermissionValue(contexts, "group." + parent.getIdentifier()).asBoolean();
}
}
@Override
public List<Subject> getParents(ContextSet contexts) {
public Set<SubjectReference> getParents(ContextSet contexts) {
try (Timing ignored = plugin.getTimings().time(LPTiming.GROUP_GET_PARENTS)) {
List<Subject> subjects = parent.getAllNodesFiltered(ExtractedContexts.generate(plugin.getService().calculateContexts(contexts))).stream()
Set<SubjectReference> subjects = parent.getAllNodesFiltered(ExtractedContexts.generate(plugin.getService().calculateContexts(contexts))).stream()
.map(LocalizedNode::getNode)
.filter(Node::isGroupNode)
.map(Node::getGroupName)
.map(s -> plugin.getService().getGroupSubjects().get(s))
.collect(Collectors.toList());
.map(LPSubject::toReference)
.collect(Collectors.toSet());
subjects.addAll(plugin.getService().getGroupSubjects().getDefaults().getParents(LuckPermsService.convertContexts(contexts)));
subjects.addAll(plugin.getService().getDefaults().getParents(LuckPermsService.convertContexts(contexts)));
subjects.addAll(plugin.getService().getGroupSubjects().getDefaultSubject().resolve(getService()).getParents(contexts));
subjects.addAll(plugin.getService().getDefaults().getParents(contexts));
return ImmutableList.copyOf(subjects);
return ImmutableSet.copyOf(subjects);
}
}
@ -153,12 +167,12 @@ public class SpongeGroup extends Group {
return option;
}
option = plugin.getService().getGroupSubjects().getDefaults().getOption(LuckPermsService.convertContexts(contexts), s);
option = plugin.getService().getGroupSubjects().getDefaultSubject().resolve(getService()).getOption(contexts, s);
if (option.isPresent()) {
return option;
}
return plugin.getService().getDefaults().getOption(LuckPermsService.convertContexts(contexts), s);
return plugin.getService().getDefaults().getOption(contexts, s);
}
}

View File

@ -23,25 +23,26 @@
package me.lucko.luckperms.sponge.model;
import co.aikar.timings.Timing;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import lombok.Getter;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.caching.MetaData;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.core.model.User;
import me.lucko.luckperms.sponge.LPSpongePlugin;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import me.lucko.luckperms.sponge.service.LuckPermsSubject;
import me.lucko.luckperms.sponge.service.LuckPermsSubjectData;
import me.lucko.luckperms.sponge.service.base.LPSubject;
import me.lucko.luckperms.sponge.service.references.SubjectCollectionReference;
import me.lucko.luckperms.sponge.service.references.SubjectReference;
import me.lucko.luckperms.sponge.timings.LPTiming;
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.Subject;
import org.spongepowered.api.service.permission.SubjectCollection;
import org.spongepowered.api.util.Tristate;
import org.spongepowered.api.service.permission.PermissionService;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
public class SpongeUser extends User {
@ -59,7 +60,7 @@ public class SpongeUser extends User {
this.spongeData = new UserSubject(plugin, this);
}
public static class UserSubject extends LuckPermsSubject {
public static class UserSubject implements LPSubject {
private final SpongeUser parent;
private final LPSpongePlugin plugin;
@ -98,8 +99,13 @@ public class SpongeUser extends User {
}
@Override
public SubjectCollection getContainingCollection() {
return plugin.getService().getUserSubjects();
public SubjectCollectionReference getParentCollection() {
return plugin.getService().getUserSubjects().toReference();
}
@Override
public LuckPermsService getService() {
return plugin.getService();
}
@Override
@ -109,21 +115,21 @@ public class SpongeUser extends User {
return Tristate.UNDEFINED;
}
return LuckPermsService.convertTristate(parent.getUserData().getPermissionData(plugin.getService().calculateContexts(contexts)).getPermissionValue(permission));
return parent.getUserData().getPermissionData(plugin.getService().calculateContexts(contexts)).getPermissionValue(permission);
}
}
@Override
public boolean isChildOf(ContextSet contexts, Subject parent) {
public boolean isChildOf(ContextSet contexts, SubjectReference parent) {
try (Timing ignored = plugin.getTimings().time(LPTiming.USER_IS_CHILD_OF)) {
return parent instanceof SpongeGroup && getPermissionValue(contexts, "group." + parent.getIdentifier()).asBoolean();
return parent.getCollection().equals(PermissionService.SUBJECTS_GROUP) && getPermissionValue(contexts, "group." + parent.getIdentifier()).asBoolean();
}
}
@Override
public List<Subject> getParents(ContextSet contexts) {
public Set<SubjectReference> getParents(ContextSet contexts) {
try (Timing ignored = plugin.getTimings().time(LPTiming.USER_GET_PARENTS)) {
ImmutableList.Builder<Subject> subjects = ImmutableList.builder();
ImmutableSet.Builder<SubjectReference> subjects = ImmutableSet.builder();
if (hasData()) {
for (String perm : parent.getUserData().getPermissionData(plugin.getService().calculateContexts(contexts)).getImmutableBacking().keySet()) {
@ -133,13 +139,13 @@ public class SpongeUser extends User {
String groupName = perm.substring("group.".length());
if (plugin.getGroupManager().isLoaded(groupName)) {
subjects.add(plugin.getService().getGroupSubjects().get(groupName));
subjects.add(plugin.getService().getGroupSubjects().get(groupName).toReference());
}
}
}
subjects.addAll(plugin.getService().getUserSubjects().getDefaults().getParents(LuckPermsService.convertContexts(contexts)));
subjects.addAll(plugin.getService().getDefaults().getParents(LuckPermsService.convertContexts(contexts)));
subjects.addAll(plugin.getService().getUserSubjects().getDefaultSubject().resolve(getService()).getParents(contexts));
subjects.addAll(plugin.getService().getDefaults().getParents(contexts));
return subjects.build();
}
@ -167,12 +173,12 @@ public class SpongeUser extends User {
}
}
Optional<String> v = plugin.getService().getUserSubjects().getDefaults().getOption(LuckPermsService.convertContexts(contexts), s);
Optional<String> v = plugin.getService().getUserSubjects().getDefaultSubject().resolve(getService()).getOption(contexts, s);
if (v.isPresent()) {
return v;
}
return plugin.getService().getDefaults().getOption(LuckPermsService.convertContexts(contexts), s);
return plugin.getService().getDefaults().getOption(contexts, s);
}
}
@ -184,5 +190,4 @@ public class SpongeUser extends User {
}
}
}

View File

@ -28,31 +28,40 @@ import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.collect.MapMaker;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.*;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.utils.ImmutableCollectors;
import me.lucko.luckperms.sponge.LPSpongePlugin;
import me.lucko.luckperms.sponge.contexts.SpongeCalculatorLink;
import me.lucko.luckperms.sponge.managers.SpongeGroupManager;
import me.lucko.luckperms.sponge.managers.SpongeUserManager;
import me.lucko.luckperms.sponge.service.base.LPSubject;
import me.lucko.luckperms.sponge.service.base.LPSubjectCollection;
import me.lucko.luckperms.sponge.service.base.LPSubjectData;
import me.lucko.luckperms.sponge.service.calculated.OptionLookup;
import me.lucko.luckperms.sponge.service.calculated.PermissionLookup;
import me.lucko.luckperms.sponge.service.persisted.PersistedCollection;
import me.lucko.luckperms.sponge.service.persisted.SubjectStorage;
import me.lucko.luckperms.sponge.service.references.SubjectReference;
import me.lucko.luckperms.sponge.service.simple.SimpleCollection;
import me.lucko.luckperms.sponge.timings.LPTiming;
import org.spongepowered.api.plugin.PluginContainer;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.context.ContextCalculator;
import org.spongepowered.api.service.permission.*;
import org.spongepowered.api.service.permission.PermissionDescription;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectCollection;
import org.spongepowered.api.text.Text;
import org.spongepowered.api.util.Tristate;
import java.io.File;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
/**
* The LuckPerms implementation of the Sponge Permission Service
@ -70,16 +79,20 @@ public class LuckPermsService implements PermissionService {
private final PersistedCollection defaultSubjects;
private final Set<PermissionDescription> descriptionSet;
private final Set<LoadingCache<PermissionLookup, Tristate>> localPermissionCaches;
private final Set<LoadingCache<Set<Context>, List<SubjectReference>>> localParentCaches;
private final Set<LoadingCache<OptionLookup, Optional<String>>> localOptionCaches;
@Getter(value = AccessLevel.NONE)
private final LoadingCache<String, SubjectCollection> collections = CacheBuilder.newBuilder()
.build(new CacheLoader<String, SubjectCollection>() {
private final LoadingCache<String, LPSubjectCollection> collections = CacheBuilder.newBuilder()
.build(new CacheLoader<String, LPSubjectCollection>() {
@Override
public SubjectCollection load(String s) {
public LPSubjectCollection load(String s) {
return new SimpleCollection(LuckPermsService.this, s);
}
@Override
public ListenableFuture<SubjectCollection> reload(String s, SubjectCollection collection) {
public ListenableFuture<LPSubjectCollection> reload(String s, LPSubjectCollection collection) {
return Futures.immediateFuture(collection); // Never needs to be refreshed.
}
});
@ -87,6 +100,10 @@ public class LuckPermsService implements PermissionService {
public LuckPermsService(LPSpongePlugin plugin) {
this.plugin = plugin;
localPermissionCaches = Collections.newSetFromMap(new MapMaker().weakKeys().makeMap());
localParentCaches = Collections.newSetFromMap(new MapMaker().weakKeys().makeMap());
localOptionCaches = Collections.newSetFromMap(new MapMaker().weakKeys().makeMap());
storage = new SubjectStorage(new File(plugin.getDataFolder(), "local"));
userSubjects = plugin.getUserManager();
@ -105,25 +122,30 @@ public class LuckPermsService implements PermissionService {
descriptionSet = ConcurrentHashMap.newKeySet();
}
public SubjectData getDefaultData() {
public LPSubjectData getDefaultData() {
return getDefaults().getSubjectData();
}
@Override
public Subject getDefaults() {
public LPSubject getDefaults() {
return getDefaultSubjects().get("default");
}
@Override
public SubjectCollection getSubjects(String s) {
public LPSubjectCollection getSubjects(String s) {
try (Timing ignored = plugin.getTimings().time(LPTiming.GET_SUBJECTS)) {
return collections.getUnchecked(s.toLowerCase());
}
}
public Map<String, LPSubjectCollection> getCollections() {
return ImmutableMap.copyOf(collections.asMap());
}
@Deprecated
@Override
public Map<String, SubjectCollection> getKnownSubjects() {
return ImmutableMap.copyOf(collections.asMap());
return getCollections().entrySet().stream().collect(ImmutableCollectors.toImmutableMap(Map.Entry::getKey, Map.Entry::getValue));
}
@Override
@ -169,36 +191,6 @@ public class LuckPermsService implements PermissionService {
);
}
public static ContextSet convertContexts(Set<Context> contexts) {
return ContextSet.fromEntries(contexts.stream().map(c -> Maps.immutableEntry(c.getKey(), c.getValue())).collect(Collectors.toSet()));
}
public static Set<Context> convertContexts(ContextSet contexts) {
return contexts.toSet().stream().map(e -> new Context(e.getKey(), e.getValue())).collect(Collectors.toSet());
}
public static Tristate convertTristate(me.lucko.luckperms.api.Tristate tristate) {
switch (tristate) {
case TRUE:
return Tristate.TRUE;
case FALSE:
return Tristate.FALSE;
default:
return Tristate.UNDEFINED;
}
}
public static me.lucko.luckperms.api.Tristate convertTristate(Tristate tristate) {
switch (tristate) {
case TRUE:
return me.lucko.luckperms.api.Tristate.TRUE;
case FALSE:
return me.lucko.luckperms.api.Tristate.FALSE;
default:
return me.lucko.luckperms.api.Tristate.UNDEFINED;
}
}
@RequiredArgsConstructor
@EqualsAndHashCode
@ToString
@ -241,10 +233,10 @@ public class LuckPermsService implements PermissionService {
service.getDescriptionSet().add(d);
// Set role-templates
SubjectCollection subjects = service.getSubjects(PermissionService.SUBJECTS_ROLE_TEMPLATE);
LPSubjectCollection subjects = service.getSubjects(PermissionService.SUBJECTS_ROLE_TEMPLATE);
for (Map.Entry<String, Tristate> assignment : roles.entrySet()) {
Subject subject = subjects.get(assignment.getKey());
subject.getTransientSubjectData().setPermission(SubjectData.GLOBAL_CONTEXT, id, assignment.getValue());
LPSubject subject = subjects.get(assignment.getKey());
subject.getTransientSubjectData().setPermission(ContextSet.empty(), id, assignment.getValue());
}
service.getPlugin().getPermissionCache().offer(id);

View File

@ -1,104 +0,0 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.sponge.service;
import com.google.common.collect.ImmutableSet;
import lombok.NonNull;
import me.lucko.luckperms.api.context.ContextSet;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.util.Tristate;
import java.util.List;
import java.util.Optional;
import java.util.Set;
public abstract class LuckPermsSubject implements Subject {
public abstract Tristate getPermissionValue(ContextSet contexts, String permission);
public abstract boolean isChildOf(ContextSet contexts, Subject parent);
public abstract List<Subject> getParents(ContextSet contexts);
public abstract Optional<String> getOption(ContextSet contexts, String s);
public abstract ContextSet getActiveContextSet();
@Override
@Deprecated
public Tristate getPermissionValue(@NonNull Set<Context> contexts, @NonNull String permission) {
return getPermissionValue(LuckPermsService.convertContexts(contexts), permission);
}
@Override
@Deprecated
public boolean hasPermission(@NonNull Set<Context> contexts, @NonNull String permission) {
return getPermissionValue(LuckPermsService.convertContexts(contexts), permission).asBoolean();
}
@Override
@Deprecated
public boolean hasPermission(@NonNull String permission) {
return getPermissionValue(getActiveContextSet(), permission).asBoolean();
}
@Override
@Deprecated
public boolean isChildOf(@NonNull Set<Context> contexts, @NonNull Subject parent) {
return isChildOf(LuckPermsService.convertContexts(contexts), parent);
}
@Override
@Deprecated
public boolean isChildOf(@NonNull Subject parent) {
return isChildOf(getActiveContextSet(), parent);
}
@Override
@Deprecated
public List<Subject> getParents(@NonNull Set<Context> contexts) {
return getParents(LuckPermsService.convertContexts(contexts));
}
@Override
@Deprecated
public List<Subject> getParents() {
return getParents(getActiveContextSet());
}
@Override
@Deprecated
public Optional<String> getOption(@NonNull Set<Context> contexts, @NonNull String s) {
return getOption(LuckPermsService.convertContexts(contexts), s);
}
@Override
@Deprecated
public Optional<String> getOption(@NonNull String key) {
return getOption(getActiveContextSet(), key);
}
@Override
@Deprecated
public Set<Context> getActiveContexts() {
return ImmutableSet.copyOf(LuckPermsService.convertContexts(getActiveContextSet()));
}
}

View File

@ -23,14 +23,15 @@
package me.lucko.luckperms.sponge.service;
import co.aikar.timings.Timing;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NonNull;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.MutableContextSet;
import me.lucko.luckperms.common.core.NodeBuilder;
import me.lucko.luckperms.common.core.NodeFactory;
import me.lucko.luckperms.common.core.model.Group;
@ -39,18 +40,19 @@ import me.lucko.luckperms.common.core.model.User;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import me.lucko.luckperms.sponge.model.SpongeGroup;
import me.lucko.luckperms.sponge.service.base.LPSubject;
import me.lucko.luckperms.sponge.service.base.LPSubjectData;
import me.lucko.luckperms.sponge.service.references.SubjectReference;
import me.lucko.luckperms.sponge.timings.LPTiming;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectData;
import org.spongepowered.api.util.Tristate;
import org.spongepowered.api.service.permission.PermissionService;
import java.util.*;
import java.util.stream.Collectors;
@SuppressWarnings({"OptionalGetWithoutIsPresent", "unused"})
@AllArgsConstructor
public class LuckPermsSubjectData implements SubjectData {
public class LuckPermsSubjectData implements LPSubjectData {
private final boolean enduring;
private final LuckPermsService service;
@ -69,12 +71,17 @@ public class LuckPermsSubjectData implements SubjectData {
}
@Override
public Map<Set<Context>, Map<String, Boolean>> getAllPermissions() {
public LPSubject getParentSubject() {
return null;
}
@Override
public Map<ContextSet, Map<String, Boolean>> getPermissions() {
try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_GET_PERMISSIONS)) {
Map<Set<Context>, Map<String, Boolean>> perms = new HashMap<>();
Map<ContextSet, Map<String, Boolean>> perms = new HashMap<>();
for (Node n : enduring ? holder.getNodes() : holder.getTransientNodes()) {
Set<Context> contexts = LuckPermsService.convertContexts(n.getContexts());
MutableContextSet contexts = MutableContextSet.fromSet(n.getContexts());
if (n.isServerSpecific()) {
contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get()));
@ -85,41 +92,32 @@ public class LuckPermsSubjectData implements SubjectData {
}
if (!perms.containsKey(contexts)) {
perms.put(contexts, new HashMap<>());
perms.put(contexts.makeImmutable(), new HashMap<>());
}
perms.get(contexts).put(n.getPermission(), n.getValue());
}
ImmutableMap.Builder<Set<Context>, Map<String, Boolean>> map = ImmutableMap.builder();
for (Map.Entry<Set<Context>, Map<String, Boolean>> e : perms.entrySet()) {
map.put(ImmutableSet.copyOf(e.getKey()), ImmutableMap.copyOf(e.getValue()));
ImmutableMap.Builder<ContextSet, Map<String, Boolean>> map = ImmutableMap.builder();
for (Map.Entry<ContextSet, Map<String, Boolean>> e : perms.entrySet()) {
map.put(e.getKey().makeImmutable(), ImmutableMap.copyOf(e.getValue()));
}
return map.build();
}
}
@Override
public Map<String, Boolean> getPermissions(@NonNull Set<Context> contexts) {
return getAllPermissions().getOrDefault(contexts, ImmutableMap.of());
}
@Override
public boolean setPermission(@NonNull Set<Context> contexts, @NonNull String permission, @NonNull Tristate tristate) {
public boolean setPermission(@NonNull ContextSet contexts, @NonNull String permission, @NonNull Tristate tristate) {
try (Timing i = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_SET_PERMISSION)) {
if (tristate == Tristate.UNDEFINED) {
// Unset
Node.Builder builder = new NodeBuilder(permission);
for (Context ct : contexts) {
builder.withExtraContext(ct.getKey(), ct.getValue());
}
Node node = new NodeBuilder(permission).withExtraContext(contexts).build();
try {
if (enduring) {
holder.unsetPermission(builder.build());
holder.unsetPermission(node);
} else {
holder.unsetTransientPermission(builder.build());
holder.unsetTransientPermission(node);
}
} catch (ObjectLacksException ignored) {}
@ -127,14 +125,7 @@ public class LuckPermsSubjectData implements SubjectData {
return true;
}
Node.Builder builder = new NodeBuilder(permission)
.setValue(tristate.asBoolean());
for (Context ct : contexts) {
builder.withExtraContext(ct.getKey(), ct.getValue());
}
Node node = builder.build();
Node node = new NodeBuilder(permission).setValue(tristate.asBoolean()).withExtraContext(contexts).build();
// Workaround: unset the inverse, to allow false -> true, true -> false overrides.
try {
@ -172,11 +163,11 @@ public class LuckPermsSubjectData implements SubjectData {
}
@Override
public boolean clearPermissions(@NonNull Set<Context> c) {
public boolean clearPermissions(@NonNull ContextSet c) {
try (Timing i = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_CLEAR_PERMISSIONS)) {
List<Node> toRemove = new ArrayList<>();
for (Node n : enduring ? holder.getNodes() : holder.getTransientNodes()) {
Set<Context> contexts = LuckPermsService.convertContexts(n.getContexts());
MutableContextSet contexts = MutableContextSet.fromSet(n.getContexts());
if (n.isServerSpecific()) {
contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get()));
@ -211,16 +202,16 @@ public class LuckPermsSubjectData implements SubjectData {
}
@Override
public Map<Set<Context>, List<Subject>> getAllParents() {
public Map<ContextSet, Set<SubjectReference>> getParents() {
try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_GET_PARENTS)) {
Map<Set<Context>, List<Subject>> parents = new HashMap<>();
Map<ContextSet, Set<SubjectReference>> parents = new HashMap<>();
for (Node n : enduring ? holder.getNodes() : holder.getTransientNodes()) {
if (!n.isGroupNode()) {
continue;
}
Set<Context> contexts = LuckPermsService.convertContexts(n.getContexts());
MutableContextSet contexts = MutableContextSet.fromSet(n.getContexts());
if (n.isServerSpecific()) {
contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get()));
@ -231,31 +222,25 @@ public class LuckPermsSubjectData implements SubjectData {
}
if (!parents.containsKey(contexts)) {
parents.put(contexts, new ArrayList<>());
parents.put(contexts.makeImmutable(), new HashSet<>());
}
parents.get(contexts).add(service.getGroupSubjects().get(n.getGroupName()));
parents.get(contexts).add(service.getGroupSubjects().get(n.getGroupName()).toReference());
}
ImmutableMap.Builder<Set<Context>, List<Subject>> map = ImmutableMap.builder();
for (Map.Entry<Set<Context>, List<Subject>> e : parents.entrySet()) {
map.put(ImmutableSet.copyOf(e.getKey()), ImmutableList.copyOf(e.getValue()));
ImmutableMap.Builder<ContextSet, Set<SubjectReference>> map = ImmutableMap.builder();
for (Map.Entry<ContextSet, Set<SubjectReference>> e : parents.entrySet()) {
map.put(e.getKey().makeImmutable(), ImmutableSet.copyOf(e.getValue()));
}
return map.build();
}
}
@Override
public List<Subject> getParents(@NonNull Set<Context> contexts) {
return getAllParents().getOrDefault(contexts, ImmutableList.of());
}
@Override
public boolean addParent(@NonNull Set<Context> set, @NonNull Subject subject) {
public boolean addParent(@NonNull ContextSet contexts, @NonNull SubjectReference subject) {
try (Timing i = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_ADD_PARENT)) {
if (subject instanceof SpongeGroup) {
SpongeGroup permsSubject = ((SpongeGroup) subject);
ContextSet contexts = LuckPermsService.convertContexts(set);
if (subject.getCollection().equals(PermissionService.SUBJECTS_GROUP)) {
SpongeGroup permsSubject = ((SpongeGroup) subject.resolve(service));
try {
if (enduring) {
@ -277,11 +262,10 @@ public class LuckPermsSubjectData implements SubjectData {
}
@Override
public boolean removeParent(@NonNull Set<Context> set, @NonNull Subject subject) {
public boolean removeParent(@NonNull ContextSet contexts, @NonNull SubjectReference subject) {
try (Timing i = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_REMOVE_PARENT)) {
if (subject instanceof SpongeGroup) {
SpongeGroup permsSubject = ((SpongeGroup) subject);
ContextSet contexts = LuckPermsService.convertContexts(set);
if (subject.getCollection().equals(PermissionService.SUBJECTS_GROUP)) {
SpongeGroup permsSubject = ((SpongeGroup) subject.resolve(service));
try {
if (enduring) {
@ -329,7 +313,7 @@ public class LuckPermsSubjectData implements SubjectData {
}
@Override
public boolean clearParents(@NonNull Set<Context> set) {
public boolean clearParents(@NonNull ContextSet set) {
try (Timing i = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_CLEAR_PARENTS)) {
List<Node> toRemove = new ArrayList<>();
for (Node n : enduring ? holder.getNodes() : holder.getTransientNodes()) {
@ -337,7 +321,7 @@ public class LuckPermsSubjectData implements SubjectData {
continue;
}
Set<Context> contexts = LuckPermsService.convertContexts(n.getContexts());
MutableContextSet contexts = MutableContextSet.fromSet(n.getContexts());
if (n.isServerSpecific()) {
contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get()));
@ -372,11 +356,11 @@ public class LuckPermsSubjectData implements SubjectData {
}
@Override
public Map<Set<Context>, Map<String, String>> getAllOptions() {
public Map<ContextSet, Map<String, String>> getOptions() {
try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_GET_OPTIONS)) {
Map<Set<Context>, Map<String, String>> options = new HashMap<>();
Map<Set<Context>, Integer> minPrefixPriority = new HashMap<>();
Map<Set<Context>, Integer> minSuffixPriority = new HashMap<>();
Map<ContextSet, Map<String, String>> options = new HashMap<>();
Map<ContextSet, Integer> minPrefixPriority = new HashMap<>();
Map<ContextSet, Integer> minSuffixPriority = new HashMap<>();
for (Node n : enduring ? holder.getNodes() : holder.getTransientNodes()) {
if (!n.getValue()) {
@ -387,7 +371,7 @@ public class LuckPermsSubjectData implements SubjectData {
continue;
}
Set<Context> contexts = LuckPermsService.convertContexts(n.getContexts());
MutableContextSet contexts = MutableContextSet.fromSet(n.getContexts());
if (n.isServerSpecific()) {
contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get()));
@ -427,24 +411,17 @@ public class LuckPermsSubjectData implements SubjectData {
}
}
ImmutableMap.Builder<Set<Context>, Map<String, String>> map = ImmutableMap.builder();
for (Map.Entry<Set<Context>, Map<String, String>> e : options.entrySet()) {
map.put(ImmutableSet.copyOf(e.getKey()), ImmutableMap.copyOf(e.getValue()));
ImmutableMap.Builder<ContextSet, Map<String, String>> map = ImmutableMap.builder();
for (Map.Entry<ContextSet, Map<String, String>> e : options.entrySet()) {
map.put(e.getKey().makeImmutable(), ImmutableMap.copyOf(e.getValue()));
}
return map.build();
}
}
@Override
public Map<String, String> getOptions(@NonNull Set<Context> set) {
return getAllOptions().getOrDefault(set, ImmutableMap.of());
}
@Override
public boolean setOption(@NonNull Set<Context> set, @NonNull String key, @NonNull String value) {
public boolean setOption(@NonNull ContextSet context, @NonNull String key, @NonNull String value) {
try (Timing i = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_SET_OPTION)) {
ContextSet context = LuckPermsService.convertContexts(set);
List<Node> toRemove = holder.getNodes().stream()
.filter(n -> n.isMeta() && n.getMeta().getKey().equals(key))
.collect(Collectors.toList());
@ -468,7 +445,25 @@ public class LuckPermsSubjectData implements SubjectData {
}
@Override
public boolean clearOptions(@NonNull Set<Context> set) {
public boolean unsetOption(ContextSet contexts, String key) {
try (Timing i = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_SET_OPTION)) {
List<Node> toRemove = holder.getNodes().stream()
.filter(n -> n.isMeta() && n.getMeta().getKey().equals(key))
.collect(Collectors.toList());
toRemove.forEach(n -> {
try {
holder.unsetPermission(n);
} catch (ObjectLacksException ignored) {}
});
objectSave(holder);
return true;
}
}
@Override
public boolean clearOptions(@NonNull ContextSet set) {
try (Timing i = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_CLEAR_OPTIONS)) {
List<Node> toRemove = new ArrayList<>();
for (Node n : enduring ? holder.getNodes() : holder.getTransientNodes()) {
@ -476,7 +471,7 @@ public class LuckPermsSubjectData implements SubjectData {
continue;
}
Set<Context> contexts = LuckPermsService.convertContexts(n.getContexts());
MutableContextSet contexts = MutableContextSet.fromSet(n.getContexts());
if (n.isServerSpecific()) {
contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get()));

View File

@ -0,0 +1,149 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.sponge.service.base;
import lombok.NonNull;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.utils.ImmutableCollectors;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import me.lucko.luckperms.sponge.service.references.SubjectCollectionReference;
import me.lucko.luckperms.sponge.service.references.SubjectReference;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.util.Tristate;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import static me.lucko.luckperms.sponge.service.base.Util.convertContexts;
import static me.lucko.luckperms.sponge.service.base.Util.convertTristate;
public interface LPSubject extends Subject {
@Override
String getIdentifier();
default Optional<String> getFriendlyIdentifier() {
return Optional.empty();
}
@Override
default Optional<CommandSource> getCommandSource() {
return Optional.empty();
}
SubjectCollectionReference getParentCollection();
LuckPermsService getService();
default SubjectReference toReference() {
return SubjectReference.of(getParentCollection().getCollection(), getIdentifier());
}
@Override
LPSubjectData getSubjectData();
@Override
LPSubjectData getTransientSubjectData();
me.lucko.luckperms.api.Tristate getPermissionValue(ContextSet contexts, String permission);
boolean isChildOf(ContextSet contexts, SubjectReference parent);
Set<SubjectReference> getParents(ContextSet contexts);
Optional<String> getOption(ContextSet contexts, String key);
ContextSet getActiveContextSet();
/* Compat */
@Deprecated
@Override
default LPSubjectCollection getContainingCollection() {
return getParentCollection().resolve(getService());
}
@Deprecated
@Override
default boolean hasPermission(@NonNull Set<Context> contexts, @NonNull String permission) {
return getPermissionValue(convertContexts(contexts), permission).asBoolean();
}
@Deprecated
@Override
default boolean hasPermission(@NonNull String permission) {
return getPermissionValue(getActiveContextSet(), permission).asBoolean();
}
@Deprecated
@Override
default Tristate getPermissionValue(@NonNull Set<Context> contexts, @NonNull String permission) {
return convertTristate(getPermissionValue(convertContexts(contexts), permission));
}
@Deprecated
@Override
default boolean isChildOf(@NonNull Subject parent) {
return isChildOf(getActiveContextSet(), SubjectReference.of(parent));
}
@Deprecated
@Override
default boolean isChildOf(@NonNull Set<Context> contexts, @NonNull Subject parent) {
return isChildOf(convertContexts(contexts), SubjectReference.of(parent));
}
@Deprecated
@Override
default List<Subject> getParents() {
return getParents(getActiveContextSet()).stream().map(s -> s.resolve(getService())).collect(ImmutableCollectors.toImmutableList());
}
@Deprecated
@Override
default List<Subject> getParents(@NonNull Set<Context> contexts) {
return getParents(convertContexts(contexts)).stream().map(s -> s.resolve(getService())).collect(ImmutableCollectors.toImmutableList());
}
@Deprecated
@Override
default Optional<String> getOption(@NonNull String key) {
return getOption(getActiveContextSet(), key);
}
@Deprecated
@Override
default Optional<String> getOption(@NonNull Set<Context> contexts, @NonNull String key) {
return getOption(getActiveContextSet(), key);
}
@Deprecated
@Override
default Set<Context> getActiveContexts() {
return convertContexts(getActiveContextSet());
}
}

View File

@ -0,0 +1,92 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.sponge.service.base;
import lombok.NonNull;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.utils.ImmutableCollectors;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import me.lucko.luckperms.sponge.service.references.SubjectCollectionReference;
import me.lucko.luckperms.sponge.service.references.SubjectReference;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectCollection;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import static me.lucko.luckperms.sponge.service.base.Util.convertContexts;
public interface LPSubjectCollection extends SubjectCollection {
@Override
String getIdentifier();
LuckPermsService getService();
default SubjectCollectionReference toReference() {
return SubjectCollectionReference.of(getIdentifier());
}
@Override
LPSubject get(String identifier);
@Override
boolean hasRegistered(String identifier);
Collection<LPSubject> getSubjects();
default Map<LPSubject, Boolean> getWithPermission(String permission) {
return getWithPermission(ContextSet.empty(), permission);
}
Map<LPSubject, Boolean> getWithPermission(ContextSet contexts, String permission);
SubjectReference getDefaultSubject();
@Deprecated
@Override
default Subject getDefaults() {
return getDefaultSubject().resolve(getService());
}
@Deprecated
@Override
default Iterable<Subject> getAllSubjects() {
return getSubjects().stream().collect(ImmutableCollectors.toImmutableList());
}
@Deprecated
@Override
default Map<Subject, Boolean> getAllWithPermission(@NonNull String permission) {
return getWithPermission(permission).entrySet().stream().collect(ImmutableCollectors.toImmutableMap(Map.Entry::getKey, Map.Entry::getValue));
}
@Deprecated
@Override
default Map<Subject, Boolean> getAllWithPermission(@NonNull Set<Context> contexts, @NonNull String permission) {
return getWithPermission(convertContexts(contexts), permission).entrySet().stream().collect(ImmutableCollectors.toImmutableMap(Map.Entry::getKey, Map.Entry::getValue));
}
}

View File

@ -0,0 +1,187 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.sponge.service.base;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.utils.ImmutableCollectors;
import me.lucko.luckperms.sponge.service.references.SubjectReference;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectData;
import org.spongepowered.api.util.Tristate;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static me.lucko.luckperms.sponge.service.base.Util.convertContexts;
import static me.lucko.luckperms.sponge.service.base.Util.convertTristate;
public interface LPSubjectData extends SubjectData {
LPSubject getParentSubject();
Map<ContextSet, Map<String, Boolean>> getPermissions();
default Map<String, Boolean> getPermissions(ContextSet contexts) {
return ImmutableMap.copyOf(getPermissions().getOrDefault(contexts, ImmutableMap.of()));
}
boolean setPermission(ContextSet contexts, String permission, me.lucko.luckperms.api.Tristate value);
@Override
boolean clearPermissions();
boolean clearPermissions(ContextSet contexts);
Map<ContextSet, Set<SubjectReference>> getParents();
default Set<SubjectReference> getParents(ContextSet contexts) {
return ImmutableSet.copyOf(getParents().getOrDefault(contexts, ImmutableSet.of()));
}
boolean addParent(ContextSet contexts, SubjectReference parent);
boolean removeParent(ContextSet contexts, SubjectReference parent);
@Override
boolean clearParents();
boolean clearParents(ContextSet contexts);
Map<ContextSet, Map<String, String>> getOptions();
default Map<String, String> getOptions(ContextSet contexts) {
return ImmutableMap.copyOf(getOptions().getOrDefault(contexts, ImmutableMap.of()));
}
boolean setOption(ContextSet contexts, String key, String value);
boolean unsetOption(ContextSet contexts, String key);
boolean clearOptions(ContextSet contexts);
@Override
boolean clearOptions();
/* Compat */
@Deprecated
@Override
default Map<Set<Context>, Map<String, Boolean>> getAllPermissions() {
return getPermissions().entrySet().stream()
.collect(ImmutableCollectors.toImmutableMap(
e -> convertContexts(e.getKey()),
e -> ImmutableMap.copyOf(e.getValue()))
);
}
@Deprecated
@Override
default Map<String, Boolean> getPermissions(Set<Context> contexts) {
return ImmutableMap.copyOf(getPermissions(convertContexts(contexts)));
}
@Deprecated
@Override
default boolean setPermission(Set<Context> contexts, String permission, Tristate value) {
return setPermission(convertContexts(contexts), permission, convertTristate(value));
}
@Deprecated
@Override
default boolean clearPermissions(Set<Context> contexts) {
return clearPermissions(convertContexts(contexts));
}
@Deprecated
@Override
default Map<Set<Context>, List<Subject>> getAllParents() {
return getParents().entrySet().stream()
.collect(ImmutableCollectors.toImmutableMap(
e -> convertContexts(e.getKey()),
e -> e.getValue().stream()
.map(s -> s.resolve(getParentSubject().getService()))
.collect(ImmutableCollectors.toImmutableList())
)
);
}
@Deprecated
@Override
default List<Subject> getParents(Set<Context> contexts) {
return getParents(convertContexts(contexts)).stream().map(s -> s.resolve(getParentSubject().getService())).collect(ImmutableCollectors.toImmutableList());
}
@Deprecated
@Override
default boolean addParent(Set<Context> contexts, Subject parent) {
return addParent(convertContexts(contexts), SubjectReference.of(parent));
}
@Deprecated
@Override
default boolean removeParent(Set<Context> contexts, Subject parent) {
return removeParent(convertContexts(contexts), SubjectReference.of(parent));
}
@Deprecated
@Override
default boolean clearParents(Set<Context> contexts) {
return clearParents(convertContexts(contexts));
}
@Deprecated
@Override
default Map<Set<Context>, Map<String, String>> getAllOptions() {
return getOptions().entrySet().stream()
.collect(ImmutableCollectors.toImmutableMap(
e -> convertContexts(e.getKey()),
e -> ImmutableMap.copyOf(e.getValue()))
);
}
@Deprecated
@Override
default Map<String, String> getOptions(Set<Context> contexts) {
return ImmutableMap.copyOf(getOptions(convertContexts(contexts)));
}
@Deprecated
@Override
default boolean setOption(Set<Context> contexts, String key, @Nullable String value) {
return value == null ? unsetOption(convertContexts(contexts), key) : setOption(convertContexts(contexts), key, value);
}
@Deprecated
@Override
default boolean clearOptions(Set<Context> contexts) {
return clearOptions(convertContexts(contexts));
}
}

View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.sponge.service.base;
import com.google.common.collect.Maps;
import lombok.experimental.UtilityClass;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.utils.ImmutableCollectors;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.util.Tristate;
import java.util.Set;
import java.util.stream.Collectors;
@UtilityClass
public class Util {
public static ContextSet convertContexts(Set<Context> contexts) {
return ContextSet.fromEntries(contexts.stream().map(c -> Maps.immutableEntry(c.getKey(), c.getValue())).collect(Collectors.toSet()));
}
public static Set<Context> convertContexts(ContextSet contexts) {
return contexts.toSet().stream().map(e -> new Context(e.getKey(), e.getValue())).collect(ImmutableCollectors.toImmutableSet());
}
public static Tristate convertTristate(me.lucko.luckperms.api.Tristate tristate) {
switch (tristate) {
case TRUE:
return Tristate.TRUE;
case FALSE:
return Tristate.FALSE;
default:
return Tristate.UNDEFINED;
}
}
public static me.lucko.luckperms.api.Tristate convertTristate(Tristate tristate) {
switch (tristate) {
case TRUE:
return me.lucko.luckperms.api.Tristate.TRUE;
case FALSE:
return me.lucko.luckperms.api.Tristate.FALSE;
default:
return me.lucko.luckperms.api.Tristate.UNDEFINED;
}
}
}

View File

@ -20,7 +20,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.sponge.service.data;
package me.lucko.luckperms.sponge.service.calculated;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
@ -31,32 +31,34 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMap;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.calculators.PermissionCalculator;
import me.lucko.luckperms.common.calculators.PermissionProcessor;
import me.lucko.luckperms.common.calculators.processors.MapProcessor;
import me.lucko.luckperms.common.utils.ImmutableCollectors;
import me.lucko.luckperms.sponge.calculators.SpongeWildcardProcessor;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectData;
import org.spongepowered.api.util.Tristate;
import me.lucko.luckperms.sponge.service.base.LPSubject;
import me.lucko.luckperms.sponge.service.base.LPSubjectData;
import me.lucko.luckperms.sponge.service.references.SubjectReference;
import javax.annotation.Nullable;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@RequiredArgsConstructor
public class CalculatedSubjectData implements SubjectData {
public class CalculatedSubjectData implements LPSubjectData {
private static final ContextComparator CONTEXT_COMPARATOR = new ContextComparator();
@Getter
private final LPSubject parentSubject;
private final LuckPermsService service;
private final String calculatorDisplayName;
private final LoadingCache<Set<Context>, CalculatorHolder> permissionCache = CacheBuilder.newBuilder()
.build(new CacheLoader<Set<Context>, CalculatorHolder>() {
private final LoadingCache<ContextSet, CalculatorHolder> permissionCache = CacheBuilder.newBuilder()
.build(new CacheLoader<ContextSet, CalculatorHolder>() {
@Override
public CalculatorHolder load(Set<Context> contexts) {
public CalculatorHolder load(ContextSet contexts) {
ImmutableList.Builder<PermissionProcessor> processors = ImmutableList.builder();
processors.add(new MapProcessor());
processors.add(new SpongeWildcardProcessor());
@ -68,77 +70,69 @@ public class CalculatedSubjectData implements SubjectData {
}
});
private final LoadingCache<Set<Context>, Map<String, String>> optionCache = CacheBuilder.newBuilder()
.build(new CacheLoader<Set<Context>, Map<String, String>>() {
private final LoadingCache<ContextSet, Map<String, String>> optionCache = CacheBuilder.newBuilder()
.build(new CacheLoader<ContextSet, Map<String, String>>() {
@Override
public Map<String, String> load(Set<Context> contexts) {
public Map<String, String> load(ContextSet contexts) {
return flattenMap(contexts, options);
}
});
private final Map<Set<Context>, Map<String, Boolean>> permissions = new ConcurrentHashMap<>();
private final Map<Set<Context>, Set<SubjectReference>> parents = new ConcurrentHashMap<>();
private final Map<Set<Context>, Map<String, String>> options = new ConcurrentHashMap<>();
private final Map<ContextSet, Map<String, Boolean>> permissions = new ConcurrentHashMap<>();
private final Map<ContextSet, Set<SubjectReference>> parents = new ConcurrentHashMap<>();
private final Map<ContextSet, Map<String, String>> options = new ConcurrentHashMap<>();
public Tristate getPermissionValue(Set<Context> contexts, String permission) {
return LuckPermsService.convertTristate(permissionCache.getUnchecked(contexts).getCalculator().getPermissionValue(permission));
public Tristate getPermissionValue(ContextSet contexts, String permission) {
return permissionCache.getUnchecked(contexts).getCalculator().getPermissionValue(permission);
}
public Map<Set<Context>, Set<SubjectReference>> getParents() {
ImmutableMap.Builder<Set<Context>, Set<SubjectReference>> map = ImmutableMap.builder();
for (Map.Entry<Set<Context>, Set<SubjectReference>> e : parents.entrySet()) {
map.put(ImmutableSet.copyOf(e.getKey()), ImmutableSet.copyOf(e.getValue()));
}
return map.build();
}
public void replacePermissions(Map<Set<Context>, Map<String, Boolean>> map) {
public void replacePermissions(Map<ContextSet, Map<String, Boolean>> map) {
permissions.clear();
for (Map.Entry<Set<Context>, Map<String, Boolean>> e : map.entrySet()) {
permissions.put(ImmutableSet.copyOf(e.getKey()), new ConcurrentHashMap<>(e.getValue()));
for (Map.Entry<ContextSet, Map<String, Boolean>> e : map.entrySet()) {
permissions.put(e.getKey().makeImmutable(), new ConcurrentHashMap<>(e.getValue()));
}
permissionCache.invalidateAll();
}
public void replaceParents(Map<Set<Context>, Set<SubjectReference>> map) {
public void replaceParents(Map<ContextSet, Set<SubjectReference>> map) {
parents.clear();
for (Map.Entry<Set<Context>, Set<SubjectReference>> e : map.entrySet()) {
for (Map.Entry<ContextSet, Set<SubjectReference>> e : map.entrySet()) {
Set<SubjectReference> set = ConcurrentHashMap.newKeySet();
set.addAll(e.getValue());
parents.put(ImmutableSet.copyOf(e.getKey()), set);
parents.put(e.getKey().makeImmutable(), set);
}
}
public void replaceOptions(Map<Set<Context>, Map<String, String>> map) {
public void replaceOptions(Map<ContextSet, Map<String, String>> map) {
options.clear();
for (Map.Entry<Set<Context>, Map<String, String>> e : map.entrySet()) {
options.put(ImmutableSet.copyOf(e.getKey()), new ConcurrentHashMap<>(e.getValue()));
for (Map.Entry<ContextSet, Map<String, String>> e : map.entrySet()) {
options.put(e.getKey().makeImmutable(), new ConcurrentHashMap<>(e.getValue()));
}
optionCache.invalidateAll();
}
@Override
public Map<Set<Context>, Map<String, Boolean>> getAllPermissions() {
ImmutableMap.Builder<Set<Context>, Map<String, Boolean>> map = ImmutableMap.builder();
for (Map.Entry<Set<Context>, Map<String, Boolean>> e : permissions.entrySet()) {
map.put(ImmutableSet.copyOf(e.getKey()), ImmutableMap.copyOf(e.getValue()));
public Map<ContextSet, Map<String, Boolean>> getPermissions() {
ImmutableMap.Builder<ContextSet, Map<String, Boolean>> map = ImmutableMap.builder();
for (Map.Entry<ContextSet, Map<String, Boolean>> e : permissions.entrySet()) {
map.put(e.getKey().makeImmutable(), ImmutableMap.copyOf(e.getValue()));
}
return map.build();
}
@Override
public Map<String, Boolean> getPermissions(Set<Context> contexts) {
public Map<String, Boolean> getPermissions(ContextSet contexts) {
return ImmutableMap.copyOf(permissions.getOrDefault(contexts, ImmutableMap.of()));
}
@Override
public boolean setPermission(Set<Context> contexts, String permission, Tristate value) {
public boolean setPermission(ContextSet contexts, String permission, Tristate value) {
boolean b;
if (value == Tristate.UNDEFINED) {
Map<String, Boolean> perms = permissions.get(contexts);
b = perms != null && perms.remove(permission.toLowerCase()) != null;
} else {
Map<String, Boolean> perms = permissions.computeIfAbsent(ImmutableSet.copyOf(contexts), c -> new ConcurrentHashMap<>());
Map<String, Boolean> perms = permissions.computeIfAbsent(contexts.makeImmutable(), c -> new ConcurrentHashMap<>());
b = !Objects.equals(perms.put(permission.toLowerCase(), value.asBoolean()), value.asBoolean());
}
if (b) {
@ -159,7 +153,7 @@ public class CalculatedSubjectData implements SubjectData {
}
@Override
public boolean clearPermissions(Set<Context> contexts) {
public boolean clearPermissions(ContextSet contexts) {
Map<String, Boolean> perms = permissions.get(contexts);
if (perms == null) {
return false;
@ -174,34 +168,29 @@ public class CalculatedSubjectData implements SubjectData {
}
@Override
public Map<Set<Context>, List<Subject>> getAllParents() {
ImmutableMap.Builder<Set<Context>, List<Subject>> map = ImmutableMap.builder();
for (Map.Entry<Set<Context>, Set<SubjectReference>> e : parents.entrySet()) {
map.put(
ImmutableSet.copyOf(e.getKey()),
e.getValue().stream().map(s -> s.resolve(service)).collect(ImmutableCollectors.toImmutableList())
);
public Map<ContextSet, Set<SubjectReference>> getParents() {
ImmutableMap.Builder<ContextSet, Set<SubjectReference>> map = ImmutableMap.builder();
for (Map.Entry<ContextSet, Set<SubjectReference>> e : parents.entrySet()) {
map.put(e.getKey().makeImmutable(), ImmutableSet.copyOf(e.getValue()));
}
return map.build();
}
@Override
public List<Subject> getParents(Set<Context> contexts) {
return parents.getOrDefault(contexts, ImmutableSet.of()).stream()
.map(s -> s.resolve(service))
.collect(ImmutableCollectors.toImmutableList());
public Set<SubjectReference> getParents(ContextSet contexts) {
return ImmutableSet.copyOf(parents.getOrDefault(contexts, ImmutableSet.of()));
}
@Override
public boolean addParent(Set<Context> contexts, Subject parent) {
Set<SubjectReference> set = parents.computeIfAbsent(ImmutableSet.copyOf(contexts), c -> ConcurrentHashMap.newKeySet());
return set.add(SubjectReference.of(parent));
public boolean addParent(ContextSet contexts, SubjectReference parent) {
Set<SubjectReference> set = parents.computeIfAbsent(contexts.makeImmutable(), c -> ConcurrentHashMap.newKeySet());
return set.add(parent);
}
@Override
public boolean removeParent(Set<Context> contexts, Subject parent) {
public boolean removeParent(ContextSet contexts, SubjectReference parent) {
Set<SubjectReference> set = parents.get(contexts);
return set != null && set.remove(SubjectReference.of(parent));
return set != null && set.remove(parent);
}
@Override
@ -215,7 +204,7 @@ public class CalculatedSubjectData implements SubjectData {
}
@Override
public boolean clearParents(Set<Context> contexts) {
public boolean clearParents(ContextSet contexts) {
Set<SubjectReference> set = parents.get(contexts);
if (set == null) {
return false;
@ -226,29 +215,33 @@ public class CalculatedSubjectData implements SubjectData {
}
@Override
public Map<Set<Context>, Map<String, String>> getAllOptions() {
ImmutableMap.Builder<Set<Context>, Map<String, String>> map = ImmutableMap.builder();
for (Map.Entry<Set<Context>, Map<String, String>> e : options.entrySet()) {
map.put(ImmutableSet.copyOf(e.getKey()), ImmutableMap.copyOf(e.getValue()));
public Map<ContextSet, Map<String, String>> getOptions() {
ImmutableMap.Builder<ContextSet, Map<String, String>> map = ImmutableMap.builder();
for (Map.Entry<ContextSet, Map<String, String>> e : options.entrySet()) {
map.put(e.getKey().makeImmutable(), ImmutableMap.copyOf(e.getValue()));
}
return map.build();
}
@Override
public Map<String, String> getOptions(Set<Context> contexts) {
public Map<String, String> getOptions(ContextSet contexts) {
return ImmutableMap.copyOf(options.getOrDefault(contexts, ImmutableMap.of()));
}
@Override
public boolean setOption(Set<Context> contexts, String key, @Nullable String value) {
boolean b;
if (value == null) {
Map<String, String> options = this.options.get(contexts);
b = options != null && options.remove(key.toLowerCase()) != null;
} else {
Map<String, String> options = this.options.computeIfAbsent(ImmutableSet.copyOf(contexts), c -> new ConcurrentHashMap<>());
b = !stringEquals(options.put(key.toLowerCase(), value), value);
public boolean setOption(ContextSet contexts, String key, String value) {
Map<String, String> options = this.options.computeIfAbsent(contexts.makeImmutable(), c -> new ConcurrentHashMap<>());
boolean b = !stringEquals(options.put(key.toLowerCase(), value), value);
if (b) {
optionCache.invalidateAll();
}
return b;
}
@Override
public boolean unsetOption(ContextSet contexts, String key) {
Map<String, String> options = this.options.get(contexts);
boolean b = options != null && options.remove(key.toLowerCase()) != null;
if (b) {
optionCache.invalidateAll();
}
@ -267,7 +260,7 @@ public class CalculatedSubjectData implements SubjectData {
}
@Override
public boolean clearOptions(Set<Context> contexts) {
public boolean clearOptions(ContextSet contexts) {
Map<String, String> map = options.get(contexts);
if (map == null) {
return false;
@ -281,10 +274,10 @@ public class CalculatedSubjectData implements SubjectData {
return false;
}
private static <V> Map<String, V> flattenMap(Set<Context> contexts, Map<Set<Context>, Map<String, V>> source) {
private static <V> Map<String, V> flattenMap(ContextSet contexts, Map<ContextSet, Map<String, V>> source) {
Map<String, V> map = new HashMap<>();
SortedMap<Set<Context>, Map<String, V>> ret = getRelevantEntries(contexts, source);
SortedMap<ContextSet, Map<String, V>> ret = getRelevantEntries(contexts, source);
for (Map<String, V> m : ret.values()) {
for (Map.Entry<String, V> e : m.entrySet()) {
if (!map.containsKey(e.getKey())) {
@ -296,18 +289,19 @@ public class CalculatedSubjectData implements SubjectData {
return ImmutableMap.copyOf(map);
}
private static <K, V> SortedMap<Set<Context>, Map<K, V>> getRelevantEntries(Set<Context> set, Map<Set<Context>, Map<K, V>> map) {
ImmutableSortedMap.Builder<Set<Context>, Map<K, V>> perms = ImmutableSortedMap.orderedBy(CONTEXT_COMPARATOR);
private static <K, V> SortedMap<ContextSet, Map<K, V>> getRelevantEntries(ContextSet set, Map<ContextSet, Map<K, V>> map) {
ImmutableSortedMap.Builder<ContextSet, Map<K, V>> perms = ImmutableSortedMap.orderedBy(CONTEXT_COMPARATOR);
loop:
for (Map.Entry<Set<Context>, Map<K, V>> e : map.entrySet()) {
for (Context c : e.getKey()) {
if (!set.contains(c)) {
for (Map.Entry<ContextSet, Map<K, V>> e : map.entrySet()) {
for (Map.Entry<String, String> c : e.getKey().toSet()) {
if (!set.has(c.getKey(), c.getValue())) {
continue loop;
}
}
perms.put(ImmutableSet.copyOf(e.getKey()), ImmutableMap.copyOf(e.getValue()));
perms.put(e.getKey().makeImmutable(), ImmutableMap.copyOf(e.getValue()));
}
return perms.build();
@ -317,10 +311,10 @@ public class CalculatedSubjectData implements SubjectData {
return a == null && b == null || a != null && b != null && a.equalsIgnoreCase(b);
}
private static class ContextComparator implements Comparator<Set<Context>> {
private static class ContextComparator implements Comparator<ContextSet> {
@Override
public int compare(Set<Context> o1, Set<Context> o2) {
public int compare(ContextSet o1, ContextSet o2) {
int i = Integer.compare(o1.size(), o2.size());
return i == 0 ? 1 : i;
}

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.sponge.service.calculated;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import me.lucko.luckperms.api.context.ContextSet;
@Getter
@ToString
@EqualsAndHashCode
@AllArgsConstructor(staticName = "of")
public class OptionLookup {
private final String key;
private final ContextSet contexts;
}

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.sponge.service.calculated;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import me.lucko.luckperms.api.context.ContextSet;
@Getter
@ToString
@EqualsAndHashCode
@AllArgsConstructor(staticName = "of")
public class PermissionLookup {
private final String node;
private final ContextSet contexts;
}

View File

@ -26,30 +26,31 @@ import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.utils.ImmutableCollectors;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectCollection;
import org.spongepowered.api.util.Tristate;
import me.lucko.luckperms.sponge.service.base.LPSubject;
import me.lucko.luckperms.sponge.service.base.LPSubjectCollection;
import me.lucko.luckperms.sponge.service.references.SubjectReference;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
/**
* A simple persistable subject collection
*/
@Getter
@RequiredArgsConstructor
public class PersistedCollection implements SubjectCollection {
public class PersistedCollection implements LPSubjectCollection {
private final LuckPermsService service;
@Getter
private final String identifier;
@Getter(AccessLevel.NONE)
private final LoadingCache<String, PersistedSubject> subjects = CacheBuilder.newBuilder()
.build(new CacheLoader<String, PersistedSubject>() {
@Override
@ -77,19 +78,14 @@ public class PersistedCollection implements SubjectCollection {
}
@Override
public Iterable<Subject> getAllSubjects() {
return subjects.asMap().values().stream().map(s -> (Subject) s).collect(ImmutableCollectors.toImmutableList());
public Collection<LPSubject> getSubjects() {
return subjects.asMap().values().stream().map(s -> (LPSubject) s).collect(ImmutableCollectors.toImmutableList());
}
@Override
public Map<Subject, Boolean> getAllWithPermission(@NonNull String id) {
return getAllWithPermission(ImmutableSet.of(), id);
}
@Override
public Map<Subject, Boolean> getAllWithPermission(@NonNull Set<Context> contexts, @NonNull String node) {
ImmutableMap.Builder<Subject, Boolean> m = ImmutableMap.builder();
for (Subject subject : subjects.asMap().values()) {
public Map<LPSubject, Boolean> getWithPermission(@NonNull ContextSet contexts, @NonNull String node) {
ImmutableMap.Builder<LPSubject, Boolean> m = ImmutableMap.builder();
for (LPSubject subject : subjects.asMap().values()) {
Tristate ts = subject.getPermissionValue(contexts, node);
if (ts != Tristate.UNDEFINED) {
m.put(subject, ts.asBoolean());
@ -100,7 +96,7 @@ public class PersistedCollection implements SubjectCollection {
}
@Override
public Subject getDefaults() {
return service.getDefaultSubjects().get(identifier);
public SubjectReference getDefaultSubject() {
return SubjectReference.of("defaults", identifier);
}
}

View File

@ -23,22 +23,22 @@
package me.lucko.luckperms.sponge.service.persisted;
import co.aikar.timings.Timing;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import lombok.Getter;
import lombok.NonNull;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.utils.BufferedRequest;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import me.lucko.luckperms.sponge.service.data.CalculatedSubjectData;
import me.lucko.luckperms.sponge.service.base.LPSubject;
import me.lucko.luckperms.sponge.service.calculated.CalculatedSubjectData;
import me.lucko.luckperms.sponge.service.references.SubjectCollectionReference;
import me.lucko.luckperms.sponge.service.references.SubjectReference;
import me.lucko.luckperms.sponge.timings.LPTiming;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.util.Tristate;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
@ -46,11 +46,12 @@ import java.util.Set;
* A simple persistable Subject implementation
*/
@Getter
public class PersistedSubject implements Subject {
public class PersistedSubject implements LPSubject {
private final String identifier;
@Getter
private final LuckPermsService service;
private final PersistedCollection containingCollection;
private final SubjectCollectionReference parentCollection;
private final PersistedSubjectData subjectData;
private final CalculatedSubjectData transientSubjectData;
private final BufferedRequest<Void> saveBuffer = new BufferedRequest<Void>(1000L, r -> PersistedSubject.this.service.getPlugin().doAsync(r)) {
@ -70,9 +71,9 @@ public class PersistedSubject implements Subject {
public PersistedSubject(String identifier, LuckPermsService service, PersistedCollection containingCollection) {
this.identifier = identifier;
this.service = service;
this.containingCollection = containingCollection;
this.parentCollection = containingCollection.toReference();
this.subjectData = new PersistedSubjectData(service, "local:" + containingCollection.getIdentifier() + "/" + identifier + "(p)", this);
this.transientSubjectData = new CalculatedSubjectData(service, "local:" + containingCollection.getIdentifier() + "/" + identifier + "(t)");
this.transientSubjectData = new CalculatedSubjectData(this, service, "local:" + containingCollection.getIdentifier() + "/" + identifier + "(t)");
}
public void loadData(SubjectDataHolder dataHolder) {
@ -91,12 +92,7 @@ public class PersistedSubject implements Subject {
}
@Override
public boolean hasPermission(@NonNull Set<Context> contexts, @NonNull String node) {
return getPermissionValue(contexts, node).asBoolean();
}
@Override
public Tristate getPermissionValue(@NonNull Set<Context> contexts, @NonNull String node) {
public Tristate getPermissionValue(@NonNull ContextSet contexts, @NonNull String node) {
try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.PERSISTED_SUBJECT_GET_PERMISSION_VALUE)) {
Tristate res = subjectData.getPermissionValue(contexts, node);
if (res != Tristate.UNDEFINED) {
@ -108,18 +104,18 @@ public class PersistedSubject implements Subject {
return res;
}
for (Subject parent : getParents(contexts)) {
Tristate tempRes = parent.getPermissionValue(contexts, node);
for (SubjectReference parent : getParents(contexts)) {
Tristate tempRes = parent.resolve(service).getPermissionValue(contexts, node);
if (tempRes != Tristate.UNDEFINED) {
return tempRes;
}
}
if (getContainingCollection().getIdentifier().equalsIgnoreCase("defaults")) {
if (getParentCollection().resolve(service).getIdentifier().equalsIgnoreCase("defaults")) {
return Tristate.UNDEFINED;
}
res = service.getGroupSubjects().getDefaults().getPermissionValue(contexts, node);
res = service.getGroupSubjects().getDefaultSubject().resolve(service).getPermissionValue(contexts, node);
if (res != Tristate.UNDEFINED) {
return res;
}
@ -130,61 +126,61 @@ public class PersistedSubject implements Subject {
}
@Override
public boolean isChildOf(@NonNull Set<Context> contexts, @NonNull Subject subject) {
public boolean isChildOf(@NonNull ContextSet contexts, @NonNull SubjectReference subject) {
try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.PERSISTED_SUBJECT_IS_CHILD_OF)) {
if (getContainingCollection().getIdentifier().equalsIgnoreCase("defaults")) {
if (getParentCollection().resolve(service).getIdentifier().equalsIgnoreCase("defaults")) {
return subjectData.getParents(contexts).contains(subject) ||
transientSubjectData.getParents(contexts).contains(subject);
} else {
return subjectData.getParents(contexts).contains(subject) ||
transientSubjectData.getParents(contexts).contains(subject) ||
getContainingCollection().getDefaults().getParents(contexts).contains(subject) ||
getParentCollection().resolve(service).getDefaultSubject().resolve(service).getParents(contexts).contains(subject) ||
service.getDefaults().getParents(contexts).contains(subject);
}
}
}
@Override
public List<Subject> getParents(@NonNull Set<Context> contexts) {
public Set<SubjectReference> getParents(@NonNull ContextSet contexts) {
try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.PERSISTED_SUBJECT_GET_PARENTS)) {
List<Subject> s = new ArrayList<>();
Set<SubjectReference> s = new HashSet<>();
s.addAll(subjectData.getParents(contexts));
s.addAll(transientSubjectData.getParents(contexts));
if (!getContainingCollection().getIdentifier().equalsIgnoreCase("defaults")) {
s.addAll(getContainingCollection().getDefaults().getParents(contexts));
if (!getParentCollection().resolve(service).getIdentifier().equalsIgnoreCase("defaults")) {
s.addAll(getParentCollection().resolve(service).getDefaultSubject().resolve(service).getParents(contexts));
s.addAll(service.getDefaults().getParents(contexts));
}
return ImmutableList.copyOf(s);
return ImmutableSet.copyOf(s);
}
}
@Override
public Optional<String> getOption(Set<Context> set, String key) {
public Optional<String> getOption(ContextSet set, String key) {
try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.PERSISTED_SUBJECT_GET_OPTION)) {
Optional<String> res = Optional.ofNullable(subjectData.getOptions(getActiveContexts()).get(key));
Optional<String> res = Optional.ofNullable(subjectData.getOptions(getActiveContextSet()).get(key));
if (res.isPresent()) {
return res;
}
res = Optional.ofNullable(transientSubjectData.getOptions(getActiveContexts()).get(key));
res = Optional.ofNullable(transientSubjectData.getOptions(getActiveContextSet()).get(key));
if (res.isPresent()) {
return res;
}
for (Subject parent : getParents(getActiveContexts())) {
Optional<String> tempRes = parent.getOption(getActiveContexts(), key);
for (SubjectReference parent : getParents(getActiveContextSet())) {
Optional<String> tempRes = parent.resolve(service).getOption(getActiveContextSet(), key);
if (tempRes.isPresent()) {
return tempRes;
}
}
if (getContainingCollection().getIdentifier().equalsIgnoreCase("defaults")) {
if (getParentCollection().resolve(service).getIdentifier().equalsIgnoreCase("defaults")) {
return Optional.empty();
}
res = getContainingCollection().getDefaults().getOption(set, key);
res = getParentCollection().resolve(service).getDefaultSubject().resolve(service).getOption(set, key);
if (res.isPresent()) {
return res;
}
@ -194,9 +190,9 @@ public class PersistedSubject implements Subject {
}
@Override
public Set<Context> getActiveContexts() {
public ContextSet getActiveContextSet() {
try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.PERSISTED_SUBJECT_GET_ACTIVE_CONTEXTS)) {
return ImmutableSet.copyOf(LuckPermsService.convertContexts(service.getPlugin().getContextManager().getApplicableContext(this)));
return service.getPlugin().getContextManager().getApplicableContext(this);
}
}
}

View File

@ -24,14 +24,10 @@ package me.lucko.luckperms.sponge.service.persisted;
import lombok.Getter;
import lombok.Setter;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import me.lucko.luckperms.sponge.service.data.CalculatedSubjectData;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.util.Tristate;
import javax.annotation.Nullable;
import java.util.Set;
import me.lucko.luckperms.sponge.service.calculated.CalculatedSubjectData;
import me.lucko.luckperms.sponge.service.references.SubjectReference;
/**
* Extension of MemorySubjectData which persists data when modified
@ -44,7 +40,7 @@ public class PersistedSubjectData extends CalculatedSubjectData {
private boolean save = true;
public PersistedSubjectData(LuckPermsService service, String calculatorDisplayName, PersistedSubject subject) {
super(service, calculatorDisplayName);
super(subject, service, calculatorDisplayName);
this.subject = subject;
}
@ -59,7 +55,7 @@ public class PersistedSubjectData extends CalculatedSubjectData {
}
@Override
public boolean setPermission(Set<Context> contexts, String permission, Tristate value) {
public boolean setPermission(ContextSet contexts, String permission, me.lucko.luckperms.api.Tristate value) {
boolean r = super.setPermission(contexts, permission, value);
save();
return r;
@ -73,21 +69,21 @@ public class PersistedSubjectData extends CalculatedSubjectData {
}
@Override
public boolean clearPermissions(Set<Context> context) {
boolean r = super.clearPermissions(context);
public boolean clearPermissions(ContextSet contexts) {
boolean r = super.clearPermissions(contexts);
save();
return r;
}
@Override
public boolean addParent(Set<Context> contexts, Subject parent) {
public boolean addParent(ContextSet contexts, SubjectReference parent) {
boolean r = super.addParent(contexts, parent);
save();
return r;
}
@Override
public boolean removeParent(Set<Context> contexts, Subject parent) {
public boolean removeParent(ContextSet contexts, SubjectReference parent) {
boolean r = super.removeParent(contexts, parent);
save();
return r;
@ -101,21 +97,28 @@ public class PersistedSubjectData extends CalculatedSubjectData {
}
@Override
public boolean clearParents(Set<Context> contexts) {
public boolean clearParents(ContextSet contexts) {
boolean r = super.clearParents(contexts);
save();
return r;
}
@Override
public boolean setOption(Set<Context> contexts, String key, @Nullable String value) {
public boolean setOption(ContextSet contexts, String key, String value) {
boolean r = super.setOption(contexts, key, value);
save();
return r;
}
@Override
public boolean clearOptions(Set<Context> contexts) {
public boolean unsetOption(ContextSet contexts, String key) {
boolean r = super.unsetOption(contexts, key);
save();
return r;
}
@Override
public boolean clearOptions(ContextSet contexts) {
boolean r = super.clearOptions(contexts);
save();
return r;

View File

@ -24,9 +24,8 @@ package me.lucko.luckperms.sponge.service.persisted;
import lombok.ToString;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.sponge.service.data.CalculatedSubjectData;
import me.lucko.luckperms.sponge.service.data.SubjectReference;
import org.spongepowered.api.service.context.Context;
import me.lucko.luckperms.sponge.service.calculated.CalculatedSubjectData;
import me.lucko.luckperms.sponge.service.references.SubjectReference;
import java.util.HashMap;
import java.util.List;
@ -34,8 +33,6 @@ import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static me.lucko.luckperms.sponge.service.LuckPermsService.convertContexts;
/**
* Holds SubjectData in a "gson friendly" format for serialization
*/
@ -45,45 +42,45 @@ public class SubjectDataHolder {
private final Map<Map<String, String>, Map<String, String>> options;
private final Map<Map<String, String>, List<String>> parents;
public SubjectDataHolder(Map<Set<Context>, Map<String, String>> options, Map<Set<Context>, Map<String, Boolean>> permissions, Map<Set<Context>, Set<SubjectReference>> parents) {
public SubjectDataHolder(Map<ContextSet, Map<String, String>> options, Map<ContextSet, Map<String, Boolean>> permissions, Map<ContextSet, Set<SubjectReference>> parents) {
this.options = new HashMap<>();
for (Map.Entry<Set<Context>, Map<String, String>> e : options.entrySet()) {
this.options.put(convertContexts(e.getKey()).toMap(), new HashMap<>(e.getValue()));
for (Map.Entry<ContextSet, Map<String, String>> e : options.entrySet()) {
this.options.put(e.getKey().toMap(), new HashMap<>(e.getValue()));
}
this.permissions = new HashMap<>();
for (Map.Entry<Set<Context>, Map<String, Boolean>> e : permissions.entrySet()) {
this.permissions.put(convertContexts(e.getKey()).toMap(), new HashMap<>(e.getValue()));
for (Map.Entry<ContextSet, Map<String, Boolean>> e : permissions.entrySet()) {
this.permissions.put(e.getKey().toMap(), new HashMap<>(e.getValue()));
}
this.parents = new HashMap<>();
for (Map.Entry<Set<Context>, Set<SubjectReference>> e : parents.entrySet()) {
this.parents.put(convertContexts(e.getKey()).toMap(), e.getValue().stream().map(SubjectReference::serialize).collect(Collectors.toList()));
for (Map.Entry<ContextSet, Set<SubjectReference>> e : parents.entrySet()) {
this.parents.put(e.getKey().toMap(), e.getValue().stream().map(SubjectReference::serialize).collect(Collectors.toList()));
}
}
public SubjectDataHolder(CalculatedSubjectData data) {
this(data.getAllOptions(), data.getAllPermissions(), data.getParents());
this(data.getOptions(), data.getPermissions(), data.getParents());
}
public void copyTo(CalculatedSubjectData subjectData) {
subjectData.replacePermissions(permissions.entrySet().stream()
.collect(Collectors.toMap(
k -> convertContexts(ContextSet.fromMap(k.getKey())),
k -> ContextSet.fromMap(k.getKey()),
Map.Entry::getValue
))
);
subjectData.replaceOptions(options.entrySet().stream()
.collect(Collectors.toMap(
k -> convertContexts(ContextSet.fromMap(k.getKey())),
k -> ContextSet.fromMap(k.getKey()),
Map.Entry::getValue
))
);
subjectData.replaceParents(parents.entrySet().stream()
.collect(Collectors.toMap(
k -> convertContexts(ContextSet.fromMap(k.getKey())),
k -> ContextSet.fromMap(k.getKey()),
v -> v.getValue().stream().map(SubjectReference::deserialize).collect(Collectors.toSet())
))
);

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.sponge.service.references;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import me.lucko.luckperms.sponge.service.base.LPSubjectCollection;
@Getter
@ToString
@EqualsAndHashCode
@AllArgsConstructor(staticName = "of")
public class SubjectCollectionReference {
private final String collection;
public LPSubjectCollection resolve(LuckPermsService service) {
return service.getSubjects(collection);
}
}

View File

@ -20,14 +20,16 @@
* SOFTWARE.
*/
package me.lucko.luckperms.sponge.service.data;
package me.lucko.luckperms.sponge.service.references;
import com.google.common.base.Splitter;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import org.spongepowered.api.service.permission.PermissionService;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import me.lucko.luckperms.sponge.service.base.LPSubject;
import me.lucko.luckperms.sponge.service.base.LPSubjectCollection;
import org.spongepowered.api.service.permission.Subject;
import java.util.List;
@ -49,10 +51,14 @@ public class SubjectReference {
private final String collection;
private final String identifier;
public Subject resolve(PermissionService service) {
public LPSubject resolve(LuckPermsService service) {
return service.getSubjects(collection).get(identifier);
}
public LPSubjectCollection resolveCollection(LuckPermsService service) {
return service.getSubjects(collection);
}
public String serialize() {
return collection + "/" + identifier;
}

View File

@ -26,30 +26,31 @@ import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.utils.ImmutableCollectors;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectCollection;
import org.spongepowered.api.util.Tristate;
import me.lucko.luckperms.sponge.service.base.LPSubject;
import me.lucko.luckperms.sponge.service.base.LPSubjectCollection;
import me.lucko.luckperms.sponge.service.references.SubjectReference;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
/**
* Super simple SubjectCollection implementation
*/
@Getter
@RequiredArgsConstructor
public class SimpleCollection implements SubjectCollection {
public class SimpleCollection implements LPSubjectCollection {
private final LuckPermsService service;
@Getter
private final String identifier;
@Getter(AccessLevel.NONE)
private final LoadingCache<String, SimpleSubject> subjects = CacheBuilder.newBuilder()
.build(new CacheLoader<String, SimpleSubject>() {
@Override
@ -59,7 +60,7 @@ public class SimpleCollection implements SubjectCollection {
});
@Override
public Subject get(@NonNull String id) {
public LPSubject get(@NonNull String id) {
return subjects.getUnchecked(id.toLowerCase());
}
@ -69,19 +70,14 @@ public class SimpleCollection implements SubjectCollection {
}
@Override
public Iterable<Subject> getAllSubjects() {
return subjects.asMap().values().stream().map(s -> (Subject) s).collect(ImmutableCollectors.toImmutableList());
public Collection<LPSubject> getSubjects() {
return subjects.asMap().values().stream().map(s -> (LPSubject) s).collect(ImmutableCollectors.toImmutableList());
}
@Override
public Map<Subject, Boolean> getAllWithPermission(@NonNull String id) {
return getAllWithPermission(ImmutableSet.of(), id);
}
@Override
public Map<Subject, Boolean> getAllWithPermission(@NonNull Set<Context> contexts, @NonNull String node) {
ImmutableMap.Builder<Subject, Boolean> m = ImmutableMap.builder();
for (Subject subject : subjects.asMap().values()) {
public Map<LPSubject, Boolean> getWithPermission(@NonNull ContextSet contexts, @NonNull String node) {
ImmutableMap.Builder<LPSubject, Boolean> m = ImmutableMap.builder();
for (LPSubject subject : subjects.asMap().values()) {
Tristate ts = subject.getPermissionValue(contexts, node);
if (ts != Tristate.UNDEFINED) {
m.put(subject, ts.asBoolean());
@ -92,7 +88,7 @@ public class SimpleCollection implements SubjectCollection {
}
@Override
public Subject getDefaults() {
return service.getDefaultSubjects().get(identifier);
public SubjectReference getDefaultSubject() {
return SubjectReference.of("defaults", identifier);
}
}

View File

@ -23,20 +23,24 @@
package me.lucko.luckperms.sponge.service.simple;
import co.aikar.timings.Timing;
import com.google.common.collect.ImmutableList;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableSet;
import lombok.Getter;
import lombok.NonNull;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import me.lucko.luckperms.sponge.service.data.CalculatedSubjectData;
import me.lucko.luckperms.sponge.service.base.LPSubject;
import me.lucko.luckperms.sponge.service.calculated.CalculatedSubjectData;
import me.lucko.luckperms.sponge.service.calculated.OptionLookup;
import me.lucko.luckperms.sponge.service.calculated.PermissionLookup;
import me.lucko.luckperms.sponge.service.references.SubjectCollectionReference;
import me.lucko.luckperms.sponge.service.references.SubjectReference;
import me.lucko.luckperms.sponge.timings.LPTiming;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.util.Tristate;
import java.util.ArrayList;
import java.util.List;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
@ -44,126 +48,153 @@ import java.util.Set;
* Super simple Subject implementation.
*/
@Getter
public class SimpleSubject implements Subject {
public class SimpleSubject implements LPSubject {
private final String identifier;
private final LuckPermsService service;
private final SimpleCollection containingCollection;
private final SubjectCollectionReference parentCollection;
private final CalculatedSubjectData subjectData;
private final CalculatedSubjectData transientSubjectData;
private final LoadingCache<PermissionLookup, Tristate> permissionLookupCache = CacheBuilder.newBuilder()
.build(new CacheLoader<PermissionLookup, Tristate>() {
@Override
public Tristate load(PermissionLookup lookup) {
return lookupPermissionValue(lookup.getContexts(), lookup.getNode());
}
});
private final LoadingCache<ContextSet, Set<SubjectReference>> parentLookupCache = CacheBuilder.newBuilder()
.build(new CacheLoader<ContextSet, Set<SubjectReference>>() {
@Override
public Set<SubjectReference> load(ContextSet contexts) {
return lookupParents(contexts);
}
});
private final LoadingCache<OptionLookup, Optional<String>> optionLookupCache = CacheBuilder.newBuilder()
.build(new CacheLoader<OptionLookup, Optional<String>>() {
@Override
public Optional<String> load(OptionLookup lookup) {
return lookupOptionValue(lookup.getContexts(), lookup.getKey());
}
});
public SimpleSubject(String identifier, LuckPermsService service, SimpleCollection containingCollection) {
this.identifier = identifier;
this.service = service;
this.containingCollection = containingCollection;
this.subjectData = new CalculatedSubjectData(service, "local:" + containingCollection.getIdentifier() + "/" + identifier + "(p)");
this.transientSubjectData = new CalculatedSubjectData(service, "local:" + containingCollection.getIdentifier() + "/" + identifier + "(t)");
this.parentCollection = containingCollection.toReference();
this.subjectData = new CalculatedSubjectData(this, service, "local:" + containingCollection.getIdentifier() + "/" + identifier + "(p)");
this.transientSubjectData = new CalculatedSubjectData(this, service, "local:" + containingCollection.getIdentifier() + "/" + identifier + "(t)");
service.getLocalPermissionCaches().add(permissionLookupCache);
}
@Override
public Optional<CommandSource> getCommandSource() {
return Optional.empty();
}
@Override
public boolean hasPermission(@NonNull Set<Context> contexts, @NonNull String node) {
return getPermissionValue(contexts, node).asBoolean();
}
@Override
public Tristate getPermissionValue(@NonNull Set<Context> contexts, @NonNull String node) {
try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.SIMPLE_SUBJECT_GET_PERMISSION_VALUE)) {
Tristate res = transientSubjectData.getPermissionValue(contexts, node);
if (res != Tristate.UNDEFINED) {
return res;
}
res = subjectData.getPermissionValue(contexts, node);
if (res != Tristate.UNDEFINED) {
return res;
}
for (Subject parent : getParents(contexts)) {
res = parent.getPermissionValue(contexts, node);
if (res != Tristate.UNDEFINED) {
return res;
}
}
if (getContainingCollection().getIdentifier().equalsIgnoreCase("defaults")) {
return Tristate.UNDEFINED;
}
res = getContainingCollection().getDefaults().getPermissionValue(contexts, node);
if (res != Tristate.UNDEFINED) {
return res;
}
res = service.getDefaults().getPermissionValue(contexts, node);
private Tristate lookupPermissionValue(ContextSet contexts, String node) {
Tristate res = transientSubjectData.getPermissionValue(contexts, node);
if (res != Tristate.UNDEFINED) {
return res;
}
res = subjectData.getPermissionValue(contexts, node);
if (res != Tristate.UNDEFINED) {
return res;
}
for (SubjectReference parent : getParents(contexts)) {
res = parent.resolve(service).getPermissionValue(contexts, node);
if (res != Tristate.UNDEFINED) {
return res;
}
}
if (getParentCollection().resolve(service).getIdentifier().equalsIgnoreCase("defaults")) {
return Tristate.UNDEFINED;
}
res = getParentCollection().resolve(service).getDefaultSubject().resolve(service).getPermissionValue(contexts, node);
if (res != Tristate.UNDEFINED) {
return res;
}
res = service.getDefaults().getPermissionValue(contexts, node);
return res;
}
private Set<SubjectReference> lookupParents(ContextSet contexts) {
Set<SubjectReference> s = new HashSet<>();
s.addAll(subjectData.getParents(contexts));
if (!getParentCollection().resolve(service).getIdentifier().equalsIgnoreCase("defaults")){
s.addAll(getParentCollection().resolve(service).getDefaultSubject().resolve(service).getParents(contexts));
s.addAll(service.getDefaults().getParents(contexts));
}
return ImmutableSet.copyOf(s);
}
private Optional<String> lookupOptionValue(ContextSet contexts, String key) {
Optional<String> res = Optional.ofNullable(subjectData.getOptions(contexts).get(key));
if (res.isPresent()) {
return res;
}
for (SubjectReference parent : getParents(getActiveContextSet())) {
Optional<String> tempRes = parent.resolve(service).getOption(contexts, key);
if (tempRes.isPresent()) {
return tempRes;
}
}
if (getParentCollection().resolve(service).getIdentifier().equalsIgnoreCase("defaults")) {
return Optional.empty();
}
res = getParentCollection().resolve(service).getDefaultSubject().resolve(service).getOption(contexts, key);
if (res.isPresent()) {
return res;
}
return service.getDefaults().getOption(contexts, key);
}
@Override
public Tristate getPermissionValue(@NonNull ContextSet contexts, @NonNull String node) {
try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.SIMPLE_SUBJECT_GET_PERMISSION_VALUE)) {
return permissionLookupCache.getUnchecked(PermissionLookup.of(node, contexts));
}
}
@Override
public boolean isChildOf(@NonNull Set<Context> contexts, @NonNull Subject subject) {
public boolean isChildOf(@NonNull ContextSet contexts, @NonNull SubjectReference subject) {
try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.SIMPLE_SUBJECT_IS_CHILD_OF)) {
if (getContainingCollection().getIdentifier().equalsIgnoreCase("defaults")) {
if (getParentCollection().resolve(service).getIdentifier().equalsIgnoreCase("defaults")) {
return subjectData.getParents(contexts).contains(subject);
} else {
return subjectData.getParents(contexts).contains(subject) ||
getContainingCollection().getDefaults().getParents(contexts).contains(subject) ||
getParentCollection().resolve(service).getDefaultSubject().resolve(service).getParents(contexts).contains(subject) ||
service.getDefaults().getParents(contexts).contains(subject);
}
}
}
@Override
public List<Subject> getParents(@NonNull Set<Context> contexts) {
public Set<SubjectReference> getParents(@NonNull ContextSet contexts) {
try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.SIMPLE_SUBJECT_GET_PARENTS)) {
List<Subject> s = new ArrayList<>();
s.addAll(subjectData.getParents(contexts));
if (!getContainingCollection().getIdentifier().equalsIgnoreCase("defaults")){
s.addAll(getContainingCollection().getDefaults().getParents(contexts));
s.addAll(service.getDefaults().getParents(contexts));
}
return ImmutableList.copyOf(s);
return parentLookupCache.getUnchecked(contexts);
}
}
@Override
public Optional<String> getOption(Set<Context> set, String key) {
public Optional<String> getOption(ContextSet contexts, String key) {
try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.SIMPLE_SUBJECT_GET_OPTION)) {
Optional<String> res = Optional.ofNullable(subjectData.getOptions(getActiveContexts()).get(key));
if (res.isPresent()) {
return res;
}
for (Subject parent : getParents(getActiveContexts())) {
Optional<String> tempRes = parent.getOption(getActiveContexts(), key);
if (tempRes.isPresent()) {
return tempRes;
}
}
if (getContainingCollection().getIdentifier().equalsIgnoreCase("defaults")) {
return Optional.empty();
}
res = getContainingCollection().getDefaults().getOption(set, key);
if (res.isPresent()) {
return res;
}
return service.getDefaults().getOption(set, key);
return optionLookupCache.getUnchecked(OptionLookup.of(key, contexts));
}
}
@Override
public Set<Context> getActiveContexts() {
public ContextSet getActiveContextSet() {
try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.SIMPLE_SUBJECT_GET_ACTIVE_CONTEXTS)) {
return ImmutableSet.copyOf(LuckPermsService.convertContexts(service.getPlugin().getContextManager().getApplicableContext(this)));
return service.getPlugin().getContextManager().getApplicableContext(this);
}
}
}