mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-10 18:40:15 +08:00
Rearrange JvmPlugin implementations
This commit is contained in:
parent
d37d6881fc
commit
11bdb438eb
@ -0,0 +1,83 @@
|
||||
package net.mamoe.mirai.console.plugins.builtin
|
||||
|
||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
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.utils.MiraiLogger
|
||||
import java.io.File
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.reflect.full.createInstance
|
||||
|
||||
/**
|
||||
* 内建的 Jar (JVM) 插件加载器
|
||||
*/
|
||||
object JarPluginLoader : AbstractFilePluginLoader<JvmPlugin, JvmPluginDescription>("jar"),
|
||||
CoroutineScope {
|
||||
private val logger: MiraiLogger by lazy {
|
||||
MiraiConsole.newLogger(JarPluginLoader::class.simpleName!!)
|
||||
}
|
||||
|
||||
override val coroutineContext: CoroutineContext by lazy {
|
||||
MiraiConsole.coroutineContext + SupervisorJob(
|
||||
MiraiConsole.coroutineContext[Job]
|
||||
) + CoroutineExceptionHandler { _, throwable ->
|
||||
logger.error("Unhandled Jar plugin exception: ${throwable.message}", throwable)
|
||||
}
|
||||
}
|
||||
|
||||
private val classLoader: PluginsLoader =
|
||||
PluginsLoader(this.javaClass.classLoader)
|
||||
|
||||
override fun getPluginDescription(plugin: JvmPlugin): JvmPluginDescription = plugin.description
|
||||
|
||||
override fun Sequence<File>.mapToDescription(): List<JvmPluginDescription> {
|
||||
TODO(
|
||||
"""
|
||||
CHECK IS JAR FILE AND CAN BE READ
|
||||
READ JAR FILE, EXTRACT PLUGIN DESCRIPTION
|
||||
SET JvmPluginDescription._file
|
||||
RETURN PLUGIN
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
@Throws(PluginLoadException::class)
|
||||
override fun load(description: JvmPluginDescription): JvmPlugin = description.runCatching {
|
||||
val main = classLoader.loadPluginMainClassByJarFile(name, mainClassName, file).kotlin.run {
|
||||
objectInstance
|
||||
?: kotlin.runCatching { createInstance() }.getOrNull()
|
||||
?: (java.constructors + java.declaredConstructors)
|
||||
.firstOrNull { it.parameterCount == 0 }
|
||||
?.apply { kotlin.runCatching { isAccessible = true } }
|
||||
?.newInstance()
|
||||
} ?: error("No Kotlin object or public no-arg constructor found")
|
||||
|
||||
check(main is JvmPlugin) { "The main class of Jar plugin must extend JvmPlugin, recommending JavaPlugin or KotlinPlugin" }
|
||||
|
||||
if (main is JvmPluginImpl) {
|
||||
main._description = description
|
||||
}
|
||||
|
||||
TODO(
|
||||
"""
|
||||
FIND PLUGIN MAIN, THEN LOAD
|
||||
SET JvmPluginImpl._description
|
||||
SET JvmPluginImpl._intrinsicCoroutineContext
|
||||
""".trimIndent()
|
||||
)
|
||||
// no need to check dependencies
|
||||
}.getOrElse {
|
||||
throw PluginLoadException(
|
||||
"Exception while loading ${description.name}",
|
||||
it
|
||||
)
|
||||
}
|
||||
|
||||
override fun enable(plugin: JvmPlugin) = plugin.onEnable()
|
||||
override fun disable(plugin: JvmPlugin) = plugin.onDisable()
|
||||
}
|
@ -9,24 +9,31 @@
|
||||
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "EXPOSED_SUPER_CLASS")
|
||||
|
||||
|
||||
package net.mamoe.mirai.console.plugins
|
||||
package net.mamoe.mirai.console.plugins.builtin
|
||||
|
||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.Transient
|
||||
import net.mamoe.mirai.console.MiraiConsole
|
||||
import net.mamoe.mirai.console.scheduler.PluginScheduler
|
||||
import net.mamoe.mirai.console.plugins.Plugin
|
||||
import net.mamoe.mirai.console.utils.JavaPluginScheduler
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
import java.io.File
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
|
||||
|
||||
/**
|
||||
* Java 或 Kotlin Jar 插件
|
||||
*
|
||||
* @see JavaPlugin Java 插件
|
||||
* @see KotlinPlugin Kotlin 插件
|
||||
*/
|
||||
interface JvmPlugin : Plugin, CoroutineScope {
|
||||
/** 日志 */
|
||||
val logger: MiraiLogger
|
||||
|
||||
/** 插件描述 */
|
||||
val description: JvmPluginDescription
|
||||
|
||||
@JvmDefault
|
||||
@ -42,7 +49,9 @@ interface JvmPlugin : Plugin, CoroutineScope {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Java 插件的父类
|
||||
*/
|
||||
abstract class JavaPlugin @JvmOverloads constructor(
|
||||
coroutineContext: CoroutineContext = EmptyCoroutineContext
|
||||
) : JvmPlugin, JvmPluginImpl(coroutineContext) {
|
||||
@ -50,7 +59,8 @@ abstract class JavaPlugin @JvmOverloads constructor(
|
||||
/**
|
||||
* Java API Scheduler
|
||||
*/
|
||||
val scheduler: PluginScheduler? = PluginScheduler(this.coroutineContext)
|
||||
val scheduler: JavaPluginScheduler =
|
||||
JavaPluginScheduler(this.coroutineContext)
|
||||
}
|
||||
|
||||
abstract class KotlinPlugin @JvmOverloads constructor(
|
||||
@ -59,41 +69,6 @@ abstract class KotlinPlugin @JvmOverloads constructor(
|
||||
// that's it
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class JvmPluginDescription internal constructor( // serializer 可以用这个构造器
|
||||
override val kind: PluginKind,
|
||||
override val name: String,
|
||||
override val author: String,
|
||||
override val version: String,
|
||||
override val info: String,
|
||||
override val loadBefore: List<String>,
|
||||
override val dependencies: List<PluginDependency>
|
||||
) : PluginDescription, FilePluginDescription {
|
||||
/**
|
||||
* 在手动实现时使用这个构造器.
|
||||
*/
|
||||
@Suppress("unused")
|
||||
constructor(
|
||||
kind: PluginKind,
|
||||
name: String,
|
||||
author: String,
|
||||
version: String,
|
||||
info: String,
|
||||
loadBefore: List<String>,
|
||||
depends: List<PluginDependency>,
|
||||
file: File
|
||||
) : this(kind, name, author, version, info, loadBefore, depends) {
|
||||
this._file = file
|
||||
}
|
||||
|
||||
@Suppress("PropertyName")
|
||||
@Transient
|
||||
internal var _file: File? = null
|
||||
|
||||
override val file: File
|
||||
get() = _file ?: error("Internal error: JvmPluginDescription(name=$name)._file == null")
|
||||
}
|
||||
|
||||
internal abstract class JvmPluginImpl(
|
||||
parentCoroutineContext: CoroutineContext
|
||||
) : JvmPlugin, CoroutineScope {
|
||||
@ -102,6 +77,11 @@ internal abstract class JvmPluginImpl(
|
||||
*/
|
||||
@Suppress("PropertyName")
|
||||
internal lateinit var _description: JvmPluginDescription
|
||||
|
||||
// for future use
|
||||
@Suppress("PropertyName")
|
||||
internal var _intrinsicCoroutineContext: CoroutineContext = EmptyCoroutineContext
|
||||
|
||||
override val description: JvmPluginDescription get() = _description
|
||||
|
||||
final override val logger: MiraiLogger by lazy { MiraiConsole.newLogger(this._description.name) }
|
||||
@ -109,37 +89,10 @@ internal abstract class JvmPluginImpl(
|
||||
final override val coroutineContext: CoroutineContext by lazy {
|
||||
CoroutineExceptionHandler { _, throwable -> logger.error(throwable) }
|
||||
.plus(parentCoroutineContext)
|
||||
.plus(SupervisorJob(parentCoroutineContext[Job]))
|
||||
.plus(SupervisorJob(parentCoroutineContext[Job])) + _intrinsicCoroutineContext
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 内建的 Jar (JVM) 插件加载器
|
||||
*/
|
||||
object JarPluginLoader : AbstractFilePluginLoader<JvmPlugin, JvmPluginDescription>("jar") {
|
||||
override fun getPluginDescription(plugin: JvmPlugin): JvmPluginDescription = plugin.description
|
||||
|
||||
override fun Sequence<File>.mapToDescription(): List<JvmPluginDescription> {
|
||||
TODO(
|
||||
"""
|
||||
CHECK IS JAR FILE AND CAN BE READ
|
||||
READ JAR FILE, EXTRACT PLUGIN DESCRIPTION
|
||||
SET JvmPluginDescription._file
|
||||
RETURN PLUGIN
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
@Throws(PluginLoadException::class)
|
||||
override fun load(description: JvmPluginDescription): JvmPlugin {
|
||||
TODO("FIND PLUGIN MAIN, THEN LOAD")
|
||||
// no need to check dependencies
|
||||
}
|
||||
|
||||
override fun enable(plugin: JvmPlugin) = plugin.onEnable()
|
||||
override fun disable(plugin: JvmPlugin) = plugin.onDisable()
|
||||
}
|
||||
|
||||
/*
|
||||
object PluginManagerOld {
|
||||
/**
|
@ -0,0 +1,48 @@
|
||||
package net.mamoe.mirai.console.plugins.builtin
|
||||
|
||||
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 java.io.File
|
||||
|
||||
@Serializable
|
||||
class JvmPluginDescription internal constructor(
|
||||
override val kind: PluginKind,
|
||||
override val name: String,
|
||||
@SerialName("main")
|
||||
val mainClassName: String,
|
||||
override val author: String,
|
||||
override val version: String,
|
||||
override val info: String,
|
||||
override val dependencies: List<PluginDependency>
|
||||
) : PluginDescription, FilePluginDescription {
|
||||
|
||||
/**
|
||||
* 在手动实现时使用这个构造器.
|
||||
*/
|
||||
@Suppress("unused")
|
||||
constructor(
|
||||
kind: PluginKind, name: String, mainClassName: String, author: String,
|
||||
version: String, info: String, depends: List<PluginDependency>,
|
||||
file: File
|
||||
) : this(kind, name, mainClassName, author, version, info, depends) {
|
||||
this._file = file
|
||||
}
|
||||
|
||||
override val file: File
|
||||
get() = _file ?: error("Internal error: JvmPluginDescription(name=$name)._file == null")
|
||||
|
||||
|
||||
@Suppress("PropertyName")
|
||||
@Transient
|
||||
@JvmField
|
||||
internal var _file: File? = null
|
||||
|
||||
override fun toString(): String {
|
||||
return "JvmPluginDescription(kind=$kind, name='$name', mainClassName='$mainClassName', author='$author', version='$version', info='$info', dependencies=$dependencies, _file=$_file)"
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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.plugins
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import java.io.File
|
||||
|
||||
|
||||
/** 插件类型 */
|
||||
enum class PluginKind {
|
||||
/** 表示此插件提供一个 [PluginLoader], 应在加载其他 [NORMAL] 类型插件前加载 */
|
||||
LOADER,
|
||||
|
||||
/** 表示此插件为一个通常的插件, 按照正常的依赖关系加载. */
|
||||
NORMAL
|
||||
}
|
||||
|
||||
/**
|
||||
* 插件描述
|
||||
*/
|
||||
interface PluginDescription {
|
||||
val kind: PluginKind
|
||||
|
||||
val name: String
|
||||
val author: String
|
||||
val version: String
|
||||
val info: String
|
||||
|
||||
/** 此插件依赖的其他插件, 将会在这些插件加载之后加载此插件 */
|
||||
val dependencies: List<PluginDependency>
|
||||
}
|
||||
|
||||
/** 插件的一个依赖的信息 */
|
||||
@Serializable
|
||||
data class PluginDependency(
|
||||
/** 依赖插件名 */
|
||||
val name: String,
|
||||
/**
|
||||
* 依赖版本号
|
||||
* @see versionKind 版本号类型
|
||||
*/
|
||||
val version: String,
|
||||
/** 版本号类型 */
|
||||
val versionKind: VersionKind,
|
||||
/**
|
||||
* 若为 `false`, 插件在找不到此依赖时也能正常加载.
|
||||
*/
|
||||
val isOptional: Boolean
|
||||
) {
|
||||
enum class VersionKind {
|
||||
/** 要求依赖精确的版本 */
|
||||
EXACT,
|
||||
|
||||
/** 要求依赖最低版本 */
|
||||
AT_LEAST,
|
||||
|
||||
/** 要求依赖最高版本 */
|
||||
AT_MOST
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "$name ${versionKind.toEnglishString()}v$version"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于文件的插件的描述
|
||||
*/
|
||||
interface FilePluginDescription : PluginDescription {
|
||||
val file: File
|
||||
}
|
||||
|
||||
internal fun PluginDependency.VersionKind.toEnglishString(): String = when (this) {
|
||||
PluginDependency.VersionKind.EXACT -> ""
|
||||
PluginDependency.VersionKind.AT_LEAST -> "at least "
|
||||
PluginDependency.VersionKind.AT_MOST -> "at most "
|
||||
}
|
Loading…
Reference in New Issue
Block a user