Further improvements to the Sponge service design

This commit is contained in:
Luck 2018-03-08 21:51:25 +00:00
parent 1b98667365
commit f6c440c172
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
49 changed files with 609 additions and 503 deletions

View File

@ -25,19 +25,10 @@
package me.lucko.luckperms.common.inheritance;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.LookupSetting;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.common.graph.Graph;
import me.lucko.luckperms.common.graph.GraphTraversers;
import me.lucko.luckperms.common.graph.TraversalAlgorithm;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
/**
* A {@link Graph} which represents an "inheritance tree".
@ -56,57 +47,4 @@ public interface InheritanceGraph extends Graph<PermissionHolder> {
return GraphTraversers.traverseUsing(algorithm, this, startNode);
}
final class NonContextual implements InheritanceGraph {
private final LuckPermsPlugin plugin;
NonContextual(LuckPermsPlugin plugin) {
this.plugin = plugin;
}
@Override
public Iterable<? extends PermissionHolder> successors(PermissionHolder holder) {
Set<Group> successors = new TreeSet<>(holder.getInheritanceComparator());
List<Node> nodes = holder.getOwnGroupNodes();
for (Node n : nodes) {
Group g = this.plugin.getGroupManager().getIfLoaded(n.getGroupName());
if (g != null) {
successors.add(g);
}
}
return successors;
}
}
final class Contextual implements InheritanceGraph {
private final LuckPermsPlugin plugin;
/**
* The contexts to resolve inheritance in.
*/
private final Contexts context;
Contextual(LuckPermsPlugin plugin, Contexts context) {
this.plugin = plugin;
this.context = context;
}
@Override
public Iterable<? extends PermissionHolder> successors(PermissionHolder holder) {
Set<Group> successors = new TreeSet<>(holder.getInheritanceComparator());
List<Node> nodes = holder.getOwnGroupNodes(this.context.getContexts());
for (Node n : nodes) {
// effectively: if not (we're applying global groups or it's specific anyways)
if (!((this.context.hasSetting(LookupSetting.APPLY_PARENTS_SET_WITHOUT_SERVER) || n.isServerSpecific()) && (this.context.hasSetting(LookupSetting.APPLY_PARENTS_SET_WITHOUT_WORLD) || n.isWorldSpecific()))) {
continue;
}
Group g = this.plugin.getGroupManager().getIfLoaded(n.getGroupName());
if (g != null) {
successors.add(g);
}
}
return successors;
}
}
}

View File

@ -29,8 +29,15 @@ import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.LookupSetting;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;
/**
@ -51,10 +58,10 @@ public class InheritanceHandler {
public InheritanceHandler(LuckPermsPlugin plugin) {
this.plugin = plugin;
this.nonContextualGraph = new InheritanceGraph.NonContextual(plugin);
this.nonContextualGraph = new NonContextualGraph(plugin);
this.contextualGraphs = Caffeine.newBuilder()
.expireAfterAccess(10, TimeUnit.MINUTES)
.build(key -> new InheritanceGraph.Contextual(this.plugin, key));
.build(key -> new ContextualGraph(this.plugin, key));
}
public InheritanceGraph getGraph() {
@ -65,4 +72,57 @@ public class InheritanceHandler {
return this.contextualGraphs.get(contexts);
}
private static final class NonContextualGraph implements InheritanceGraph {
private final LuckPermsPlugin plugin;
NonContextualGraph(LuckPermsPlugin plugin) {
this.plugin = plugin;
}
@Override
public Iterable<? extends PermissionHolder> successors(PermissionHolder holder) {
Set<Group> successors = new TreeSet<>(holder.getInheritanceComparator());
List<Node> nodes = holder.getOwnGroupNodes();
for (Node n : nodes) {
Group g = this.plugin.getGroupManager().getIfLoaded(n.getGroupName());
if (g != null) {
successors.add(g);
}
}
return successors;
}
}
private static final class ContextualGraph implements InheritanceGraph {
private final LuckPermsPlugin plugin;
/**
* The contexts to resolve inheritance in.
*/
private final Contexts context;
ContextualGraph(LuckPermsPlugin plugin, Contexts context) {
this.plugin = plugin;
this.context = context;
}
@Override
public Iterable<? extends PermissionHolder> successors(PermissionHolder holder) {
Set<Group> successors = new TreeSet<>(holder.getInheritanceComparator());
List<Node> nodes = holder.getOwnGroupNodes(this.context.getContexts());
for (Node n : nodes) {
// effectively: if not (we're applying global groups or it's specific anyways)
if (!((this.context.hasSetting(LookupSetting.APPLY_PARENTS_SET_WITHOUT_SERVER) || n.isServerSpecific()) && (this.context.hasSetting(LookupSetting.APPLY_PARENTS_SET_WITHOUT_WORLD) || n.isWorldSpecific()))) {
continue;
}
Group g = this.plugin.getGroupManager().getIfLoaded(n.getGroupName());
if (g != null) {
successors.add(g);
}
}
return successors;
}
}
}

View File

