Implement PluginLoaders and PluginManager

This commit is contained in:
Him188 2020-05-23 17:44:34 +08:00
parent 4de8a6b01c
commit 9c18c04466
16 changed files with 708 additions and 449 deletions

View File

@ -224,7 +224,8 @@ fun genCollectionValueImpl(
""" """
internal fun Setting.valueImpl(default: ${kotlinTypeName}): ${miraiValueName}Value { internal fun Setting.valueImpl(default: ${kotlinTypeName}): ${miraiValueName}Value {
var internalValue: $kotlinTypeName = default var internalValue: $kotlinTypeName = default
return object : ${miraiValueName}Value(), $kotlinTypeName by dynamic$collectionName({ internalValue }) { val delegt = dynamic$collectionName { internalValue }
return object : ${miraiValueName}Value(), $kotlinTypeName by delegt {
override var value: $kotlinTypeName override var value: $kotlinTypeName
get() = internalValue get() = internalValue
set(new) { set(new) {

View File

@ -1,4 +1,3 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import upload.Bintray import upload.Bintray
import java.util.* import java.util.*
@ -12,19 +11,46 @@ plugins {
apply(plugin = "com.github.johnrengelman.shadow") apply(plugin = "com.github.johnrengelman.shadow")
kotlin { version = Versions.Mirai.console
sourceSets { description = "Console backend for mirai"
all {
languageSettings.enableLanguageFeature("InlineClasses")
languageSettings.useExperimentalAnnotation("kotlin.Experimental") java {
languageSettings.useExperimentalAnnotation("kotlin.OptIn") sourceCompatibility = JavaVersion.VERSION_1_8
languageSettings.progressiveMode = true targetCompatibility = JavaVersion.VERSION_1_8
languageSettings.useExperimentalAnnotation("net.mamoe.mirai.utils.MiraiInternalAPI") }
languageSettings.useExperimentalAnnotation("net.mamoe.mirai.utils.MiraiExperimentalAPI")
languageSettings.useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes") tasks.withType(JavaCompile::class.java) {
languageSettings.useExperimentalAnnotation("kotlin.experimental.ExperimentalTypeInference") options.encoding = "UTF8"
languageSettings.useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts") }
kotlin {
sourceSets.all {
target.compilations.all {
kotlinOptions {
freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=enable"
jvmTarget = "1.8"
}
}
languageSettings.apply {
enableLanguageFeature("InlineClasses")
progressiveMode = true
useExperimentalAnnotation("kotlin.Experimental")
useExperimentalAnnotation("kotlin.OptIn")
useExperimentalAnnotation("net.mamoe.mirai.utils.MiraiInternalAPI")
useExperimentalAnnotation("net.mamoe.mirai.utils.MiraiExperimentalAPI")
useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes")
useExperimentalAnnotation("kotlin.experimental.ExperimentalTypeInference")
useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts")
}
}
sourceSets {
getByName("test") {
languageSettings.apply {
languageVersion = "1.4"
}
} }
} }
} }
@ -34,36 +60,15 @@ dependencies {
compileAndRuntime(kotlin("stdlib")) compileAndRuntime(kotlin("stdlib"))
api("net.mamoe.yamlkt:yamlkt:0.3.1") api("net.mamoe.yamlkt:yamlkt:0.3.1")
api("org.jetbrains:annotations:19.0.0") api("org.jetbrains:annotations:19.0.0")
testApi("net.mamoe:mirai-core-qqandroid:${Versions.Mirai.core}") testApi("net.mamoe:mirai-core-qqandroid:${Versions.Mirai.core}")
testApi(kotlin("stdlib")) testApi(kotlin("stdlib-jdk8"))
testApi(kotlin("test")) testApi(kotlin("test"))
testApi(kotlin("test-junit5")) testApi(kotlin("test-junit5"))
} }
version = Versions.Mirai.console // region PUBLISHING
description = "Console backend for mirai"
val compileKotlin: KotlinCompile by tasks
compileKotlin.kotlinOptions {
jvmTarget = "1.8"
}
val compileTestKotlin: KotlinCompile by tasks
compileTestKotlin.kotlinOptions {
jvmTarget = "1.8"
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
tasks.withType(JavaCompile::class.java) {
options.encoding = "UTF8"
}
tasks.register("ensureBintrayAvailable") { tasks.register("ensureBintrayAvailable") {
doLast { doLast {
@ -128,4 +133,6 @@ if (Bintray.isBintrayAvailable(project)) {
} }
} }
} }
} else println("bintray isn't available. NO PUBLICATIONS WILL BE SET") } else println("bintray isn't available. NO PUBLICATIONS WILL BE SET")
// endregion

View File

@ -13,33 +13,40 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.io.charsets.Charset import kotlinx.io.charsets.Charset
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.console.utils.MiraiConsoleFrontEnd import net.mamoe.mirai.console.plugins.JarPluginLoader
import net.mamoe.mirai.console.plugins.PluginLoader
import net.mamoe.mirai.utils.DefaultLogger import net.mamoe.mirai.utils.DefaultLogger
import net.mamoe.mirai.utils.MiraiExperimentalAPI import net.mamoe.mirai.utils.MiraiExperimentalAPI
import net.mamoe.mirai.utils.MiraiLogger import net.mamoe.mirai.utils.MiraiLogger
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.io.File
import java.io.PrintStream import java.io.PrintStream
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
// 前端使用 // 前端使用
interface IMiraiConsole : CoroutineScope { internal interface IMiraiConsole : CoroutineScope {
val build: String val build: String
val version: String val version: String
/** /**
* Console运行路径 * Console 运行路径
*/ */
val path: String val rootDir: File
/** /**
* Console前端接口 * Console 前端接口
*/ */
val frontEnd: MiraiConsoleFrontEnd val frontEnd: MiraiConsoleFrontEnd
/** /**
* 与前端交互所使用的Logger * 与前端交互所使用的 Logger
*/ */
val mainLogger: MiraiLogger val mainLogger: MiraiLogger
/**
* 内建加载器列表, 一般需要包含 [JarPluginLoader]
*/
val builtInPluginLoaders: List<PluginLoader<*, *>>
} }
object MiraiConsole : CoroutineScope, IMiraiConsole { object MiraiConsole : CoroutineScope, IMiraiConsole {
@ -52,19 +59,19 @@ object MiraiConsole : CoroutineScope, IMiraiConsole {
override val build: String get() = instance.build override val build: String get() = instance.build
override val version: String get() = instance.version override val version: String get() = instance.version
override val path: String get() = instance.path override val rootDir: File get() = instance.rootDir
override val frontEnd: MiraiConsoleFrontEnd get() = instance.frontEnd override val frontEnd: MiraiConsoleFrontEnd get() = instance.frontEnd
override val mainLogger: MiraiLogger get() = instance.mainLogger override val mainLogger: MiraiLogger get() = instance.mainLogger
override val coroutineContext: CoroutineContext get() = instance.coroutineContext override val coroutineContext: CoroutineContext get() = instance.coroutineContext
override val builtInPluginLoaders: List<PluginLoader<*, *>> = instance.builtInPluginLoaders
init { init {
DefaultLogger = { DefaultLogger = { identity ->
this.newLogger(it) this.newLogger(identity)
} }
this.coroutineContext[Job]!!.invokeOnCompletion { this.coroutineContext[Job]!!.invokeOnCompletion {
Bot.botInstances.forEach { Bot.botInstances.forEach { kotlin.runCatching { it.close() }.exceptionOrNull()?.let(mainLogger::error) }
it.close()
}
} }
} }
@ -72,6 +79,9 @@ object MiraiConsole : CoroutineScope, IMiraiConsole {
fun newLogger(identity: String?): MiraiLogger = frontEnd.loggerFor(identity) fun newLogger(identity: String?): MiraiLogger = frontEnd.loggerFor(identity)
} }
/**
* Included in kotlin stdlib 1.4
*/
internal val Throwable.stacktraceString: String internal val Throwable.stacktraceString: String
get() = get() =
ByteArrayOutputStream().apply { ByteArrayOutputStream().apply {

View File

@ -7,7 +7,7 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE * https://github.com/mamoe/mirai/blob/master/LICENSE
*/ */
package net.mamoe.mirai.console.utils package net.mamoe.mirai.console
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.console.center.CuiPluginCenter import net.mamoe.mirai.console.center.CuiPluginCenter

View File

@ -10,11 +10,7 @@
package net.mamoe.mirai.console.command.description package net.mamoe.mirai.console.command.description
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.console.command.BotAwareCommandSender import net.mamoe.mirai.console.command.*
import net.mamoe.mirai.console.command.CommandSender
import net.mamoe.mirai.console.command.MemberCommandSender
import net.mamoe.mirai.console.command.UserCommandSender
import net.mamoe.mirai.console.utils.fuzzySearchMember
import net.mamoe.mirai.contact.Friend import net.mamoe.mirai.contact.Friend
import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.Member import net.mamoe.mirai.contact.Member

View File

@ -9,6 +9,8 @@
package net.mamoe.mirai.console.command package net.mamoe.mirai.console.command
import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.Member
import java.util.concurrent.locks.ReentrantLock import java.util.concurrent.locks.ReentrantLock
@ -61,4 +63,97 @@ internal infix fun <T> Array<out T>.intersects(other: Array<out T>): Boolean {
if (this[i] == other[i]) return true if (this[i] == other[i]) return true
} }
return false return false
}
internal fun String.fuzzyCompare(target: String): Double {
var step = 0
if (this == target) {
return 1.0
}
if (target.length > this.length) {
return 0.0
}
for (i in this.indices) {
if (target.length == i) {
step--
} else {
if (this[i] != target[i]) {
break
}
step++
}
}
if (step == this.length - 1) {
return 1.0
}
return step.toDouble() / this.length
}
/**
* 模糊搜索一个List中index最接近target的东西
*/
internal inline fun <T : Any> Collection<T>.fuzzySearch(
target: String,
index: (T) -> String
): T? {
if (this.isEmpty()) {
return null
}
var potential: T? = null
var rate = 0.0
this.forEach {
val thisIndex = index(it)
if (thisIndex == target) {
return it
}
with(thisIndex.fuzzyCompare(target)) {
if (this > rate) {
rate = this
potential = it
}
}
}
return potential
}
/**
* 模糊搜索一个List中index最接近target的东西
* 并且确保target是唯一的
* 如搜索index为XXXXYY list中同时存在XXXXYYY XXXXYYYY 将返回null
*/
internal inline fun <T : Any> Collection<T>.fuzzySearchOnly(
target: String,
index: (T) -> String
): T? {
if (this.isEmpty()) {
return null
}
var potential: T? = null
var rate = 0.0
var collide = 0
this.forEach {
with(index(it).fuzzyCompare(target)) {
if (this > rate) {
rate = this
potential = it
}
if (this == 1.0) {
collide++
}
if (collide > 1) {
return null//collide
}
}
}
return potential
}
internal fun Group.fuzzySearchMember(nameCardTarget: String): Member? {
return this.members.fuzzySearchOnly(nameCardTarget) {
it.nameCard
}
} }

View File

@ -6,50 +6,133 @@
* *
* https://github.com/mamoe/mirai/blob/master/LICENSE * https://github.com/mamoe/mirai/blob/master/LICENSE
*/ */
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") @file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "EXPOSED_SUPER_CLASS")
package net.mamoe.mirai.console.plugins package net.mamoe.mirai.console.plugins
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import net.mamoe.mirai.console.MiraiConsole
import net.mamoe.mirai.utils.MiraiLogger
import java.io.File
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
sealed class JarPlugin : Plugin(), CoroutineScope { interface JvmPlugin : Plugin, CoroutineScope {
internal lateinit var _description: JarPluginDescription val logger: MiraiLogger
val description: JvmPluginDescription
final override val description: PluginDescription get() = _description @JvmDefault
final override val loader: JarPluginLoader get() = JarPluginLoader fun onLoad() {
}
@JvmDefault
fun onEnable() {
}
@JvmDefault
fun onDisable() {
}
}
abstract class JavaPlugin @JvmOverloads constructor(
coroutineContext: CoroutineContext = EmptyCoroutineContext
) : JvmPlugin, JvmPluginImpl(coroutineContext) {
// TODO: 2020/5/23 scheduler, event listener(?)
}
abstract class KotlinPlugin @JvmOverloads constructor(
coroutineContext: CoroutineContext = EmptyCoroutineContext
) : JvmPlugin, JvmPluginImpl(coroutineContext) {
// that's it
} }
@Serializable @Serializable
internal class JarPluginDescription( data class JvmPluginDescription internal constructor( // serializer 可以用这个构造器
override val kind: PluginKind,
override val name: String, override val name: String,
override val author: String, override val author: String,
override val version: String, override val version: String,
override val info: String, override val info: String,
override val depends: List<String> override val loadBefore: List<String>,
) : PluginDescription 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
}
abstract class JavaPlugin : JarPlugin() @Suppress("PropertyName")
@Transient
internal var _file: File? = null
abstract class KotlinPlugin : JarPlugin() override val file: File
get() = _file ?: error("Internal error: JvmPluginDescription(name=$name)._file == null")
}
internal abstract class JvmPluginImpl(
parentCoroutineContext: CoroutineContext
) : JvmPlugin, CoroutineScope {
/**
* Initialized immediately after construction of [JvmPluginImpl] instance
*/
@Suppress("PropertyName")
internal lateinit var _description: JvmPluginDescription
override val description: JvmPluginDescription get() = _description
final override val logger: MiraiLogger by lazy { MiraiConsole.newLogger(this._description.name) }
final override val coroutineContext: CoroutineContext by lazy {
SupervisorJob(parentCoroutineContext[Job]) + CoroutineExceptionHandler { _, throwable ->
logger.error(throwable)
}
}
}
/** /**
* 内建的 Jar (JVM) 插件加载器 * 内建的 Jar (JVM) 插件加载器
*/ */
object JarPluginLoader : PluginLoader<JarPlugin> { object JarPluginLoader : AbstractFilePluginLoader<JvmPlugin, JvmPluginDescription>("jar") {
override val list: List<JarPlugin> override fun getPluginDescription(plugin: JvmPlugin): JvmPluginDescription = plugin.description
get() = TODO("Not yet implemented")
override fun load(plugin: JarPlugin) { override fun Sequence<File>.mapToDescription(): List<JvmPluginDescription> {
TODO("Not yet implemented") TODO(
"""
CHECK IS JAR FILE AND CAN BE READ
READ JAR FILE, EXTRACT PLUGIN DESCRIPTION
SET JvmPluginDescription._file
RETURN PLUGIN
""".trimIndent()
)
} }
override fun enable(plugin: JarPlugin) { @Throws(PluginLoadException::class)
TODO("Not yet implemented") 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()
} }
/* /*

View File

@ -9,45 +9,82 @@
package net.mamoe.mirai.console.plugins package net.mamoe.mirai.console.plugins
import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.serialization.Serializable
import kotlinx.coroutines.CoroutineScope import java.io.File
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob /** 插件类型 */
import net.mamoe.mirai.console.MiraiConsole enum class PluginKind {
import net.mamoe.mirai.utils.MiraiExperimentalAPI /** 表示此插件提供一个 [PluginLoader], 应在加载其他 [NORMAL] 类型插件前加载 */
import net.mamoe.mirai.utils.MiraiLogger LOADER,
import kotlin.coroutines.CoroutineContext
/** 表示此插件为一个通常的插件, 按照正常的依赖关系加载. */
NORMAL
}
/** /**
* 插件信息 * 插件描述
*/ */
interface PluginDescription { interface PluginDescription {
val kind: PluginKind
val name: String val name: String
val author: String val author: String
val version: String val version: String
val info: String val info: String
val depends: List<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 "
} }
/** /**
* 插件基类. * 基于文件的插件的描述
*
* 内建的插件类型:
* - [JarPlugin]
*/ */
abstract class Plugin : CoroutineScope { interface FilePluginDescription : PluginDescription {
abstract val description: PluginDescription val file: File
abstract val loader: PluginLoader<*> }
@OptIn(MiraiExperimentalAPI::class) /**
val logger: MiraiLogger by lazy { MiraiConsole.newLogger(description.name) } * 表示一个 mirai-console 插件.
*
override val coroutineContext: CoroutineContext * @see JvmPlugin
get() = SupervisorJob(MiraiConsole.coroutineContext[Job]) + CoroutineExceptionHandler { _, throwable -> */
logger.error(throwable) interface Plugin
}
open fun onLoaded() {}
open fun onDisabled() {}
open fun onEnabled() {}
}

View File

@ -1,29 +1,68 @@
@file:Suppress("unused")
package net.mamoe.mirai.console.plugins package net.mamoe.mirai.console.plugins
import net.mamoe.mirai.console.MiraiConsole
import java.io.File
/** /**
* 插件加载器 * 插件加载器.
* *
* 插件加载器只实现寻找插件列表, 加载插件, 启用插件, 关闭插件这四个功能.
*
* 有关插件的依赖和已加载的插件列表由 [PluginManager] 维护.
*/
interface PluginLoader<P : Plugin, D : PluginDescription> {
/**
* 扫描并返回可以被加载的插件的 [描述][PluginDescription] 列表. 此函数只会被调用一次
*/
fun listPlugins(): List<D>
/**
* 获取此插件的描述
*/
@Throws(PluginLoadException::class)
fun getPluginDescription(plugin: P): D
/**
* 加载一个插件 (实例), 但不 [启用][enable] . 返回加载成功的实例
*
* @throws PluginLoadException 在加载插件遇到意料之中的错误时抛出 (如找不到主类等).
*/
@Throws(PluginLoadException::class)
fun load(description: D): P
fun enable(plugin: P)
fun disable(plugin: P)
}
open class PluginLoadException : RuntimeException {
constructor() : super()
constructor(message: String?) : super(message)
constructor(message: String?, cause: Throwable?) : super(message, cause)
constructor(cause: Throwable?) : super(cause)
}
/**
* '/plugins' 目录中的插件的加载器. 每个加载器需绑定一个后缀.
*
* @see AbstractFilePluginLoader
* @see JarPluginLoader 内建的 Jar (JVM) 插件加载器. * @see JarPluginLoader 内建的 Jar (JVM) 插件加载器.
*/ */
interface PluginLoader<P : Plugin> { interface FilePluginLoader<P : Plugin, D : PluginDescription> : PluginLoader<P, D> {
val list: List<P> /**
* 所支持的插件文件后缀, 不含 '.'. [JarPluginLoader] "jar"
fun loadAll() = list.forEach(::load) */
fun enableAll() = list.forEach(::enable) val fileSuffix: String
fun unloadAll() = list.forEach(::unload)
fun reloadAll() = list.forEach(::reload)
val isUnloadSupported: Boolean
get() = false
fun load(plugin: P)
fun enable(plugin: P)
fun unload(plugin: P) {
error("NotImplemented")
}
fun reload(plugin: P) {
unload(plugin)
load(plugin)
}
} }
abstract class AbstractFilePluginLoader<P : Plugin, D : PluginDescription>(
override val fileSuffix: String
) : FilePluginLoader<P, D> {
private fun pluginsFilesSequence(): Sequence<File> =
PluginManager.pluginsDir.walk().filter { it.isFile && it.name.endsWith(fileSuffix, ignoreCase = true) }
protected abstract fun Sequence<File>.mapToDescription(): List<D>
final override fun listPlugins(): List<D> = pluginsFilesSequence().mapToDescription()
}

View File

@ -1,24 +1,180 @@
@file:Suppress("NOTHING_TO_INLINE")
package net.mamoe.mirai.console.plugins 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()
inline fun PluginLoader<*, *>.register() = PluginManager.registerPluginLoader(this)
inline fun PluginLoader<*, *>.unregister() = PluginManager.unregisterPluginLoader(this)
object PluginManager { object PluginManager {
private val _loaders: MutableSet<PluginLoader<*>> = mutableSetOf() val pluginsDir = File(MiraiConsole.rootDir, "plugins").apply { mkdir() }
val loaders: Set<PluginLoader<*>> get() = _loaders class LoaderNode<P : Plugin, D : PluginDescription>(
val loader: PluginLoader<P, D>,
val loadedPlugins: MutableList<P> = mutableListOf()
)
fun registerPluginLoader(loader: PluginLoader<*>) { private val _pluginLoaders: MutableSet<LoaderNode<*, *>> = mutableSetOf()
_loaders.add(loader) private val loadersLock: ReentrantLock = ReentrantLock()
private val resolvedPlugins: LinkedList<Plugin> = LinkedList()
@JvmStatic
val plugins: List<Plugin>
get() = _pluginLoaders.flatMap { it.loadedPlugins }
/**
* 内建的插件加载器列表. [MiraiConsole] 初始化
*/
@JvmStatic
val builtInLoaders: List<PluginLoader<*, *>>
get() = MiraiConsole.builtInPluginLoaders
/**
* 由插件创建的 [PluginLoader]
*/
val pluginLoaders: List<PluginLoader<*, *>> get() = _pluginLoaders.map { it.loader }
@JvmStatic
fun registerPluginLoader(loader: PluginLoader<*, *>): Boolean = loadersLock.withLock {
_pluginLoaders.add(LoaderNode(loader))
} }
fun unregisterPluginLoader(loader: PluginLoader<*>) { @JvmStatic
_loaders.remove(loader) fun unregisterPluginLoader(loader: PluginLoader<*, *>) = loadersLock.withLock {
_pluginLoaders.removeAll { it.loader == loader }
} }
fun loadPlugins() {
loaders.forEach(PluginLoader<*>::loadAll) // region LOADING
private fun <P : Plugin, D : PluginDescription> PluginLoader<P, D>.loadPluginNoEnable(description: D): P {
return this.load(description).also { resolvedPlugins.add(it) }
} }
fun enablePlugins() { private fun <P : Plugin, D : PluginDescription> PluginLoader<P, D>.loadPluginAndEnable(description: D) {
loaders.forEach(PluginLoader<*>::enableAll) @Suppress("UNCHECKED_CAST")
return this.enable(loadPluginNoEnable(description.unwrap()))
} }
/**
* STEPS:
* 1. 遍历插件列表, 使用 [builtInLoaders] 加载 [PluginKind.LOADER] 类型的插件
* 2. [启动][PluginLoader.enable] 所有 [PluginKind.LOADER] 的插件
* 3. 使用内建和所有插件提供的 [PluginLoader] 加载全部除 [PluginKind.LOADER] 外的插件列表.
* 4. 解决依赖并排序
* 5. 依次 [PluginLoader.load]
* 但不 [PluginLoader.enable]
*
* @return [builtInLoaders] 可以加载的插件. 已经完成了 [PluginLoader.load], 但没有 [PluginLoader.enable]
*/
@Suppress("UNCHECKED_CAST")
@Throws(PluginMissingDependencyException::class)
internal fun loadEnablePlugins() {
val all = loadAndEnableLoaderProviders() + pluginLoaders.listAllPlugins().flatMap { it.second }
for ((loader, desc) in all.sortByDependencies()) {
loader.loadPluginAndEnable(desc)
}
}
/**
* @return [builtInLoaders] 可以加载的插件. 已经完成了 [PluginLoader.load], 但没有 [PluginLoader.enable]
*/
@Suppress("UNCHECKED_CAST")
@Throws(PluginMissingDependencyException::class)
private fun loadAndEnableLoaderProviders(): List<PluginDescriptionWithLoader> {
val allDescriptions =
this.builtInLoaders.listAllPlugins()
.asSequence()
.onEach { (loader, descriptions) ->
loader as PluginLoader<Plugin, PluginDescription>
for (it in descriptions.filter { it.kind == PluginKind.LOADER }.sortByDependencies()) {
loader.loadPluginAndEnable(it)
}
}
.flatMap { it.second.asSequence() }
return allDescriptions.toList()
}
private fun List<PluginLoader<*, *>>.listAllPlugins(): List<Pair<PluginLoader<*, *>, List<PluginDescriptionWithLoader>>> {
return associateWith { loader -> loader.listPlugins().map { desc -> desc.wrapWith(loader) } }.toList()
}
@Throws(PluginMissingDependencyException::class)
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 List<D>.consumeLoadable(): List<D> {
val (canBeLoad, cannotBeLoad) = this.partition { it.canBeLoad() }
resolved.addAll(canBeLoad)
return cannotBeLoad
}
fun List<PluginDependency>.filterIsMissing(): List<PluginDependency> = this.filterNot { it in resolved }
tailrec fun List<D>.doSort() {
if (this.isEmpty()) return
val beforeSize = this.size
this.consumeLoadable().also { resultPlugins ->
check(resultPlugins.size < beforeSize) {
throw PluginMissingDependencyException(resultPlugins.joinToString("\n") { badPlugin ->
"Cannot load plugin ${badPlugin.name}, missing dependencies: ${badPlugin.dependencies.filterIsMissing()
.joinToString()}"
})
}
}.doSort()
}
this.doSort()
return resolved
}
// endregion
}
internal data class PluginDescriptionWithLoader(
@JvmField val loader: PluginLoader<*, PluginDescription>, // easier type
@JvmField val delegate: PluginDescription
) : PluginDescription by delegate
@Suppress("UNCHECKED_CAST")
internal fun <D : PluginDescription> PluginDescription.unwrap(): D =
if (this is PluginDescriptionWithLoader) this.delegate as D else this as D
@Suppress("UNCHECKED_CAST")
internal fun PluginDescription.wrapWith(loader: PluginLoader<*, *>): PluginDescriptionWithLoader =
PluginDescriptionWithLoader(
loader as PluginLoader<*, PluginDescription>, this
)
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)
} }

View File

@ -9,10 +9,7 @@
package net.mamoe.mirai.console.setting.internal package net.mamoe.mirai.console.setting.internal
import kotlinx.serialization.Decoder import kotlinx.serialization.*
import kotlinx.serialization.Encoder
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialDescriptor
import kotlinx.serialization.builtins.* import kotlinx.serialization.builtins.*
import net.mamoe.mirai.console.setting.* import net.mamoe.mirai.console.setting.*
@ -415,7 +412,8 @@ internal fun Setting.valueImpl(default: Array<String>): TypedStringArrayValue {
internal fun Setting.valueImpl(default: List<Int>): IntListValue { internal fun Setting.valueImpl(default: List<Int>): IntListValue {
var internalValue: List<Int> = default var internalValue: List<Int> = default
return object : IntListValue(), List<Int> by dynamicList({ internalValue }) { val delegt = dynamicList { internalValue }
return object : IntListValue(), List<Int> by delegt {
override var value: List<Int> override var value: List<Int>
get() = internalValue get() = internalValue
set(new) { set(new) {
@ -430,7 +428,8 @@ internal fun Setting.valueImpl(default: List<Int>): IntListValue {
internal fun Setting.valueImpl(default: List<Short>): ShortListValue { internal fun Setting.valueImpl(default: List<Short>): ShortListValue {
var internalValue: List<Short> = default var internalValue: List<Short> = default
return object : ShortListValue(), List<Short> by dynamicList({ internalValue }) { val delegt = dynamicList { internalValue }
return object : ShortListValue(), List<Short> by delegt {
override var value: List<Short> override var value: List<Short>
get() = internalValue get() = internalValue
set(new) { set(new) {
@ -445,7 +444,8 @@ internal fun Setting.valueImpl(default: List<Short>): ShortListValue {
internal fun Setting.valueImpl(default: List<Byte>): ByteListValue { internal fun Setting.valueImpl(default: List<Byte>): ByteListValue {
var internalValue: List<Byte> = default var internalValue: List<Byte> = default
return object : ByteListValue(), List<Byte> by dynamicList({ internalValue }) { val delegt = dynamicList { internalValue }
return object : ByteListValue(), List<Byte> by delegt {
override var value: List<Byte> override var value: List<Byte>
get() = internalValue get() = internalValue
set(new) { set(new) {
@ -460,7 +460,8 @@ internal fun Setting.valueImpl(default: List<Byte>): ByteListValue {
internal fun Setting.valueImpl(default: List<Long>): LongListValue { internal fun Setting.valueImpl(default: List<Long>): LongListValue {
var internalValue: List<Long> = default var internalValue: List<Long> = default
return object : LongListValue(), List<Long> by dynamicList({ internalValue }) { val delegt = dynamicList { internalValue }
return object : LongListValue(), List<Long> by delegt {
override var value: List<Long> override var value: List<Long>
get() = internalValue get() = internalValue
set(new) { set(new) {
@ -475,7 +476,8 @@ internal fun Setting.valueImpl(default: List<Long>): LongListValue {
internal fun Setting.valueImpl(default: List<Float>): FloatListValue { internal fun Setting.valueImpl(default: List<Float>): FloatListValue {
var internalValue: List<Float> = default var internalValue: List<Float> = default
return object : FloatListValue(), List<Float> by dynamicList({ internalValue }) { val delegt = dynamicList { internalValue }
return object : FloatListValue(), List<Float> by delegt {
override var value: List<Float> override var value: List<Float>
get() = internalValue get() = internalValue
set(new) { set(new) {
@ -490,7 +492,8 @@ internal fun Setting.valueImpl(default: List<Float>): FloatListValue {
internal fun Setting.valueImpl(default: List<Double>): DoubleListValue { internal fun Setting.valueImpl(default: List<Double>): DoubleListValue {
var internalValue: List<Double> = default var internalValue: List<Double> = default
return object : DoubleListValue(), List<Double> by dynamicList({ internalValue }) { val delegt = dynamicList { internalValue }
return object : DoubleListValue(), List<Double> by delegt {
override var value: List<Double> override var value: List<Double>
get() = internalValue get() = internalValue
set(new) { set(new) {
@ -505,7 +508,8 @@ internal fun Setting.valueImpl(default: List<Double>): DoubleListValue {
internal fun Setting.valueImpl(default: List<Boolean>): BooleanListValue { internal fun Setting.valueImpl(default: List<Boolean>): BooleanListValue {
var internalValue: List<Boolean> = default var internalValue: List<Boolean> = default
return object : BooleanListValue(), List<Boolean> by dynamicList({ internalValue }) { val delegt = dynamicList { internalValue }
return object : BooleanListValue(), List<Boolean> by delegt {
override var value: List<Boolean> override var value: List<Boolean>
get() = internalValue get() = internalValue
set(new) { set(new) {
@ -520,7 +524,8 @@ internal fun Setting.valueImpl(default: List<Boolean>): BooleanListValue {
internal fun Setting.valueImpl(default: List<Char>): CharListValue { internal fun Setting.valueImpl(default: List<Char>): CharListValue {
var internalValue: List<Char> = default var internalValue: List<Char> = default
return object : CharListValue(), List<Char> by dynamicList({ internalValue }) { val delegt = dynamicList { internalValue }
return object : CharListValue(), List<Char> by delegt {
override var value: List<Char> override var value: List<Char>
get() = internalValue get() = internalValue
set(new) { set(new) {
@ -535,7 +540,8 @@ internal fun Setting.valueImpl(default: List<Char>): CharListValue {
internal fun Setting.valueImpl(default: List<String>): StringListValue { internal fun Setting.valueImpl(default: List<String>): StringListValue {
var internalValue: List<String> = default var internalValue: List<String> = default
return object : StringListValue(), List<String> by dynamicList({ internalValue }) { val delegt = dynamicList { internalValue }
return object : StringListValue(), List<String> by delegt {
override var value: List<String> override var value: List<String>
get() = internalValue get() = internalValue
set(new) { set(new) {
@ -550,7 +556,8 @@ internal fun Setting.valueImpl(default: List<String>): StringListValue {
internal fun Setting.valueImpl(default: Set<Int>): IntSetValue { internal fun Setting.valueImpl(default: Set<Int>): IntSetValue {
var internalValue: Set<Int> = default var internalValue: Set<Int> = default
return object : IntSetValue(), Set<Int> by dynamicSet({ internalValue }) { val delegt = dynamicSet { internalValue }
return object : IntSetValue(), Set<Int> by delegt {
override var value: Set<Int> override var value: Set<Int>
get() = internalValue get() = internalValue
set(new) { set(new) {
@ -565,7 +572,8 @@ internal fun Setting.valueImpl(default: Set<Int>): IntSetValue {
internal fun Setting.valueImpl(default: Set<Short>): ShortSetValue { internal fun Setting.valueImpl(default: Set<Short>): ShortSetValue {
var internalValue: Set<Short> = default var internalValue: Set<Short> = default
return object : ShortSetValue(), Set<Short> by dynamicSet({ internalValue }) { val delegt = dynamicSet { internalValue }
return object : ShortSetValue(), Set<Short> by delegt {
override var value: Set<Short> override var value: Set<Short>
get() = internalValue get() = internalValue
set(new) { set(new) {
@ -580,7 +588,8 @@ internal fun Setting.valueImpl(default: Set<Short>): ShortSetValue {
internal fun Setting.valueImpl(default: Set<Byte>): ByteSetValue { internal fun Setting.valueImpl(default: Set<Byte>): ByteSetValue {
var internalValue: Set<Byte> = default var internalValue: Set<Byte> = default
return object : ByteSetValue(), Set<Byte> by dynamicSet({ internalValue }) { val delegt = dynamicSet { internalValue }
return object : ByteSetValue(), Set<Byte> by delegt {
override var value: Set<Byte> override var value: Set<Byte>
get() = internalValue get() = internalValue
set(new) { set(new) {
@ -595,7 +604,8 @@ internal fun Setting.valueImpl(default: Set<Byte>): ByteSetValue {
internal fun Setting.valueImpl(default: Set<Long>): LongSetValue { internal fun Setting.valueImpl(default: Set<Long>): LongSetValue {
var internalValue: Set<Long> = default var internalValue: Set<Long> = default
return object : LongSetValue(), Set<Long> by dynamicSet({ internalValue }) { val delegt = dynamicSet { internalValue }
return object : LongSetValue(), Set<Long> by delegt {
override var value: Set<Long> override var value: Set<Long>
get() = internalValue get() = internalValue
set(new) { set(new) {
@ -610,7 +620,8 @@ internal fun Setting.valueImpl(default: Set<Long>): LongSetValue {
internal fun Setting.valueImpl(default: Set<Float>): FloatSetValue { internal fun Setting.valueImpl(default: Set<Float>): FloatSetValue {
var internalValue: Set<Float> = default var internalValue: Set<Float> = default
return object : FloatSetValue(), Set<Float> by dynamicSet({ internalValue }) { val delegt = dynamicSet { internalValue }
return object : FloatSetValue(), Set<Float> by delegt {
override var value: Set<Float> override var value: Set<Float>
get() = internalValue get() = internalValue
set(new) { set(new) {
@ -625,7 +636,8 @@ internal fun Setting.valueImpl(default: Set<Float>): FloatSetValue {
internal fun Setting.valueImpl(default: Set<Double>): DoubleSetValue { internal fun Setting.valueImpl(default: Set<Double>): DoubleSetValue {
var internalValue: Set<Double> = default var internalValue: Set<Double> = default
return object : DoubleSetValue(), Set<Double> by dynamicSet({ internalValue }) { val delegt = dynamicSet { internalValue }
return object : DoubleSetValue(), Set<Double> by delegt {
override var value: Set<Double> override var value: Set<Double>
get() = internalValue get() = internalValue
set(new) { set(new) {
@ -640,7 +652,8 @@ internal fun Setting.valueImpl(default: Set<Double>): DoubleSetValue {
internal fun Setting.valueImpl(default: Set<Boolean>): BooleanSetValue { internal fun Setting.valueImpl(default: Set<Boolean>): BooleanSetValue {
var internalValue: Set<Boolean> = default var internalValue: Set<Boolean> = default
return object : BooleanSetValue(), Set<Boolean> by dynamicSet({ internalValue }) { val delegt = dynamicSet { internalValue }
return object : BooleanSetValue(), Set<Boolean> by delegt {
override var value: Set<Boolean> override var value: Set<Boolean>
get() = internalValue get() = internalValue
set(new) { set(new) {
@ -655,7 +668,8 @@ internal fun Setting.valueImpl(default: Set<Boolean>): BooleanSetValue {
internal fun Setting.valueImpl(default: Set<Char>): CharSetValue { internal fun Setting.valueImpl(default: Set<Char>): CharSetValue {
var internalValue: Set<Char> = default var internalValue: Set<Char> = default
return object : CharSetValue(), Set<Char> by dynamicSet({ internalValue }) { val delegt = dynamicSet { internalValue }
return object : CharSetValue(), Set<Char> by delegt {
override var value: Set<Char> override var value: Set<Char>
get() = internalValue get() = internalValue
set(new) { set(new) {
@ -670,7 +684,8 @@ internal fun Setting.valueImpl(default: Set<Char>): CharSetValue {
internal fun Setting.valueImpl(default: Set<String>): StringSetValue { internal fun Setting.valueImpl(default: Set<String>): StringSetValue {
var internalValue: Set<String> = default var internalValue: Set<String> = default
return object : StringSetValue(), Set<String> by dynamicSet({ internalValue }) { val delegt = dynamicSet { internalValue }
return object : StringSetValue(), Set<String> by delegt {
override var value: Set<String> override var value: Set<String>
get() = internalValue get() = internalValue
set(new) { set(new) {
@ -690,7 +705,7 @@ internal fun Setting.valueImpl(
): MutableIntListValue { ): MutableIntListValue {
var internalValue: MutableList<Int> = default var internalValue: MutableList<Int> = default
val delegt = dynamicMutableList { internalValue } val delegt = dynamicMutableList{ internalValue }
return object : MutableIntListValue(), MutableList<Int> by delegt { return object : MutableIntListValue(), MutableList<Int> by delegt {
override var value: MutableList<Int> override var value: MutableList<Int>
get() = internalValue get() = internalValue
@ -700,15 +715,15 @@ internal fun Setting.valueImpl(
onElementChanged(this) onElementChanged(this)
} }
} }
private val outerThis get() = this private val outerThis get() = this
override val serializer: KSerializer<MutableList<Int>> = object : KSerializer<MutableList<Int>> { override val serializer: KSerializer<MutableList<Int>> = object : KSerializer<MutableList<Int>> {
private val delegate = ListSerializer(Int.serializer()) private val delegate = ListSerializer(Int.serializer())
override val descriptor: SerialDescriptor = delegate.descriptor override val descriptor: SerialDescriptor = delegate.descriptor
override fun deserialize(decoder: Decoder): MutableList<Int> { override fun deserialize(decoder: Decoder): MutableList<Int> {
return delegate.deserialize(decoder).toMutableList().observable { return delegate.deserialize(decoder).toMutableList().observable {
onElementChanged(outerThis) onElementChanged(outerThis)
} }
} }
@ -726,7 +741,7 @@ internal fun Setting.valueImpl(
): MutableShortListValue { ): MutableShortListValue {
var internalValue: MutableList<Short> = default var internalValue: MutableList<Short> = default
val delegt = dynamicMutableList { internalValue } val delegt = dynamicMutableList{ internalValue }
return object : MutableShortListValue(), MutableList<Short> by delegt { return object : MutableShortListValue(), MutableList<Short> by delegt {
override var value: MutableList<Short> override var value: MutableList<Short>
get() = internalValue get() = internalValue
@ -736,15 +751,15 @@ internal fun Setting.valueImpl(
onElementChanged(this) onElementChanged(this)
} }
} }
private val outerThis get() = this private val outerThis get() = this
override val serializer: KSerializer<MutableList<Short>> = object : KSerializer<MutableList<Short>> { override val serializer: KSerializer<MutableList<Short>> = object : KSerializer<MutableList<Short>> {
private val delegate = ListSerializer(Short.serializer()) private val delegate = ListSerializer(Short.serializer())
override val descriptor: SerialDescriptor = delegate.descriptor override val descriptor: SerialDescriptor = delegate.descriptor
override fun deserialize(decoder: Decoder): MutableList<Short> { override fun deserialize(decoder: Decoder): MutableList<Short> {
return delegate.deserialize(decoder).toMutableList().observable { return delegate.deserialize(decoder).toMutableList().observable {
onElementChanged(outerThis) onElementChanged(outerThis)
} }
} }
@ -762,7 +777,7 @@ internal fun Setting.valueImpl(
): MutableByteListValue { ): MutableByteListValue {
var internalValue: MutableList<Byte> = default var internalValue: MutableList<Byte> = default
val delegt = dynamicMutableList { internalValue } val delegt = dynamicMutableList{ internalValue }
return object : MutableByteListValue(), MutableList<Byte> by delegt { return object : MutableByteListValue(), MutableList<Byte> by delegt {
override var value: MutableList<Byte> override var value: MutableList<Byte>
get() = internalValue get() = internalValue
@ -772,15 +787,15 @@ internal fun Setting.valueImpl(
onElementChanged(this) onElementChanged(this)
} }
} }
private val outerThis get() = this private val outerThis get() = this
override val serializer: KSerializer<MutableList<Byte>> = object : KSerializer<MutableList<Byte>> { override val serializer: KSerializer<MutableList<Byte>> = object : KSerializer<MutableList<Byte>> {
private val delegate = ListSerializer(Byte.serializer()) private val delegate = ListSerializer(Byte.serializer())
override val descriptor: SerialDescriptor = delegate.descriptor override val descriptor: SerialDescriptor = delegate.descriptor
override fun deserialize(decoder: Decoder): MutableList<Byte> { override fun deserialize(decoder: Decoder): MutableList<Byte> {
return delegate.deserialize(decoder).toMutableList().observable { return delegate.deserialize(decoder).toMutableList().observable {
onElementChanged(outerThis) onElementChanged(outerThis)
} }
} }
@ -798,7 +813,7 @@ internal fun Setting.valueImpl(
): MutableLongListValue { ): MutableLongListValue {
var internalValue: MutableList<Long> = default var internalValue: MutableList<Long> = default
val delegt = dynamicMutableList { internalValue } val delegt = dynamicMutableList{ internalValue }
return object : MutableLongListValue(), MutableList<Long> by delegt { return object : MutableLongListValue(), MutableList<Long> by delegt {
override var value: MutableList<Long> override var value: MutableList<Long>
get() = internalValue get() = internalValue
@ -808,15 +823,15 @@ internal fun Setting.valueImpl(
onElementChanged(this) onElementChanged(this)
} }
} }
private val outerThis get() = this private val outerThis get() = this
override val serializer: KSerializer<MutableList<Long>> = object : KSerializer<MutableList<Long>> { override val serializer: KSerializer<MutableList<Long>> = object : KSerializer<MutableList<Long>> {
private val delegate = ListSerializer(Long.serializer()) private val delegate = ListSerializer(Long.serializer())
override val descriptor: SerialDescriptor = delegate.descriptor override val descriptor: SerialDescriptor = delegate.descriptor
override fun deserialize(decoder: Decoder): MutableList<Long> { override fun deserialize(decoder: Decoder): MutableList<Long> {
return delegate.deserialize(decoder).toMutableList().observable { return delegate.deserialize(decoder).toMutableList().observable {
onElementChanged(outerThis) onElementChanged(outerThis)
} }
} }
@ -834,7 +849,7 @@ internal fun Setting.valueImpl(
): MutableFloatListValue { ): MutableFloatListValue {
var internalValue: MutableList<Float> = default var internalValue: MutableList<Float> = default
val delegt = dynamicMutableList { internalValue } val delegt = dynamicMutableList{ internalValue }
return object : MutableFloatListValue(), MutableList<Float> by delegt { return object : MutableFloatListValue(), MutableList<Float> by delegt {
override var value: MutableList<Float> override var value: MutableList<Float>
get() = internalValue get() = internalValue
@ -844,15 +859,15 @@ internal fun Setting.valueImpl(
onElementChanged(this) onElementChanged(this)
} }
} }
private val outerThis get() = this private val outerThis get() = this
override val serializer: KSerializer<MutableList<Float>> = object : KSerializer<MutableList<Float>> { override val serializer: KSerializer<MutableList<Float>> = object : KSerializer<MutableList<Float>> {
private val delegate = ListSerializer(Float.serializer()) private val delegate = ListSerializer(Float.serializer())
override val descriptor: SerialDescriptor = delegate.descriptor override val descriptor: SerialDescriptor = delegate.descriptor
override fun deserialize(decoder: Decoder): MutableList<Float> { override fun deserialize(decoder: Decoder): MutableList<Float> {
return delegate.deserialize(decoder).toMutableList().observable { return delegate.deserialize(decoder).toMutableList().observable {
onElementChanged(outerThis) onElementChanged(outerThis)
} }
} }
@ -870,7 +885,7 @@ internal fun Setting.valueImpl(
): MutableDoubleListValue { ): MutableDoubleListValue {
var internalValue: MutableList<Double> = default var internalValue: MutableList<Double> = default
val delegt = dynamicMutableList { internalValue } val delegt = dynamicMutableList{ internalValue }
return object : MutableDoubleListValue(), MutableList<Double> by delegt { return object : MutableDoubleListValue(), MutableList<Double> by delegt {
override var value: MutableList<Double> override var value: MutableList<Double>
get() = internalValue get() = internalValue
@ -880,15 +895,15 @@ internal fun Setting.valueImpl(
onElementChanged(this) onElementChanged(this)
} }
} }
private val outerThis get() = this private val outerThis get() = this
override val serializer: KSerializer<MutableList<Double>> = object : KSerializer<MutableList<Double>> { override val serializer: KSerializer<MutableList<Double>> = object : KSerializer<MutableList<Double>> {
private val delegate = ListSerializer(Double.serializer()) private val delegate = ListSerializer(Double.serializer())
override val descriptor: SerialDescriptor = delegate.descriptor override val descriptor: SerialDescriptor = delegate.descriptor
override fun deserialize(decoder: Decoder): MutableList<Double> { override fun deserialize(decoder: Decoder): MutableList<Double> {
return delegate.deserialize(decoder).toMutableList().observable { return delegate.deserialize(decoder).toMutableList().observable {
onElementChanged(outerThis) onElementChanged(outerThis)
} }
} }
@ -906,7 +921,7 @@ internal fun Setting.valueImpl(
): MutableBooleanListValue { ): MutableBooleanListValue {
var internalValue: MutableList<Boolean> = default var internalValue: MutableList<Boolean> = default
val delegt = dynamicMutableList { internalValue } val delegt = dynamicMutableList{ internalValue }
return object : MutableBooleanListValue(), MutableList<Boolean> by delegt { return object : MutableBooleanListValue(), MutableList<Boolean> by delegt {
override var value: MutableList<Boolean> override var value: MutableList<Boolean>
get() = internalValue get() = internalValue
@ -916,15 +931,15 @@ internal fun Setting.valueImpl(
onElementChanged(this) onElementChanged(this)
} }
} }
private val outerThis get() = this private val outerThis get() = this
override val serializer: KSerializer<MutableList<Boolean>> = object : KSerializer<MutableList<Boolean>> { override val serializer: KSerializer<MutableList<Boolean>> = object : KSerializer<MutableList<Boolean>> {
private val delegate = ListSerializer(Boolean.serializer()) private val delegate = ListSerializer(Boolean.serializer())
override val descriptor: SerialDescriptor = delegate.descriptor override val descriptor: SerialDescriptor = delegate.descriptor
override fun deserialize(decoder: Decoder): MutableList<Boolean> { override fun deserialize(decoder: Decoder): MutableList<Boolean> {
return delegate.deserialize(decoder).toMutableList().observable { return delegate.deserialize(decoder).toMutableList().observable {
onElementChanged(outerThis) onElementChanged(outerThis)
} }
} }
@ -942,7 +957,7 @@ internal fun Setting.valueImpl(
): MutableCharListValue { ): MutableCharListValue {
var internalValue: MutableList<Char> = default var internalValue: MutableList<Char> = default
val delegt = dynamicMutableList { internalValue } val delegt = dynamicMutableList{ internalValue }
return object : MutableCharListValue(), MutableList<Char> by delegt { return object : MutableCharListValue(), MutableList<Char> by delegt {
override var value: MutableList<Char> override var value: MutableList<Char>
get() = internalValue get() = internalValue
@ -952,15 +967,15 @@ internal fun Setting.valueImpl(
onElementChanged(this) onElementChanged(this)
} }
} }
private val outerThis get() = this private val outerThis get() = this
override val serializer: KSerializer<MutableList<Char>> = object : KSerializer<MutableList<Char>> { override val serializer: KSerializer<MutableList<Char>> = object : KSerializer<MutableList<Char>> {
private val delegate = ListSerializer(Char.serializer()) private val delegate = ListSerializer(Char.serializer())
override val descriptor: SerialDescriptor = delegate.descriptor override val descriptor: SerialDescriptor = delegate.descriptor
override fun deserialize(decoder: Decoder): MutableList<Char> { override fun deserialize(decoder: Decoder): MutableList<Char> {
return delegate.deserialize(decoder).toMutableList().observable { return delegate.deserialize(decoder).toMutableList().observable {
onElementChanged(outerThis) onElementChanged(outerThis)
} }
} }
@ -978,7 +993,7 @@ internal fun Setting.valueImpl(
): MutableStringListValue { ): MutableStringListValue {
var internalValue: MutableList<String> = default var internalValue: MutableList<String> = default
val delegt = dynamicMutableList { internalValue } val delegt = dynamicMutableList{ internalValue }
return object : MutableStringListValue(), MutableList<String> by delegt { return object : MutableStringListValue(), MutableList<String> by delegt {
override var value: MutableList<String> override var value: MutableList<String>
get() = internalValue get() = internalValue
@ -988,15 +1003,15 @@ internal fun Setting.valueImpl(
onElementChanged(this) onElementChanged(this)
} }
} }
private val outerThis get() = this private val outerThis get() = this
override val serializer: KSerializer<MutableList<String>> = object : KSerializer<MutableList<String>> { override val serializer: KSerializer<MutableList<String>> = object : KSerializer<MutableList<String>> {
private val delegate = ListSerializer(String.serializer()) private val delegate = ListSerializer(String.serializer())
override val descriptor: SerialDescriptor = delegate.descriptor override val descriptor: SerialDescriptor = delegate.descriptor
override fun deserialize(decoder: Decoder): MutableList<String> { override fun deserialize(decoder: Decoder): MutableList<String> {
return delegate.deserialize(decoder).toMutableList().observable { return delegate.deserialize(decoder).toMutableList().observable {
onElementChanged(outerThis) onElementChanged(outerThis)
} }
} }
@ -1014,7 +1029,7 @@ internal fun Setting.valueImpl(
): MutableIntSetValue { ): MutableIntSetValue {
var internalValue: MutableSet<Int> = default var internalValue: MutableSet<Int> = default
val delegt = dynamicMutableSet { internalValue } val delegt = dynamicMutableSet{ internalValue }
return object : MutableIntSetValue(), MutableSet<Int> by delegt { return object : MutableIntSetValue(), MutableSet<Int> by delegt {
override var value: MutableSet<Int> override var value: MutableSet<Int>
get() = internalValue get() = internalValue
@ -1024,15 +1039,15 @@ internal fun Setting.valueImpl(
onElementChanged(this) onElementChanged(this)
} }
} }
private val outerThis get() = this private val outerThis get() = this
override val serializer: KSerializer<MutableSet<Int>> = object : KSerializer<MutableSet<Int>> { override val serializer: KSerializer<MutableSet<Int>> = object : KSerializer<MutableSet<Int>> {
private val delegate = SetSerializer(Int.serializer()) private val delegate = SetSerializer(Int.serializer())
override val descriptor: SerialDescriptor = delegate.descriptor override val descriptor: SerialDescriptor = delegate.descriptor
override fun deserialize(decoder: Decoder): MutableSet<Int> { override fun deserialize(decoder: Decoder): MutableSet<Int> {
return delegate.deserialize(decoder).toMutableSet().observable { return delegate.deserialize(decoder).toMutableSet().observable {
onElementChanged(outerThis) onElementChanged(outerThis)
} }
} }
@ -1050,7 +1065,7 @@ internal fun Setting.valueImpl(
): MutableShortSetValue { ): MutableShortSetValue {
var internalValue: MutableSet<Short> = default var internalValue: MutableSet<Short> = default
val delegt = dynamicMutableSet { internalValue } val delegt = dynamicMutableSet{ internalValue }
return object : MutableShortSetValue(), MutableSet<Short> by delegt { return object : MutableShortSetValue(), MutableSet<Short> by delegt {
override var value: MutableSet<Short> override var value: MutableSet<Short>
get() = internalValue get() = internalValue
@ -1060,15 +1075,15 @@ internal fun Setting.valueImpl(
onElementChanged(this) onElementChanged(this)
} }
} }
private val outerThis get() = this private val outerThis get() = this
override val serializer: KSerializer<MutableSet<Short>> = object : KSerializer<MutableSet<Short>> { override val serializer: KSerializer<MutableSet<Short>> = object : KSerializer<MutableSet<Short>> {
private val delegate = SetSerializer(Short.serializer()) private val delegate = SetSerializer(Short.serializer())
override val descriptor: SerialDescriptor = delegate.descriptor override val descriptor: SerialDescriptor = delegate.descriptor
override fun deserialize(decoder: Decoder): MutableSet<Short> { override fun deserialize(decoder: Decoder): MutableSet<Short> {
return delegate.deserialize(decoder).toMutableSet().observable { return delegate.deserialize(decoder).toMutableSet().observable {
onElementChanged(outerThis) onElementChanged(outerThis)
} }
} }
@ -1086,7 +1101,7 @@ internal fun Setting.valueImpl(
): MutableByteSetValue { ): MutableByteSetValue {
var internalValue: MutableSet<Byte> = default var internalValue: MutableSet<Byte> = default
val delegt = dynamicMutableSet { internalValue } val delegt = dynamicMutableSet{ internalValue }
return object : MutableByteSetValue(), MutableSet<Byte> by delegt { return object : MutableByteSetValue(), MutableSet<Byte> by delegt {
override var value: MutableSet<Byte> override var value: MutableSet<Byte>
get() = internalValue get() = internalValue
@ -1096,15 +1111,15 @@ internal fun Setting.valueImpl(
onElementChanged(this) onElementChanged(this)
} }
} }
private val outerThis get() = this private val outerThis get() = this
override val serializer: KSerializer<MutableSet<Byte>> = object : KSerializer<MutableSet<Byte>> { override val serializer: KSerializer<MutableSet<Byte>> = object : KSerializer<MutableSet<Byte>> {
private val delegate = SetSerializer(Byte.serializer()) private val delegate = SetSerializer(Byte.serializer())
override val descriptor: SerialDescriptor = delegate.descriptor override val descriptor: SerialDescriptor = delegate.descriptor
override fun deserialize(decoder: Decoder): MutableSet<Byte> { override fun deserialize(decoder: Decoder): MutableSet<Byte> {
return delegate.deserialize(decoder).toMutableSet().observable { return delegate.deserialize(decoder).toMutableSet().observable {
onElementChanged(outerThis) onElementChanged(outerThis)
} }
} }
@ -1122,7 +1137,7 @@ internal fun Setting.valueImpl(
): MutableLongSetValue { ): MutableLongSetValue {
var internalValue: MutableSet<Long> = default var internalValue: MutableSet<Long> = default
val delegt = dynamicMutableSet { internalValue } val delegt = dynamicMutableSet{ internalValue }
return object : MutableLongSetValue(), MutableSet<Long> by delegt { return object : MutableLongSetValue(), MutableSet<Long> by delegt {
override var value: MutableSet<Long> override var value: MutableSet<Long>
get() = internalValue get() = internalValue
@ -1132,15 +1147,15 @@ internal fun Setting.valueImpl(
onElementChanged(this) onElementChanged(this)
} }
} }
private val outerThis get() = this private val outerThis get() = this
override val serializer: KSerializer<MutableSet<Long>> = object : KSerializer<MutableSet<Long>> { override val serializer: KSerializer<MutableSet<Long>> = object : KSerializer<MutableSet<Long>> {
private val delegate = SetSerializer(Long.serializer()) private val delegate = SetSerializer(Long.serializer())
override val descriptor: SerialDescriptor = delegate.descriptor override val descriptor: SerialDescriptor = delegate.descriptor
override fun deserialize(decoder: Decoder): MutableSet<Long> { override fun deserialize(decoder: Decoder): MutableSet<Long> {
return delegate.deserialize(decoder).toMutableSet().observable { return delegate.deserialize(decoder).toMutableSet().observable {
onElementChanged(outerThis) onElementChanged(outerThis)
} }
} }
@ -1158,7 +1173,7 @@ internal fun Setting.valueImpl(
): MutableFloatSetValue { ): MutableFloatSetValue {
var internalValue: MutableSet<Float> = default var internalValue: MutableSet<Float> = default
val delegt = dynamicMutableSet { internalValue } val delegt = dynamicMutableSet{ internalValue }
return object : MutableFloatSetValue(), MutableSet<Float> by delegt { return object : MutableFloatSetValue(), MutableSet<Float> by delegt {
override var value: MutableSet<Float> override var value: MutableSet<Float>
get() = internalValue get() = internalValue
@ -1168,15 +1183,15 @@ internal fun Setting.valueImpl(
onElementChanged(this) onElementChanged(this)
} }
} }
private val outerThis get() = this private val outerThis get() = this
override val serializer: KSerializer<MutableSet<Float>> = object : KSerializer<MutableSet<Float>> { override val serializer: KSerializer<MutableSet<Float>> = object : KSerializer<MutableSet<Float>> {
private val delegate = SetSerializer(Float.serializer()) private val delegate = SetSerializer(Float.serializer())
override val descriptor: SerialDescriptor = delegate.descriptor override val descriptor: SerialDescriptor = delegate.descriptor
override fun deserialize(decoder: Decoder): MutableSet<Float> { override fun deserialize(decoder: Decoder): MutableSet<Float> {
return delegate.deserialize(decoder).toMutableSet().observable { return delegate.deserialize(decoder).toMutableSet().observable {
onElementChanged(outerThis) onElementChanged(outerThis)
} }
} }
@ -1194,7 +1209,7 @@ internal fun Setting.valueImpl(
): MutableDoubleSetValue { ): MutableDoubleSetValue {
var internalValue: MutableSet<Double> = default var internalValue: MutableSet<Double> = default
val delegt = dynamicMutableSet { internalValue } val delegt = dynamicMutableSet{ internalValue }
return object : MutableDoubleSetValue(), MutableSet<Double> by delegt { return object : MutableDoubleSetValue(), MutableSet<Double> by delegt {
override var value: MutableSet<Double> override var value: MutableSet<Double>
get() = internalValue get() = internalValue
@ -1204,15 +1219,15 @@ internal fun Setting.valueImpl(
onElementChanged(this) onElementChanged(this)
} }
} }
private val outerThis get() = this private val outerThis get() = this
override val serializer: KSerializer<MutableSet<Double>> = object : KSerializer<MutableSet<Double>> { override val serializer: KSerializer<MutableSet<Double>> = object : KSerializer<MutableSet<Double>> {
private val delegate = SetSerializer(Double.serializer()) private val delegate = SetSerializer(Double.serializer())
override val descriptor: SerialDescriptor = delegate.descriptor override val descriptor: SerialDescriptor = delegate.descriptor
override fun deserialize(decoder: Decoder): MutableSet<Double> { override fun deserialize(decoder: Decoder): MutableSet<Double> {
return delegate.deserialize(decoder).toMutableSet().observable { return delegate.deserialize(decoder).toMutableSet().observable {
onElementChanged(outerThis) onElementChanged(outerThis)
} }
} }
@ -1230,7 +1245,7 @@ internal fun Setting.valueImpl(
): MutableBooleanSetValue { ): MutableBooleanSetValue {
var internalValue: MutableSet<Boolean> = default var internalValue: MutableSet<Boolean> = default
val delegt = dynamicMutableSet { internalValue } val delegt = dynamicMutableSet{ internalValue }
return object : MutableBooleanSetValue(), MutableSet<Boolean> by delegt { return object : MutableBooleanSetValue(), MutableSet<Boolean> by delegt {
override var value: MutableSet<Boolean> override var value: MutableSet<Boolean>
get() = internalValue get() = internalValue
@ -1240,15 +1255,15 @@ internal fun Setting.valueImpl(
onElementChanged(this) onElementChanged(this)
} }
} }
private val outerThis get() = this private val outerThis get() = this
override val serializer: KSerializer<MutableSet<Boolean>> = object : KSerializer<MutableSet<Boolean>> { override val serializer: KSerializer<MutableSet<Boolean>> = object : KSerializer<MutableSet<Boolean>> {
private val delegate = SetSerializer(Boolean.serializer()) private val delegate = SetSerializer(Boolean.serializer())
override val descriptor: SerialDescriptor = delegate.descriptor override val descriptor: SerialDescriptor = delegate.descriptor
override fun deserialize(decoder: Decoder): MutableSet<Boolean> { override fun deserialize(decoder: Decoder): MutableSet<Boolean> {
return delegate.deserialize(decoder).toMutableSet().observable { return delegate.deserialize(decoder).toMutableSet().observable {
onElementChanged(outerThis) onElementChanged(outerThis)
} }
} }
@ -1266,7 +1281,7 @@ internal fun Setting.valueImpl(
): MutableCharSetValue { ): MutableCharSetValue {
var internalValue: MutableSet<Char> = default var internalValue: MutableSet<Char> = default
val delegt = dynamicMutableSet { internalValue } val delegt = dynamicMutableSet{ internalValue }
return object : MutableCharSetValue(), MutableSet<Char> by delegt { return object : MutableCharSetValue(), MutableSet<Char> by delegt {
override var value: MutableSet<Char> override var value: MutableSet<Char>
get() = internalValue get() = internalValue
@ -1276,15 +1291,15 @@ internal fun Setting.valueImpl(
onElementChanged(this) onElementChanged(this)
} }
} }
private val outerThis get() = this private val outerThis get() = this
override val serializer: KSerializer<MutableSet<Char>> = object : KSerializer<MutableSet<Char>> { override val serializer: KSerializer<MutableSet<Char>> = object : KSerializer<MutableSet<Char>> {
private val delegate = SetSerializer(Char.serializer()) private val delegate = SetSerializer(Char.serializer())
override val descriptor: SerialDescriptor = delegate.descriptor override val descriptor: SerialDescriptor = delegate.descriptor
override fun deserialize(decoder: Decoder): MutableSet<Char> { override fun deserialize(decoder: Decoder): MutableSet<Char> {
return delegate.deserialize(decoder).toMutableSet().observable { return delegate.deserialize(decoder).toMutableSet().observable {
onElementChanged(outerThis) onElementChanged(outerThis)
} }
} }
@ -1302,7 +1317,7 @@ internal fun Setting.valueImpl(
): MutableStringSetValue { ): MutableStringSetValue {
var internalValue: MutableSet<String> = default var internalValue: MutableSet<String> = default
val delegt = dynamicMutableSet { internalValue } val delegt = dynamicMutableSet{ internalValue }
return object : MutableStringSetValue(), MutableSet<String> by delegt { return object : MutableStringSetValue(), MutableSet<String> by delegt {
override var value: MutableSet<String> override var value: MutableSet<String>
get() = internalValue get() = internalValue
@ -1312,15 +1327,15 @@ internal fun Setting.valueImpl(
onElementChanged(this) onElementChanged(this)
} }
} }
private val outerThis get() = this private val outerThis get() = this
override val serializer: KSerializer<MutableSet<String>> = object : KSerializer<MutableSet<String>> { override val serializer: KSerializer<MutableSet<String>> = object : KSerializer<MutableSet<String>> {
private val delegate = SetSerializer(String.serializer()) private val delegate = SetSerializer(String.serializer())
override val descriptor: SerialDescriptor = delegate.descriptor override val descriptor: SerialDescriptor = delegate.descriptor
override fun deserialize(decoder: Decoder): MutableSet<String> { override fun deserialize(decoder: Decoder): MutableSet<String> {
return delegate.deserialize(decoder).toMutableSet().observable { return delegate.deserialize(decoder).toMutableSet().observable {
onElementChanged(outerThis) onElementChanged(outerThis)
} }
} }
@ -1344,7 +1359,7 @@ internal fun <T : Setting> Setting.valueImpl(default: T): Value<T> {
onElementChanged(this) onElementChanged(this)
} }
} }
override val serializer = object : KSerializer<T> { override val serializer = object : KSerializer<T>{
override val descriptor: SerialDescriptor override val descriptor: SerialDescriptor
get() = internalValue.updaterSerializer.descriptor get() = internalValue.updaterSerializer.descriptor

View File

@ -22,13 +22,6 @@ import java.io.File
val User.isManager: Boolean val User.isManager: Boolean
get() = this.bot.managers.contains(this.id) get() = this.bot.managers.contains(this.id)
@JvmName("addManager")
@JvmSynthetic
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
fun Bot.addManagerDeprecated(long: Long) {
addManager(long)
}
internal fun Bot.addManager(long: Long): Boolean { internal fun Bot.addManager(long: Long): Boolean {
TODO() TODO()
return true return true

View File

@ -1,161 +0,0 @@
package net.mamoe.mirai.console.utils
import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.Member
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
/**
* 执行N次 builder
* 成功一次就会结束
* 否则就会throw
*/
@OptIn(ExperimentalContracts::class)
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "RESULT_CLASS_IN_RETURN_TYPE")
@kotlin.internal.InlineOnly
inline fun <R> retryCatching(n: Int, block: () -> R): Result<R> {
contract {
callsInPlace(block, InvocationKind.AT_LEAST_ONCE)
}
require(n >= 0) { "param n for retryCatching must not be negative" }
var exception: Throwable? = null
repeat(n){
try {
return Result.success(block())
} catch (e: Throwable) {
exception?.addSuppressedMirai(e)
exception = e
}
}
return Result.failure(exception!!)
}
@OptIn(ExperimentalContracts::class)
inline fun <T> tryNTimes(n: Int = 2, block: () -> T):T {
contract {
callsInPlace(block, InvocationKind.AT_LEAST_ONCE)
}
require(n >= 0) { "param n for tryNTimes must not be negative" }
var last:Exception? = null
repeat(n){
try {
return block.invoke()
}catch (e:Exception){
last = e
}
}
//给我编译
throw last!!
}
@PublishedApi
internal fun Throwable.addSuppressedMirai(e: Throwable) {
if (e === this) {
return
}
kotlin.runCatching {
this.addSuppressed(e)
}
}
/**
* 两个字符串的近似值
* 要求前面完全一致
*
* XXXXXYYYYY.fuzzyCompare(XXXXXYYY) = 0.8
* XXXXXYYYYY.fuzzyCompare(XXXXXYYYZZ) = 0.8
*/
internal fun String.fuzzyCompare(target: String): Double {
var step = 0
if (this == target) {
return 1.0
}
if (target.length > this.length) {
return 0.0
}
for (i in this.indices) {
if (target.length == i) {
step--
}else {
if (this[i] != target[i]) {
break
}
step++
}
}
if(step == this.length-1){
return 1.0
}
return step.toDouble()/this.length
}
/**
* 模糊搜索一个List中index最接近target的东西
*/
internal inline fun <T : Any> Collection<T>.fuzzySearch(
target: String,
index: (T) -> String
): T? {
if (this.isEmpty()) {
return null
}
var potential: T? = null
var rate = 0.0
this.forEach {
val thisIndex = index(it)
if(thisIndex == target){
return it
}
with(thisIndex.fuzzyCompare(target)) {
if (this > rate) {
rate = this
potential = it
}
}
}
return potential
}
/**
* 模糊搜索一个List中index最接近target的东西
* 并且确保target是唯一的
* 如搜索index为XXXXYY list中同时存在XXXXYYY XXXXYYYY 将返回null
*/
internal inline fun <T : Any> Collection<T>.fuzzySearchOnly(
target: String,
index: (T) -> String
): T? {
if (this.isEmpty()) {
return null
}
var potential: T? = null
var rate = 0.0
var collide = 0
this.forEach {
with(index(it).fuzzyCompare(target)) {
if (this > rate) {
rate = this
potential = it
}
if(this == 1.0){
collide++
}
if(collide > 1){
return null//collide
}
}
}
return potential
}
internal fun Group.fuzzySearchMember(nameCardTarget: String): Member? {
return this.members.fuzzySearchOnly(nameCardTarget) {
it.nameCard
}
}

View File

@ -1,50 +0,0 @@
package net.mamoe.mirai.console.utils
import net.mamoe.mirai.utils.MiraiExperimentalAPI
/**
* A Value
* the input type of this Value is T while the output is V
*/
@MiraiExperimentalAPI
abstract class Value<T, V> {
operator fun invoke(): V = get()
abstract fun get(): V
abstract fun set(t: T)
}
/**
* This value can be used as a Config Value
*/
@MiraiExperimentalAPI
interface ConfigValue
/**
* A simple value
* the input type is same as output value
*/
@MiraiExperimentalAPI
open class SimpleValue<T>(
var value: T
) : Value<T, T>() {
override fun get() = this.value
override fun set(t: T) {
this.value = t
}
}
@MiraiExperimentalAPI
open class NullableSimpleValue<T>(
value: T? = null
) : SimpleValue<T?>(
value
) {
fun isNull() = value == null
}

View File

@ -0,0 +1,38 @@
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "RESULT_CLASS_IN_RETURN_TYPE")
package net.mamoe.mirai.console.utils
import org.jetbrains.annotations.Range
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
/**
* 执行 [n] [block], 在第一次成功时返回执行结果, 在捕获到异常时返回异常.
*/
@kotlin.internal.InlineOnly
inline fun <R> retryCatching(n: @Range(from = 1, to = Long.MAX_VALUE) Int, block: () -> R): Result<R> {
contract {
callsInPlace(block, InvocationKind.AT_LEAST_ONCE)
}
require(n >= 0) { "param n for retryCatching must not be negative" }
var exception: Throwable? = null
repeat(n) {
try {
return Result.success(block())
} catch (e: Throwable) {
exception?.addSuppressedMirai(e)
exception = e
}
}
return Result.failure(exception!!)
}
@PublishedApi
internal fun Throwable.addSuppressedMirai(e: Throwable) {
if (e === this) {
return
}
kotlin.runCatching {
this.addSuppressed(e)
}
}

View File

@ -1,5 +1,5 @@
import net.mamoe.mirai.console.utils.fuzzySearch import net.mamoe.mirai.console.command.fuzzySearch
import net.mamoe.mirai.console.utils.fuzzySearchOnly import net.mamoe.mirai.console.command.fuzzySearchOnly
class Him188(val name:String){ class Him188(val name:String){
override fun toString(): String { override fun toString(): String {