Review plugins:

Move PluginLoader into plugin.loader;
Improve docs;
Change extension PluginLoader.description to member function PluginLoader.getPluginDescription;
Change builtIn loader lists with Lazy items;
Add Regex for testing plugin names and ids.
This commit is contained in:
Him188 2020-09-12 20:20:41 +08:00
parent 5c6b4aa8cc
commit 6b9ec05c98
22 changed files with 211 additions and 177 deletions

View File

@ -21,10 +21,10 @@ import net.mamoe.mirai.console.MiraiConsoleImplementation.Companion.start
import net.mamoe.mirai.console.extension.GlobalComponentStorage import net.mamoe.mirai.console.extension.GlobalComponentStorage
import net.mamoe.mirai.console.extensions.BotConfigurationAlterer import net.mamoe.mirai.console.extensions.BotConfigurationAlterer
import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge
import net.mamoe.mirai.console.plugin.PluginLoader
import net.mamoe.mirai.console.plugin.PluginManager import net.mamoe.mirai.console.plugin.PluginManager
import net.mamoe.mirai.console.plugin.center.PluginCenter import net.mamoe.mirai.console.plugin.center.PluginCenter
import net.mamoe.mirai.console.plugin.jvm.JvmPluginLoader import net.mamoe.mirai.console.plugin.jvm.JvmPluginLoader
import net.mamoe.mirai.console.plugin.loader.PluginLoader
import net.mamoe.mirai.console.util.ConsoleExperimentalApi import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import net.mamoe.mirai.console.util.ConsoleInternalApi import net.mamoe.mirai.console.util.ConsoleInternalApi
import net.mamoe.mirai.console.util.CoroutineScopeUtils.childScopeContext import net.mamoe.mirai.console.util.CoroutineScopeUtils.childScopeContext
@ -68,7 +68,7 @@ public interface MiraiConsole : CoroutineScope {
* *
* @return 不可变 [List] ([java.util.Collections.unmodifiableList]) * @return 不可变 [List] ([java.util.Collections.unmodifiableList])
*/ */
public val builtInPluginLoaders: List<PluginLoader<*, *>> public val builtInPluginLoaders: List<Lazy<PluginLoader<*, *>>>
/** /**
* Console 后端构建时间 * Console 后端构建时间
@ -80,6 +80,7 @@ public interface MiraiConsole : CoroutineScope {
*/ */
public val version: Semver public val version: Semver
@ConsoleExperimentalApi @ConsoleExperimentalApi
public val pluginCenter: PluginCenter public val pluginCenter: PluginCenter

View File

@ -18,8 +18,8 @@ import net.mamoe.mirai.console.MiraiConsoleImplementation.Companion.start
import net.mamoe.mirai.console.command.ConsoleCommandSender import net.mamoe.mirai.console.command.ConsoleCommandSender
import net.mamoe.mirai.console.data.PluginDataStorage import net.mamoe.mirai.console.data.PluginDataStorage
import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge
import net.mamoe.mirai.console.plugin.PluginLoader
import net.mamoe.mirai.console.plugin.jvm.JvmPluginLoader import net.mamoe.mirai.console.plugin.jvm.JvmPluginLoader
import net.mamoe.mirai.console.plugin.loader.PluginLoader
import net.mamoe.mirai.console.util.ConsoleInput import net.mamoe.mirai.console.util.ConsoleInput
import net.mamoe.mirai.message.data.Message import net.mamoe.mirai.message.data.Message
import net.mamoe.mirai.utils.BotConfiguration import net.mamoe.mirai.utils.BotConfiguration
@ -76,7 +76,7 @@ public interface MiraiConsoleImplementation : CoroutineScope {
* *
* @return 不可变的 [List], [Collections.unmodifiableList] * @return 不可变的 [List], [Collections.unmodifiableList]
*/ */
public val builtInPluginLoaders: List<PluginLoader<*, *>> public val builtInPluginLoaders: List<Lazy<PluginLoader<*, *>>>
/** /**
* Kotlin 用户实现 * Kotlin 用户实现
@ -120,8 +120,8 @@ public interface MiraiConsoleImplementation : CoroutineScope {
public val consoleCommandSender: ConsoleCommandSenderImpl public val consoleCommandSender: ConsoleCommandSenderImpl
public val dataStorageForJarPluginLoader: PluginDataStorage public val dataStorageForJvmPluginLoader: PluginDataStorage
public val configStorageForJarPluginLoader: PluginDataStorage public val configStorageForJvmPluginLoader: PluginDataStorage
public val dataStorageForBuiltIns: PluginDataStorage public val dataStorageForBuiltIns: PluginDataStorage
public val configStorageForBuiltIns: PluginDataStorage public val configStorageForBuiltIns: PluginDataStorage

View File

@ -11,7 +11,7 @@
package net.mamoe.mirai.console.extension package net.mamoe.mirai.console.extension
import net.mamoe.mirai.console.plugin.PluginLoader import net.mamoe.mirai.console.plugin.loader.PluginLoader
import net.mamoe.mirai.console.util.ConsoleExperimentalApi import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import kotlin.reflect.KClass import kotlin.reflect.KClass
import kotlin.reflect.full.isSubclassOf import kotlin.reflect.full.isSubclassOf

View File

@ -2,7 +2,7 @@ package net.mamoe.mirai.console.extensions
import net.mamoe.mirai.console.extension.AbstractExtensionPoint import net.mamoe.mirai.console.extension.AbstractExtensionPoint
import net.mamoe.mirai.console.extension.InstanceExtension import net.mamoe.mirai.console.extension.InstanceExtension
import net.mamoe.mirai.console.plugin.PluginLoader import net.mamoe.mirai.console.plugin.loader.PluginLoader
/** /**
* 提供扩展 [PluginLoader] * 提供扩展 [PluginLoader]

View File

@ -42,10 +42,10 @@ import net.mamoe.mirai.console.internal.util.autoHexToBytes
import net.mamoe.mirai.console.permission.PermissionService import net.mamoe.mirai.console.permission.PermissionService
import net.mamoe.mirai.console.permission.PermissionService.Companion.grantPermission import net.mamoe.mirai.console.permission.PermissionService.Companion.grantPermission
import net.mamoe.mirai.console.permission.RootPermission import net.mamoe.mirai.console.permission.RootPermission
import net.mamoe.mirai.console.plugin.PluginLoader
import net.mamoe.mirai.console.plugin.PluginManager import net.mamoe.mirai.console.plugin.PluginManager
import net.mamoe.mirai.console.plugin.center.PluginCenter import net.mamoe.mirai.console.plugin.center.PluginCenter
import net.mamoe.mirai.console.plugin.jvm.AbstractJvmPlugin import net.mamoe.mirai.console.plugin.jvm.AbstractJvmPlugin
import net.mamoe.mirai.console.plugin.loader.PluginLoader
import net.mamoe.mirai.console.util.ConsoleExperimentalApi import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import net.mamoe.mirai.console.util.ConsoleInput import net.mamoe.mirai.console.util.ConsoleInput
import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.*
@ -74,11 +74,11 @@ internal object MiraiConsoleImplementationBridge : CoroutineScope, MiraiConsoleI
createLogger("main") createLogger("main")
} }
override val coroutineContext: CoroutineContext by instance::coroutineContext override val coroutineContext: CoroutineContext by instance::coroutineContext
override val builtInPluginLoaders: List<PluginLoader<*, *>> by instance::builtInPluginLoaders override val builtInPluginLoaders: List<Lazy<PluginLoader<*, *>>> by instance::builtInPluginLoaders
override val consoleCommandSender: MiraiConsoleImplementation.ConsoleCommandSenderImpl by instance::consoleCommandSender override val consoleCommandSender: MiraiConsoleImplementation.ConsoleCommandSenderImpl by instance::consoleCommandSender
override val dataStorageForJarPluginLoader: PluginDataStorage by instance::dataStorageForJarPluginLoader override val dataStorageForJvmPluginLoader: PluginDataStorage by instance::dataStorageForJvmPluginLoader
override val configStorageForJarPluginLoader: PluginDataStorage by instance::configStorageForJarPluginLoader override val configStorageForJvmPluginLoader: PluginDataStorage by instance::configStorageForJvmPluginLoader
override val dataStorageForBuiltIns: PluginDataStorage by instance::dataStorageForBuiltIns override val dataStorageForBuiltIns: PluginDataStorage by instance::dataStorageForBuiltIns
override val configStorageForBuiltIns: PluginDataStorage by instance::configStorageForBuiltIns override val configStorageForBuiltIns: PluginDataStorage by instance::configStorageForBuiltIns
override val consoleInput: ConsoleInput by instance::consoleInput override val consoleInput: ConsoleInput by instance::consoleInput

View File

@ -17,9 +17,9 @@ import net.mamoe.mirai.console.data.PluginDataStorage
import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge
import net.mamoe.mirai.console.internal.util.PluginServiceHelper.findServices import net.mamoe.mirai.console.internal.util.PluginServiceHelper.findServices
import net.mamoe.mirai.console.internal.util.PluginServiceHelper.loadAllServices import net.mamoe.mirai.console.internal.util.PluginServiceHelper.loadAllServices
import net.mamoe.mirai.console.plugin.AbstractFilePluginLoader
import net.mamoe.mirai.console.plugin.PluginLoadException
import net.mamoe.mirai.console.plugin.jvm.* import net.mamoe.mirai.console.plugin.jvm.*
import net.mamoe.mirai.console.plugin.loader.AbstractFilePluginLoader
import net.mamoe.mirai.console.plugin.loader.PluginLoadException
import net.mamoe.mirai.console.util.CoroutineScopeUtils.childScope import net.mamoe.mirai.console.util.CoroutineScopeUtils.childScope
import net.mamoe.mirai.utils.MiraiLogger import net.mamoe.mirai.utils.MiraiLogger
import java.io.File import java.io.File
@ -28,25 +28,24 @@ import java.util.concurrent.ConcurrentHashMap
internal object BuiltInJvmPluginLoaderImpl : internal object BuiltInJvmPluginLoaderImpl :
AbstractFilePluginLoader<JvmPlugin, JvmPluginDescription>(".jar"), AbstractFilePluginLoader<JvmPlugin, JvmPluginDescription>(".jar"),
CoroutineScope by MiraiConsole.childScope("JarPluginLoader", CoroutineExceptionHandler { _, throwable -> CoroutineScope by MiraiConsole.childScope("JvmPluginLoader", CoroutineExceptionHandler { _, throwable ->
BuiltInJvmPluginLoaderImpl.logger.error("Unhandled Jar plugin exception: ${throwable.message}", throwable) BuiltInJvmPluginLoaderImpl.logger.error("Unhandled Jar plugin exception: ${throwable.message}", throwable)
}), }),
JvmPluginLoader { JvmPluginLoader {
override val configStorage: PluginDataStorage override val configStorage: PluginDataStorage
get() = MiraiConsoleImplementationBridge.configStorageForJarPluginLoader get() = MiraiConsoleImplementationBridge.configStorageForJvmPluginLoader
@JvmStatic @JvmStatic
internal val logger: MiraiLogger = MiraiConsole.createLogger(JvmPluginLoader::class.simpleName!!) internal val logger: MiraiLogger = MiraiConsole.createLogger(JvmPluginLoader::class.simpleName!!)
override val dataStorage: PluginDataStorage override val dataStorage: PluginDataStorage
get() = MiraiConsoleImplementationBridge.dataStorageForJarPluginLoader get() = MiraiConsoleImplementationBridge.dataStorageForJvmPluginLoader
internal val classLoaders: MutableList<ClassLoader> = mutableListOf() internal val classLoaders: MutableList<ClassLoader> = mutableListOf()
@Suppress("EXTENSION_SHADOWED_BY_MEMBER") // doesn't matter @Suppress("EXTENSION_SHADOWED_BY_MEMBER") // doesn't matter
override val JvmPlugin.description: JvmPluginDescription override fun getPluginDescription(plugin: JvmPlugin): JvmPluginDescription = plugin.description
get() = this.description
private val pluginFileToInstanceMap: MutableMap<File, JvmPlugin> = ConcurrentHashMap() private val pluginFileToInstanceMap: MutableMap<File, JvmPlugin> = ConcurrentHashMap()

View File

@ -18,10 +18,14 @@ import net.mamoe.mirai.console.extension.GlobalComponentStorage
import net.mamoe.mirai.console.extensions.PluginLoaderProvider import net.mamoe.mirai.console.extensions.PluginLoaderProvider
import net.mamoe.mirai.console.internal.data.cast import net.mamoe.mirai.console.internal.data.cast
import net.mamoe.mirai.console.internal.data.mkdir import net.mamoe.mirai.console.internal.data.mkdir
import net.mamoe.mirai.console.plugin.* import net.mamoe.mirai.console.plugin.Plugin
import net.mamoe.mirai.console.plugin.PluginManager
import net.mamoe.mirai.console.plugin.description.PluginDependency import net.mamoe.mirai.console.plugin.description.PluginDependency
import net.mamoe.mirai.console.plugin.description.PluginDescription import net.mamoe.mirai.console.plugin.description.PluginDescription
import net.mamoe.mirai.console.plugin.jvm.JvmPlugin import net.mamoe.mirai.console.plugin.jvm.JvmPlugin
import net.mamoe.mirai.console.plugin.loader.PluginLoadException
import net.mamoe.mirai.console.plugin.loader.PluginLoader
import net.mamoe.mirai.console.plugin.name
import net.mamoe.mirai.console.util.CoroutineScopeUtils.childScope import net.mamoe.mirai.console.util.CoroutineScopeUtils.childScope
import net.mamoe.mirai.utils.info import net.mamoe.mirai.utils.info
import java.io.File import java.io.File
@ -39,8 +43,9 @@ internal object PluginManagerImpl : PluginManager, CoroutineScope by MiraiConsol
@Suppress("ObjectPropertyName") @Suppress("ObjectPropertyName")
private val _pluginLoaders: MutableList<PluginLoader<*, *>> by lazy { private val _pluginLoaders: MutableList<PluginLoader<*, *>> by lazy {
MiraiConsole.builtInPluginLoaders.toMutableList() builtInLoaders.toMutableList()
} }
private val logger = MiraiConsole.createLogger("plugin") private val logger = MiraiConsole.createLogger("plugin")
@JvmField @JvmField
@ -48,17 +53,18 @@ internal object PluginManagerImpl : PluginManager, CoroutineScope by MiraiConsol
CopyOnWriteArrayList() // write operations are mostly performed on init CopyOnWriteArrayList() // write operations are mostly performed on init
override val plugins: List<Plugin> override val plugins: List<Plugin>
get() = resolvedPlugins.toList() get() = resolvedPlugins.toList()
override val builtInLoaders: List<PluginLoader<*, *>> override val builtInLoaders: List<PluginLoader<*, *>> by lazy {
get() = MiraiConsole.builtInPluginLoaders MiraiConsole.builtInPluginLoaders.map { it.value }
}
override val pluginLoaders: List<PluginLoader<*, *>> override val pluginLoaders: List<PluginLoader<*, *>>
get() = _pluginLoaders.toList() get() = _pluginLoaders.toList()
override val Plugin.description: PluginDescription override val Plugin.description: PluginDescription
get() = if (this is JvmPlugin) { get() = if (this is JvmPlugin) {
this.safeLoader.getDescription(this) this.safeLoader.getPluginDescription(this)
} else resolvedPlugins.firstOrNull { it == this } } else resolvedPlugins.firstOrNull { it == this }
?.loader?.cast<PluginLoader<Plugin, PluginDescription>>() ?.loader?.cast<PluginLoader<Plugin, PluginDescription>>()
?.getDescription(this) ?.getPluginDescription(this)
?: error("Plugin is unloaded") ?: error("Plugin is unloaded")
@ -76,10 +82,10 @@ internal object PluginManagerImpl : PluginManager, CoroutineScope by MiraiConsol
resolvedPlugins.add(plugin) resolvedPlugins.add(plugin)
}.fold( }.fold(
onSuccess = { onSuccess = {
logger.info { "Successfully loaded plugin ${plugin.description.name}" } logger.info { "Successfully loaded plugin ${getPluginDescription(plugin).name}" }
}, },
onFailure = { onFailure = {
logger.info { "Cannot load plugin ${plugin.description.name}" } logger.info { "Cannot load plugin ${getPluginDescription(plugin).name}" }
throw it throw it
} }
) )

View File

@ -19,6 +19,7 @@ import net.mamoe.mirai.console.plugin.PluginManager.INSTANCE.safeLoader
import net.mamoe.mirai.console.plugin.description.PluginDependency import net.mamoe.mirai.console.plugin.description.PluginDependency
import net.mamoe.mirai.console.plugin.description.PluginDescription import net.mamoe.mirai.console.plugin.description.PluginDescription
import net.mamoe.mirai.console.plugin.jvm.JvmPlugin import net.mamoe.mirai.console.plugin.jvm.JvmPlugin
import net.mamoe.mirai.console.plugin.loader.PluginLoader
/** /**
* 表示一个 mirai-console 插件. * 表示一个 mirai-console 插件.
@ -51,7 +52,7 @@ public interface Plugin : CommandOwner {
/** /**
* 获取 [PluginDescription] * 获取 [PluginDescription]
*/ */
public inline val Plugin.description: PluginDescription get() = this.safeLoader.getDescription(this) public inline val Plugin.description: PluginDescription get() = this.safeLoader.getPluginDescription(this)
/** /**
* 获取 [PluginDescription.name`] * 获取 [PluginDescription.name`]

View File

@ -14,6 +14,7 @@ package net.mamoe.mirai.console.plugin
import net.mamoe.mirai.console.MiraiConsole import net.mamoe.mirai.console.MiraiConsole
import net.mamoe.mirai.console.internal.plugin.PluginManagerImpl import net.mamoe.mirai.console.internal.plugin.PluginManagerImpl
import net.mamoe.mirai.console.plugin.description.PluginDescription import net.mamoe.mirai.console.plugin.description.PluginDescription
import net.mamoe.mirai.console.plugin.loader.PluginLoader
import java.io.File import java.io.File
import java.nio.file.Path import java.nio.file.Path
@ -102,7 +103,7 @@ public interface PluginManager {
public val pluginLoaders: List<PluginLoader<*, *>> public val pluginLoaders: List<PluginLoader<*, *>>
/** /**
* 获取插件的 [描述][PluginDescription], 通过 [PluginLoader.getDescription] * 获取插件的 [描述][PluginDescription], 通过 [PluginLoader.getPluginDescription]
*/ */
public val Plugin.description: PluginDescription public val Plugin.description: PluginDescription

View File

@ -14,6 +14,9 @@ import kotlinx.serialization.Serializable
import net.mamoe.mirai.console.util.ConsoleExperimentalApi import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import java.io.File import java.io.File
/**
* 插件中心, 计划实现中
*/
@ConsoleExperimentalApi @ConsoleExperimentalApi
public interface PluginCenter { public interface PluginCenter {
@ -29,7 +32,7 @@ public interface PluginCenter {
val author: String, val author: String,
val description: String, val description: String,
val tags: List<String>, val tags: List<String>,
val commands: List<String> val commands: List<String>,
) )
@ConsoleExperimentalApi @ConsoleExperimentalApi
@ -48,7 +51,7 @@ public interface PluginCenter {
val usage: String, val usage: String,
val vcs: String, val vcs: String,
val commands: List<String>, val commands: List<String>,
val changeLog: List<String> val changeLog: List<String>,
) )
/** /**

View File

@ -1,5 +1,21 @@
/*
* Copyright 2019-2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:Suppress("unused")
package net.mamoe.mirai.console.plugin.description package net.mamoe.mirai.console.plugin.description
/**
* 在检查到非法 [PluginDescription] 时抛出.
*
* @see PluginDescription.checkPluginDescription
*/
public class IllegalPluginDescriptionException : RuntimeException { public class IllegalPluginDescriptionException : RuntimeException {
public constructor() : super() public constructor() : super()
public constructor(message: String?) : super(message) public constructor(message: String?) : super(message)

View File

@ -11,7 +11,6 @@ package net.mamoe.mirai.console.plugin.description
import com.vdurmont.semver4j.Semver import com.vdurmont.semver4j.Semver
import net.mamoe.mirai.console.plugin.Plugin import net.mamoe.mirai.console.plugin.Plugin
import net.mamoe.mirai.console.plugin.PluginLoadException
/** /**
@ -21,34 +20,40 @@ import net.mamoe.mirai.console.plugin.PluginLoadException
*/ */
public interface PluginDescription { public interface PluginDescription {
/** /**
* 插件 ID, 必须全英文, 仅允许英文字母, '-', '_', '.'. * 插件 ID.
* *
* - 仅允许英文字母, '-', '_', '.'. 在内部操作处理时不区分大小写.
* - 类似于 Java 包名, 插件 ID 需要 '域名.名称' 格式, `net.mamoe.mirai.example-plugin` * - 类似于 Java 包名, 插件 ID 需要 '域名.名称' 格式, `net.mamoe.mirai.example-plugin`
* - 域名和名称都是必须的 * - 域名和名称都是必须的
* - '.' 不允许位于首位或末尾 * - 数字和符号都不允许位于首位
* - '-' '_' 仅允许存在于两个英文字母之间 * - '-' '_' 仅允许存在于两个英文字母之间. 不推荐使用 '_'. 请参照 `org.example.mirai.plugin.my-example-plugin` 格式.
*
* 可使用 [ID_REGEX] 检验格式合法性.
* *
* ID 在插件发布后就应该保持不变, 以便其他插件添加依赖. * ID 在插件发布后就应该保持不变, 以便其他插件添加依赖.
* *
* 插件 ID 的域名和名称都不能完全是以下其中一个 ([FORBIDDEN_ID_WORDS]). * 插件 ID 的域名和名称都不能完全是以下其中一个 ([FORBIDDEN_ID_NAMES]).
* - "console" * - "console"
* - "main" * - "main"
* - "plugin" * - "plugin"
* - "config" * - "config"
* - "data" * - "data"
* *
* ### 示例
* - 合法 `net.mamoe.mirai.example-plugin`
* - 非法 `.example-plugin`
* *
* ID 用于指令权限等一些内部处理 * ID 用于指令权限等一些内部处理
* *
* @see FORBIDDEN_ID_LETTERS * @see ID_REGEX
* @see FORBIDDEN_ID_WORDS * @see FORBIDDEN_ID_NAMES
*/ */
public val id: String public val id: String
/** /**
* 插件名称. 允许中文, 允许各类符号. * 插件名称. 允许中文, 允许各类符号.
* *
* 插件名称不能完全是以下其中一种 ([FORBIDDEN_ID_WORDS]). * 插件名称不能完全是以下其中一种 ([FORBIDDEN_ID_NAMES]).
* - console * - console
* - main * - main
* - plugin * - plugin
@ -57,8 +62,7 @@ public interface PluginDescription {
* *
* 插件名称用于显示给用户. * 插件名称用于显示给用户.
* *
* @see FORBIDDEN_ID_LETTERS * @see FORBIDDEN_ID_NAMES
* @see FORBIDDEN_ID_WORDS
*/ */
public val name: String public val name: String
@ -103,8 +107,22 @@ public interface PluginDescription {
public val dependencies: Set<PluginDependency> public val dependencies: Set<PluginDependency>
public companion object { public companion object {
public val FORBIDDEN_ID_LETTERS: Array<String> = "~!@#$%^&*()+/*<>{}|[]\\?".map(Char::toString).toTypedArray() /**
public val FORBIDDEN_ID_WORDS: Array<String> = arrayOf("main", "console", "plugin", "config", "data") * [PluginDescription.id] 的合法 [Regex].
*
* - Group 1: 域名
* - Group 2: 名称
*
* @see PluginDescription.id
*/
public val ID_REGEX: Regex = Regex("""([a-zA-Z]+[a-zA-Z0-9]*)\.([a-zA-Z]+[a-zA-Z0-9]*)""")
/**
* [PluginDescription.id] [PluginDescription.name] 中禁止用的完全匹配名称列表.
*
* @see PluginDescription.id
*/
public val FORBIDDEN_ID_NAMES: Array<String> = arrayOf("main", "console", "plugin", "config", "data")
/** /**
* 依次检查 [PluginDescription] [PluginDescription.id], [PluginDescription.name], [PluginDescription.dependencies] 的合法性 * 依次检查 [PluginDescription] [PluginDescription.id], [PluginDescription.name], [PluginDescription.dependencies] 的合法性
@ -126,50 +144,55 @@ public interface PluginDescription {
} }
/** /**
* 检查 [PluginDescription.id] 的合法性. * 检查 [PluginDescription.id] 的合法性. 忽略大小写.
* *
* @throws IllegalPluginDescriptionException 当不合法时抛出. * @throws IllegalPluginDescriptionException 当不合法时抛出.
*/ */
@Throws(IllegalPluginDescriptionException::class) @Throws(IllegalPluginDescriptionException::class)
public fun checkPluginId(id: String) { public fun checkPluginId(id: String) {
if (id.isBlank()) throw IllegalPluginDescriptionException("Plugin id cannot be blank") if (id.isBlank()) throw IllegalPluginDescriptionException("Plugin id cannot be blank")
if (id.count { it == '.' } < 2) throw IllegalPluginDescriptionException("'$id' is illegal. Plugin id must consist of both domain and name. ") if (id.none { it == '.' }) throw IllegalPluginDescriptionException("'$id' is illegal. Plugin id must consist of both domain and name. ")
FORBIDDEN_ID_LETTERS.firstOrNull { it in id }?.let { illegal -> val lowercaseId = id.toLowerCase()
throw IllegalPluginDescriptionException("Plugin id contains illegal char: $illegal.")
if (ID_REGEX.matchEntire(id) == null) {
throw IllegalPluginDescriptionException("Plugin does not match regex '${ID_REGEX.pattern}'.")
} }
val idSections = id.split('.') FORBIDDEN_ID_NAMES.firstOrNull { it == lowercaseId }?.let { illegal ->
FORBIDDEN_ID_WORDS.firstOrNull { it in idSections }?.let { illegal ->
throw IllegalPluginDescriptionException("Plugin id contains illegal word: '$illegal'.") throw IllegalPluginDescriptionException("Plugin id contains illegal word: '$illegal'.")
} }
} }
/** /**
* 检查 [PluginDescription.name] 的合法性. * 检查 [PluginDescription.name] 的合法性. 忽略大小写.
* *
* @throws IllegalPluginDescriptionException 当不合法时抛出. * @throws IllegalPluginDescriptionException 当不合法时抛出.
*/ */
@Throws(IllegalPluginDescriptionException::class) @Throws(IllegalPluginDescriptionException::class)
public fun checkPluginName(name: String) { public fun checkPluginName(name: String) {
if (name.isBlank()) throw IllegalPluginDescriptionException("Plugin name cannot be blank") if (name.isBlank()) throw IllegalPluginDescriptionException("Plugin name cannot be blank")
FORBIDDEN_ID_WORDS.firstOrNull { it in name }?.let { illegal -> val lowercaseName = name.toLowerCase()
FORBIDDEN_ID_NAMES.firstOrNull { it in lowercaseName }?.let { illegal ->
throw IllegalPluginDescriptionException("Plugin name is illegal: '$illegal'.") throw IllegalPluginDescriptionException("Plugin name is illegal: '$illegal'.")
} }
} }
/** /**
* 检查 [PluginDescription.dependencies] 的合法性. * 检查 [PluginDescription.dependencies] 的合法性. 忽略大小写.
* *
* @throws IllegalPluginDescriptionException 当不合法时抛出. * @throws IllegalPluginDescriptionException 当不合法时抛出.
*/ */
@Throws(IllegalPluginDescriptionException::class) @Throws(IllegalPluginDescriptionException::class)
public fun checkDependencies(pluginId: String, dependencies: Set<PluginDependency>) { public fun checkDependencies(pluginId: String, dependencies: Set<PluginDependency>) {
if (dependencies.distinctBy { it.id }.size != dependencies.size) val lowercaseId = pluginId.toLowerCase()
throw PluginLoadException("Duplicated dependency detected: A plugin cannot depend on different versions of dependencies of the same id") val lowercaseDependencies = dependencies.mapTo(LinkedHashSet(dependencies.size)) { it.id.toLowerCase() }
if (dependencies.any { it.id == pluginId }) if (lowercaseDependencies.size != dependencies.size)
throw PluginLoadException("Recursive dependency detected: A plugin cannot depend on itself") throw IllegalPluginDescriptionException("Duplicated dependency detected: A plugin cannot depend on different versions of dependencies of the same id")
if (lowercaseDependencies.any { it == lowercaseId })
throw IllegalPluginDescriptionException("Recursive dependency detected: A plugin cannot depend on itself")
} }
} }
} }

View File

@ -12,13 +12,16 @@ package net.mamoe.mirai.console.plugin.jvm
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import net.mamoe.mirai.console.data.PluginDataStorage import net.mamoe.mirai.console.data.PluginDataStorage
import net.mamoe.mirai.console.internal.plugin.BuiltInJvmPluginLoaderImpl import net.mamoe.mirai.console.internal.plugin.BuiltInJvmPluginLoaderImpl
import net.mamoe.mirai.console.plugin.FilePluginLoader import net.mamoe.mirai.console.plugin.loader.FilePluginLoader
/** /**
* 内建的 Jar (JVM) 插件加载器 * 内建的 Jar (JVM) 插件加载器
*/ */
public interface JvmPluginLoader : CoroutineScope, FilePluginLoader<JvmPlugin, JvmPluginDescription> { public interface JvmPluginLoader : CoroutineScope, FilePluginLoader<JvmPlugin, JvmPluginDescription> {
public override val fileSuffix: String get() = ".jar" /**
* ".jar"
*/
public override val fileSuffix: String
/** /**
* [AbstractJvmPlugin.reloadPluginData] 默认使用的实例 * [AbstractJvmPlugin.reloadPluginData] 默认使用的实例
@ -32,7 +35,7 @@ public interface JvmPluginLoader : CoroutineScope, FilePluginLoader<JvmPlugin, J
public companion object BuiltIn : JvmPluginLoader by BuiltInJvmPluginLoaderImpl { public companion object BuiltIn : JvmPluginLoader by BuiltInJvmPluginLoaderImpl {
@Suppress("EXTENSION_SHADOWED_BY_MEMBER") @Suppress("EXTENSION_SHADOWED_BY_MEMBER")
override val JvmPlugin.description: JvmPluginDescription override fun getPluginDescription(plugin: JvmPlugin): JvmPluginDescription =
get() = BuiltInJvmPluginLoaderImpl.run { description } BuiltInJvmPluginLoaderImpl.run { plugin.description }
} }
} }

View File

@ -0,0 +1,43 @@
package net.mamoe.mirai.console.plugin.loader
import net.mamoe.mirai.console.plugin.Plugin
import net.mamoe.mirai.console.plugin.PluginManager
import net.mamoe.mirai.console.plugin.description.PluginDescription
import net.mamoe.mirai.console.plugin.jvm.JvmPluginLoader
import java.io.File
/**
* ['/plugins'][PluginManager.pluginsPath] 目录中的插件的加载器. 每个加载器需绑定一个后缀.
*
* @see AbstractFilePluginLoader 默认基础实现
* @see JvmPluginLoader 内建的 Jar (JVM) 插件加载器.
*/
public interface FilePluginLoader<P : Plugin, D : PluginDescription> : PluginLoader<P, D> {
/**
* 所支持的插件文件后缀, '.', 不区分大小写. [JvmPluginLoader] ".jar"
*/
public val fileSuffix: String
}
/**
* [FilePluginLoader] 的默认基础实现.
*
* @see FilePluginLoader
*/
public abstract class AbstractFilePluginLoader<P : Plugin, D : PluginDescription>(
/**
* 所支持的插件文件后缀, '.', 不区分大小写. [JvmPluginLoader] ".jar"
*/
public override val fileSuffix: String,
) : FilePluginLoader<P, D> {
private fun pluginsFilesSequence(): Sequence<File> =
PluginManager.pluginsFolder.listFiles().orEmpty().asSequence()
.filter { it.isFile && it.name.endsWith(fileSuffix, ignoreCase = true) }
/**
* 读取扫描到的后缀与 [fileSuffix] 相同的文件中的插件实例, 但不 [加载][PluginLoader.load]
*/
protected abstract fun Sequence<File>.extractPlugins(): List<P>
public final override fun listPlugins(): List<P> = pluginsFilesSequence().extractPlugins()
}

View File

@ -0,0 +1,27 @@
/*
* Copyright 2019-2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:Suppress("unused")
package net.mamoe.mirai.console.plugin.loader
/**
* 在加载插件过程中遇到的意料之中的问题.
*
* @see PluginLoader.load
* @see PluginLoader.enable
* @see PluginLoader.disable
* @see PluginLoader.getPluginDescription
*/
public open class PluginLoadException : RuntimeException {
public constructor() : super()
public constructor(message: String?) : super(message)
public constructor(message: String?, cause: Throwable?) : super(message, cause)
public constructor(cause: Throwable?) : super(cause)
}

View File

@ -9,13 +9,14 @@
@file:Suppress("unused", "INAPPLICABLE_JVM_NAME", "NOTHING_TO_INLINE") @file:Suppress("unused", "INAPPLICABLE_JVM_NAME", "NOTHING_TO_INLINE")
package net.mamoe.mirai.console.plugin package net.mamoe.mirai.console.plugin.loader
import net.mamoe.mirai.console.plugin.Plugin
import net.mamoe.mirai.console.plugin.PluginManager
import net.mamoe.mirai.console.plugin.PluginManager.INSTANCE.disable import net.mamoe.mirai.console.plugin.PluginManager.INSTANCE.disable
import net.mamoe.mirai.console.plugin.PluginManager.INSTANCE.enable import net.mamoe.mirai.console.plugin.PluginManager.INSTANCE.enable
import net.mamoe.mirai.console.plugin.description.PluginDescription import net.mamoe.mirai.console.plugin.description.PluginDescription
import net.mamoe.mirai.console.plugin.jvm.JvmPluginLoader import net.mamoe.mirai.console.plugin.jvm.JvmPluginLoader
import java.io.File
import java.util.* import java.util.*
/** /**
@ -58,11 +59,10 @@ public interface PluginLoader<P : Plugin, D : PluginDescription> {
* @throws PluginLoadException 在加载插件遇到意料之中的错误时抛出 (如无法读取插件信息等). * @throws PluginLoadException 在加载插件遇到意料之中的错误时抛出 (如无法读取插件信息等).
* *
* @see PluginDescription 插件描述 * @see PluginDescription 插件描述
* @see getDescription receiver, 接受参数的版本. * @see getPluginDescription receiver, 接受参数的版本.
*/ */
@get:JvmName("getPluginDescription") @Throws(PluginLoadException::class)
@get:Throws(PluginLoadException::class) public fun getPluginDescription(plugin: P): D // Java signature: `public D getDescription(P)`
public val P.description: D // Java signature: `public D getDescription(P)`
/** /**
* 主动加载一个插件 (实例), 但不 [启用][enable] . 返回加载成功的主类实例 * 主动加载一个插件 (实例), 但不 [启用][enable] . 返回加载成功的主类实例
@ -100,86 +100,4 @@ public interface PluginLoader<P : Plugin, D : PluginDescription> {
*/ */
@Throws(IllegalStateException::class, PluginLoadException::class) @Throws(IllegalStateException::class, PluginLoadException::class)
public fun disable(plugin: P) public fun disable(plugin: P)
} }
/**
* 获取此插件的描述.
*
* **实现细节**: 此函数只允许抛出 [PluginLoadException] 作为正常失败原因, 其他任意异常都属于意外错误.
*
* 若在 console 启动并加载所有插件的过程中, 本函数抛出异常, 则会放弃此插件的加载, 并影响依赖它的其他插件.
*
* @throws PluginLoadException 在加载插件遇到意料之中的错误时抛出 (如无法读取插件信息等).
*
* @see PluginDescription 插件描述
* @see PluginLoader.description
*/
@Suppress("UNCHECKED_CAST")
@JvmSynthetic
public inline fun <D : PluginDescription, P : Plugin> PluginLoader<in P, out D>.getDescription(plugin: P): D =
plugin.description
/**
* 在加载插件过程中遇到的意料之中的问题.
*
* @see PluginLoader.load
* @see PluginLoader.enable
* @see PluginLoader.disable
* @see PluginLoader.description
*/
public open class PluginLoadException : RuntimeException {
public constructor() : super()
public constructor(message: String?) : super(message)
public constructor(message: String?, cause: Throwable?) : super(message, cause)
public constructor(cause: Throwable?) : super(cause)
}
/**
* ['/plugins'][PluginManager.pluginsPath] 目录中的插件的加载器. 每个加载器需绑定一个后缀.
*
* @see AbstractFilePluginLoader 默认基础实现
* @see JvmPluginLoader 内建的 Jar (JVM) 插件加载器.
*/
public interface FilePluginLoader<P : Plugin, D : PluginDescription> : PluginLoader<P, D> {
/**
* 所支持的插件文件后缀, '.', 不区分大小写. [JvmPluginLoader] ".jar"
*/
public val fileSuffix: String
}
/**
* [FilePluginLoader] 的默认基础实现.
*
* @see FilePluginLoader
*/
public abstract class AbstractFilePluginLoader<P : Plugin, D : PluginDescription>(
/**
* 所支持的插件文件后缀, '.', 不区分大小写. [JvmPluginLoader] ".jar"
*/
public override val fileSuffix: String,
) : FilePluginLoader<P, D> {
private fun pluginsFilesSequence(): Sequence<File> =
PluginManager.pluginsFolder.listFiles().orEmpty().asSequence()
.filter { it.isFile && it.name.endsWith(fileSuffix, ignoreCase = true) }
/**
* 读取扫描到的后缀与 [fileSuffix] 相同的文件中的插件实例, 但不 [加载][PluginLoader.load]
*/
protected abstract fun Sequence<File>.extractPlugins(): List<P>
public final override fun listPlugins(): List<P> = pluginsFilesSequence().extractPlugins()
}
// Not yet decided to make public API
internal class DeferredPluginLoader<P : Plugin, D : PluginDescription>(
initializer: () -> PluginLoader<P, D>,
) : PluginLoader<P, D> {
private val instance by lazy(initializer)
override fun listPlugins(): List<P> = instance.run { listPlugins() }
override val P.description: D get() = instance.run { description }
override fun load(plugin: P) = instance.load(plugin)
override fun enable(plugin: P) = instance.enable(plugin)
override fun disable(plugin: P) = instance.disable(plugin)
}

View File

@ -15,9 +15,8 @@ import net.mamoe.mirai.console.MiraiConsoleImplementation.Companion.start
import net.mamoe.mirai.console.command.CommandManager import net.mamoe.mirai.console.command.CommandManager
import net.mamoe.mirai.console.data.MemoryPluginDataStorage import net.mamoe.mirai.console.data.MemoryPluginDataStorage
import net.mamoe.mirai.console.data.PluginDataStorage 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.JvmPluginLoader import net.mamoe.mirai.console.plugin.jvm.JvmPluginLoader
import net.mamoe.mirai.console.plugin.loader.PluginLoader
import net.mamoe.mirai.console.util.ConsoleExperimentalApi import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import net.mamoe.mirai.console.util.ConsoleInput import net.mamoe.mirai.console.util.ConsoleInput
import net.mamoe.mirai.console.util.ConsoleInternalApi import net.mamoe.mirai.console.util.ConsoleInternalApi
@ -48,7 +47,7 @@ fun initTestEnvironment() {
get() = Semver("1.0.0") get() = Semver("1.0.0")
} }
override val builtInPluginLoaders: List<PluginLoader<*, *>> = listOf(DeferredPluginLoader { JvmPluginLoader }) override val builtInPluginLoaders: List<Lazy<PluginLoader<*, *>>> = listOf(lazy { JvmPluginLoader })
override val consoleCommandSender: MiraiConsoleImplementation.ConsoleCommandSenderImpl = override val consoleCommandSender: MiraiConsoleImplementation.ConsoleCommandSenderImpl =
object : MiraiConsoleImplementation.ConsoleCommandSenderImpl { object : MiraiConsoleImplementation.ConsoleCommandSenderImpl {
override suspend fun sendMessage(message: Message) { override suspend fun sendMessage(message: Message) {
@ -59,8 +58,8 @@ fun initTestEnvironment() {
println(message) println(message)
} }
} }
override val dataStorageForJarPluginLoader: PluginDataStorage = MemoryPluginDataStorage() override val dataStorageForJvmPluginLoader: PluginDataStorage = MemoryPluginDataStorage()
override val configStorageForJarPluginLoader: PluginDataStorage = MemoryPluginDataStorage() override val configStorageForJvmPluginLoader: PluginDataStorage = MemoryPluginDataStorage()
override val dataStorageForBuiltIns: PluginDataStorage = MemoryPluginDataStorage() override val dataStorageForBuiltIns: PluginDataStorage = MemoryPluginDataStorage()
override val configStorageForBuiltIns: PluginDataStorage = MemoryPluginDataStorage() override val configStorageForBuiltIns: PluginDataStorage = MemoryPluginDataStorage()

View File

@ -3,9 +3,9 @@
[`Plugin`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/Plugin.kt [`Plugin`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/Plugin.kt
[`PluginDescription`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/description/PluginDescription.kt [`PluginDescription`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/description/PluginDescription.kt
[`PluginLoader`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/PluginLoader.kt [`PluginLoader`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/loader/PluginLoader.kt
[`PluginManager`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/PluginManager.kt [`PluginManager`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/PluginManager.kt
[`JarPluginLoader`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JarPluginLoader.kt [`JvmPluginLoader`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPluginLoader.kt
[`JvmPlugin`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPlugin.kt [`JvmPlugin`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPlugin.kt
[`JvmPluginDescription`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPluginDescription.kt [`JvmPluginDescription`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPluginDescription.kt
[`AbstractJvmPlugin`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/AbstractJvmPlugin.kt [`AbstractJvmPlugin`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/AbstractJvmPlugin.kt

View File

@ -2,9 +2,9 @@
[`Plugin`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/Plugin.kt [`Plugin`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/Plugin.kt
[`PluginDescription`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/description/PluginDescription.kt [`PluginDescription`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/description/PluginDescription.kt
[`PluginLoader`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/PluginLoader.kt [`PluginLoader`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/loader/PluginLoader.kt
[`PluginManager`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/PluginManager.kt [`PluginManager`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/PluginManager.kt
[`JarPluginLoader`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JarPluginLoader.kt [`JvmPluginLoader`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPluginLoader.kt
[`JvmPlugin`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPlugin.kt [`JvmPlugin`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPlugin.kt
[`JvmPluginDescription`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPluginDescription.kt [`JvmPluginDescription`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPluginDescription.kt
[`AbstractJvmPlugin`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/AbstractJvmPlugin.kt [`AbstractJvmPlugin`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/AbstractJvmPlugin.kt
@ -35,7 +35,6 @@
[`RawCommand`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/RawCommand.kt [`RawCommand`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/RawCommand.kt
[`CommandManager`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandManager.kt [`CommandManager`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandManager.kt
[`BotManager`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/util/BotManager.kt
[`Annotations`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/util/Annotations.kt [`Annotations`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/util/Annotations.kt
[`ConsoleInput`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/util/ConsoleInput.kt [`ConsoleInput`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/util/ConsoleInput.kt
[`JavaPluginScheduler`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JavaPluginScheduler.kt [`JavaPluginScheduler`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JavaPluginScheduler.kt

View File

@ -2,9 +2,9 @@
[`Plugin`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/Plugin.kt [`Plugin`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/Plugin.kt
[`PluginDescription`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/description/PluginDescription.kt [`PluginDescription`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/description/PluginDescription.kt
[`PluginLoader`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/PluginLoader.kt [`PluginLoader`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/loader/PluginLoader.kt
[`PluginManager`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/PluginManager.kt [`PluginManager`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/PluginManager.kt
[`JarPluginLoader`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JarPluginLoader.kt [`JvmPluginLoader`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPluginLoader.kt
[`JvmPlugin`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPlugin.kt [`JvmPlugin`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPlugin.kt
[`JvmPluginDescription`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPluginDescription.kt [`JvmPluginDescription`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPluginDescription.kt
[`AbstractJvmPlugin`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/AbstractJvmPlugin.kt [`AbstractJvmPlugin`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/AbstractJvmPlugin.kt
@ -63,7 +63,7 @@ interface Plugin : CommandOwner { // CommandOwner 是空的 interface
## JVM 平台插件接口 - [`JvmPlugin`] ## JVM 平台插件接口 - [`JvmPlugin`]
所有的 JVM 插件都必须实现 [`JvmPlugin`](否则不会被 [`JarPluginLoader`] 加载)。 所有的 JVM 插件都必须实现 [`JvmPlugin`](否则不会被 [`JvmPluginLoader`] 加载)。
Mirai Console 提供一些基础的实现,即 [`AbstractJvmPlugin`],并将 [`JvmPlugin`] 分为 [`KotlinPlugin`] 和 [`JavaPlugin`]。 Mirai Console 提供一些基础的实现,即 [`AbstractJvmPlugin`],并将 [`JvmPlugin`] 分为 [`KotlinPlugin`] 和 [`JavaPlugin`]。
### 主类和描述 ### 主类和描述
@ -174,7 +174,7 @@ Mirai Console 不提供热加载和热卸载功能,所有插件只能在服务
#### 加载 #### 加载
[`JarPluginLoader`] 调用插件的 `onLoad()`,在 `onLoad()` 正常返回后插件被认为成功加载。 [`JvmPluginLoader`] 调用插件的 `onLoad()`,在 `onLoad()` 正常返回后插件被认为成功加载。
由于 `onLoad()` 只会被初始化一次,插件可以在该方法内进行一些*一次性*的*初始化*任务。 由于 `onLoad()` 只会被初始化一次,插件可以在该方法内进行一些*一次性*的*初始化*任务。
@ -184,13 +184,13 @@ Mirai Console 不提供热加载和热卸载功能,所有插件只能在服务
#### 启用 #### 启用
[`JarPluginLoader`] 调用插件的 `onEnable()`,意为启用一个插件。 [`JvmPluginLoader`] 调用插件的 `onEnable()`,意为启用一个插件。
此时插件可以启动所有协程,事件监听,和其他任务。**但这些任务都应该拥有生命周期管理,详见 [任务生命周期管理](#任务生命周期管理)。** 此时插件可以启动所有协程,事件监听,和其他任务。**但这些任务都应该拥有生命周期管理,详见 [任务生命周期管理](#任务生命周期管理)。**
#### 禁用 #### 禁用
[`JarPluginLoader`] 调用插件的 `onDisable()`,意为禁用一个插件。 [`JvmPluginLoader`] 调用插件的 `onDisable()`,意为禁用一个插件。
插件的任何类和对象都不会被卸载。「禁用」仅表示停止关闭所有正在进行的任务,保存所有数据,停止处理将来的数据。 插件的任何类和对象都不会被卸载。「禁用」仅表示停止关闭所有正在进行的任务,保存所有数据,停止处理将来的数据。

View File

@ -5,7 +5,7 @@
## 目录 ## 目录
- **[准备工作](#准备工作)** - **[准备工作](#准备工作)**
- **[启动 Console](#Run.md)** - **[启动 Console](Run.md)**
### 后端插件开发基础 ### 后端插件开发基础
@ -29,10 +29,9 @@
[`JavaPluginScheduler`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JavaPluginScheduler.kt [`JavaPluginScheduler`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JavaPluginScheduler.kt
[`JvmPlugin`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPlugin.kt [`JvmPlugin`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPlugin.kt
[`PluginConfig`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginConfig.kt [`PluginConfig`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginConfig.kt
[`PluginLoader`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/PluginLoader.kt [`PluginLoader`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/loader/PluginLoader.kt
[`ConsoleInput`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/util/ConsoleInput.kt [`ConsoleInput`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/util/ConsoleInput.kt
[`PluginDataStorage`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginDataStorage.kt [`PluginDataStorage`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginDataStorage.kt
[`BotManager`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/util/BotManager.kt
[`Command`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/Command.kt [`Command`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/Command.kt
## 准备工作 ## 准备工作

View File

@ -30,9 +30,8 @@ import net.mamoe.mirai.console.MiraiConsoleFrontEndDescription
import net.mamoe.mirai.console.MiraiConsoleImplementation import net.mamoe.mirai.console.MiraiConsoleImplementation
import net.mamoe.mirai.console.data.MultiFilePluginDataStorage import net.mamoe.mirai.console.data.MultiFilePluginDataStorage
import net.mamoe.mirai.console.data.PluginDataStorage 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.JvmPluginLoader import net.mamoe.mirai.console.plugin.jvm.JvmPluginLoader
import net.mamoe.mirai.console.plugin.loader.PluginLoader
import net.mamoe.mirai.console.pure.ConsoleInputImpl.requestInput import net.mamoe.mirai.console.pure.ConsoleInputImpl.requestInput
import net.mamoe.mirai.console.util.ConsoleExperimentalApi import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import net.mamoe.mirai.console.util.ConsoleInput import net.mamoe.mirai.console.util.ConsoleInput
@ -51,7 +50,6 @@ import java.time.Instant
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.ZoneId import java.time.ZoneId
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
import java.util.*
/** /**
* mirai-console-pure 后端实现 * mirai-console-pure 后端实现
@ -61,15 +59,13 @@ import java.util.*
@ConsoleExperimentalApi @ConsoleExperimentalApi
class MiraiConsoleImplementationPure class MiraiConsoleImplementationPure
@JvmOverloads constructor( @JvmOverloads constructor(
override val rootPath: Path = Paths.get("."), override val rootPath: Path = Paths.get(".").toAbsolutePath(),
override val builtInPluginLoaders: List<PluginLoader<*, *>> = Collections.unmodifiableList( override val builtInPluginLoaders: List<Lazy<PluginLoader<*, *>>> = listOf(lazy { JvmPluginLoader }),
listOf(DeferredPluginLoader { JvmPluginLoader })
),
override val frontEndDescription: MiraiConsoleFrontEndDescription = ConsoleFrontEndDescImpl, override val frontEndDescription: MiraiConsoleFrontEndDescription = ConsoleFrontEndDescImpl,
override val consoleCommandSender: MiraiConsoleImplementation.ConsoleCommandSenderImpl = ConsoleCommandSenderImplPure, override val consoleCommandSender: MiraiConsoleImplementation.ConsoleCommandSenderImpl = ConsoleCommandSenderImplPure,
override val dataStorageForJarPluginLoader: PluginDataStorage = MultiFilePluginDataStorage(rootPath.resolve("data")), override val dataStorageForJvmPluginLoader: PluginDataStorage = MultiFilePluginDataStorage(rootPath.resolve("data")),
override val dataStorageForBuiltIns: PluginDataStorage = MultiFilePluginDataStorage(rootPath.resolve("data")), override val dataStorageForBuiltIns: PluginDataStorage = MultiFilePluginDataStorage(rootPath.resolve("data")),
override val configStorageForJarPluginLoader: PluginDataStorage = MultiFilePluginDataStorage(rootPath.resolve("config")), override val configStorageForJvmPluginLoader: PluginDataStorage = MultiFilePluginDataStorage(rootPath.resolve("config")),
override val configStorageForBuiltIns: PluginDataStorage = MultiFilePluginDataStorage(rootPath.resolve("config")), override val configStorageForBuiltIns: PluginDataStorage = MultiFilePluginDataStorage(rootPath.resolve("config")),
) : MiraiConsoleImplementation, CoroutineScope by CoroutineScope( ) : MiraiConsoleImplementation, CoroutineScope by CoroutineScope(
NamedSupervisorJob("MiraiConsoleImplementationPure") + NamedSupervisorJob("MiraiConsoleImplementationPure") +