diff --git a/PluginDocs/java/source.java b/PluginDocs/java/source.java index 92ff7d906..d60cf7367 100644 --- a/PluginDocs/java/source.java +++ b/PluginDocs/java/source.java @@ -3,10 +3,10 @@ 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.plugins.Config; -import net.mamoe.mirai.console.plugins.ConfigSection; -import net.mamoe.mirai.console.plugins.ConfigSectionFactory; -import net.mamoe.mirai.console.plugins.PluginBase; +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.utils.Utils; import net.mamoe.mirai.message.GroupMessage; import org.jetbrains.annotations.NotNull; diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/SettingValueUseSiteCodegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/SettingValueUseSiteCodegen.kt index 87af74d6a..3906cf4d1 100644 --- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/SettingValueUseSiteCodegen.kt +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/SettingValueUseSiteCodegen.kt @@ -101,7 +101,11 @@ fun genAllValueUseSite(): String = buildString { require(this::class != default::class) { "Recursive nesting is prohibited" } - return valueImpl(default) + return valueImpl(default).also { + if (default is Setting.NestedSetting) { + default.attachedValue = it + } + } } inline fun Setting.value(default: T, crossinline initializer: T.() -> Unit): Value = diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValueImplCodegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValueImplCodegen.kt index d09d147c8..b4c0014a3 100644 --- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValueImplCodegen.kt +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValueImplCodegen.kt @@ -110,7 +110,7 @@ fun genAllValueImpl(): String = buildString { ): Mutable${number}${collectionName}Value { var internalValue: Mutable${collectionName}<${number}> = default - val delegt = dynamicMutable${collectionName}{ internalValue } + val delegt = dynamicMutable${collectionName} { internalValue } return object : Mutable${number}${collectionName}Value(), Mutable${collectionName}<${number}> by delegt { override var value: Mutable${collectionName}<${number}> get() = internalValue @@ -125,10 +125,10 @@ fun genAllValueImpl(): String = buildString { override val serializer: KSerializer> = object : KSerializer> { private val delegate = ${collectionName}Serializer(${number}.serializer()) - override val descriptor: SerialDescriptor = delegate.descriptor + override val descriptor: SerialDescriptor get() = delegate.descriptor override fun deserialize(decoder: Decoder): Mutable${collectionName}<${number}> { - return delegate.deserialize(decoder).toMutable${collectionName}().observable { + return delegate.deserialize(decoder).toMutable${collectionName}().observable { onElementChanged(outerThis) } } @@ -208,7 +208,7 @@ fun genPrimitiveValueImpl( """.trim() } } - override val serializer = $serializer + override val serializer get() = $serializer } } """.trimIndent() + "\n" @@ -244,7 +244,7 @@ fun genCollectionValueImpl( """.trim() } } - override val serializer = $serializer + override val serializer get() = $serializer } } """.trimIndent() + "\n" diff --git a/backend/mirai-console/src/main/java/net/mamoe/mirai/console/command/JCommandManager.java b/backend/mirai-console/src/main/java/net/mamoe/mirai/console/command/JCommandManager.java new file mode 100644 index 000000000..e9e803446 --- /dev/null +++ b/backend/mirai-console/src/main/java/net/mamoe/mirai/console/command/JCommandManager.java @@ -0,0 +1,139 @@ +package net.mamoe.mirai.console.command; + +import kotlin.NotImplementedError; +import kotlin.coroutines.EmptyCoroutineContext; +import kotlinx.coroutines.BuildersKt; +import kotlinx.coroutines.CoroutineScope; +import kotlinx.coroutines.CoroutineStart; +import kotlinx.coroutines.future.FutureKt; +import net.mamoe.mirai.console.plugin.jvm.JavaPlugin; +import net.mamoe.mirai.message.data.Message; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; + +/** + * Java 适配的 {@link CommandManagerKt} + */ +@SuppressWarnings("unused") +public final class JCommandManager { + private JCommandManager() { + throw new NotImplementedError(); + } + + /** + * 获取指令前缀 + * + * @return 指令前缀 + */ + @NotNull + public static String getCommandPrefix() { + return CommandManagerKt.getCommandPrefix(); + } + + /** + * 获取一个指令所有者已经注册了的指令列表. + * + * @param owner 指令所有者 + * @return 指令列表 + */ + @NotNull + public static List<@NotNull Command> getRegisteredCommands(final @NotNull CommandOwner owner) { + return CommandManagerKt.getRegisteredCommands(Objects.requireNonNull(owner, "owner")); + } + + /** + * 注册一个指令. + * + * @param command 指令实例 + * @param override 是否覆盖重名指令. + *

+ * 若原有指令 P, 其 {@link Command#getNames()} 为 'a', 'b', 'c'.
+ * 新指令 Q, 其 {@link Command#getNames()} 为 'b', 将会覆盖原指令 A 注册的 'b'. + *

+ * 即注册完成后, 'a' 和 'c' 将会解析到指令 P, 而 'b' 会解析到指令 Q. + * @return 若已有重名指令, 且 overridefalse, 返回 false;
+ * 若已有重名指令, 但 overridetrue, 覆盖原有指令并返回 true. + */ + public static boolean register(final @NotNull Command command, final boolean override) { + Objects.requireNonNull(command, "command"); + return CommandManagerKt.register(command, override); + } + + /** + * 注册一个指令, 已有重复名称的指令时返回 false + * + * @param command 指令实例 + * @return 若已有重名指令, 返回 false, 否则返回 true. + */ + public static boolean register(final @NotNull Command command) { + Objects.requireNonNull(command, "command"); + return register(command, false); + } + + /** + * 查找并返回重名的指令. 返回重名指令. + */ + @Nullable + public static Command findDuplicate(final @NotNull Command command) { + Objects.requireNonNull(command, "command"); + return CommandManagerKt.findDuplicate(command); + } + + /** + * 取消注册这个指令. 若指令未注册, 返回 false. + */ + public static boolean unregister(final @NotNull Command command) { + Objects.requireNonNull(command, "command"); + return CommandManagerKt.unregister(command); + } + + /** + * 取消注册所有属于 owner 的指令 + * + * @param owner 指令所有者 + */ + public static void unregisterAllCommands(final @NotNull CommandOwner owner) { + Objects.requireNonNull(owner, "owner"); + CommandManagerKt.unregisterAllCommands(owner); + } + + /** + * 解析并执行一个指令 + * + * @param args 接受 {@link String} 或 {@link Message} , 其他对象将会被 {@link Object#toString()} + * @return 是否成功解析到指令. 返回 `false` 代表无任何指令匹配 + * @see #executeCommandAsync(CoroutineScope, CommandSender, Object...) + */ + public static boolean executeCommand(final @NotNull CommandSender sender, final @NotNull Object... args) throws InterruptedException { + Objects.requireNonNull(sender, "sender"); + Objects.requireNonNull(args, "args"); + for (Object arg : args) { + Objects.requireNonNull(arg, "element of args"); + } + + return BuildersKt.runBlocking(EmptyCoroutineContext.INSTANCE, (scope, completion) -> CommandManagerKt.executeCommand(sender, args, completion)); + } + + /** + * 异步 (在 Kotlin 协程线程池) 解析并执行一个指令 + * + * @param scope 协程作用域 (用于管理协程生命周期). 一般填入 {@link JavaPlugin} 实例. + * @param args 接受 {@link String} 或 {@link Message} , 其他对象将会被 {@link Object#toString()} + * @return 是否成功解析到指令. 返回 `false` 代表无任何指令匹配 + * @see #executeCommand(CommandSender, Object...) + */ + public static CompletableFuture executeCommandAsync(final @NotNull CoroutineScope scope, final @NotNull CommandSender sender, final @NotNull Object... args) { + Objects.requireNonNull(sender, "sender"); + Objects.requireNonNull(args, "args"); + Objects.requireNonNull(scope, "scope"); + for (Object arg : args) { + Objects.requireNonNull(arg, "element of args"); + } + + return FutureKt.future(scope, EmptyCoroutineContext.INSTANCE, CoroutineStart.DEFAULT, (sc, completion) -> CommandManagerKt.executeCommand(sender, args, completion)); + } +} diff --git a/backend/mirai-console/src/main/java/net/mamoe/mirai/console/utils/BotManager.java b/backend/mirai-console/src/main/java/net/mamoe/mirai/console/utils/BotManager.java index c30422724..285bcfb48 100644 --- a/backend/mirai-console/src/main/java/net/mamoe/mirai/console/utils/BotManager.java +++ b/backend/mirai-console/src/main/java/net/mamoe/mirai/console/utils/BotManager.java @@ -25,7 +25,7 @@ public class BotManager { } public static List getManagers(Bot bot) { - return BotHelperKt.getBotManagers(bot); + return BotManagers.getManagers(bot); } public static boolean isManager(Bot bot, long target) { 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 82b299f82..8cab73f5b 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 @@ -13,8 +13,11 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.io.charsets.Charset import net.mamoe.mirai.Bot -import net.mamoe.mirai.console.plugins.PluginLoader -import net.mamoe.mirai.console.plugins.builtin.JarPluginLoader +import net.mamoe.mirai.console.plugin.PluginLoader +import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader +import net.mamoe.mirai.console.plugin.jvm.JvmPlugin +import net.mamoe.mirai.console.setting.SettingStorage +import net.mamoe.mirai.console.setting.internal.ConsoleBuiltInSetting import net.mamoe.mirai.utils.DefaultLogger import net.mamoe.mirai.utils.MiraiExperimentalAPI import net.mamoe.mirai.utils.MiraiLogger @@ -34,14 +37,48 @@ object MiraiConsole : CoroutineScope, IMiraiConsole { this.instance = instance } - override val build: String get() = instance.build - override val version: String get() = instance.version + /** + * `mirai-console` build 号 + */ + @MiraiExperimentalAPI + override val build: String + get() = instance.build + + /** + * `mirai-console` 版本 + */ + @MiraiExperimentalAPI + override val version: String + get() = instance.version + + /** + * Console 运行路径 + */ override val rootDir: File get() = instance.rootDir + + /** + * Console 前端接口 + */ override val frontEnd: MiraiConsoleFrontEnd get() = instance.frontEnd - override val mainLogger: MiraiLogger get() = instance.mainLogger + + /** + * 与前端交互所使用的 Logger + */ + @MiraiExperimentalAPI + override val mainLogger: MiraiLogger + get() = instance.mainLogger + override val coroutineContext: CoroutineContext get() = instance.coroutineContext - override val builtInPluginLoaders: List> = instance.builtInPluginLoaders + override val builtInPluginLoaders: List> get() = instance.builtInPluginLoaders + + @Suppress("CANNOT_WEAKEN_ACCESS_PRIVILEGE") + internal override val jvmSettingStorage: SettingStorage + get() = instance.jvmSettingStorage + + @Suppress("CANNOT_WEAKEN_ACCESS_PRIVILEGE") + override val consoleBuiltIntSettingStorage: SettingStorage + get() = instance.consoleBuiltIntSettingStorage init { DefaultLogger = { identity -> this.newLogger(identity) } @@ -79,6 +116,16 @@ internal interface IMiraiConsole : CoroutineScope { * 内建加载器列表, 一般需要包含 [JarPluginLoader] */ val builtInPluginLoaders: List> + + /** + * 内建的供 [JvmPlugin] 使用的 [SettingStorage] + */ + val jvmSettingStorage: SettingStorage + + /** + * 内建的供 [ConsoleBuiltInSetting] 使用的 [SettingStorage] + */ + val consoleBuiltIntSettingStorage: SettingStorage } /** diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/Command.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/Command.kt index 609ae4cf9..3b1b85c36 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/Command.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/Command.kt @@ -12,13 +12,8 @@ package net.mamoe.mirai.console.command import net.mamoe.mirai.console.command.description.* -import net.mamoe.mirai.console.command.description.CommandParam -import net.mamoe.mirai.console.command.description.CommandParserContext -import net.mamoe.mirai.console.command.description.EmptyCommandParserContext -import net.mamoe.mirai.console.command.description.plus import net.mamoe.mirai.message.data.PlainText import net.mamoe.mirai.message.data.SingleMessage -import java.lang.Exception import kotlin.reflect.KAnnotatedElement import kotlin.reflect.KClass import kotlin.reflect.full.* @@ -29,20 +24,37 @@ import kotlin.reflect.full.* * @see register 注册这个指令 */ interface Command { + /** + * 指令名. 需要至少有一个元素. 所有元素都不能带有空格 + */ val names: Array - fun getPrimaryName():String = names[0] - val usage: String val description: String + + /** + * 指令权限 + */ val permission: CommandPermission + + /** + * 为 `true` 时表示 [指令前缀][CommandPrefix] 可选 + */ val prefixOptional: Boolean val owner: CommandOwner + /** + * @param args 指令参数. 可能是 [SingleMessage] 或 [String]. 且已经以 ' ' 分割. + */ suspend fun onCommand(sender: CommandSender, args: Array) } +/** + * 主要指令名. 为 [Command.names] 的第一个元素. + */ +val Command.primaryName: String get() = names[0] + /** * 功能最集中的Commend * 支持且只支持有sub的指令 @@ -55,20 +67,26 @@ interface Command { abstract class CompositeCommand @JvmOverloads constructor( override val owner: CommandOwner, vararg names: String, - override val description: String = "no description available", + description: String = "no description available", override val permission: CommandPermission = CommandPermission.Default, override val prefixOptional: Boolean = false, overrideContext: CommandParserContext = EmptyCommandParserContext ) : Command { - - class IllegalParameterException(message:String): Exception(message) - - + override val description = description.trimIndent() override val names: Array = - names.map(String::trim).filterNot(String::isEmpty).map(String::toLowerCase).toTypedArray() + names.map(String::trim).filterNot(String::isEmpty).map(String::toLowerCase).also { list -> + list.firstOrNull { !it.isValidSubName() }?.let { + error("Name is not valid: $it") + } + }.toTypedArray() + + /** + * [CommandArgParser] 的环境 + */ val context: CommandParserContext = CommandParserContext.Builtins + overrideContext - override lateinit var usage: String + override var usage: String = "" // initialized by subCommand reflection + internal set /** 指定子指令要求的权限 */ @Retention(AnnotationRetention.RUNTIME) @@ -107,6 +125,9 @@ abstract class CompositeCommand @JvmOverloads constructor( ) } + + class IllegalParameterException internal constructor(message: String) : Exception(message) + internal val subCommands: Array by lazy { val buildUsage = StringBuilder(this.description).append(": \n") @@ -117,7 +138,7 @@ abstract class CompositeCommand @JvmOverloads constructor( val overridePermission = function.findAnnotation()//optional val subDescription = function.findAnnotation()?.description?:"no description available" - if((function.returnType.classifier as? KClass<*>)?.isSubclassOf(Boolean::class) != true){ + if ((function.returnType.classifier as? KClass<*>)?.isSubclassOf(Boolean::class) != true) { throw IllegalParameterException("Return Type of SubCommand must be Boolean") } @@ -126,7 +147,7 @@ abstract class CompositeCommand @JvmOverloads constructor( throw IllegalParameterException("First parameter (receiver for kotlin) for sub commend " + function.name + " from " + this.getPrimaryName() + " should be ") } - if(notStatic){ + if (notStatic) { parameter.removeAt(0) } @@ -136,12 +157,12 @@ abstract class CompositeCommand @JvmOverloads constructor( ((receiver.type.classifier as? KClass<*>).also { print(it) } ?.isSubclassOf(CommandSender::class) != true) ) { - throw IllegalParameterException("First parameter (receiver for kotlin) for sub commend " + function.name + " from " + this.getPrimaryName() + " should be ") + throw IllegalParameterException("First parameter (receiver for kotlin) for sub commend " + function.name + " from " + this.primaryName + " should be ") } } val commandName = function.findAnnotation()!!.name.map { - if(!it.isValidSubName()){ + if (!it.isValidSubName()) { error("SubName $it is not valid") } it @@ -149,20 +170,22 @@ abstract class CompositeCommand @JvmOverloads constructor( //map parameter val parms = parameter.map { - buildUsage.append("/" + getPrimaryName() + " ") + buildUsage.append("/$primaryName ") - if(it.isVararg){ - throw IllegalParameterException("parameter for sub commend " + function.name + " from " + this.getPrimaryName() + " should not be var arg") + if (it.isVararg) { + throw IllegalParameterException("parameter for sub commend " + function.name + " from " + this.primaryName + " should not be var arg") } - if(it.isOptional){ - throw IllegalParameterException("parameter for sub commend " + function.name + " from " + this.getPrimaryName() + " should not be var optional") + if (it.isOptional) { + throw IllegalParameterException("parameter for sub commend " + function.name + " from " + this.primaryName + " should not be var optional") } - val argName = it.findAnnotation()?.name?:it.name?:"unknown" - buildUsage.append("<").append(argName).append("> ") + val argName = it.findAnnotation()?.name ?: it.name ?: "unknown" + buildUsage.append("<").append(argName).append("> ").append(" ") CommandParam( argName, - (it.type.classifier as? KClass<*>)?: throw IllegalParameterException("unsolved type reference from param " + it.name + " in " + function.name + " from " + this.getPrimaryName())) + (it.type.classifier as? KClass<*>) + ?: throw IllegalParameterException("unsolved type reference from param " + it.name + " in " + function.name + " from " + this.primaryName) + ) }.toTypedArray() buildUsage.append(subDescription).append("\n") @@ -173,9 +196,9 @@ abstract class CompositeCommand @JvmOverloads constructor( subDescription, overridePermission?.permission?.getInstance() ?: permission, onCommand = block { sender: CommandSender, args: Array -> - if(notStatic) { - function.callSuspend(this,sender, *args) as Boolean - }else{ + if (notStatic) { + function.callSuspend(this, sender, *args) as Boolean + } else { function.callSuspend(sender, *args) as Boolean } } @@ -306,7 +329,7 @@ internal fun Any.flattenCommandComponents(): ArrayList { internal inline fun KAnnotatedElement.hasAnnotation(): Boolean = findAnnotation() != null -internal inline fun KClass.getInstance():T { +internal inline fun KClass.getInstance(): T { return this.objectInstance ?: this.createInstance() } diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandManager.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandManager.kt index cd3a229f2..2a5cca566 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandManager.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandManager.kt @@ -8,34 +8,66 @@ */ @file:Suppress("NOTHING_TO_INLINE", "unused") -@file:JvmName("CommandManager") +@file:JvmName("CommandManagerKt") package net.mamoe.mirai.console.command import kotlinx.atomicfu.locks.withLock -import net.mamoe.mirai.console.plugins.Plugin +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import net.mamoe.mirai.console.plugin.Plugin import net.mamoe.mirai.message.data.Message import net.mamoe.mirai.message.data.MessageChain import net.mamoe.mirai.message.data.SingleMessage +import net.mamoe.mirai.utils.MiraiInternalAPI +/** + * 指令的所有者. + * @see PluginCommandOwner + */ sealed class CommandOwner +@MiraiInternalAPI object TestCommandOwner : CommandOwner() -abstract class PluginCommandOwner(val plugin: Plugin) : CommandOwner() +/** + * 插件指令所有者. 插件只能通过 [PluginCommandOwner] 管理指令. + */ +abstract class PluginCommandOwner(val plugin: Plugin) : CommandOwner() { + init { + if (plugin is CoroutineScope) { // JVM Plugin + plugin.coroutineContext[Job]?.invokeOnCompletion { + this.unregisterAllCommands() + } + } + } +} -// 由前端实现 +/** + * 代表控制台所有者. 所有的 mirai-console 内建的指令都属于 [ConsoleCommandOwner]. + * + * 由前端实现 + */ internal abstract class ConsoleCommandOwner : CommandOwner() /** - * 获取已经注册了的指令列表 + * 获取已经注册了的属于这个 [CommandOwner] 的指令列表. + * @see JCommandManager.getRegisteredCommands Java 方法 */ val CommandOwner.registeredCommands: List get() = InternalCommandManager.registeredCommands.filter { it.owner == this } +/** + * 指令前缀, 如 '/' + * @see JCommandManager.getCommandPrefix Java 方法 + */ @get:JvmName("getCommandPrefix") val CommandPrefix: String get() = InternalCommandManager.COMMAND_PREFIX +/** + * 取消注册所有属于 [this] 的指令 + * @see JCommandManager.unregisterAllCommands Java 方法 + */ fun CommandOwner.unregisterAllCommands() { for (registeredCommand in registeredCommands) { registeredCommand.unregister() @@ -43,10 +75,26 @@ fun CommandOwner.unregisterAllCommands() { } /** - * 注册一个指令. 若此指令已经注册或有已经注册的指令与 [SubCommandDescriptor] 重名, 返回 `false` + * 注册一个指令. + * + * @param override 是否覆盖重名指令. + * + * 若原有指令 P, 其 [Command.names] 为 'a', 'b', 'c'. + * 新指令 Q, 其 [Command.names] 为 'b', 将会覆盖原指令 A 注册的 'b'. + * + * 即注册完成后, 'a' 和 'c' 将会解析到指令 P, 而 'b' 会解析到指令 Q. + * + * @return + * 若已有重名指令, 且 [override] 为 `false`, 返回 `false`; + * 若已有重名指令, 但 [override] 为 `true`, 覆盖原有指令并返回 `true`. + * + * @see JCommandManager.register Java 方法 */ -fun Command.register(): Boolean = InternalCommandManager.modifyLock.withLock { - if (findDuplicate() != null) return false +@JvmOverloads +fun Command.register(override: Boolean = false): Boolean = InternalCommandManager.modifyLock.withLock { + if (!override) { + if (findDuplicate() != null) return false + } InternalCommandManager.registeredCommands.add(this@register) if (this.prefixOptional) { for (name in this.names) { @@ -54,6 +102,7 @@ fun Command.register(): Boolean = InternalCommandManager.modifyLock.withLock { } } else { for (name in this.names) { + InternalCommandManager.optionalPrefixCommandMap.remove(name) // ensure resolution consistency InternalCommandManager.requiredPrefixCommandMap[name] = this } } @@ -61,13 +110,17 @@ fun Command.register(): Boolean = InternalCommandManager.modifyLock.withLock { } /** - * 查找是否有重名的指令. 返回重名的指令. + * 查找并返回重名的指令. 返回重名指令. + * + * @see JCommandManager.findDuplicate Java 方法 */ fun Command.findDuplicate(): Command? = InternalCommandManager.registeredCommands.firstOrNull { it.names intersects this.names } /** - * 取消注册这个指令. 若指令未注册, 返回 `false` + * 取消注册这个指令. 若指令未注册, 返回 `false`. + * + * @see JCommandManager.unregister Java 方法 */ fun Command.unregister(): Boolean = InternalCommandManager.modifyLock.withLock { InternalCommandManager.registeredCommands.remove(this) @@ -78,8 +131,12 @@ fun Command.unregister(): Boolean = InternalCommandManager.modifyLock.withLock { /** * 解析并执行一个指令 * + * Java 调用方式: ` CommandManager.executeCommand(Command)` + * * @param messages 接受 [String] 或 [Message], 其他对象将会被 [Any.toString] * @return 是否成功解析到指令. 返回 `false` 代表无任何指令匹配 + * + * @see JCommandManager.executeCommand Java 方法 */ suspend fun CommandSender.executeCommand(vararg messages: Any): Boolean { if (messages.isEmpty()) return false @@ -88,17 +145,21 @@ suspend fun CommandSender.executeCommand(vararg messages: Any): Boolean { messages[0].let { if (it is SingleMessage) it.toString() else it.toString().substringBefore(' ') }) } +@JvmSynthetic internal inline fun List.dropToTypedArray(n: Int): Array = Array(size - n) { this[n + it] } /** * 解析并执行一个指令 * @return 是否成功解析到指令. 返回 `false` 代表无任何指令匹配 + * + * @see JCommandManager.executeCommand Java 方法 */ suspend fun CommandSender.executeCommand(message: MessageChain): Boolean { if (message.isEmpty()) return false return executeCommandInternal(message, message[0].toString()) } +@JvmSynthetic internal suspend inline fun CommandSender.executeCommandInternal( messages: Any, commandName: String diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandSender.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandSender.kt index 5f168a279..b8fe33288 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandSender.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandSender.kt @@ -7,22 +7,26 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -@file:Suppress("NOTHING_TO_INLINE") +@file:Suppress("NOTHING_TO_INLINE", "INAPPLICABLE_JVM_NAME") package net.mamoe.mirai.console.command import kotlinx.coroutines.runBlocking import net.mamoe.mirai.Bot +import net.mamoe.mirai.console.MiraiConsole +import net.mamoe.mirai.console.utils.JavaFriendlyAPI import net.mamoe.mirai.contact.* import net.mamoe.mirai.message.MessageEvent import net.mamoe.mirai.message.data.Message import net.mamoe.mirai.message.data.PlainText +import org.jetbrains.annotations.Contract /** * 指令发送者 * * @see AbstractCommandSender 请继承于该抽象类 */ +@Suppress("FunctionName") interface CommandSender { /** * 与这个 [CommandSender] 相关的 [Bot]. 当通过控制台执行时为 null. @@ -32,15 +36,18 @@ interface CommandSender { /** * 立刻发送一条消息 */ + @JvmSynthetic suspend fun sendMessage(message: Message) - /** - * 写入要发送的内容 所有内容最后会被以一条发出 - */ - fun appendMessage(message: String) + @JvmDefault + @JavaFriendlyAPI + @JvmName("sendMessage") + fun __sendMessageBlocking(messageChain: Message) = runBlocking { sendMessage(messageChain) } - fun sendMessageBlocking(messageChain: Message) = runBlocking { sendMessage(messageChain) } - fun sendMessageBlocking(message: String) = runBlocking { sendMessage(message) } + @JvmDefault + @JavaFriendlyAPI + @JvmName("sendMessage") + fun __sendMessageBlocking(message: String) = runBlocking { sendMessage(message) } } /** @@ -52,42 +59,19 @@ interface BotAwareCommandSender : CommandSender { suspend inline fun CommandSender.sendMessage(message: String) = sendMessage(PlainText(message)) -abstract class AbstractCommandSender : CommandSender { - internal val builder = StringBuilder() - - override fun appendMessage(message: String) { - builder.appendln(message) - } - - internal open suspend fun flushMessage() { - if (builder.isNotEmpty()) { - sendMessage(builder.toString().removeSuffix("\n")) - } - } -} - /** * 控制台指令执行者. 代表由控制台执行指令 */ -object ConsoleCommandSender : AbstractCommandSender() { - override val bot: Nothing? get() = null - - override suspend fun sendMessage(message: Message) { - TODO() - // MiraiConsole.logger("[Command]", 0, messageChain.toString()) - } - - override suspend fun flushMessage() { - super.flushMessage() - builder.clear() - } +// 前端实现 +abstract class ConsoleCommandSender internal constructor() : CommandSender { + final override val bot: Nothing? get() = null } -inline fun Friend.asCommandSender(): FriendCommandSender = FriendCommandSender(this) +fun Friend.asCommandSender(): FriendCommandSender = FriendCommandSender(this) -inline fun Member.asCommandSender(): MemberCommandSender = MemberCommandSender(this) +fun Member.asCommandSender(): MemberCommandSender = MemberCommandSender(this) -inline fun User.asCommandSender(): UserCommandSender { +fun User.asCommandSender(): UserCommandSender { return when (this) { is Friend -> this.asCommandSender() is Member -> this.asCommandSender() @@ -100,7 +84,10 @@ inline fun User.asCommandSender(): UserCommandSender { * 代表一个用户私聊机器人执行指令 * @see User.asCommandSender */ -sealed class UserCommandSender : AbstractCommandSender(), BotAwareCommandSender { +sealed class UserCommandSender : CommandSender, BotAwareCommandSender { + /** + * @see MessageEvent.sender + */ abstract val user: User /** diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/Plugin.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/Plugin.kt similarity index 76% rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/Plugin.kt rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/Plugin.kt index d9ecf24e4..f5a8c5142 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/Plugin.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/Plugin.kt @@ -7,9 +7,10 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -package net.mamoe.mirai.console.plugins +package net.mamoe.mirai.console.plugin -import net.mamoe.mirai.console.plugins.builtin.JvmPlugin +import net.mamoe.mirai.console.plugin.jvm.JvmPlugin +import java.io.File /** * 表示一个 mirai-console 插件. @@ -22,4 +23,9 @@ interface Plugin { * 所属插件加载器实例 */ val loader: PluginLoader<*, *> + + /** + * 插件数据目录 + */ + val dataFolder: File } \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginLoader.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/PluginLoader.kt similarity index 89% rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginLoader.kt rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/PluginLoader.kt index 43af25148..d0e3fdb8b 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginLoader.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/PluginLoader.kt @@ -9,8 +9,9 @@ @file:Suppress("unused") -package net.mamoe.mirai.console.plugins +package net.mamoe.mirai.console.plugin +import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader import java.io.File /** @@ -59,7 +60,7 @@ open class PluginLoadException : RuntimeException { */ interface FilePluginLoader

: PluginLoader { /** - * 所支持的插件文件后缀, 不含 '.'. 如 [JarPluginLoader] 为 "jar" + * 所支持的插件文件后缀, 含 '.'. 如 [JarPluginLoader] 为 ".jar" */ val fileSuffix: String } @@ -70,6 +71,9 @@ abstract class AbstractFilePluginLoader

( private fun pluginsFilesSequence(): Sequence = PluginManager.pluginsDir.walk().filter { it.isFile && it.name.endsWith(fileSuffix, ignoreCase = true) } + /** + * 读取扫描到的后缀与 [fileSuffix] 相同的文件中的 [PluginDescription] + */ protected abstract fun Sequence.mapToDescription(): List final override fun listPlugins(): List = pluginsFilesSequence().mapToDescription() diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginManager.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/PluginManager.kt similarity index 98% rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginManager.kt rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/PluginManager.kt index 09724d3ee..5b94228c5 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginManager.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/PluginManager.kt @@ -9,7 +9,7 @@ @file:Suppress("NOTHING_TO_INLINE") -package net.mamoe.mirai.console.plugins +package net.mamoe.mirai.console.plugin import kotlinx.atomicfu.locks.withLock import net.mamoe.mirai.console.MiraiConsole @@ -24,6 +24,7 @@ inline fun PluginLoader<*, *>.unregister() = PluginManager.unregisterPluginLoade object PluginManager { val pluginsDir = File(MiraiConsole.rootDir, "plugins").apply { mkdir() } + val pluginsDataFolder = File(MiraiConsole.rootDir, "data").apply { mkdir() } private val _pluginLoaders: MutableList> = mutableListOf() private val loadersLock: ReentrantLock = ReentrantLock() diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/description.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/description.kt similarity index 98% rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/description.kt rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/description.kt index 4d23c90e4..e267c0cd8 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/description.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/description.kt @@ -7,7 +7,7 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -package net.mamoe.mirai.console.plugins +package net.mamoe.mirai.console.plugin import kotlinx.serialization.* import kotlinx.serialization.builtins.serializer diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/builtin/JvmPlugin.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/internal/JvmPluginImpl.kt similarity index 56% rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/builtin/JvmPlugin.kt rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/internal/JvmPluginImpl.kt index 970f0b8ae..b10898d4d 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/builtin/JvmPlugin.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/internal/JvmPluginImpl.kt @@ -7,9 +7,7 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "EXPOSED_SUPER_CLASS") - -package net.mamoe.mirai.console.plugins.builtin +package net.mamoe.mirai.console.plugin.internal import kotlinx.atomicfu.locks.withLock import kotlinx.coroutines.CoroutineExceptionHandler @@ -17,91 +15,47 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.SupervisorJob import net.mamoe.mirai.console.MiraiConsole -import net.mamoe.mirai.console.plugins.Plugin -import net.mamoe.mirai.console.plugins.PluginLoader -import net.mamoe.mirai.console.utils.JavaPluginScheduler +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.utils.MiraiLogger +import java.io.File import java.util.concurrent.locks.ReentrantLock import kotlin.coroutines.CoroutineContext import kotlin.coroutines.EmptyCoroutineContext +internal val T.job: Job where T : CoroutineScope, T : Plugin get() = this.coroutineContext[Job]!! -/** - * Java 或 Kotlin Jar 插件 - * - * @see JavaPlugin Java 插件 - * @see KotlinPlugin Kotlin 插件 - */ -interface JvmPlugin : Plugin, CoroutineScope { - /** 日志 */ - val logger: MiraiLogger - - /** 插件描述 */ - val description: JvmPluginDescription - - /** 所属插件加载器实例 */ - override val loader: PluginLoader<*, *> get() = JarPluginLoader - - @JvmDefault - fun onLoad() { - } - - @JvmDefault - fun onEnable() { - } - - @JvmDefault - fun onDisable() { - } -} - -/** - * Java 插件的父类 - */ -abstract class JavaPlugin @JvmOverloads constructor( - parentCoroutineContext: CoroutineContext = EmptyCoroutineContext -) : JvmPlugin, JvmPluginImpl(parentCoroutineContext) { - - /** - * Java API Scheduler - */ - val scheduler: JavaPluginScheduler = - JavaPluginScheduler(this.coroutineContext) -} - -abstract class KotlinPlugin @JvmOverloads constructor( - parentCoroutineContext: CoroutineContext = EmptyCoroutineContext -) : JvmPlugin, JvmPluginImpl(parentCoroutineContext) { - // that's it -} - -internal sealed class JvmPluginImpl( +@PublishedApi +internal abstract class JvmPluginImpl( parentCoroutineContext: CoroutineContext -) : JvmPlugin, CoroutineScope { +) : JvmPlugin, + CoroutineScope { + // region JvmPlugin /** * Initialized immediately after construction of [JvmPluginImpl] instance */ @Suppress("PropertyName") internal lateinit var _description: JvmPluginDescription - // for future use - @Suppress("PropertyName") - @JvmField - internal var _intrinsicCoroutineContext: CoroutineContext = EmptyCoroutineContext - override val description: JvmPluginDescription get() = _description - final override val logger: MiraiLogger by lazy { MiraiConsole.newLogger(this._description.name) } - - @JvmField - internal val coroutineContextInitializer = { - CoroutineExceptionHandler { _, throwable -> logger.error(throwable) } - .plus(parentCoroutineContext) - .plus(SupervisorJob(parentCoroutineContext[Job])) + _intrinsicCoroutineContext + final override val logger: MiraiLogger by lazy { + MiraiConsole.newLogger( + this._description.name + ) } private var firstRun = true + override val dataFolder: File by lazy { + File( + PluginManager.pluginsDataFolder, + description.name + ).apply { mkdir() } + } + internal fun internalOnDisable() { firstRun = false this.onDisable() @@ -116,14 +70,33 @@ internal sealed class JvmPluginImpl( this.onEnable() } + // endregion + + // region CoroutineScope + + // for future use + @Suppress("PropertyName") + @JvmField + internal var _intrinsicCoroutineContext: CoroutineContext = + EmptyCoroutineContext + + @JvmField + internal val coroutineContextInitializer = { + CoroutineExceptionHandler { _, throwable -> logger.error(throwable) } + .plus(parentCoroutineContext) + .plus(SupervisorJob(parentCoroutineContext[Job])) + _intrinsicCoroutineContext + } + private fun refreshCoroutineContext(): CoroutineContext { return coroutineContextInitializer().also { _coroutineContext = it } } - private val contextUpdateLock: ReentrantLock = ReentrantLock() + private val contextUpdateLock: ReentrantLock = + ReentrantLock() private var _coroutineContext: CoroutineContext? = null final override val coroutineContext: CoroutineContext get() = _coroutineContext ?: contextUpdateLock.withLock { _coroutineContext ?: refreshCoroutineContext() } + // endregion } \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginsLoader.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/internal/PluginsLoader.kt similarity index 94% rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginsLoader.kt rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/internal/PluginsLoader.kt index 08051d2cc..217fbeb98 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginsLoader.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/internal/PluginsLoader.kt @@ -7,7 +7,7 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -package net.mamoe.mirai.console.plugins +package net.mamoe.mirai.console.plugin.internal import net.mamoe.mirai.console.MiraiConsole import java.io.File @@ -50,7 +50,13 @@ internal class PluginsLoader(private val parentClassLoader: ClassLoader) { fun loadPluginMainClassByJarFile(pluginName: String, mainClass: String, jarFile: File): Class<*> { try { if (!pluginLoaders.containsKey(pluginName)) { - pluginLoaders[pluginName] = PluginClassLoader(pluginName, jarFile, this, parentClassLoader) + pluginLoaders[pluginName] = + PluginClassLoader( + pluginName, + jarFile, + this, + parentClassLoader + ) } return pluginLoaders[pluginName]!!.loadClass(mainClass) } catch (e: ClassNotFoundException) { diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/builtin/JarPluginLoader.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JarPluginLoader.kt similarity index 86% rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/builtin/JarPluginLoader.kt rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JarPluginLoader.kt index 476a863af..6491cfd7f 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/builtin/JarPluginLoader.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JarPluginLoader.kt @@ -7,15 +7,16 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -package net.mamoe.mirai.console.plugins.builtin +package net.mamoe.mirai.console.plugin.jvm import kotlinx.coroutines.* import net.mamoe.mirai.console.MiraiConsole -import net.mamoe.mirai.console.plugins.AbstractFilePluginLoader -import net.mamoe.mirai.console.plugins.PluginLoadException -import net.mamoe.mirai.console.plugins.PluginsLoader +import net.mamoe.mirai.console.plugin.AbstractFilePluginLoader +import net.mamoe.mirai.console.plugin.PluginLoadException +import net.mamoe.mirai.console.plugin.internal.JvmPluginImpl +import net.mamoe.mirai.console.plugin.internal.PluginsLoader +import net.mamoe.mirai.console.setting.SettingStorage import net.mamoe.mirai.utils.MiraiLogger -import net.mamoe.mirai.utils.error import net.mamoe.yamlkt.Yaml import java.io.File import java.net.URL @@ -25,7 +26,7 @@ import kotlin.reflect.full.createInstance /** * 内建的 Jar (JVM) 插件加载器 */ -object JarPluginLoader : AbstractFilePluginLoader("jar"), CoroutineScope { +object JarPluginLoader : AbstractFilePluginLoader(".jar"), CoroutineScope { private val logger: MiraiLogger by lazy { MiraiConsole.newLogger(JarPluginLoader::class.simpleName!!) } @@ -39,7 +40,8 @@ object JarPluginLoader : AbstractFilePluginLoader.mapToDescription(): List { diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JavaPlugin.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JavaPlugin.kt new file mode 100644 index 000000000..4f245939e --- /dev/null +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JavaPlugin.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2020 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/master/LICENSE + */ + +@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "EXPOSED_SUPER_CLASS") + +package net.mamoe.mirai.console.plugin.jvm + +import net.mamoe.mirai.console.plugin.internal.JvmPluginImpl +import net.mamoe.mirai.console.utils.JavaPluginScheduler +import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.EmptyCoroutineContext + +/** + * Java 插件的父类 + */ +abstract class JavaPlugin @JvmOverloads constructor( + parentCoroutineContext: CoroutineContext = EmptyCoroutineContext +) : JvmPlugin, JvmPluginImpl(parentCoroutineContext) { + + /** + * Java API Scheduler + */ + val scheduler: JavaPluginScheduler = + JavaPluginScheduler(this.coroutineContext) +} \ No newline at end of file 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 new file mode 100644 index 000000000..4321c8255 --- /dev/null +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPlugin.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2020 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/master/LICENSE + */ + +@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "EXPOSED_SUPER_CLASS") + +package net.mamoe.mirai.console.plugin.jvm + +import kotlinx.coroutines.CoroutineScope +import net.mamoe.mirai.console.plugin.Plugin +import net.mamoe.mirai.utils.MiraiLogger + + +/** + * Java 或 Kotlin Jar 插件 + * + * @see JavaPlugin Java 插件 + * @see KotlinPlugin Kotlin 插件 + */ +interface JvmPlugin : Plugin, CoroutineScope { + /** 日志 */ + val logger: MiraiLogger + + /** 插件描述 */ + val description: JvmPluginDescription + + /** 所属插件加载器实例 */ + override val loader: JarPluginLoader get() = JarPluginLoader + + @JvmDefault + fun onLoad() { + } + + @JvmDefault + fun onEnable() { + } + + @JvmDefault + fun onDisable() { + } +} + + diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/builtin/JvmPluginDescription.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPluginDescription.kt similarity index 87% rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/builtin/JvmPluginDescription.kt rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPluginDescription.kt index 562ad58f2..8c239b770 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/builtin/JvmPluginDescription.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPluginDescription.kt @@ -7,15 +7,15 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -package net.mamoe.mirai.console.plugins.builtin +package net.mamoe.mirai.console.plugin.jvm import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.Transient -import net.mamoe.mirai.console.plugins.FilePluginDescription -import net.mamoe.mirai.console.plugins.PluginDependency -import net.mamoe.mirai.console.plugins.PluginDescription -import net.mamoe.mirai.console.plugins.PluginKind +import net.mamoe.mirai.console.plugin.FilePluginDescription +import net.mamoe.mirai.console.plugin.PluginDependency +import net.mamoe.mirai.console.plugin.PluginDescription +import net.mamoe.mirai.console.plugin.PluginKind import java.io.File @Serializable 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 new file mode 100644 index 000000000..891163d74 --- /dev/null +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/KotlinPlugin.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2020 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/master/LICENSE + */ + +@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "EXPOSED_SUPER_CLASS") + +package net.mamoe.mirai.console.plugin.jvm + +import net.mamoe.mirai.console.plugin.internal.JvmPluginImpl +import net.mamoe.mirai.console.plugin.internal.job +import net.mamoe.mirai.console.setting.Setting +import net.mamoe.mirai.console.setting.Value +import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.EmptyCoroutineContext + +/** + * Kotlin 插件的父类 + */ +abstract class KotlinPlugin @JvmOverloads constructor( + parentCoroutineContext: CoroutineContext = EmptyCoroutineContext +) : JvmPlugin, JvmPluginImpl(parentCoroutineContext) { + abstract inner class PluginSetting : Setting() { + private val track = + @Suppress("LeakingThis") + JarPluginLoader.settingStorage.trackOn(this) + + init { + this@KotlinPlugin.job.invokeOnCompletion { + track.close() + } + } + + override fun onElementChanged(value: Value<*>) { + TODO() + } + } +} \ 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 index 0c42bc83d..4e32f1a1a 100644 --- 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 @@ -7,15 +7,17 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -@file:Suppress("NOTHING_TO_INLINE") +@file:Suppress("NOTHING_TO_INLINE", "unused") package net.mamoe.mirai.console.setting import kotlinx.serialization.KSerializer import net.mamoe.mirai.console.setting.internal.SettingImpl +import net.mamoe.mirai.console.setting.internal.serialNameOrPropertyName import net.mamoe.mirai.utils.MiraiExperimentalAPI import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty +import kotlin.reflect.KProperty0 import kotlin.reflect.full.findAnnotation /** @@ -33,6 +35,23 @@ typealias Comment = net.mamoe.yamlkt.Comment */ @Suppress("EXPOSED_SUPER_CLASS") abstract class Setting : SettingImpl() { + + /** + * 表示这个配置的嵌套对象, 自动绑定数据更新. + */ + abstract inner class Inner : Setting() { + internal lateinit var attachedValue: Value<*> + override fun onElementChanged(value: Value<*>) { + this@Setting.onElementChanged(attachedValue) + } + } + + data class PropertyInfo( + val serialName: String, + val annotations: List, + val propertyOriginalName: String? + ) + /** * 这个配置的名称, 仅对于顶层配置有效. */ @@ -43,6 +62,33 @@ abstract class Setting : SettingImpl() { ?: error("Names should be assigned to anonymous classes manually by overriding serialName") + // for Java only + fun addProperty( + propertyInfo: PropertyInfo, + value: Value<*> + ): Value<*> { + if (built) error("The Setting is already serialized so it's structure is immutable.") + valueList.add(value to propertyInfo) + return value + } + + /** + * 获取这个属性的真实 [Value] 委托 + */ + @get:JvmSynthetic + val KProperty0.correspondingValue: Value + @Suppress("UNCHECKED_CAST") + get() = findCorrespondingValue(this) + ?: throw NoSuchElementException("No corresponding Value found for property $this") + + /** + * 获取这个属性的真实 [Value] 委托 + */ + fun findCorrespondingValue(property: KProperty0): Value? { + @Suppress("UNCHECKED_CAST") + return this@Setting.valueList.firstOrNull { it.second.propertyOriginalName == property.name }?.first as Value? + } + /** * 提供属性委托, 并添加这个对象的自动保存跟踪. */ @@ -52,10 +98,12 @@ abstract class Setting : SettingImpl() { property: KProperty<*> ): ReadWriteProperty { if (built) error("The Setting is already serialized so it's structure is immutable.") - valueList.add(this to property) + valueList.add(this to PropertyInfo(property.serialNameOrPropertyName, property.annotations, property.name)) return this } + abstract override fun onElementChanged(value: Value<*>) + override fun toString(): String = yamlForToString.stringify(this.serializer, this) } 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 new file mode 100644 index 000000000..9d14cfcc2 --- /dev/null +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/SettingStorage.kt @@ -0,0 +1,65 @@ +@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") + +package net.mamoe.mirai.console.setting + +import kotlinx.atomicfu.locks.withLock +import kotlinx.serialization.* +import kotlinx.serialization.internal.getChecked +import net.mamoe.mirai.console.setting.internal.SettingSerializerMark +import java.io.Closeable +import java.io.File +import java.util.concurrent.locks.ReentrantLock + +/** + * [Setting] 存储方式 + */ +interface SettingStorage { + interface TrackedSetting : Closeable { + fun save() + fun update() + + override fun close() + } + + fun trackOn(setting: Setting): TrackedSetting + + fun saveAll() + fun updateAll() +} + +class SingleFileSettingStorage( + val file: File +) : SettingStorage { + private val descriptor: MutableList = ArrayList() + private val updaterSerializer: KSerializer = object : KSerializer { + override val descriptor: SerialDescriptor = SerialDescriptor("SingleFileSettingStorage") { + TODO() + } + + override fun deserialize(decoder: Decoder): SettingSerializerMark { + TODO("Not yet implemented") + } + + override fun serialize(encoder: Encoder, value: SettingSerializerMark) { + TODO("Not yet implemented") + } + + } + + init { + require(file.isFile) { "file $file is not a file" } + require(file.canRead()) { "file $file is not readable" } + } + + override fun trackOn(setting: Setting): SettingStorage.TrackedSetting { + TODO("Not yet implemented") + } + + override fun saveAll() { + TODO("Not yet implemented") + } + + override fun updateAll() { + TODO("Not yet implemented") + } +} \ 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 index 1fd951369..4706684f9 100644 --- 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 @@ -124,7 +124,11 @@ fun Setting.value(default: T): Value { require(this::class != default::class) { "Recursive nesting is prohibited" } - return valueImpl(default) + return valueImpl(default).also { + if (default is Setting.Inner) { + default.attachedValue = it + } + } } inline fun Setting.value(default: T, crossinline initializer: T.() -> Unit): Value = diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ConsoleBuiltInSetting.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ConsoleBuiltInSetting.kt new file mode 100644 index 000000000..5597e81cb --- /dev/null +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ConsoleBuiltInSetting.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2020 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/master/LICENSE + */ + +package net.mamoe.mirai.console.setting.internal + +import kotlinx.coroutines.Job +import net.mamoe.mirai.console.MiraiConsole +import net.mamoe.mirai.console.setting.Setting +import net.mamoe.mirai.console.setting.Value + + +internal abstract class ConsoleBuiltInSetting : Setting() { + private val track = + @Suppress("LeakingThis") + MiraiConsole.jvmSettingStorage.trackOn(this) + + init { + MiraiConsole.coroutineContext[Job]!!.invokeOnCompletion { + track.close() + } + } + + override fun onElementChanged(value: Value<*>) { + TODO() + } +} \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_ValueImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_ValueImpl.kt index d43cfc582..e6ac2ab62 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_ValueImpl.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_ValueImpl.kt @@ -9,7 +9,10 @@ package net.mamoe.mirai.console.setting.internal -import kotlinx.serialization.* +import kotlinx.serialization.Decoder +import kotlinx.serialization.Encoder +import kotlinx.serialization.KSerializer +import kotlinx.serialization.SerialDescriptor import kotlinx.serialization.builtins.* import net.mamoe.mirai.console.setting.* @@ -31,7 +34,7 @@ internal fun Setting.valueImpl(default: Int): IntValue { onElementChanged(this) } } - override val serializer = Int.serializer() + override val serializer get() = Int.serializer() } } @@ -46,7 +49,7 @@ internal fun Setting.valueImpl(default: Short): ShortValue { onElementChanged(this) } } - override val serializer = Short.serializer() + override val serializer get() = Short.serializer() } } @@ -61,7 +64,7 @@ internal fun Setting.valueImpl(default: Byte): ByteValue { onElementChanged(this) } } - override val serializer = Byte.serializer() + override val serializer get() = Byte.serializer() } } @@ -76,7 +79,7 @@ internal fun Setting.valueImpl(default: Long): LongValue { onElementChanged(this) } } - override val serializer = Long.serializer() + override val serializer get() = Long.serializer() } } @@ -91,7 +94,7 @@ internal fun Setting.valueImpl(default: Float): FloatValue { onElementChanged(this) } } - override val serializer = Float.serializer() + override val serializer get() = Float.serializer() } } @@ -106,7 +109,7 @@ internal fun Setting.valueImpl(default: Double): DoubleValue { onElementChanged(this) } } - override val serializer = Double.serializer() + override val serializer get() = Double.serializer() } } @@ -121,7 +124,7 @@ internal fun Setting.valueImpl(default: Boolean): BooleanValue { onElementChanged(this) } } - override val serializer = Boolean.serializer() + override val serializer get() = Boolean.serializer() } } @@ -136,7 +139,7 @@ internal fun Setting.valueImpl(default: Char): CharValue { onElementChanged(this) } } - override val serializer = Char.serializer() + override val serializer get() = Char.serializer() } } @@ -151,7 +154,7 @@ internal fun Setting.valueImpl(default: String): StringValue { onElementChanged(this) } } - override val serializer = String.serializer() + override val serializer get() = String.serializer() } } @@ -166,7 +169,7 @@ internal fun Setting.valueImpl(default: IntArray): IntArrayValue { onElementChanged(this) } } - override val serializer = IntArraySerializer() + override val serializer get() = IntArraySerializer() } } @@ -181,7 +184,7 @@ internal fun Setting.valueImpl(default: ShortArray): ShortArrayValue { onElementChanged(this) } } - override val serializer = ShortArraySerializer() + override val serializer get() = ShortArraySerializer() } } @@ -196,7 +199,7 @@ internal fun Setting.valueImpl(default: ByteArray): ByteArrayValue { onElementChanged(this) } } - override val serializer = ByteArraySerializer() + override val serializer get() = ByteArraySerializer() } } @@ -211,7 +214,7 @@ internal fun Setting.valueImpl(default: LongArray): LongArrayValue { onElementChanged(this) } } - override val serializer = LongArraySerializer() + override val serializer get() = LongArraySerializer() } } @@ -226,7 +229,7 @@ internal fun Setting.valueImpl(default: FloatArray): FloatArrayValue { onElementChanged(this) } } - override val serializer = FloatArraySerializer() + override val serializer get() = FloatArraySerializer() } } @@ -241,7 +244,7 @@ internal fun Setting.valueImpl(default: DoubleArray): DoubleArrayValue { onElementChanged(this) } } - override val serializer = DoubleArraySerializer() + override val serializer get() = DoubleArraySerializer() } } @@ -256,7 +259,7 @@ internal fun Setting.valueImpl(default: BooleanArray): BooleanArrayValue { onElementChanged(this) } } - override val serializer = BooleanArraySerializer() + override val serializer get() = BooleanArraySerializer() } } @@ -271,7 +274,7 @@ internal fun Setting.valueImpl(default: CharArray): CharArrayValue { onElementChanged(this) } } - override val serializer = CharArraySerializer() + override val serializer get() = CharArraySerializer() } } @@ -286,7 +289,7 @@ internal fun Setting.valueImpl(default: Array): TypedIntArrayValue { onElementChanged(this) } } - override val serializer = ArraySerializer(Int.serializer()) + override val serializer get() = ArraySerializer(Int.serializer()) } } @@ -301,7 +304,7 @@ internal fun Setting.valueImpl(default: Array): TypedShortArrayValue { onElementChanged(this) } } - override val serializer = ArraySerializer(Short.serializer()) + override val serializer get() = ArraySerializer(Short.serializer()) } } @@ -316,7 +319,7 @@ internal fun Setting.valueImpl(default: Array): TypedByteArrayValue { onElementChanged(this) } } - override val serializer = ArraySerializer(Byte.serializer()) + override val serializer get() = ArraySerializer(Byte.serializer()) } } @@ -331,7 +334,7 @@ internal fun Setting.valueImpl(default: Array): TypedLongArrayValue { onElementChanged(this) } } - override val serializer = ArraySerializer(Long.serializer()) + override val serializer get() = ArraySerializer(Long.serializer()) } } @@ -346,7 +349,7 @@ internal fun Setting.valueImpl(default: Array): TypedFloatArrayValue { onElementChanged(this) } } - override val serializer = ArraySerializer(Float.serializer()) + override val serializer get() = ArraySerializer(Float.serializer()) } } @@ -361,7 +364,7 @@ internal fun Setting.valueImpl(default: Array): TypedDoubleArrayValue { onElementChanged(this) } } - override val serializer = ArraySerializer(Double.serializer()) + override val serializer get() = ArraySerializer(Double.serializer()) } } @@ -376,7 +379,7 @@ internal fun Setting.valueImpl(default: Array): TypedBooleanArrayValue onElementChanged(this) } } - override val serializer = ArraySerializer(Boolean.serializer()) + override val serializer get() = ArraySerializer(Boolean.serializer()) } } @@ -391,7 +394,7 @@ internal fun Setting.valueImpl(default: Array): TypedCharArrayValue { onElementChanged(this) } } - override val serializer = ArraySerializer(Char.serializer()) + override val serializer get() = ArraySerializer(Char.serializer()) } } @@ -406,7 +409,7 @@ internal fun Setting.valueImpl(default: Array): TypedStringArrayValue { onElementChanged(this) } } - override val serializer = ArraySerializer(String.serializer()) + override val serializer get() = ArraySerializer(String.serializer()) } } @@ -422,7 +425,7 @@ internal fun Setting.valueImpl(default: List): IntListValue { onElementChanged(this) } } - override val serializer = ListSerializer(Int.serializer()) + override val serializer get() = ListSerializer(Int.serializer()) } } @@ -438,7 +441,7 @@ internal fun Setting.valueImpl(default: List): ShortListValue { onElementChanged(this) } } - override val serializer = ListSerializer(Short.serializer()) + override val serializer get() = ListSerializer(Short.serializer()) } } @@ -454,7 +457,7 @@ internal fun Setting.valueImpl(default: List): ByteListValue { onElementChanged(this) } } - override val serializer = ListSerializer(Byte.serializer()) + override val serializer get() = ListSerializer(Byte.serializer()) } } @@ -470,7 +473,7 @@ internal fun Setting.valueImpl(default: List): LongListValue { onElementChanged(this) } } - override val serializer = ListSerializer(Long.serializer()) + override val serializer get() = ListSerializer(Long.serializer()) } } @@ -486,7 +489,7 @@ internal fun Setting.valueImpl(default: List): FloatListValue { onElementChanged(this) } } - override val serializer = ListSerializer(Float.serializer()) + override val serializer get() = ListSerializer(Float.serializer()) } } @@ -502,7 +505,7 @@ internal fun Setting.valueImpl(default: List): DoubleListValue { onElementChanged(this) } } - override val serializer = ListSerializer(Double.serializer()) + override val serializer get() = ListSerializer(Double.serializer()) } } @@ -518,7 +521,7 @@ internal fun Setting.valueImpl(default: List): BooleanListValue { onElementChanged(this) } } - override val serializer = ListSerializer(Boolean.serializer()) + override val serializer get() = ListSerializer(Boolean.serializer()) } } @@ -534,7 +537,7 @@ internal fun Setting.valueImpl(default: List): CharListValue { onElementChanged(this) } } - override val serializer = ListSerializer(Char.serializer()) + override val serializer get() = ListSerializer(Char.serializer()) } } @@ -550,7 +553,7 @@ internal fun Setting.valueImpl(default: List): StringListValue { onElementChanged(this) } } - override val serializer = ListSerializer(String.serializer()) + override val serializer get() = ListSerializer(String.serializer()) } } @@ -566,7 +569,7 @@ internal fun Setting.valueImpl(default: Set): IntSetValue { onElementChanged(this) } } - override val serializer = SetSerializer(Int.serializer()) + override val serializer get() = SetSerializer(Int.serializer()) } } @@ -582,7 +585,7 @@ internal fun Setting.valueImpl(default: Set): ShortSetValue { onElementChanged(this) } } - override val serializer = SetSerializer(Short.serializer()) + override val serializer get() = SetSerializer(Short.serializer()) } } @@ -598,7 +601,7 @@ internal fun Setting.valueImpl(default: Set): ByteSetValue { onElementChanged(this) } } - override val serializer = SetSerializer(Byte.serializer()) + override val serializer get() = SetSerializer(Byte.serializer()) } } @@ -614,7 +617,7 @@ internal fun Setting.valueImpl(default: Set): LongSetValue { onElementChanged(this) } } - override val serializer = SetSerializer(Long.serializer()) + override val serializer get() = SetSerializer(Long.serializer()) } } @@ -630,7 +633,7 @@ internal fun Setting.valueImpl(default: Set): FloatSetValue { onElementChanged(this) } } - override val serializer = SetSerializer(Float.serializer()) + override val serializer get() = SetSerializer(Float.serializer()) } } @@ -646,7 +649,7 @@ internal fun Setting.valueImpl(default: Set): DoubleSetValue { onElementChanged(this) } } - override val serializer = SetSerializer(Double.serializer()) + override val serializer get() = SetSerializer(Double.serializer()) } } @@ -662,7 +665,7 @@ internal fun Setting.valueImpl(default: Set): BooleanSetValue { onElementChanged(this) } } - override val serializer = SetSerializer(Boolean.serializer()) + override val serializer get() = SetSerializer(Boolean.serializer()) } } @@ -678,7 +681,7 @@ internal fun Setting.valueImpl(default: Set): CharSetValue { onElementChanged(this) } } - override val serializer = SetSerializer(Char.serializer()) + override val serializer get() = SetSerializer(Char.serializer()) } } @@ -694,7 +697,7 @@ internal fun Setting.valueImpl(default: Set): StringSetValue { onElementChanged(this) } } - override val serializer = SetSerializer(String.serializer()) + override val serializer get() = SetSerializer(String.serializer()) } } @@ -705,7 +708,7 @@ internal fun Setting.valueImpl( ): MutableIntListValue { var internalValue: MutableList = default - val delegt = dynamicMutableList{ internalValue } + val delegt = dynamicMutableList { internalValue } return object : MutableIntListValue(), MutableList by delegt { override var value: MutableList get() = internalValue @@ -715,15 +718,15 @@ internal fun Setting.valueImpl( onElementChanged(this) } } - + private val outerThis get() = this - + override val serializer: KSerializer> = object : KSerializer> { private val delegate = ListSerializer(Int.serializer()) - override val descriptor: SerialDescriptor = delegate.descriptor + override val descriptor: SerialDescriptor get() = delegate.descriptor override fun deserialize(decoder: Decoder): MutableList { - return delegate.deserialize(decoder).toMutableList().observable { + return delegate.deserialize(decoder).toMutableList().observable { onElementChanged(outerThis) } } @@ -741,7 +744,7 @@ internal fun Setting.valueImpl( ): MutableShortListValue { var internalValue: MutableList = default - val delegt = dynamicMutableList{ internalValue } + val delegt = dynamicMutableList { internalValue } return object : MutableShortListValue(), MutableList by delegt { override var value: MutableList get() = internalValue @@ -751,15 +754,15 @@ internal fun Setting.valueImpl( onElementChanged(this) } } - + private val outerThis get() = this - + override val serializer: KSerializer> = object : KSerializer> { private val delegate = ListSerializer(Short.serializer()) - override val descriptor: SerialDescriptor = delegate.descriptor + override val descriptor: SerialDescriptor get() = delegate.descriptor override fun deserialize(decoder: Decoder): MutableList { - return delegate.deserialize(decoder).toMutableList().observable { + return delegate.deserialize(decoder).toMutableList().observable { onElementChanged(outerThis) } } @@ -777,7 +780,7 @@ internal fun Setting.valueImpl( ): MutableByteListValue { var internalValue: MutableList = default - val delegt = dynamicMutableList{ internalValue } + val delegt = dynamicMutableList { internalValue } return object : MutableByteListValue(), MutableList by delegt { override var value: MutableList get() = internalValue @@ -787,15 +790,15 @@ internal fun Setting.valueImpl( onElementChanged(this) } } - + private val outerThis get() = this - + override val serializer: KSerializer> = object : KSerializer> { private val delegate = ListSerializer(Byte.serializer()) - override val descriptor: SerialDescriptor = delegate.descriptor + override val descriptor: SerialDescriptor get() = delegate.descriptor override fun deserialize(decoder: Decoder): MutableList { - return delegate.deserialize(decoder).toMutableList().observable { + return delegate.deserialize(decoder).toMutableList().observable { onElementChanged(outerThis) } } @@ -813,7 +816,7 @@ internal fun Setting.valueImpl( ): MutableLongListValue { var internalValue: MutableList = default - val delegt = dynamicMutableList{ internalValue } + val delegt = dynamicMutableList { internalValue } return object : MutableLongListValue(), MutableList by delegt { override var value: MutableList get() = internalValue @@ -823,15 +826,15 @@ internal fun Setting.valueImpl( onElementChanged(this) } } - + private val outerThis get() = this - + override val serializer: KSerializer> = object : KSerializer> { private val delegate = ListSerializer(Long.serializer()) - override val descriptor: SerialDescriptor = delegate.descriptor + override val descriptor: SerialDescriptor get() = delegate.descriptor override fun deserialize(decoder: Decoder): MutableList { - return delegate.deserialize(decoder).toMutableList().observable { + return delegate.deserialize(decoder).toMutableList().observable { onElementChanged(outerThis) } } @@ -849,7 +852,7 @@ internal fun Setting.valueImpl( ): MutableFloatListValue { var internalValue: MutableList = default - val delegt = dynamicMutableList{ internalValue } + val delegt = dynamicMutableList { internalValue } return object : MutableFloatListValue(), MutableList by delegt { override var value: MutableList get() = internalValue @@ -859,15 +862,15 @@ internal fun Setting.valueImpl( onElementChanged(this) } } - + private val outerThis get() = this - + override val serializer: KSerializer> = object : KSerializer> { private val delegate = ListSerializer(Float.serializer()) - override val descriptor: SerialDescriptor = delegate.descriptor + override val descriptor: SerialDescriptor get() = delegate.descriptor override fun deserialize(decoder: Decoder): MutableList { - return delegate.deserialize(decoder).toMutableList().observable { + return delegate.deserialize(decoder).toMutableList().observable { onElementChanged(outerThis) } } @@ -885,7 +888,7 @@ internal fun Setting.valueImpl( ): MutableDoubleListValue { var internalValue: MutableList = default - val delegt = dynamicMutableList{ internalValue } + val delegt = dynamicMutableList { internalValue } return object : MutableDoubleListValue(), MutableList by delegt { override var value: MutableList get() = internalValue @@ -895,15 +898,15 @@ internal fun Setting.valueImpl( onElementChanged(this) } } - + private val outerThis get() = this - + override val serializer: KSerializer> = object : KSerializer> { private val delegate = ListSerializer(Double.serializer()) - override val descriptor: SerialDescriptor = delegate.descriptor + override val descriptor: SerialDescriptor get() = delegate.descriptor override fun deserialize(decoder: Decoder): MutableList { - return delegate.deserialize(decoder).toMutableList().observable { + return delegate.deserialize(decoder).toMutableList().observable { onElementChanged(outerThis) } } @@ -921,7 +924,7 @@ internal fun Setting.valueImpl( ): MutableBooleanListValue { var internalValue: MutableList = default - val delegt = dynamicMutableList{ internalValue } + val delegt = dynamicMutableList { internalValue } return object : MutableBooleanListValue(), MutableList by delegt { override var value: MutableList get() = internalValue @@ -931,15 +934,15 @@ internal fun Setting.valueImpl( onElementChanged(this) } } - + private val outerThis get() = this - + override val serializer: KSerializer> = object : KSerializer> { private val delegate = ListSerializer(Boolean.serializer()) - override val descriptor: SerialDescriptor = delegate.descriptor + override val descriptor: SerialDescriptor get() = delegate.descriptor override fun deserialize(decoder: Decoder): MutableList { - return delegate.deserialize(decoder).toMutableList().observable { + return delegate.deserialize(decoder).toMutableList().observable { onElementChanged(outerThis) } } @@ -957,7 +960,7 @@ internal fun Setting.valueImpl( ): MutableCharListValue { var internalValue: MutableList = default - val delegt = dynamicMutableList{ internalValue } + val delegt = dynamicMutableList { internalValue } return object : MutableCharListValue(), MutableList by delegt { override var value: MutableList get() = internalValue @@ -967,15 +970,15 @@ internal fun Setting.valueImpl( onElementChanged(this) } } - + private val outerThis get() = this - + override val serializer: KSerializer> = object : KSerializer> { private val delegate = ListSerializer(Char.serializer()) - override val descriptor: SerialDescriptor = delegate.descriptor + override val descriptor: SerialDescriptor get() = delegate.descriptor override fun deserialize(decoder: Decoder): MutableList { - return delegate.deserialize(decoder).toMutableList().observable { + return delegate.deserialize(decoder).toMutableList().observable { onElementChanged(outerThis) } } @@ -993,7 +996,7 @@ internal fun Setting.valueImpl( ): MutableStringListValue { var internalValue: MutableList = default - val delegt = dynamicMutableList{ internalValue } + val delegt = dynamicMutableList { internalValue } return object : MutableStringListValue(), MutableList by delegt { override var value: MutableList get() = internalValue @@ -1003,15 +1006,15 @@ internal fun Setting.valueImpl( onElementChanged(this) } } - + private val outerThis get() = this - + override val serializer: KSerializer> = object : KSerializer> { private val delegate = ListSerializer(String.serializer()) - override val descriptor: SerialDescriptor = delegate.descriptor + override val descriptor: SerialDescriptor get() = delegate.descriptor override fun deserialize(decoder: Decoder): MutableList { - return delegate.deserialize(decoder).toMutableList().observable { + return delegate.deserialize(decoder).toMutableList().observable { onElementChanged(outerThis) } } @@ -1029,7 +1032,7 @@ internal fun Setting.valueImpl( ): MutableIntSetValue { var internalValue: MutableSet = default - val delegt = dynamicMutableSet{ internalValue } + val delegt = dynamicMutableSet { internalValue } return object : MutableIntSetValue(), MutableSet by delegt { override var value: MutableSet get() = internalValue @@ -1039,15 +1042,15 @@ internal fun Setting.valueImpl( onElementChanged(this) } } - + private val outerThis get() = this - + override val serializer: KSerializer> = object : KSerializer> { private val delegate = SetSerializer(Int.serializer()) - override val descriptor: SerialDescriptor = delegate.descriptor + override val descriptor: SerialDescriptor get() = delegate.descriptor override fun deserialize(decoder: Decoder): MutableSet { - return delegate.deserialize(decoder).toMutableSet().observable { + return delegate.deserialize(decoder).toMutableSet().observable { onElementChanged(outerThis) } } @@ -1065,7 +1068,7 @@ internal fun Setting.valueImpl( ): MutableShortSetValue { var internalValue: MutableSet = default - val delegt = dynamicMutableSet{ internalValue } + val delegt = dynamicMutableSet { internalValue } return object : MutableShortSetValue(), MutableSet by delegt { override var value: MutableSet get() = internalValue @@ -1075,15 +1078,15 @@ internal fun Setting.valueImpl( onElementChanged(this) } } - + private val outerThis get() = this - + override val serializer: KSerializer> = object : KSerializer> { private val delegate = SetSerializer(Short.serializer()) - override val descriptor: SerialDescriptor = delegate.descriptor + override val descriptor: SerialDescriptor get() = delegate.descriptor override fun deserialize(decoder: Decoder): MutableSet { - return delegate.deserialize(decoder).toMutableSet().observable { + return delegate.deserialize(decoder).toMutableSet().observable { onElementChanged(outerThis) } } @@ -1101,7 +1104,7 @@ internal fun Setting.valueImpl( ): MutableByteSetValue { var internalValue: MutableSet = default - val delegt = dynamicMutableSet{ internalValue } + val delegt = dynamicMutableSet { internalValue } return object : MutableByteSetValue(), MutableSet by delegt { override var value: MutableSet get() = internalValue @@ -1111,15 +1114,15 @@ internal fun Setting.valueImpl( onElementChanged(this) } } - + private val outerThis get() = this - + override val serializer: KSerializer> = object : KSerializer> { private val delegate = SetSerializer(Byte.serializer()) - override val descriptor: SerialDescriptor = delegate.descriptor + override val descriptor: SerialDescriptor get() = delegate.descriptor override fun deserialize(decoder: Decoder): MutableSet { - return delegate.deserialize(decoder).toMutableSet().observable { + return delegate.deserialize(decoder).toMutableSet().observable { onElementChanged(outerThis) } } @@ -1137,7 +1140,7 @@ internal fun Setting.valueImpl( ): MutableLongSetValue { var internalValue: MutableSet = default - val delegt = dynamicMutableSet{ internalValue } + val delegt = dynamicMutableSet { internalValue } return object : MutableLongSetValue(), MutableSet by delegt { override var value: MutableSet get() = internalValue @@ -1147,15 +1150,15 @@ internal fun Setting.valueImpl( onElementChanged(this) } } - + private val outerThis get() = this - + override val serializer: KSerializer> = object : KSerializer> { private val delegate = SetSerializer(Long.serializer()) - override val descriptor: SerialDescriptor = delegate.descriptor + override val descriptor: SerialDescriptor get() = delegate.descriptor override fun deserialize(decoder: Decoder): MutableSet { - return delegate.deserialize(decoder).toMutableSet().observable { + return delegate.deserialize(decoder).toMutableSet().observable { onElementChanged(outerThis) } } @@ -1173,7 +1176,7 @@ internal fun Setting.valueImpl( ): MutableFloatSetValue { var internalValue: MutableSet = default - val delegt = dynamicMutableSet{ internalValue } + val delegt = dynamicMutableSet { internalValue } return object : MutableFloatSetValue(), MutableSet by delegt { override var value: MutableSet get() = internalValue @@ -1183,15 +1186,15 @@ internal fun Setting.valueImpl( onElementChanged(this) } } - + private val outerThis get() = this - + override val serializer: KSerializer> = object : KSerializer> { private val delegate = SetSerializer(Float.serializer()) - override val descriptor: SerialDescriptor = delegate.descriptor + override val descriptor: SerialDescriptor get() = delegate.descriptor override fun deserialize(decoder: Decoder): MutableSet { - return delegate.deserialize(decoder).toMutableSet().observable { + return delegate.deserialize(decoder).toMutableSet().observable { onElementChanged(outerThis) } } @@ -1209,7 +1212,7 @@ internal fun Setting.valueImpl( ): MutableDoubleSetValue { var internalValue: MutableSet = default - val delegt = dynamicMutableSet{ internalValue } + val delegt = dynamicMutableSet { internalValue } return object : MutableDoubleSetValue(), MutableSet by delegt { override var value: MutableSet get() = internalValue @@ -1219,15 +1222,15 @@ internal fun Setting.valueImpl( onElementChanged(this) } } - + private val outerThis get() = this - + override val serializer: KSerializer> = object : KSerializer> { private val delegate = SetSerializer(Double.serializer()) - override val descriptor: SerialDescriptor = delegate.descriptor + override val descriptor: SerialDescriptor get() = delegate.descriptor override fun deserialize(decoder: Decoder): MutableSet { - return delegate.deserialize(decoder).toMutableSet().observable { + return delegate.deserialize(decoder).toMutableSet().observable { onElementChanged(outerThis) } } @@ -1245,7 +1248,7 @@ internal fun Setting.valueImpl( ): MutableBooleanSetValue { var internalValue: MutableSet = default - val delegt = dynamicMutableSet{ internalValue } + val delegt = dynamicMutableSet { internalValue } return object : MutableBooleanSetValue(), MutableSet by delegt { override var value: MutableSet get() = internalValue @@ -1255,15 +1258,15 @@ internal fun Setting.valueImpl( onElementChanged(this) } } - + private val outerThis get() = this - + override val serializer: KSerializer> = object : KSerializer> { private val delegate = SetSerializer(Boolean.serializer()) - override val descriptor: SerialDescriptor = delegate.descriptor + override val descriptor: SerialDescriptor get() = delegate.descriptor override fun deserialize(decoder: Decoder): MutableSet { - return delegate.deserialize(decoder).toMutableSet().observable { + return delegate.deserialize(decoder).toMutableSet().observable { onElementChanged(outerThis) } } @@ -1281,7 +1284,7 @@ internal fun Setting.valueImpl( ): MutableCharSetValue { var internalValue: MutableSet = default - val delegt = dynamicMutableSet{ internalValue } + val delegt = dynamicMutableSet { internalValue } return object : MutableCharSetValue(), MutableSet by delegt { override var value: MutableSet get() = internalValue @@ -1291,15 +1294,15 @@ internal fun Setting.valueImpl( onElementChanged(this) } } - + private val outerThis get() = this - + override val serializer: KSerializer> = object : KSerializer> { private val delegate = SetSerializer(Char.serializer()) - override val descriptor: SerialDescriptor = delegate.descriptor + override val descriptor: SerialDescriptor get() = delegate.descriptor override fun deserialize(decoder: Decoder): MutableSet { - return delegate.deserialize(decoder).toMutableSet().observable { + return delegate.deserialize(decoder).toMutableSet().observable { onElementChanged(outerThis) } } @@ -1317,7 +1320,7 @@ internal fun Setting.valueImpl( ): MutableStringSetValue { var internalValue: MutableSet = default - val delegt = dynamicMutableSet{ internalValue } + val delegt = dynamicMutableSet { internalValue } return object : MutableStringSetValue(), MutableSet by delegt { override var value: MutableSet get() = internalValue @@ -1327,15 +1330,15 @@ internal fun Setting.valueImpl( onElementChanged(this) } } - + private val outerThis get() = this - + override val serializer: KSerializer> = object : KSerializer> { private val delegate = SetSerializer(String.serializer()) - override val descriptor: SerialDescriptor = delegate.descriptor + override val descriptor: SerialDescriptor get() = delegate.descriptor override fun deserialize(decoder: Decoder): MutableSet { - return delegate.deserialize(decoder).toMutableSet().observable { + return delegate.deserialize(decoder).toMutableSet().observable { onElementChanged(outerThis) } } @@ -1359,7 +1362,7 @@ internal fun Setting.valueImpl(default: T): Value { onElementChanged(this) } } - override val serializer = object : KSerializer{ + override val serializer = object : KSerializer { override val descriptor: SerialDescriptor get() = internalValue.updaterSerializer.descriptor diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/internal.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/internal.kt index ee3e4418b..3ca8bbafb 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/internal.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/internal.kt @@ -24,7 +24,7 @@ import kotlin.reflect.full.findAnnotation internal abstract class SettingImpl { @JvmField - internal var valueList: MutableList, KProperty<*>>> = mutableListOf() + internal var valueList: MutableList, Setting.PropertyInfo>> = mutableListOf() @JvmField internal var built: Boolean = false @@ -53,9 +53,7 @@ internal abstract class SettingImpl { } } - internal fun onElementChanged(value: Value<*>) { - println("my value changed!") - } + abstract fun onElementChanged(value: Value<*>) companion object { @JvmStatic @@ -78,8 +76,9 @@ internal class SettingUpdaterSerializer( override val descriptor: SerialDescriptor by lazy { @OptIn(MiraiExperimentalAPI::class) SerialDescriptor(instance.serialName) { - for ((value, property) in instance.valueList) { - element(property.serialNameOrPropertyName, value.serializer.descriptor, annotations, true) + for ((value, prop) in instance.valueList) { + val (serialName, annotations) = prop + element(serialName, value.serializer.descriptor, annotations, true) } } } diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/internalValueImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/internalValueImpl.kt index 0942f9fdd..113a9da03 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/internalValueImpl.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/internalValueImpl.kt @@ -17,7 +17,9 @@ import net.mamoe.mirai.console.setting.* import net.mamoe.yamlkt.YamlDynamicSerializer import kotlin.internal.LowPriorityInOverloadResolution import kotlin.reflect.KClass +import kotlin.reflect.KType import kotlin.reflect.full.createInstance +import kotlin.reflect.typeOf /// region MUTABLE LIST @@ -291,6 +293,7 @@ internal fun Setting.valueImpl( /** * For primitives and serializable only */ +@OptIn(ExperimentalStdlibApi::class) @PublishedApi @LowPriorityInOverloadResolution internal inline fun Setting.valueImpl(default: T): Value = diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/BotHelper.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/BotManagers.kt similarity index 62% rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/BotHelper.kt rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/BotManagers.kt index 5bef2c575..65be10639 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/BotHelper.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/BotManagers.kt @@ -6,14 +6,21 @@ * * https://github.com/mamoe/mirai/blob/master/LICENSE */ +@file:JvmName("BotManagers") package net.mamoe.mirai.console.utils +import kotlinx.atomicfu.locks.withLock import net.mamoe.mirai.Bot -import net.mamoe.mirai.console.MiraiConsole -import net.mamoe.mirai.console.plugins.* +import net.mamoe.mirai.console.setting.Value +import net.mamoe.mirai.console.setting.internal.ConsoleBuiltInSetting +import net.mamoe.mirai.console.setting.value import net.mamoe.mirai.contact.User -import java.io.File +import java.util.concurrent.TimeUnit +import java.util.concurrent.locks.Condition +import java.util.concurrent.locks.Lock +import java.util.concurrent.locks.ReentrantLock +import kotlin.properties.ReadWriteProperty /** @@ -32,15 +39,4 @@ fun Bot.removeManager(long: Long) { } val Bot.managers: List - get() { - TODO() - } - -fun Bot.checkManager(long: Long): Boolean { - return this.managers.contains(long) -} - - -fun getBotManagers(bot: Bot): List { - return bot.managers -} + get() = TODO() diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/JavaFriendlyAPI.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/JavaFriendlyAPI.kt new file mode 100644 index 000000000..23db91223 --- /dev/null +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/JavaFriendlyAPI.kt @@ -0,0 +1,8 @@ +package net.mamoe.mirai.console.utils + +/** + * 表明这个 API 是为了让 Java 使用者调用更方便. Kotlin 使用者不应该使用这些 API. + */ +@RequiresOptIn(level = RequiresOptIn.Level.ERROR) +@Target(AnnotationTarget.PROPERTY, AnnotationTarget.FUNCTION, AnnotationTarget.TYPE, AnnotationTarget.CLASS) +internal annotation class JavaFriendlyAPI diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/JavaPluginScheduler.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/JavaPluginScheduler.kt index ab334872c..af24ad333 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/JavaPluginScheduler.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/JavaPluginScheduler.kt @@ -11,7 +11,7 @@ package net.mamoe.mirai.console.utils import kotlinx.coroutines.* import kotlinx.coroutines.future.future -import net.mamoe.mirai.console.plugins.builtin.JavaPlugin +import net.mamoe.mirai.console.plugin.jvm.JavaPlugin import java.util.concurrent.Callable import java.util.concurrent.CompletableFuture import java.util.concurrent.Future diff --git a/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/command/TestCommands.kt b/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/command/TestCommands.kt index 11350c771..797047519 100644 --- a/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/command/TestCommands.kt +++ b/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/command/TestCommands.kt @@ -12,14 +12,20 @@ package net.mamoe.mirai.console.command import net.mamoe.mirai.Bot -import net.mamoe.mirai.console.plugins.builtin.KotlinPlugin +import net.mamoe.mirai.console.plugin.jvm.KotlinPlugin +import net.mamoe.mirai.console.setting.value import net.mamoe.mirai.message.data.* import org.junit.jupiter.api.Test import kotlin.test.assertEquals -val plugin: KotlinPlugin = object : KotlinPlugin() { +val plugin = MyPlugin() +class MyPlugin : KotlinPlugin() { + + inner class MySetting : PluginSetting() { + val int by value(1) + } } /* @@ -94,9 +100,6 @@ internal inline fun withSender(block: CommandSender.() -> Unit): MessageChain { result.add(message) } - override fun appendMessage(message: String) { - result.add(message) - } } sender.let(block) return result.asMessageChain()