diff --git a/sponge/src/main/java/me/lucko/luckperms/api/sponge/LuckPermsService.java b/sponge/src/main/java/me/lucko/luckperms/api/sponge/LuckPermsService.java index a0a65f34..5bb957db 100644 --- a/sponge/src/main/java/me/lucko/luckperms/api/sponge/LuckPermsService.java +++ b/sponge/src/main/java/me/lucko/luckperms/api/sponge/LuckPermsService.java @@ -29,6 +29,8 @@ import me.lucko.luckperms.LPSpongePlugin; import me.lucko.luckperms.api.sponge.collections.GroupCollection; import me.lucko.luckperms.api.sponge.collections.UserCollection; 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 org.spongepowered.api.plugin.PluginContainer; 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.util.Tristate; +import java.io.File; import java.util.*; import java.util.concurrent.ConcurrentHashMap; +/** + * The LuckPerms implementation of the Sponge Permission Service + */ public class LuckPermsService implements PermissionService { public static final String SERVER_CONTEXT = "server"; @Getter private final LPSpongePlugin plugin; + @Getter + private final SubjectStorage storage; + @Getter private final UserCollection userSubjects; @Getter private final GroupCollection groupSubjects; + @Getter + private final SimplePersistedCollection defaultSubjects; + @Getter private final Set descriptionSet; @@ -59,12 +71,17 @@ public class LuckPermsService implements PermissionService { public LuckPermsService(LPSpongePlugin plugin) { this.plugin = plugin; + storage = new SubjectStorage(new File(plugin.getDataFolder(), "local")); + userSubjects = new UserCollection(this, plugin.getUserManager()); groupSubjects = new GroupCollection(this, plugin.getGroupManager()); + defaultSubjects = new SimplePersistedCollection(this, "defaults"); + defaultSubjects.loadAll(); subjects = new ConcurrentHashMap<>(); subjects.put(PermissionService.SUBJECTS_USER, userSubjects); subjects.put(PermissionService.SUBJECTS_GROUP, groupSubjects); + subjects.put("defaults", defaultSubjects); descriptionSet = ConcurrentHashMap.newKeySet(); } @@ -75,7 +92,7 @@ public class LuckPermsService implements PermissionService { @Override public Subject getDefaults() { - return getSubjects("defaults").get("default"); + return getDefaultSubjects().get("default"); } @Override diff --git a/sponge/src/main/java/me/lucko/luckperms/api/sponge/collections/GroupCollection.java b/sponge/src/main/java/me/lucko/luckperms/api/sponge/collections/GroupCollection.java index 2156e3ee..ac50d00c 100644 --- a/sponge/src/main/java/me/lucko/luckperms/api/sponge/collections/GroupCollection.java +++ b/sponge/src/main/java/me/lucko/luckperms/api/sponge/collections/GroupCollection.java @@ -89,6 +89,6 @@ public class GroupCollection implements SubjectCollection { @Override public Subject getDefaults() { - return service.getDefaults(); + return service.getDefaultSubjects().get(getIdentifier()); } } diff --git a/sponge/src/main/java/me/lucko/luckperms/api/sponge/collections/UserCollection.java b/sponge/src/main/java/me/lucko/luckperms/api/sponge/collections/UserCollection.java index 99d3b2c4..8d6336c9 100644 --- a/sponge/src/main/java/me/lucko/luckperms/api/sponge/collections/UserCollection.java +++ b/sponge/src/main/java/me/lucko/luckperms/api/sponge/collections/UserCollection.java @@ -161,6 +161,6 @@ public class UserCollection implements SubjectCollection { @Override public Subject getDefaults() { - return service.getDefaults(); + return service.getDefaultSubjects().get(getIdentifier()); } } diff --git a/sponge/src/main/java/me/lucko/luckperms/api/sponge/simple/SimpleCollection.java b/sponge/src/main/java/me/lucko/luckperms/api/sponge/simple/SimpleCollection.java index ec8549aa..94c4072b 100644 --- a/sponge/src/main/java/me/lucko/luckperms/api/sponge/simple/SimpleCollection.java +++ b/sponge/src/main/java/me/lucko/luckperms/api/sponge/simple/SimpleCollection.java @@ -25,8 +25,8 @@ package me.lucko.luckperms.api.sponge.simple; 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.PermissionService; import org.spongepowered.api.service.permission.Subject; import org.spongepowered.api.service.permission.SubjectCollection; import org.spongepowered.api.util.Tristate; @@ -37,9 +37,12 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +/** + * Super simple SubjectCollection implementation + */ @RequiredArgsConstructor public class SimpleCollection implements SubjectCollection { - private final PermissionService service; + private final LuckPermsService service; @Getter private final String identifier; @@ -85,6 +88,6 @@ public class SimpleCollection implements SubjectCollection { @Override public Subject getDefaults() { - return new SimpleSubject("default", service, this); + return service.getDefaultSubjects().get(identifier); } } diff --git a/sponge/src/main/java/me/lucko/luckperms/api/sponge/simple/SimpleSubject.java b/sponge/src/main/java/me/lucko/luckperms/api/sponge/simple/SimpleSubject.java index e4c4fdc2..c2b59a31 100644 --- a/sponge/src/main/java/me/lucko/luckperms/api/sponge/simple/SimpleSubject.java +++ b/sponge/src/main/java/me/lucko/luckperms/api/sponge/simple/SimpleSubject.java @@ -66,11 +66,6 @@ public class SimpleSubject implements Subject { return getPermissionValue(contexts, node).asBoolean(); } - @Override - public boolean hasPermission(@NonNull String permission) { - return hasPermission(getActiveContexts(), permission); - } - @Override public Tristate getPermissionValue(@NonNull Set contexts, @NonNull String node) { Tristate res = subjectData.getNodeTree(contexts).get(node); @@ -86,21 +81,11 @@ public class SimpleSubject implements Subject { return res; } - @Override - public boolean isChildOf(@NonNull Subject parent) { - return isChildOf(getActiveContexts(), parent); - } - @Override public boolean isChildOf(@NonNull Set contexts, @NonNull Subject subject) { return subjectData.getParents(contexts).contains(subject); } - @Override - public List getParents() { - return getParents(getActiveContexts()); - } - @Override public List getParents(@NonNull Set contexts) { return subjectData.getParents(contexts); @@ -121,11 +106,6 @@ public class SimpleSubject implements Subject { return res; } - @Override - public Optional getOption(String key) { - return getOption(getActiveContexts(), key); - } - @Override public Set getActiveContexts() { return SubjectData.GLOBAL_CONTEXT; diff --git a/sponge/src/main/java/me/lucko/luckperms/api/sponge/simple/persisted/SimplePersistedCollection.java b/sponge/src/main/java/me/lucko/luckperms/api/sponge/simple/persisted/SimplePersistedCollection.java new file mode 100644 index 00000000..00faeb38 --- /dev/null +++ b/sponge/src/main/java/me/lucko/luckperms/api/sponge/simple/persisted/SimplePersistedCollection.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * 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 subjects = new ConcurrentHashMap<>(); + + public void loadAll() { + Map holders = service.getStorage().loadAllFromFile(identifier); + for (Map.Entry 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 getAllSubjects() { + return subjects.values().stream().map(s -> (Subject) s).collect(Collectors.toList()); + } + + @Override + public Map getAllWithPermission(@NonNull String id) { + return getAllWithPermission(Collections.emptySet(), id); + } + + @Override + public Map getAllWithPermission(@NonNull Set contexts, @NonNull String node) { + Map 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); + } +} diff --git a/sponge/src/main/java/me/lucko/luckperms/api/sponge/simple/persisted/SimplePersistedSubject.java b/sponge/src/main/java/me/lucko/luckperms/api/sponge/simple/persisted/SimplePersistedSubject.java new file mode 100644 index 00000000..52635033 --- /dev/null +++ b/sponge/src/main/java/me/lucko/luckperms/api/sponge/simple/persisted/SimplePersistedSubject.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * 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 getCommandSource() { + return Optional.empty(); + } + + @Override + public boolean hasPermission(@NonNull Set contexts, @NonNull String node) { + return getPermissionValue(contexts, node).asBoolean(); + } + + @Override + public Tristate getPermissionValue(@NonNull Set 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 contexts, @NonNull Subject subject) { + return subjectData.getParents(contexts).contains(subject) || transientSubjectData.getParents(contexts).contains(subject); + } + + @Override + public List getParents(@NonNull Set contexts) { + List s = new ArrayList<>(); + s.addAll(subjectData.getParents(contexts)); + s.addAll(transientSubjectData.getParents(contexts)); + return s; + } + + @Override + public Optional getOption(Set set, String key) { + Optional 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 tempRes = parent.getOption(getActiveContexts(), key); + if (tempRes.isPresent()) { + res = tempRes; + break; + } + } + } + return res; + } + + @Override + public Set getActiveContexts() { + return SubjectData.GLOBAL_CONTEXT; + } +} diff --git a/sponge/src/main/java/me/lucko/luckperms/api/sponge/simple/persisted/SimplePersistedSubjectData.java b/sponge/src/main/java/me/lucko/luckperms/api/sponge/simple/persisted/SimplePersistedSubjectData.java new file mode 100644 index 00000000..681c7078 --- /dev/null +++ b/sponge/src/main/java/me/lucko/luckperms/api/sponge/simple/persisted/SimplePersistedSubjectData.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * 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 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) { + boolean r = super.clearPermissions(context); + save(); + return r; + } + + @Override + public boolean addParent(Set contexts, Subject parent) { + boolean r = super.addParent(contexts, parent); + save(); + return r; + } + + @Override + public boolean removeParent(Set 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 contexts) { + boolean r = super.clearParents(contexts); + save(); + return r; + } + + @Override + public boolean setOption(Set contexts, String key, @Nullable String value) { + boolean r = super.setOption(contexts, key, value); + save(); + return r; + } + + @Override + public boolean clearOptions(Set contexts) { + boolean r = super.clearOptions(contexts); + save(); + return r; + } + + @Override + public boolean clearOptions() { + boolean r = super.clearOptions(); + save(); + return r; + } +} diff --git a/sponge/src/main/java/me/lucko/luckperms/api/sponge/simple/persisted/SimpleSubjectDataHolder.java b/sponge/src/main/java/me/lucko/luckperms/api/sponge/simple/persisted/SimpleSubjectDataHolder.java new file mode 100644 index 00000000..34dd7783 --- /dev/null +++ b/sponge/src/main/java/me/lucko/luckperms/api/sponge/simple/persisted/SimpleSubjectDataHolder.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * 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> permissions; + private final Map, Map> options; + private final Map, List>> parents; + + public SimpleSubjectDataHolder(Map, Map> options, Map, Map> permissions, Map, List>> parents) { + this.options = new HashMap<>(); + for (Map.Entry, Map> e : options.entrySet()) { + this.options.put(convertContexts(e.getKey()), new HashMap<>(e.getValue())); + } + + this.permissions = new HashMap<>(); + for (Map.Entry, Map> e : permissions.entrySet()) { + this.permissions.put(convertContexts(e.getKey()), new HashMap<>(e.getValue())); + } + + this.parents = new HashMap<>(); + for (Map.Entry, List>> 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> e : permissions.entrySet()) { + for (Map.Entry perm : e.getValue().entrySet()) { + subjectData.setPermission(convertContexts(e.getKey()), perm.getKey(), Tristate.fromBoolean(perm.getValue())); + } + } + + for (Map.Entry, Map> e : options.entrySet()) { + for (Map.Entry option : e.getValue().entrySet()) { + subjectData.setOption(convertContexts(e.getKey()), option.getKey(), option.getValue()); + } + } + + for (Map.Entry, List>> e : parents.entrySet()) { + for (Map.Entry parent : e.getValue()) { + subjectData.addParent(convertContexts(e.getKey()), service.getSubjects(parent.getKey()).get(parent.getValue())); + } + } + } + + public static Map convertContexts(Set contexts) { + return contexts.stream().collect(Collectors.toMap(Context::getKey, Context::getValue)); + } + + public static Set convertContexts(Map contexts) { + return contexts.entrySet().stream().map(e -> new Context(e.getKey(), e.getValue())).collect(Collectors.toSet()); + } +} diff --git a/sponge/src/main/java/me/lucko/luckperms/api/sponge/simple/persisted/SubjectStorage.java b/sponge/src/main/java/me/lucko/luckperms/api/sponge/simple/persisted/SubjectStorage.java new file mode 100644 index 00000000..5df97833 --- /dev/null +++ b/sponge/src/main/java/me/lucko/luckperms/api/sponge/simple/persisted/SubjectStorage.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * 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 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 holders = new HashMap<>(); + for (String name : fileNames) { + File subject = new File(collection, name); + + try { + Map.Entry s = loadFromFile(subject); + if (s != null) { + holders.put(s.getKey(), s.getValue()); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + return holders; + } + + public Map.Entry 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 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); + } + +}