@ -53,7 +53,7 @@ import javax.annotation.Nonnull;
public class LuckPermsMessagingService implements InternalMessagingService, IncomingMessageConsumer {
private final LuckPermsPlugin plugin;
private final Set<UUID> receivedMessages;
private final BufferedRequest<Void> updateBuffer;
private final PushUpdateBuffer updateBuffer;
private final MessengerProvider messengerProvider;
private final Messenger messenger;

View File

@ -53,7 +53,7 @@ public class Group extends PermissionHolder implements Identifiable<String> {
*/
private final GroupCachedData cachedData;
private final BufferedRequest<Void> refreshBuffer;
private final GroupRefreshBuffer refreshBuffer;
public Group(String name, LuckPermsPlugin plugin) {
super(name, plugin);

View File

@ -62,7 +62,7 @@ public class User extends PermissionHolder implements Identifiable<UserIdentifie
*/
private final UserCachedData cachedData;
private final BufferedRequest<Void> refreshBuffer;
private final UserRefreshBuffer refreshBuffer;
public User(UUID uuid, String name, LuckPermsPlugin plugin) {
super(uuid.toString(), plugin);

View File

@ -44,14 +44,14 @@ import java.util.Objects;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public final class LPDescriptionBuilder implements PermissionDescription.Builder {
public final class DescriptionBuilder implements PermissionDescription.Builder {
@Nonnull private final LPPermissionService service;
@Nonnull private final PluginContainer container;
@Nonnull private final Map<String, Tristate> roles = new HashMap<>();
@Nullable private String id = null;
@Nullable private Text description = null;
public LPDescriptionBuilder(@Nonnull LPPermissionService service, @Nonnull PluginContainer container) {
public DescriptionBuilder(@Nonnull LPPermissionService service, @Nonnull PluginContainer container) {
this.service = Objects.requireNonNull(service, "service");
this.container = Objects.requireNonNull(container, "container");
}
@ -107,8 +107,8 @@ public final class LPDescriptionBuilder implements PermissionDescription.Builder
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof LPDescriptionBuilder)) return false;
final LPDescriptionBuilder other = (LPDescriptionBuilder) o;
if (!(o instanceof DescriptionBuilder)) return false;
final DescriptionBuilder other = (DescriptionBuilder) o;
return this.container.equals(other.container) &&
this.roles.equals(other.roles) &&

View File

@ -65,7 +65,7 @@ public final class PermissionServiceProxy implements PermissionService {
@Nonnull
@Override
public Subject getDefaults() {
return this.handle.getDefaults().sponge();
return this.handle.getRootDefaults().sponge();
}
@Nonnull
@ -91,7 +91,7 @@ public final class PermissionServiceProxy implements PermissionService {
throw new IllegalArgumentException("Couldn't find a plugin container for " + o.getClass().getSimpleName());
}
return Optional.of(new LPDescriptionBuilder(this.handle, container.get()));
return Optional.of(new DescriptionBuilder(this.handle, container.get()));
}
@Nonnull

View File

@ -30,7 +30,6 @@ import me.lucko.luckperms.sponge.service.CompatibilityUtil;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectCollection;
import me.lucko.luckperms.sponge.service.reference.SubjectReferenceFactory;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.Subject;
@ -79,7 +78,7 @@ public final class SubjectCollectionProxy implements SubjectCollection {
// this behaviour should be replaced when CompletableFutures are added to Sponge
return (List) this.handle.getAllIdentifiers()
.thenApply(ids -> ids.stream()
.map(s -> new SubjectProxy(this.service, SubjectReferenceFactory.obtain(this.service, getIdentifier(), s)))
.map(s -> new SubjectProxy(this.service, this.service.getReferenceFactory().obtain(getIdentifier(), s)))
.collect(ImmutableCollectors.toList())
).join();
}

View File

@ -30,8 +30,7 @@ import me.lucko.luckperms.sponge.service.CompatibilityUtil;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectData;
import me.lucko.luckperms.sponge.service.reference.LPSubjectReference;
import me.lucko.luckperms.sponge.service.reference.SubjectReferenceFactory;
import me.lucko.luckperms.sponge.service.model.LPSubjectReference;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.Subject;
@ -126,7 +125,7 @@ public final class SubjectDataProxy implements SubjectData {
public boolean addParent(@Nonnull Set<Context> contexts, @Nonnull Subject parent) {
handle().thenCompose(handle -> handle.addParent(
CompatibilityUtil.convertContexts(contexts),
SubjectReferenceFactory.obtain(this.service, parent)
this.service.getReferenceFactory().obtain(parent)
));
return true;
}
@ -135,7 +134,7 @@ public final class SubjectDataProxy implements SubjectData {
public boolean removeParent(@Nonnull Set<Context> contexts, @Nonnull Subject parent) {
handle().thenCompose(handle -> handle.removeParent(
CompatibilityUtil.convertContexts(contexts),
SubjectReferenceFactory.obtain(this.service, parent)
this.service.getReferenceFactory().obtain(parent)
));
return true;
}

View File

@ -30,9 +30,8 @@ import me.lucko.luckperms.common.utils.ImmutableCollectors;
import me.lucko.luckperms.sponge.service.CompatibilityUtil;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectReference;
import me.lucko.luckperms.sponge.service.model.ProxiedSubject;
import me.lucko.luckperms.sponge.service.reference.LPSubjectReference;
import me.lucko.luckperms.sponge.service.reference.SubjectReferenceFactory;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.service.context.Context;
@ -110,7 +109,7 @@ public final class SubjectProxy implements Subject, ProxiedSubject {
public boolean isChildOf(@Nonnull Subject parent) {
return handle().thenApply(handle -> handle.isChildOf(
ImmutableContextSet.empty(),
SubjectReferenceFactory.obtain(this.service, parent)
this.service.getReferenceFactory().obtain(parent)
)).join();
}
@ -118,7 +117,7 @@ public final class SubjectProxy implements Subject, ProxiedSubject {
public boolean isChildOf(@Nonnull Set<Context> contexts, @Nonnull Subject parent) {
return handle().thenApply(handle -> handle.isChildOf(
CompatibilityUtil.convertContexts(contexts),
SubjectReferenceFactory.obtain(this.service, parent)
this.service.getReferenceFactory().obtain(parent)
)).join();
}

View File

@ -44,14 +44,14 @@ import java.util.Objects;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public final class LPDescriptionBuilder implements PermissionDescription.Builder {
public final class DescriptionBuilder implements PermissionDescription.Builder {
@Nonnull private final LPPermissionService service;
@Nonnull private final PluginContainer container;
@Nonnull private final Map<String, Tristate> roles = new HashMap<>();
@Nullable private String id = null;
@Nullable private Text description = null;
public LPDescriptionBuilder(LPPermissionService service, PluginContainer container) {
public DescriptionBuilder(LPPermissionService service, PluginContainer container) {
this.service = Objects.requireNonNull(service, "service");
this.container = Objects.requireNonNull(container, "container");
}
@ -107,8 +107,8 @@ public final class LPDescriptionBuilder implements PermissionDescription.Builder
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof LPDescriptionBuilder)) return false;
final LPDescriptionBuilder other = (LPDescriptionBuilder) o;
if (!(o instanceof DescriptionBuilder)) return false;
final DescriptionBuilder other = (DescriptionBuilder) o;
return this.container.equals(other.container) &&
this.roles.equals(other.roles) &&

View File

@ -31,7 +31,6 @@ import me.lucko.luckperms.common.utils.ImmutableCollectors;
import me.lucko.luckperms.sponge.service.model.LPPermissionDescription;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.model.LPSubjectCollection;
import me.lucko.luckperms.sponge.service.reference.SubjectReferenceFactory;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.plugin.PluginContainer;
@ -74,7 +73,7 @@ public final class PermissionServiceProxy implements PermissionService {
@Nonnull
@Override
public Subject getDefaults() {
return this.handle.getDefaults().sponge();
return this.handle.getRootDefaults().sponge();
}
@Nonnull
@ -129,7 +128,7 @@ public final class PermissionServiceProxy implements PermissionService {
}
// obtain a reference
return SubjectReferenceFactory.obtain(this.handle, collectionIdentifier, subjectIdentifier);
return this.handle.getReferenceFactory().obtain(collectionIdentifier, subjectIdentifier);
}
@Override
@ -139,7 +138,7 @@ public final class PermissionServiceProxy implements PermissionService {
throw new IllegalArgumentException("Couldn't find a plugin container for " + o.getClass().getSimpleName());
}
return new LPDescriptionBuilder(this.handle, container.get());
return new DescriptionBuilder(this.handle, container.get());
}
@Nonnull

View File

@ -29,7 +29,6 @@ import me.lucko.luckperms.common.utils.ImmutableCollectors;
import me.lucko.luckperms.sponge.service.CompatibilityUtil;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectCollection;
import me.lucko.luckperms.sponge.service.reference.SubjectReferenceFactory;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.Subject;
@ -110,7 +109,7 @@ public final class SubjectCollectionProxy implements SubjectCollection {
throw new IllegalArgumentException("Subject identifier '" + subjectIdentifier + "' does not pass the validity predicate");
}
return SubjectReferenceFactory.obtain(this.handle.getService(), getIdentifier(), subjectIdentifier);
return this.handle.getService().getReferenceFactory().obtain(getIdentifier(), subjectIdentifier);
}
@Nonnull

View File

@ -30,8 +30,7 @@ import me.lucko.luckperms.sponge.service.CompatibilityUtil;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectData;
import me.lucko.luckperms.sponge.service.reference.LPSubjectReference;
import me.lucko.luckperms.sponge.service.reference.SubjectReferenceFactory;
import me.lucko.luckperms.sponge.service.model.LPSubjectReference;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.SubjectData;
@ -120,13 +119,13 @@ public final class SubjectDataProxy implements SubjectData {
@Nonnull
@Override
public CompletableFuture<Boolean> addParent(@Nonnull Set<Context> contexts, @Nonnull org.spongepowered.api.service.permission.SubjectReference ref) {
return handle().thenCompose(handle -> handle.addParent(CompatibilityUtil.convertContexts(contexts), SubjectReferenceFactory.obtain(this.service, ref)));
return handle().thenCompose(handle -> handle.addParent(CompatibilityUtil.convertContexts(contexts), this.service.getReferenceFactory().obtain(ref)));
}
@Nonnull
@Override
public CompletableFuture<Boolean> removeParent(@Nonnull Set<Context> contexts, @Nonnull org.spongepowered.api.service.permission.SubjectReference ref) {
return handle().thenCompose(handle -> handle.removeParent(CompatibilityUtil.convertContexts(contexts), SubjectReferenceFactory.obtain(this.service, ref)));
return handle().thenCompose(handle -> handle.removeParent(CompatibilityUtil.convertContexts(contexts), this.service.getReferenceFactory().obtain(ref)));
}
@Nonnull

View File

@ -29,9 +29,8 @@ import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.sponge.service.CompatibilityUtil;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectReference;
import me.lucko.luckperms.sponge.service.model.ProxiedSubject;
import me.lucko.luckperms.sponge.service.reference.LPSubjectReference;
import me.lucko.luckperms.sponge.service.reference.SubjectReferenceFactory;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.service.context.Context;
@ -113,12 +112,12 @@ public final class SubjectProxy implements Subject, ProxiedSubject {
@Override
public boolean isChildOf(@Nonnull SubjectReference parent) {
return handle().thenApply(handle -> handle.isChildOf(ImmutableContextSet.empty(), SubjectReferenceFactory.obtain(this.service, parent))).join();
return handle().thenApply(handle -> handle.isChildOf(ImmutableContextSet.empty(), this.service.getReferenceFactory().obtain(parent))).join();
}
@Override
public boolean isChildOf(@Nonnull Set<Context> contexts, @Nonnull SubjectReference parent) {
return handle().thenApply(handle -> handle.isChildOf(CompatibilityUtil.convertContexts(contexts), SubjectReferenceFactory.obtain(this.service, parent))).join();
return handle().thenApply(handle -> handle.isChildOf(CompatibilityUtil.convertContexts(contexts), this.service.getReferenceFactory().obtain(parent))).join();
}
@Nonnull

View File

@ -25,8 +25,6 @@
package me.lucko.luckperms.sponge.service.model;
import me.lucko.luckperms.sponge.service.reference.LPSubjectReference;
import org.spongepowered.api.plugin.PluginContainer;
import org.spongepowered.api.service.permission.PermissionDescription;
import org.spongepowered.api.text.Text;

View File

@ -60,7 +60,7 @@ public interface LPPermissionService {
LPSubjectCollection getDefaultSubjects();
LPSubject getDefaults();
LPSubject getRootDefaults();
Predicate<String> getIdentifierValidityPredicate();

View File

@ -29,8 +29,6 @@ import com.google.common.collect.ImmutableList;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.sponge.service.reference.LPSubjectReference;
import me.lucko.luckperms.sponge.service.reference.SubjectReferenceFactory;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.service.permission.Subject;
@ -49,12 +47,10 @@ public interface LPSubject {
String getIdentifier();
default LPSubjectReference toReference() {
return SubjectReferenceFactory.obtain(getService(), this);
return getService().getReferenceFactory().obtain(this);
}
default LPSubject getDefaults() {
return getService().getDefaultSubjects().loadSubject(getIdentifier()).join();
}
LPSubject getDefaults();
default Optional<String> getFriendlyIdentifier() {
return Optional.empty();

View File

@ -30,7 +30,6 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.sponge.service.reference.LPSubjectReference;
import org.spongepowered.api.service.permission.SubjectCollection;

View File

@ -31,7 +31,6 @@ import com.google.common.collect.ImmutableMap;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.common.model.NodeMapType;
import me.lucko.luckperms.sponge.service.reference.LPSubjectReference;
import org.spongepowered.api.service.permission.SubjectData;

View File

@ -23,9 +23,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.sponge.service.reference;
import me.lucko.luckperms.sponge.service.model.LPSubject;
package me.lucko.luckperms.sponge.service.model;
import org.spongepowered.api.service.permission.SubjectReference;

View File

@ -25,8 +25,6 @@
package me.lucko.luckperms.sponge.service.model;
import me.lucko.luckperms.sponge.service.reference.LPSubjectReference;
import org.spongepowered.api.service.permission.Subject;
import javax.annotation.Nonnull;

View File

@ -25,9 +25,19 @@
package me.lucko.luckperms.sponge.service.model;
/**
* Defines in what order data should be resolved.
*/
public enum ResolutionOrder {
/**
* Marks that transient data should be considered before enduring data
*/
TRANSIENT_FIRST,
/**
* Marks that transient data should be considered after enduring data
*/
TRANSIENT_LAST
}

View File

@ -27,6 +27,7 @@ package me.lucko.luckperms.sponge.service.reference;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectReference;
import org.spongepowered.api.service.permission.Subject;
@ -43,7 +44,7 @@ import javax.annotation.Nonnull;
* Use of this class (or interface) should have no negative impact on
* performance, as {@link #resolve()} calls are cached.
*/
final class LuckPermsSubjectReference implements LPSubjectReference {
final class CachedSubjectReference implements LPSubjectReference {
/**
* The time a subject instance should be cached in this reference
@ -71,7 +72,7 @@ final class LuckPermsSubjectReference implements LPSubjectReference {
private long lastLookup = 0L;
private WeakReference<LPSubject> cache = null;
LuckPermsSubjectReference(LPPermissionService service, String collectionIdentifier, String subjectIdentifier) {
CachedSubjectReference(LPPermissionService service, String collectionIdentifier, String subjectIdentifier) {
this.service = Objects.requireNonNull(service);
this.collectionIdentifier = Objects.requireNonNull(collectionIdentifier);
this.subjectIdentifier = Objects.requireNonNull(subjectIdentifier);

View File

@ -31,6 +31,7 @@ import com.google.common.base.Splitter;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectReference;
import me.lucko.luckperms.sponge.service.model.ProxiedSubject;
import org.spongepowered.api.service.permission.Subject;
@ -45,34 +46,6 @@ import java.util.concurrent.TimeUnit;
*/
public final class SubjectReferenceFactory {
// static util access
@Deprecated
public static LPSubjectReference deserialize(LPPermissionService service, String serializedReference) {
Objects.requireNonNull(service, "service");
return service.getReferenceFactory().deserialize(serializedReference);
}
public static LPSubjectReference obtain(LPPermissionService service, LPSubject subject) {
Objects.requireNonNull(service, "service");
return service.getReferenceFactory().obtain(subject);
}
public static LPSubjectReference obtain(LPPermissionService service, Subject subject) {
Objects.requireNonNull(service, "service");
return service.getReferenceFactory().obtain(subject);
}
public static LPSubjectReference obtain(LPPermissionService service, SubjectReference reference) {
Objects.requireNonNull(service, "service");
return service.getReferenceFactory().obtain(reference);
}
public static LPSubjectReference obtain(LPPermissionService service, String collectionIdentifier, String subjectIdentifier) {
Objects.requireNonNull(service, "service");
return service.getReferenceFactory().obtain(collectionIdentifier, subjectIdentifier);
}
/**
* The permission service to obtain real subject instances from
*/
@ -87,9 +60,9 @@ public final class SubjectReferenceFactory {
*
* It's perfectly ok if two instances of the same SubjectReference exist. (hence the 1 hour expiry)
*/
private final LoadingCache<SubjectReferenceAttributes, LuckPermsSubjectReference> referenceCache = Caffeine.newBuilder()
private final LoadingCache<SubjectReferenceAttributes, CachedSubjectReference> referenceCache = Caffeine.newBuilder()
.expireAfterAccess(1, TimeUnit.HOURS)
.build(a -> new LuckPermsSubjectReference(SubjectReferenceFactory.this.service, a.collectionId, a.id));
.build(a -> new CachedSubjectReference(SubjectReferenceFactory.this.service, a.collectionId, a.id));
public SubjectReferenceFactory(LPPermissionService service) {
this.service = service;
@ -105,7 +78,7 @@ public final class SubjectReferenceFactory {
public LPSubjectReference obtain(LPSubject subject) {
Objects.requireNonNull(subject, "subject");
LPSubjectReference ret = obtain(subject.getParentCollection().getIdentifier(), subject.getIdentifier());
((LuckPermsSubjectReference) ret).fillCache(subject);
((CachedSubjectReference) ret).fillCache(subject);
return ret;
}

View File

@ -156,7 +156,6 @@ public class LPSpongePlugin extends AbstractLuckPermsPlugin {
} else {
this.bootstrap.getGame().getServiceManager().setProvider(this.bootstrap, LPPermissionService.class, this.service);
this.bootstrap.getGame().getServiceManager().setProvider(this.bootstrap, PermissionService.class, this.service.sponge());
this.bootstrap.getGame().getServiceManager().setProvider(this.bootstrap, LuckPermsService.class, this.service);
}
}
@ -185,7 +184,6 @@ public class LPSpongePlugin extends AbstractLuckPermsPlugin {
getLogger().info("Providing late registration of PermissionService...");
this.bootstrap.getGame().getServiceManager().setProvider(this.bootstrap, LPPermissionService.class, this.service);
this.bootstrap.getGame().getServiceManager().setProvider(this.bootstrap, PermissionService.class, this.service.sponge());
this.bootstrap.getGame().getServiceManager().setProvider(this.bootstrap, LuckPermsService.class, this.service);
}
}

View File

@ -39,7 +39,7 @@ import me.lucko.luckperms.common.locale.LocaleManager;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.sponge.service.model.LPSubjectData;
import me.lucko.luckperms.sponge.service.reference.LPSubjectReference;
import me.lucko.luckperms.sponge.service.model.LPSubjectReference;
import java.util.List;
import java.util.Map;

View File

@ -29,7 +29,7 @@ import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.CommandUtils;
import me.lucko.luckperms.sponge.service.reference.LPSubjectReference;
import me.lucko.luckperms.sponge.service.model.LPSubjectReference;
import java.util.List;
import java.util.Map;

View File

@ -42,11 +42,10 @@ 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.ProxyFactory;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectCollection;
import me.lucko.luckperms.sponge.service.reference.LPSubjectReference;
import me.lucko.luckperms.sponge.service.reference.SubjectReferenceFactory;
import me.lucko.luckperms.sponge.service.model.LPSubjectReference;
import me.lucko.luckperms.sponge.service.proxy.ProxyFactory;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.service.permission.SubjectCollection;
@ -191,7 +190,7 @@ public class SpongeGroupManager extends AbstractGroupManager<SpongeGroup> implem
List<HeldPermission<String>> lookup = this.plugin.getStorage().getGroupsWithPermission(permission).join();
for (HeldPermission<String> holder : lookup) {
if (holder.asNode().getFullContexts().equals(ImmutableContextSet.empty())) {
ret.put(SubjectReferenceFactory.obtain(getService(), getIdentifier(), holder.getHolder()), holder.getValue());
ret.put(getService().getReferenceFactory().obtain(getIdentifier(), holder.getHolder()), holder.getValue());
}
}
@ -207,7 +206,7 @@ public class SpongeGroupManager extends AbstractGroupManager<SpongeGroup> implem
List<HeldPermission<String>> lookup = this.plugin.getStorage().getGroupsWithPermission(permission).join();
for (HeldPermission<String> holder : lookup) {
if (holder.asNode().getFullContexts().equals(contexts)) {
ret.put(SubjectReferenceFactory.obtain(getService(), getIdentifier(), holder.getHolder()), holder.getValue());
ret.put(getService().getReferenceFactory().obtain(getIdentifier(), holder.getHolder()), holder.getValue());
}
}
@ -235,7 +234,7 @@ public class SpongeGroupManager extends AbstractGroupManager<SpongeGroup> implem
@Override
public LPSubject getDefaults() {
return getService().getDefaultSubjects().loadSubject(getIdentifier()).join();
return getService().getDefaultSubjects().getTypeDefaults(getIdentifier());
}
}

View File

@ -43,11 +43,10 @@ import me.lucko.luckperms.common.utils.Uuids;
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.ProxyFactory;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectCollection;
import me.lucko.luckperms.sponge.service.reference.LPSubjectReference;
import me.lucko.luckperms.sponge.service.reference.SubjectReferenceFactory;
import me.lucko.luckperms.sponge.service.model.LPSubjectReference;
import me.lucko.luckperms.sponge.service.proxy.ProxyFactory;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.service.permission.SubjectCollection;
@ -216,7 +215,7 @@ public class SpongeUserManager extends AbstractUserManager<SpongeUser> implement
List<HeldPermission<UUID>> lookup = this.plugin.getStorage().getUsersWithPermission(permission).join();
for (HeldPermission<UUID> holder : lookup) {
if (holder.asNode().getFullContexts().equals(ImmutableContextSet.empty())) {
ret.put(SubjectReferenceFactory.obtain(getService(), getIdentifier(), holder.getHolder().toString()), holder.getValue());
ret.put(getService().getReferenceFactory().obtain(getIdentifier(), holder.getHolder().toString()), holder.getValue());
}
}
@ -232,7 +231,7 @@ public class SpongeUserManager extends AbstractUserManager<SpongeUser> implement
List<HeldPermission<UUID>> lookup = this.plugin.getStorage().getUsersWithPermission(permission).join();
for (HeldPermission<UUID> holder : lookup) {
if (holder.asNode().getFullContexts().equals(contexts)) {
ret.put(SubjectReferenceFactory.obtain(getService(), getIdentifier(), holder.getHolder().toString()), holder.getValue());
ret.put(getService().getReferenceFactory().obtain(getIdentifier(), holder.getHolder().toString()), holder.getValue());
}
}
@ -260,7 +259,7 @@ public class SpongeUserManager extends AbstractUserManager<SpongeUser> implement
@Override
public LPSubject getDefaults() {
return getService().getDefaultSubjects().loadSubject(getIdentifier()).join();
return getService().getDefaultSubjects().getTypeDefaults(getIdentifier());
}
}

View File

@ -32,7 +32,7 @@ import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.model.LPSubject;
public abstract class DefaultsProcessor implements PermissionProcessor {
private final LPPermissionService service;
protected final LPPermissionService service;
private final ImmutableContextSet contexts;
public DefaultsProcessor(LPPermissionService service, ImmutableContextSet contexts) {
@ -40,16 +40,16 @@ public abstract class DefaultsProcessor implements PermissionProcessor {
this.contexts = contexts;
}
protected abstract LPSubject getTypeDefaults(LPPermissionService service);
protected abstract LPSubject getTypeDefaults();
@Override
public Tristate hasPermission(String permission) {
Tristate t = getTypeDefaults(this.service).getPermissionValue(this.contexts, permission);
Tristate t = getTypeDefaults().getPermissionValue(this.contexts, permission);
if (t != Tristate.UNDEFINED) {
return t;
}
t = this.service.getDefaults().getPermissionValue(this.contexts, permission);
t = this.service.getRootDefaults().getPermissionValue(this.contexts, permission);
if (t != Tristate.UNDEFINED) {
return t;
}

View File

@ -38,7 +38,7 @@ public class FixedDefaultsProcessor extends DefaultsProcessor {
}
@Override
protected LPSubject getTypeDefaults(LPPermissionService service) {
protected LPSubject getTypeDefaults() {
return this.defaultsSubject;
}
}

View File

@ -36,7 +36,7 @@ public class GroupDefaultsProcessor extends DefaultsProcessor implements Permiss
}
@Override
protected LPSubject getTypeDefaults(LPPermissionService service) {
return service.getGroupSubjects().getDefaults();
protected LPSubject getTypeDefaults() {
return this.service.getGroupSubjects().getDefaults();
}
}

View File

@ -36,7 +36,7 @@ public class UserDefaultsProcessor extends DefaultsProcessor implements Permissi
}
@Override
protected LPSubject getTypeDefaults(LPPermissionService service) {
return service.getUserSubjects().getDefaults();
protected LPSubject getTypeDefaults() {
return this.service.getUserSubjects().getDefaults();
}
}

View File

@ -36,13 +36,17 @@ import me.lucko.luckperms.sponge.LPSpongePlugin;
import me.lucko.luckperms.sponge.contexts.SpongeProxiedContextCalculator;
import me.lucko.luckperms.sponge.managers.SpongeGroupManager;
import me.lucko.luckperms.sponge.managers.SpongeUserManager;
import me.lucko.luckperms.sponge.service.misc.SimplePermissionDescription;
import me.lucko.luckperms.sponge.service.model.LPPermissionDescription;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectCollection;
import me.lucko.luckperms.sponge.service.model.LPSubjectReference;
import me.lucko.luckperms.sponge.service.persisted.DefaultsCollection;
import me.lucko.luckperms.sponge.service.persisted.PersistedCollection;
import me.lucko.luckperms.sponge.service.persisted.SubjectStorage;
import me.lucko.luckperms.sponge.service.proxy.ProxyFactory;
import me.lucko.luckperms.sponge.service.reference.SubjectReferenceFactory;
import me.lucko.luckperms.sponge.service.storage.SubjectStorage;
import org.spongepowered.api.plugin.PluginContainer;
import org.spongepowered.api.service.context.ContextCalculator;
@ -63,17 +67,39 @@ import java.util.function.Predicate;
*/
public class LuckPermsService implements LPPermissionService {
/**
* The plugin
*/
private final LPSpongePlugin plugin;
/**
* A cached proxy of this instance
*/
private final PermissionService spongeProxy;
/**
* Reference factory, used to obtain {@link LPSubjectReference}s.
*/
private final SubjectReferenceFactory referenceFactory;
private final SubjectStorage storage;
private final SpongeUserManager userSubjects;
private final SpongeGroupManager groupSubjects;
private final PersistedCollection defaultSubjects;
private final Set<LPPermissionDescription> descriptionSet;
/**
* Subject storage, used to save PersistedSubjects to a file
*/
private final SubjectStorage storage;
/**
* The defaults subject collection
*/
private final DefaultsCollection defaultSubjects;
/**
* A set of registered permission description instances
*/
private final Set<LPPermissionDescription> permissionDescriptions;
/**
* The loaded collections in this service
*/
private final LoadingCache<String, LPSubjectCollection> collections = Caffeine.newBuilder()
.build(s -> new PersistedCollection(this, s));
@ -81,29 +107,33 @@ public class LuckPermsService implements LPPermissionService {
this.plugin = plugin;
this.referenceFactory = new SubjectReferenceFactory(this);
this.spongeProxy = ProxyFactory.toSponge(this);
this.permissionDescriptions = ConcurrentHashMap.newKeySet();
// init subject storage
this.storage = new SubjectStorage(this, new File(plugin.getBootstrap().getDataDirectory(), "sponge-data"));
this.userSubjects = plugin.getUserManager();
this.groupSubjects = plugin.getGroupManager();
this.defaultSubjects = new PersistedCollection(this, "defaults");
// load defaults collection
this.defaultSubjects = new DefaultsCollection(this);
this.defaultSubjects.loadAll();
this.collections.put("user", this.userSubjects);
this.collections.put("group", this.groupSubjects);
// pre-populate collections map with the default types
this.collections.put("user", plugin.getUserManager());
this.collections.put("group", plugin.getGroupManager());
this.collections.put("defaults", this.defaultSubjects);
for (String collection : this.storage.getSavedCollections()) {
if (this.collections.asMap().containsKey(collection.toLowerCase())) {
// load known collections
for (String identifier : this.storage.getSavedCollections()) {
if (this.collections.asMap().containsKey(identifier.toLowerCase())) {
continue;
}
PersistedCollection c = new PersistedCollection(this, collection.toLowerCase());
c.loadAll();
this.collections.put(c.getIdentifier(), c);
}
// load data
PersistedCollection collection = new PersistedCollection(this, identifier.toLowerCase());
collection.loadAll();
this.descriptionSet = ConcurrentHashMap.newKeySet();
// cache in this instance
this.collections.put(collection.getIdentifier(), collection);
}
}
@Override
@ -132,22 +162,22 @@ public class LuckPermsService implements LPPermissionService {
@Override
public SpongeUserManager getUserSubjects() {
return this.userSubjects;
return this.plugin.getUserManager();
}
@Override
public SpongeGroupManager getGroupSubjects() {
return this.groupSubjects;
return this.plugin.getGroupManager();
}
@Override
public PersistedCollection getDefaultSubjects() {
public DefaultsCollection getDefaultSubjects() {
return this.defaultSubjects;
}
@Override
public LPSubject getDefaults() {
return getDefaultSubjects().loadSubject("default").join();
public LPSubject getRootDefaults() {
return this.defaultSubjects.getRootSubject();
}
@Override
@ -168,15 +198,15 @@ public class LuckPermsService implements LPPermissionService {
@Override
public LPPermissionDescription registerPermissionDescription(String id, Text description, PluginContainer owner) {
LuckPermsPermissionDescription desc = new LuckPermsPermissionDescription(this, id, description, owner);
this.descriptionSet.add(desc);
SimplePermissionDescription desc = new SimplePermissionDescription(this, id, description, owner);
this.permissionDescriptions.add(desc);
return desc;
}
@Override
public Optional<LPPermissionDescription> getDescription(String s) {
Objects.requireNonNull(s);
for (LPPermissionDescription d : this.descriptionSet) {
for (LPPermissionDescription d : this.permissionDescriptions) {
if (d.getId().equals(s)) {
return Optional.of(d);
}
@ -187,11 +217,11 @@ public class LuckPermsService implements LPPermissionService {
@Override
public ImmutableSet<LPPermissionDescription> getDescriptions() {
Set<LPPermissionDescription> descriptions = new HashSet<>(this.descriptionSet);
Set<LPPermissionDescription> descriptions = new HashSet<>(this.permissionDescriptions);
// collect known values from the permission vault
for (String knownPermission : this.plugin.getPermissionVault().getKnownPermissions()) {
LPPermissionDescription desc = new LuckPermsPermissionDescription(this, knownPermission, null, null);
LPPermissionDescription desc = new SimplePermissionDescription(this, knownPermission, null, null);
// don't override plugin defined values
if (!descriptions.contains(desc)) {

View File

@ -1,71 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* 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 me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.sponge.service.internal.GroupSubject;
import me.lucko.luckperms.sponge.service.reference.LPSubjectReference;
import org.spongepowered.api.service.permission.PermissionService;
import java.util.Comparator;
public class SubjectComparator implements Comparator<LPSubjectReference> {
private static final Comparator<LPSubjectReference> INSTANCE = new SubjectComparator();
private static final Comparator<LPSubjectReference> REVERSE = INSTANCE.reversed();
public static Comparator<LPSubjectReference> normal() {
return INSTANCE;
}
public static Comparator<LPSubjectReference> reverse() {
return REVERSE;
}
@Override
public int compare(LPSubjectReference o1, LPSubjectReference o2) {
if (o1.equals(o2)) {
return 0;
}
boolean o1isGroup = o1.getCollectionIdentifier().equals(PermissionService.SUBJECTS_GROUP);
boolean o2isGroup = o2.getCollectionIdentifier().equals(PermissionService.SUBJECTS_GROUP);
if (o1isGroup != o2isGroup) {
return o1isGroup ? 1 : -1;
}
// Neither are groups
if (!o1isGroup) {
return 1;
}
Group g1 = ((GroupSubject) o1.resolveLp().join()).getParent();
Group g2 = ((GroupSubject) o2.resolveLp().join()).getParent();
return Integer.compare(g1.getWeight().orElse(0), g2.getWeight().orElse(0)) == 1 ? 1 : -1;
}
}

View File

@ -29,29 +29,16 @@ import com.google.common.collect.ImmutableList;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.caching.MetaContexts;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.api.metastacking.MetaStackDefinition;
import me.lucko.luckperms.common.caching.AbstractCachedData;
import me.lucko.luckperms.common.caching.type.MetaAccumulator;
import me.lucko.luckperms.common.calculators.CalculatorFactory;
import me.lucko.luckperms.common.calculators.PermissionCalculator;
import me.lucko.luckperms.common.calculators.PermissionCalculatorMetadata;
import me.lucko.luckperms.common.graph.TraversalAlgorithm;
import me.lucko.luckperms.common.metastacking.SimpleMetaStackDefinition;
import me.lucko.luckperms.common.metastacking.StandardStackElements;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.processors.MapProcessor;
import me.lucko.luckperms.common.processors.PermissionProcessor;
import me.lucko.luckperms.common.processors.WildcardProcessor;
import me.lucko.luckperms.common.verbose.CheckOrigin;
import me.lucko.luckperms.sponge.processors.FixedDefaultsProcessor;
import me.lucko.luckperms.sponge.processors.SpongeWildcardProcessor;
import me.lucko.luckperms.sponge.LPSpongePlugin;
import me.lucko.luckperms.sponge.service.inheritance.SubjectInheritanceGraph;
import me.lucko.luckperms.sponge.service.inheritance.SubjectInheritanceGraphs;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.reference.LPSubjectReference;
import me.lucko.luckperms.sponge.service.model.LPSubjectReference;
import java.util.HashMap;
import java.util.LinkedHashSet;
@ -60,17 +47,17 @@ import java.util.Optional;
import java.util.Set;
public abstract class CalculatedSubject implements LPSubject {
private static final MetaStackDefinition DEFAULT_META_STACK = new SimpleMetaStackDefinition(
ImmutableList.of(StandardStackElements.HIGHEST_PRIORITY),
"", "", ""
);
private final LuckPermsPlugin plugin;
private final LPSpongePlugin plugin;
private final SubjectCachedData cachedData;
protected CalculatedSubject(LuckPermsPlugin plugin) {
protected CalculatedSubject(LPSpongePlugin plugin) {
this.plugin = plugin;
this.cachedData = new SubjectCachedData(plugin);
this.cachedData = new SubjectCachedData(this, plugin);
}
@Override
public LPSubject getDefaults() {
return this.plugin.getService().getDefaultSubjects().getTypeDefaults(getParentCollection().getIdentifier());
}
public abstract CalculatedSubjectData getSubjectData();
@ -353,58 +340,4 @@ public abstract class CalculatedSubject implements LPSubject {
this.cachedData.invalidateCaches();
}
private final class SubjectCachedData extends AbstractCachedData implements CalculatorFactory {
private SubjectCachedData(LuckPermsPlugin plugin) {
super(plugin);
}
@Override
protected PermissionCalculatorMetadata getMetadataForContexts(Contexts contexts) {
return PermissionCalculatorMetadata.of(null, getParentCollection().getIdentifier() + "/" + getIdentifier(), contexts.getContexts());
}
@Override
protected CalculatorFactory getCalculatorFactory() {
return this;
}
@Override
protected MetaContexts getDefaultMetaContexts(Contexts contexts) {
return MetaContexts.of(contexts, DEFAULT_META_STACK, DEFAULT_META_STACK);
}
@Override
protected Map<String, Boolean> resolvePermissions() {
return resolveAllPermissions();
}
@Override
protected Map<String, Boolean> resolvePermissions(Contexts contexts) {
return resolveAllPermissions(contexts.getContexts().makeImmutable());
}
@Override
protected void resolveMeta(MetaAccumulator accumulator) {
resolveAllOptions(accumulator);
}
@Override
protected void resolveMeta(MetaAccumulator accumulator, MetaContexts contexts) {
resolveAllOptions(accumulator, contexts.getContexts().getContexts().makeImmutable());
}
@Override
public PermissionCalculator build(Contexts contexts, PermissionCalculatorMetadata metadata) {
ImmutableList.Builder<PermissionProcessor> processors = ImmutableList.builder();
processors.add(new MapProcessor());
processors.add(new SpongeWildcardProcessor());
processors.add(new WildcardProcessor());
if (!getParentCollection().isDefaultsCollection()) {
processors.add(new FixedDefaultsProcessor(getService(), contexts.getContexts().makeImmutable(), getDefaults()));
}
return new PermissionCalculator(this.plugin, metadata, processors.build());
}
}
}

View File

@ -33,12 +33,11 @@ import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.common.contexts.ContextSetComparator;
import me.lucko.luckperms.common.model.NodeMapType;
import me.lucko.luckperms.sponge.service.ProxyFactory;
import me.lucko.luckperms.sponge.service.SubjectComparator;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectData;
import me.lucko.luckperms.sponge.service.reference.LPSubjectReference;
import me.lucko.luckperms.sponge.service.model.LPSubjectReference;
import me.lucko.luckperms.sponge.service.proxy.ProxyFactory;
import org.spongepowered.api.service.permission.SubjectData;
@ -207,7 +206,7 @@ public class CalculatedSubjectData implements LPSubjectData {
public ImmutableMap<ImmutableContextSet, ImmutableList<LPSubjectReference>> getAllParents() {
ImmutableMap.Builder<ImmutableContextSet, ImmutableList<LPSubjectReference>> map = ImmutableMap.builder();
for (Map.Entry<ImmutableContextSet, Set<LPSubjectReference>> e : this.parents.entrySet()) {
map.put(e.getKey(), ImmutableList.sortedCopyOf(SubjectComparator.reverse(), e.getValue()));
map.put(e.getKey(), ImmutableList.copyOf(e.getValue()));
}
return map.build();
}

View File

@ -30,78 +30,77 @@ import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.common.model.NodeMapType;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.reference.LPSubjectReference;
import me.lucko.luckperms.sponge.service.model.LPSubjectReference;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
/**
* Extension of CalculatedSubjectData which allows subclasses to respond to updates
*/
public abstract class MonitoredSubjectData extends CalculatedSubjectData {
private final Function<Boolean, Boolean> saveFunction = b -> {
onUpdate(b);
return b;
};
public MonitoredSubjectData(LPSubject subject, NodeMapType type, LuckPermsService service) {
super(subject, type, service);
}
private boolean callUpdate(boolean success) {
onUpdate(success);
return success;
}
protected abstract void onUpdate(boolean success);
@Override
public CompletableFuture<Boolean> setPermission(ImmutableContextSet contexts, String permission, Tristate value) {
return super.setPermission(contexts, permission, value).thenApply(this.saveFunction);
return super.setPermission(contexts, permission, value).thenApply(this::callUpdate);
}
@Override
public CompletableFuture<Boolean> clearPermissions() {
return super.clearPermissions().thenApply(this.saveFunction);
return super.clearPermissions().thenApply(this::callUpdate);
}
@Override
public CompletableFuture<Boolean> clearPermissions(ImmutableContextSet contexts) {
return super.clearPermissions(contexts).thenApply(this.saveFunction);
return super.clearPermissions(contexts).thenApply(this::callUpdate);
}
@Override
public CompletableFuture<Boolean> addParent(ImmutableContextSet contexts, LPSubjectReference parent) {
return super.addParent(contexts, parent).thenApply(this.saveFunction);
return super.addParent(contexts, parent).thenApply(this::callUpdate);
}
@Override
public CompletableFuture<Boolean> removeParent(ImmutableContextSet contexts, LPSubjectReference parent) {
return super.removeParent(contexts, parent).thenApply(this.saveFunction);
return super.removeParent(contexts, parent).thenApply(this::callUpdate);
}
@Override
public CompletableFuture<Boolean> clearParents() {
return super.clearParents().thenApply(this.saveFunction);
return super.clearParents().thenApply(this::callUpdate);
}
@Override
public CompletableFuture<Boolean> clearParents(ImmutableContextSet contexts) {
return super.clearParents(contexts).thenApply(this.saveFunction);
return super.clearParents(contexts).thenApply(this::callUpdate);
}
@Override
public CompletableFuture<Boolean> setOption(ImmutableContextSet contexts, String key, String value) {
return super.setOption(contexts, key, value).thenApply(this.saveFunction);
return super.setOption(contexts, key, value).thenApply(this::callUpdate);
}
@Override
public CompletableFuture<Boolean> unsetOption(ImmutableContextSet contexts, String key) {
return super.unsetOption(contexts, key).thenApply(this.saveFunction);
return super.unsetOption(contexts, key).thenApply(this::callUpdate);
}
@Override
public CompletableFuture<Boolean> clearOptions() {
return super.clearOptions().thenApply(this.saveFunction);
return super.clearOptions().thenApply(this::callUpdate);
}
@Override
public CompletableFuture<Boolean> clearOptions(ImmutableContextSet contexts) {
return super.clearOptions(contexts).thenApply(this.saveFunction);
return super.clearOptions(contexts).thenApply(this::callUpdate);
}
}

View File

@ -0,0 +1,110 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* 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 com.google.common.collect.ImmutableList;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.caching.MetaContexts;
import me.lucko.luckperms.api.metastacking.MetaStackDefinition;
import me.lucko.luckperms.common.caching.AbstractCachedData;
import me.lucko.luckperms.common.caching.type.MetaAccumulator;
import me.lucko.luckperms.common.calculators.CalculatorFactory;
import me.lucko.luckperms.common.calculators.PermissionCalculator;
import me.lucko.luckperms.common.calculators.PermissionCalculatorMetadata;
import me.lucko.luckperms.common.metastacking.SimpleMetaStackDefinition;
import me.lucko.luckperms.common.metastacking.StandardStackElements;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.processors.MapProcessor;
import me.lucko.luckperms.common.processors.PermissionProcessor;
import me.lucko.luckperms.common.processors.WildcardProcessor;
import me.lucko.luckperms.sponge.processors.FixedDefaultsProcessor;
import me.lucko.luckperms.sponge.processors.SpongeWildcardProcessor;
import java.util.Map;
public class SubjectCachedData extends AbstractCachedData implements CalculatorFactory {
private static final MetaStackDefinition DEFAULT_META_STACK = new SimpleMetaStackDefinition(
ImmutableList.of(StandardStackElements.HIGHEST_PRIORITY),
"", "", ""
);
private final CalculatedSubject subject;
SubjectCachedData(CalculatedSubject subject, LuckPermsPlugin plugin) {
super(plugin);
this.subject = subject;
}
@Override
protected PermissionCalculatorMetadata getMetadataForContexts(Contexts contexts) {
return PermissionCalculatorMetadata.of(null, this.subject.getParentCollection().getIdentifier() + "/" + this.subject.getIdentifier(), contexts.getContexts());
}
@Override
protected CalculatorFactory getCalculatorFactory() {
return this;
}
@Override
protected MetaContexts getDefaultMetaContexts(Contexts contexts) {
return MetaContexts.of(contexts, DEFAULT_META_STACK, DEFAULT_META_STACK);
}
@Override
protected Map<String, Boolean> resolvePermissions() {
return this.subject.resolveAllPermissions();
}
@Override
protected Map<String, Boolean> resolvePermissions(Contexts contexts) {
return this.subject.resolveAllPermissions(contexts.getContexts().makeImmutable());
}
@Override
protected void resolveMeta(MetaAccumulator accumulator) {
this.subject.resolveAllOptions(accumulator);
}
@Override
protected void resolveMeta(MetaAccumulator accumulator, MetaContexts contexts) {
this.subject.resolveAllOptions(accumulator, contexts.getContexts().getContexts().makeImmutable());
}
@Override
public PermissionCalculator build(Contexts contexts, PermissionCalculatorMetadata metadata) {
ImmutableList.Builder<PermissionProcessor> processors = ImmutableList.builder();
processors.add(new MapProcessor());
processors.add(new SpongeWildcardProcessor());
processors.add(new WildcardProcessor());
if (!this.subject.getParentCollection().isDefaultsCollection()) {
processors.add(new FixedDefaultsProcessor(this.subject.getService(), contexts.getContexts().makeImmutable(), this.subject.getDefaults()));
}
return new PermissionCalculator(this.plugin, metadata, processors.build());
}
}

View File

@ -27,26 +27,27 @@ package me.lucko.luckperms.sponge.service.internal;
import com.google.common.collect.ImmutableList;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.caching.MetaData;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.common.graph.TraversalAlgorithm;
import me.lucko.luckperms.common.inheritance.InheritanceGraph;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.NodeMapType;
import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.common.verbose.CheckOrigin;
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.ProxyFactory;
import me.lucko.luckperms.sponge.service.SubjectComparator;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.reference.LPSubjectReference;
import me.lucko.luckperms.sponge.service.model.LPSubjectReference;
import me.lucko.luckperms.sponge.service.proxy.ProxyFactory;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.service.permission.Subject;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
/**
@ -86,6 +87,11 @@ public abstract class HolderSubject<T extends PermissionHolder> implements LPSub
return this.plugin.getService();
}
@Override
public LPSubject getDefaults() {
return this.plugin.getService().getDefaultSubjects().getTypeDefaults(getParentCollection().getIdentifier());
}
@Override
public HolderSubjectData getSubjectData() {
return this.subjectData;
@ -98,38 +104,30 @@ public abstract class HolderSubject<T extends PermissionHolder> implements LPSub
@Override
public Tristate getPermissionValue(ImmutableContextSet contexts, String permission) {
return this.parent.getCachedData().getPermissionData(this.plugin.getContextManager().formContexts(contexts)).getPermissionValue(permission, CheckOrigin.PLATFORM_LOOKUP_CHECK);
Contexts lookupContexts = this.plugin.getContextManager().formContexts(contexts);
return this.parent.getCachedData().getPermissionData(lookupContexts).getPermissionValue(permission, CheckOrigin.PLATFORM_LOOKUP_CHECK);
}
@Override
public boolean isChildOf(ImmutableContextSet contexts, LPSubjectReference parent) {
return parent.getCollectionIdentifier().equals(PermissionService.SUBJECTS_GROUP) && getPermissionValue(contexts, NodeFactory.groupNode(parent.getSubjectIdentifier())).asBoolean();
return parent.getCollectionIdentifier().equals(PermissionService.SUBJECTS_GROUP) &&
getPermissionValue(contexts, NodeFactory.groupNode(parent.getSubjectIdentifier())).asBoolean();
}
@Override
public ImmutableList<LPSubjectReference> getParents(ImmutableContextSet contexts) {
List<LPSubjectReference> subjects = new ArrayList<>();
InheritanceGraph graph = this.plugin.getInheritanceHandler().getGraph(this.plugin.getContextManager().formContexts(contexts));
Iterable<PermissionHolder> traversal = graph.traverse(TraversalAlgorithm.DEPTH_FIRST_PRE_ORDER, this.parent);
for (Map.Entry<String, Boolean> entry : this.parent.getCachedData().getPermissionData(this.plugin.getContextManager().formContexts(contexts)).getImmutableBacking().entrySet()) {
if (!entry.getValue()) {
ImmutableList.Builder<LPSubjectReference> subjects = ImmutableList.builder();
for (PermissionHolder parent : traversal) {
if (!(parent instanceof Group)) {
continue;
}
String groupName = NodeFactory.parseGroupNode(entry.getKey());
if (groupName == null) {
continue;
}
if (this.plugin.getGroupManager().isLoaded(groupName)) {
subjects.add(this.plugin.getService().getGroupSubjects().loadSubject(groupName).join().toReference());
}
subjects.add(((SpongeGroup) parent).sponge().toReference());
}
subjects.addAll(getParentCollection().getDefaults().getParents(contexts));
subjects.addAll(this.plugin.getService().getDefaults().getParents(contexts));
subjects.sort(SubjectComparator.reverse());
return ImmutableList.copyOf(subjects);
return subjects.build();
}
@Override
@ -157,7 +155,7 @@ public abstract class HolderSubject<T extends PermissionHolder> implements LPSub
return v;
}
return this.plugin.getService().getDefaults().getOption(contexts, s);
return this.plugin.getService().getRootDefaults().getOption(contexts, s);
}
@Override

View File

@ -40,10 +40,10 @@ import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import me.lucko.luckperms.sponge.service.ProxyFactory;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectData;
import me.lucko.luckperms.sponge.service.reference.LPSubjectReference;
import me.lucko.luckperms.sponge.service.model.LPSubjectReference;
import me.lucko.luckperms.sponge.service.proxy.ProxyFactory;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.service.permission.SubjectData;

View File

@ -23,13 +23,14 @@
* SOFTWARE.
*/
package me.lucko.luckperms.sponge.service;
package me.lucko.luckperms.sponge.service.misc;
import me.lucko.luckperms.sponge.service.model.LPPermissionDescription;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectCollection;
import me.lucko.luckperms.sponge.service.reference.LPSubjectReference;
import me.lucko.luckperms.sponge.service.model.LPSubjectReference;
import me.lucko.luckperms.sponge.service.proxy.ProxyFactory;
import org.spongepowered.api.plugin.PluginContainer;
import org.spongepowered.api.service.permission.PermissionDescription;
@ -42,7 +43,7 @@ import java.util.concurrent.CompletableFuture;
import javax.annotation.Nullable;
public final class LuckPermsPermissionDescription implements LPPermissionDescription {
public final class SimplePermissionDescription implements LPPermissionDescription {
private final LPPermissionService service;
private final String id;
@ -51,7 +52,7 @@ public final class LuckPermsPermissionDescription implements LPPermissionDescrip
private PermissionDescription spongeProxy = null;
public LuckPermsPermissionDescription(LPPermissionService service, String id, @Nullable Text description, @Nullable PluginContainer owner) {
public SimplePermissionDescription(LPPermissionService service, String id, @Nullable Text description, @Nullable PluginContainer owner) {
this.service = service;
this.id = Objects.requireNonNull(id, "id");
this.description = description;
@ -102,8 +103,8 @@ public final class LuckPermsPermissionDescription implements LPPermissionDescrip
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof LuckPermsPermissionDescription)) return false;
final LuckPermsPermissionDescription other = (LuckPermsPermissionDescription) o;
if (!(o instanceof SimplePermissionDescription)) return false;
final SimplePermissionDescription other = (SimplePermissionDescription) o;
return this.id.equals(other.id);
}
@ -114,7 +115,7 @@ public final class LuckPermsPermissionDescription implements LPPermissionDescrip
@Override
public String toString() {
return "LuckPermsPermissionDescription(" +
return "PermissionDescription(" +
"id=" + this.id + ", " +
"description=" + this.description + ", " +
"owner=" + this.owner + ")";

View File

@ -23,16 +23,25 @@
* SOFTWARE.
*/
package me.lucko.luckperms.sponge.service.model;
package me.lucko.luckperms.sponge.service.persisted;
import me.lucko.luckperms.common.contexts.ContextManager;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import org.spongepowered.api.service.permission.Subject;
/**
* Subject collection used for storing default subjects
*/
public class DefaultsCollection extends PersistedCollection {
public DefaultsCollection(LuckPermsService service) {
super(service, "defaults");
}
public interface LuckPermsSpongePlugin extends LuckPermsPlugin {
public LPSubject getRootSubject() {
return obtainSubject("default");
}
@Override
ContextManager<Subject> getContextManager();
public LPSubject getTypeDefaults(String collectionIdentifier) {
return obtainSubject(collectionIdentifier);
}
}

View File

@ -37,11 +37,10 @@ import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.common.utils.ImmutableCollectors;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import me.lucko.luckperms.sponge.service.ProxyFactory;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectCollection;
import me.lucko.luckperms.sponge.service.reference.LPSubjectReference;
import me.lucko.luckperms.sponge.service.storage.SubjectStorageModel;
import me.lucko.luckperms.sponge.service.model.LPSubjectReference;
import me.lucko.luckperms.sponge.service.proxy.ProxyFactory;
import org.spongepowered.api.service.permission.SubjectCollection;
@ -57,24 +56,38 @@ import java.util.function.Predicate;
*/
public class PersistedCollection implements LPSubjectCollection {
private final LuckPermsService service;
private final String identifier;
private final boolean defaultsCollection;
/**
* The collection identifier
*/
private final String identifier;
/**
* If the collection is the defaults collection
*/
private final boolean isDefaultsCollection;
/**
* Cached sponge proxy instance
*/
private final SubjectCollection spongeProxy;
/**
* The contained subjects
*/
private final LoadingCache<String, PersistedSubject> subjects = Caffeine.newBuilder()
.build(s -> new PersistedSubject(s, getService(), this));
.build(s -> new PersistedSubject(getService(), this, s));
public PersistedCollection(LuckPermsService service, String identifier) {
this.service = service;
this.identifier = identifier;
this.defaultsCollection = identifier.equals("defaults");
this.isDefaultsCollection = identifier.equals("defaults");
this.spongeProxy = ProxyFactory.toSponge(this);
}
public void loadAll() {
Map<String, SubjectStorageModel> holders = this.service.getStorage().loadAllFromFile(this.identifier);
for (Map.Entry<String, SubjectStorageModel> e : holders.entrySet()) {
Map<String, SubjectDataContainer> holders = this.service.getStorage().loadAllFromFile(this.identifier);
for (Map.Entry<String, SubjectDataContainer> e : holders.entrySet()) {
PersistedSubject subject = this.subjects.get(e.getKey().toLowerCase());
if (subject != null) {
subject.loadData(e.getValue());
@ -104,17 +117,23 @@ public class PersistedCollection implements LPSubjectCollection {
@Override
public boolean isDefaultsCollection() {
return this.defaultsCollection;
return this.isDefaultsCollection;
}
public LPSubject obtainSubject(String identifier) {
return this.subjects.get(identifier.toLowerCase());
}
@Override
@Deprecated // not necessary to wrap with a completablefuture
public CompletableFuture<LPSubject> loadSubject(String identifier) {
return CompletableFuture.completedFuture(this.subjects.get(identifier.toLowerCase()));
return CompletableFuture.completedFuture(obtainSubject(identifier));
}
@Override
@Deprecated // not necessary to wrap with an optional
public Optional<LPSubject> getSubject(String identifier) {
return Optional.of(Objects.requireNonNull(this.subjects.get(identifier.toLowerCase())));
return Optional.of(Objects.requireNonNull(obtainSubject(identifier)));
}
@Override
@ -181,7 +200,7 @@ public class PersistedCollection implements LPSubjectCollection {
@Override
public LPSubject getDefaults() {
return this.service.getDefaultSubjects().loadSubject(getIdentifier()).join();
return this.service.getDefaultSubjects().getTypeDefaults(getIdentifier());
}
}

View File

@ -27,14 +27,14 @@ package me.lucko.luckperms.sponge.service.persisted;
import me.lucko.luckperms.common.buffers.BufferedRequest;
import me.lucko.luckperms.common.model.NodeMapType;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import me.lucko.luckperms.sponge.service.ProxyFactory;
import me.lucko.luckperms.sponge.service.calculated.CalculatedSubject;
import me.lucko.luckperms.sponge.service.calculated.CalculatedSubjectData;
import me.lucko.luckperms.sponge.service.calculated.MonitoredSubjectData;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectData;
import me.lucko.luckperms.sponge.service.storage.SubjectStorageModel;
import me.lucko.luckperms.sponge.service.proxy.ProxyFactory;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.service.permission.Subject;
@ -46,31 +46,33 @@ import java.util.Optional;
* A simple persistable Subject implementation
*/
public class PersistedSubject extends CalculatedSubject implements LPSubject {
private final LuckPermsService service;
/**
* The subjects identifier
*/
private final String identifier;
private final LuckPermsService service;
/**
* The parent collection
*/
private final PersistedCollection parentCollection;
// subject data instances
private final PersistedSubjectData subjectData;
private final CalculatedSubjectData transientSubjectData;
private final BufferedRequest<Void> saveBuffer = new BufferedRequest<Void>(1000L, 500L, r -> PersistedSubject.this.service.getPlugin().getBootstrap().getScheduler().doAsync(r)) {
@Override
protected Void perform() {
try {
PersistedSubject.this.service.getStorage().saveToFile(PersistedSubject.this);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
};
/**
* The save buffer instance for saving changes to disk
*/
private final SaveBuffer saveBuffer;
public PersistedSubject(String identifier, LuckPermsService service, PersistedCollection parentCollection) {
public PersistedSubject(LuckPermsService service, PersistedCollection parentCollection, String identifier) {
super(service.getPlugin());
this.identifier = identifier;
this.service = service;
this.parentCollection = parentCollection;
this.identifier = identifier;
this.subjectData = new PersistedSubjectData(this, NodeMapType.ENDURING, service) {
@Override
protected void onUpdate(boolean success) {
@ -88,18 +90,34 @@ public class PersistedSubject extends CalculatedSubject implements LPSubject {
}
}
};
this.saveBuffer = new SaveBuffer(service.getPlugin());
}
/**
* Calls the subject data update event for the given {@link LPSubjectData} instance.
*
* @param subjectData the subject data
*/
private void fireUpdateEvent(LPSubjectData subjectData) {
this.service.getPlugin().getUpdateEventHandler().fireUpdateEvent(subjectData);
}
public void loadData(SubjectStorageModel dataHolder) {
/**
* Loads data into this {@link PersistedSubject} from the given
* {@link SubjectDataContainer} container
*
* @param container the container to load from
*/
public void loadData(SubjectDataContainer container) {
this.subjectData.setSave(false);
dataHolder.applyToData(this.subjectData);
container.applyToData(this.subjectData);
this.subjectData.setSave(true);
}
/**
* Requests that this subjects data is saved to disk
*/
public void save() {
this.saveBuffer.request();
}
@ -138,4 +156,20 @@ public class PersistedSubject extends CalculatedSubject implements LPSubject {
public Optional<CommandSource> getCommandSource() {
return Optional.empty();
}
private final class SaveBuffer extends BufferedRequest<Void> {
public SaveBuffer(LuckPermsPlugin plugin) {
super(1000L, 500L, plugin.getBootstrap().getScheduler().async());
}
@Override
protected Void perform() {
try {
PersistedSubject.this.service.getStorage().saveToFile(PersistedSubject.this);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
}

View File

@ -23,7 +23,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.sponge.service.storage;
package me.lucko.luckperms.sponge.service.persisted;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
@ -38,25 +38,44 @@ import me.lucko.luckperms.common.contexts.ContextSetJsonSerializer;
import me.lucko.luckperms.common.utils.CollationKeyCache;
import me.lucko.luckperms.sponge.service.calculated.CalculatedSubjectData;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.reference.LPSubjectReference;
import me.lucko.luckperms.sponge.service.reference.SubjectReferenceFactory;
import me.lucko.luckperms.sponge.service.model.LPSubjectData;
import me.lucko.luckperms.sponge.service.model.LPSubjectReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Used for converting a SubjectData instance to and from JSON
* Immutable container for a subjects persisted data
*/
public class SubjectStorageModel {
private final LPPermissionService service;
public class SubjectDataContainer {
/**
* Creates a {@link SubjectDataContainer} container for the given {@link LPSubjectData}.
*
* @param subjectData the subject data to copy from
* @return a new container
*/
public static SubjectDataContainer copyOf(LPSubjectData subjectData) {
return new SubjectDataContainer(subjectData.getAllPermissions(), subjectData.getAllOptions(), subjectData.getAllParents());
}
/**
* Deserializes a {@link SubjectDataContainer} container from a json object
*
* @param service the permission service
* @param root the root json object
* @return a container representing the json data
*/
public static SubjectDataContainer derserialize(LPPermissionService service, JsonObject root) {
return new SubjectDataContainer(service, root);
}
private final Map<ImmutableContextSet, Map<String, Boolean>> permissions;
private final Map<ImmutableContextSet, Map<String, String>> options;
private final Map<ImmutableContextSet, List<LPSubjectReference>> parents;
public SubjectStorageModel(LPPermissionService service, Map<ImmutableContextSet, ? extends Map<String, Boolean>> permissions, Map<ImmutableContextSet, ? extends Map<String, String>> options, Map<ImmutableContextSet, ? extends List<LPSubjectReference>> parents) {
this.service = service;
private SubjectDataContainer(Map<ImmutableContextSet, ? extends Map<String, Boolean>> permissions, Map<ImmutableContextSet, ? extends Map<String, String>> options, Map<ImmutableContextSet, ? extends List<LPSubjectReference>> parents) {
ImmutableMap.Builder<ImmutableContextSet, Map<String, Boolean>> permissionsBuilder = ImmutableMap.builder();
for (Map.Entry<ImmutableContextSet, ? extends Map<String, Boolean>> e : permissions.entrySet()) {
permissionsBuilder.put(e.getKey(), ImmutableMap.copyOf(e.getValue()));
@ -75,18 +94,12 @@ public class SubjectStorageModel {
}
this.parents = parentsBuilder.build();
}
public SubjectStorageModel(CalculatedSubjectData data) {
this(data.getParentSubject().getService(), data.getAllPermissions(), data.getAllOptions(), data.getAllParents());
}
public SubjectStorageModel(LPPermissionService service, JsonObject root) {
this.service = service;
private SubjectDataContainer(LPPermissionService service, JsonObject root) {
Preconditions.checkArgument(root.get("permissions").isJsonArray());
Preconditions.checkArgument(root.get("options").isJsonArray());
Preconditions.checkArgument(root.get("parents").isJsonArray());
JsonArray permissions = root.get("permissions").getAsJsonArray();
JsonArray options = root.get("options").getAsJsonArray();
JsonArray parents = root.get("parents").getAsJsonArray();
@ -96,20 +109,20 @@ public class SubjectStorageModel {
if (!e.isJsonObject()) {
continue;
}
JsonObject section = e.getAsJsonObject();
if (!section.get("context").isJsonObject()) continue;
if (!section.get("data").isJsonObject()) continue;
JsonObject context = section.get("context").getAsJsonObject();
JsonObject data = section.get("data").getAsJsonObject();
ImmutableContextSet contextSet = ContextSetJsonSerializer.deserializeContextSet(context).makeImmutable();
ImmutableMap.Builder<String, Boolean> perms = ImmutableMap.builder();
for (Map.Entry<String, JsonElement> perm : data.entrySet()) {
perms.put(perm.getKey(), perm.getValue().getAsBoolean());
}
permissionsBuilder.put(contextSet, perms.build());
}
this.permissions = permissionsBuilder.build();
@ -156,13 +169,13 @@ public class SubjectStorageModel {
if (!p.isJsonObject()) {
continue;
}
JsonObject parent = p.getAsJsonObject();
String collection = parent.get("collection").getAsString();
String subject = parent.get("subject").getAsString();
pars.add(SubjectReferenceFactory.obtain(service, collection, subject));
pars.add(service.getReferenceFactory().obtain(collection, subject));
}
parentsBuilder.put(contextSet, pars.build());
@ -170,13 +183,12 @@ public class SubjectStorageModel {
this.parents = parentsBuilder.build();
}
private static <T> List<Map.Entry<ImmutableContextSet, T>> sortContextMap(Map<ImmutableContextSet, T> map) {
List<Map.Entry<ImmutableContextSet, T>> entries = new ArrayList<>(map.entrySet());
entries.sort((o1, o2) -> ContextSetComparator.reverse().compare(o1.getKey(), o2.getKey()));
return entries;
}
public JsonObject toJson() {
/**
* Converts this container to json
*
* @return a json serialisation of the data in this container
*/
public JsonObject serialize() {
JsonObject root = new JsonObject();
JsonArray permissions = new JsonArray();
@ -252,14 +264,22 @@ public class SubjectStorageModel {
return root;
}
/**
* Applies the data encapsulated by this container to the given
* {@link CalculatedSubjectData}.
*
* @param subjectData the data to apply to
*/
public void applyToData(CalculatedSubjectData subjectData) {
subjectData.replacePermissions(this.permissions);
subjectData.replaceOptions(this.options);
subjectData.replaceParents(this.parents);
}
public LPPermissionService getService() {
return this.service;
private static <T> List<Map.Entry<ImmutableContextSet, T>> sortContextMap(Map<ImmutableContextSet, T> map) {
List<Map.Entry<ImmutableContextSet, T>> entries = new ArrayList<>(map.entrySet());
entries.sort((o1, o2) -> ContextSetComparator.reverse().compare(o1.getKey(), o2.getKey()));
return entries;
}
}

View File

@ -23,16 +23,14 @@
* SOFTWARE.
*/
package me.lucko.luckperms.sponge.service.storage;
package me.lucko.luckperms.sponge.service.persisted;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.persisted.PersistedSubject;
import java.io.BufferedReader;
import java.io.BufferedWriter;
@ -50,8 +48,20 @@ import java.util.stream.Collectors;
* Handles persisted Subject I/O and (de)serialization
*/
public class SubjectStorage {
/**
* The permission service
*/
private final LPPermissionService service;
/**
* Gson instance
*/
private final Gson gson;
/**
* The root directory used to store files
*/
private final File container;
public SubjectStorage(LPPermissionService service, File container) {
@ -65,6 +75,11 @@ public class SubjectStorage {
this.container.getParentFile().mkdirs();
}
/**
* Returns a set of all known collections
*
* @return the identifiers of all known collections
*/
public Set<String> getSavedCollections() {
checkContainer();
@ -76,22 +91,42 @@ public class SubjectStorage {
return ImmutableSet.copyOf(dirs).stream().map(File::getName).collect(Collectors.toSet());
}
public File resolveFile(String collectionName, String subjectName) {
/**
* Returns the file where a subjects data should be stored
*
* @param collectionIdentifier the identifier of the subjects collection
* @param subjectIdentifier the identifier of the subject
* @return a file
*/
private File resolveFile(String collectionIdentifier, String subjectIdentifier) {
checkContainer();
File collection = new File(this.container, collectionName);
File collection = new File(this.container, collectionIdentifier);
if (!collection.exists()) {
collection.mkdirs();
}
return new File(collection, subjectName + ".json");
return new File(collection, subjectIdentifier + ".json");
}
/**
* Saves a subject
*
* @param subject the subject to save
* @throws IOException if the write fails
*/
public void saveToFile(PersistedSubject subject) throws IOException {
File subjectFile = resolveFile(subject.getParentCollection().getIdentifier(), subject.getIdentifier());
saveToFile(new SubjectStorageModel(subject.getSubjectData()), subjectFile);
saveToFile(SubjectDataContainer.copyOf(subject.getSubjectData()), subjectFile);
}
public void saveToFile(SubjectStorageModel model, File file) throws IOException {
/**
* Saves subject data to a specific file
*
* @param container the data
* @param file the file
* @throws IOException if the write fails
*/
public void saveToFile(SubjectDataContainer container, File file) throws IOException {
file.getParentFile().mkdirs();
if (file.exists()) {
file.delete();
@ -99,14 +134,20 @@ public class SubjectStorage {
file.createNewFile();
try (BufferedWriter writer = Files.newBufferedWriter(file.toPath(), StandardCharsets.UTF_8)) {
this.gson.toJson(model.toJson(), writer);
this.gson.toJson(container.serialize(), writer);
writer.flush();
}
}
public Map<String, SubjectStorageModel> loadAllFromFile(String collectionName) {
/**
* Loads all known subjects for a given collection
*
* @param collectionIdentifier the collection identifier
* @return a map of found subjects
*/
public Map<String, SubjectDataContainer> loadAllFromFile(String collectionIdentifier) {
checkContainer();
File collection = new File(this.container, collectionName);
File collection = new File(this.container, collectionIdentifier);
if (!collection.exists()) {
return Collections.emptyMap();
}
@ -114,14 +155,14 @@ public class SubjectStorage {
String[] fileNames = collection.list((dir, name) -> name.endsWith(".json"));
if (fileNames == null) return Collections.emptyMap();
Map<String, SubjectStorageModel> holders = new HashMap<>();
Map<String, SubjectDataContainer> holders = new HashMap<>();
for (String name : fileNames) {
File subject = new File(collection, name);
File subjectFile = new File(collection, name);
try {
Map.Entry<String, SubjectStorageModel> s = loadFromFile(subject);
LoadedSubject s = loadFromFile(subjectFile);
if (s != null) {
holders.put(s.getKey(), s.getValue());
holders.put(s.identifier, s.data);
}
} catch (IOException e) {
e.printStackTrace();
@ -131,18 +172,33 @@ public class SubjectStorage {
return holders;
}
public Map.Entry<String, SubjectStorageModel> loadFromFile(String collectionName, String subjectName) throws IOException {
/**
* Loads a subject
*
* @param collectionIdentifier the collection id
* @param subjectIdentifier the subject id
* @return a loaded subject
* @throws IOException if the read fails
*/
public LoadedSubject loadFromFile(String collectionIdentifier, String subjectIdentifier) throws IOException {
checkContainer();
File collection = new File(this.container, collectionName);
File collection = new File(this.container, collectionIdentifier);
if (!collection.exists()) {
return null;
}
File subject = new File(collection, subjectName + ".json");
return Maps.immutableEntry(subjectName, loadFromFile(subject).getValue());
File subject = new File(collection, subjectIdentifier + ".json");
return new LoadedSubject(subjectIdentifier, loadFromFile(subject).data);
}
public Map.Entry<String, SubjectStorageModel> loadFromFile(File file) throws IOException {
/**
* Loads a subject from a particular file
*
* @param file the file to load from
* @return a loaded subject
* @throws IOException if the read fails
*/
public LoadedSubject loadFromFile(File file) throws IOException {
if (!file.exists()) {
return null;
}
@ -151,8 +207,18 @@ public class SubjectStorage {
try (BufferedReader reader = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8)) {
JsonObject data = this.gson.fromJson(reader, JsonObject.class);
SubjectStorageModel model = new SubjectStorageModel(this.service, data);
return Maps.immutableEntry(subjectName, model);
SubjectDataContainer model = SubjectDataContainer.derserialize(this.service, data);
return new LoadedSubject(subjectName, model);
}
}
private static final class LoadedSubject {
private final String identifier;
private final SubjectDataContainer data;
private LoadedSubject(String identifier, SubjectDataContainer data) {
this.identifier = identifier;
this.data = data;
}
}
}

View File

@ -23,7 +23,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.sponge.service;
package me.lucko.luckperms.sponge.service.proxy;
import me.lucko.luckperms.common.model.NodeMapType;
import me.lucko.luckperms.sponge.service.model.LPPermissionDescription;