This commit is contained in:
Him188 2020-01-18 21:41:40 +08:00
parent 06685158a2
commit be91d6078a

View File

@ -1,17 +1,17 @@
package net.mamoe.mirai.plugin
import net.mamoe.mirai.utils.DefaultLogger
import java.io.BufferedReader
import net.mamoe.mirai.utils.io.encodeToString
import java.io.File
import java.io.InputStream
import java.io.InputStreamReader
import java.net.JarURLConnection
import java.net.URL
import java.net.URLClassLoader
import java.util.jar.JarFile
abstract class PluginBase constructor() {
val dataFolder: File by lazy {
File(PluginManager.pluginsPath + pluginDescription.name).also { it.mkdir() }
}
open fun onLoad() {
@ -25,38 +25,27 @@ abstract class PluginBase constructor() {
}
fun getPluginManager(): PluginManager {
return PluginManager
}
private lateinit var pluginDescription: PluginDescription
internal fun init(pluginDescription: PluginDescription) {
this.pluginDescription = pluginDescription
this.onLoad()
}
fun getDataFolder(): File {
return File(PluginManager.pluginsPath + pluginDescription.pluginName).also {
it.mkdirs()
}
}
}
class PluginDescription(
val pluginName: String,
val pluginAuthor: String,
val pluginBasePath: String,
val pluginVersion: String,
val pluginInfo: String,
val name: String,
val author: String,
val basePath: String,
val version: String,
val info: String,
val depends: List<String>,//插件的依赖
internal var loaded: Boolean = false,
internal var noCircularDepend: Boolean = true
) {
override fun toString(): String {
return "name: $pluginName\nauthor: $pluginAuthor\npath: $pluginBasePath\nver: $pluginVersion\ninfo: $pluginInfo\ndepends: $depends"
return "name: $name\nauthor: $author\npath: $basePath\nver: $version\ninfo: $info\ndepends: $depends"
}
companion object {
@ -103,7 +92,7 @@ class PluginDescription(
}
class PluginClassLoader(file: File, parent: ClassLoader) : URLClassLoader(arrayOf(file.toURI().toURL()), parent) {
internal class PluginClassLoader(file: File, parent: ClassLoader) : URLClassLoader(arrayOf(file.toURI().toURL()), parent) {
override fun findClass(moduleName: String?, name: String?): Class<*> {
return super.findClass(name)
}
@ -129,29 +118,18 @@ object PluginManager {
val pluginsLocation: MutableMap<String, File> = mutableMapOf()
File(pluginsPath).listFiles()?.forEach { file ->
if (file != null) {
if (file.extension == "jar") {
val jar = JarFile(file)
val pluginYml =
jar.entries().asSequence().filter { it.name.toLowerCase().contains("plugin.yml") }.firstOrNull()
if (pluginYml == null) {
logger.info("plugin.yml not found in jar " + jar.name + ", it will not be consider as a Plugin")
} else {
val url = URL("jar:file:" + file.absoluteFile + "!/" + pluginYml.name)
val jarConnection: JarURLConnection = url
.openConnection() as JarURLConnection
val inputStream: InputStream = jarConnection.getInputStream()
val br = BufferedReader(InputStreamReader(inputStream, "UTF-8"))
var con: String?
val sb = StringBuffer()
while (br.readLine().also { con = it } != null) {
sb.append(con).append("\n")
}
val description = PluginDescription.readFromContent(sb.toString())
println(description)
pluginsFound[description.pluginName] = description
pluginsLocation[description.pluginName] = file
}
if (file != null && file.extension == "jar") {
val jar = JarFile(file)
val pluginYml =
jar.entries().asSequence().filter { it.name.toLowerCase().contains("plugin.yml") }.firstOrNull()
if (pluginYml == null) {
logger.info("plugin.yml not found in jar " + jar.name + ", it will not be consider as a Plugin")
} else {
val description =
PluginDescription.readFromContent(URL("jar:file:" + file.absoluteFile + "!/" + pluginYml.name).openConnection().inputStream.readAllBytes().encodeToString())
println(description)
pluginsFound[description.name] = description
pluginsLocation[description.name] = file
}
}
}
@ -166,7 +144,7 @@ object PluginManager {
return
}
existDepends.add(target.pluginName)
existDepends.add(target.name)
if (needDepends.any { existDepends.contains(it) }) {
target.noCircularDepend = false
@ -191,58 +169,51 @@ object PluginManager {
fun loadPlugin(description: PluginDescription): Boolean {
if (!description.noCircularDepend) {
return false.also {
logger.error("Failed to load plugin " + description.pluginName + " because it has circular dependency")
}
logger.error("Failed to load plugin " + description.name + " because it has circular dependency")
return false
}
//load depends first
description.depends.forEach {
if (!pluginsFound.containsKey(it)) {
return false.also { _ ->
logger.error("Failed to load plugin " + description.pluginName + " because it need " + it + " as dependency")
}
description.depends.forEach { dependent ->
if (!pluginsFound.containsKey(dependent)) {
logger.error("Failed to load plugin " + description.name + " because it need " + dependent + " as dependency")
return false
}
val depend = pluginsFound[it]!!
val depend = pluginsFound[dependent]!!
//还没有加载
if (!depend.loaded) {
if (!loadPlugin(pluginsFound[it]!!)) {
return false.also { _ ->
logger.error("Failed to load plugin " + description.pluginName + " because " + it + " as dependency failed to load")
}
}
if (!depend.loaded && !loadPlugin(pluginsFound[dependent]!!)) {
logger.error("Failed to load plugin " + description.name + " because " + dependent + " as dependency failed to load")
return false
}
}
//在这里所有的depends都已经加载了
//real load
logger.info("loading plugin " + description.pluginName)
logger.info("loading plugin " + description.name)
try {
val pluginClass =
PluginClassLoader((pluginsLocation[description.pluginName]!!), this.javaClass.classLoader)
.loadClass(description.pluginBasePath)
PluginClassLoader((pluginsLocation[description.name]!!), this.javaClass.classLoader)
.loadClass(description.basePath)
return try {
val subClass = pluginClass.asSubclass(PluginBase::class.java)
val plugin: PluginBase = subClass.getDeclaredConstructor().newInstance()
description.loaded = true
logger.info("successfully loaded plugin " + description.pluginName)
logger.info(description.pluginInfo)
logger.info("successfully loaded plugin " + description.name)
logger.info(description.info)
nameToPluginBaseMap[description.pluginName] = plugin
nameToPluginBaseMap[description.name] = plugin
plugin.init(description)
true
} catch (e: ClassCastException) {
false.also {
logger.error("failed to load plugin " + description.pluginName + " , Main class does not extends PluginBase ")
}
logger.error("failed to load plugin " + description.name + " , Main class does not extends PluginBase ")
false
}
} catch (e: ClassNotFoundException) {
e.printStackTrace()
return false.also {
logger.error("failed to load plugin " + description.pluginName + " , Main class not found under " + description.pluginBasePath)
}
logger.error("failed to load plugin " + description.name + " , Main class not found under " + description.basePath)
return false
}
}