From 0016a04d5e12c87834cc8c5ec12264b3ee47f426 Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Sat, 22 Aug 2020 01:36:22 +0800 Subject: [PATCH] Rename Setting to PluginData for compatiblity issue --- PluginDocs/java/source.java | 176 ------------- .../console/codegen/ValueSettingCodegen.kt | 24 +- .../console/codegen/old/JSettingCodegen.kt | 6 +- .../codegen/old/SettingValueUseSiteCodegen.kt | 28 +-- .../console/codegen/old/ValueImplCodegen.kt | 26 +- .../console/codegen/old/ValuesCodegen.kt | 16 +- .../net/mamoe/mirai/console/MiraiConsole.kt | 21 +- .../console/MiraiConsoleImplementation.kt | 6 +- .../mirai/console/data/AbstractPluginData.kt | 57 +++++ .../mamoe/mirai/console/data/PluginConfig.kt | 17 ++ .../mamoe/mirai/console/data/PluginData.kt | 232 ++++++++++++++++++ .../mirai/console/data/PluginDataHolder.kt | 84 +++++++ .../mirai/console/data/PluginDataStorage.kt | 115 +++++++++ .../mirai/console/{setting => data}/Value.kt | 39 +-- .../MiraiConsoleImplementationBridge.kt | 10 +- .../console/internal/command/internal.kt | 17 +- .../{setting => data}/CompositeValueImpl.kt | 10 +- .../PluginData.value composite impl.kt} | 12 +- .../SettingImpl.kt => data/PluginDataImpl.kt} | 22 +- .../PluginDataStorage internal.kt} | 93 +++---- .../SemverAsStringSerializer.kt | 2 +- .../_PluginData.value.kt} | 69 ++++-- .../_PrimitiveValueDeclarations.kt | 5 +- .../internal/{setting => data}/asKClass.kt | 12 +- .../{setting => data}/collectionUtil.kt | 2 +- .../{setting => data}/serializerHelper.kt | 2 +- .../{setting => data}/serializerUtil.kt | 2 +- .../internal/plugin/JarPluginLoaderImpl.kt | 6 +- .../internal/plugin/JvmPluginInternal.kt | 47 +++- .../internal/plugin/PluginManagerImpl.kt | 2 +- .../console/internal/utils/BotManagerImpl.kt | 16 +- .../mamoe/mirai/console/plugin/description.kt | 4 +- .../console/plugin/jvm/JarPluginLoader.kt | 6 +- .../mirai/console/plugin/jvm/JvmPlugin.kt | 19 +- .../plugin/jvm/JvmPluginDescriptionImpl.kt | 2 +- .../mirai/console/plugin/jvm/KotlinPlugin.kt | 2 +- .../mamoe/mirai/console/setting/Setting.kt | 206 ---------------- .../mirai/console/setting/SettingStorage.kt | 187 -------------- .../mamoe/mirai/console/TestMiraiConosle.kt | 8 +- .../console/{setting => data}/SettingTest.kt | 50 ++-- .../pure/MiraiConsoleImplementationPure.kt | 8 +- .../console/pure/MiraiConsolePureLoader.kt | 24 ++ 42 files changed, 851 insertions(+), 841 deletions(-) delete mode 100644 PluginDocs/java/source.java create mode 100644 backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/AbstractPluginData.kt create mode 100644 backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginConfig.kt create mode 100644 backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginData.kt create mode 100644 backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginDataHolder.kt create mode 100644 backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginDataStorage.kt rename backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/{setting => data}/Value.kt (89%) rename backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/{setting => data}/CompositeValueImpl.kt (94%) rename backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/{setting/Setting.value composite impl.kt => data/PluginData.value composite impl.kt} (92%) rename backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/{setting/SettingImpl.kt => data/PluginDataImpl.kt} (85%) rename backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/{setting/SettingStorage internal.kt => data/PluginDataStorage internal.kt} (59%) rename backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/{setting => data}/SemverAsStringSerializer.kt (95%) rename backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/{setting/_Setting.value.kt => data/_PluginData.value.kt} (69%) rename backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/{setting => data}/_PrimitiveValueDeclarations.kt (99%) rename backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/{setting => data}/asKClass.kt (78%) rename backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/{setting => data}/collectionUtil.kt (99%) rename backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/{setting => data}/serializerHelper.kt (99%) rename backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/{setting => data}/serializerUtil.kt (97%) delete mode 100644 backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt delete mode 100644 backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/SettingStorage.kt rename backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/{setting => data}/SettingTest.kt (73%) diff --git a/PluginDocs/java/source.java b/PluginDocs/java/source.java deleted file mode 100644 index 7585e5883..000000000 --- a/PluginDocs/java/source.java +++ /dev/null @@ -1,176 +0,0 @@ -package net.mamoe.n; - -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import net.mamoe.mirai.console.command.*; -import net.mamoe.mirai.console.plugin.Config; -import net.mamoe.mirai.console.plugin.ConfigSection; -import net.mamoe.mirai.console.plugin.ConfigSectionFactory; -import net.mamoe.mirai.console.plugin.PluginBase; -import net.mamoe.mirai.console.util.Utils; -import net.mamoe.mirai.message.GroupMessage; -import org.jetbrains.annotations.NotNull; -import org.jsoup.Jsoup; - -import java.util.ArrayList; -import java.util.List; - -class PingMyMCServerMain extends PluginBase { - - private String defaultServerName; - private ConfigSection serverMap; - private Config setting; - private String API; - private String responseTemplate; - - public void onLoad(){ - super.onLoad(); - - this.setting = this.loadConfig("setting.yml"); - - this.setting.setIfAbsent("API","https://api-mping.loliboy.com/ping/{address}/{port}"); - this.setting.setIfAbsent("ServerList", ConfigSectionFactory.create()); - this.setting.setIfAbsent("DefaultServerName",""); - this.setting.setIfAbsent("ResponseTemplate","Ping {serverName}: \nGame: {game}, {version}\nName: {fullName}\nPlayer: {currentPlayers}/{maxPlayers}\nConnected: {connected}\nIP: {address}:{port}"); - - - this.API = this.setting.getString("API"); - this.defaultServerName = this.setting.getString("DefaultServerName"); - this.serverMap = this.setting.getConfigSection("ServerList"); - this.responseTemplate = this.setting.getString("ResponseTemplate"); - } - - @Override - public void onDisable() { - super.onDisable(); - this.setting.set("ServerList",serverMap); - this.setting.set("DefaultServerName",defaultServerName); - this.setting.save(); - } - - public void onEnable(){ - this.getEventListener().subscribeAlways(GroupMessage.class, (GroupMessage event) -> { - - String messageInString = event.getMessage().toString(); - - if(!messageInString.contains("ping ")) { - return; - } - - String serverName = messageInString.replace("ping ", "").toLowerCase().trim(); - - if(!this.serverMap.containsKey(serverName)) { - serverName = this.defaultServerName; - } - - if(!this.serverMap.containsKey(serverName)){ - event.getSubject().sendMessage("Bot管理员没有设置任何可ping的服务器, 请使用/mcserver 来增加"); - return; - } - - ConfigSection serverInfo = this.serverMap.getConfigSection(serverName); - - final String serverName_ = serverName; - - getScheduler().async(() -> { - event.getSubject().sendMessage("正在获取中.."); - try { - String response = Utils.tryNTimes(2, () -> - Jsoup.connect(API - .replace("{address}", serverInfo.getString("address")) - .replace("{port}", serverInfo.getString("port")) - ).ignoreContentType(true).timeout(8000).execute().body() - ); - JsonObject resObj = JsonParser.parseString(response).getAsJsonObject(); - JsonObject addressObj = resObj.get("rinfo").getAsJsonObject(); - event.getSubject().sendMessage(this.responseTemplate - .replace("{connected}",resObj.get("connected").getAsString()) - .replace("{currentPlayers}",resObj.get("currentPlayers").getAsString()) - .replace("{maxPlayers}",resObj.get("maxPlayers").getAsString()) - .replace("{serverName}",serverName_) - .replace("{fullName}",resObj.get("cleanName").getAsString()) - .replace("{game}",resObj.get("game").getAsString()) - .replace("{version}",resObj.get("version").getAsString()) - .replace("{address}",addressObj.get("address").getAsString()) - .replace("{port}",addressObj.get("port").getAsString()) - ); - } catch (Exception e) { - event.getSubject().sendMessage("获取失败.." + e.getMessage()); - e.printStackTrace(); - } - }); - - }); - - JCommandManager.getInstance().register(this, new BlockingCommand( - "mcserver", new ArrayList<>(),"管理可以ping的MC服务器","/mcserver add/remove" - ) { - @Override - public boolean onCommandBlocking(@NotNull CommandSender commandSender, @NotNull List<String> list) { - if(list.size() < 1){ - return false; - } - switch (list.get(0)){ - case "add": - if(list.size() < 4){ - commandSender.sendMessageBlocking("/mcserver add 服务器名字 IP 端口"); - return true; - } - String serverName = list.get(1); - - String IP = list.get(2); - - int port = -1; - try { - port = Integer.parseInt(list.get(3)); - }catch (Exception e){ - commandSender.sendMessageBlocking("无法识别端口号"); - return true; - } - - if(port < 0 || port > 65535){ - commandSender.sendMessageBlocking("无法识别端口号[0-65535]"); - return true; - } - if(IP.contains(":")){ - commandSender.sendMessageBlocking("IP中不应包含端口"); - return true; - } - - ConfigSection data = ConfigSectionFactory.create(); - - data.set("address",IP); - data.set("port",port); - - if(serverMap.size() == 0){ - defaultServerName = serverName; - } - - serverMap.put(serverName.toLowerCase(),data); - commandSender.sendMessageBlocking("设置成功, 发送ping " + serverName + " 即可"); - - break; - case "remove": - if(list.size() < 2){ - commandSender.sendMessageBlocking("/mcserver remove 服务器名字"); - return true; - } - String serverNameToRemove = list.get(1).toLowerCase(); - if(serverMap.containsKey(serverNameToRemove)){ - serverMap.remove(serverNameToRemove); - commandSender.sendMessageBlocking("移除成功"); - }else{ - commandSender.sendMessageBlocking("没有找到" + list.get(1) + "的数据"); - } - break; - default: - return false; - } - return true; - } - }); - - this.getLogger().info("PingMyMCServer Enabled"); - } - -} \ No newline at end of file diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValueSettingCodegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValueSettingCodegen.kt index 54ddc3179..6b2db60ea 100644 --- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValueSettingCodegen.kt +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValueSettingCodegen.kt @@ -7,7 +7,7 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -@file:Suppress("PRE_RELEASE_CLASS", "ClassName", "RedundantVisibilityModifier") +@file:Suppress("PRE_RELEASE_CLASS", "ClassName", "RedundantVisibilityModifier", "KDocUnresolvedReference") package net.mamoe.mirai.console.codegen @@ -15,7 +15,7 @@ import kotlin.reflect.full.functions import kotlin.reflect.full.hasAnnotation import kotlin.reflect.full.isSubclassOf -internal object ValueSettingCodegen { +internal object ValuePluginDataCodegen { /** * The interface */ @@ -37,7 +37,7 @@ internal object ValueSettingCodegen { } } - object BuiltInSerializerConstantsPrimitivesCodegen : RegionCodegen("_Setting.value.kt"), DefaultInvoke { + object BuiltInSerializerConstantsPrimitivesCodegen : RegionCodegen("_PluginData.value.kt"), DefaultInvoke { @JvmStatic fun main(args: Array<String>) = super.startIndependently() override val defaultInvokeArgs: List<KtType> = KtPrimitives + KtString @@ -99,7 +99,7 @@ internal abstract class ${ktType.standardName}ValueImpl : ${ktType.standardName} } - object Setting_value_PrimitivesImplCodegen : RegionCodegen("_Setting.value.kt"), DefaultInvoke { + object PluginData_value_PrimitivesImplCodegen : RegionCodegen("_PluginData.value.kt"), DefaultInvoke { @JvmStatic fun main(args: Array<String>) = super.startIndependently() override val defaultInvokeArgs: List<KtType> = KtPrimitives + KtString @@ -107,12 +107,12 @@ internal abstract class ${ktType.standardName}ValueImpl : ${ktType.standardName} override fun StringBuilder.apply(ktType: KtType) { appendKCode( """ -internal fun Setting.valueImpl(default: ${ktType.standardName}): SerializerAwareValue<${ktType.standardName}> { +internal fun PluginData.valueImpl(default: ${ktType.standardName}): SerializerAwareValue<${ktType.standardName}> { return object : ${ktType.standardName}ValueImpl(default) { override fun onChanged() = this@valueImpl.onValueChanged(this) } } -internal fun Setting.${ktType.lowerCaseName}ValueImpl(): SerializerAwareValue<${ktType.standardName}> { +internal fun PluginData.${ktType.lowerCaseName}ValueImpl(): SerializerAwareValue<${ktType.standardName}> { return object : ${ktType.standardName}ValueImpl() { override fun onChanged() = this@${ktType.lowerCaseName}ValueImpl.onValueChanged(this) } @@ -122,7 +122,7 @@ internal fun Setting.${ktType.lowerCaseName}ValueImpl(): SerializerAwareValue<${ } } - object Setting_valueImplPrimitiveCodegen : RegionCodegen("_Setting.value.kt"), DefaultInvoke { + object PluginData_valueImplPrimitiveCodegen : RegionCodegen("_PluginData.value.kt"), DefaultInvoke { @JvmStatic fun main(args: Array<String>) = super.startIndependently() override val defaultInvokeArgs: List<KtType> = KtPrimitives + KtString @@ -136,7 +136,7 @@ internal fun Setting.${ktType.lowerCaseName}ValueImpl(): SerializerAwareValue<${ } } - object Setting_value_primitivesCodegen : RegionCodegen("Setting.kt"), DefaultInvoke { + object PluginData_value_primitivesCodegen : RegionCodegen("PluginData.kt"), DefaultInvoke { @JvmStatic fun main(args: Array<String>) = super.startIndependently() override val defaultInvokeArgs: List<KtType> = KtPrimitives + KtString @@ -145,9 +145,13 @@ internal fun Setting.${ktType.lowerCaseName}ValueImpl(): SerializerAwareValue<${ @Suppress("unused") appendKCode( """ - public fun Setting.value(default: ${ktType.standardName}): SerializerAwareValue<${ktType.standardName}> = valueImpl(default) + /** + * 创建一个 [${ktType.standardName}] 类型的 [Value], 并设置初始值为 [default] + */ + public fun PluginData.value(default: ${ktType.standardName}): SerializerAwareValue<${ktType.standardName}> = valueImpl(default) """ ) + appendLine() } } @@ -158,7 +162,7 @@ internal fun Setting.${ktType.lowerCaseName}ValueImpl(): SerializerAwareValue<${ @OptIn(ExperimentalStdlibApi::class) @JvmStatic fun main(args: Array<String>) { - ValueSettingCodegen::class.nestedClasses + ValuePluginDataCodegen::class.nestedClasses .filter { it.isSubclassOf(RegionCodegen::class) } .associateWith { kClass -> kClass.functions.find { it.name == "main" && it.hasAnnotation<JvmStatic>() } } .filter { it.value != null } diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/JSettingCodegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/JSettingCodegen.kt index d9a33b193..54a0ade77 100644 --- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/JSettingCodegen.kt +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/JSettingCodegen.kt @@ -12,7 +12,7 @@ package net.mamoe.mirai.console.codegen.old /** - * used to generate Java Setting + * used to generate Java PluginData */ @@ -48,7 +48,7 @@ internal val J_EXTRA = listOf( fun JClazz.getTemplate(): String = """ @NotNull default Value<${this.packageName}> $funName(${this.primitiveName} defaultValue){ - return _SettingKt.value(this,defaultValue); + return _PluginDataKt.value(this,defaultValue); } """ @@ -61,7 +61,7 @@ fun main() { appendLine() appendLine( "/**\n" + - " * !!! This file is auto-generated by backend/codegen/src/kotlin/net.mamoe.mirai.console.codegen.JSettingCodegen.kt\n" + + " * !!! This file is auto-generated by backend/codegen/src/kotlin/net.mamoe.mirai.console.codegen.JPluginDataCodegen.kt\n" + " * !!! DO NOT MODIFY THIS FILE MANUALLY\n" + " */\n" + "\"\"\"" diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/SettingValueUseSiteCodegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/SettingValueUseSiteCodegen.kt index 68aa3818e..3d81a1d0c 100644 --- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/SettingValueUseSiteCodegen.kt +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/SettingValueUseSiteCodegen.kt @@ -18,7 +18,7 @@ import java.io.File fun main() { println(File("").absolutePath) // default project base dir - File("backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/_Setting.kt").apply { + File("backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/_PluginData.kt").apply { createNewFile() }.writeText(buildString { appendLine(COPYRIGHT) @@ -39,20 +39,20 @@ fun main() { private val DO_NOT_MODIFY = """ /** - * !!! This file is auto-generated by backend/codegen/src/kotlin/net.mamoe.mirai.console.codegen.SettingValueUseSiteCodegen.kt + * !!! This file is auto-generated by backend/codegen/src/kotlin/net.mamoe.mirai.console.codegen.PluginDataValueUseSiteCodegen.kt * !!! DO NOT MODIFY THIS FILE MANUALLY */ """.trimIndent() private val PACKAGE = """ -package net.mamoe.mirai.console.setting +package net.mamoe.mirai.console.data """.trimIndent() internal val FILE_SUPPRESS = """ @file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "unused") """.trimIndent() private val IMPORTS = """ -import net.mamoe.mirai.console.setting.internal.valueImpl +import net.mamoe.mirai.console.data.internal.valueImpl import kotlin.internal.LowPriorityInOverloadResolution """.trimIndent() @@ -104,7 +104,7 @@ fun genAllValueUseSite(): String = buildString { appendln( """ @JvmName("valueMutable") - fun Setting.value(default: Mutable${collectionName}<${number}>): Mutable${number}${collectionName}Value = valueImpl(default) + fun PluginData.value(default: Mutable${collectionName}<${number}>): Mutable${number}${collectionName}Value = valueImpl(default) """.trimIndent() ) } @@ -114,30 +114,30 @@ fun genAllValueUseSite(): String = buildString { appendLine() appendln( """ - fun <T : Setting> Setting.value(default: T): Value<T> { + fun <T : PluginData> PluginData.value(default: T): Value<T> { require(this::class != default::class) { "Recursive nesting is prohibited" } return valueImpl(default).also { - if (default is Setting.NestedSetting) { + if (default is PluginData.NestedPluginData) { default.attachedValue = it } } } - inline fun <T : Setting> Setting.value(default: T, crossinline initializer: T.() -> Unit): Value<T> = + inline fun <T : PluginData> PluginData.value(default: T, crossinline initializer: T.() -> Unit): Value<T> = value(default).also { it.value.apply(initializer) } - inline fun <reified T : Setting> Setting.value(default: List<T>): SettingListValue<T> = valueImpl(default) + inline fun <reified T : PluginData> PluginData.value(default: List<T>): PluginDataListValue<T> = valueImpl(default) @JvmName("valueMutable") - inline fun <reified T : Setting> Setting.value(default: MutableList<T>): MutableSettingListValue<T> = valueImpl(default) + inline fun <reified T : PluginData> PluginData.value(default: MutableList<T>): MutablePluginDataListValue<T> = valueImpl(default) - inline fun <reified T : Setting> Setting.value(default: Set<T>): SettingSetValue<T> = valueImpl(default) + inline fun <reified T : PluginData> PluginData.value(default: Set<T>): PluginDataSetValue<T> = valueImpl(default) @JvmName("valueMutable") - inline fun <reified T : Setting> Setting.value(default: MutableSet<T>): MutableSettingSetValue<T> = valueImpl(default) + inline fun <reified T : PluginData> PluginData.value(default: MutableSet<T>): MutablePluginDataSetValue<T> = valueImpl(default) /** * 创建一个只引用对象而不跟踪其属性的值. @@ -147,7 +147,7 @@ fun genAllValueUseSite(): String = buildString { @DangerousReferenceOnlyValue @JvmName("valueDynamic") @LowPriorityInOverloadResolution - inline fun <reified T : Any> Setting.value(default: T): Value<T> = valueImpl(default) + inline fun <reified T : Any> PluginData.value(default: T): Value<T> = valueImpl(default) @RequiresOptIn( ""${'"'} @@ -164,6 +164,6 @@ fun genAllValueUseSite(): String = buildString { fun genValueUseSite(kotlinTypeName: String, miraiValueName: String): String = """ - fun Setting.value(default: $kotlinTypeName): ${miraiValueName}Value = valueImpl(default) + fun PluginData.value(default: $kotlinTypeName): ${miraiValueName}Value = valueImpl(default) """.trimIndent() diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/ValueImplCodegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/ValueImplCodegen.kt index a13681156..5d484784f 100644 --- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/ValueImplCodegen.kt +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/ValueImplCodegen.kt @@ -18,7 +18,7 @@ import java.io.File fun main() { println(File("").absolutePath) // default project base dir - File("backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_ValueImpl.kt").apply { + File("backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/internal/_ValueImpl.kt").apply { createNewFile() }.writeText(buildString { appendLine(COPYRIGHT) @@ -43,13 +43,13 @@ private val DO_NOT_MODIFY = """ """.trimIndent() private val PACKAGE = """ -package net.mamoe.mirai.console.setting.internal +package net.mamoe.mirai.console.data.internal """.trimIndent() private val IMPORTS = """ import kotlinx.serialization.* import kotlinx.serialization.builtins.* -import net.mamoe.mirai.console.setting.* +import net.mamoe.mirai.console.data.* """.trimIndent() fun genAllValueImpl(): String = buildString { @@ -121,7 +121,7 @@ fun genAllValueImpl(): String = buildString { appendln( """ @JvmName("valueImplMutable${number}${collectionName}") - internal fun Setting.valueImpl( + internal fun PluginData.valueImpl( default: Mutable${collectionName}<${number}> ): Mutable${number}${collectionName}Value { var internalValue: Mutable${collectionName}<${number}> = default @@ -166,8 +166,8 @@ fun genAllValueImpl(): String = buildString { appendln( """ - internal fun <T : Setting> Setting.valueImpl(default: T): Value<T> { - return object : SettingValue<T>() { + internal fun <T : PluginData> PluginData.valueImpl(default: T): Value<T> { + return object : PluginDataValue<T>() { private var internalValue: T = default override var value: T get() = internalValue @@ -187,7 +187,7 @@ fun genAllValueImpl(): String = buildString { } override fun serialize(encoder: Encoder, value: T) { - internalValue.updaterSerializer.serialize(encoder, SettingSerializerMark) + internalValue.updaterSerializer.serialize(encoder, PluginDataSerializerMark) } } } @@ -203,20 +203,20 @@ fun genPrimitiveValueImpl( isArray: Boolean ): String = """ - internal fun Setting.valueImpl(default: ${kotlinTypeName}): ${miraiValueName}Value { + internal fun PluginData.valueImpl(default: ${kotlinTypeName}): ${miraiValueName}Value { return object : ${miraiValueName}Value() { private var internalValue: $kotlinTypeName = default override var value: $kotlinTypeName get() = internalValue set(new) { ${ - if (isArray) """ + if (isArray) """ if (!new.contentEquals(internalValue)) { internalValue = new onElementChanged(this) } """.trim() - else """ + else """ if (new != internalValue) { internalValue = new onElementChanged(this) @@ -238,7 +238,7 @@ fun genCollectionValueImpl( isArray: Boolean ): String = """ - internal fun Setting.valueImpl(default: ${kotlinTypeName}): ${miraiValueName}Value { + internal fun PluginData.valueImpl(default: ${kotlinTypeName}): ${miraiValueName}Value { var internalValue: $kotlinTypeName = default val delegt = dynamic$collectionName { internalValue } return object : ${miraiValueName}Value(), $kotlinTypeName by delegt { @@ -246,13 +246,13 @@ fun genCollectionValueImpl( get() = internalValue set(new) { ${ - if (isArray) """ + if (isArray) """ if (!new.contentEquals(internalValue)) { internalValue = new onElementChanged(this) } """.trim() - else """ + else """ if (new != internalValue) { internalValue = new onElementChanged(this) diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/ValuesCodegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/ValuesCodegen.kt index 9e780e909..dbdd443cc 100644 --- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/ValuesCodegen.kt +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/ValuesCodegen.kt @@ -17,7 +17,7 @@ import java.io.File fun main() { println(File("").absolutePath) // default project base dir - File("backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/_Value.kt").apply { + File("backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/_Value.kt").apply { createNewFile() }.writeText(genPublicApi()) } @@ -64,7 +64,7 @@ fun genPublicApi() = buildString { appendLine() appendln( """ - package net.mamoe.mirai.console.setting + package net.mamoe.mirai.console.data import kotlinx.serialization.KSerializer import kotlin.properties.ReadWriteProperty @@ -85,15 +85,15 @@ fun genPublicApi() = buildString { appendln( """ -sealed class Value<T : Any> : ReadWriteProperty<Setting, T> { +sealed class Value<T : Any> : ReadWriteProperty<PluginData, T> { abstract var value: T /** * 用于更新 [value] 的序列化器 */ abstract val serializer: KSerializer<T> - override fun getValue(thisRef: Setting, property: KProperty<*>): T = value - override fun setValue(thisRef: Setting, property: KProperty<*>, value: T) { + override fun getValue(thisRef: PluginData, property: KProperty<*>): T = value + override fun setValue(thisRef: PluginData, property: KProperty<*>, value: T) { this.value = value } @@ -212,7 +212,7 @@ sealed class Value<T : Any> : ReadWriteProperty<Setting, T> { // SETTING appendln( """ - abstract class Setting${collectionName}Value<T: Setting> internal constructor() : Value<${collectionName}<T>>(), ${collectionName}<T> + abstract class PluginData${collectionName}Value<T: PluginData> internal constructor() : Value<${collectionName}<T>>(), ${collectionName}<T> """ ) appendLine() @@ -222,7 +222,7 @@ sealed class Value<T : Any> : ReadWriteProperty<Setting, T> { appendln( """ - abstract class SettingValue<T : Setting> internal constructor() : Value<T>() + abstract class PluginDataValue<T : PluginData> internal constructor() : Value<T>() """ ) @@ -250,7 +250,7 @@ sealed class Value<T : Any> : ReadWriteProperty<Setting, T> { // SETTING appendln( """ - abstract class MutableSetting${collectionName}Value<T: Setting> internal constructor() : Value<Mutable${collectionName}<T>>(), Mutable${collectionName}<T> + abstract class MutablePluginData${collectionName}Value<T: PluginData> internal constructor() : Value<Mutable${collectionName}<T>>(), Mutable${collectionName}<T> """ ) appendLine() diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt index 38145751b..fc01c86b7 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt @@ -14,6 +14,7 @@ package net.mamoe.mirai.console import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job +import net.mamoe.mirai.Bot import net.mamoe.mirai.console.MiraiConsole.INSTANCE import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge import net.mamoe.mirai.console.plugin.PluginLoader @@ -21,6 +22,7 @@ import net.mamoe.mirai.console.plugin.center.PluginCenter import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader import net.mamoe.mirai.console.util.ConsoleExperimentalAPI import net.mamoe.mirai.console.util.ConsoleInternalAPI +import net.mamoe.mirai.utils.BotConfiguration import net.mamoe.mirai.utils.MiraiLogger import java.io.File import java.util.* @@ -72,7 +74,24 @@ public interface MiraiConsole : CoroutineScope { */ // MiraiConsole.INSTANCE.getJob() public val job: Job get() = MiraiConsole.coroutineContext[Job] - ?: error("Internal error: Job not found in MiraiConsole.coroutineContext") + ?: throw IllegalMiraiConsoleImplementationError("Internal error: Job not found in MiraiConsole.coroutineContext") + + /** + * 添加一个 [Bot] 实例到全局 Bot 列表, 但不登录. + * + * 调用 [Bot.login] 可登录. + * + * @see Bot.botInstances 获取现有 [Bot] 实例列表 + */ + // don't static + @ConsoleExperimentalAPI("This is a low-level API and might be removed in the future.") + public fun addBot(id: Long, password: String, configuration: BotConfiguration.() -> Unit = {}): Bot = + Bot(id, password) { + fileBasedDeviceInfo() + this.loginSolver = frontEnd.createLoginSolver() + redirectNetworkLogToDirectory() + configuration() + } } } diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleImplementation.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleImplementation.kt index 217a86de1..3e4680a8e 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleImplementation.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleImplementation.kt @@ -15,10 +15,10 @@ import kotlinx.atomicfu.locks.withLock import kotlinx.coroutines.CoroutineScope import net.mamoe.mirai.console.MiraiConsoleImplementation.Companion.start import net.mamoe.mirai.console.command.ConsoleCommandSender +import net.mamoe.mirai.console.data.PluginDataStorage import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge import net.mamoe.mirai.console.plugin.PluginLoader import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader -import net.mamoe.mirai.console.setting.SettingStorage import net.mamoe.mirai.console.util.ConsoleExperimentalAPI import net.mamoe.mirai.utils.MiraiLogger import java.io.File @@ -75,8 +75,8 @@ public interface MiraiConsoleImplementation : CoroutineScope { public val consoleCommandSender: ConsoleCommandSender - public val settingStorageForJarPluginLoader: SettingStorage - public val settingStorageForBuiltIns: SettingStorage + public val dataStorageForJarPluginLoader: PluginDataStorage + public val dataStorageForBuiltIns: PluginDataStorage public companion object { internal lateinit var instance: MiraiConsoleImplementation diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/AbstractPluginData.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/AbstractPluginData.kt new file mode 100644 index 000000000..34797fe68 --- /dev/null +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/AbstractPluginData.kt @@ -0,0 +1,57 @@ +/* + * Copyright 2019-2020 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions license that can be found via the following link. + * + * https://github.com/mamoe/mirai/blob/master/LICENSE + */ + +@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "EXPOSED_SUPER_CLASS", "NOTHING_TO_INLINE") + +package net.mamoe.mirai.console.data + +import kotlinx.serialization.KSerializer +import net.mamoe.mirai.console.data.PluginData.ValueNode +import net.mamoe.mirai.console.internal.data.PluginDataImpl +import net.mamoe.mirai.console.internal.data.serialName +import net.mamoe.mirai.console.util.ConsoleExperimentalAPI +import kotlin.reflect.KProperty + +/** + * [PluginData] 的默认实现. 支持使用 `by value()` 等委托方法创建 [Value] 并跟踪其改动. + * + * @see PluginData + */ +public abstract class AbstractPluginData : PluginData, PluginDataImpl() { + /** + * 添加了追踪的 [ValueNode] 列表, 即通过 `by value` 初始化的属性列表. + * + * 他们的修改会被跟踪, 并触发 [onValueChanged]. + * + * @see provideDelegate + */ + public override val valueNodes: MutableList<ValueNode<*>> = mutableListOf() + + /** + * 使用 `by` 时自动调用此方法, 添加对 [Value] 的值修改的跟踪. + * + * 将会创建一个 [ValueNode] 并添加到 [valueNodes] + */ + public final override operator fun <T> SerializerAwareValue<T>.provideDelegate( + thisRef: Any?, + property: KProperty<*> + ): SerializerAwareValue<T> = apply { valueNodes.add(ValueNode(property.serialName, this, this.serializer)) } + + /** + * 值更新序列化器. 仅供内部使用. + */ + @ConsoleExperimentalAPI + public final override val updaterSerializer: KSerializer<Unit> + get() = super.updaterSerializer + + /** + * 当所属于这个 [PluginData] 的 [Value] 的 [值][Value.value] 被修改时被调用. + */ + public abstract override fun onValueChanged(value: Value<*>) +} \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginConfig.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginConfig.kt new file mode 100644 index 000000000..a2a0ec216 --- /dev/null +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginConfig.kt @@ -0,0 +1,17 @@ +/* + * Copyright 2019-2020 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions license that can be found via the following link. + * + * https://github.com/mamoe/mirai/blob/master/LICENSE + */ + +package net.mamoe.mirai.console.data + +/** + * 一个插件的配置数据, 用于和用户交互. + * + * 用户可通过 mirai-console 前端修改这些配置, 修改会自动写入这个对象中. + */ +public interface PluginConfig : PluginData \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginData.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginData.kt new file mode 100644 index 000000000..73e26021e --- /dev/null +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginData.kt @@ -0,0 +1,232 @@ +/* + * Copyright 2019-2020 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions license that can be found via the following link. + * + * https://github.com/mamoe/mirai/blob/master/LICENSE + */ + +@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "EXPOSED_SUPER_CLASS", "NOTHING_TO_INLINE") + +package net.mamoe.mirai.console.data + +import kotlinx.serialization.KSerializer +import net.mamoe.mirai.console.internal.data.createInstanceSmart +import net.mamoe.mirai.console.internal.data.typeOf0 +import net.mamoe.mirai.console.internal.data.valueFromKTypeImpl +import net.mamoe.mirai.console.internal.data.valueImpl +import net.mamoe.mirai.console.plugin.jvm.JvmPlugin +import net.mamoe.mirai.console.plugin.jvm.loadPluginData +import net.mamoe.mirai.console.util.ConsoleExperimentalAPI +import kotlin.internal.LowPriorityInOverloadResolution +import kotlin.reflect.KClass +import kotlin.reflect.KProperty +import kotlin.reflect.KType + + +/** + * 序列化之后的名称. + * + * 例: + * ``` + * @SerialName("accounts") + * object AccountPluginData : PluginData by ... { + * @SerialName("info") + * val map: Map<String, String> by value("a" to "b") + * } + * ``` + * + * 将被保存为配置 (YAML 作为示例): + * ```yaml + * accounts: + * info: + * a: b + * ``` + */ +public typealias SerialName = kotlinx.serialization.SerialName + +/** + * 一个插件内部的, 对用户隐藏的数据对象. 可包含对多个 [Value] 的值变更的跟踪. + * + * [PluginData] 不涉及有关数据的存储, 而是只维护数据结构: [属性节点列表][valueNodes]. + * + * 有关存储方案, 请查看 [PluginDataStorage] + * + * 在 [JvmPlugin] 的典型实现方式: + * ``` + * object PluginMain : KotlinPlugin() + * + * object AccountPluginData : PluginData by PluginMain.loadPluginData() { + * val map: Map<String, String> by value("a" to "b") + * } + * ``` + * + * @see JvmPlugin.loadPluginData 通过 [JvmPlugin] 获取指定 [PluginData] 实例. + * @see PluginDataStorage [PluginData] 存储仓库 + */ +public interface PluginData { + /** + * 添加了追踪的 [ValueNode] 列表 (即使用 `by value()` 委托的属性), 即通过 `by value` 初始化的属性列表. + * + * 他们的修改会被跟踪, 并触发 [onValueChanged]. + * + * @see provideDelegate + */ + public val valueNodes: MutableList<ValueNode<*>> + + /** + * 由 [provideDelegate] 创建, 来自一个通过 `by value` 初始化的属性节点. + */ + public data class ValueNode<T>( + /** + * 节点名称. + * + * 如果属性带有 [SerialName], 则使用 [kotlinx.serialization.SerialName.value], + * 否则使用 [属性名称][KProperty.name] + */ + val serialName: String, + /** + * 属性值代理 + */ + val value: Value<T>, + /** + * 属性值更新器 + * + * @suppress 注意, 这是实验性 API. + */ + @ConsoleExperimentalAPI + val updaterSerializer: KSerializer<Unit> + ) + + /** + * 使用 `by value()` 时自动调用此方法, 添加对 [Value] 的值修改的跟踪, 并创建 [ValueNode] 加入 [valueNodes] + */ + public operator fun <T> SerializerAwareValue<T>.provideDelegate( + thisRef: Any?, + property: KProperty<*> + ): SerializerAwareValue<T> + + /** + * 值更新序列化器. 仅供内部使用 + * + * @suppress 注意, 这是实验性 API. + */ + @ConsoleExperimentalAPI + public val updaterSerializer: KSerializer<Unit> + + /** + * 当所属于这个 [PluginData] 的 [Value] 的 [值][Value.value] 被修改时被调用. + */ + public fun onValueChanged(value: Value<*>) + + /** + * 当这个 [PluginData] 被放入一个 [PluginDataStorage] 时调用 + */ + public fun setStorage(storage: PluginDataStorage) +} + +/** + * 用于支持属性委托 + */ +@JvmSynthetic +public inline operator fun <T> Value<T>.getValue(thisRef: Any?, property: KProperty<*>): T = value + +/** + * 用于支持属性委托 + */ +@JvmSynthetic +public inline operator fun <T> Value<T>.setValue(thisRef: Any?, property: KProperty<*>, value: T) { + this.value = value +} + +//// region PluginData_value_primitives CODEGEN //// + +/** + * 创建一个 [Byte] 类型的 [Value], 并设置初始值为 [default] + */ +public fun PluginData.value(default: Byte): SerializerAwareValue<Byte> = valueImpl(default) + +/** + * 创建一个 [Short] 类型的 [Value], 并设置初始值为 [default] + */ +public fun PluginData.value(default: Short): SerializerAwareValue<Short> = valueImpl(default) + +/** + * 创建一个 [Int] 类型的 [Value], 并设置初始值为 [default] + */ +public fun PluginData.value(default: Int): SerializerAwareValue<Int> = valueImpl(default) + +/** + * 创建一个 [Long] 类型的 [Value], 并设置初始值为 [default] + */ +public fun PluginData.value(default: Long): SerializerAwareValue<Long> = valueImpl(default) + +/** + * 创建一个 [Float] 类型的 [Value], 并设置初始值为 [default] + */ +public fun PluginData.value(default: Float): SerializerAwareValue<Float> = valueImpl(default) + +/** + * 创建一个 [Double] 类型的 [Value], 并设置初始值为 [default] + */ +public fun PluginData.value(default: Double): SerializerAwareValue<Double> = valueImpl(default) + +/** + * 创建一个 [Char] 类型的 [Value], 并设置初始值为 [default] + */ +public fun PluginData.value(default: Char): SerializerAwareValue<Char> = valueImpl(default) + +/** + * 创建一个 [Boolean] 类型的 [Value], 并设置初始值为 [default] + */ +public fun PluginData.value(default: Boolean): SerializerAwareValue<Boolean> = valueImpl(default) + +/** + * 创建一个 [String] 类型的 [Value], 并设置初始值为 [default] + */ +public fun PluginData.value(default: String): SerializerAwareValue<String> = valueImpl(default) + +//// endregion PluginData_value_primitives CODEGEN //// + + +/** + * 通过具体化类型创建一个 [SerializerAwareValue], 并设置初始值. + * + * @param T 具体化参数类型 T. 仅支持: + * - 基础数据类型 + * - 标准库集合类型 ([List], [Map], [Set]) + * - 标准库数据类型 ([Map.Entry], [Pair], [Triple]) + * - 和使用 [kotlinx.serialization](https://github.com/Kotlin/kotlinx.serialization) 的 [Serializable] 标记的 + */ +@Suppress("UNCHECKED_CAST") +@LowPriorityInOverloadResolution +public inline fun <reified T> PluginData.value(default: T): SerializerAwareValue<T> = + valueFromKType(typeOf0<T>(), default) + +/** + * 通过具体化类型创建一个 [SerializerAwareValue]. + * @see valueFromKType 查看更多实现信息 + */ +@LowPriorityInOverloadResolution +public inline fun <reified T> PluginData.value(): SerializerAwareValue<T> = + value(T::class.run { objectInstance ?: createInstanceSmart() } as T) + +/** + * 通过一个特定的 [KType] 创建 [Value], 并设置初始值. + * + * 对于 [List], [Map], [Set] 等标准库类型, 这个函数会尝试构造 [LinkedHashMap] 等相关类型. + * 而对于自定义数据类型, 本函数只会反射获取 [objectInstance][KClass.objectInstance] 或使用无参构造器构造实例. + * + * @param T 具体化参数类型 T. 仅支持: + * - 基础数据类型 + * - 标准库集合类型 ([List], [Map], [Set]) + * - 标准库数据类型 ([Map.Entry], [Pair], [Triple]) + * - 和使用 [kotlinx.serialization](https://github.com/Kotlin/kotlinx.serialization) 的 [Serializable] 标记的 + */ +@Suppress("UNCHECKED_CAST") +@ConsoleExperimentalAPI +public fun <T> PluginData.valueFromKType(type: KType, default: T): SerializerAwareValue<T> = + (valueFromKTypeImpl(type) as SerializerAwareValue<Any?>).apply { this.value = default } as SerializerAwareValue<T> + +// TODO: 2020/6/24 Introduce class TypeToken for compound types for Java. \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginDataHolder.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginDataHolder.kt new file mode 100644 index 000000000..ef46b3e12 --- /dev/null +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginDataHolder.kt @@ -0,0 +1,84 @@ +@file:Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST", "unused") + +package net.mamoe.mirai.console.data + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import net.mamoe.mirai.console.data.PluginDataStorage.Companion.load +import net.mamoe.mirai.console.internal.data.AutoSavePluginData +import net.mamoe.mirai.console.internal.data.cast +import net.mamoe.mirai.console.internal.data.newPluginDataInstanceUsingReflection +import net.mamoe.mirai.console.internal.data.typeOf0 +import kotlin.reflect.KClass +import kotlin.reflect.KType +import kotlin.reflect.full.createType + +/** + * 可以持有相关 [PluginData] 实例的对象, 作为 [PluginData] 实例的拥有者. + * + * @see PluginDataStorage.load + * @see PluginDataStorage.store + * + * @see AutoSavePluginDataHolder 自动保存 + */ +public interface PluginDataHolder { + /** + * 保存时使用的分类名 + */ + public val name: String + + /** + * 创建一个 [PluginData] 实例. + * + * @see Companion.newPluginDataInstance + * @see KClass.createType + */ + @JvmDefault + public fun <T : PluginData> newPluginDataInstance(type: KType): T = + newPluginDataInstanceUsingReflection<PluginData>(type) as T + + public companion object { + /** + * 创建一个 [PluginData] 实例. + * + * @see PluginDataHolder.newPluginDataInstance + */ + @JvmSynthetic + public inline fun <reified T : PluginData> PluginDataHolder.newPluginDataInstance(): T { + return this.newPluginDataInstance(typeOf0<T>()) + } + } +} + +/** + * 可以持有相关 [AutoSavePluginData] 的对象. + * + * @see net.mamoe.mirai.console.plugin.jvm.JvmPlugin + */ +public interface AutoSavePluginDataHolder : PluginDataHolder, CoroutineScope { + /** + * [AutoSavePluginData] 每次自动保存时间间隔 + * + * - 区间的左端点为最小间隔, 一个 [Value] 被修改后, 若此时间段后无其他修改, 将触发自动保存; 若有, 将重新开始计时. + * - 区间的右端点为最大间隔, 一个 [Value] 被修改后, 最多不超过这个时间段后就会被保存. + * + * 若 [AutoSavePluginDataHolder.coroutineContext] 含有 [Job], + * 则 [AutoSavePluginData] 会通过 [Job.invokeOnCompletion] 在 Job 完结时触发自动保存. + * + * @see LongRange Java 用户使用 [LongRange] 的构造器创建 + * @see Long.rangeTo Kotlin 用户使用 [Long.rangeTo] 创建, 如 `3000..50000` + */ + public val autoSaveIntervalMillis: LongRange + + /** + * 仅支持确切的 [PluginData] 类型 + */ + @JvmDefault + public override fun <T : PluginData> newPluginDataInstance(type: KType): T { + val classifier = type.classifier?.cast<KClass<PluginData>>() + require(classifier != null && classifier.java == PluginData::class.java) { + "Cannot create PluginData instance. AutoSavePluginDataHolder supports only PluginData type." + } + return AutoSavePluginData(this, classifier) as T // T is always PluginData + } +} \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginDataStorage.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginDataStorage.kt new file mode 100644 index 000000000..0782c983a --- /dev/null +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginDataStorage.kt @@ -0,0 +1,115 @@ +/* + * Copyright 2019-2020 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions license that can be found via the following link. + * + * https://github.com/mamoe/mirai/blob/master/LICENSE + */ + +@file:Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST", "unused") + +package net.mamoe.mirai.console.data + +import net.mamoe.mirai.console.internal.data.MemoryPluginDataStorageImpl +import net.mamoe.mirai.console.internal.data.MultiFilePluginDataStorageImpl +import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader +import net.mamoe.mirai.console.plugin.jvm.JvmPlugin +import java.io.File +import kotlin.reflect.KClass + +/** + * [PluginData] 存储仓库. + * + * 此为较低层的 API, 一般插件开发者不会接触. + * + * [JarPluginLoader] 实现一个 [PluginDataStorage], 用于管理所有 [JvmPlugin] 的 [PluginData] 实例. + * + * @see PluginDataHolder + * @see JarPluginLoader.dataStorage + */ +public interface PluginDataStorage { + /** + * 读取一个实例. 在 [T] 实例创建后 [设置 [PluginDataStorage]][PluginData.setStorage] + */ + public fun <T : PluginData> load(holder: PluginDataHolder, dataClass: Class<T>): T + + /** + * 保存一个实例 + */ + public fun store(holder: PluginDataHolder, pluginData: PluginData) + + public companion object { + /** + * 读取一个实例. 在 [T] 实例创建后 [设置 [PluginDataStorage]][PluginData.setStorage] + */ + @JvmStatic + public fun <T : PluginData> PluginDataStorage.load(holder: PluginDataHolder, dataClass: KClass<T>): T = + this.load(holder, dataClass.java) + + /** + * 读取一个实例. 在 [T] 实例创建后 [设置 [PluginDataStorage]][PluginData.setStorage] + */ + @JvmSynthetic + public inline fun <reified T : PluginData> PluginDataStorage.load(holder: PluginDataHolder): T = + this.load(holder, T::class) + } +} + +/** + * 在内存存储所有 [PluginData] 实例的 [PluginDataStorage]. 在内存数据丢失后相关 [PluginData] 实例也会丢失. + * @see PluginDataStorage + */ +public interface MemoryPluginDataStorage : PluginDataStorage, Map<Class<out PluginData>, PluginData> { + /** + * 当任一 [PluginData] 实例拥有的 [Value] 的值被改变后调用的回调函数. + */ + public fun interface OnChangedCallback { + public fun onChanged(storage: MemoryPluginDataStorage, value: Value<*>) + + /** + * 无任何操作的 [OnChangedCallback] + * @see OnChangedCallback + */ + public object NoOp : OnChangedCallback { + public override fun onChanged(storage: MemoryPluginDataStorage, value: Value<*>) { + // no-op + } + } + } + + public companion object { + /** + * 创建一个 [MemoryPluginDataStorage] 实例. + * + * @param onChanged 当任一 [PluginData] 实例拥有的 [Value] 的值被改变后调用的回调函数. + */ + @JvmStatic + @JvmName("create") + // @JvmOverloads + public operator fun invoke(onChanged: OnChangedCallback = OnChangedCallback.NoOp): MemoryPluginDataStorage = + MemoryPluginDataStorageImpl(onChanged) + } +} + +/** + * 用多个文件存储 [PluginData] 实例的 [PluginDataStorage]. + */ +public interface MultiFilePluginDataStorage : PluginDataStorage { + /** + * 存放 [PluginData] 的目录. + */ + public val directory: File + + public companion object { + /** + * 创建一个 [MultiFilePluginDataStorage] 实例. + * + * @see directory 存放 [PluginData] 的目录. + */ + @JvmStatic + @JvmName("create") + public operator fun invoke(directory: File): MultiFilePluginDataStorage = + MultiFilePluginDataStorageImpl(directory) + } +} diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/Value.kt similarity index 89% rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/Value.kt index b37bcd6f2..62aa495d8 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/Value.kt @@ -9,23 +9,24 @@ @file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "unused", "NOTHING_TO_INLINE") -package net.mamoe.mirai.console.setting +package net.mamoe.mirai.console.data import kotlinx.serialization.BinaryFormat import kotlinx.serialization.KSerializer import kotlinx.serialization.StringFormat -import net.mamoe.mirai.console.internal.setting.map -import net.mamoe.mirai.console.internal.setting.setValueBySerializer +import net.mamoe.mirai.console.internal.data.map +import net.mamoe.mirai.console.internal.data.setValueBySerializer import net.mamoe.mirai.console.util.ConsoleExperimentalAPI -import kotlin.reflect.KProperty /** - * 表示一个可被观测的, 不可变的值包装. + * 表示一个值代理. * - * [Value.value] 可以像 Kotlin 的 `var` 一样被修改, 然而它也可能被用户修改, 如通过 UI 前端. + * [Value.value] 可以像 Kotlin 的 `var` 一样被修改, 然而它也可能被用户修改, 如通过 UI 前端, 或通过自动重载. * * 一些常用的基础类型实现由代码生成创建特性的优化. * + * @see PluginData 容纳 [Value] 的数据对象 + * * @see PrimitiveValue 基础数据类型实现 * @see CompositeValue 复合数据类型实现 */ @@ -39,7 +40,7 @@ public interface Value<T> { public class SerializableValue<T>( private val delegate: Value<T>, /** - * The serializer used to update and dump [delegate] + * 用于更新和保存 [delegate] 的序列化器 */ public override val serializer: KSerializer<Unit> ) : Value<T> by delegate, SerializerAwareValue<T> { @@ -63,7 +64,7 @@ public class SerializableValue<T>( * 带有显式 [序列化器][serializer] 的 [Value]. * * @see SerializableValue 简单实现 - * @see Setting.value 创建一个这样的 [SerializerAwareValue] + * @see PluginData.value 创建一个这样的 [SerializerAwareValue] */ public interface SerializerAwareValue<T> : Value<T> { /** @@ -109,20 +110,6 @@ public interface SerializerAwareValue<T> : Value<T> { } } -/** - * 用于支持属性委托 - */ -@JvmSynthetic -public inline operator fun <T> Value<T>.getValue(mySetting: Any?, property: KProperty<*>): T = value - -/** - * 用于支持属性委托 - */ -@JvmSynthetic -public inline operator fun <T> Value<T>.setValue(mySetting: Any?, property: KProperty<*>, value: T) { - this.value = value -} - /** * 基础数据类型 [Value] * @@ -144,42 +131,34 @@ public interface PrimitiveValue<T> : Value<T> * 表示一个不可空 [Byte] [Value]. */ public interface ByteValue : PrimitiveValue<Byte> - /** * 表示一个不可空 [Short] [Value]. */ public interface ShortValue : PrimitiveValue<Short> - /** * 表示一个不可空 [Int] [Value]. */ public interface IntValue : PrimitiveValue<Int> - /** * 表示一个不可空 [Long] [Value]. */ public interface LongValue : PrimitiveValue<Long> - /** * 表示一个不可空 [Float] [Value]. */ public interface FloatValue : PrimitiveValue<Float> - /** * 表示一个不可空 [Double] [Value]. */ public interface DoubleValue : PrimitiveValue<Double> - /** * 表示一个不可空 [Char] [Value]. */ public interface CharValue : PrimitiveValue<Char> - /** * 表示一个不可空 [Boolean] [Value]. */ public interface BooleanValue : PrimitiveValue<Boolean> - /** * 表示一个不可空 [String] [Value]. */ diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/MiraiConsoleImplementationBridge.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/MiraiConsoleImplementationBridge.kt index 6b41969a9..273ab3744 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/MiraiConsoleImplementationBridge.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/MiraiConsoleImplementationBridge.kt @@ -22,13 +22,13 @@ import net.mamoe.mirai.console.command.BuiltInCommands import net.mamoe.mirai.console.command.Command.Companion.primaryName import net.mamoe.mirai.console.command.CommandManagerImpl import net.mamoe.mirai.console.command.ConsoleCommandSender +import net.mamoe.mirai.console.data.PluginDataStorage import net.mamoe.mirai.console.internal.plugin.CuiPluginCenter import net.mamoe.mirai.console.internal.plugin.PluginManagerImpl -import net.mamoe.mirai.console.internal.utils.ConsoleBuiltInSettingStorage +import net.mamoe.mirai.console.internal.utils.ConsoleBuiltInPluginDataStorage import net.mamoe.mirai.console.plugin.PluginLoader import net.mamoe.mirai.console.plugin.PluginManager import net.mamoe.mirai.console.plugin.center.PluginCenter -import net.mamoe.mirai.console.setting.SettingStorage import net.mamoe.mirai.console.util.ConsoleExperimentalAPI import net.mamoe.mirai.utils.DefaultLogger import net.mamoe.mirai.utils.MiraiLogger @@ -58,8 +58,8 @@ internal object MiraiConsoleImplementationBridge : CoroutineScope, MiraiConsoleI override val builtInPluginLoaders: List<PluginLoader<*, *>> get() = instance.builtInPluginLoaders override val consoleCommandSender: ConsoleCommandSender get() = instance.consoleCommandSender - override val settingStorageForJarPluginLoader: SettingStorage get() = instance.settingStorageForJarPluginLoader - override val settingStorageForBuiltIns: SettingStorage get() = instance.settingStorageForBuiltIns + override val dataStorageForJarPluginLoader: PluginDataStorage get() = instance.dataStorageForJarPluginLoader + override val dataStorageForBuiltIns: PluginDataStorage get() = instance.dataStorageForBuiltIns init { DefaultLogger = { identity -> this.newLogger(identity) } @@ -91,7 +91,7 @@ internal object MiraiConsoleImplementationBridge : CoroutineScope, MiraiConsoleI mainLogger.info { "${PluginManager.plugins.size} plugin(s) loaded." } mainLogger.info { "mirai-console started successfully." } - ConsoleBuiltInSettingStorage // init + ConsoleBuiltInPluginDataStorage // init // Only for initialize } } \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/command/internal.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/command/internal.kt index f0aea62fa..d90a3a281 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/command/internal.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/command/internal.kt @@ -10,8 +10,10 @@ package net.mamoe.mirai.console.internal.command import net.mamoe.mirai.console.command.* +import net.mamoe.mirai.console.command.description.CommandArgumentParserException import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.Member +import net.mamoe.mirai.contact.nameCardOrNick internal infix fun Array<String>.matchesBeginning(list: List<Any>): Boolean { @@ -61,9 +63,6 @@ internal inline fun <T : Any> Collection<T>.fuzzySearch( target: String, index: (T) -> String ): T? { - if (this.isEmpty()) { - return null - } var potential: T? = null var rate = 0.0 this.forEach { @@ -90,9 +89,6 @@ internal inline fun <T : Any> Collection<T>.fuzzySearchOnly( target: String, index: (T) -> String ): T? { - if (this.isEmpty()) { - return null - } var potential: T? = null var rate = 0.0 var collide = 0 @@ -115,9 +111,7 @@ internal inline fun <T : Any> Collection<T>.fuzzySearchOnly( internal fun Group.fuzzySearchMember(nameCardTarget: String): Member? { - return this.members.fuzzySearchOnly(nameCardTarget) { - it.nameCard - } + return this.members.fuzzySearch(nameCardTarget) { it.nameCardOrNick } } @@ -159,7 +153,10 @@ internal suspend inline fun CommandSender.executeCommandInternal( kotlin.runCatching { command.onCommand(this, args) }.onFailure { - throw CommandExecutionException(command, commandName, it) + catchExecutionException(it) + if (it !is CommandArgumentParserException) { + throw CommandExecutionException(command, commandName, it) + } } } diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/CompositeValueImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/CompositeValueImpl.kt similarity index 94% rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/CompositeValueImpl.kt rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/CompositeValueImpl.kt index cc3f308e7..b7df66e71 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/CompositeValueImpl.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/CompositeValueImpl.kt @@ -9,13 +9,13 @@ @file:Suppress("unused") -package net.mamoe.mirai.console.internal.setting +package net.mamoe.mirai.console.internal.data -import net.mamoe.mirai.console.setting.* +import net.mamoe.mirai.console.data.* // type inference bug -internal fun <T> Setting.createCompositeSetValueImpl(tToValue: (T) -> Value<T>): CompositeSetValueImpl<T> { +internal fun <T> PluginData.createCompositeSetValueImpl(tToValue: (T) -> Value<T>): CompositeSetValueImpl<T> { return object : CompositeSetValueImpl<T>(tToValue) { override fun onChanged() { this@createCompositeSetValueImpl.onValueChanged(this) @@ -62,7 +62,7 @@ internal abstract class CompositeSetValueImpl<T>( // type inference bug -internal fun <T> Setting.createCompositeListValueImpl(tToValue: (T) -> Value<T>): CompositeListValueImpl<T> { +internal fun <T> PluginData.createCompositeListValueImpl(tToValue: (T) -> Value<T>): CompositeListValueImpl<T> { return object : CompositeListValueImpl<T>(tToValue) { override fun onChanged() { this@createCompositeListValueImpl.onValueChanged(this) @@ -108,7 +108,7 @@ internal abstract class CompositeListValueImpl<T>( } // workaround to a type inference bug -internal fun <K, V> Setting.createCompositeMapValueImpl( +internal fun <K, V> PluginData.createCompositeMapValueImpl( kToValue: (K) -> Value<K>, vToValue: (V) -> Value<V> ): CompositeMapValueImpl<K, V> { diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/Setting.value composite impl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/PluginData.value composite impl.kt similarity index 92% rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/Setting.value composite impl.kt rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/PluginData.value composite impl.kt index 990e778f0..4bfb9ed43 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/Setting.value composite impl.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/PluginData.value composite impl.kt @@ -9,13 +9,13 @@ @file:Suppress("NOTHING_TO_INLINE", "INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") -package net.mamoe.mirai.console.internal.setting +package net.mamoe.mirai.console.internal.data import kotlinx.serialization.KSerializer -import net.mamoe.mirai.console.setting.SerializableValue.Companion.serializableValueWith -import net.mamoe.mirai.console.setting.SerializerAwareValue -import net.mamoe.mirai.console.setting.Setting -import net.mamoe.mirai.console.setting.valueFromKType +import net.mamoe.mirai.console.data.PluginData +import net.mamoe.mirai.console.data.SerializableValue.Companion.serializableValueWith +import net.mamoe.mirai.console.data.SerializerAwareValue +import net.mamoe.mirai.console.data.valueFromKType import kotlin.reflect.KClass import kotlin.reflect.KType import kotlin.reflect.full.createInstance as createInstanceKotlin @@ -30,7 +30,7 @@ internal inline fun <reified T> typeOf0(): KType = kotlin.reflect.typeOf<T>() @PublishedApi @Suppress("UnsafeCall", "SMARTCAST_IMPOSSIBLE", "UNCHECKED_CAST") -internal fun Setting.valueFromKTypeImpl(type: KType): SerializerAwareValue<*> { +internal fun PluginData.valueFromKTypeImpl(type: KType): SerializerAwareValue<*> { val classifier = type.classifier require(classifier is KClass<*>) diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/SettingImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/PluginDataImpl.kt similarity index 85% rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/SettingImpl.kt rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/PluginDataImpl.kt index 6afe1b203..88eb0b3cf 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/SettingImpl.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/PluginDataImpl.kt @@ -9,7 +9,7 @@ @file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "EXPOSED_SUPER_CLASS") -package net.mamoe.mirai.console.internal.setting +package net.mamoe.mirai.console.internal.data import kotlinx.serialization.KSerializer import kotlinx.serialization.SerialName @@ -19,9 +19,9 @@ import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.CompositeDecoder import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder -import net.mamoe.mirai.console.setting.AbstractSetting.ValueNode -import net.mamoe.mirai.console.setting.Setting -import net.mamoe.mirai.console.setting.Value +import net.mamoe.mirai.console.data.PluginData +import net.mamoe.mirai.console.data.PluginData.ValueNode +import net.mamoe.mirai.console.data.Value import net.mamoe.yamlkt.YamlNullableDynamicSerializer import kotlin.reflect.KProperty import kotlin.reflect.full.findAnnotation @@ -29,17 +29,17 @@ import kotlin.reflect.full.findAnnotation internal val KProperty<*>.serialName: String get() = this.findAnnotation<SerialName>()?.value ?: this.name /** - * Internal implementation for [Setting] including: + * Internal implementation for [PluginData] including: * - Reflection on Kotlin properties and Java fields * - Auto-saving */ -internal abstract class SettingImpl { +internal abstract class PluginDataImpl { internal fun findNodeInstance(name: String): ValueNode<*>? = valueNodes.firstOrNull { it.serialName == name } internal abstract val valueNodes: MutableList<ValueNode<*>> internal open val updaterSerializer: KSerializer<Unit> = object : KSerializer<Unit> { - override val descriptor: SerialDescriptor get() = settingUpdaterSerializerDescriptor + override val descriptor: SerialDescriptor get() = dataUpdaterSerializerDescriptor @Suppress("UNCHECKED_CAST") override fun deserialize(decoder: Decoder) { @@ -96,7 +96,7 @@ internal abstract class SettingImpl { with(encoder.beginCollection(descriptor, valueNodes.size)) { var index = 0 - // val vSerializer = settingUpdaterSerializerTypeArguments[1] as KSerializer<Any?> + // val vSerializer = dataUpdaterSerializerTypeArguments[1] as KSerializer<Any?> valueNodes.forEach { (serialName, _, valueSerializer) -> encodeSerializableElement(descriptor, index++, String.serializer(), serialName) encodeSerializableElement(descriptor, index++, valueSerializer, Unit) @@ -113,8 +113,8 @@ internal abstract class SettingImpl { abstract fun onValueChanged(value: Value<*>) companion object { - private val settingUpdaterSerializerTypeArguments = arrayOf(String.serializer(), YamlNullableDynamicSerializer) - private val settingUpdaterSerializerDescriptor = - MapSerializer(settingUpdaterSerializerTypeArguments[0], settingUpdaterSerializerTypeArguments[1]).descriptor + private val dataUpdaterSerializerTypeArguments = arrayOf(String.serializer(), YamlNullableDynamicSerializer) + private val dataUpdaterSerializerDescriptor = + MapSerializer(dataUpdaterSerializerTypeArguments[0], dataUpdaterSerializerTypeArguments[1]).descriptor } } \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/SettingStorage internal.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/PluginDataStorage internal.kt similarity index 59% rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/SettingStorage internal.kt rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/PluginDataStorage internal.kt index 04e4fcf31..b83886b02 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/SettingStorage internal.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/PluginDataStorage internal.kt @@ -7,14 +7,14 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -package net.mamoe.mirai.console.internal.setting +package net.mamoe.mirai.console.internal.data import kotlinx.atomicfu.atomic import kotlinx.coroutines.* +import net.mamoe.mirai.console.data.* import net.mamoe.mirai.console.internal.command.qualifiedNameOrTip import net.mamoe.mirai.console.internal.plugin.updateWhen -import net.mamoe.mirai.console.plugin.jvm.loadSetting -import net.mamoe.mirai.console.setting.* +import net.mamoe.mirai.console.plugin.jvm.loadPluginData import net.mamoe.mirai.console.util.ConsoleExperimentalAPI import net.mamoe.mirai.console.util.ConsoleInternalAPI import net.mamoe.mirai.utils.currentTimeMillis @@ -26,21 +26,21 @@ import kotlin.reflect.full.findAnnotation /** - * 链接自动保存的 [Setting]. + * 链接自动保存的 [PluginData]. * 当任一相关 [Value] 的值被修改时, 将在一段时间无其他修改时保存 * - * 若 [AutoSaveSettingHolder.coroutineContext] 含有 [Job], 则 [AutoSaveSetting] 会通过 [Job.invokeOnCompletion] 在 Job 完结时触发自动保存. + * 若 [AutoSavePluginDataHolder.coroutineContext] 含有 [Job], 则 [AutoSavePluginData] 会通过 [Job.invokeOnCompletion] 在 Job 完结时触发自动保存. * - * @see loadSetting + * @see loadPluginData */ -internal open class AutoSaveSetting( - private val owner: AutoSaveSettingHolder, - internal val originSettingClass: KClass<out Setting> +internal open class AutoSavePluginData( + private val owner: AutoSavePluginDataHolder, + internal val originPluginDataClass: KClass<out PluginData> ) : - AbstractSetting() { - private lateinit var storage: SettingStorage + AbstractPluginData() { + private lateinit var storage: PluginDataStorage - override fun setStorage(storage: SettingStorage) { + override fun setStorage(storage: PluginDataStorage) { check(!this::storage.isInitialized) { "storage is already initialized" } this.storage = storage } @@ -82,71 +82,71 @@ internal open class AutoSaveSetting( private fun doSave() = storage.store(owner, this) } -internal class MemorySettingStorageImpl( - private val onChanged: MemorySettingStorage.OnChangedCallback -) : SettingStorage, MemorySettingStorage, - MutableMap<Class<out Setting>, Setting> by mutableMapOf() { +internal class MemoryPluginDataStorageImpl( + private val onChanged: MemoryPluginDataStorage.OnChangedCallback +) : PluginDataStorage, MemoryPluginDataStorage, + MutableMap<Class<out PluginData>, PluginData> by mutableMapOf() { - internal inner class MemorySettingImpl : AbstractSetting() { + internal inner class MemoryPluginDataImpl : AbstractPluginData() { @ConsoleInternalAPI override fun onValueChanged(value: Value<*>) { - onChanged.onChanged(this@MemorySettingStorageImpl, value) + onChanged.onChanged(this@MemoryPluginDataStorageImpl, value) } - override fun setStorage(storage: SettingStorage) { - check(storage is MemorySettingStorageImpl) { "storage is not MemorySettingStorageImpl" } + override fun setStorage(storage: PluginDataStorage) { + check(storage is MemoryPluginDataStorageImpl) { "storage is not MemoryPluginDataStorageImpl" } } } @Suppress("UNCHECKED_CAST") - override fun <T : Setting> load(holder: SettingHolder, settingClass: Class<T>): T = (synchronized(this) { - this.getOrPut(settingClass) { - settingClass.kotlin.run { + override fun <T : PluginData> load(holder: PluginDataHolder, dataClass: Class<T>): T = (synchronized(this) { + this.getOrPut(dataClass) { + dataClass.kotlin.run { objectInstance ?: createInstanceOrNull() ?: kotlin.run { - if (settingClass != Setting::class.java) { + if (dataClass != PluginData::class.java) { throw IllegalArgumentException( - "Cannot create Setting instance. Make sure settingClass is Setting::class.java or a Kotlin's object, " + + "Cannot create PluginData instance. Make sure dataClass is PluginData::class.java or a Kotlin's object, " + "or has a constructor which either has no parameters or all parameters of which are optional" ) } - MemorySettingImpl() + MemoryPluginDataImpl() } } } } as T).also { it.setStorage(this) } - override fun store(holder: SettingHolder, setting: Setting) { + override fun store(holder: PluginDataHolder, pluginData: PluginData) { synchronized(this) { - this[setting::class.java] = setting + this[pluginData::class.java] = pluginData } } } @Suppress("RedundantVisibilityModifier") // might be public in the future -internal open class MultiFileSettingStorageImpl( +internal open class MultiFilePluginDataStorageImpl( public final override val directory: File -) : SettingStorage, MultiFileSettingStorage { +) : PluginDataStorage, MultiFilePluginDataStorage { init { directory.mkdir() } - public override fun <T : Setting> load(holder: SettingHolder, settingClass: Class<T>): T = - with(settingClass.kotlin) { + public override fun <T : PluginData> load(holder: PluginDataHolder, dataClass: Class<T>): T = + with(dataClass.kotlin) { @Suppress("UNCHECKED_CAST") val instance = objectInstance ?: this.createInstanceOrNull() ?: kotlin.run { - require(settingClass == Setting::class.java) { - "Cannot create Setting instance. Make sure settingClass is Setting::class.java or a Kotlin's object, " + + require(dataClass == PluginData::class.java) { + "Cannot create PluginData instance. Make sure dataClass is PluginData::class.java or a Kotlin's object, " + "or has a constructor which either has no parameters or all parameters of which are optional" } - if (holder is AutoSaveSettingHolder) { - AutoSaveSetting(holder, this) as T? + if (holder is AutoSavePluginDataHolder) { + AutoSavePluginData(holder, this) as T? } else null } ?: throw IllegalArgumentException( - "Cannot create Setting instance. Make sure 'holder' is a AutoSaveSettingHolder, " + - "or 'setting' is an object or has a constructor which either has no parameters or all parameters of which are optional" + "Cannot create PluginData instance. Make sure 'holder' is a AutoSavePluginDataHolder, " + + "or 'data' is an object or has a constructor which either has no parameters or all parameters of which are optional" ) - val file = getSettingFile(holder, this) + val file = getPluginDataFile(holder, this) file.createNewFile() check(file.exists() && file.isFile && file.canRead()) { "${file.absolutePath} cannot be read" } val text = file.readText() @@ -156,29 +156,32 @@ internal open class MultiFileSettingStorageImpl( instance }.also { it.setStorage(this) } - protected open fun getSettingFile(holder: SettingHolder, clazz: KClass<*>): File = with(clazz) { + protected open fun getPluginDataFile(holder: PluginDataHolder, clazz: KClass<*>): File = with(clazz) { val name = findASerialName() val dir = File(directory, holder.name) if (dir.isFile) { - error("Target directory ${dir.path} for holder $holder is occupied by a file therefore setting $qualifiedNameOrTip can't be saved.") + error("Target directory ${dir.path} for holder $holder is occupied by a file therefore data $qualifiedNameOrTip can't be saved.") } dir.mkdir() val file = File(directory, name) if (file.isDirectory) { - error("Target file $file is occupied by a directory therefore setting $qualifiedNameOrTip can't be saved.") + error("Target file $file is occupied by a directory therefore data $qualifiedNameOrTip can't be saved.") } return file } @ConsoleExperimentalAPI - public override fun store(holder: SettingHolder, setting: Setting) { + public override fun store(holder: PluginDataHolder, pluginData: PluginData) { val file = - getSettingFile(holder, if (setting is AutoSaveSetting) setting.originSettingClass else setting::class) + getPluginDataFile( + holder, + if (pluginData is AutoSavePluginData) pluginData.originPluginDataClass else pluginData::class + ) if (file.exists() && file.isFile && file.canRead()) { - file.writeText(Yaml.default.encodeToString(setting.updaterSerializer, Unit)) + file.writeText(Yaml.default.encodeToString(pluginData.updaterSerializer, Unit)) } } } diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/SemverAsStringSerializer.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/SemverAsStringSerializer.kt similarity index 95% rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/SemverAsStringSerializer.kt rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/SemverAsStringSerializer.kt index 39fe0f637..f319a7a0a 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/SemverAsStringSerializer.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/SemverAsStringSerializer.kt @@ -7,7 +7,7 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -package net.mamoe.mirai.console.internal.setting +package net.mamoe.mirai.console.internal.data import com.vdurmont.semver4j.Semver import kotlinx.serialization.KSerializer diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/_Setting.value.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/_PluginData.value.kt similarity index 69% rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/_Setting.value.kt rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/_PluginData.value.kt index abf3b6c04..d8b5aa213 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/_Setting.value.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/_PluginData.value.kt @@ -7,11 +7,11 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -package net.mamoe.mirai.console.internal.setting +package net.mamoe.mirai.console.internal.data import kotlinx.serialization.builtins.serializer -import net.mamoe.mirai.console.setting.SerializerAwareValue -import net.mamoe.mirai.console.setting.Setting +import net.mamoe.mirai.console.data.PluginData +import net.mamoe.mirai.console.data.SerializerAwareValue import kotlin.reflect.KClass @@ -49,9 +49,9 @@ internal object BuiltInSerializerConstants { } @Suppress("UNCHECKED_CAST") -internal fun <T : Any> Setting.valueImplPrimitive(kClass: KClass<T>): SerializerAwareValue<T>? { +internal fun <T : Any> PluginData.valueImplPrimitive(kClass: KClass<T>): SerializerAwareValue<T>? { return when (kClass) { - //// region Setting_valueImplPrimitive CODEGEN //// + //// region PluginData_valueImplPrimitive CODEGEN //// Byte::class -> byteValueImpl() Short::class -> shortValueImpl() @@ -63,103 +63,120 @@ internal fun <T : Any> Setting.valueImplPrimitive(kClass: KClass<T>): Serializer Boolean::class -> booleanValueImpl() String::class -> stringValueImpl() - //// endregion Setting_valueImplPrimitive CODEGEN //// + //// endregion PluginData_valueImplPrimitive CODEGEN //// else -> error("Internal error: unexpected type passed: ${kClass.qualifiedName}") } as SerializerAwareValue<T>? } -//// region Setting_value_PrimitivesImpl CODEGEN //// +//// region PluginData_value_PrimitivesImpl CODEGEN //// -internal fun Setting.valueImpl(default: Byte): SerializerAwareValue<Byte> { +internal fun PluginData.valueImpl(default: Byte): SerializerAwareValue<Byte> { return object : ByteValueImpl(default) { override fun onChanged() = this@valueImpl.onValueChanged(this) } } -internal fun Setting.byteValueImpl(): SerializerAwareValue<Byte> { + +internal fun PluginData.byteValueImpl(): SerializerAwareValue<Byte> { return object : ByteValueImpl() { override fun onChanged() = this@byteValueImpl.onValueChanged(this) } } -internal fun Setting.valueImpl(default: Short): SerializerAwareValue<Short> { + +internal fun PluginData.valueImpl(default: Short): SerializerAwareValue<Short> { return object : ShortValueImpl(default) { override fun onChanged() = this@valueImpl.onValueChanged(this) } } -internal fun Setting.shortValueImpl(): SerializerAwareValue<Short> { + +internal fun PluginData.shortValueImpl(): SerializerAwareValue<Short> { return object : ShortValueImpl() { override fun onChanged() = this@shortValueImpl.onValueChanged(this) } } -internal fun Setting.valueImpl(default: Int): SerializerAwareValue<Int> { + +internal fun PluginData.valueImpl(default: Int): SerializerAwareValue<Int> { return object : IntValueImpl(default) { override fun onChanged() = this@valueImpl.onValueChanged(this) } } -internal fun Setting.intValueImpl(): SerializerAwareValue<Int> { + +internal fun PluginData.intValueImpl(): SerializerAwareValue<Int> { return object : IntValueImpl() { override fun onChanged() = this@intValueImpl.onValueChanged(this) } } -internal fun Setting.valueImpl(default: Long): SerializerAwareValue<Long> { + +internal fun PluginData.valueImpl(default: Long): SerializerAwareValue<Long> { return object : LongValueImpl(default) { override fun onChanged() = this@valueImpl.onValueChanged(this) } } -internal fun Setting.longValueImpl(): SerializerAwareValue<Long> { + +internal fun PluginData.longValueImpl(): SerializerAwareValue<Long> { return object : LongValueImpl() { override fun onChanged() = this@longValueImpl.onValueChanged(this) } } -internal fun Setting.valueImpl(default: Float): SerializerAwareValue<Float> { + +internal fun PluginData.valueImpl(default: Float): SerializerAwareValue<Float> { return object : FloatValueImpl(default) { override fun onChanged() = this@valueImpl.onValueChanged(this) } } -internal fun Setting.floatValueImpl(): SerializerAwareValue<Float> { + +internal fun PluginData.floatValueImpl(): SerializerAwareValue<Float> { return object : FloatValueImpl() { override fun onChanged() = this@floatValueImpl.onValueChanged(this) } } -internal fun Setting.valueImpl(default: Double): SerializerAwareValue<Double> { + +internal fun PluginData.valueImpl(default: Double): SerializerAwareValue<Double> { return object : DoubleValueImpl(default) { override fun onChanged() = this@valueImpl.onValueChanged(this) } } -internal fun Setting.doubleValueImpl(): SerializerAwareValue<Double> { + +internal fun PluginData.doubleValueImpl(): SerializerAwareValue<Double> { return object : DoubleValueImpl() { override fun onChanged() = this@doubleValueImpl.onValueChanged(this) } } -internal fun Setting.valueImpl(default: Char): SerializerAwareValue<Char> { + +internal fun PluginData.valueImpl(default: Char): SerializerAwareValue<Char> { return object : CharValueImpl(default) { override fun onChanged() = this@valueImpl.onValueChanged(this) } } -internal fun Setting.charValueImpl(): SerializerAwareValue<Char> { + +internal fun PluginData.charValueImpl(): SerializerAwareValue<Char> { return object : CharValueImpl() { override fun onChanged() = this@charValueImpl.onValueChanged(this) } } -internal fun Setting.valueImpl(default: Boolean): SerializerAwareValue<Boolean> { + +internal fun PluginData.valueImpl(default: Boolean): SerializerAwareValue<Boolean> { return object : BooleanValueImpl(default) { override fun onChanged() = this@valueImpl.onValueChanged(this) } } -internal fun Setting.booleanValueImpl(): SerializerAwareValue<Boolean> { + +internal fun PluginData.booleanValueImpl(): SerializerAwareValue<Boolean> { return object : BooleanValueImpl() { override fun onChanged() = this@booleanValueImpl.onValueChanged(this) } } -internal fun Setting.valueImpl(default: String): SerializerAwareValue<String> { + +internal fun PluginData.valueImpl(default: String): SerializerAwareValue<String> { return object : StringValueImpl(default) { override fun onChanged() = this@valueImpl.onValueChanged(this) } } -internal fun Setting.stringValueImpl(): SerializerAwareValue<String> { + +internal fun PluginData.stringValueImpl(): SerializerAwareValue<String> { return object : StringValueImpl() { override fun onChanged() = this@stringValueImpl.onValueChanged(this) } } -//// endregion Setting_value_PrimitivesImpl CODEGEN //// +//// endregion PluginData_value_PrimitivesImpl CODEGEN //// diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/_PrimitiveValueDeclarations.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/_PrimitiveValueDeclarations.kt similarity index 99% rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/_PrimitiveValueDeclarations.kt rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/_PrimitiveValueDeclarations.kt index 81dee4d8a..df89a4931 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/_PrimitiveValueDeclarations.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/_PrimitiveValueDeclarations.kt @@ -7,14 +7,14 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -package net.mamoe.mirai.console.internal.setting +package net.mamoe.mirai.console.internal.data import kotlinx.serialization.KSerializer import kotlinx.serialization.builtins.serializer import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder -import net.mamoe.mirai.console.setting.* +import net.mamoe.mirai.console.data.* /** * The super class to all ValueImpl s @@ -98,7 +98,6 @@ internal abstract class ShortValueImpl : ShortValue, SerializerAwareValue<Short> else value.hashCode() * 31 } } - internal abstract class IntValueImpl : IntValue, SerializerAwareValue<Int>, KSerializer<Unit>, AbstractValueImpl<Int> { constructor() constructor(default: Int) { diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/asKClass.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/asKClass.kt similarity index 78% rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/asKClass.kt rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/asKClass.kt index 0e0ab2e2d..1ea34d799 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/asKClass.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/asKClass.kt @@ -7,10 +7,10 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -package net.mamoe.mirai.console.internal.setting +package net.mamoe.mirai.console.internal.data +import net.mamoe.mirai.console.data.PluginData import net.mamoe.mirai.console.internal.command.qualifiedNameOrTip -import net.mamoe.mirai.console.setting.Setting import kotlin.reflect.KClass import kotlin.reflect.KType import kotlin.reflect.full.isSubclassOf @@ -29,16 +29,16 @@ internal inline fun <reified T : Any> KType.asKClass(): KClass<out T> { return clazz } -internal inline fun <reified T : Setting> newSettingInstanceUsingReflection(type: KType): T { +internal inline fun <reified T : PluginData> newPluginDataInstanceUsingReflection(type: KType): T { val classifier = type.asKClass<T>() return with(classifier) { objectInstance ?: createInstanceOrNull() ?: throw IllegalArgumentException( - "Cannot create Setting instance. " + - "SettingHolder supports Settings implemented as an object " + - "or the ones with a constructor which either has no parameters or all parameters of which are optional, by default newSettingInstance implementation." + "Cannot create PluginData instance. " + + "PluginDataHolder supports PluginDatas implemented as an object " + + "or the ones with a constructor which either has no parameters or all parameters of which are optional, by default newPluginDataInstance implementation." ) } } diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/collectionUtil.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/collectionUtil.kt similarity index 99% rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/collectionUtil.kt rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/collectionUtil.kt index 528293c23..571138e53 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/collectionUtil.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/collectionUtil.kt @@ -9,7 +9,7 @@ @file:Suppress("DuplicatedCode") -package net.mamoe.mirai.console.internal.setting +package net.mamoe.mirai.console.internal.data import kotlinx.serialization.InternalSerializationApi import kotlinx.serialization.serializer diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/serializerHelper.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/serializerHelper.kt similarity index 99% rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/serializerHelper.kt rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/serializerHelper.kt index c74954ab7..8a5afe07c 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/serializerHelper.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/serializerHelper.kt @@ -7,7 +7,7 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -package net.mamoe.mirai.console.internal.setting +package net.mamoe.mirai.console.internal.data import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.InternalSerializationApi diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/serializerUtil.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/serializerUtil.kt similarity index 97% rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/serializerUtil.kt rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/serializerUtil.kt index 342777ccd..1800eafe6 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/serializerUtil.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/serializerUtil.kt @@ -7,7 +7,7 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -package net.mamoe.mirai.console.internal.setting +package net.mamoe.mirai.console.internal.data import kotlinx.serialization.KSerializer import kotlinx.serialization.SerialName diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/JarPluginLoaderImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/JarPluginLoaderImpl.kt index 45b4ea85a..6bb33be26 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/JarPluginLoaderImpl.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/JarPluginLoaderImpl.kt @@ -11,6 +11,7 @@ package net.mamoe.mirai.console.internal.plugin import kotlinx.coroutines.* import net.mamoe.mirai.console.MiraiConsole +import net.mamoe.mirai.console.data.PluginDataStorage import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge import net.mamoe.mirai.console.plugin.AbstractFilePluginLoader import net.mamoe.mirai.console.plugin.PluginLoadException @@ -18,7 +19,6 @@ import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader import net.mamoe.mirai.console.plugin.jvm.JvmPlugin import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescriptionImpl -import net.mamoe.mirai.console.setting.SettingStorage import net.mamoe.mirai.console.util.ConsoleExperimentalAPI import net.mamoe.mirai.utils.MiraiLogger import net.mamoe.yamlkt.Yaml @@ -35,8 +35,8 @@ internal object JarPluginLoaderImpl : private val logger: MiraiLogger = MiraiConsole.newLogger(JarPluginLoader::class.simpleName!!) @ConsoleExperimentalAPI - override val settingStorage: SettingStorage - get() = MiraiConsoleImplementationBridge.settingStorageForJarPluginLoader + override val dataStorage: PluginDataStorage + get() = MiraiConsoleImplementationBridge.dataStorageForJarPluginLoader override val coroutineContext: CoroutineContext = MiraiConsole.coroutineContext + diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/JvmPluginInternal.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/JvmPluginInternal.kt index 575969f86..d9f90f98b 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/JvmPluginInternal.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/JvmPluginInternal.kt @@ -17,6 +17,7 @@ import net.mamoe.mirai.console.plugin.Plugin import net.mamoe.mirai.console.plugin.PluginManager import net.mamoe.mirai.console.plugin.jvm.JvmPlugin import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription +import net.mamoe.mirai.console.plugin.safeLoader import net.mamoe.mirai.console.util.ResourceContainer.Companion.asResourceContainer import net.mamoe.mirai.utils.MiraiLogger import java.io.File @@ -65,17 +66,36 @@ internal abstract class JvmPluginInternal( internal fun internalOnDisable() { firstRun = false - this.onDisable() - this.cancel(CancellationException("plugin disabled")) + kotlin.runCatching { + onLoad() + }.fold( + onSuccess = { + cancel(CancellationException("plugin disabled")) + }, + onFailure = { + cancel(CancellationException("Exception while enabling plugin", it)) + } + ) } - internal fun internalOnLoad() { - this.onLoad() + @Throws(Throwable::class) + internal fun internalOnLoad() { // propagate exceptions + onLoad() } - internal fun internalOnEnable() { + internal fun internalOnEnable(): Boolean { if (!firstRun) refreshCoroutineContext() - this.onEnable() + kotlin.runCatching { + onEnable() + }.fold( + onSuccess = { + return true + }, + onFailure = { + cancel(CancellationException("Exception while enabling plugin", it)) + return false + } + ) } // endregion @@ -85,18 +105,25 @@ internal abstract class JvmPluginInternal( // for future use @Suppress("PropertyName") @JvmField - internal var _intrinsicCoroutineContext: CoroutineContext = - EmptyCoroutineContext + internal var _intrinsicCoroutineContext: CoroutineContext = EmptyCoroutineContext @JvmField internal val coroutineContextInitializer = { CoroutineExceptionHandler { _, throwable -> logger.error(throwable) } .plus(parentCoroutineContext) - .plus(SupervisorJob(parentCoroutineContext[Job])) + _intrinsicCoroutineContext + .plus(SupervisorJob(parentCoroutineContext[Job])) + .plus(_intrinsicCoroutineContext) } private fun refreshCoroutineContext(): CoroutineContext { - return coroutineContextInitializer().also { _coroutineContext = it } + return coroutineContextInitializer().also { _coroutineContext = it }.also { + job.invokeOnCompletion { e -> + if (e != null) { + logger.error(e) + safeLoader.disable(this) + } + } + } } private val contextUpdateLock: ReentrantLock = diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/PluginManagerImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/PluginManagerImpl.kt index 303996e27..6cc295f1e 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/PluginManagerImpl.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/PluginManagerImpl.kt @@ -15,7 +15,7 @@ import kotlinx.atomicfu.locks.withLock import kotlinx.coroutines.InternalCoroutinesApi import kotlinx.coroutines.Job import net.mamoe.mirai.console.MiraiConsole -import net.mamoe.mirai.console.internal.setting.cast +import net.mamoe.mirai.console.internal.data.cast import net.mamoe.mirai.console.plugin.* import net.mamoe.mirai.utils.info import java.io.File diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/utils/BotManagerImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/utils/BotManagerImpl.kt index e4d0c06c5..85b6347b3 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/utils/BotManagerImpl.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/utils/BotManagerImpl.kt @@ -16,9 +16,9 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.SupervisorJob import net.mamoe.mirai.Bot import net.mamoe.mirai.console.MiraiConsole +import net.mamoe.mirai.console.data.* +import net.mamoe.mirai.console.data.PluginDataStorage.Companion.load import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge -import net.mamoe.mirai.console.setting.* -import net.mamoe.mirai.console.setting.SettingStorage.Companion.load import net.mamoe.mirai.console.util.BotManager import net.mamoe.mirai.contact.User import net.mamoe.mirai.utils.minutesToMillis @@ -29,7 +29,7 @@ internal object BotManagerImpl : BotManager { /** * 判断此用户是否为 console 管理员 */ - override val User.isManager: Boolean get() = this.id in this.bot.managers + override val User.isManager: Boolean get() = this.id in ManagersConfig[this.bot] override fun Bot.removeManager(id: Long): Boolean { return ManagersConfig[this].remove(id) @@ -43,7 +43,7 @@ internal object BotManagerImpl : BotManager { } } -internal object ManagersConfig : Setting by ConsoleBuiltInSettingStorage.load() { +internal object ManagersConfig : PluginData by ConsoleBuiltInPluginDataStorage.load() { private val managers: MutableMap<Long, MutableSet<Long>> by value() internal operator fun get(bot: Bot): MutableSet<Long> = managers.getOrPut(bot.id, ::mutableSetOf) @@ -54,14 +54,14 @@ internal fun CoroutineContext.overrideWithSupervisorJob(): CoroutineContext = th internal fun CoroutineScope.childScope(context: CoroutineContext = EmptyCoroutineContext): CoroutineScope = CoroutineScope(this.coroutineContext.overrideWithSupervisorJob() + context) -internal object ConsoleBuiltInSettingHolder : AutoSaveSettingHolder, +internal object ConsoleBuiltInPluginDataHolder : AutoSavePluginDataHolder, CoroutineScope by MiraiConsole.childScope() { override val autoSaveIntervalMillis: LongRange = 30.minutesToMillis..60.minutesToMillis override val name: String get() = "ConsoleBuiltIns" } -internal object ConsoleBuiltInSettingStorage : - SettingStorage by MiraiConsoleImplementationBridge.settingStorageForJarPluginLoader { +internal object ConsoleBuiltInPluginDataStorage : + PluginDataStorage by MiraiConsoleImplementationBridge.dataStorageForBuiltIns { - inline fun <reified T : Setting> load(): T = load(ConsoleBuiltInSettingHolder) + inline fun <reified T : PluginData> load(): T = load(ConsoleBuiltInPluginDataHolder) } \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/description.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/description.kt index f7ef9c8c0..9029e8d15 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/description.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/description.kt @@ -14,8 +14,8 @@ import kotlinx.serialization.KSerializer import kotlinx.serialization.Serializable import kotlinx.serialization.builtins.serializer import kotlinx.serialization.encodeToString -import net.mamoe.mirai.console.internal.setting.SemverAsStringSerializerIvy -import net.mamoe.mirai.console.internal.setting.map +import net.mamoe.mirai.console.internal.data.SemverAsStringSerializerIvy +import net.mamoe.mirai.console.internal.data.map import net.mamoe.yamlkt.Yaml import net.mamoe.yamlkt.YamlDynamicSerializer import java.io.File diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JarPluginLoader.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JarPluginLoader.kt index 5ac08034c..134b2d018 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JarPluginLoader.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JarPluginLoader.kt @@ -10,9 +10,9 @@ package net.mamoe.mirai.console.plugin.jvm import kotlinx.coroutines.CoroutineScope +import net.mamoe.mirai.console.data.PluginDataStorage import net.mamoe.mirai.console.internal.plugin.JarPluginLoaderImpl import net.mamoe.mirai.console.plugin.FilePluginLoader -import net.mamoe.mirai.console.setting.SettingStorage import net.mamoe.mirai.console.util.ConsoleExperimentalAPI /** @@ -20,10 +20,10 @@ import net.mamoe.mirai.console.util.ConsoleExperimentalAPI */ public interface JarPluginLoader : CoroutineScope, FilePluginLoader<JvmPlugin, JvmPluginDescription> { /** - * [JvmPlugin.loadSetting] 默认使用的实例 + * [JvmPlugin.loadPluginData] 默认使用的实例 */ @ConsoleExperimentalAPI - public val settingStorage: SettingStorage + public val dataStorage: PluginDataStorage public companion object INSTANCE : JarPluginLoader by JarPluginLoaderImpl { @Suppress("EXTENSION_SHADOWED_BY_MEMBER") diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPlugin.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPlugin.kt index d11003d5d..867b4002a 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPlugin.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPlugin.kt @@ -12,10 +12,10 @@ package net.mamoe.mirai.console.plugin.jvm import kotlinx.coroutines.CoroutineScope +import net.mamoe.mirai.console.data.AutoSavePluginDataHolder +import net.mamoe.mirai.console.data.PluginData import net.mamoe.mirai.console.plugin.Plugin import net.mamoe.mirai.console.plugin.PluginFileExtensions -import net.mamoe.mirai.console.setting.AutoSaveSettingHolder -import net.mamoe.mirai.console.setting.Setting import net.mamoe.mirai.console.util.ResourceContainer import net.mamoe.mirai.utils.MiraiLogger import kotlin.reflect.KClass @@ -36,7 +36,7 @@ import kotlin.reflect.KClass * @see ResourceContainer 支持资源获取 (如 Jar 中的资源文件) */ public interface JvmPlugin : Plugin, CoroutineScope, - PluginFileExtensions, ResourceContainer, AutoSaveSettingHolder { + PluginFileExtensions, ResourceContainer, AutoSavePluginDataHolder { /** 日志 */ public val logger: MiraiLogger @@ -49,10 +49,10 @@ public interface JvmPlugin : Plugin, CoroutineScope, get() = JarPluginLoader /** - * 从 [JarPluginLoader.settingStorage] 获取一个 [Setting] 实例 + * 从 [JarPluginLoader.dataStorage] 获取一个 [PluginData] 实例 */ @JvmDefault - public fun <T : Setting> loadSetting(clazz: Class<T>): T = loader.settingStorage.load(this, clazz) + public fun <T : PluginData> loadPluginData(clazz: Class<T>): T = loader.dataStorage.load(this, clazz) /** * 在插件被加载时调用. 只会被调用一次. @@ -77,7 +77,12 @@ public interface JvmPlugin : Plugin, CoroutineScope, } @JvmSynthetic -public inline fun <T : Setting> JvmPlugin.loadSetting(clazz: KClass<T>): T = this.loadSetting(clazz.java) +public inline fun <T : PluginData> JvmPlugin.loadPluginData(clazz: KClass<T>): T = this.loadPluginData(clazz.java) +/** + * 读取一个插件数据. + * + * 插件数据 + */ @JvmSynthetic -public inline fun <reified T : Setting> JvmPlugin.loadSetting(): T = this.loadSetting(T::class) \ No newline at end of file +public inline fun <reified T : PluginData> JvmPlugin.loadPluginData(): T = this.loadPluginData(T::class) \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPluginDescriptionImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPluginDescriptionImpl.kt index 100e48294..32d834527 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPluginDescriptionImpl.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPluginDescriptionImpl.kt @@ -13,7 +13,7 @@ import com.vdurmont.semver4j.Semver import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.Transient -import net.mamoe.mirai.console.internal.setting.SemverAsStringSerializerLoose +import net.mamoe.mirai.console.internal.data.SemverAsStringSerializerLoose import net.mamoe.mirai.console.plugin.PluginDependency import net.mamoe.mirai.console.plugin.PluginDescription import net.mamoe.mirai.console.plugin.PluginKind diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/KotlinPlugin.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/KotlinPlugin.kt index b26d1d2e6..3199b6236 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/KotlinPlugin.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/KotlinPlugin.kt @@ -48,7 +48,7 @@ public abstract class KotlinMemoryPlugin @JvmOverloads constructor( public object MyPlugin : KotlinPlugin() -public object AccountSetting : Setting by MyPlugin.getSetting() { +public object AccountPluginData : PluginData by MyPlugin.getPluginData() { public val s by value(1) } */ \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt deleted file mode 100644 index f780b7752..000000000 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright 2019-2020 Mamoe Technologies and contributors. - * - * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions 许可证的约束, 可以在以下链接找到该许可证. - * Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions license that can be found via the following link. - * - * https://github.com/mamoe/mirai/blob/master/LICENSE - */ - -@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "EXPOSED_SUPER_CLASS") - -package net.mamoe.mirai.console.setting - -import kotlinx.serialization.KSerializer -import net.mamoe.mirai.console.internal.setting.* -import net.mamoe.mirai.console.plugin.jvm.JvmPlugin -import net.mamoe.mirai.console.plugin.jvm.loadSetting -import net.mamoe.mirai.console.util.ConsoleExperimentalAPI -import kotlin.internal.LowPriorityInOverloadResolution -import kotlin.reflect.KClass -import kotlin.reflect.KProperty -import kotlin.reflect.KType - - -/** - * 序列化之后的名称. - * - * 例: - * ``` - * @SerialName("accounts") - * object AccountSettings : Setting by ... { - * @SerialName("info") - * val map: Map<String, String> by value("a" to "b") - * } - * ``` - * - * 将被保存为配置 (YAML 作为示例): - * ```yaml - * accounts: - * info: - * a: b - * ``` - */ -public typealias SerialName = kotlinx.serialization.SerialName - -/** - * [Setting] 的默认实现. 支持使用 `by value()` 等委托方法创建 [Value] 并跟踪其改动. - * - * @see Setting - */ -public abstract class AbstractSetting : Setting, SettingImpl() { - /** - * 添加了追踪的 [ValueNode] 列表, 即通过 `by value` 初始化的属性列表. - * - * 他们的修改会被跟踪, 并触发 [onValueChanged]. - * - * @see provideDelegate - */ - public override val valueNodes: MutableList<ValueNode<*>> = mutableListOf() - - /** - * 由 [provideDelegate] 创建, 来自一个通过 `by value` 初始化的属性. - */ - public data class ValueNode<T>( - val serialName: String, - val value: Value<T>, - @ConsoleExperimentalAPI - val updaterSerializer: KSerializer<Unit> - ) - - /** - * 使用 `by` 时自动调用此方法, 添加对 [Value] 的值修改的跟踪. - * - * 将会创建一个 [ValueNode] 并添加到 [valueNodes] - */ - public final override operator fun <T> SerializerAwareValue<T>.provideDelegate( - thisRef: Any?, - property: KProperty<*> - ): SerializerAwareValue<T> { - val name = property.serialName - valueNodes.add(ValueNode(name, this, this.serializer)) - return this - } - - /** - * 值更新序列化器. 仅供内部使用. - */ - @ConsoleExperimentalAPI - public final override val updaterSerializer: KSerializer<Unit> - get() = super.updaterSerializer - - /** - * 当所属于这个 [Setting] 的 [Value] 的 [值][Value.value] 被修改时被调用. - */ - public abstract override fun onValueChanged(value: Value<*>) -} - -/** - * 一个配置对象. 可包含对多个 [Value] 的值变更的跟踪. - * - * 在 [JvmPlugin] 的典型实现方式: - * ``` - * object PluginMain : KotlinPlugin() - * - * object AccountSettings : Setting by PluginMain.loadSetting() { - * val map: Map<String, String> by value("a" to "b") - * } - * ``` - * - * @see JvmPlugin.loadSetting 通过 [JvmPlugin] 获取指定 [Setting] 实例. - */ -public interface Setting : ExperimentalSettingExtensions { - /** - * 使用 `by` 时自动调用此方法, 添加对 [Value] 的值修改的跟踪. - */ - public operator fun <T> SerializerAwareValue<T>.provideDelegate( - thisRef: Any?, - property: KProperty<*> - ): SerializerAwareValue<T> - - /** - * 值更新序列化器. 仅供内部使用 - */ - @ConsoleExperimentalAPI - public val updaterSerializer: KSerializer<Unit> - - /** - * 当所属于这个 [Setting] 的 [Value] 的 [值][Value.value] 被修改时被调用. - */ - public fun onValueChanged(value: Value<*>) - - /** - * 当这个 [Setting] 被放入一个 [SettingStorage] 时调用 - */ - public fun setStorage(storage: SettingStorage) -} - -@ConsoleExperimentalAPI("") -public interface ExperimentalSettingExtensions { - public fun <E, V, K> MutableMap<E, V>.shadowMap( - eToK: (E) -> K, - kToE: (K) -> E - ): MutableMap<K, V> { - return this.shadowMap( - kTransform = eToK, - kTransformBack = kToE, - vTransform = { it }, - vTransformBack = { it } - ) - } -} - -//// region Setting_value_primitives CODEGEN //// - -public fun Setting.value(default: Byte): SerializerAwareValue<Byte> = valueImpl(default) -public fun Setting.value(default: Short): SerializerAwareValue<Short> = valueImpl(default) -public fun Setting.value(default: Int): SerializerAwareValue<Int> = valueImpl(default) -public fun Setting.value(default: Long): SerializerAwareValue<Long> = valueImpl(default) -public fun Setting.value(default: Float): SerializerAwareValue<Float> = valueImpl(default) -public fun Setting.value(default: Double): SerializerAwareValue<Double> = valueImpl(default) -public fun Setting.value(default: Char): SerializerAwareValue<Char> = valueImpl(default) -public fun Setting.value(default: Boolean): SerializerAwareValue<Boolean> = valueImpl(default) -public fun Setting.value(default: String): SerializerAwareValue<String> = valueImpl(default) - -//// endregion Setting_value_primitives CODEGEN //// - - -/** - * 通过具体化类型创建一个 [SerializerAwareValue], 并设置初始值. - * - * @param T 具体化参数类型 T. 仅支持: - * - 基础数据类型 - * - 标准库集合类型 ([List], [Map], [Set]) - * - 标准库数据类型 ([Map.Entry], [Pair], [Triple]) - * - 和使用 [kotlinx.serialization](https://github.com/Kotlin/kotlinx.serialization) 的 [Serializable] 标记的 - */ -@Suppress("UNCHECKED_CAST") -@LowPriorityInOverloadResolution -public inline fun <reified T> Setting.value(default: T): SerializerAwareValue<T> = valueFromKType(typeOf0<T>(), default) - -/** - * 通过具体化类型创建一个 [SerializerAwareValue]. - * @see valueFromKType 查看更多实现信息 - */ -@LowPriorityInOverloadResolution -public inline fun <reified T> Setting.value(): SerializerAwareValue<T> = - value(T::class.run { objectInstance ?: createInstanceSmart() } as T) - -/** - * 通过一个特定的 [KType] 创建 [Value], 并设置初始值. - * - * 对于 [List], [Map], [Set] 等标准库类型, 这个函数会尝试构造 [LinkedHashMap] 等相关类型. - * 而对于自定义数据类型, 本函数只会反射获取 [objectInstance][KClass.objectInstance] 或使用无参构造器构造实例. - * - * @param T 具体化参数类型 T. 仅支持: - * - 基础数据类型 - * - 标准库集合类型 ([List], [Map], [Set]) - * - 标准库数据类型 ([Map.Entry], [Pair], [Triple]) - * - 和使用 [kotlinx.serialization](https://github.com/Kotlin/kotlinx.serialization) 的 [Serializable] 标记的 - */ -@Suppress("UNCHECKED_CAST") -@ConsoleExperimentalAPI -public fun <T> Setting.valueFromKType(type: KType, default: T): SerializerAwareValue<T> = - (valueFromKTypeImpl(type) as SerializerAwareValue<Any?>).apply { this.value = default } as SerializerAwareValue<T> - -// TODO: 2020/6/24 Introduce class TypeToken for compound types for Java. \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/SettingStorage.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/SettingStorage.kt deleted file mode 100644 index c24ed9900..000000000 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/SettingStorage.kt +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright 2019-2020 Mamoe Technologies and contributors. - * - * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions 许可证的约束, 可以在以下链接找到该许可证. - * Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions license that can be found via the following link. - * - * https://github.com/mamoe/mirai/blob/master/LICENSE - */ - -@file:Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST", "unused") - -package net.mamoe.mirai.console.setting - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Job -import net.mamoe.mirai.console.internal.setting.* -import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader -import net.mamoe.mirai.console.plugin.jvm.JvmPlugin -import net.mamoe.mirai.console.setting.SettingStorage.Companion.load -import java.io.File -import kotlin.reflect.KClass -import kotlin.reflect.KType -import kotlin.reflect.full.createType - -/** - * [Setting] 存储容器. - * - * 此为较低层的 API, 一般插件开发者不会接触. - * - * [JarPluginLoader] 实现一个 [SettingStorage], 用于管理所有 [JvmPlugin] 的 [Setting] 实例. - * - * @see SettingHolder - * @see JarPluginLoader.settingStorage - */ -public interface SettingStorage { - /** - * 读取一个实例. 在 [T] 实例创建后 [设置 [SettingStorage]][Setting.setStorage] - */ - public fun <T : Setting> load(holder: SettingHolder, settingClass: Class<T>): T - - /** - * 保存一个实例 - */ - public fun store(holder: SettingHolder, setting: Setting) - - public companion object { - /** - * 读取一个实例. 在 [T] 实例创建后 [设置 [SettingStorage]][Setting.setStorage] - */ - @JvmStatic - public fun <T : Setting> SettingStorage.load(holder: SettingHolder, settingClass: KClass<T>): T = - this.load(holder, settingClass.java) - - /** - * 读取一个实例. 在 [T] 实例创建后 [设置 [SettingStorage]][Setting.setStorage] - */ - @JvmSynthetic - public inline fun <reified T : Setting> SettingStorage.load(holder: SettingHolder): T = - this.load(holder, T::class) - } -} - -/** - * 在内存存储所有 [Setting] 实例的 [SettingStorage]. 在内存数据丢失后相关 [Setting] 实例也会丢失. - */ -public interface MemorySettingStorage : SettingStorage, Map<Class<out Setting>, Setting> { - /** - * 当任一 [Setting] 实例拥有的 [Value] 的值被改变后调用的回调函数. - */ - public fun interface OnChangedCallback { - public fun onChanged(storage: MemorySettingStorage, value: Value<*>) - - /** - * 无任何操作的 [OnChangedCallback] - * @see OnChangedCallback - */ - public object NoOp : OnChangedCallback { - public override fun onChanged(storage: MemorySettingStorage, value: Value<*>) { - // no-op - } - } - } - - public companion object { - /** - * 创建一个 [MemorySettingStorage] 实例. - * - * @param onChanged 当任一 [Setting] 实例拥有的 [Value] 的值被改变后调用的回调函数. - */ - @JvmStatic - @JvmName("create") - // @JvmOverloads - public operator fun invoke(onChanged: OnChangedCallback = OnChangedCallback.NoOp): MemorySettingStorage = - MemorySettingStorageImpl(onChanged) - } -} - -/** - * 用多个文件存储 [Setting] 实例的 [SettingStorage]. - */ -public interface MultiFileSettingStorage : SettingStorage { - /** - * 存放 [Setting] 的目录. - */ - public val directory: File - - public companion object { - /** - * 创建一个 [MultiFileSettingStorage] 实例. - * - * @see directory 存放 [Setting] 的目录. - */ - @JvmStatic - @JvmName("create") - public operator fun invoke(directory: File): MultiFileSettingStorage = MultiFileSettingStorageImpl(directory) - } -} - -/** - * 可以持有相关 [Setting] 实例的对象, 作为 [Setting] 实例的拥有者. - * - * @see SettingStorage.load - * @see SettingStorage.store - * - * @see AutoSaveSettingHolder 自动保存 - */ -public interface SettingHolder { - /** - * 保存时使用的分类名 - */ - public val name: String - - /** - * 创建一个 [Setting] 实例. - * - * @see Companion.newSettingInstance - * @see KClass.createType - */ - @JvmDefault - public fun <T : Setting> newSettingInstance(type: KType): T = - newSettingInstanceUsingReflection<Setting>(type) as T - - public companion object { - /** - * 创建一个 [Setting] 实例. - * - * @see SettingHolder.newSettingInstance - */ - @JvmSynthetic - public inline fun <reified T : Setting> SettingHolder.newSettingInstance(): T { - return this.newSettingInstance(typeOf0<T>()) - } - } -} - -/** - * 可以持有相关 [AutoSaveSetting] 的对象. - * - * @see net.mamoe.mirai.console.plugin.jvm.JvmPlugin - */ -public interface AutoSaveSettingHolder : SettingHolder, CoroutineScope { - /** - * [AutoSaveSetting] 每次自动保存时间间隔 - * - * - 区间的左端点为最小间隔, 一个 [Value] 被修改后, 若此时间段后无其他修改, 将触发自动保存; 若有, 将重新开始计时. - * - 区间的右端点为最大间隔, 一个 [Value] 被修改后, 最多不超过这个时间段后就会被保存. - * - * 若 [AutoSaveSettingHolder.coroutineContext] 含有 [Job], - * 则 [AutoSaveSetting] 会通过 [Job.invokeOnCompletion] 在 Job 完结时触发自动保存. - * - * @see LongRange Java 用户使用 [LongRange] 的构造器创建 - * @see Long.rangeTo Kotlin 用户使用 [Long.rangeTo] 创建, 如 `3000..50000` - */ - public val autoSaveIntervalMillis: LongRange - - /** - * 仅支持确切的 [Setting] 类型 - */ - @JvmDefault - public override fun <T : Setting> newSettingInstance(type: KType): T { - val classifier = type.classifier?.cast<KClass<Setting>>() - require(classifier != null && classifier.java == Setting::class.java) { - "Cannot create Setting instance. AutoSaveSettingHolder supports only Setting type." - } - return AutoSaveSetting(this, classifier) as T // T is always Setting - } -} \ No newline at end of file diff --git a/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/TestMiraiConosle.kt b/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/TestMiraiConosle.kt index 8242e9b2a..8dd4fc9ef 100644 --- a/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/TestMiraiConosle.kt +++ b/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/TestMiraiConosle.kt @@ -17,11 +17,11 @@ import net.mamoe.mirai.Bot import net.mamoe.mirai.console.MiraiConsoleImplementation.Companion.start import net.mamoe.mirai.console.command.CommandManager import net.mamoe.mirai.console.command.ConsoleCommandSender +import net.mamoe.mirai.console.data.MemoryPluginDataStorage +import net.mamoe.mirai.console.data.PluginDataStorage import net.mamoe.mirai.console.plugin.DeferredPluginLoader import net.mamoe.mirai.console.plugin.PluginLoader import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader -import net.mamoe.mirai.console.setting.MemorySettingStorage -import net.mamoe.mirai.console.setting.SettingStorage import net.mamoe.mirai.console.util.ConsoleInternalAPI import net.mamoe.mirai.message.data.Message import net.mamoe.mirai.utils.DefaultLogger @@ -51,8 +51,8 @@ fun initTestEnvironment() { override val consoleCommandSender: ConsoleCommandSender = object : ConsoleCommandSender() { override suspend fun sendMessage(message: Message) = println(message) } - override val settingStorageForJarPluginLoader: SettingStorage get() = MemorySettingStorage() - override val settingStorageForBuiltIns: SettingStorage get() = MemorySettingStorage() + override val dataStorageForJarPluginLoader: PluginDataStorage get() = MemoryPluginDataStorage() + override val dataStorageForBuiltIns: PluginDataStorage get() = MemoryPluginDataStorage() override val coroutineContext: CoroutineContext = SupervisorJob() }.start() CommandManager diff --git a/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/setting/SettingTest.kt b/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/data/SettingTest.kt similarity index 73% rename from backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/setting/SettingTest.kt rename to backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/data/SettingTest.kt index 5ca8a5c14..be874cbfe 100644 --- a/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/setting/SettingTest.kt +++ b/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/data/SettingTest.kt @@ -7,7 +7,7 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -package net.mamoe.mirai.console.setting +package net.mamoe.mirai.console.data import kotlinx.serialization.json.Json import net.mamoe.mirai.console.util.ConsoleInternalAPI @@ -16,9 +16,9 @@ import kotlin.test.assertEquals import kotlin.test.assertSame @OptIn(ConsoleInternalAPI::class) -internal class SettingTest { +internal class PluginDataTest { - class MySetting : AbstractSetting() { + class MyPluginData : AbstractPluginData() { var int by value(1) val map by value<MutableMap<String, String>>() val map2 by value<MutableMap<String, MutableMap<String, String>>>() @@ -28,7 +28,7 @@ internal class SettingTest { } - override fun setStorage(storage: SettingStorage) { + override fun setStorage(storage: PluginDataStorage) { } } @@ -37,45 +37,45 @@ internal class SettingTest { @Test fun testStringify() { - val setting = MySetting() + val data = MyPluginData() - var string = json.encodeToString(setting.updaterSerializer, Unit) + var string = json.encodeToString(data.updaterSerializer, Unit) assertEquals("""{"int":1,"map":{},"map2":{}}""", string) - setting.int = 2 + data.int = 2 - string = json.encodeToString(setting.updaterSerializer, Unit) + string = json.encodeToString(data.updaterSerializer, Unit) assertEquals("""{"int":2,"map":{},"map2":{}}""", string) } @Test fun testParseUpdate() { - val setting = MySetting() + val data = MyPluginData() - assertEquals(1, setting.int) + assertEquals(1, data.int) json.decodeFromString( - setting.updaterSerializer, """ + data.updaterSerializer, """ {"int":3,"map":{},"map2":{}} """.trimIndent() ) - assertEquals(3, setting.int) + assertEquals(3, data.int) } @Test fun testNestedParseUpdate() { - val setting = MySetting() + val data = MyPluginData() - fun delegation() = setting.map + fun delegation() = data.map - val refBefore = setting.map + val refBefore = data.map fun reference() = refBefore assertEquals(mutableMapOf(), delegation()) // delegation json.decodeFromString( - setting.updaterSerializer, """ + data.updaterSerializer, """ {"int":1,"map":{"t":"test"},"map2":{}} """.trimIndent() ) @@ -88,17 +88,17 @@ internal class SettingTest { @Test fun testDeepNestedParseUpdate() { - val setting = MySetting() + val data = MyPluginData() - fun delegation() = setting.map2 + fun delegation() = data.map2 - val refBefore = setting.map2 + val refBefore = data.map2 fun reference() = refBefore assertEquals(mutableMapOf(), delegation()) // delegation json.decodeFromString( - setting.updaterSerializer, """ + data.updaterSerializer, """ {"int":1,"map":{},"map2":{"t":{"f":"test"}}} """.trimIndent() ) @@ -111,19 +111,19 @@ internal class SettingTest { @Test fun testDeepNestedTrackingParseUpdate() { - val setting = MySetting() + val data = MyPluginData() - setting.map2["t"] = mutableMapOf() + data.map2["t"] = mutableMapOf() - fun delegation() = setting.map2["t"]!! + fun delegation() = data.map2["t"]!! - val refBefore = setting.map2["t"]!! + val refBefore = data.map2["t"]!! fun reference() = refBefore assertEquals(mutableMapOf(), delegation()) // delegation json.decodeFromString( - setting.updaterSerializer, """ + data.updaterSerializer, """ {"int":1,"map":{},"map2":{"t":{"f":"test"}}} """.trimIndent() ) diff --git a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleImplementationPure.kt b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleImplementationPure.kt index c59bf10b1..b259e3a31 100644 --- a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleImplementationPure.kt +++ b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleImplementationPure.kt @@ -28,11 +28,11 @@ import net.mamoe.mirai.console.ConsoleFrontEndImplementation import net.mamoe.mirai.console.MiraiConsoleFrontEnd import net.mamoe.mirai.console.MiraiConsoleImplementation import net.mamoe.mirai.console.command.ConsoleCommandSender +import net.mamoe.mirai.console.data.MultiFilePluginDataStorage +import net.mamoe.mirai.console.data.PluginDataStorage import net.mamoe.mirai.console.plugin.DeferredPluginLoader import net.mamoe.mirai.console.plugin.PluginLoader import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader -import net.mamoe.mirai.console.setting.MultiFileSettingStorage -import net.mamoe.mirai.console.setting.SettingStorage import net.mamoe.mirai.console.util.ConsoleInternalAPI import net.mamoe.mirai.utils.MiraiLogger import java.io.File @@ -53,8 +53,8 @@ class MiraiConsoleImplementationPure override val frontEnd: MiraiConsoleFrontEnd = MiraiConsoleFrontEndPure, override val mainLogger: MiraiLogger = frontEnd.loggerFor("main"), override val consoleCommandSender: ConsoleCommandSender = ConsoleCommandSenderImpl, - override val settingStorageForJarPluginLoader: SettingStorage = MultiFileSettingStorage(File(rootDir, "data")), - override val settingStorageForBuiltIns: SettingStorage = MultiFileSettingStorage(File(rootDir, "data")) + override val dataStorageForJarPluginLoader: PluginDataStorage = MultiFilePluginDataStorage(File(rootDir, "data")), + override val dataStorageForBuiltIns: PluginDataStorage = MultiFilePluginDataStorage(File(rootDir, "data")) ) : MiraiConsoleImplementation, CoroutineScope by CoroutineScope(SupervisorJob()) { init { rootDir.mkdir() diff --git a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt index 9e1d2e269..e81c4342d 100644 --- a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt +++ b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt @@ -20,9 +20,18 @@ package net.mamoe.mirai.console.pure +import kotlinx.coroutines.runBlocking +import net.mamoe.mirai.alsoLogin +import net.mamoe.mirai.console.MiraiConsole import net.mamoe.mirai.console.MiraiConsoleImplementation.Companion.start +import net.mamoe.mirai.console.command.CommandManager.INSTANCE.register +import net.mamoe.mirai.console.command.CommandPermission +import net.mamoe.mirai.console.command.CommandSender import net.mamoe.mirai.console.command.ConsoleCommandSender +import net.mamoe.mirai.console.command.SimpleCommand import net.mamoe.mirai.console.util.ConsoleInternalAPI +import net.mamoe.mirai.contact.Member +import net.mamoe.mirai.contact.nameCardOrNick import net.mamoe.mirai.message.data.Message import net.mamoe.mirai.message.data.content import net.mamoe.mirai.utils.DefaultLogger @@ -35,9 +44,24 @@ object MiraiConsolePureLoader { @JvmStatic fun main(args: Array<String>?) { startup() + YellowCommand.register() + runBlocking { MiraiConsole.addBot(1994701021, "Asd123456789asd").alsoLogin() } } } +object YellowCommand : SimpleCommand( + net.mamoe.mirai.console.command.ConsoleCommandOwner, "睡", "sleep", + prefixOptional = true, + description = "睡一个人", + permission = CommandPermission.Any +) { + @Handler + suspend fun CommandSender.handle(target: Member) { + target.mute(1) + + sendMessage("${this.name} 睡了 ${target.nameCardOrNick}") + } +} internal fun startup() { DefaultLogger = { MiraiConsoleFrontEndPure.loggerFor(it) }