mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-25 15:40:28 +08:00
Misc
This commit is contained in:
parent
11bdb438eb
commit
c3120cf1ac
@ -61,6 +61,7 @@ dependencies {
|
||||
|
||||
api("net.mamoe.yamlkt:yamlkt:0.3.1")
|
||||
api("org.jetbrains:annotations:19.0.0")
|
||||
api(kotlinx("coroutines-jdk8", Versions.Kotlin.coroutines))
|
||||
|
||||
testApi("net.mamoe:mirai-core-qqandroid:${Versions.Mirai.core}")
|
||||
testApi(kotlin("stdlib-jdk8"))
|
||||
|
@ -13,8 +13,8 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.io.charsets.Charset
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.console.plugins.JarPluginLoader
|
||||
import net.mamoe.mirai.console.plugins.PluginLoader
|
||||
import net.mamoe.mirai.console.plugins.builtin.JarPluginLoader
|
||||
import net.mamoe.mirai.utils.DefaultLogger
|
||||
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
@ -23,6 +23,38 @@ import java.io.File
|
||||
import java.io.PrintStream
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
/**
|
||||
* mirai 控制台实例.
|
||||
*/
|
||||
object MiraiConsole : CoroutineScope, IMiraiConsole {
|
||||
private lateinit var instance: IMiraiConsole
|
||||
|
||||
/** 由前端调用 */
|
||||
internal fun init(instance: IMiraiConsole) {
|
||||
this.instance = instance
|
||||
}
|
||||
|
||||
override val build: String get() = instance.build
|
||||
override val version: String get() = instance.version
|
||||
override val rootDir: File get() = instance.rootDir
|
||||
override val frontEnd: MiraiConsoleFrontEnd get() = instance.frontEnd
|
||||
override val mainLogger: MiraiLogger get() = instance.mainLogger
|
||||
override val coroutineContext: CoroutineContext get() = instance.coroutineContext
|
||||
|
||||
override val builtInPluginLoaders: List<PluginLoader<*, *>> = instance.builtInPluginLoaders
|
||||
|
||||
init {
|
||||
DefaultLogger = { identity -> this.newLogger(identity) }
|
||||
this.coroutineContext[Job]!!.invokeOnCompletion {
|
||||
Bot.botInstances.forEach { kotlin.runCatching { it.close() }.exceptionOrNull()?.let(mainLogger::error) }
|
||||
}
|
||||
}
|
||||
|
||||
@MiraiExperimentalAPI
|
||||
fun newLogger(identity: String?): MiraiLogger = frontEnd.loggerFor(identity)
|
||||
}
|
||||
|
||||
|
||||
// 前端使用
|
||||
internal interface IMiraiConsole : CoroutineScope {
|
||||
val build: String
|
||||
@ -49,36 +81,6 @@ internal interface IMiraiConsole : CoroutineScope {
|
||||
val builtInPluginLoaders: List<PluginLoader<*, *>>
|
||||
}
|
||||
|
||||
object MiraiConsole : CoroutineScope, IMiraiConsole {
|
||||
private lateinit var instance: IMiraiConsole
|
||||
|
||||
/** 由前端调用 */
|
||||
internal fun init(instance: IMiraiConsole) {
|
||||
this.instance = instance
|
||||
}
|
||||
|
||||
override val build: String get() = instance.build
|
||||
override val version: String get() = instance.version
|
||||
override val rootDir: File get() = instance.rootDir
|
||||
override val frontEnd: MiraiConsoleFrontEnd get() = instance.frontEnd
|
||||
override val mainLogger: MiraiLogger get() = instance.mainLogger
|
||||
override val coroutineContext: CoroutineContext get() = instance.coroutineContext
|
||||
|
||||
override val builtInPluginLoaders: List<PluginLoader<*, *>> = instance.builtInPluginLoaders
|
||||
|
||||
init {
|
||||
DefaultLogger = { identity ->
|
||||
this.newLogger(identity)
|
||||
}
|
||||
this.coroutineContext[Job]!!.invokeOnCompletion {
|
||||
Bot.botInstances.forEach { kotlin.runCatching { it.close() }.exceptionOrNull()?.let(mainLogger::error) }
|
||||
}
|
||||
}
|
||||
|
||||
@MiraiExperimentalAPI
|
||||
fun newLogger(identity: String?): MiraiLogger = frontEnd.loggerFor(identity)
|
||||
}
|
||||
|
||||
/**
|
||||
* Included in kotlin stdlib 1.4
|
||||
*/
|
||||
|
@ -9,82 +9,17 @@
|
||||
|
||||
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 loadBefore: List<String>
|
||||
|
||||
/** 此插件依赖的其他插件, 将会在这些插件加载之后加载此插件 */
|
||||
val dependencies: List<PluginDependency>
|
||||
}
|
||||
|
||||
/** 插件的一个依赖的信息 */
|
||||
@Serializable
|
||||
data class PluginDependency(
|
||||
/** 依赖插件名 */
|
||||
val name: String,
|
||||
/**
|
||||
* 依赖版本号
|
||||
* @see versionKind 版本号类型
|
||||
*/
|
||||
val version: String,
|
||||
/** 版本号类型 */
|
||||
val versionKind: VersionKind
|
||||
) {
|
||||
enum class VersionKind {
|
||||
/** 要求依赖精确的版本 */
|
||||
EXACT,
|
||||
|
||||
/** 要求依赖最低版本 */
|
||||
AT_LEAST,
|
||||
|
||||
/** 要求依赖最高版本 */
|
||||
AT_MOST
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "$name ${versionKind.toEnglishString()}v$version"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal fun PluginDependency.VersionKind.toEnglishString(): String = when (this) {
|
||||
PluginDependency.VersionKind.EXACT -> ""
|
||||
PluginDependency.VersionKind.AT_LEAST -> "at least "
|
||||
PluginDependency.VersionKind.AT_MOST -> "at most "
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于文件的插件的描述
|
||||
*/
|
||||
interface FilePluginDescription : PluginDescription {
|
||||
val file: File
|
||||
}
|
||||
import net.mamoe.mirai.console.plugins.builtin.JvmPlugin
|
||||
|
||||
/**
|
||||
* 表示一个 mirai-console 插件.
|
||||
*
|
||||
* @see JvmPlugin
|
||||
* @see PluginDescription 插件描述
|
||||
*/
|
||||
interface Plugin
|
||||
interface Plugin {
|
||||
/**
|
||||
* 所属插件加载器实例
|
||||
*/
|
||||
val loader: PluginLoader<*, *>
|
||||
}
|
@ -2,7 +2,6 @@
|
||||
|
||||
package net.mamoe.mirai.console.plugins
|
||||
|
||||
import net.mamoe.mirai.console.MiraiConsole
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
|
@ -5,12 +5,10 @@ package net.mamoe.mirai.console.plugins
|
||||
import kotlinx.atomicfu.locks.withLock
|
||||
import net.mamoe.mirai.console.MiraiConsole
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
val Plugin.description: PluginDescription get() = TODO()
|
||||
val <P : Plugin> P.loader: PluginLoader<P, *> get() = TODO()
|
||||
val Plugin.description: PluginDescription
|
||||
get() = PluginManager.resolvedPlugins.firstOrNull { it == this }?.description ?: error("Plugin is unloaded")
|
||||
|
||||
inline fun PluginLoader<*, *>.register() = PluginManager.registerPluginLoader(this)
|
||||
inline fun PluginLoader<*, *>.unregister() = PluginManager.unregisterPluginLoader(this)
|
||||
@ -18,19 +16,18 @@ inline fun PluginLoader<*, *>.unregister() = PluginManager.unregisterPluginLoade
|
||||
object PluginManager {
|
||||
val pluginsDir = File(MiraiConsole.rootDir, "plugins").apply { mkdir() }
|
||||
|
||||
class LoaderNode<P : Plugin, D : PluginDescription>(
|
||||
val loader: PluginLoader<P, D>,
|
||||
val loadedPlugins: MutableList<P> = mutableListOf()
|
||||
)
|
||||
|
||||
private val _pluginLoaders: MutableSet<LoaderNode<*, *>> = mutableSetOf()
|
||||
private val _pluginLoaders: MutableList<PluginLoader<*, *>> = mutableListOf()
|
||||
private val loadersLock: ReentrantLock = ReentrantLock()
|
||||
|
||||
private val resolvedPlugins: LinkedList<Plugin> = LinkedList()
|
||||
@JvmField
|
||||
internal val resolvedPlugins: MutableList<Plugin> = mutableListOf()
|
||||
|
||||
/**
|
||||
* 已加载的插件列表
|
||||
*/
|
||||
@JvmStatic
|
||||
val plugins: List<Plugin>
|
||||
get() = _pluginLoaders.flatMap { it.loadedPlugins }
|
||||
get() = resolvedPlugins.toList()
|
||||
|
||||
/**
|
||||
* 内建的插件加载器列表. 由 [MiraiConsole] 初始化
|
||||
@ -42,16 +39,21 @@ object PluginManager {
|
||||
/**
|
||||
* 由插件创建的 [PluginLoader]
|
||||
*/
|
||||
val pluginLoaders: List<PluginLoader<*, *>> get() = _pluginLoaders.map { it.loader }
|
||||
@JvmStatic
|
||||
val pluginLoaders: List<PluginLoader<*, *>>
|
||||
get() = _pluginLoaders.toList()
|
||||
|
||||
@JvmStatic
|
||||
fun registerPluginLoader(loader: PluginLoader<*, *>): Boolean = loadersLock.withLock {
|
||||
_pluginLoaders.add(LoaderNode(loader))
|
||||
if (_pluginLoaders.any { it::class == loader }) {
|
||||
return false
|
||||
}
|
||||
_pluginLoaders.add(loader)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun unregisterPluginLoader(loader: PluginLoader<*, *>) = loadersLock.withLock {
|
||||
_pluginLoaders.removeAll { it.loader == loader }
|
||||
_pluginLoaders.remove(loader)
|
||||
}
|
||||
|
||||
|
||||
@ -80,7 +82,7 @@ object PluginManager {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@Throws(PluginMissingDependencyException::class)
|
||||
internal fun loadEnablePlugins() {
|
||||
val all = loadAndEnableLoaderProviders() + pluginLoaders.listAllPlugins().flatMap { it.second }
|
||||
val all = loadAndEnableLoaderProviders() + _pluginLoaders.listAllPlugins().flatMap { it.second }
|
||||
|
||||
for ((loader, desc) in all.sortByDependencies()) {
|
||||
loader.loadPluginAndEnable(desc)
|
||||
@ -116,7 +118,7 @@ object PluginManager {
|
||||
private fun <D : PluginDescription> List<D>.sortByDependencies(): List<D> {
|
||||
val resolved = ArrayList<D>(this.size)
|
||||
|
||||
fun D.canBeLoad(): Boolean = this.dependencies.all { it in resolved }
|
||||
fun D.canBeLoad(): Boolean = this.dependencies.all { it.isOptional || it in resolved }
|
||||
|
||||
fun List<D>.consumeLoadable(): List<D> {
|
||||
val (canBeLoad, cannotBeLoad) = this.partition { it.canBeLoad() }
|
||||
@ -124,7 +126,8 @@ object PluginManager {
|
||||
return cannotBeLoad
|
||||
}
|
||||
|
||||
fun List<PluginDependency>.filterIsMissing(): List<PluginDependency> = this.filterNot { it in resolved }
|
||||
fun List<PluginDependency>.filterIsMissing(): List<PluginDependency> =
|
||||
this.filterNot { it.isOptional || it in resolved }
|
||||
|
||||
tailrec fun List<D>.doSort() {
|
||||
if (this.isEmpty()) return
|
||||
@ -147,6 +150,21 @@ object PluginManager {
|
||||
// endregion
|
||||
}
|
||||
|
||||
class PluginMissingDependencyException : PluginResolutionException {
|
||||
constructor() : super()
|
||||
constructor(message: String?) : super(message)
|
||||
constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||
constructor(cause: Throwable?) : super(cause)
|
||||
}
|
||||
|
||||
open class PluginResolutionException : Exception {
|
||||
constructor() : super()
|
||||
constructor(message: String?) : super(message)
|
||||
constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||
constructor(cause: Throwable?) : super(cause)
|
||||
}
|
||||
|
||||
|
||||
internal data class PluginDescriptionWithLoader(
|
||||
@JvmField val loader: PluginLoader<*, PluginDescription>, // easier type
|
||||
@JvmField val delegate: PluginDescription
|
||||
@ -164,17 +182,3 @@ internal fun PluginDescription.wrapWith(loader: PluginLoader<*, *>): PluginDescr
|
||||
|
||||
internal operator fun List<PluginDescription>.contains(dependency: PluginDependency): Boolean =
|
||||
any { it.name == dependency.name }
|
||||
|
||||
class PluginMissingDependencyException : Exception {
|
||||
constructor() : super()
|
||||
constructor(message: String?) : super(message)
|
||||
constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||
constructor(cause: Throwable?) : super(cause)
|
||||
}
|
||||
|
||||
open class PluginResolutionException : Exception {
|
||||
constructor() : super()
|
||||
constructor(message: String?) : super(message)
|
||||
constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||
constructor(cause: Throwable?) : super(cause)
|
||||
}
|
@ -17,6 +17,7 @@ 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.utils.MiraiLogger
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
@ -36,6 +37,9 @@ interface JvmPlugin : Plugin, CoroutineScope {
|
||||
/** 插件描述 */
|
||||
val description: JvmPluginDescription
|
||||
|
||||
/** 所属插件加载器实例 */
|
||||
override val loader: PluginLoader<*, *> get() = JarPluginLoader
|
||||
|
||||
@JvmDefault
|
||||
fun onLoad() {
|
||||
}
|
||||
@ -53,8 +57,8 @@ interface JvmPlugin : Plugin, CoroutineScope {
|
||||
* Java 插件的父类
|
||||
*/
|
||||
abstract class JavaPlugin @JvmOverloads constructor(
|
||||
coroutineContext: CoroutineContext = EmptyCoroutineContext
|
||||
) : JvmPlugin, JvmPluginImpl(coroutineContext) {
|
||||
parentCoroutineContext: CoroutineContext = EmptyCoroutineContext
|
||||
) : JvmPlugin, JvmPluginImpl(parentCoroutineContext) {
|
||||
|
||||
/**
|
||||
* Java API Scheduler
|
||||
@ -64,8 +68,8 @@ abstract class JavaPlugin @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
abstract class KotlinPlugin @JvmOverloads constructor(
|
||||
coroutineContext: CoroutineContext = EmptyCoroutineContext
|
||||
) : JvmPlugin, JvmPluginImpl(coroutineContext) {
|
||||
parentCoroutineContext: CoroutineContext = EmptyCoroutineContext
|
||||
) : JvmPlugin, JvmPluginImpl(parentCoroutineContext) {
|
||||
// that's it
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user