This commit is contained in:
sky 2020-04-29 15:21:06 +08:00
parent 058ff6c141
commit b2e1813cff
11 changed files with 278 additions and 19 deletions

View File

@ -6,7 +6,7 @@ plugins {
} }
group = 'me.skymc' group = 'me.skymc'
version = '5.26' version = '5.27'
sourceCompatibility = 1.8 sourceCompatibility = 1.8
targetCompatibility = 1.8 targetCompatibility = 1.8

View File

@ -52,6 +52,12 @@ public class TabooLib {
logger = TLogger.getUnformatted("TabooLib"); logger = TLogger.getUnformatted("TabooLib");
// 配置文件从 config.yml 修改为 settings.yml 防止与老版本插件冲突 // 配置文件从 config.yml 修改为 settings.yml 防止与老版本插件冲突
config = TConfig.create(getPlugin(), "settings.yml"); config = TConfig.create(getPlugin(), "settings.yml");
// 配置更新
try {
config.migrate();
} catch (Throwable t) {
t.printStackTrace();
}
// 加载版本号 // 加载版本号
try { try {
version = NumberConversions.toDouble(IO.readFully(Files.getResource("__resources__/version"), StandardCharsets.UTF_8)); version = NumberConversions.toDouble(IO.readFully(Files.getResource("__resources__/version"), StandardCharsets.UTF_8));

View File

@ -1,5 +1,6 @@
package io.izzel.taboolib.module.config; package io.izzel.taboolib.module.config;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import io.izzel.taboolib.TabooLib; import io.izzel.taboolib.TabooLib;
@ -7,12 +8,14 @@ import io.izzel.taboolib.TabooLibAPI;
import io.izzel.taboolib.module.locale.TLocale; import io.izzel.taboolib.module.locale.TLocale;
import io.izzel.taboolib.module.locale.logger.TLogger; import io.izzel.taboolib.module.locale.logger.TLogger;
import io.izzel.taboolib.util.Files; import io.izzel.taboolib.util.Files;
import io.izzel.taboolib.util.KV;
import io.izzel.taboolib.util.Ref; import io.izzel.taboolib.util.Ref;
import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -24,12 +27,16 @@ import java.util.Map;
*/ */
public class TConfig extends YamlConfiguration { public class TConfig extends YamlConfiguration {
private static Map<String, List<File>> files = Maps.newHashMap(); private static final Map<String, List<File>> files = Maps.newHashMap();
private File file; private final Plugin plugin;
private List<Runnable> runnable = Lists.newArrayList(); private final File file;
private final List<Runnable> runnable = Lists.newArrayList();
private final List<KV<String, String[]>> migrate = Lists.newArrayList();
private String path;
private TConfig(File file, Plugin plugin) { private TConfig(File file, Plugin plugin) {
files.computeIfAbsent(plugin.getName(), name -> new ArrayList<>()).add(file); files.computeIfAbsent(plugin.getName(), name -> new ArrayList<>()).add(file);
this.plugin = plugin;
this.file = file; this.file = file;
reload(); reload();
TConfigWatcher.getInst().addSimpleListener(this.file, this::reload); TConfigWatcher.getInst().addSimpleListener(this.file, this::reload);
@ -53,7 +60,9 @@ public class TConfig extends YamlConfiguration {
if (!file.exists()) { if (!file.exists()) {
Files.releaseResource(plugin, path, false); Files.releaseResource(plugin, path, false);
} }
return create(file, plugin); TConfig conf = create(file, plugin);
conf.path = path;
return conf;
} }
public String getStringColored(String path) { public String getStringColored(String path) {
@ -89,6 +98,25 @@ public class TConfig extends YamlConfiguration {
} }
} }
public TConfig migrate() {
Preconditions.checkNotNull(path, "path not exists");
try (FileInputStream fileInputStream = new FileInputStream(file)) {
List<String> migrate = TConfigMigrate.migrate(fileInputStream, Files.getResourceChecked(plugin, path));
if (migrate != null) {
Files.write(file, w -> {
for (String line : migrate) {
w.write(line);
w.newLine();
}
});
load(file);
}
} catch (Throwable t) {
t.printStackTrace();
}
return this;
}
// ********************************* // *********************************
// //
// Getter and Setter // Getter and Setter

View File

@ -0,0 +1,152 @@
package io.izzel.taboolib.module.config;
import com.google.common.collect.Lists;
import io.izzel.taboolib.module.db.local.SecuredFile;
import io.izzel.taboolib.util.ArrayUtil;
import io.izzel.taboolib.util.Files;
import io.izzel.taboolib.util.KV;
import io.izzel.taboolib.util.Strings;
import org.bukkit.configuration.ConfigurationSection;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.IntStream;
/**
* @Author sky
* @Since 2020-04-27 21:02
*/
public class TConfigMigrate {
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm");
public static List<String> migrate(InputStream current, InputStream source) {
boolean migrated = false;
List<String> content = Files.readToList(current);
String cc = String.join("\n", content);
String cs = String.join("\n", Files.readToList(source));
SecuredFile c = SecuredFile.loadConfiguration(cc);
SecuredFile s = SecuredFile.loadConfiguration(cs);
String hash1 = Strings.hashKeyForDisk(cs, "sha-1");
String hash2 = "";
for (String line : content) {
if (line.startsWith("# HASH ")) {
hash2 = line.substring("# HASH ".length()).trim().split(" ")[0];
break;
}
}
if (Objects.equals(hash1, hash2)) {
return null;
}
List<KV<String, String[]>> update = Lists.newArrayList();
List<KV<String, Object>> contrast = contrast(c.getValues(true), s.getValues(true));
for (KV<String, Object> pair : contrast) {
int index = pair.getKey().lastIndexOf(".");
if (pair.getValue() == null) {
Object data = s.get(pair.getKey());
String[] nodes = pair.getKey().split("\\.");
int regex = 0;
int match = 0;
int find = -1;
for (int i = 0; i < content.size(); i++) {
String line = content.get(i);
for (int j = regex; j < nodes.length; j++) {
if (line.matches("( *)(['\"])?(" + nodes[j] + ")(['\"])?:(.*)")) {
match++;
find = i;
regex = j;
break;
}
}
}
if (find == -1) {
update.add(new KV<>(pair.getKey(), SecuredFile.dump(data).split("\n")));
} else {
String space = Strings.copy(" ", nodes.length - 1);
String[] dumpList = SecuredFile.dump(data).split("\n");
if (dumpList.length > 1) {
IntStream.range(0, dumpList.length).forEach(j -> dumpList[j] = space + " # " + dumpList[j]);
}
ArrayUtil.addAutoExpand(content, find + 1, space + "# ------------------------- #\n" + space + "# UPDATE " + dateFormat.format(System.currentTimeMillis()) + " #\n" + space + "# ------------------------- #", "");
if (dumpList.length == 1) {
ArrayUtil.addAutoExpand(content, find + 2, space + "# " + pair.getKey().substring(index + 1) + ": " + dumpList[0] + "\n", "");
} else {
ArrayUtil.addAutoExpand(content, find + 2, space + "# " + pair.getKey().substring(index + 1) + ":", "");
ArrayUtil.addAutoExpand(content, find + 3, String.join("\n# ", dumpList) + "\n", "");
}
migrated = true;
}
}
}
if (update.size() > 0) {
content.add("");
content.add("# ------------------------- #\n" + "# UPDATE " + dateFormat.format(System.currentTimeMillis()) + " #\n" + "# ------------------------- #");
for (KV<String, String[]> pair : update) {
if (pair.getValue().length == 1) {
content.add("# " + pair.getKey() + ": " + pair.getValue()[0]);
} else {
content.add("# " + pair.getKey() + ":");
content.add(String.join("\n# ", pair.getValue()));
}
}
migrated = true;
}
if (migrated) {
if (hash2.isEmpty()) {
content.add("");
content.add("# --------------------------------------------- #");
content.add("# HASH " + hash1 + " #");
content.add("# --------------------------------------------- #");
} else {
for (int i = 0; i < content.size(); i++) {
String line = content.get(i);
if (line.startsWith("# HASH ")) {
content.set(i, "# HASH " + hash1 + " #");
break;
}
}
}
}
return migrated ? content : null;
}
public static List<KV<String, Object>> contrast(Map<?, ?> current, Map<?, ?> source) {
List<String> deleted = Lists.newArrayList();
List<KV<String, Object>> difference = Lists.newArrayList();
// change & add
for (Map.Entry<?, ?> entry : current.entrySet()) {
if (entry.getValue() instanceof ConfigurationSection) {
continue;
}
if (entry.getValue() instanceof Map && source.get(entry.getKey()) instanceof Map) {
List<KV<String, Object>> contrast = contrast((Map<?, ?>) entry.getValue(), (Map<?, ?>) source.get(entry.getKey()));
for (KV<String, Object> pair : contrast) {
pair.setKey(entry.getKey() + "." + pair.getKey());
}
difference.addAll(contrast);
} else if (!Objects.equals(entry.getValue(), source.get(entry.getKey()))) {
difference.add(new KV<>(entry.getKey().toString(), entry.getValue()));
}
}
// delete
for (Map.Entry<?, ?> entry : source.entrySet()) {
if (deleted.stream().anyMatch(delete -> entry.getKey().toString().startsWith(delete) && delete.split("\\.").length < entry.getKey().toString().split("\\.").length)) {
continue;
}
if (entry.getValue() instanceof Map && current.get(entry.getKey()) instanceof Map) {
List<KV<String, Object>> contrast = contrast((Map<?, ?>) entry.getValue(), (Map<?, ?>) source.get(entry.getKey()));
for (KV<String, Object> pair : contrast) {
pair.setKey(entry.getKey() + "." + pair.getKey());
}
difference.addAll(contrast);
} else if (!current.containsKey(entry.getKey())) {
deleted.add(entry.getKey().toString());
difference.add(new KV<>(entry.getKey().toString(), null));
}
}
return difference;
}
}

View File

@ -19,7 +19,7 @@ import java.util.function.Consumer;
*/ */
public class TConfigWatcher { public class TConfigWatcher {
private static TConfigWatcher configWatcher = new TConfigWatcher(); private final static TConfigWatcher configWatcher = new TConfigWatcher();
private final ScheduledExecutorService service = Executors.newScheduledThreadPool(1, new BasicThreadFactory.Builder().namingPattern("TConfigWatcherService-%d").build()); private final ScheduledExecutorService service = Executors.newScheduledThreadPool(1, new BasicThreadFactory.Builder().namingPattern("TConfigWatcherService-%d").build());
private final Map<WatchService, Triple<File, Object, Consumer<Object>>> map = new HashMap<>(); private final Map<WatchService, Triple<File, Object, Consumer<Object>>> map = new HashMap<>();

View File

@ -1,9 +1,11 @@
package io.izzel.taboolib.module.db.local; package io.izzel.taboolib.module.db.local;
import io.izzel.taboolib.module.lite.SimpleReflection;
import io.izzel.taboolib.util.Files; import io.izzel.taboolib.util.Files;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.file.YamlConfiguration;
import org.yaml.snakeyaml.Yaml;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -11,7 +13,7 @@ import java.text.SimpleDateFormat;
import java.util.logging.Level; import java.util.logging.Level;
/** /**
* @Author sky * @Author sky, yumc
* @Since 2020-02-28 11:14 * @Since 2020-02-28 11:14
*/ */
public class SecuredFile extends YamlConfiguration { public class SecuredFile extends YamlConfiguration {
@ -39,7 +41,7 @@ public class SecuredFile extends YamlConfiguration {
public void load(File file) throws InvalidConfigurationException { public void load(File file) throws InvalidConfigurationException {
String content = Files.readFromFile(file); String content = Files.readFromFile(file);
try { try {
super.loadFromString(Files.readFromFile(file)); loadFromString(content);
} catch (InvalidConfigurationException t) { } catch (InvalidConfigurationException t) {
Files.copy(file, new File(file.getParent(), file.getName() + "_" + new SimpleDateFormat("yyyyMMddHHmmss").format(System.currentTimeMillis()) + ".bak")); Files.copy(file, new File(file.getParent(), file.getName() + "_" + new SimpleDateFormat("yyyyMMddHHmmss").format(System.currentTimeMillis()) + ".bak"));
throw t; throw t;
@ -60,6 +62,21 @@ public class SecuredFile extends YamlConfiguration {
} }
} }
@Override
public String saveToString() {
return super.saveToString();
}
public static String dump(Object data) {
Yaml yaml = (Yaml) SimpleReflection.getFieldValueChecked(YamlConfiguration.class, new YamlConfiguration(), "yaml", true);
try {
return yaml.dump(data);
} catch (Throwable t) {
t.printStackTrace();
}
return "";
}
public static SecuredFile loadConfiguration(String contents) { public static SecuredFile loadConfiguration(String contents) {
SecuredFile config = new SecuredFile(); SecuredFile config = new SecuredFile();
try { try {

View File

@ -31,6 +31,8 @@ public @interface TInject {
State state() default State.NONE; State state() default State.NONE;
boolean autoMigrate() default false;
enum State { enum State {
LOADING, STARTING, ACTIVATED, NONE LOADING, STARTING, ACTIVATED, NONE

View File

@ -28,7 +28,7 @@ import java.util.Map;
*/ */
public class TInjectLoader implements TabooLibLoader.Loader { public class TInjectLoader implements TabooLibLoader.Loader {
private static Map<Class<?>, TInjectTask> injectTypes = Maps.newLinkedHashMap(); private static final Map<Class<?>, TInjectTask> injectTypes = Maps.newLinkedHashMap();
static { static {
// Instance Inject // Instance Inject
@ -91,6 +91,9 @@ public class TInjectLoader implements TabooLibLoader.Loader {
t.printStackTrace(); t.printStackTrace();
} }
} }
if (args.autoMigrate()) {
config.migrate();
}
TabooLibLoader.runTask(config::runListener); TabooLibLoader.runTask(config::runListener);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();

View File

@ -18,7 +18,7 @@ public class ArrayUtil {
public static <T> boolean contains(T[] array, T obj) { public static <T> boolean contains(T[] array, T obj) {
return indexOf(array, obj) != -1; return indexOf(array, obj) != -1;
} }
public static <T> int indexOf(T[] array, T obj) { public static <T> int indexOf(T[] array, T obj) {
return array == null || array.length == 0 ? -1 : IntStream.range(0, array.length).filter(i -> array[i] != null && array[i].equals(obj)).findFirst().orElse(-1); return array == null || array.length == 0 ? -1 : IntStream.range(0, array.length).filter(i -> array[i] != null && array[i].equals(obj)).findFirst().orElse(-1);
} }
@ -73,6 +73,22 @@ public class ArrayUtil {
return arrayNew; return arrayNew;
} }
public static <T> List<T> setAutoExpand(List<T> list, int index, T element, T def) {
while (list.size() <= index) {
list.add(def);
}
list.set(index, element);
return list;
}
public static <T> List<T> addAutoExpand(List<T> list, int index, T element, T def) {
while (list.size() <= index) {
list.add(def);
}
list.add(index, element);
return list;
}
@SuppressWarnings("SuspiciousSystemArraycopy") @SuppressWarnings("SuspiciousSystemArraycopy")
public static <T> T arrayExpand(T oldArray, int expand) { public static <T> T arrayExpand(T oldArray, int expand) {
int length = Array.getLength(oldArray); int length = Array.getLength(oldArray);

View File

@ -21,6 +21,7 @@ import java.security.MessageDigest;
import java.util.*; import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.jar.JarFile; import java.util.jar.JarFile;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipFile; import java.util.zip.ZipFile;
@ -70,6 +71,10 @@ public class Files {
return plugin instanceof InternalPlugin ? getTabooLibResource(filename) : plugin.getClass().getClassLoader().getResourceAsStream(filename); return plugin instanceof InternalPlugin ? getTabooLibResource(filename) : plugin.getClass().getClassLoader().getResourceAsStream(filename);
} }
public static InputStream getResourceChecked(Plugin plugin, String filename) {
return plugin instanceof InternalPlugin ? getResource(plugin, "__resources__/" + filename) : getResource(filename);
}
public static InputStream getTabooLibResource(String filename) { public static InputStream getTabooLibResource(String filename) {
return getCanonicalResource(TabooLib.getPlugin(), filename); return getCanonicalResource(TabooLib.getPlugin(), filename);
} }
@ -234,7 +239,7 @@ public class Files {
return Optional.ofNullable(readFromURL(url)).orElse(def); return Optional.ofNullable(readFromURL(url)).orElse(def);
} }
public static String readFromURL(String url, Charset charset, String def) { public static String readFromURL(String url, Charset charset, String def) {
return Optional.ofNullable(readFromURL(url, charset)).orElse(def); return Optional.ofNullable(readFromURL(url, charset)).orElse(def);
} }
@ -273,6 +278,24 @@ public class Files {
return null; return null;
} }
public static List<String> readToList(File file) {
try (FileInputStream fin = new FileInputStream(file); InputStreamReader isr = new InputStreamReader(fin, StandardCharsets.UTF_8); BufferedReader bin = new BufferedReader(isr)) {
return bin.lines().collect(Collectors.toList());
} catch (IOException e) {
e.printStackTrace();
}
return Collections.emptyList();
}
public static List<String> readToList(InputStream inputStream) {
try (InputStreamReader isr = new InputStreamReader(inputStream, StandardCharsets.UTF_8); BufferedReader bin = new BufferedReader(isr)) {
return bin.lines().collect(Collectors.toList());
} catch (IOException e) {
e.printStackTrace();
}
return Collections.emptyList();
}
public static String readFromStream(InputStream in) { public static String readFromStream(InputStream in) {
return readFromStream(in, 1024, StandardCharsets.UTF_8); return readFromStream(in, 1024, StandardCharsets.UTF_8);
} }
@ -296,7 +319,9 @@ public class Files {
} }
public static void read(File file, ReadHandle readHandle) { public static void read(File file, ReadHandle readHandle) {
try (FileReader fileReader = new FileReader(file); BufferedReader bufferedReader = new BufferedReader(fileReader)) { try (FileInputStream fileInputStream = new FileInputStream(file);
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
readHandle.read(bufferedReader); readHandle.read(bufferedReader);
} catch (Throwable t) { } catch (Throwable t) {
t.printStackTrace(); t.printStackTrace();
@ -304,7 +329,8 @@ public class Files {
} }
public static void read(InputStream in, ReadHandle readHandle) { public static void read(InputStream in, ReadHandle readHandle) {
try (InputStreamReader inputStreamReader = new InputStreamReader(in); BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) { try (InputStreamReader inputStreamReader = new InputStreamReader(in, StandardCharsets.UTF_8);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
readHandle.read(bufferedReader); readHandle.read(bufferedReader);
} catch (Throwable t) { } catch (Throwable t) {
t.printStackTrace(); t.printStackTrace();
@ -312,7 +338,9 @@ public class Files {
} }
public static void write(File file, WriteHandle writeHandle) { public static void write(File file, WriteHandle writeHandle) {
try (FileWriter fileWriter = new FileWriter(file); BufferedWriter bufferedWriter = new BufferedWriter(fileWriter)) { try (FileOutputStream fileOutputStream = new FileOutputStream(file);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, StandardCharsets.UTF_8);
BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter)) {
writeHandle.write(bufferedWriter); writeHandle.write(bufferedWriter);
bufferedWriter.flush(); bufferedWriter.flush();
} catch (Throwable t) { } catch (Throwable t) {
@ -321,7 +349,9 @@ public class Files {
} }
public static void writeAppend(File file, WriteHandle writeHandle) { public static void writeAppend(File file, WriteHandle writeHandle) {
try (FileWriter fileWriter = new FileWriter(file, true); BufferedWriter bufferedWriter = new BufferedWriter(fileWriter)) { try (FileOutputStream fileOutputStream = new FileOutputStream(file, true);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, StandardCharsets.UTF_8);
BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter)) {
writeHandle.write(bufferedWriter); writeHandle.write(bufferedWriter);
bufferedWriter.flush(); bufferedWriter.flush();
} catch (Throwable t) { } catch (Throwable t) {
@ -330,7 +360,8 @@ public class Files {
} }
public static void write(OutputStream out, WriteHandle writeHandle) { public static void write(OutputStream out, WriteHandle writeHandle) {
try (OutputStreamWriter outputStreamWriter = new OutputStreamWriter(out); BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter)) { try (OutputStreamWriter outputStreamWriter = new OutputStreamWriter(out, StandardCharsets.UTF_8);
BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter)) {
writeHandle.write(bufferedWriter); writeHandle.write(bufferedWriter);
bufferedWriter.flush(); bufferedWriter.flush();
} catch (Throwable t) { } catch (Throwable t) {
@ -355,14 +386,14 @@ public class Files {
} }
public static String getFileHash(File file, String algorithm) { public static String getFileHash(File file, String algorithm) {
try(FileInputStream fileInputStream = new FileInputStream(file)) { try (FileInputStream fileInputStream = new FileInputStream(file)) {
MessageDigest digest = MessageDigest.getInstance(algorithm); MessageDigest digest = MessageDigest.getInstance(algorithm);
byte[] buffer = new byte[1024]; byte[] buffer = new byte[1024];
int length; int length;
while ((length = fileInputStream.read(buffer, 0, 1024)) != -1) { while ((length = fileInputStream.read(buffer, 0, 1024)) != -1) {
digest.update(buffer, 0, length); digest.update(buffer, 0, length);
} }
byte[] md5Bytes = digest.digest(); byte[] md5Bytes = digest.digest();
return new BigInteger(1, md5Bytes).toString(16); return new BigInteger(1, md5Bytes).toString(16);
} catch (Throwable t) { } catch (Throwable t) {
t.printStackTrace(); t.printStackTrace();

View File

@ -60,9 +60,13 @@ public class Strings {
} }
public static String hashKeyForDisk(String key) { public static String hashKeyForDisk(String key) {
return hashKeyForDisk(key, "MD5");
}
public static String hashKeyForDisk(String key, String type) {
String cacheKey; String cacheKey;
try { try {
final MessageDigest mDigest = MessageDigest.getInstance("MD5"); final MessageDigest mDigest = MessageDigest.getInstance(type);
mDigest.update(key.getBytes()); mDigest.update(key.getBytes());
cacheKey = bytesToHexString(mDigest.digest()); cacheKey = bytesToHexString(mDigest.digest());
} catch (NoSuchAlgorithmException e) { } catch (NoSuchAlgorithmException e) {