mirror of
https://github.com/LuckPerms/LuckPerms.git
synced 2024-11-24 11:38:40 +01:00
Implement nicer json format for Sponge local data
This commit is contained in:
parent
85c7a7db8d
commit
073b775566
@ -25,6 +25,7 @@ package me.lucko.luckperms.api.context;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSetMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Multimaps;
|
||||
import com.google.common.collect.SetMultimap;
|
||||
@ -179,7 +180,7 @@ public final class MutableContextSet implements ContextSet {
|
||||
|
||||
@Override
|
||||
public Multimap<String, String> toMultimap() {
|
||||
return map;
|
||||
return ImmutableSetMultimap.copyOf(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -30,6 +30,7 @@ import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
|
||||
import me.lucko.luckperms.api.HeldPermission;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
@ -547,11 +548,11 @@ public class JSONBacking extends FlatfileBacking {
|
||||
int size = vals.size();
|
||||
|
||||
if (size == 1) {
|
||||
context.addProperty(e.getKey(), vals.get(0));;
|
||||
context.addProperty(e.getKey(), vals.get(0));
|
||||
} else if (size > 1) {
|
||||
JsonArray arr = new JsonArray();
|
||||
for (String s : vals) {
|
||||
arr.add(s);
|
||||
arr.add(new JsonPrimitive(s));
|
||||
}
|
||||
context.add(e.getKey(), arr);
|
||||
}
|
||||
|
@ -57,12 +57,13 @@ import me.lucko.luckperms.sponge.model.SpongeGroup;
|
||||
import me.lucko.luckperms.sponge.service.calculated.CalculatedSubjectData;
|
||||
import me.lucko.luckperms.sponge.service.calculated.OptionLookup;
|
||||
import me.lucko.luckperms.sponge.service.calculated.PermissionLookup;
|
||||
import me.lucko.luckperms.sponge.service.legacystorage.LegacyDataMigrator;
|
||||
import me.lucko.luckperms.sponge.service.persisted.PersistedCollection;
|
||||
import me.lucko.luckperms.sponge.service.persisted.SubjectStorage;
|
||||
import me.lucko.luckperms.sponge.service.proxy.LPSubject;
|
||||
import me.lucko.luckperms.sponge.service.proxy.LPSubjectCollection;
|
||||
import me.lucko.luckperms.sponge.service.proxy.LPSubjectData;
|
||||
import me.lucko.luckperms.sponge.service.references.SubjectReference;
|
||||
import me.lucko.luckperms.sponge.service.storage.SubjectStorage;
|
||||
import me.lucko.luckperms.sponge.timings.LPTiming;
|
||||
|
||||
import org.spongepowered.api.plugin.PluginContainer;
|
||||
@ -129,7 +130,8 @@ public class LuckPermsService implements PermissionService {
|
||||
localOptionCaches = Collections.newSetFromMap(new MapMaker().weakKeys().makeMap());
|
||||
localDataCaches = Collections.newSetFromMap(new MapMaker().weakKeys().makeMap());
|
||||
|
||||
storage = new SubjectStorage(new File(plugin.getDataDirectory(), "local"));
|
||||
storage = new SubjectStorage(new File(plugin.getDataDirectory(), "sponge-data"));
|
||||
new LegacyDataMigrator(plugin, new File(plugin.getDataDirectory(), "local"), storage).run();
|
||||
|
||||
userSubjects = plugin.getUserManager();
|
||||
fallbackUserSubjects = new PersistedCollection(this, "fallback-users", true);
|
||||
|
@ -47,6 +47,7 @@ import me.lucko.luckperms.sponge.service.references.SubjectReference;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
@ -133,29 +134,29 @@ public class CalculatedSubjectData implements LPSubjectData {
|
||||
return permissionCache.getUnchecked(contexts).getCalculator().getPermissionValue(permission);
|
||||
}
|
||||
|
||||
public void replacePermissions(Map<ContextSet, Map<String, Boolean>> map) {
|
||||
public void replacePermissions(Map<ImmutableContextSet, Map<String, Boolean>> map) {
|
||||
permissions.clear();
|
||||
for (Map.Entry<ContextSet, Map<String, Boolean>> e : map.entrySet()) {
|
||||
permissions.put(e.getKey().makeImmutable(), new ConcurrentHashMap<>(e.getValue()));
|
||||
for (Map.Entry<ImmutableContextSet, Map<String, Boolean>> e : map.entrySet()) {
|
||||
permissions.put(e.getKey(), new ConcurrentHashMap<>(e.getValue()));
|
||||
}
|
||||
permissionCache.invalidateAll();
|
||||
service.invalidatePermissionCaches();
|
||||
}
|
||||
|
||||
public void replaceParents(Map<ContextSet, Set<SubjectReference>> map) {
|
||||
public void replaceParents(Map<ImmutableContextSet, List<SubjectReference>> map) {
|
||||
parents.clear();
|
||||
for (Map.Entry<ContextSet, Set<SubjectReference>> e : map.entrySet()) {
|
||||
for (Map.Entry<ImmutableContextSet, List<SubjectReference>> e : map.entrySet()) {
|
||||
Set<SubjectReference> set = ConcurrentHashMap.newKeySet();
|
||||
set.addAll(e.getValue());
|
||||
parents.put(e.getKey().makeImmutable(), set);
|
||||
parents.put(e.getKey(), set);
|
||||
}
|
||||
service.invalidateParentCaches();
|
||||
}
|
||||
|
||||
public void replaceOptions(Map<ContextSet, Map<String, String>> map) {
|
||||
public void replaceOptions(Map<ImmutableContextSet, Map<String, String>> map) {
|
||||
options.clear();
|
||||
for (Map.Entry<ContextSet, Map<String, String>> e : map.entrySet()) {
|
||||
options.put(e.getKey().makeImmutable(), new ConcurrentHashMap<>(e.getValue()));
|
||||
for (Map.Entry<ImmutableContextSet, Map<String, String>> e : map.entrySet()) {
|
||||
options.put(e.getKey(), new ConcurrentHashMap<>(e.getValue()));
|
||||
}
|
||||
service.invalidateOptionCaches();
|
||||
}
|
||||
@ -228,6 +229,14 @@ public class CalculatedSubjectData implements LPSubjectData {
|
||||
return map.build();
|
||||
}
|
||||
|
||||
public Map<ImmutableContextSet, List<SubjectReference>> getParentsAsList() {
|
||||
ImmutableMap.Builder<ImmutableContextSet, List<SubjectReference>> map = ImmutableMap.builder();
|
||||
for (Map.Entry<ContextSet, Set<SubjectReference>> e : parents.entrySet()) {
|
||||
map.put(e.getKey().makeImmutable(), ImmutableList.copyOf(e.getValue()));
|
||||
}
|
||||
return map.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SubjectReference> getParents(ContextSet contexts) {
|
||||
return ImmutableSet.copyOf(parents.getOrDefault(contexts, ImmutableSet.of()));
|
||||
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.sponge.service.legacystorage;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
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")
|
||||
@RequiredArgsConstructor
|
||||
public class LegacyDataMigrator implements Runnable {
|
||||
private final LuckPermsPlugin plugin;
|
||||
|
||||
private final File oldDirectory;
|
||||
private final SubjectStorage storage;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!oldDirectory.exists() || !oldDirectory.isDirectory()) {
|
||||
return;
|
||||
}
|
||||
|
||||
plugin.getLog().warn("Migrating old sponge data... Please wait.");
|
||||
|
||||
File[] collections = 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 = storage.getGson().fromJson(reader, SubjectDataHolder.class);
|
||||
storage.saveToFile(holder.asSubjectModel(), storage.resolveFile(collectionDir.getName(), subjectName));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
subjectFile.delete();
|
||||
}
|
||||
|
||||
collectionDir.delete();
|
||||
}
|
||||
|
||||
oldDirectory.delete();
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.sponge.service.legacystorage;
|
||||
|
||||
import lombok.ToString;
|
||||
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
import me.lucko.luckperms.sponge.service.references.SubjectReference;
|
||||
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
|
||||
*/
|
||||
@ToString
|
||||
@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() {
|
||||
return new SubjectStorageModel(
|
||||
permissions.entrySet().stream()
|
||||
.collect(Collectors.toMap(
|
||||
k -> ContextSet.fromMap(k.getKey()),
|
||||
Map.Entry::getValue
|
||||
)),
|
||||
options.entrySet().stream()
|
||||
.collect(Collectors.toMap(
|
||||
k -> ContextSet.fromMap(k.getKey()),
|
||||
Map.Entry::getValue
|
||||
)),
|
||||
parents.entrySet().stream()
|
||||
.collect(Collectors.toMap(
|
||||
k -> ContextSet.fromMap(k.getKey()),
|
||||
v -> v.getValue().stream().map(SubjectReference::deserialize).collect(Collectors.toList())
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
@ -39,6 +39,7 @@ import me.lucko.luckperms.sponge.service.LuckPermsService;
|
||||
import me.lucko.luckperms.sponge.service.proxy.LPSubject;
|
||||
import me.lucko.luckperms.sponge.service.proxy.LPSubjectCollection;
|
||||
import me.lucko.luckperms.sponge.service.references.SubjectReference;
|
||||
import me.lucko.luckperms.sponge.service.storage.SubjectStorageModel;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
@ -63,8 +64,8 @@ public class PersistedCollection implements LPSubjectCollection {
|
||||
});
|
||||
|
||||
public void loadAll() {
|
||||
Map<String, SubjectDataHolder> holders = service.getStorage().loadAllFromFile(identifier);
|
||||
for (Map.Entry<String, SubjectDataHolder> e : holders.entrySet()) {
|
||||
Map<String, SubjectStorageModel> holders = service.getStorage().loadAllFromFile(identifier);
|
||||
for (Map.Entry<String, SubjectStorageModel> e : holders.entrySet()) {
|
||||
PersistedSubject subject = get(e.getKey());
|
||||
subject.loadData(e.getValue());
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ import me.lucko.luckperms.sponge.service.calculated.PermissionLookup;
|
||||
import me.lucko.luckperms.sponge.service.proxy.LPSubject;
|
||||
import me.lucko.luckperms.sponge.service.references.SubjectCollectionReference;
|
||||
import me.lucko.luckperms.sponge.service.references.SubjectReference;
|
||||
import me.lucko.luckperms.sponge.service.storage.SubjectStorageModel;
|
||||
import me.lucko.luckperms.sponge.timings.LPTiming;
|
||||
|
||||
import org.spongepowered.api.command.CommandSource;
|
||||
@ -130,9 +131,9 @@ public class PersistedSubject implements LPSubject {
|
||||
this.optionLookupCache.cleanUp();
|
||||
}
|
||||
|
||||
public void loadData(SubjectDataHolder dataHolder) {
|
||||
public void loadData(SubjectStorageModel dataHolder) {
|
||||
subjectData.setSave(false);
|
||||
dataHolder.copyTo(subjectData);
|
||||
dataHolder.applyToData(subjectData);
|
||||
subjectData.setSave(true);
|
||||
}
|
||||
|
||||
|
@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.sponge.service.persisted;
|
||||
|
||||
import lombok.ToString;
|
||||
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
import me.lucko.luckperms.api.context.ImmutableContextSet;
|
||||
import me.lucko.luckperms.sponge.service.calculated.CalculatedSubjectData;
|
||||
import me.lucko.luckperms.sponge.service.references.SubjectReference;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Holds SubjectData in a "gson friendly" format for serialization
|
||||
*/
|
||||
@ToString
|
||||
public class SubjectDataHolder {
|
||||
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<String>> parents;
|
||||
|
||||
public SubjectDataHolder(Map<ImmutableContextSet, Map<String, String>> options, Map<ImmutableContextSet, Map<String, Boolean>> permissions, Map<ImmutableContextSet, Set<SubjectReference>> parents) {
|
||||
this.options = new HashMap<>();
|
||||
for (Map.Entry<ImmutableContextSet, Map<String, String>> e : options.entrySet()) {
|
||||
if (!e.getValue().isEmpty()) {
|
||||
this.options.put(e.getKey().toMap(), new HashMap<>(e.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
this.permissions = new HashMap<>();
|
||||
for (Map.Entry<ImmutableContextSet, Map<String, Boolean>> e : permissions.entrySet()) {
|
||||
if (!e.getValue().isEmpty()) {
|
||||
this.permissions.put(e.getKey().toMap(), new HashMap<>(e.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
this.parents = new HashMap<>();
|
||||
for (Map.Entry<ImmutableContextSet, Set<SubjectReference>> e : parents.entrySet()) {
|
||||
if (!e.getValue().isEmpty()) {
|
||||
this.parents.put(e.getKey().toMap(), e.getValue().stream().map(SubjectReference::serialize).collect(Collectors.toList()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SubjectDataHolder(CalculatedSubjectData data) {
|
||||
this(data.getOptions(), data.getPermissions(), data.getParents());
|
||||
}
|
||||
|
||||
public void copyTo(CalculatedSubjectData subjectData) {
|
||||
subjectData.replacePermissions(permissions.entrySet().stream()
|
||||
.collect(Collectors.toMap(
|
||||
k -> ContextSet.fromMap(k.getKey()),
|
||||
Map.Entry::getValue
|
||||
))
|
||||
);
|
||||
|
||||
subjectData.replaceOptions(options.entrySet().stream()
|
||||
.collect(Collectors.toMap(
|
||||
k -> ContextSet.fromMap(k.getKey()),
|
||||
Map.Entry::getValue
|
||||
))
|
||||
);
|
||||
|
||||
subjectData.replaceParents(parents.entrySet().stream()
|
||||
.collect(Collectors.toMap(
|
||||
k -> ContextSet.fromMap(k.getKey()),
|
||||
v -> v.getValue().stream().map(SubjectReference::deserialize).collect(Collectors.toSet())
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
@ -20,17 +20,24 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.sponge.service.persisted;
|
||||
package me.lucko.luckperms.sponge.service.storage;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.io.Files;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import me.lucko.luckperms.sponge.service.persisted.PersistedSubject;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.AbstractMap;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@ -41,11 +48,14 @@ import java.util.stream.Collectors;
|
||||
* Handles persisted Subject I/O and (de)serialization
|
||||
*/
|
||||
public class SubjectStorage {
|
||||
|
||||
@Getter
|
||||
private final Gson gson;
|
||||
|
||||
private final File container;
|
||||
|
||||
public SubjectStorage(File container) {
|
||||
this.gson = new GsonBuilder().setPrettyPrinting().enableComplexMapKeySerialization().create();
|
||||
this.gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
this.container = container;
|
||||
checkContainer();
|
||||
}
|
||||
@ -65,32 +75,35 @@ public class SubjectStorage {
|
||||
return ImmutableSet.copyOf(dirs).stream().map(File::getName).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public void saveToFile(PersistedSubject subject) throws IOException {
|
||||
public File resolveFile(String collectionName, String subjectName) {
|
||||
checkContainer();
|
||||
File collection = new File(container, subject.getContainingCollection().getIdentifier());
|
||||
File collection = new File(container, collectionName);
|
||||
if (!collection.exists()) {
|
||||
collection.mkdirs();
|
||||
}
|
||||
|
||||
File subjectFile = new File(collection, subject.getIdentifier() + ".json");
|
||||
saveToFile(subject, subjectFile);
|
||||
return new File(collection, subjectName + ".json");
|
||||
}
|
||||
|
||||
public void saveToFile(PersistedSubject subject, File file) throws IOException {
|
||||
public void saveToFile(PersistedSubject subject) throws IOException {
|
||||
File subjectFile = resolveFile(subject.getContainingCollection().getIdentifier(), subject.getIdentifier());
|
||||
saveToFile(new SubjectStorageModel(subject.getSubjectData()), subjectFile);
|
||||
}
|
||||
|
||||
public void saveToFile(SubjectStorageModel model, File file) throws IOException {
|
||||
file.getParentFile().mkdirs();
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
}
|
||||
file.createNewFile();
|
||||
|
||||
Files.write(saveToString(new SubjectDataHolder(subject.getSubjectData())), file, Charset.defaultCharset());
|
||||
try (BufferedWriter writer = Files.newBufferedWriter(file.toPath(), StandardCharsets.UTF_8)) {
|
||||
gson.toJson(model.toJson(), writer);
|
||||
writer.flush();
|
||||
}
|
||||
}
|
||||
|
||||
public String saveToString(SubjectDataHolder subject) {
|
||||
return gson.toJson(subject);
|
||||
}
|
||||
|
||||
public Map<String, SubjectDataHolder> loadAllFromFile(String collectionName) {
|
||||
public Map<String, SubjectStorageModel> loadAllFromFile(String collectionName) {
|
||||
checkContainer();
|
||||
File collection = new File(container, collectionName);
|
||||
if (!collection.exists()) {
|
||||
@ -100,12 +113,12 @@ public class SubjectStorage {
|
||||
String[] fileNames = collection.list((dir, name) -> name.endsWith(".json"));
|
||||
if (fileNames == null) return Collections.emptyMap();
|
||||
|
||||
Map<String, SubjectDataHolder> holders = new HashMap<>();
|
||||
Map<String, SubjectStorageModel> holders = new HashMap<>();
|
||||
for (String name : fileNames) {
|
||||
File subject = new File(collection, name);
|
||||
|
||||
try {
|
||||
Map.Entry<String, SubjectDataHolder> s = loadFromFile(subject);
|
||||
Map.Entry<String, SubjectStorageModel> s = loadFromFile(subject);
|
||||
if (s != null) {
|
||||
holders.put(s.getKey(), s.getValue());
|
||||
}
|
||||
@ -117,7 +130,7 @@ public class SubjectStorage {
|
||||
return holders;
|
||||
}
|
||||
|
||||
public Map.Entry<String, SubjectDataHolder> loadFromFile(String collectionName, String subjectName) throws IOException {
|
||||
public Map.Entry<String, SubjectStorageModel> loadFromFile(String collectionName, String subjectName) throws IOException {
|
||||
checkContainer();
|
||||
File collection = new File(container, collectionName);
|
||||
if (!collection.exists()) {
|
||||
@ -125,20 +138,21 @@ public class SubjectStorage {
|
||||
}
|
||||
|
||||
File subject = new File(collection, subjectName + ".json");
|
||||
return new AbstractMap.SimpleEntry<>(subjectName, loadFromFile(subject).getValue());
|
||||
return Maps.immutableEntry(subjectName, loadFromFile(subject).getValue());
|
||||
}
|
||||
|
||||
public Map.Entry<String, SubjectDataHolder> loadFromFile(File file) throws IOException {
|
||||
public Map.Entry<String, SubjectStorageModel> loadFromFile(File file) throws IOException {
|
||||
if (!file.exists()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String s = Files.toString(file, Charset.defaultCharset());
|
||||
return new AbstractMap.SimpleEntry<>(file.getName().substring(0, file.getName().length() - 5), loadFromString(s));
|
||||
}
|
||||
String subjectName = file.getName().substring(0, file.getName().length() - ".json".length());
|
||||
|
||||
public SubjectDataHolder loadFromString(String s) {
|
||||
return gson.fromJson(s, SubjectDataHolder.class);
|
||||
try (BufferedReader reader = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8)) {
|
||||
JsonObject data = gson.fromJson(reader, JsonObject.class);
|
||||
SubjectStorageModel model = new SubjectStorageModel(data);
|
||||
return Maps.immutableEntry(subjectName, model);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,274 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.sponge.service.storage;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
import me.lucko.luckperms.api.context.ImmutableContextSet;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.sponge.service.calculated.CalculatedSubjectData;
|
||||
import me.lucko.luckperms.sponge.service.references.SubjectReference;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Used for converting a SubjectData instance to and from JSON
|
||||
*/
|
||||
@Getter
|
||||
public class SubjectStorageModel {
|
||||
private final Map<ImmutableContextSet, Map<String, Boolean>> permissions;
|
||||
private final Map<ImmutableContextSet, Map<String, String>> options;
|
||||
private final Map<ImmutableContextSet, List<SubjectReference>> parents;
|
||||
|
||||
public SubjectStorageModel(Map<ImmutableContextSet, Map<String, Boolean>> permissions, Map<ImmutableContextSet, Map<String, String>> options, Map<ImmutableContextSet, List<SubjectReference>> parents) {
|
||||
ImmutableMap.Builder<ImmutableContextSet, Map<String, Boolean>> permissionsBuilder = ImmutableMap.builder();
|
||||
for (Map.Entry<ImmutableContextSet, Map<String, Boolean>> e : permissions.entrySet()) {
|
||||
permissionsBuilder.put(e.getKey(), ImmutableMap.copyOf(e.getValue()));
|
||||
}
|
||||
this.permissions = permissionsBuilder.build();
|
||||
|
||||
ImmutableMap.Builder<ImmutableContextSet, Map<String, String>> optionsBuilder = ImmutableMap.builder();
|
||||
for (Map.Entry<ImmutableContextSet, Map<String, String>> e : options.entrySet()) {
|
||||
optionsBuilder.put(e.getKey(), ImmutableMap.copyOf(e.getValue()));
|
||||
}
|
||||
this.options = optionsBuilder.build();
|
||||
|
||||
ImmutableMap.Builder<ImmutableContextSet, List<SubjectReference>> parentsBuilder = ImmutableMap.builder();
|
||||
for (Map.Entry<ImmutableContextSet, List<SubjectReference>> e : parents.entrySet()) {
|
||||
parentsBuilder.put(e.getKey(), ImmutableList.copyOf(e.getValue()));
|
||||
}
|
||||
this.parents = parentsBuilder.build();
|
||||
}
|
||||
|
||||
public SubjectStorageModel(CalculatedSubjectData data) {
|
||||
this(data.getPermissions(), data.getOptions(), data.getParentsAsList());
|
||||
}
|
||||
|
||||
public SubjectStorageModel(JsonObject root) {
|
||||
Preconditions.checkArgument(root.get("permissions").isJsonArray());
|
||||
Preconditions.checkArgument(root.get("options").isJsonArray());
|
||||
Preconditions.checkArgument(root.get("parents").isJsonArray());
|
||||
|
||||
JsonArray permissions = root.get("permissions").getAsJsonArray();
|
||||
JsonArray options = root.get("options").getAsJsonArray();
|
||||
JsonArray parents = root.get("parents").getAsJsonArray();
|
||||
|
||||
ImmutableMap.Builder<ImmutableContextSet, Map<String, Boolean>> permissionsBuilder = ImmutableMap.builder();
|
||||
for (JsonElement e : permissions) {
|
||||
if (!e.isJsonObject()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
JsonObject section = e.getAsJsonObject();
|
||||
if (!section.get("context").isJsonObject()) continue;
|
||||
if (!section.get("data").isJsonObject()) continue;
|
||||
|
||||
JsonObject context = section.get("context").getAsJsonObject();
|
||||
JsonObject data = section.get("data").getAsJsonObject();
|
||||
|
||||
ImmutableContextSet contextSet = contextsFromJson(context);
|
||||
ImmutableMap.Builder<String, Boolean> perms = ImmutableMap.builder();
|
||||
for (Map.Entry<String, JsonElement> perm : data.entrySet()) {
|
||||
perms.put(perm.getKey(), perm.getValue().getAsBoolean());
|
||||
}
|
||||
|
||||
permissionsBuilder.put(contextSet, perms.build());
|
||||
}
|
||||
this.permissions = permissionsBuilder.build();
|
||||
|
||||
ImmutableMap.Builder<ImmutableContextSet, Map<String, String>> optionsBuilder = ImmutableMap.builder();
|
||||
for (JsonElement e : options) {
|
||||
if (!e.isJsonObject()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
JsonObject section = e.getAsJsonObject();
|
||||
if (!section.get("context").isJsonObject()) continue;
|
||||
if (!section.get("data").isJsonObject()) continue;
|
||||
|
||||
JsonObject context = section.get("context").getAsJsonObject();
|
||||
JsonObject data = section.get("data").getAsJsonObject();
|
||||
|
||||
ImmutableContextSet contextSet = contextsFromJson(context);
|
||||
ImmutableMap.Builder<String, String> opts = ImmutableMap.builder();
|
||||
for (Map.Entry<String, JsonElement> opt : data.entrySet()) {
|
||||
opts.put(opt.getKey(), opt.getValue().getAsString());
|
||||
}
|
||||
|
||||
optionsBuilder.put(contextSet, opts.build());
|
||||
}
|
||||
this.options = optionsBuilder.build();
|
||||
|
||||
ImmutableMap.Builder<ImmutableContextSet, List<SubjectReference>> parentsBuilder = ImmutableMap.builder();
|
||||
for (JsonElement e : parents) {
|
||||
if (!e.isJsonObject()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
JsonObject section = e.getAsJsonObject();
|
||||
if (!section.get("context").isJsonObject()) continue;
|
||||
if (!section.get("data").isJsonArray()) continue;
|
||||
|
||||
JsonObject context = section.get("context").getAsJsonObject();
|
||||
JsonArray data = section.get("data").getAsJsonArray();
|
||||
|
||||
ImmutableContextSet contextSet = contextsFromJson(context);
|
||||
ImmutableList.Builder<SubjectReference> pars = ImmutableList.builder();
|
||||
for (JsonElement p : data) {
|
||||
if (!p.isJsonObject()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
JsonObject parent = p.getAsJsonObject();
|
||||
|
||||
String collection = parent.get("collection").getAsString();
|
||||
String subject = parent.get("subject").getAsString();
|
||||
|
||||
pars.add(SubjectReference.of(collection, subject));
|
||||
}
|
||||
|
||||
parentsBuilder.put(contextSet, pars.build());
|
||||
}
|
||||
this.parents = parentsBuilder.build();
|
||||
}
|
||||
|
||||
public JsonObject toJson() {
|
||||
JsonObject root = new JsonObject();
|
||||
|
||||
JsonArray permissions = new JsonArray();
|
||||
for (Map.Entry<ImmutableContextSet, Map<String, Boolean>> e : this.permissions.entrySet()) {
|
||||
if (e.getValue().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
JsonObject section = new JsonObject();
|
||||
section.add("context", contextsToJson(e.getKey()));
|
||||
|
||||
JsonObject data = new JsonObject();
|
||||
for (Map.Entry<String, Boolean> ent : e.getValue().entrySet()) {
|
||||
data.addProperty(ent.getKey(), ent.getValue());
|
||||
}
|
||||
section.add("data", data);
|
||||
|
||||
permissions.add(section);
|
||||
}
|
||||
root.add("permissions", permissions);
|
||||
|
||||
JsonArray options = new JsonArray();
|
||||
for (Map.Entry<ImmutableContextSet, Map<String, String>> e : this.options.entrySet()) {
|
||||
if (e.getValue().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
JsonObject section = new JsonObject();
|
||||
section.add("context", contextsToJson(e.getKey()));
|
||||
|
||||
JsonObject data = new JsonObject();
|
||||
for (Map.Entry<String, String> ent : e.getValue().entrySet()) {
|
||||
data.addProperty(ent.getKey(), ent.getValue());
|
||||
}
|
||||
section.add("data", data);
|
||||
|
||||
options.add(section);
|
||||
}
|
||||
root.add("options", options);
|
||||
|
||||
JsonArray parents = new JsonArray();
|
||||
for (Map.Entry<ImmutableContextSet, List<SubjectReference>> e : this.parents.entrySet()) {
|
||||
if (e.getValue().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
JsonObject section = new JsonObject();
|
||||
section.add("context", contextsToJson(e.getKey()));
|
||||
|
||||
JsonArray data = new JsonArray();
|
||||
for (SubjectReference ref : e.getValue()) {
|
||||
JsonObject parent = new JsonObject();
|
||||
parent.addProperty("collection", ref.getCollection());
|
||||
parent.addProperty("subject", ref.getCollection());
|
||||
data.add(parent);
|
||||
}
|
||||
section.add("data", data);
|
||||
|
||||
options.add(section);
|
||||
}
|
||||
root.add("parents", parents);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
public void applyToData(CalculatedSubjectData subjectData) {
|
||||
subjectData.replacePermissions(permissions);
|
||||
subjectData.replaceOptions(options);
|
||||
subjectData.replaceParents(parents);
|
||||
}
|
||||
|
||||
private static ImmutableContextSet contextsFromJson(JsonObject contexts) {
|
||||
MutableContextSet ret = MutableContextSet.create();
|
||||
for (Map.Entry<String, JsonElement> e : contexts.entrySet()) {
|
||||
String key = e.getKey();
|
||||
|
||||
if (e.getValue().isJsonArray()) {
|
||||
JsonArray values = e.getValue().getAsJsonArray();
|
||||
for (JsonElement value : values) {
|
||||
ret.add(key, value.getAsString());
|
||||
}
|
||||
} else {
|
||||
ret.add(key, e.getValue().getAsString());
|
||||
}
|
||||
}
|
||||
return ret.makeImmutable();
|
||||
}
|
||||
|
||||
private static JsonObject contextsToJson(ContextSet contexts) {
|
||||
JsonObject ret = new JsonObject();
|
||||
for (Map.Entry<String, Collection<String>> e : contexts.toMultimap().asMap().entrySet()) {
|
||||
String key = e.getKey();
|
||||
List<String> values = new ArrayList<>(e.getValue());
|
||||
|
||||
if (values.size() == 1) {
|
||||
ret.addProperty(key, values.get(0));
|
||||
} else if (values.size() > 1) {
|
||||
JsonArray arr = new JsonArray();
|
||||
for (String s : values) {
|
||||
arr.add(new JsonPrimitive(s));
|
||||
}
|
||||
ret.add(key, arr);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user