1
0
mirror of https://github.com/mamoe/mirai.git synced 2025-04-25 21:23:55 +08:00

wrapper rewrite

This commit is contained in:
jiahua.liu 2020-03-26 22:04:48 +08:00
parent ac125b22d2
commit 90d074a1dd
8 changed files with 173 additions and 209 deletions

View File

@ -1,21 +1,21 @@
# style guide
kotlin.code.style=official
# config
miraiVersion=0.29.1
miraiConsoleVersion=0.3.6
miraiConsoleWrapperVersion=0.1.3
miraiVersion=0.30.0
miraiConsoleVersion=0.3.7
miraiConsoleWrapperVersion=0.1.4
kotlin.incremental.multiplatform=true
kotlin.parallel.tasks.in.project=true
# kotlin
kotlinVersion=1.3.70
kotlinVersion=1.4-M1
# kotlin libraries
serializationVersion=0.20.0
coroutinesVersion=1.3.4
atomicFuVersion=0.14.1
serializationVersion=0.20.0-1.4-M1
coroutinesVersion=1.3.5-1.4-M1
atomicFuVersion=0.14.2-1.4-M1
kotlinXIoVersion=0.1.16
coroutinesIoVersion=0.1.16
# utility
ktorVersion=1.3.2
ktorVersion=1.3.2-1.4-M1
klockVersion=1.7.0
# gradle plugin
protobufJavaVersion=3.10.0

View File

@ -80,6 +80,8 @@ dependencies {
api(group = "org.yaml", name = "snakeyaml", version = "1.25")
api(group = "com.moandjiezana.toml", name = "toml4j", version = "0.7.2")
api(group = "com.github.tomas-langer.cli", name="cli-progress", version="1.0.0")
}
val miraiConsoleWrapperVersion: String by project.ext

View File

@ -51,8 +51,9 @@ internal object ConsoleUpdater {
if (current != newest) {
println("Updating Console-$type from V$current -> V$newest, this is a force update")
this.getFile()?.delete()
downloadConsole(newest)
println("Download Console complete")
MiraiDownloader.addTask(
"https://raw.githubusercontent.com/mamoe/mirai-repo/master/shadow/${getProjectName()}/${getProjectName()}-$newest.jar",getContent("${getProjectName()}-$newest.jar")
)
}
}
@ -102,11 +103,12 @@ internal object ConsoleUpdater {
}
private suspend fun downloadConsole(version: String) {
/*
tryNTimesOrQuit(3, "Failed to download Console, please seek for help") {
Http.downloadMavenArchive("net/mamoe", getProjectName(), version)
.saveToContent("${getProjectName()}-$version.jar")
}
LibManager.clearLibs()
LibManager.addDependencyRequest("net/mamoe", getProjectName(), version)
*/
}
}

View File

