Implement persisting subjects (+ defaults)
This commit is contained in:
parent
069e535f1a
commit
5b4975f34c
@ -29,6 +29,8 @@ import me.lucko.luckperms.LPSpongePlugin;
|
|||||||
import me.lucko.luckperms.api.sponge.collections.GroupCollection;
|
import me.lucko.luckperms.api.sponge.collections.GroupCollection;
|
||||||
import me.lucko.luckperms.api.sponge.collections.UserCollection;
|
import me.lucko.luckperms.api.sponge.collections.UserCollection;
|
||||||
import me.lucko.luckperms.api.sponge.simple.SimpleCollection;
|
import me.lucko.luckperms.api.sponge.simple.SimpleCollection;
|
||||||
|
import me.lucko.luckperms.api.sponge.simple.persisted.SimplePersistedCollection;
|
||||||
|
import me.lucko.luckperms.api.sponge.simple.persisted.SubjectStorage;
|
||||||
import me.lucko.luckperms.contexts.SpongeCalculatorLink;
|
import me.lucko.luckperms.contexts.SpongeCalculatorLink;
|
||||||
import org.spongepowered.api.plugin.PluginContainer;
|
import org.spongepowered.api.plugin.PluginContainer;
|
||||||
import org.spongepowered.api.service.context.ContextCalculator;
|
import org.spongepowered.api.service.context.ContextCalculator;
|
||||||
@ -36,21 +38,31 @@ import org.spongepowered.api.service.permission.*;
|
|||||||
import org.spongepowered.api.text.Text;
|
import org.spongepowered.api.text.Text;
|
||||||
import org.spongepowered.api.util.Tristate;
|
import org.spongepowered.api.util.Tristate;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The LuckPerms implementation of the Sponge Permission Service
|
||||||
|
*/
|
||||||
public class LuckPermsService implements PermissionService {
|
public class LuckPermsService implements PermissionService {
|
||||||
public static final String SERVER_CONTEXT = "server";
|
public static final String SERVER_CONTEXT = "server";
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final LPSpongePlugin plugin;
|
private final LPSpongePlugin plugin;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final SubjectStorage storage;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final UserCollection userSubjects;
|
private final UserCollection userSubjects;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final GroupCollection groupSubjects;
|
private final GroupCollection groupSubjects;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final SimplePersistedCollection defaultSubjects;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final Set<PermissionDescription> descriptionSet;
|
private final Set<PermissionDescription> descriptionSet;
|
||||||
|
|
||||||
@ -59,12 +71,17 @@ public class LuckPermsService implements PermissionService {
|
|||||||
public LuckPermsService(LPSpongePlugin plugin) {
|
public LuckPermsService(LPSpongePlugin plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
|
||||||
|
storage = new SubjectStorage(new File(plugin.getDataFolder(), "local"));
|
||||||
|
|
||||||
userSubjects = new UserCollection(this, plugin.getUserManager());
|
userSubjects = new UserCollection(this, plugin.getUserManager());
|
||||||
groupSubjects = new GroupCollection(this, plugin.getGroupManager());
|
groupSubjects = new GroupCollection(this, plugin.getGroupManager());
|
||||||
|
defaultSubjects = new SimplePersistedCollection(this, "defaults");
|
||||||
|
defaultSubjects.loadAll();
|
||||||
|
|
||||||
subjects = new ConcurrentHashMap<>();
|
subjects = new ConcurrentHashMap<>();
|
||||||
subjects.put(PermissionService.SUBJECTS_USER, userSubjects);
|
subjects.put(PermissionService.SUBJECTS_USER, userSubjects);
|
||||||
subjects.put(PermissionService.SUBJECTS_GROUP, groupSubjects);
|
subjects.put(PermissionService.SUBJECTS_GROUP, groupSubjects);
|
||||||
|
subjects.put("defaults", defaultSubjects);
|
||||||
|
|
||||||
descriptionSet = ConcurrentHashMap.newKeySet();
|
descriptionSet = ConcurrentHashMap.newKeySet();
|
||||||
}
|
}
|
||||||
@ -75,7 +92,7 @@ public class LuckPermsService implements PermissionService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Subject getDefaults() {
|
public Subject getDefaults() {
|
||||||
return getSubjects("defaults").get("default");
|
return getDefaultSubjects().get("default");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -89,6 +89,6 @@ public class GroupCollection implements SubjectCollection {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Subject getDefaults() {
|
public Subject getDefaults() {
|
||||||
return service.getDefaults();
|
return service.getDefaultSubjects().get(getIdentifier());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,6 +161,6 @@ public class UserCollection implements SubjectCollection {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Subject getDefaults() {
|
public Subject getDefaults() {
|
||||||
return service.getDefaults();
|
return service.getDefaultSubjects().get(getIdentifier());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,8 @@ package me.lucko.luckperms.api.sponge.simple;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import me.lucko.luckperms.api.sponge.LuckPermsService;
|
||||||
import org.spongepowered.api.service.context.Context;
|
import org.spongepowered.api.service.context.Context;
|
||||||
import org.spongepowered.api.service.permission.PermissionService;
|
|
||||||
import org.spongepowered.api.service.permission.Subject;
|
import org.spongepowered.api.service.permission.Subject;
|
||||||
import org.spongepowered.api.service.permission.SubjectCollection;
|
import org.spongepowered.api.service.permission.SubjectCollection;
|
||||||
import org.spongepowered.api.util.Tristate;
|
import org.spongepowered.api.util.Tristate;
|
||||||
@ -37,9 +37,12 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Super simple SubjectCollection implementation
|
||||||
|
*/
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class SimpleCollection implements SubjectCollection {
|
public class SimpleCollection implements SubjectCollection {
|
||||||
private final PermissionService service;
|
private final LuckPermsService service;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final String identifier;
|
private final String identifier;
|
||||||
@ -85,6 +88,6 @@ public class SimpleCollection implements SubjectCollection {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Subject getDefaults() {
|
public Subject getDefaults() {
|
||||||
return new SimpleSubject("default", service, this);
|
return service.getDefaultSubjects().get(identifier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,11 +66,6 @@ public class SimpleSubject implements Subject {
|
|||||||
return getPermissionValue(contexts, node).asBoolean();
|
return getPermissionValue(contexts, node).asBoolean();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasPermission(@NonNull String permission) {
|
|
||||||
return hasPermission(getActiveContexts(), permission);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Tristate getPermissionValue(@NonNull Set<Context> contexts, @NonNull String node) {
|
public Tristate getPermissionValue(@NonNull Set<Context> contexts, @NonNull String node) {
|
||||||
Tristate res = subjectData.getNodeTree(contexts).get(node);
|
Tristate res = subjectData.getNodeTree(contexts).get(node);
|
||||||
@ -86,21 +81,11 @@ public class SimpleSubject implements Subject {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isChildOf(@NonNull Subject parent) {
|
|
||||||
return isChildOf(getActiveContexts(), parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isChildOf(@NonNull Set<Context> contexts, @NonNull Subject subject) {
|
public boolean isChildOf(@NonNull Set<Context> contexts, @NonNull Subject subject) {
|
||||||
return subjectData.getParents(contexts).contains(subject);
|
return subjectData.getParents(contexts).contains(subject);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Subject> getParents() {
|
|
||||||
return getParents(getActiveContexts());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Subject> getParents(@NonNull Set<Context> contexts) {
|
public List<Subject> getParents(@NonNull Set<Context> contexts) {
|
||||||
return subjectData.getParents(contexts);
|
return subjectData.getParents(contexts);
|
||||||
@ -121,11 +106,6 @@ public class SimpleSubject implements Subject {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<String> getOption(String key) {
|
|
||||||
return getOption(getActiveContexts(), key);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<Context> getActiveContexts() {
|
public Set<Context> getActiveContexts() {
|
||||||
return SubjectData.GLOBAL_CONTEXT;
|
return SubjectData.GLOBAL_CONTEXT;
|
||||||
|
@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package me.lucko.luckperms.api.sponge.simple.persisted;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import me.lucko.luckperms.api.sponge.LuckPermsService;
|
||||||
|
import org.spongepowered.api.service.context.Context;
|
||||||
|
import org.spongepowered.api.service.permission.Subject;
|
||||||
|
import org.spongepowered.api.service.permission.SubjectCollection;
|
||||||
|
import org.spongepowered.api.util.Tristate;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple persistable subject collection
|
||||||
|
*/
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class SimplePersistedCollection implements SubjectCollection {
|
||||||
|
private final LuckPermsService service;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final String identifier;
|
||||||
|
|
||||||
|
private final Map<String, SimplePersistedSubject> subjects = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public void loadAll() {
|
||||||
|
Map<String, SimpleSubjectDataHolder> holders = service.getStorage().loadAllFromFile(identifier);
|
||||||
|
for (Map.Entry<String, SimpleSubjectDataHolder> e : holders.entrySet()) {
|
||||||
|
SimplePersistedSubject subject = new SimplePersistedSubject(e.getKey(), service, this);
|
||||||
|
subject.loadData(e.getValue());
|
||||||
|
subjects.put(e.getKey(), subject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized Subject get(@NonNull String id) {
|
||||||
|
if (!subjects.containsKey(id)) {
|
||||||
|
subjects.put(id, new SimplePersistedSubject(id, service, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
return subjects.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasRegistered(@NonNull String id) {
|
||||||
|
return subjects.containsKey(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterable<Subject> getAllSubjects() {
|
||||||
|
return subjects.values().stream().map(s -> (Subject) s).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<Subject, Boolean> getAllWithPermission(@NonNull String id) {
|
||||||
|
return getAllWithPermission(Collections.emptySet(), id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<Subject, Boolean> getAllWithPermission(@NonNull Set<Context> contexts, @NonNull String node) {
|
||||||
|
Map<Subject, Boolean> m = new HashMap<>();
|
||||||
|
for (Subject subject : subjects.values()) {
|
||||||
|
Tristate ts = subject.getPermissionValue(contexts, node);
|
||||||
|
if (ts != Tristate.UNDEFINED) {
|
||||||
|
m.put(subject, ts.asBoolean());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Subject getDefaults() {
|
||||||
|
return service.getDefaultSubjects().get(identifier);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package me.lucko.luckperms.api.sponge.simple.persisted;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import me.lucko.luckperms.api.sponge.LuckPermsService;
|
||||||
|
import org.spongepowered.api.command.CommandSource;
|
||||||
|
import org.spongepowered.api.service.context.Context;
|
||||||
|
import org.spongepowered.api.service.permission.MemorySubjectData;
|
||||||
|
import org.spongepowered.api.service.permission.Subject;
|
||||||
|
import org.spongepowered.api.service.permission.SubjectCollection;
|
||||||
|
import org.spongepowered.api.service.permission.SubjectData;
|
||||||
|
import org.spongepowered.api.util.Tristate;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple persistable Subject implementation
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public class SimplePersistedSubject implements Subject {
|
||||||
|
private final String identifier;
|
||||||
|
|
||||||
|
private final LuckPermsService service;
|
||||||
|
private final SubjectCollection containingCollection;
|
||||||
|
private final SimplePersistedSubjectData subjectData;
|
||||||
|
private final MemorySubjectData transientSubjectData;
|
||||||
|
|
||||||
|
public SimplePersistedSubject(String identifier, LuckPermsService service, SubjectCollection containingCollection) {
|
||||||
|
this.identifier = identifier;
|
||||||
|
this.service = service;
|
||||||
|
this.containingCollection = containingCollection;
|
||||||
|
this.subjectData = new SimplePersistedSubjectData(service, this);
|
||||||
|
this.transientSubjectData = new MemorySubjectData(service);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadData(SimpleSubjectDataHolder dataHolder) {
|
||||||
|
subjectData.setSave(false);
|
||||||
|
dataHolder.copyTo(subjectData, service);
|
||||||
|
subjectData.setSave(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save() {
|
||||||
|
service.getPlugin().doAsync(() -> {
|
||||||
|
try {
|
||||||
|
service.getStorage().saveToFile(this);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<CommandSource> getCommandSource() {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPermission(@NonNull Set<Context> contexts, @NonNull String node) {
|
||||||
|
return getPermissionValue(contexts, node).asBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Tristate getPermissionValue(@NonNull Set<Context> contexts, @NonNull String node) {
|
||||||
|
Tristate res = subjectData.getNodeTree(contexts).get(node);
|
||||||
|
if (res == Tristate.UNDEFINED) {
|
||||||
|
transientSubjectData.getNodeTree(contexts).get(node);
|
||||||
|
}
|
||||||
|
if (res == Tristate.UNDEFINED) {
|
||||||
|
for (Subject parent : getParents(contexts)) {
|
||||||
|
Tristate tempRes = parent.getPermissionValue(contexts, node);
|
||||||
|
if (tempRes != Tristate.UNDEFINED) {
|
||||||
|
res = tempRes;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isChildOf(@NonNull Set<Context> contexts, @NonNull Subject subject) {
|
||||||
|
return subjectData.getParents(contexts).contains(subject) || transientSubjectData.getParents(contexts).contains(subject);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Subject> getParents(@NonNull Set<Context> contexts) {
|
||||||
|
List<Subject> s = new ArrayList<>();
|
||||||
|
s.addAll(subjectData.getParents(contexts));
|
||||||
|
s.addAll(transientSubjectData.getParents(contexts));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<String> getOption(Set<Context> set, String key) {
|
||||||
|
Optional<String> res = Optional.ofNullable(subjectData.getOptions(getActiveContexts()).get(key));
|
||||||
|
if (!res.isPresent()) {
|
||||||
|
res = Optional.ofNullable(transientSubjectData.getOptions(getActiveContexts()).get(key));
|
||||||
|
}
|
||||||
|
if (!res.isPresent()) {
|
||||||
|
for (Subject parent : getParents(getActiveContexts())) {
|
||||||
|
Optional<String> tempRes = parent.getOption(getActiveContexts(), key);
|
||||||
|
if (tempRes.isPresent()) {
|
||||||
|
res = tempRes;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Context> getActiveContexts() {
|
||||||
|
return SubjectData.GLOBAL_CONTEXT;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package me.lucko.luckperms.api.sponge.simple.persisted;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.spongepowered.api.service.context.Context;
|
||||||
|
import org.spongepowered.api.service.permission.MemorySubjectData;
|
||||||
|
import org.spongepowered.api.service.permission.PermissionService;
|
||||||
|
import org.spongepowered.api.service.permission.Subject;
|
||||||
|
import org.spongepowered.api.util.Tristate;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension of MemorySubjectData which persists data when modified
|
||||||
|
*/
|
||||||
|
public class SimplePersistedSubjectData extends MemorySubjectData {
|
||||||
|
private final SimplePersistedSubject subject;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private boolean save = true;
|
||||||
|
|
||||||
|
public SimplePersistedSubjectData(PermissionService service, SimplePersistedSubject subject) {
|
||||||
|
super(service);
|
||||||
|
this.subject = subject;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void save() {
|
||||||
|
if (!save) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subject != null) {
|
||||||
|
subject.save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setPermission(Set<Context> contexts, String permission, Tristate value) {
|
||||||
|
boolean r = super.setPermission(contexts, permission, value);
|
||||||
|
save();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean clearPermissions() {
|
||||||
|
boolean r = super.clearPermissions();
|
||||||
|
save();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean clearPermissions(Set<Context> context) {
|
||||||
|
boolean r = super.clearPermissions(context);
|
||||||
|
save();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean addParent(Set<Context> contexts, Subject parent) {
|
||||||
|
boolean r = super.addParent(contexts, parent);
|
||||||
|
save();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean removeParent(Set<Context> contexts, Subject parent) {
|
||||||
|
boolean r = super.removeParent(contexts, parent);
|
||||||
|
save();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean clearParents() {
|
||||||
|
boolean r = super.clearParents();
|
||||||
|
save();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean clearParents(Set<Context> contexts) {
|
||||||
|
boolean r = super.clearParents(contexts);
|
||||||
|
save();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setOption(Set<Context> contexts, String key, @Nullable String value) {
|
||||||
|
boolean r = super.setOption(contexts, key, value);
|
||||||
|
save();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean clearOptions(Set<Context> contexts) {
|
||||||
|
boolean r = super.clearOptions(contexts);
|
||||||
|
save();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean clearOptions() {
|
||||||
|
boolean r = super.clearOptions();
|
||||||
|
save();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package me.lucko.luckperms.api.sponge.simple.persisted;
|
||||||
|
|
||||||
|
import org.spongepowered.api.service.context.Context;
|
||||||
|
import org.spongepowered.api.service.permission.MemorySubjectData;
|
||||||
|
import org.spongepowered.api.service.permission.PermissionService;
|
||||||
|
import org.spongepowered.api.util.Tristate;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds SubjectData in a "gson friendly" format for serialization
|
||||||
|
*/
|
||||||
|
public class SimpleSubjectDataHolder {
|
||||||
|
private final Map<Map<String, String>, Map<String, Boolean>> permissions;
|
||||||
|
private final Map<Map<String, String>, Map<String, String>> options;
|
||||||
|
private final Map<Map<String, String>, List<Map.Entry<String, String>>> parents;
|
||||||
|
|
||||||
|
public SimpleSubjectDataHolder(Map<Set<Context>, Map<String, String>> options, Map<Set<Context>, Map<String, Boolean>> permissions, Map<Set<Context>, List<Map.Entry<String, String>>> parents) {
|
||||||
|
this.options = new HashMap<>();
|
||||||
|
for (Map.Entry<Set<Context>, Map<String, String>> e : options.entrySet()) {
|
||||||
|
this.options.put(convertContexts(e.getKey()), new HashMap<>(e.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.permissions = new HashMap<>();
|
||||||
|
for (Map.Entry<Set<Context>, Map<String, Boolean>> e : permissions.entrySet()) {
|
||||||
|
this.permissions.put(convertContexts(e.getKey()), new HashMap<>(e.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.parents = new HashMap<>();
|
||||||
|
for (Map.Entry<Set<Context>, List<Map.Entry<String, String>>> e : parents.entrySet()) {
|
||||||
|
this.parents.put(convertContexts(e.getKey()), e.getValue().stream().map(p -> new AbstractMap.SimpleEntry<>(p.getKey(), p.getValue())).collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleSubjectDataHolder(MemorySubjectData data) {
|
||||||
|
this(
|
||||||
|
data.getAllOptions(),
|
||||||
|
data.getAllPermissions(),
|
||||||
|
data.getAllParents().entrySet().stream()
|
||||||
|
.collect(Collectors.toMap(
|
||||||
|
Map.Entry::getKey,
|
||||||
|
e -> e.getValue().stream()
|
||||||
|
.map(s -> new AbstractMap.SimpleEntry<>(
|
||||||
|
s.getContainingCollection().getIdentifier(),
|
||||||
|
s.getIdentifier())
|
||||||
|
)
|
||||||
|
.collect(Collectors.toList())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void copyTo(MemorySubjectData subjectData, PermissionService service) {
|
||||||
|
for (Map.Entry<Map<String, String>, Map<String, Boolean>> e : permissions.entrySet()) {
|
||||||
|
for (Map.Entry<String, Boolean> perm : e.getValue().entrySet()) {
|
||||||
|
subjectData.setPermission(convertContexts(e.getKey()), perm.getKey(), Tristate.fromBoolean(perm.getValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Map.Entry<Map<String, String>, Map<String, String>> e : options.entrySet()) {
|
||||||
|
for (Map.Entry<String, String> option : e.getValue().entrySet()) {
|
||||||
|
subjectData.setOption(convertContexts(e.getKey()), option.getKey(), option.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Map.Entry<Map<String, String>, List<Map.Entry<String, String>>> e : parents.entrySet()) {
|
||||||
|
for (Map.Entry<String, String> parent : e.getValue()) {
|
||||||
|
subjectData.addParent(convertContexts(e.getKey()), service.getSubjects(parent.getKey()).get(parent.getValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<String, String> convertContexts(Set<Context> contexts) {
|
||||||
|
return contexts.stream().collect(Collectors.toMap(Context::getKey, Context::getValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Set<Context> convertContexts(Map<String, String> contexts) {
|
||||||
|
return contexts.entrySet().stream().map(e -> new Context(e.getKey(), e.getValue())).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package me.lucko.luckperms.api.sponge.simple.persisted;
|
||||||
|
|
||||||
|
import com.google.common.io.Files;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.AbstractMap;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles persisted Subject I/O and (de)serialization
|
||||||
|
*/
|
||||||
|
public class SubjectStorage {
|
||||||
|
private final Gson gson;
|
||||||
|
private final File container;
|
||||||
|
|
||||||
|
public SubjectStorage(File container) {
|
||||||
|
this.gson = new GsonBuilder().setPrettyPrinting().enableComplexMapKeySerialization().create();
|
||||||
|
this.container = container;
|
||||||
|
checkContainer();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkContainer() {
|
||||||
|
this.container.getParentFile().mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveToFile(SimplePersistedSubject subject) throws IOException {
|
||||||
|
checkContainer();
|
||||||
|
File collection = new File(container, subject.getContainingCollection().getIdentifier());
|
||||||
|
if (!collection.exists()) {
|
||||||
|
collection.mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
File subjectFile = new File(collection, subject.getIdentifier().toLowerCase() + ".json");
|
||||||
|
saveToFile(subject, subjectFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveToFile(SimplePersistedSubject subject, File file) throws IOException {
|
||||||
|
file.getParentFile().mkdirs();
|
||||||
|
if (file.exists()) {
|
||||||
|
file.delete();
|
||||||
|
}
|
||||||
|
file.createNewFile();
|
||||||
|
|
||||||
|
Files.write(saveToString(new SimpleSubjectDataHolder(subject.getSubjectData())), file, Charset.defaultCharset());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String saveToString(SimpleSubjectDataHolder subject) {
|
||||||
|
return gson.toJson(subject);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, SimpleSubjectDataHolder> loadAllFromFile(String collectionName) {
|
||||||
|
checkContainer();
|
||||||
|
File collection = new File(container, collectionName);
|
||||||
|
if (!collection.exists()) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] fileNames = collection.list((dir, name) -> name.endsWith(".json"));
|
||||||
|
if (fileNames == null) return Collections.emptyMap();
|
||||||
|
|
||||||
|
Map<String, SimpleSubjectDataHolder> holders = new HashMap<>();
|
||||||
|
for (String name : fileNames) {
|
||||||
|
File subject = new File(collection, name);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Map.Entry<String, SimpleSubjectDataHolder> s = loadFromFile(subject);
|
||||||
|
if (s != null) {
|
||||||
|
holders.put(s.getKey(), s.getValue());
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return holders;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map.Entry<String, SimpleSubjectDataHolder> loadFromFile(String collectionName, String subjectName) throws IOException {
|
||||||
|
checkContainer();
|
||||||
|
File collection = new File(container, collectionName);
|
||||||
|
if (!collection.exists()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
File subject = new File(collection, subjectName.toLowerCase() + ".json");
|
||||||
|
return new AbstractMap.SimpleEntry<>(subjectName.toLowerCase(), loadFromFile(subject).getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map.Entry<String, SimpleSubjectDataHolder> loadFromFile(File file) throws IOException {
|
||||||
|
if (!file.exists()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String s = Files.toString(file, Charset.defaultCharset());
|
||||||
|
return new AbstractMap.SimpleEntry<>(file.getName().substring(file.getName().length() - 5).toLowerCase(), loadFromString(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleSubjectDataHolder loadFromString(String s) {
|
||||||
|
return gson.fromJson(s, SimpleSubjectDataHolder.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user