Cleanup parts of the sponge service implementation

This commit is contained in:
Luck 2018-03-01 08:48:39 +00:00
parent 98fb9946e4
commit fbe84322b5
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
32 changed files with 632 additions and 884 deletions

View File

@ -45,7 +45,7 @@ public final class BukkitMigrationUtils {
}
}
if (uuid == null) {
log.logErr("Unable to get a UUID for user identifier: " + s);
log.logError("Unable to get a UUID for user identifier: " + s);
}
return uuid;
}

View File

@ -85,7 +85,7 @@ public class MigrationBPermissions extends SubCommand<Object> {
WorldManager worldManager = WorldManager.getInstance();
if (worldManager == null) {
log.logErr("Plugin not loaded.");
log.logError("Plugin not loaded.");
return CommandResult.STATE_ERROR;
}
@ -111,7 +111,7 @@ public class MigrationBPermissions extends SubCommand<Object> {
Set<String> users = configSection.getKeys(false);
if (users == null) {
log.logErr("Couldn't get a list of users.");
log.logError("Couldn't get a list of users.");
return CommandResult.FAILURE;
}
AtomicInteger userLoadCount = new AtomicInteger(0);

View File

@ -74,14 +74,14 @@ public class MigrationGroupManager extends SubCommand<Object> {
log.log("Starting.");
if (!args.get(0).equalsIgnoreCase("true") && !args.get(0).equalsIgnoreCase("false")) {
log.logErr("Was expecting true/false, but got " + args.get(0) + " instead.");
log.logError("Was expecting true/false, but got " + args.get(0) + " instead.");
return CommandResult.STATE_ERROR;
}
final boolean migrateAsGlobal = Boolean.parseBoolean(args.get(0));
final Function<String, String> worldMappingFunc = s -> migrateAsGlobal ? null : s;
if (!Bukkit.getPluginManager().isPluginEnabled("GroupManager")) {
log.logErr("Plugin not loaded.");
log.logError("Plugin not loaded.");
return CommandResult.STATE_ERROR;
}

View File

@ -66,7 +66,7 @@ public class MigrationPermissionsBukkit extends SubCommand<Object> {
log.log("Starting.");
if (!Bukkit.getPluginManager().isPluginEnabled("PermissionsBukkit")) {
log.logErr("Plugin not loaded.");
log.logError("Plugin not loaded.");
return CommandResult.STATE_ERROR;
}

View File

@ -99,7 +99,7 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
log.log("Starting.");
if (!Bukkit.getPluginManager().isPluginEnabled("PermissionsEx")) {
log.logErr("Plugin not loaded.");
log.logError("Plugin not loaded.");
return CommandResult.STATE_ERROR;
}

View File

@ -85,7 +85,7 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
log.log("Starting.");
if (!Bukkit.getPluginManager().isPluginEnabled("PowerfulPerms")) {
log.logErr("Plugin not loaded.");
log.logError("Plugin not loaded.");
return CommandResult.STATE_ERROR;
}
@ -143,7 +143,7 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
}
if (uuids.isEmpty()) {
log.logErr("Unable to find any UUIDs to migrate.");
log.logError("Unable to find any UUIDs to migrate.");
return CommandResult.FAILURE;
}

View File

@ -76,12 +76,12 @@ public class MigrationZPermissions extends SubCommand<Object> {
log.log("Starting.");
if (!Bukkit.getPluginManager().isPluginEnabled("zPermissions")) {
log.logErr("Plugin not loaded.");
log.logError("Plugin not loaded.");
return CommandResult.STATE_ERROR;
}
if (!Bukkit.getServicesManager().isProvidedFor(ZPermissionsService.class)) {
log.logErr("Plugin not loaded.");
log.logError("Plugin not loaded.");
return CommandResult.STATE_ERROR;
}

View File

@ -66,7 +66,7 @@ public class MigrationBungeePerms extends SubCommand<Object> {
// Get BungeePerms instance
BungeePerms bp = BungeePerms.getInstance();
if (bp == null) {
log.logErr("Plugin not loaded.");
log.logError("Plugin not loaded.");
return CommandResult.STATE_ERROR;
}
@ -106,7 +106,7 @@ public class MigrationBungeePerms extends SubCommand<Object> {
SafeIteration.iterate(bp.getPermissionsManager().getBackEnd().loadUsers(), u -> {
if (u.getUUID() == null) {
log.logErr("Could not parse UUID for user: " + u.getName());
log.logError("Could not parse UUID for user: " + u.getName());
return;
}

View File

@ -62,7 +62,7 @@ public class ProgressLogger {
}
}
public void logErr(String msg) {
public void logError(String msg) {
if (this.pluginName == null) {
this.listeners.forEach(s -> this.logMessage.send(s, "Error -> " + msg));
} else {
@ -80,7 +80,6 @@ public class ProgressLogger {
public void logProgress(String msg, int amount) {
if (amount % NOTIFY_FREQUENCY == 0) {
// migrated {} groups so far.
logAllProgress(msg, amount);
}
}

View File

@ -25,8 +25,30 @@
package me.lucko.luckperms.common.model;
import java.util.function.Supplier;
public enum NodeMapType {
ENDURING, TRANSIENT
ENDURING,
TRANSIENT;
// useful methods for fluent/conditional execution
public void run(Runnable ifEnduring, Runnable ifTransient) {
if (this == ENDURING) {
ifEnduring.run();
} else {
ifTransient.run();
}
}
public <T> T supply(Supplier<T> ifEnduring, Supplier<T> ifTransient) {
if (this == ENDURING) {
return ifEnduring.get();
} else {
return ifTransient.get();
}
}
}

View File

@ -262,6 +262,10 @@ public abstract class PermissionHolder {
return this.transientNodes;
}
public ImmutableSetMultimap<ImmutableContextSet, Node> getNodes(NodeMapType type) {
return getData(type).immutable();
}
public ImmutableSetMultimap<ImmutableContextSet, Node> getEnduringNodes() {
return this.enduringNodes.immutable();
}

View File

@ -36,7 +36,6 @@ import me.lucko.luckperms.common.processors.MapProcessor;
import me.lucko.luckperms.common.processors.PermissionProcessor;
import me.lucko.luckperms.common.processors.RegexProcessor;
import me.lucko.luckperms.common.processors.WildcardProcessor;
import me.lucko.luckperms.common.references.HolderType;
import me.lucko.luckperms.sponge.LPSpongePlugin;
import me.lucko.luckperms.sponge.processors.GroupDefaultsProcessor;
import me.lucko.luckperms.sponge.processors.SpongeWildcardProcessor;
@ -68,9 +67,9 @@ public class SpongeCalculatorFactory extends AbstractCalculatorFactory {
}
if (this.plugin.getConfiguration().get(ConfigKeys.APPLY_SPONGE_DEFAULT_SUBJECTS)) {
if (metadata.getHolderType() == HolderType.USER) {
if (metadata.getHolderType().isUser()) {
processors.add(new UserDefaultsProcessor(this.plugin.getService(), contexts.getContexts().makeImmutable()));
} else if (metadata.getHolderType() == HolderType.GROUP) {
} else if (metadata.getHolderType().isGroup()) {
processors.add(new GroupDefaultsProcessor(this.plugin.getService(), contexts.getContexts().makeImmutable()));
}
}

View File

@ -62,14 +62,14 @@ public class SpongeConnectionListener extends AbstractLoginListener {
/* Called when the player first attempts a connection with the server.
Listening on AFTER_PRE priority to allow plugins to modify username / UUID data here. (auth plugins) */
final GameProfile p = e.getProfile();
final String username = p.getName().orElseThrow(() -> new RuntimeException("No username present for user " + p.getUniqueId()));
final GameProfile profile = e.getProfile();
final String username = profile.getName().orElseThrow(() -> new RuntimeException("No username present for user " + profile.getUniqueId()));
if (this.plugin.getConfiguration().get(ConfigKeys.DEBUG_LOGINS)) {
this.plugin.getLog().info("Processing auth event for " + p.getUniqueId() + " - " + p.getName());
this.plugin.getLog().info("Processing auth event for " + profile.getUniqueId() + " - " + profile.getName());
}
this.plugin.getUniqueConnections().add(p.getUniqueId());
this.plugin.getUniqueConnections().add(profile.getUniqueId());
/* Actually process the login for the connection.
We do this here to delay the login until the data is ready.
@ -81,13 +81,13 @@ public class SpongeConnectionListener extends AbstractLoginListener {
- creating a user instance in the UserManager for this connection.
- setting up cached data. */
try {
User user = loadUser(p.getUniqueId(), username);
this.plugin.getEventFactory().handleUserLoginProcess(p.getUniqueId(), username, user);
User user = loadUser(profile.getUniqueId(), username);
this.plugin.getEventFactory().handleUserLoginProcess(profile.getUniqueId(), username, user);
} catch (Exception ex) {
this.plugin.getLog().severe("Exception occurred whilst loading data for " + p.getUniqueId() + " - " + p.getName());
this.plugin.getLog().severe("Exception occurred whilst loading data for " + profile.getUniqueId() + " - " + profile.getName());
ex.printStackTrace();
this.deniedAsyncLogin.add(p.getUniqueId());
this.deniedAsyncLogin.add(profile.getUniqueId());
e.setCancelled(true);
e.setMessageCancelled(false);
@ -120,19 +120,19 @@ public class SpongeConnectionListener extends AbstractLoginListener {
At this point, the users data should be present and loaded.
Listening on LOW priority to allow plugins to further modify data here. (auth plugins, etc.) */
final GameProfile player = e.getProfile();
final GameProfile profile = e.getProfile();
if (this.plugin.getConfiguration().get(ConfigKeys.DEBUG_LOGINS)) {
this.plugin.getLog().info("Processing login event for " + player.getUniqueId() + " - " + player.getName());
this.plugin.getLog().info("Processing login event for " + profile.getUniqueId() + " - " + profile.getName());
}
final User user = this.plugin.getUserManager().getIfLoaded(player.getUniqueId());
final User user = this.plugin.getUserManager().getIfLoaded(profile.getUniqueId());
/* User instance is null for whatever reason. Could be that it was unloaded between asyncpre and now. */
if (user == null) {
this.deniedLogin.add(player.getUniqueId());
this.deniedLogin.add(profile.getUniqueId());
this.plugin.getLog().warn("User " + player.getUniqueId() + " - " + player.getName() + " doesn't have data pre-loaded. - denying login.");
this.plugin.getLog().warn("User " + profile.getUniqueId() + " - " + profile.getName() + " doesn't have data pre-loaded. - denying login.");
e.setCancelled(true);
e.setMessageCancelled(false);
//noinspection deprecation

View File

@ -73,7 +73,7 @@ public class MigrationPermissionManager extends SubCommand<Object> {
Optional<PluginContainer> pm = Sponge.getPluginManager().getPlugin("permissionmanager");
if (!pm.isPresent()) {
log.logErr("Plugin not loaded.");
log.logError("Plugin not loaded.");
return CommandResult.STATE_ERROR;
}
@ -120,7 +120,7 @@ public class MigrationPermissionManager extends SubCommand<Object> {
SafeIteration.iterate(pmService.getUserSubjects().getAllSubjects(), pmUser -> {
UUID uuid = Uuids.parseNullable(pmUser.getIdentifier());
if (uuid == null) {
log.logErr("Could not parse UUID for user: " + pmUser.getIdentifier());
log.logError("Could not parse UUID for user: " + pmUser.getIdentifier());
return;
}

View File

@ -79,7 +79,7 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
Optional<PluginContainer> pex = Sponge.getPluginManager().getPlugin("permissionsex");
if (!pex.isPresent()) {
log.logErr("Plugin not loaded.");
log.logError("Plugin not loaded.");
return CommandResult.STATE_ERROR;
}
@ -172,7 +172,7 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
SafeIteration.iterate(pexService.getUserSubjects().getAllSubjects(), pexUser -> {
UUID uuid = Uuids.parseNullable(pexUser.getIdentifier());
if (uuid == null) {
log.logErr("Could not parse UUID for user: " + pexUser.getIdentifier());
log.logError("Could not parse UUID for user: " + pexUser.getIdentifier());
return;
}

View File

@ -25,32 +25,11 @@
package me.lucko.luckperms.sponge.model;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
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.model.Group;
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.service.LuckPermsService;
import me.lucko.luckperms.sponge.service.LuckPermsSubjectData;
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 org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.service.permission.Subject;
import java.util.Map;
import java.util.Optional;
public class SpongeGroup extends Group {
import me.lucko.luckperms.sponge.service.internal.GroupSubject;
public class SpongeGroup extends Group implements SpongePermissionHolder {
private final GroupSubject spongeData;
public SpongeGroup(String name, LPSpongePlugin plugin) {
@ -58,133 +37,9 @@ public class SpongeGroup extends Group {
this.spongeData = new GroupSubject(plugin, this);
}
@Override
public GroupSubject sponge() {
return this.spongeData;
}
public static class GroupSubject implements LPSubject {
private final SpongeGroup parent;
private final LPSpongePlugin plugin;
private final LuckPermsSubjectData subjectData;
private final LuckPermsSubjectData transientSubjectData;
private GroupSubject(LPSpongePlugin plugin, SpongeGroup parent) {
this.parent = parent;
this.plugin = plugin;
this.subjectData = new LuckPermsSubjectData(true, plugin.getService(), parent, this);
this.transientSubjectData = new LuckPermsSubjectData(false, plugin.getService(), parent, this);
}
@Override
public String getIdentifier() {
return this.parent.getObjectName();
}
@Override
public Optional<String> getFriendlyIdentifier() {
return this.parent.getDisplayName();
}
@Override
public Optional<CommandSource> getCommandSource() {
return Optional.empty();
}
@Override
public LPSubjectCollection getParentCollection() {
return this.plugin.getService().getGroupSubjects();
}
@Override
public Subject sponge() {
return ProxyFactory.toSponge(this);
}
@Override
public LuckPermsService getService() {
return this.plugin.getService();
}
@Override
public LuckPermsSubjectData getSubjectData() {
return this.subjectData;
}
@Override
public LuckPermsSubjectData getTransientSubjectData() {
return this.transientSubjectData;
}
@Override
public Tristate getPermissionValue(ImmutableContextSet contexts, String permission) {
return this.parent.getCachedData().getPermissionData(this.plugin.getContextManager().formContexts(contexts)).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();
}
@Override
public ImmutableList<LPSubjectReference> getParents(ImmutableContextSet contexts) {
ImmutableSet.Builder<LPSubjectReference> subjects = ImmutableSet.builder();
for (Map.Entry<String, Boolean> entry : this.parent.getCachedData().getPermissionData(this.plugin.getContextManager().formContexts(contexts)).getImmutableBacking().entrySet()) {
if (!entry.getValue()) {
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.addAll(this.plugin.getService().getGroupSubjects().getDefaults().getParents(contexts));
subjects.addAll(this.plugin.getService().getDefaults().getParents(contexts));
return getService().sortSubjects(subjects.build());
}
@Override
public Optional<String> getOption(ImmutableContextSet contexts, String s) {
MetaData data = this.parent.getCachedData().getMetaData(this.plugin.getContextManager().formContexts(contexts));
if (s.equalsIgnoreCase(NodeFactory.PREFIX_KEY)) {
if (data.getPrefix() != null) {
return Optional.of(data.getPrefix());
}
}
if (s.equalsIgnoreCase(NodeFactory.SUFFIX_KEY)) {
if (data.getSuffix() != null) {
return Optional.of(data.getSuffix());
}
}
String val = data.getMeta().get(s);
if (val != null) {
return Optional.of(val);
}
Optional<String> v = this.plugin.getService().getGroupSubjects().getDefaults().getOption(contexts, s);
if (v.isPresent()) {
return v;
}
return this.plugin.getService().getDefaults().getOption(contexts, s);
}
@Override
public void invalidateCaches(CacheLevel cacheLevel) {
// invalidate for all changes
this.parent.getCachedData().invalidateCaches();
}
}
}

View File

@ -0,0 +1,43 @@
/*
* 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.model;
import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.sponge.service.model.LPSubject;
/**
* A sponge specific extension of {@link PermissionHolder}.
*/
public interface SpongePermissionHolder {
/**
* Gets a {@link LPSubject} representation of this holder.
*
* @return a subject
*/
LPSubject sponge();
}

View File

@ -25,35 +25,17 @@
package me.lucko.luckperms.sponge.model;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
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.model.User;
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.service.LuckPermsService;
import me.lucko.luckperms.sponge.service.LuckPermsSubjectData;
import me.lucko.luckperms.sponge.service.ProxyFactory;
import me.lucko.luckperms.sponge.service.internal.UserSubject;
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 org.spongepowered.api.Sponge;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.service.permission.Subject;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Function;
public class SpongeUser extends User {
/**
* Extension of {@link User} to hold an implementation for {@link LPSubject}.
*/
public class SpongeUser extends User implements SpongePermissionHolder {
private final UserSubject spongeData;
public SpongeUser(UUID uuid, LPSpongePlugin plugin) {
@ -66,134 +48,9 @@ public class SpongeUser extends User {
this.spongeData = new UserSubject(plugin, this);
}
@Override
public UserSubject sponge() {
return this.spongeData;
}
public static final class UserSubject implements LPSubject {
private final SpongeUser parent;
private final LPSpongePlugin plugin;
private final LuckPermsSubjectData subjectData;
private final LuckPermsSubjectData transientSubjectData;
private UserSubject(LPSpongePlugin plugin, SpongeUser parent) {
this.parent = parent;
this.plugin = plugin;
this.subjectData = new LuckPermsSubjectData(true, plugin.getService(), parent, this);
this.transientSubjectData = new LuckPermsSubjectData(false, plugin.getService(), parent, this);
}
@Override
public String getIdentifier() {
return this.parent.getUuid().toString();
}
@Override
public Optional<String> getFriendlyIdentifier() {
return this.parent.getName();
}
@Override
public Optional<CommandSource> getCommandSource() {
final UUID uuid = this.parent.getUuid();
return Sponge.getServer().getPlayer(uuid).map(Function.identity());
}
@Override
public LPSubjectCollection getParentCollection() {
return this.plugin.getService().getUserSubjects();
}
@Override
public Subject sponge() {
return ProxyFactory.toSponge(this);
}
@Override
public LuckPermsService getService() {
return this.plugin.getService();
}
@Override
public LuckPermsSubjectData getSubjectData() {
return this.subjectData;
}
@Override
public LuckPermsSubjectData getTransientSubjectData() {
return this.transientSubjectData;
}
@Override
public Tristate getPermissionValue(ImmutableContextSet contexts, String permission) {
return this.parent.getCachedData().getPermissionData(this.plugin.getContextManager().formContexts(contexts)).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();
}
@Override
public ImmutableList<LPSubjectReference> getParents(ImmutableContextSet contexts) {
ImmutableSet.Builder<LPSubjectReference> subjects = ImmutableSet.builder();
for (Map.Entry<String, Boolean> entry : this.parent.getCachedData().getPermissionData(this.plugin.getContextManager().formContexts(contexts)).getImmutableBacking().entrySet()) {
if (!entry.getValue()) {
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.addAll(this.plugin.getService().getUserSubjects().getDefaults().getParents(contexts));
subjects.addAll(this.plugin.getService().getDefaults().getParents(contexts));
return getService().sortSubjects(subjects.build());
}
@Override
public Optional<String> getOption(ImmutableContextSet contexts, String s) {
MetaData data = this.parent.getCachedData().getMetaData(this.plugin.getContextManager().formContexts(contexts));
if (s.equalsIgnoreCase(NodeFactory.PREFIX_KEY)) {
if (data.getPrefix() != null) {
return Optional.of(data.getPrefix());
}
}
if (s.equalsIgnoreCase(NodeFactory.SUFFIX_KEY)) {
if (data.getSuffix() != null) {
return Optional.of(data.getSuffix());
}
}
String val = data.getMeta().get(s);
if (val != null) {
return Optional.of(val);
}
Optional<String> v = this.plugin.getService().getUserSubjects().getDefaults().getOption(contexts, s);
if (v.isPresent()) {
return v;
}
return this.plugin.getService().getDefaults().getOption(contexts, s);
}
@Override
public void invalidateCaches(CacheLevel cacheLevel) {
// invalidate for all changes
this.parent.getCachedData().invalidateCaches();
}
}
}

View File

@ -43,7 +43,6 @@ import java.util.concurrent.CompletableFuture;
import javax.annotation.Nullable;
public final class LuckPermsPermissionDescription implements LPPermissionDescription {
private final LPPermissionService service;
private final String id;

View File

@ -37,7 +37,6 @@ 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.legacy.LegacyDataMigrator;
import me.lucko.luckperms.sponge.service.model.LPPermissionDescription;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.model.LPSubject;
@ -90,7 +89,6 @@ public class LuckPermsService implements LPPermissionService {
this.spongeProxy = ProxyFactory.toSponge(this);
this.storage = new SubjectStorage(this, new File(plugin.getDataDirectory(), "sponge-data"));
new LegacyDataMigrator(plugin, new File(plugin.getDataDirectory(), "local"), this.storage).run();
this.userSubjects = plugin.getUserManager();
this.groupSubjects = plugin.getGroupManager();

View File

@ -29,7 +29,6 @@ import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSortedMap;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ImmutableContextSet;
@ -38,7 +37,6 @@ import me.lucko.luckperms.common.calculators.PermissionCalculatorMetadata;
import me.lucko.luckperms.common.contexts.ContextSetComparator;
import me.lucko.luckperms.common.processors.MapProcessor;
import me.lucko.luckperms.common.processors.PermissionProcessor;
import me.lucko.luckperms.common.references.HolderType;
import me.lucko.luckperms.common.verbose.CheckOrigin;
import me.lucko.luckperms.sponge.processors.SpongeWildcardProcessor;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
@ -52,6 +50,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
@ -60,33 +59,28 @@ import java.util.concurrent.TimeUnit;
* In-memory implementation of {@link LPSubjectData}.
*/
public class CalculatedSubjectData implements LPSubjectData {
private final LPSubject parentSubject;
private final LPPermissionService service;
private final String calculatorDisplayName;
private final Map<ImmutableContextSet, Map<String, Boolean>> permissions = new ConcurrentHashMap<>();
private final Map<ImmutableContextSet, Set<LPSubjectReference>> parents = new ConcurrentHashMap<>();
private final Map<ImmutableContextSet, Map<String, String>> options = new ConcurrentHashMap<>();
private final LoadingCache<ImmutableContextSet, CalculatorHolder> permissionCache = Caffeine.newBuilder()
.expireAfterAccess(10, TimeUnit.MINUTES)
.build(contexts -> {
ImmutableList.Builder<PermissionProcessor> processors = ImmutableList.builder();
processors.add(new MapProcessor());
processors.add(new SpongeWildcardProcessor());
CalculatorHolder holder = new CalculatorHolder(new PermissionCalculator(CalculatedSubjectData.this.service.getPlugin(), PermissionCalculatorMetadata.of(HolderType.GROUP, CalculatedSubjectData.this.calculatorDisplayName, contexts), processors.build()));
holder.setPermissions(flattenMap(getRelevantEntries(contexts, CalculatedSubjectData.this.permissions)));
return holder;
});
private final LoadingCache<ImmutableContextSet, CalculatorHolder> permissionCache;
public CalculatedSubjectData(LPSubject parentSubject, LPPermissionService service, String calculatorDisplayName) {
this.parentSubject = parentSubject;
this.service = service;
this.calculatorDisplayName = calculatorDisplayName;
this.permissionCache = Caffeine.newBuilder()
.expireAfterAccess(10, TimeUnit.MINUTES)
.build(contexts -> {
ImmutableList<PermissionProcessor> processors = ImmutableList.of(new MapProcessor(), new SpongeWildcardProcessor());
PermissionCalculatorMetadata calcMetadata = PermissionCalculatorMetadata.of(null, calculatorDisplayName, contexts);
CalculatorHolder holder = new CalculatorHolder(new PermissionCalculator(this.service.getPlugin(), calcMetadata, processors));
holder.setPermissions(processPermissionsMap(contexts, this.permissions));
return holder;
});
}
@Override
@ -103,7 +97,8 @@ public class CalculatedSubjectData implements LPSubjectData {
}
public Tristate getPermissionValue(ImmutableContextSet contexts, String permission) {
return this.permissionCache.get(contexts).getCalculator().getPermissionValue(permission, CheckOrigin.INTERNAL);
CalculatorHolder calculatorHolder = Objects.requireNonNull(this.permissionCache.get(contexts));
return calculatorHolder.getCalculator().getPermissionValue(permission, CheckOrigin.INTERNAL);
}
public void replacePermissions(Map<ImmutableContextSet, Map<String, Boolean>> map) {
@ -291,30 +286,25 @@ public class CalculatedSubjectData implements LPSubjectData {
return CompletableFuture.completedFuture(!map.isEmpty());
}
private static <V> Map<String, V> flattenMap(SortedMap<ImmutableContextSet, Map<String, V>> data) {
Map<String, V> map = new HashMap<>();
for (Map<String, V> m : data.values()) {
for (Map.Entry<String, V> e : m.entrySet()) {
map.putIfAbsent(e.getKey(), e.getValue());
}
}
return ImmutableMap.copyOf(map);
}
private static <K, V> SortedMap<ImmutableContextSet, Map<K, V>> getRelevantEntries(ImmutableContextSet set, Map<ImmutableContextSet, Map<K, V>> map) {
ImmutableSortedMap.Builder<ImmutableContextSet, Map<K, V>> perms = ImmutableSortedMap.orderedBy(ContextSetComparator.reverse());
for (Map.Entry<ImmutableContextSet, Map<K, V>> e : map.entrySet()) {
if (!e.getKey().isSatisfiedBy(set)) {
private static Map<String, Boolean> processPermissionsMap(ImmutableContextSet filter, Map<ImmutableContextSet, Map<String, Boolean>> input) {
// get relevant entries
SortedMap<ImmutableContextSet, Map<String, Boolean>> sorted = new TreeMap<>(ContextSetComparator.reverse());
for (Map.Entry<ImmutableContextSet, Map<String, Boolean>> entry : input.entrySet()) {
if (!entry.getKey().isSatisfiedBy(filter)) {
continue;
}
perms.put(e.getKey(), ImmutableMap.copyOf(e.getValue()));
sorted.put(entry.getKey(), entry.getValue());
}
return perms.build();
// flatten
Map<String, Boolean> result = new HashMap<>();
for (Map<String, Boolean> map : sorted.values()) {
for (Map.Entry<String, Boolean> e : map.entrySet()) {
result.putIfAbsent(e.getKey(), e.getValue());
}
}
return ImmutableMap.copyOf(result);
}
private static boolean stringEquals(String a, String b) {
@ -322,9 +312,7 @@ public class CalculatedSubjectData implements LPSubjectData {
}
private static class CalculatorHolder {
private final PermissionCalculator calculator;
private final Map<String, Boolean> permissions;
public CalculatorHolder(PermissionCalculator calculator) {

View File

@ -23,52 +23,42 @@
* SOFTWARE.
*/
package me.lucko.luckperms.sponge.service.persisted;
package me.lucko.luckperms.sponge.service.internal;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.sponge.LPSpongePlugin;
import me.lucko.luckperms.sponge.model.SpongeGroup;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectCollection;
public final class OptionLookupKey {
import org.spongepowered.api.command.CommandSource;
public static OptionLookupKey of(String key, ImmutableContextSet contexts) {
return new OptionLookupKey(key, contexts);
}
import java.util.Optional;
private final String key;
private final ImmutableContextSet contexts;
private OptionLookupKey(String key, ImmutableContextSet contexts) {
this.key = key;
this.contexts = contexts;
}
public String getKey() {
return this.key;
}
public ImmutableContextSet getContexts() {
return this.contexts;
/**
* Implements {@link LPSubject} for a {@link SpongeGroup}.
*/
public class GroupSubject extends HolderSubject<SpongeGroup> implements LPSubject {
public GroupSubject(LPSpongePlugin plugin, SpongeGroup parent) {
super(plugin, parent);
}
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof OptionLookupKey)) return false;
final OptionLookupKey other = (OptionLookupKey) o;
return this.getKey().equals(other.getKey()) && this.getContexts().equals(other.getContexts());
public String getIdentifier() {
return this.parent.getObjectName();
}
@Override
public int hashCode() {
final int PRIME = 59;
int result = 1;
result = result * PRIME + this.getKey().hashCode();
result = result * PRIME + this.getContexts().hashCode();
return result;
public Optional<String> getFriendlyIdentifier() {
return this.parent.getDisplayName();
}
@Override
public String toString() {
return "OptionLookupKey(key=" + this.getKey() + ", contexts=" + this.getContexts() + ")";
public Optional<CommandSource> getCommandSource() {
return Optional.empty();
}
}
@Override
public LPSubjectCollection getParentCollection() {
return this.plugin.getService().getGroupSubjects();
}
}

View File

@ -0,0 +1,156 @@
/*
* 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.internal;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
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.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.service.LuckPermsService;
import me.lucko.luckperms.sponge.service.ProxyFactory;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.reference.LPSubjectReference;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.service.permission.Subject;
import java.util.Map;
import java.util.Optional;
/**
* Implements {@link LPSubject} for a {@link PermissionHolder}.
*/
public abstract class HolderSubject<T extends PermissionHolder> implements LPSubject {
protected final T parent;
protected final LPSpongePlugin plugin;
private final HolderSubjectData subjectData;
private final HolderSubjectData transientSubjectData;
HolderSubject(LPSpongePlugin plugin, T parent) {
this.parent = parent;
this.plugin = plugin;
this.subjectData = new HolderSubjectData(plugin.getService(), NodeMapType.ENDURING, parent, this);
this.transientSubjectData = new HolderSubjectData(plugin.getService(), NodeMapType.TRANSIENT, parent, this);
}
@Override
public Subject sponge() {
return ProxyFactory.toSponge(this);
}
@Override
public LuckPermsService getService() {
return this.plugin.getService();
}
@Override
public HolderSubjectData getSubjectData() {
return this.subjectData;
}
@Override
public HolderSubjectData getTransientSubjectData() {
return this.transientSubjectData;
}
@Override
public Tristate getPermissionValue(ImmutableContextSet contexts, String permission) {
return this.parent.getCachedData().getPermissionData(this.plugin.getContextManager().formContexts(contexts)).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();
}
@Override
public ImmutableList<LPSubjectReference> getParents(ImmutableContextSet contexts) {
ImmutableSet.Builder<LPSubjectReference> subjects = ImmutableSet.builder();
for (Map.Entry<String, Boolean> entry : this.parent.getCachedData().getPermissionData(this.plugin.getContextManager().formContexts(contexts)).getImmutableBacking().entrySet()) {
if (!entry.getValue()) {
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.addAll(getParentCollection().getDefaults().getParents(contexts));
subjects.addAll(this.plugin.getService().getDefaults().getParents(contexts));
return getService().sortSubjects(subjects.build());
}
@Override
public Optional<String> getOption(ImmutableContextSet contexts, String s) {
MetaData data = this.parent.getCachedData().getMetaData(this.plugin.getContextManager().formContexts(contexts));
if (s.equalsIgnoreCase(NodeFactory.PREFIX_KEY)) {
if (data.getPrefix() != null) {
return Optional.of(data.getPrefix());
}
}
if (s.equalsIgnoreCase(NodeFactory.SUFFIX_KEY)) {
if (data.getSuffix() != null) {
return Optional.of(data.getSuffix());
}
}
String val = data.getMeta().get(s);
if (val != null) {
return Optional.of(val);
}
Optional<String> v = getParentCollection().getDefaults().getOption(contexts, s);
if (v.isPresent()) {
return v;
}
return this.plugin.getService().getDefaults().getOption(contexts, s);
}
@Override
public void invalidateCaches(CacheLevel cacheLevel) {
// invalidate for all changes
this.parent.getCachedData().invalidateCaches();
}
}

View File

@ -23,7 +23,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.sponge.service;
package me.lucko.luckperms.sponge.service.internal;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@ -35,9 +35,11 @@ import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.common.caching.type.MetaAccumulator;
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.model.User;
import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectData;
import me.lucko.luckperms.sponge.service.reference.LPSubjectReference;
@ -50,25 +52,27 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class LuckPermsSubjectData implements LPSubjectData {
private final boolean enduring;
public class HolderSubjectData implements LPSubjectData {
private final LuckPermsService service;
private final NodeMapType type;
private final PermissionHolder holder;
private final LPSubject parentSubject;
public LuckPermsSubjectData(boolean enduring, LuckPermsService service, PermissionHolder holder, LPSubject parentSubject) {
this.enduring = enduring;
public HolderSubjectData(LuckPermsService service, NodeMapType type, PermissionHolder holder, LPSubject parentSubject) {
this.type = type;
this.service = service;
this.holder = holder;
this.parentSubject = parentSubject;
}
private Stream<Node> streamNodes() {
return this.holder.getNodes(this.type).values().stream();
}
@Override
public LPSubject getParentSubject() {
return this.parentSubject;
@ -76,21 +80,15 @@ public class LuckPermsSubjectData implements LPSubjectData {
@Override
public ImmutableMap<ImmutableContextSet, ImmutableMap<String, Boolean>> getAllPermissions() {
Map<ImmutableContextSet, ImmutableMap.Builder<String, Boolean>> perms = new HashMap<>();
for (Map.Entry<ImmutableContextSet, Collection<Node>> e : (this.enduring ? this.holder.getEnduringNodes() : this.holder.getTransientNodes()).asMap().entrySet()) {
ImmutableMap.Builder<String, Boolean> results = ImmutableMap.builder();
for (Node n : e.getValue()) {
results.put(n.getPermission(), n.getValuePrimitive());
ImmutableMap.Builder<ImmutableContextSet, ImmutableMap<String, Boolean>> ret = ImmutableMap.builder();
for (Map.Entry<ImmutableContextSet, Collection<Node>> entry : this.holder.getNodes(this.type).asMap().entrySet()) {
ImmutableMap.Builder<String, Boolean> builder = ImmutableMap.builder();
for (Node n : entry.getValue()) {
builder.put(n.getPermission(), n.getValuePrimitive());
}
perms.put(e.getKey(), results);
ret.put(entry.getKey(), builder.build());
}
ImmutableMap.Builder<ImmutableContextSet, ImmutableMap<String, Boolean>> map = ImmutableMap.builder();
for (Map.Entry<ImmutableContextSet, ImmutableMap.Builder<String, Boolean>> e : perms.entrySet()) {
map.put(e.getKey(), e.getValue().build());
}
return map.build();
return ret.build();
}
@Override
@ -102,42 +100,35 @@ public class LuckPermsSubjectData implements LPSubjectData {
if (tristate == Tristate.UNDEFINED) {
// Unset
Node node = NodeFactory.builder(permission).withExtraContext(contexts).build();
if (this.enduring) {
this.holder.unsetPermission(node);
} else {
this.holder.unsetTransientPermission(node);
}
this.type.run(
() -> this.holder.unsetPermission(node),
() -> this.holder.unsetTransientPermission(node)
);
return objectSave(this.holder).thenApply(v -> true);
}
Node node = NodeFactory.builder(permission).setValue(tristate.asBoolean()).withExtraContext(contexts).build();
// Workaround: unset the inverse, to allow false -> true, true -> false overrides.
if (this.enduring) {
this.holder.unsetPermission(node);
} else {
this.holder.unsetTransientPermission(node);
}
if (this.enduring) {
this.holder.setPermission(node);
} else {
this.holder.setTransientPermission(node);
}
this.type.run(
() -> {
// unset the inverse, to allow false -> true, true -> false overrides.
this.holder.unsetPermission(node);
this.holder.setPermission(node);
},
() -> {
// unset the inverse, to allow false -> true, true -> false overrides.
this.holder.unsetTransientPermission(node);
this.holder.setTransientPermission(node);
}
);
return objectSave(this.holder).thenApply(v -> true);
}
@Override
public CompletableFuture<Boolean> clearPermissions() {
boolean ret;
if (this.enduring) {
ret = this.holder.clearNodes();
} else {
ret = this.holder.clearTransientNodes();
}
boolean ret = this.type.supply(
this.holder::clearNodes,
this.holder::clearTransientNodes
);
if (!ret) {
return CompletableFuture.completedFuture(false);
@ -153,18 +144,17 @@ public class LuckPermsSubjectData implements LPSubjectData {
@Override
public CompletableFuture<Boolean> clearPermissions(ImmutableContextSet contexts) {
Objects.requireNonNull(contexts, "contexts");
boolean ret = this.type.supply(
() -> this.holder.clearNodes(contexts),
() -> {
List<Node> toRemove = streamNodes()
.filter(n -> n.getFullContexts().equals(contexts))
.collect(Collectors.toList());
boolean ret;
if (this.enduring) {
ret = this.holder.clearNodes(contexts);
} else {
List<Node> toRemove = streamNodes(false)
.filter(n -> n.getFullContexts().equals(contexts))
.collect(Collectors.toList());
toRemove.forEach(makeUnsetConsumer(false));
ret = !toRemove.isEmpty();
}
toRemove.forEach(this.holder::unsetTransientPermission);
return !toRemove.isEmpty();
}
);
if (!ret) {
return CompletableFuture.completedFuture(false);
@ -179,23 +169,17 @@ public class LuckPermsSubjectData implements LPSubjectData {
@Override
public ImmutableMap<ImmutableContextSet, ImmutableList<LPSubjectReference>> getAllParents() {
Map<ImmutableContextSet, ImmutableList.Builder<LPSubjectReference>> parents = new HashMap<>();
for (Map.Entry<ImmutableContextSet, Collection<Node>> e : (this.enduring ? this.holder.getEnduringNodes() : this.holder.getTransientNodes()).asMap().entrySet()) {
ImmutableList.Builder<LPSubjectReference> results = ImmutableList.builder();
for (Node n : e.getValue()) {
ImmutableMap.Builder<ImmutableContextSet, ImmutableList<LPSubjectReference>> ret = ImmutableMap.builder();
for (Map.Entry<ImmutableContextSet, Collection<Node>> entry : this.holder.getNodes(this.type).asMap().entrySet()) {
ImmutableList.Builder<LPSubjectReference> builder = ImmutableList.builder();
for (Node n : entry.getValue()) {
if (n.isGroupNode()) {
results.add(this.service.getGroupSubjects().loadSubject(n.getGroupName()).join().toReference());
builder.add(this.service.getGroupSubjects().loadSubject(n.getGroupName()).join().toReference());
}
}
parents.put(e.getKey(), results);
ret.put(entry.getKey(), builder.build());
}
ImmutableMap.Builder<ImmutableContextSet, ImmutableList<LPSubjectReference>> map = ImmutableMap.builder();
for (Map.Entry<ImmutableContextSet, ImmutableList.Builder<LPSubjectReference>> e : parents.entrySet()) {
map.put(e.getKey(), e.getValue().build());
}
return map.build();
return ret.build();
}
@Override
@ -203,28 +187,24 @@ public class LuckPermsSubjectData implements LPSubjectData {
Objects.requireNonNull(contexts, "contexts");
Objects.requireNonNull(subject, "subject");
if (subject.getCollectionIdentifier().equals(PermissionService.SUBJECTS_GROUP)) {
return subject.resolveLp().thenCompose(sub -> {
DataMutateResult result;
if (this.enduring) {
result = this.holder.setPermission(NodeFactory.buildGroupNode(sub.getIdentifier())
.withExtraContext(contexts)
.build());
} else {
result = this.holder.setTransientPermission(NodeFactory.buildGroupNode(sub.getIdentifier())
.withExtraContext(contexts)
.build());
}
if (!result.asBoolean()) {
return CompletableFuture.completedFuture(false);
}
return objectSave(this.holder).thenApply(v -> true);
});
if (!subject.getCollectionIdentifier().equals(PermissionService.SUBJECTS_GROUP)) {
return CompletableFuture.completedFuture(false);
}
return CompletableFuture.completedFuture(false);
Node node = NodeFactory.buildGroupNode(subject.getSubjectIdentifier())
.withExtraContext(contexts)
.build();
DataMutateResult result = this.type.supply(
() -> this.holder.setPermission(node),
() -> this.holder.setTransientPermission(node)
);
if (!result.asBoolean()) {
return CompletableFuture.completedFuture(false);
}
return objectSave(this.holder).thenApply(v -> true);
}
@Override
@ -232,47 +212,39 @@ public class LuckPermsSubjectData implements LPSubjectData {
Objects.requireNonNull(contexts, "contexts");
Objects.requireNonNull(subject, "subject");
if (subject.getCollectionIdentifier().equals(PermissionService.SUBJECTS_GROUP)) {
subject.resolveLp().thenCompose(sub -> {
DataMutateResult result;
if (this.enduring) {
result = this.holder.unsetPermission(NodeFactory.buildGroupNode(sub.getIdentifier())
.withExtraContext(contexts)
.build());
} else {
result = this.holder.unsetTransientPermission(NodeFactory.buildGroupNode(sub.getIdentifier())
.withExtraContext(contexts)
.build());
}
if (!result.asBoolean()) {
return CompletableFuture.completedFuture(false);
}
return objectSave(this.holder).thenApply(v -> true);
});
if (!subject.getCollectionIdentifier().equals(PermissionService.SUBJECTS_GROUP)) {
return CompletableFuture.completedFuture(false);
}
return CompletableFuture.completedFuture(false);
Node node = NodeFactory.buildGroupNode(subject.getSubjectIdentifier())
.withExtraContext(contexts)
.build();
DataMutateResult result = this.type.supply(
() -> this.holder.unsetPermission(node),
() -> this.holder.unsetTransientPermission(node)
);
if (!result.asBoolean()) {
return CompletableFuture.completedFuture(false);
}
return objectSave(this.holder).thenApply(v -> true);
}
@Override
public CompletableFuture<Boolean> clearParents() {
boolean ret;
if (this.enduring) {
ret = this.holder.clearParents(true);
} else {
List<Node> toRemove = streamNodes(false)
.filter(Node::isGroupNode)
.collect(Collectors.toList());
boolean ret = this.type.supply(
() -> this.holder.clearParents(true),
() -> {
List<Node> toRemove = streamNodes()
.filter(Node::isGroupNode)
.collect(Collectors.toList());
toRemove.forEach(makeUnsetConsumer(false));
ret = !toRemove.isEmpty();
if (ret && this.holder.getType().isUser()) {
this.service.getPlugin().getUserManager().giveDefaultIfNeeded(((User) this.holder), false);
}
}
toRemove.forEach(this.holder::unsetTransientPermission);
return !toRemove.isEmpty();
}
);
if (!ret) {
return CompletableFuture.completedFuture(false);
@ -284,23 +256,18 @@ public class LuckPermsSubjectData implements LPSubjectData {
@Override
public CompletableFuture<Boolean> clearParents(ImmutableContextSet contexts) {
Objects.requireNonNull(contexts, "contexts");
boolean ret = this.type.supply(
() -> this.holder.clearParents(contexts, true),
() -> {
List<Node> toRemove = streamNodes()
.filter(Node::isGroupNode)
.filter(n -> n.getFullContexts().equals(contexts))
.collect(Collectors.toList());
boolean ret;
if (this.enduring) {
ret = this.holder.clearParents(contexts, true);
} else {
List<Node> toRemove = streamNodes(false)
.filter(Node::isGroupNode)
.filter(n -> n.getFullContexts().equals(contexts))
.collect(Collectors.toList());
toRemove.forEach(makeUnsetConsumer(false));
ret = !toRemove.isEmpty();
if (ret && this.holder.getType().isUser()) {
this.service.getPlugin().getUserManager().giveDefaultIfNeeded(((User) this.holder), false);
}
}
toRemove.forEach(this.holder::unsetTransientPermission);
return !toRemove.isEmpty();
}
);
if (!ret) {
return CompletableFuture.completedFuture(false);
@ -315,7 +282,7 @@ public class LuckPermsSubjectData implements LPSubjectData {
Map<ImmutableContextSet, Integer> minPrefixPriority = new HashMap<>();
Map<ImmutableContextSet, Integer> minSuffixPriority = new HashMap<>();
for (Node n : this.enduring ? this.holder.getEnduringNodes().values() : this.holder.getTransientNodes().values()) {
for (Node n : this.holder.getNodes(this.type).values()) {
if (!n.getValuePrimitive()) continue;
if (!n.isMeta() && !n.isPrefix() && !n.isSuffix()) continue;
@ -364,44 +331,46 @@ public class LuckPermsSubjectData implements LPSubjectData {
Objects.requireNonNull(key, "key");
Objects.requireNonNull(value, "value");
Node node;
if (key.equalsIgnoreCase(NodeFactory.PREFIX_KEY) || key.equalsIgnoreCase(NodeFactory.SUFFIX_KEY)) {
// special handling.
ChatMetaType type = ChatMetaType.valueOf(key.toUpperCase());
// remove all prefixes/suffixes from the user
List<Node> toRemove = streamNodes(this.enduring)
List<Node> toRemove = streamNodes()
.filter(type::matches)
.filter(n -> n.getFullContexts().equals(contexts))
.collect(Collectors.toList());
toRemove.forEach(makeUnsetConsumer(this.enduring));
toRemove.forEach(n -> this.type.run(
() -> this.holder.unsetPermission(n),
() -> this.holder.unsetTransientPermission(n)
));
MetaAccumulator metaAccumulator = this.holder.accumulateMeta(null, this.service.getPlugin().getContextManager().formContexts(contexts));
int priority = metaAccumulator.getChatMeta(type).keySet().stream().mapToInt(e -> e).max().orElse(0);
priority += 10;
if (this.enduring) {
this.holder.setPermission(NodeFactory.buildChatMetaNode(type, priority, value).withExtraContext(contexts).build());
} else {
this.holder.setTransientPermission(NodeFactory.buildChatMetaNode(type, priority, value).withExtraContext(contexts).build());
}
node = NodeFactory.buildChatMetaNode(type, priority, value).withExtraContext(contexts).build();
} else {
// standard remove
List<Node> toRemove = streamNodes(this.enduring)
List<Node> toRemove = streamNodes()
.filter(n -> n.isMeta() && n.getMeta().getKey().equals(key))
.filter(n -> n.getFullContexts().equals(contexts))
.collect(Collectors.toList());
toRemove.forEach(makeUnsetConsumer(this.enduring));
toRemove.forEach(n -> this.type.run(
() -> this.holder.unsetPermission(n),
() -> this.holder.unsetTransientPermission(n)
));
if (this.enduring) {
this.holder.setPermission(NodeFactory.buildMetaNode(key, value).withExtraContext(contexts).build());
} else {
this.holder.setTransientPermission(NodeFactory.buildMetaNode(key, value).withExtraContext(contexts).build());
}
node = NodeFactory.buildMetaNode(key, value).withExtraContext(contexts).build();
}
this.type.run(
() -> this.holder.setPermission(node),
() -> this.holder.setTransientPermission(node)
);
return objectSave(this.holder).thenApply(v -> true);
}
@ -410,7 +379,7 @@ public class LuckPermsSubjectData implements LPSubjectData {
Objects.requireNonNull(contexts, "contexts");
Objects.requireNonNull(key, "key");
List<Node> toRemove = streamNodes(this.enduring)
List<Node> toRemove = streamNodes()
.filter(n -> {
if (key.equalsIgnoreCase(NodeFactory.PREFIX_KEY)) {
return n.isPrefix();
@ -423,7 +392,10 @@ public class LuckPermsSubjectData implements LPSubjectData {
.filter(n -> n.getFullContexts().equals(contexts))
.collect(Collectors.toList());
toRemove.forEach(makeUnsetConsumer(this.enduring));
toRemove.forEach(node -> this.type.run(
() -> this.holder.unsetPermission(node),
() -> this.holder.unsetTransientPermission(node)
));
return objectSave(this.holder).thenApply(v -> true);
}
@ -432,43 +404,36 @@ public class LuckPermsSubjectData implements LPSubjectData {
public CompletableFuture<Boolean> clearOptions(ImmutableContextSet contexts) {
Objects.requireNonNull(contexts, "contexts");
List<Node> toRemove = streamNodes(this.enduring)
List<Node> toRemove = streamNodes()
.filter(n -> n.isMeta() || n.isPrefix() || n.isSuffix())
.filter(n -> n.getFullContexts().equals(contexts))
.collect(Collectors.toList());
toRemove.forEach(makeUnsetConsumer(this.enduring));
toRemove.forEach(node -> this.type.run(
() -> this.holder.unsetPermission(node),
() -> this.holder.unsetTransientPermission(node)
));
return objectSave(this.holder).thenApply(v -> !toRemove.isEmpty());
}
@Override
public CompletableFuture<Boolean> clearOptions() {
List<Node> toRemove = streamNodes(this.enduring)
List<Node> toRemove = streamNodes()
.filter(n -> n.isMeta() || n.isPrefix() || n.isSuffix())
.collect(Collectors.toList());
toRemove.forEach(makeUnsetConsumer(this.enduring));
toRemove.forEach(node -> this.type.run(
() -> this.holder.unsetPermission(node),
() -> this.holder.unsetTransientPermission(node)
));
return objectSave(this.holder).thenApply(v -> !toRemove.isEmpty());
}
private Stream<Node> streamNodes(boolean enduring) {
return (enduring ? this.holder.getEnduringNodes() : this.holder.getTransientNodes()).values().stream();
}
private Consumer<Node> makeUnsetConsumer(boolean enduring) {
return n -> {
if (enduring) {
this.holder.unsetPermission(n);
} else {
this.holder.unsetTransientPermission(n);
}
};
}
private CompletableFuture<Void> objectSave(PermissionHolder t) {
if (!this.enduring) {
// handle transient first
if (this.type == NodeMapType.TRANSIENT) {
// don't bother saving to primary storage. just refresh
if (t.getType().isUser()) {
User user = ((User) t);
@ -476,30 +441,31 @@ public class LuckPermsSubjectData implements LPSubjectData {
} else {
return this.service.getPlugin().getUpdateTaskBuffer().request();
}
}
// handle enduring
if (t.getType().isUser()) {
User user = ((User) t);
CompletableFuture<Void> fut = new CompletableFuture<>();
this.service.getPlugin().getStorage().saveUser(user).whenCompleteAsync((v, ex) -> {
if (ex != null) {
fut.complete(null);
}
user.getRefreshBuffer().request().thenAccept(fut::complete);
}, this.service.getPlugin().getScheduler().async());
return fut;
} else {
if (t.getType().isUser()) {
User user = ((User) t);
CompletableFuture<Void> fut = new CompletableFuture<>();
this.service.getPlugin().getStorage().saveUser(user).whenCompleteAsync((v, ex) -> {
if (ex != null) {
fut.complete(null);
}
Group group = ((Group) t);
CompletableFuture<Void> fut = new CompletableFuture<>();
this.service.getPlugin().getStorage().saveGroup(group).whenCompleteAsync((v, ex) -> {
if (ex != null) {
fut.complete(null);
}
user.getRefreshBuffer().request().thenAccept(fut::complete);
}, this.service.getPlugin().getScheduler().async());
return fut;
} else {
Group group = ((Group) t);
CompletableFuture<Void> fut = new CompletableFuture<>();
this.service.getPlugin().getStorage().saveGroup(group).whenCompleteAsync((v, ex) -> {
if (ex != null) {
fut.complete(null);
}
this.service.getPlugin().getUpdateTaskBuffer().request().thenAccept(fut::complete);
}, this.service.getPlugin().getScheduler().async());
return fut;
}
this.service.getPlugin().getUpdateTaskBuffer().request().thenAccept(fut::complete);
}, this.service.getPlugin().getScheduler().async());
return fut;
}
}
}

View File

@ -0,0 +1,68 @@
/*
* 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.internal;
import me.lucko.luckperms.sponge.LPSpongePlugin;
import me.lucko.luckperms.sponge.model.SpongeUser;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectCollection;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.command.CommandSource;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Function;
/**
* Implements {@link LPSubject} for a {@link SpongeUser}.
*/
public final class UserSubject extends HolderSubject<SpongeUser> implements LPSubject {
public UserSubject(LPSpongePlugin plugin, SpongeUser parent) {
super(plugin, parent);
}
@Override
public String getIdentifier() {
return this.parent.getUuid().toString();
}
@Override
public Optional<String> getFriendlyIdentifier() {
return this.parent.getName();
}
@Override
public Optional<CommandSource> getCommandSource() {
final UUID uuid = this.parent.getUuid();
return Sponge.getServer().getPlayer(uuid).map(Function.identity());
}
@Override
public LPSubjectCollection getParentCollection() {
return this.plugin.getService().getUserSubjects();
}
}

View File

@ -1,88 +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.legacy;
import me.lucko.luckperms.sponge.LPSpongePlugin;
import me.lucko.luckperms.sponge.service.storage.SubjectStorage;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
@SuppressWarnings("deprecation")
public class LegacyDataMigrator implements Runnable {
private final LPSpongePlugin plugin;
private final File oldDirectory;
private final SubjectStorage storage;
public LegacyDataMigrator(LPSpongePlugin plugin, File oldDirectory, SubjectStorage storage) {
this.plugin = plugin;
this.oldDirectory = oldDirectory;
this.storage = storage;
}
@Override
public void run() {
if (!this.oldDirectory.exists() || !this.oldDirectory.isDirectory()) {
return;
}
this.plugin.getLog().warn("Migrating old sponge data... Please wait.");
File[] collections = this.oldDirectory.listFiles(File::isDirectory);
if (collections == null) {
return;
}
for (File collectionDir : collections) {
File[] subjects = collectionDir.listFiles((dir, name) -> name.endsWith(".json"));
if (subjects == null) {
continue;
}
for (File subjectFile : subjects) {
String subjectName = subjectFile.getName().substring(0, subjectFile.getName().length() - ".json".length());
try (BufferedReader reader = Files.newBufferedReader(subjectFile.toPath(), StandardCharsets.UTF_8)) {
SubjectDataHolder holder = this.storage.getGson().fromJson(reader, SubjectDataHolder.class);
this.storage.saveToFile(holder.asSubjectModel(this.plugin.getService()), this.storage.resolveFile(collectionDir.getName(), subjectName));
} catch (IOException e) {
e.printStackTrace();
}
subjectFile.delete();
}
collectionDir.delete();
}
this.oldDirectory.delete();
}
}

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.legacy;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.reference.SubjectReferenceFactory;
import me.lucko.luckperms.sponge.service.storage.SubjectStorageModel;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @deprecated Because this format is no longer being used to store data.
* @see SubjectStorageModel
*/
@SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated
public class SubjectDataHolder {
private Map<Map<String, String>, Map<String, Boolean>> permissions;
private Map<Map<String, String>, Map<String, String>> options;
private Map<Map<String, String>, List<String>> parents;
public SubjectDataHolder() {
// For gson
}
public SubjectStorageModel asSubjectModel(LPPermissionService service) {
return new SubjectStorageModel(service,
this.permissions.entrySet().stream()
.collect(Collectors.toMap(
k -> ImmutableContextSet.fromMap(k.getKey()),
Map.Entry::getValue
)),
this.options.entrySet().stream()
.collect(Collectors.toMap(
k -> ImmutableContextSet.fromMap(k.getKey()),
Map.Entry::getValue
)),
this.parents.entrySet().stream()
.collect(Collectors.toMap(
k -> ImmutableContextSet.fromMap(k.getKey()),
v -> v.getValue().stream().map(s -> SubjectReferenceFactory.deserialize(service, s)).collect(Collectors.toList())
))
);
}
}

View File

@ -1,74 +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.persisted;
import me.lucko.luckperms.api.context.ImmutableContextSet;
public final class PermissionLookupKey {
public static PermissionLookupKey of(String node, ImmutableContextSet contexts) {
return new PermissionLookupKey(node, contexts);
}
private final String node;
private final ImmutableContextSet contexts;
private PermissionLookupKey(String node, ImmutableContextSet contexts) {
this.node = node;
this.contexts = contexts;
}
public String getNode() {
return this.node;
}
public ImmutableContextSet getContexts() {
return this.contexts;
}
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof PermissionLookupKey)) return false;
final PermissionLookupKey other = (PermissionLookupKey) o;
return this.getNode().equals(other.getNode()) && this.getContexts().equals(other.getContexts());
}
@Override
public int hashCode() {
final int PRIME = 59;
int result = 1;
result = result * PRIME + this.getNode().hashCode();
result = result * PRIME + this.getContexts().hashCode();
return result;
}
@Override
public String toString() {
return "PermissionLookupKey(node=" + this.getNode() + ", contexts=" + this.getContexts() + ")";
}
}

View File

@ -62,7 +62,7 @@ public class PersistedCollection implements LPSubjectCollection {
private final SubjectCollection spongeProxy;
private final LoadingCache<String, PersistedSubject> subjects = Caffeine.newBuilder()
.build(s -> new PersistedSubject(s, getService(), PersistedCollection.this));
.build(s -> new PersistedSubject(s, getService(), this));
public PersistedCollection(LuckPermsService service, String identifier) {
this.service = service;

View File

@ -64,7 +64,7 @@ public class PersistedSubject implements LPSubject {
private final LoadingCache<PermissionLookupKey, Tristate> permissionLookupCache = Caffeine.newBuilder()
.expireAfterAccess(20, TimeUnit.MINUTES)
.build(lookup -> lookupPermissionValue(lookup.getContexts(), lookup.getNode()));
.build(lookup -> lookupPermissionValue(lookup.contexts, lookup.node));
private final LoadingCache<ImmutableContextSet, ImmutableList<LPSubjectReference>> parentLookupCache = Caffeine.newBuilder()
.expireAfterAccess(20, TimeUnit.MINUTES)
@ -72,7 +72,7 @@ public class PersistedSubject implements LPSubject {
private final LoadingCache<OptionLookupKey, Optional<String>> optionLookupCache = Caffeine.newBuilder()
.expireAfterAccess(20, TimeUnit.MINUTES)
.build(lookup -> lookupOptionValue(lookup.getContexts(), lookup.getKey()));
.build(lookup -> lookupOptionValue(lookup.contexts, lookup.key));
private final BufferedRequest<Void> saveBuffer = new BufferedRequest<Void>(1000L, 500L, r -> PersistedSubject.this.service.getPlugin().getScheduler().doAsync(r)) {
@Override
@ -91,8 +91,9 @@ public class PersistedSubject implements LPSubject {
this.service = service;
this.parentCollection = parentCollection;
this.subjectData = new PersistedSubjectData(service, parentCollection.getIdentifier() + "/" + identifier + "/p", this);
this.transientSubjectData = new CalculatedSubjectData(this, service, parentCollection.getIdentifier() + "/" + identifier + "/t");
String displayName = parentCollection.getIdentifier() + "/" + identifier;
this.subjectData = new PersistedSubjectData(service, displayName + "/p", this);
this.transientSubjectData = new CalculatedSubjectData(this, service, displayName + "/t");
}
@Override
@ -277,7 +278,7 @@ public class PersistedSubject implements LPSubject {
Objects.requireNonNull(contexts, "contexts");
Objects.requireNonNull(node, "node");
Tristate t = this.permissionLookupCache.get(PermissionLookupKey.of(node, contexts));
Tristate t = this.permissionLookupCache.get(new PermissionLookupKey(node, contexts));
this.service.getPlugin().getVerboseHandler().offerCheckData(CheckOrigin.INTERNAL, getParentCollection().getIdentifier() + "/" + this.identifier, contexts, node, t);
return t;
}
@ -306,6 +307,54 @@ public class PersistedSubject implements LPSubject {
@Override
public Optional<String> getOption(ImmutableContextSet contexts, String key) {
return this.optionLookupCache.get(OptionLookupKey.of(key, contexts));
return this.optionLookupCache.get(new OptionLookupKey(key, contexts));
}
private static final class PermissionLookupKey {
private final String node;
private final ImmutableContextSet contexts;
public PermissionLookupKey(String node, ImmutableContextSet contexts) {
this.node = node;
this.contexts = contexts;
}
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof PermissionLookupKey)) return false;
final PermissionLookupKey other = (PermissionLookupKey) o;
return this.node.equals(other.node) && this.contexts.equals(other.contexts);
}
@Override
public int hashCode() {
return Objects.hash(this.node, this.contexts);
}
}
public static final class OptionLookupKey {
private final String key;
private final ImmutableContextSet contexts;
public OptionLookupKey(String key, ImmutableContextSet contexts) {
this.key = key;
this.contexts = contexts;
}
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof OptionLookupKey)) return false;
final OptionLookupKey other = (OptionLookupKey) o;
return this.key.equals(other.key) && this.contexts.equals(other.contexts);
}
@Override
public int hashCode() {
return Objects.hash(this.key, this.contexts);
}
}
}

View File

@ -37,11 +37,16 @@ import java.util.function.Function;
/**
* Extension of MemorySubjectData which persists data when modified
*/
public class PersistedSubjectData extends CalculatedSubjectData implements Function<Boolean, Boolean> {
public class PersistedSubjectData extends CalculatedSubjectData {
private final PersistedSubject subject;
private boolean save = true;
private final Function<Boolean, Boolean> saveFunction = b -> {
save();
return b;
};
public PersistedSubjectData(LuckPermsService service, String calculatorDisplayName, PersistedSubject subject) {
super(subject, service, calculatorDisplayName);
this.subject = subject;
@ -57,72 +62,62 @@ public class PersistedSubjectData extends CalculatedSubjectData implements Funct
}
}
@Override
public Boolean apply(Boolean b) {
save();
return b;
public void setSave(boolean save) {
this.save = save;
}
@Override
public CompletableFuture<Boolean> setPermission(ImmutableContextSet contexts, String permission, Tristate value) {
return super.setPermission(contexts, permission, value).thenApply(this);
return super.setPermission(contexts, permission, value).thenApply(this.saveFunction);
}
@Override
public CompletableFuture<Boolean> clearPermissions() {
return super.clearPermissions().thenApply(this);
return super.clearPermissions().thenApply(this.saveFunction);
}
@Override
public CompletableFuture<Boolean> clearPermissions(ImmutableContextSet contexts) {
return super.clearPermissions(contexts).thenApply(this);
return super.clearPermissions(contexts).thenApply(this.saveFunction);
}
@Override
public CompletableFuture<Boolean> addParent(ImmutableContextSet contexts, LPSubjectReference parent) {
return super.addParent(contexts, parent).thenApply(this);
return super.addParent(contexts, parent).thenApply(this.saveFunction);
}
@Override
public CompletableFuture<Boolean> removeParent(ImmutableContextSet contexts, LPSubjectReference parent) {
return super.removeParent(contexts, parent).thenApply(this);
return super.removeParent(contexts, parent).thenApply(this.saveFunction);
}
@Override
public CompletableFuture<Boolean> clearParents() {
return super.clearParents().thenApply(this);
return super.clearParents().thenApply(this.saveFunction);
}
@Override
public CompletableFuture<Boolean> clearParents(ImmutableContextSet contexts) {
return super.clearParents(contexts).thenApply(this);
return super.clearParents(contexts).thenApply(this.saveFunction);
}
@Override
public CompletableFuture<Boolean> setOption(ImmutableContextSet contexts, String key, String value) {
return super.setOption(contexts, key, value).thenApply(this);
return super.setOption(contexts, key, value).thenApply(this.saveFunction);
}
@Override
public CompletableFuture<Boolean> unsetOption(ImmutableContextSet contexts, String key) {
return super.unsetOption(contexts, key).thenApply(this);
return super.unsetOption(contexts, key).thenApply(this.saveFunction);
}
@Override
public CompletableFuture<Boolean> clearOptions() {
return super.clearOptions().thenApply(this);
return super.clearOptions().thenApply(this.saveFunction);
}
@Override
public CompletableFuture<Boolean> clearOptions(ImmutableContextSet contexts) {
return super.clearOptions(contexts).thenApply(this);
}
public boolean isSave() {
return this.save;
}
public void setSave(boolean save) {
this.save = save;
return super.clearOptions(contexts).thenApply(this.saveFunction);
}
}

View File

@ -50,11 +50,8 @@ import java.util.stream.Collectors;
* Handles persisted Subject I/O and (de)serialization
*/
public class SubjectStorage {
private final LPPermissionService service;
private final Gson gson;
private final File container;
public SubjectStorage(LPPermissionService service, File container) {
@ -158,8 +155,4 @@ public class SubjectStorage {
return Maps.immutableEntry(subjectName, model);
}
}
public Gson getGson() {
return this.gson;
}
}