From f52a760bbeeb8d9f72e3b1552559a17a884dcaa8 Mon Sep 17 00:00:00 2001 From: Will FP Date: Tue, 26 Dec 2023 13:33:46 +0100 Subject: [PATCH] Added yaml autosaving --- .../core/config/interfaces/LoadableConfig.java | 16 ++++++++++++++++ .../eco/internal/config/EcoLoadableConfig.kt | 16 ++++++++++++++++ .../eco/internal/spigot/EcoSpigotPlugin.kt | 2 ++ .../eco/internal/spigot/data/ProfileHandler.kt | 13 +++++++++++++ .../internal/spigot/data/storage/DataHandler.kt | 4 ++++ .../spigot/data/storage/YamlDataHandler.kt | 4 ++++ .../core-plugin/src/main/resources/config.yml | 4 ++++ 7 files changed, 59 insertions(+) diff --git a/eco-api/src/main/java/com/willfp/eco/core/config/interfaces/LoadableConfig.java b/eco-api/src/main/java/com/willfp/eco/core/config/interfaces/LoadableConfig.java index 3f19337a..83c3ae14 100644 --- a/eco-api/src/main/java/com/willfp/eco/core/config/interfaces/LoadableConfig.java +++ b/eco-api/src/main/java/com/willfp/eco/core/config/interfaces/LoadableConfig.java @@ -29,6 +29,22 @@ public interface LoadableConfig extends Config { */ void save() throws IOException; + /** + * Save the config asynchronously. + */ + default void saveAsync() { + // This default implementation exists purely for backwards compatibility + // with legacy Config implementations that don't have saveAsync(). + // Default eco implementations of Config have saveAsync() implemented. + new Thread(() -> { + try { + this.save(); + } catch (IOException e) { + e.printStackTrace(); + } + }).start(); + } + /** * Get the config file. * diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/EcoLoadableConfig.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/EcoLoadableConfig.kt index eabe3e61..d8920fe3 100644 --- a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/EcoLoadableConfig.kt +++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/EcoLoadableConfig.kt @@ -10,6 +10,8 @@ import java.io.IOException import java.io.InputStreamReader import java.io.OutputStream import java.io.Reader +import java.nio.ByteBuffer +import java.nio.channels.AsynchronousFileChannel import java.nio.file.Files import java.nio.file.StandardOpenOption @@ -74,6 +76,20 @@ open class EcoLoadableConfig( } } + override fun saveAsync() { + // Save asynchronously using NIO + AsynchronousFileChannel.open( + configFile.toPath(), + StandardOpenOption.WRITE, + StandardOpenOption.CREATE + ).use { channel -> + channel.write( + ByteBuffer.wrap(this.toPlaintext().toByteArray()), + 0 + ) + } + } + private fun makeHeader(contents: String) { header.clear() diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoSpigotPlugin.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoSpigotPlugin.kt index af1ee650..9b5c1753 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoSpigotPlugin.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoSpigotPlugin.kt @@ -261,6 +261,8 @@ abstract class EcoSpigotPlugin : EcoPlugin() { profileHandler.migrateIfNeeded() } + profileHandler.startAutosaving() + ProfileSaver(this, profileHandler).startTicking() this.scheduler.runTimer( diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/ProfileHandler.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/ProfileHandler.kt index 76648060..0809ee12 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/ProfileHandler.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/ProfileHandler.kt @@ -169,4 +169,17 @@ class ProfileHandler( localHandler.initialize() } } + + fun startAutosaving() { + if (!plugin.configYml.getBool("yaml.autosave")) { + return + } + + val interval = plugin.configYml.getInt("yaml.autosave-interval") * 20L + + plugin.scheduler.runTimer(20, interval) { + handler.saveAsync() + localHandler.saveAsync() + } + } } diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/storage/DataHandler.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/storage/DataHandler.kt index 1da537d1..0855a066 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/storage/DataHandler.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/storage/DataHandler.kt @@ -27,6 +27,10 @@ abstract class DataHandler( } + open fun saveAsync() { + + } + open fun initialize() { } diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/storage/YamlDataHandler.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/storage/YamlDataHandler.kt index 1174799a..edbf73b6 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/storage/YamlDataHandler.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/storage/YamlDataHandler.kt @@ -18,6 +18,10 @@ class YamlDataHandler( dataYml.save() } + override fun saveAsync() { + dataYml.saveAsync() + } + override fun read(uuid: UUID, key: PersistentDataKey): T? { // Separate `as T?` for each branch to prevent compiler warnings. val value = when (key.type) { diff --git a/eco-core/core-plugin/src/main/resources/config.yml b/eco-core/core-plugin/src/main/resources/config.yml index ed17ec4b..dc1f4ecb 100644 --- a/eco-core/core-plugin/src/main/resources/config.yml +++ b/eco-core/core-plugin/src/main/resources/config.yml @@ -30,6 +30,10 @@ mysql: user: username password: passy +yaml: + autosave: true # If data should be saved automatically + autosave-interval: 1800 # How often data should be saved (in seconds) + # How many ticks to wait between committing data to a database. This doesn't # affect yaml storage, only MySQL and MongoDB. By default, data is committed # every tick, but you can increase this to be every x ticks, for example 20