mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-25 15:40:28 +08:00
Update Plugin load mechanism for compatibility with Android
This commit is contained in:
parent
2ea86b377a
commit
e8bb0f0bb4
@ -15,18 +15,20 @@ import kotlinx.coroutines.ensureActive
|
||||
import net.mamoe.mirai.console.MiraiConsole
|
||||
import net.mamoe.mirai.console.data.PluginDataStorage
|
||||
import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge
|
||||
import net.mamoe.mirai.console.internal.data.cast
|
||||
import net.mamoe.mirai.console.internal.data.createInstanceOrNull
|
||||
import net.mamoe.mirai.console.plugin.AbstractFilePluginLoader
|
||||
import net.mamoe.mirai.console.plugin.PluginLoadException
|
||||
import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader
|
||||
import net.mamoe.mirai.console.plugin.jvm.JvmPlugin
|
||||
import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription
|
||||
import net.mamoe.mirai.console.util.childScopeContext
|
||||
import net.mamoe.mirai.console.util.childScope
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
import net.mamoe.mirai.utils.error
|
||||
import net.mamoe.mirai.utils.info
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import java.net.URLClassLoader
|
||||
import java.util.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.streams.asSequence
|
||||
|
||||
internal object JarPluginLoaderImpl :
|
||||
AbstractFilePluginLoader<JvmPlugin, JvmPluginDescription>(".jar"),
|
||||
@ -56,33 +58,35 @@ internal object JarPluginLoaderImpl :
|
||||
override fun Sequence<File>.extractPlugins(): List<JvmPlugin> {
|
||||
ensureActive()
|
||||
|
||||
fun <T> ServiceLoader<T>.loadAll(file: File?): Sequence<T> {
|
||||
return stream().asSequence().mapNotNull {
|
||||
fun Sequence<ClassLoader>.loadAll(): Sequence<JvmPlugin> {
|
||||
return mapNotNull { pluginClassLoader ->
|
||||
pluginClassLoader.getResourceAsStream(JvmPlugin::class.qualifiedName!!)?.use(InputStream::readBytes)
|
||||
?.let(::String)?.let { it to pluginClassLoader }
|
||||
}.mapNotNull { (pluginQualifiedName, classLoader) ->
|
||||
kotlin.runCatching {
|
||||
it.type().kotlin.objectInstance ?: it.get()
|
||||
}.onFailure {
|
||||
logger.error("Cannot load plugin ${file ?: "<no-file>"}", it)
|
||||
}.getOrNull()
|
||||
val clazz =
|
||||
Class.forName(pluginQualifiedName, true, classLoader).cast<Class<out JvmPlugin>>()
|
||||
clazz.kotlin.objectInstance
|
||||
?: clazz.kotlin.createInstanceOrNull() ?: clazz.newInstance()
|
||||
}.getOrElse {
|
||||
logger.error(
|
||||
{ "Could not load PluginLoader ${pluginQualifiedName}." },
|
||||
PluginLoadException("Could not load PluginLoader ${pluginQualifiedName}.", it)
|
||||
)
|
||||
return@mapNotNull null
|
||||
}.also {
|
||||
logger.info { "Successfully loaded PluginLoader ${pluginQualifiedName}." }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val inMemoryPlugins =
|
||||
ServiceLoader.load(
|
||||
JvmPlugin::class.java,
|
||||
generateSequence(MiraiConsole::class.java.classLoader) { it.parent }.last()
|
||||
).loadAll(null)
|
||||
|
||||
val filePlugins = this.associateWith {
|
||||
val filePlugins = this.map {
|
||||
URLClassLoader(arrayOf(it.toURI().toURL()), MiraiConsole::class.java.classLoader)
|
||||
}.onEach { (_, classLoader) ->
|
||||
}.onEach { classLoader ->
|
||||
classLoaders.add(classLoader)
|
||||
}.mapValues {
|
||||
ServiceLoader.load(JvmPlugin::class.java, it.value)
|
||||
}.flatMap { (file, loader) ->
|
||||
loader.loadAll(file)
|
||||
}
|
||||
}.loadAll()
|
||||
|
||||
return (inMemoryPlugins + filePlugins).toSet().toList()
|
||||
return filePlugins.toSet().toList()
|
||||
}
|
||||
|
||||
@Throws(PluginLoadException::class)
|
||||
|
@ -16,6 +16,7 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import net.mamoe.mirai.console.MiraiConsole
|
||||
import net.mamoe.mirai.console.internal.data.cast
|
||||
import net.mamoe.mirai.console.internal.data.createInstanceOrNull
|
||||
import net.mamoe.mirai.console.internal.data.mkdir
|
||||
import net.mamoe.mirai.console.plugin.*
|
||||
import net.mamoe.mirai.console.plugin.description.PluginDependency
|
||||
@ -26,11 +27,9 @@ import net.mamoe.mirai.console.util.childScope
|
||||
import net.mamoe.mirai.utils.error
|
||||
import net.mamoe.mirai.utils.info
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import java.nio.file.Path
|
||||
import java.util.*
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.streams.asSequence
|
||||
|
||||
internal object PluginManagerImpl : PluginManager, CoroutineScope by MiraiConsole.childScope("PluginManager") {
|
||||
|
||||
@ -138,23 +137,25 @@ internal object PluginManagerImpl : PluginManager, CoroutineScope by MiraiConsol
|
||||
private fun loadPluginLoaderProvidedByPlugins() {
|
||||
loadersLock.withLock {
|
||||
JarPluginLoaderImpl.classLoaders.asSequence()
|
||||
.flatMap { pluginClassLoader ->
|
||||
ServiceLoader.load(PluginLoader::class.java, pluginClassLoader)
|
||||
.stream().asSequence()
|
||||
.asSequence()
|
||||
.mapNotNull { pluginClassLoader ->
|
||||
pluginClassLoader.getResourceAsStream(JvmPlugin::class.qualifiedName!!)?.use(InputStream::readBytes)
|
||||
?.let(::String)?.let { it to pluginClassLoader }
|
||||
}
|
||||
.forEach { provider ->
|
||||
.forEach { (pluginQualifiedName, classLoader) ->
|
||||
val pluginLoader = kotlin.runCatching {
|
||||
provider.get()
|
||||
val clazz =
|
||||
Class.forName(pluginQualifiedName, true, classLoader).cast<Class<out PluginLoader<*, *>>>()
|
||||
clazz.kotlin.objectInstance
|
||||
?: clazz.kotlin.createInstanceOrNull() ?: clazz.newInstance()
|
||||
}.getOrElse {
|
||||
logger.error(
|
||||
{ "Could not load PluginLoader ${provider.type().canonicalName}." },
|
||||
it
|
||||
{ "Could not load PluginLoader ${pluginQualifiedName}." },
|
||||
PluginLoadException("Could not load PluginLoader ${pluginQualifiedName}.", it)
|
||||
)
|
||||
return@forEach
|
||||
}
|
||||
_pluginLoaders.add(pluginLoader)
|
||||
logger.info { "Successfully loaded PluginLoader ${provider.type().canonicalName}." }
|
||||
logger.info { "Successfully loaded PluginLoader ${pluginQualifiedName}." }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,10 +23,9 @@ package net.mamoe.mirai.console.pure
|
||||
|
||||
|
||||
import com.vdurmont.semver4j.Semver
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.coroutines.*
|
||||
import net.mamoe.mirai.console.ConsoleFrontEndImplementation
|
||||
import net.mamoe.mirai.console.MiraiConsole
|
||||
import net.mamoe.mirai.console.MiraiConsoleFrontEndDescription
|
||||
import net.mamoe.mirai.console.MiraiConsoleImplementation
|
||||
import net.mamoe.mirai.console.data.MultiFilePluginDataStorage
|
||||
@ -72,7 +71,11 @@ class MiraiConsoleImplementationPure
|
||||
override val dataStorageForBuiltIns: PluginDataStorage = MultiFilePluginDataStorage(rootPath.resolve("data")),
|
||||
override val configStorageForJarPluginLoader: PluginDataStorage = MultiFilePluginDataStorage(rootPath.resolve("config")),
|
||||
override val configStorageForBuiltIns: PluginDataStorage = MultiFilePluginDataStorage(rootPath.resolve("config"))
|
||||
) : MiraiConsoleImplementation, CoroutineScope by CoroutineScope(NamedSupervisorJob("MiraiConsoleImplementationPure")) {
|
||||
) : MiraiConsoleImplementation, CoroutineScope by CoroutineScope(NamedSupervisorJob("MiraiConsoleImplementationPure") +
|
||||
CoroutineExceptionHandler { coroutineContext, throwable ->
|
||||
val coroutineName = coroutineContext[CoroutineName]?.name ?: "<unnamed>"
|
||||
MiraiConsole.mainLogger.error("Exception in coroutine $coroutineName", throwable)
|
||||
}) {
|
||||
override val consoleInput: ConsoleInput get() = ConsoleInputImpl
|
||||
|
||||
override fun createLoginSolver(requesterBot: Long, configuration: BotConfiguration): LoginSolver {
|
||||
|
Loading…
Reference in New Issue
Block a user