fix: extract new config option for deleting disk history on logout (#2772)

* fix: extract new config option for deleting disk history on logout
 - fixes #2663

* Copyto is nullable
This commit is contained in:
Jordan 2024-06-26 17:32:36 +02:00 committed by GitHub
parent 06bf7104cc
commit 75af797d4c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 69 additions and 20 deletions

View File

@ -6,6 +6,7 @@ import com.sk89q.util.StringUtil;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import org.apache.logging.log4j.Logger;
import javax.annotation.Nullable;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.PrintWriter;
@ -18,6 +19,7 @@ import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@ -31,10 +33,15 @@ public class Config {
private static final Logger LOGGER = LogManagerCompat.getLogger();
private final Map<String, Object> removedKeyVals = new HashMap<>();
@Nullable
private Map<String, Map.Entry<String, Object>> copyTo = new HashMap<>();
private boolean performCopyTo = false;
private List<String> existingMigrateNodes = null;
public Config() {
save(new PrintWriter(new ByteArrayOutputStream(0)), getClass(), this, 0);
// This is now definitely required as the save -> load -> save order means the @CopiedFrom annotated fields work
save(new PrintWriter(new ByteArrayOutputStream(0)), getClass(), this, 0, null);
performCopyTo = true;
}
/**
@ -60,11 +67,12 @@ public class Config {
/**
* Set the value of a specific node. Probably throws some error if you supply non existing keys or invalid values.
* This should only be called during loading of a config file
*
* @param key config node
* @param value value
*/
private void set(String key, Object value, Class<?> root) {
private void setLoadedNode(String key, Object value, Class<?> root) {
String[] split = key.split("\\.");
Object instance = getInstance(split, root);
if (instance != null) {
@ -74,8 +82,18 @@ public class Config {
if (field.getAnnotation(Final.class) != null) {
return;
}
if (copyTo != null) {
copyTo.remove(key); // Remove if the config field is already written
final Object finalValue = value;
copyTo.replaceAll((copyToNode, entry) -> {
if (!key.equals(entry.getKey())) {
return entry;
}
return new AbstractMap.SimpleEntry<>(key, finalValue);
});
}
Migrate migrate = field.getAnnotation(Migrate.class);
if (existingMigrateNodes != null && migrate != null) {
if (migrate != null) {
existingMigrateNodes.add(migrate.value());
}
if (field.getType() == String.class && !(value instanceof String)) {
@ -90,8 +108,9 @@ public class Config {
}
}
removedKeyVals.put(key, value);
LOGGER.error(
"Failed to set config option: {}: {} | {} | {}.yml. This is likely because it was removed.",
LOGGER.warn(
"Failed to set config option: {}: {} | {} | {}.yml. This is likely because it was removed or was set with an " +
"invalid value.",
key,
value,
instance,
@ -110,7 +129,7 @@ public class Config {
if (value instanceof MemorySection) {
continue;
}
set(key, value, getClass());
setLoadedNode(key, value, getClass());
}
for (String node : existingMigrateNodes) {
removedKeyVals.remove(node);
@ -133,7 +152,7 @@ public class Config {
}
PrintWriter writer = new PrintWriter(file);
Object instance = this;
save(writer, getClass(), instance, 0);
save(writer, getClass(), instance, 0, null);
writer.close();
} catch (Throwable e) {
LOGGER.error("Failed to save config file: {}", file, e);
@ -190,7 +209,7 @@ public class Config {
}
/**
* Indicates that a field should be instantiated / created.
* Indicates that a field should be migrated from a node that is deleted
*
* @since 2.10.0
*/
@ -202,6 +221,19 @@ public class Config {
}
/**
* Indicates that a field's default value should match another input if the config is otherwise already generated
*
* @since TODO
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface CopiedFrom {
String value();
}
@Ignore // This is not part of the config
public static class ConfigBlock<T> {
@ -254,7 +286,7 @@ public class Config {
return value != null ? value.toString() : "null";
}
private void save(PrintWriter writer, Class<?> clazz, final Object instance, int indent) {
private void save(PrintWriter writer, Class<?> clazz, final Object instance, int indent, String parentNode) {
try {
String CTRF = System.lineSeparator();
String spacing = StringMan.repeat(" ", indent);
@ -274,7 +306,7 @@ public class Config {
}
if (current == ConfigBlock.class) {
current = (Class<?>) ((ParameterizedType) (field.getGenericType())).getActualTypeArguments()[0];
handleConfigBlockSave(writer, instance, indent, field, spacing, CTRF, current);
handleConfigBlockSave(writer, instance, indent, field, spacing, CTRF, current, parentNode);
continue;
} else if (!removedKeyVals.isEmpty()) {
Migrate migrate = field.getAnnotation(Migrate.class);
@ -283,6 +315,17 @@ public class Config {
field.set(instance, value);
}
}
CopiedFrom copiedFrom;
if (copyTo != null && (copiedFrom = field.getAnnotation(CopiedFrom.class)) != null) {
String node = toNodeName(field.getName());
node = parentNode == null ? node : parentNode + "." + node;
Map.Entry<String, Object> entry = copyTo.remove(node);
if (entry == null) {
copyTo.put(node,new AbstractMap.SimpleEntry<>(copiedFrom.value(), null));
} else {
field.set(instance, entry.getValue());
}
}
Create create = field.getAnnotation(Create.class);
if (create != null) {
Object value = field.get(instance);
@ -296,11 +339,12 @@ public class Config {
writer.write(spacing + "# " + commentLine + CTRF);
}
}
writer.write(spacing + toNodeName(current.getSimpleName()) + ":" + CTRF);
String node = toNodeName(current.getSimpleName());
writer.write(spacing + node + ":" + CTRF);
if (value == null) {
field.set(instance, value = current.getDeclaredConstructor().newInstance());
}
save(writer, current, value, indent + 2);
save(writer, current, value, indent + 2, parentNode == null ? node : parentNode + "." + node);
} else {
writer.write(spacing + toNodeName(field.getName() + ": ") + toYamlString(
field.get(instance),
@ -311,6 +355,10 @@ public class Config {
} catch (Throwable e) {
LOGGER.error("Failed to save config file", e);
}
if (parentNode == null && performCopyTo) {
performCopyTo = false;
copyTo = null;
}
}
private <T> void handleConfigBlockSave(
@ -320,7 +368,8 @@ public class Config {
Field field,
String spacing,
String CTRF,
Class<T> current
Class<T> current,
String parentNode
) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
Comment comment = current.getAnnotation(Comment.class);
if (comment != null) {
@ -330,6 +379,7 @@ public class Config {
}
BlockName blockNames = current.getAnnotation(BlockName.class);
if (blockNames != null) {
String node = toNodeName(current.getSimpleName());
writer.write(spacing + toNodeName(current.getSimpleName()) + ":" + CTRF);
ConfigBlock<T> configBlock = (ConfigBlock<T>) field.get(instance);
if (configBlock == null || configBlock.getInstances().isEmpty()) {
@ -343,7 +393,7 @@ public class Config {
for (Map.Entry<String, T> entry : configBlock.getRaw().entrySet()) {
String key = entry.getKey();
writer.write(spacing + " " + toNodeName(key) + ":" + CTRF);
save(writer, current, entry.getValue(), indent + 4);
save(writer, current, entry.getValue(), indent + 4, parentNode == null ? node : parentNode + "." + node);
}
}
}

View File

@ -518,6 +518,9 @@ public class Settings extends Config {
public int DELETE_AFTER_DAYS = 7;
@Comment("Delete history in memory on logout (does not effect disk)")
public boolean DELETE_ON_LOGOUT = true;
@Comment("Delete history on disk on logout")
@CopiedFrom("history.delete-on-logout")
public boolean DELETE_DISK_ON_LOGOUT = false;
@Comment({
"If history should be enabled by default for plugins using WorldEdit:",
" - It is faster to have disabled",

View File

@ -22,19 +22,15 @@ package com.sk89q.worldedit.entity;
import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.configuration.Caption;
import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.extent.clipboard.DiskOptimizedClipboard;
import com.fastasyncworldedit.core.internal.exception.FaweClipboardVersionMismatchException;
import com.fastasyncworldedit.core.regions.FaweMaskManager;
import com.fastasyncworldedit.core.util.MainUtil;
import com.sk89q.worldedit.EmptyClipboardException;
import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.internal.util.DeprecationUtil;
@ -43,7 +39,6 @@ import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionSelector;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.HandSide;
import com.sk89q.worldedit.util.Location;
@ -432,7 +427,8 @@ public interface Player extends Entity, Actor {
} else if (Settings.settings().CLIPBOARD.DELETE_ON_LOGOUT) {
session.setClipboard(null);
}
if (Settings.settings().HISTORY.DELETE_ON_LOGOUT) {
if (!Settings.settings().HISTORY.USE_DISK && Settings.settings().HISTORY.DELETE_ON_LOGOUT
|| Settings.settings().HISTORY.USE_DISK && Settings.settings().HISTORY.DELETE_DISK_ON_LOGOUT) {
session.clearHistory();
}
}