@ -13,10 +13,7 @@ package net.mamoe.mirai.console.wrapper
import io.ktor.client.request.get
import io.ktor.http.URLProtocol
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import java.io.File
import java.net.URLClassLoader
import kotlin.math.pow
import kotlin.system.exitProcess
@ -31,15 +28,6 @@ internal object CoreUpdater {
return null
}
fun getCore(): File? {
contentPath.listFiles()?.forEach { file ->
if (file != null && file.extension == "jar" && file.name.contains("core") && (!file.name.contains("qqandroid"))) {
return file
}
}
return null
}
suspend fun versionCheck() {
println("Fetching Newest Core Version .. ")
@ -47,19 +35,13 @@ internal object CoreUpdater {
val current = getCurrentVersion()
println("Local Core Version: $current | Newest Core Version: $newest")
if (current != newest) {
println("Updating Core/Lib from V$current -> V$newest, this is a force update")
cleanCoreAndLib()
downloadCoreAndLib(newest)
println("Download Core/Lib complete")
println("Updating shadowed-core from V$current -> V$newest, this is a force update")
this.getProtocolLib()?.delete()
MiraiDownloader
.addTask("https://raw.githubusercontent.com/mamoe/mirai-repo/master/shadow/mirai-core-qqandroid/mirai-core-qqandroid-$newest.jar", getContent("mirai-core-qqandroid-jvm-$newest.jar"))
}
}
fun loadCore() {
println("Loading Core")
loadCoreAndLib()
println("Mirai Core and Libraries Loaded")
}
/**
* 判断最新版本
* */
@ -93,8 +75,7 @@ internal object CoreUpdater {
* 默认返回 "0.0.0"
*/
fun getCurrentVersion(): String {
val file = getProtocolLib()
if (file == null || getCore() == null) return "0.0.0"
val file = getProtocolLib() ?: return "0.0.0"
val numberVersion = """([0-9])*\.([0-9])*\.([0-9])*""".toRegex().find(file.name)?.value
if (numberVersion != null) {
return numberVersion + file.name.substringAfter(numberVersion).substringBefore(".jar")
@ -103,13 +84,16 @@ internal object CoreUpdater {
}
private fun cleanCoreAndLib() {
this.getCore()?.delete()
this.getProtocolLib()?.delete()
}
/*
private suspend fun downloadCore(version: String) {
/**
* from github
*/
private suspend fun downloadCoreAndLib(version: String) {
/**
* from jcenter
coroutineScope {
launch {
tryNTimesOrQuit(3, "Failed to download newest Protocol lib, please seek for help") {
@ -124,48 +108,13 @@ internal object CoreUpdater {
.saveToContent("mirai-core-jvm-$version.jar")
}
}
launch {
LibManager.clearLibs()
LibManager.addDependencyRequest("net/mamoe", "mirai-core-jvm", version)
LibManager.addDependencyRequest("net/mamoe", "mirai-core-qqandroid-jvm", version)
}
}
*/
}
private fun loadCoreAndLib() {
try {
val coreFile = getCore()!!
val protocolFile = getProtocolLib()!!
println("Core: $coreFile")
println("Protocol: $protocolFile")
val classloader = URLClassLoader(
arrayOf(coreFile.toURI().toURL(), protocolFile.toURI().toURL()),
this.javaClass.classLoader
)
ClassLoader.getSystemClassLoader()
// this.javaClass.classLoader.
println(classloader.loadClass("net.mamoe.mirai.BotFactory"))
println(classloader.loadClass("net.mamoe.mirai.qqandroid.QQAndroid"))
println(classloader.loadClass("net.mamoe.mirai.utils.cryptor.ECDHJvmKt"))
val a = classloader.loadClass("net.mamoe.mirai.qqandroid.QQAndroid").kotlin.objectInstance!!
println(a::class.java)
println(Class.forName("net.mamoe.mirai.qqandroid.QQAndroid"))
} catch (e: ClassNotFoundException) {
println("Failed to load core, please seek for help")
e.printStackTrace()
println("Failed to load core, please seek for help")
exitProcess(1)
}
}
*/
}

View File

@ -17,7 +17,6 @@ internal val Http: HttpClient = HttpClient(CIO)
internal inline fun <R> tryNTimesOrQuit(repeat: Int, errorHint: String, block: (Int) -> R) {
var lastException: Throwable? = null
repeat(repeat) {
try {
block(it)
@ -34,7 +33,6 @@ internal inline fun <R> tryNTimesOrQuit(repeat: Int, errorHint: String, block: (
exitProcess(1)
}
internal suspend inline fun HttpClient.downloadRequest(url: String): ByteReadChannel {
return with(this.get<HttpResponse>(url)) {
if (this.status.value == 404 || this.status.value == 403) {
@ -140,3 +138,6 @@ internal suspend fun ByteReadChannel.saveToContent(filepath: String) {
internal fun getContent(filepath: String):File{
return File(contentPath.absolutePath + "/" + filepath)
}

View File

@ -1,121 +0,0 @@
package net.mamoe.mirai.console.wrapper
import java.io.File
import java.util.*
object LibManager{
val libPath by lazy{
File(contentPath.absolutePath + "/lib/").also {
if(!it.exists()){
it.mkdirs()
}
}
}
/**
* 开关
* 当前版本不写dynamic加载lib
*/
val dynamic = false;
fun clearLibs(){
if(!dynamic){
return;
}
libPath.listFiles()?.forEach {
it.delete()
}
}
/**
* 增加dependency 不是立刻下载
* 全部完成后使用 @link downloadIfNeeded()开始下载
*/
/**
* 由Pom Path提供必要依赖
* LibManager会进行下载和递归处理
*/
suspend fun addDependencyRequest(
group: String,
project: String,
version: String
){
if(!dynamic){
return;
}
var pom:String? = null
if(project.contains("maven") && project.contains("plugin")){
return
}
if(project.contains("toplink-essentials") || project.contains("ejb") ||project.contains("glassfish-embedded-all") || project.contains("maven-bundle-plugin") || project.contains("jetty") || project.contains("plexus-component-annotations") || project.contains("slf4j") || project.contains("sisu-inject-plexus") || project.contains("maven-remote-resources-plugin") || project.contains("easymock") || project.contains("junit") || project.contains("log4j") || project.contains("doxia-logging-api") || project.contains("maven-enforcer-plugin") || project.contains("maven-plugin") || project.contains("maven-artifact") || project.contains("maven-core") || project.contains("cglib") || project.contains("spring-core")){
return
}
tryNTimesOrQuit(3, "Failed to find dependency for $project") {
pom = Http.downloadMavenPomAsString(
group, project, version
)
}
addDependency(group,project,version)
if(pom == null){
println("Failed to load dependency POM")
return
}
pom!!.replace("\n","").split("</dependency>").forEach {
if(it.contains("<dependency>")) {
val dependencyInfo = it.replace("<dependency>","")
if(dependencyInfo.contains("<groupId>") && dependencyInfo.contains("<artifactId>") && dependencyInfo.contains("<version>")) {
val groupName =
dependencyInfo.substringAfter("<groupId>").substringBefore("</groupId>").replace(".", "/")
.removeSuffix("/")
val projectName = dependencyInfo.substringAfter("<artifactId>").substringBefore("</artifactId>")
val versionName = dependencyInfo.substringAfter("<version>").substringBefore("</version>")
if (!versionName.contains("{")) {
if (addDependency(groupName, projectName, versionName)) {
addDependencyRequest(groupName, projectName, versionName)
}
}
}
}
}
}
/**
* 普通的增加一个dependency
*/
private val dependency = HashSet<String>()
fun addDependency(
group: String,
project: String,
version: String
):Boolean{
if(!dynamic){
return false;
}
if(project.contains("maven") && project.contains("plugin")){
return true
}
if(project.contains("toplink-essentials") ||project.contains("ejb") || project.contains("glassfish-embedded-all") || project.contains("maven-bundle-plugin") || project.contains("jetty") || project.contains("slf4j") || project.contains("sisu-inject-plexus") || project.contains("maven-remote-resources-plugin") || project.contains("easymock") || project.contains("junit") || project.contains("log4j") || project.contains("doxia-logging-api") || project.contains("maven-enforcer-plugin") || project.contains("maven-plugin") || project.contains("maven-artifact") || project.contains("maven-core") || project.contains("cglib") || project.contains("spring-core")){
return true
}
val id = "${group
.replace(".","/")
.removeSuffix("/")
}-$project:$version"
if(dependency.contains(id)){
return false
}
println(id)
dependency.add(id)
return true
}
suspend fun downloadIfNeeded(){
this.dependency.forEach {
println(it)
}
}
}

View File

@ -0,0 +1,128 @@
package net.mamoe.mirai.console.wrapper
import kotlinx.coroutines.*
import java.io.File
import java.io.FileOutputStream
import java.io.InputStream
import java.net.HttpURLConnection
import java.net.URL
import java.util.concurrent.atomic.AtomicInteger
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.system.exitProcess
internal object MiraiDownloader{
private val tasks = mutableMapOf<String,File>()
fun addTask(
fromUrl: String,
to: File
){
tasks[fromUrl] = to
}
suspend fun downloadIfNeed(){
if(tasks.isNotEmpty()){
MiraiDownloaderImpl(EmptyCoroutineContext, tasks).waitUntilFinish()
}
}
}
private class MiraiDownloaderImpl(
override val coroutineContext: CoroutineContext = EmptyCoroutineContext,
tasks: Map<String, File>
):CoroutineScope {
val bar = MiraiDownloaderProgressBar()
var totalDownload = AtomicInteger(0)
var totalSize = AtomicInteger(0)
private var isDownloadFinish: Job
init {
println("Mirai Downloader")
isDownloadFinish = this.async {
tasks.forEach {
this.launch {
downloadTask(it.key, it.value)
}
}
}
}
suspend fun waitUntilFinish(){
while (!isDownloadFinish.isCompleted){
bar.update(totalDownload.get().toFloat()/totalSize.get(),(totalSize.get()/(1024*1024)).toString() + "MB" )
delay(50)
}
bar.update(1F,"Complete")
bar.complete()
}
@Throws(Exception::class)
private suspend fun downloadTask(fromUrl: String, file: File) {
withContext(Dispatchers.IO) {
try {
val url = URL(fromUrl)
val con: HttpURLConnection = url.openConnection() as HttpURLConnection
val input: InputStream = con.inputStream
totalSize.addAndGet(con.contentLength)
val outputStream = FileOutputStream(file)
var len = -1
val buff = ByteArray(1024)
while (input.read(buff).also { len = it } != -1) {
totalDownload.addAndGet(len)
outputStream.write(buff, 0, len);
}
}catch (e: Exception){
bar.update(1F,"Failed")
bar.complete()
println("Failed to download resources from " + fromUrl + " reason " + e.message)
e.printStackTrace()
println("Failed to download resources from " + fromUrl + " reason " + e.message)
println("Please Seek For Help")
exitProcess(1)
}
}
}
}
class MiraiDownloaderProgressBar(){
private fun reset() {
print('\r')
}
private val barLen = 40
fun update(rate: Float, message: String) {
reset()
print("Progress: ")
val len = (rate * barLen).toInt()
for (i in 0 until len) {
print("#")
}
for (i in 0 until barLen - len) {
print(" ")
}
print(" | $message")
}
fun complete(){
println()
}
}

View File

@ -65,21 +65,26 @@ object WrapperMain {
ConsoleUpdater.versionCheck(type)
}
}
runBlocking {
MiraiDownloader.downloadIfNeed()
}
println("Version check complete, starting Mirai")
println("Core :" + CoreUpdater.getCore()!!)
println("Protocol:" + CoreUpdater.getProtocolLib()!!)
println("Console :" + ConsoleUpdater.getFile()!!)
println("Root :" + System.getProperty("user.dir") + "/")
println("shadow-Protocol:" + CoreUpdater.getProtocolLib()!!)
println("Console :" + ConsoleUpdater.getFile()!!)
println("Root :" + System.getProperty("user.dir") + "/")
val loader = MiraiClassLoader(
CoreUpdater.getCore()!!,
CoreUpdater.getProtocolLib()!!,
ConsoleUpdater.getFile()!!,
this.javaClass.classLoader
)
loader.loadClass("net.mamoe.mirai.BotFactoryJvm")
when (type) {
CONSOLE_PURE -> {
loader.loadClass("net.mamoe.mirai.BotFactoryJvm")
loader.loadClass(
"net.mamoe.mirai.console.pure.MiraiConsolePureLoader"
).getMethod("load", String::class.java, String::class.java)
@ -90,12 +95,10 @@ object WrapperMain {
}
class MiraiClassLoader(
core:File,
protocol: File,
console: File,
parent: ClassLoader
): URLClassLoader(arrayOf(
core.toURI().toURL(),
protocol.toURI().toURL(),
console.toURI().toURL()
), parent)