From 255a02c93cb8100e36d48de26770ea5aee3f5ad0 Mon Sep 17 00:00:00 2001 From: LamGC Date: Mon, 15 Aug 2022 01:38:08 +0800 Subject: [PATCH] =?UTF-8?q?refactor(config):=20=E9=87=8D=E6=9E=84=20AppPat?= =?UTF-8?q?hs=20=E7=9A=84=E6=9E=84=E9=80=A0=E6=96=B9=E6=B3=95,=20=E5=BA=94?= =?UTF-8?q?=E5=AF=B9=E5=B0=86=E6=9D=A5=20Kotlin=20=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E7=89=B9=E6=80=A7.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 先前的方法是利用了初始化与调用的顺序, 来实现的 Supplier 互补(虽然在代码中, 确实存在未初始化调用的情况, 但实际运行的时候, 会先初始化, 再调用 Supplier), 但是未来 Kotlin 的更新中,编译器会把这个操作视为未初始化错误, 所以在这次改动中修复掉这个 bug 操作. --- scalabot-app/src/main/kotlin/AppConfigs.kt | 50 +++++++++++++++---- scalabot-app/src/test/kotlin/AppConfigTest.kt | 11 ++++ 2 files changed, 51 insertions(+), 10 deletions(-) diff --git a/scalabot-app/src/main/kotlin/AppConfigs.kt b/scalabot-app/src/main/kotlin/AppConfigs.kt index 5980be5..14db5fe 100644 --- a/scalabot-app/src/main/kotlin/AppConfigs.kt +++ b/scalabot-app/src/main/kotlin/AppConfigs.kt @@ -17,7 +17,8 @@ import java.io.File import java.net.URL import java.nio.charset.StandardCharsets import java.util.concurrent.atomic.AtomicBoolean -import java.util.concurrent.atomic.AtomicInteger +import java.util.function.Supplier +import kotlin.reflect.KProperty private val log = KotlinLogging.logger { } @@ -102,9 +103,9 @@ private fun createDefaultRepositoryId(): String { * 必须提供 `pathSupplier` 或 `fileSupplier` 其中一个, 才能正常提供路径. */ internal enum class AppPaths( - private val pathSupplier: () -> String = { fileSupplier.invoke().canonicalPath }, + private val pathSupplier: PathSupplier, private val initializer: AppPaths.() -> Unit = AppPaths::defaultInitializer, - private val fileSupplier: () -> File = { File(pathSupplier()) } + private val fileSupplier: FileSupplier, ) { /** * 数据根目录. @@ -113,7 +114,7 @@ internal enum class AppPaths( * * 提示: 结尾不带 `/`. */ - DATA_ROOT(fileSupplier = { + DATA_ROOT(fileSupplier = FileSupplier { File( System.getProperty(PathConst.PROP_DATA_PATH) ?: System.getenv(PathConst.ENV_DATA_PATH) ?: System.getProperty("user.dir") ?: "." @@ -125,7 +126,7 @@ internal enum class AppPaths( } }), - CONFIG_APPLICATION({ "$DATA_ROOT/config.json" }, { + CONFIG_APPLICATION(PathSupplier { "$DATA_ROOT/config.json" }, { if (!file.exists()) { file.bufferedWriter(StandardCharsets.UTF_8).use { GsonConst.appConfigGson.toJson( @@ -141,7 +142,7 @@ internal enum class AppPaths( } } }), - CONFIG_BOT({ "$DATA_ROOT/bot.json" }, { + CONFIG_BOT(PathSupplier { "$DATA_ROOT/bot.json" }, { if (!file.exists()) { file.bufferedWriter(StandardCharsets.UTF_8).use { GsonConst.botConfigGson.toJson( @@ -167,10 +168,25 @@ internal enum class AppPaths( TEMP({ "$DATA_ROOT/tmp/" }) ; - val file: File - get() = fileSupplier.invoke() - val path: String - get() = pathSupplier.invoke() + constructor(pathSupplier: PathSupplier, initializer: AppPaths.() -> Unit = AppPaths::defaultInitializer) : this( + fileSupplier = FileSupplier { File(pathSupplier.path).canonicalFile }, + pathSupplier = pathSupplier, + initializer = initializer + ) + + constructor(fileSupplier: FileSupplier, initializer: AppPaths.() -> Unit = AppPaths::defaultInitializer) : this( + fileSupplier = fileSupplier, + pathSupplier = PathSupplier { fileSupplier.file.canonicalPath }, + initializer = initializer + ) + + constructor(pathSupplier: () -> String) : this( + fileSupplier = FileSupplier { File(pathSupplier.invoke()).canonicalFile }, + pathSupplier = PathSupplier { pathSupplier.invoke() } + ) + + val file: File by fileSupplier + val path: String by pathSupplier private val initialized = AtomicBoolean(false) @@ -206,6 +222,20 @@ internal enum class AppPaths( const val ENV_DATA_PATH = "BOT_DATA_PATH" } + private class FileSupplier(private val supplier: Supplier) { + operator fun getValue(appPaths: AppPaths, property: KProperty<*>): File = supplier.get() + + val file: File + get() = supplier.get() + } + + private class PathSupplier(private val supplier: Supplier) { + operator fun getValue(appPaths: AppPaths, property: KProperty<*>): String = supplier.get() + + val path: String + get() = supplier.get() + } + } /** diff --git a/scalabot-app/src/test/kotlin/AppConfigTest.kt b/scalabot-app/src/test/kotlin/AppConfigTest.kt index fb664d6..fd9325b 100644 --- a/scalabot-app/src/test/kotlin/AppConfigTest.kt +++ b/scalabot-app/src/test/kotlin/AppConfigTest.kt @@ -21,6 +21,17 @@ import kotlin.test.* internal class AppPathsTest { + @Test + fun `Consistency check`() { + for (path in AppPaths.values()) { + assertEquals( + File(path.path).canonicalPath, + path.file.canonicalPath, + "路径 File 与 Path 不一致: ${path.name}" + ) + } + } + @Test fun `Data root path priority`() { System.setProperty(AppPaths.PathConst.PROP_DATA_PATH, "fromSystemProperties")