Extract mirai-console-wrapper from mirai-console repository, close #81

This commit is contained in:
Him188 2020-05-10 14:34:19 +08:00
parent dd55f9d0bd
commit 042e8094f1
9 changed files with 0 additions and 975 deletions

View File

@ -1,5 +0,0 @@
## Mirai Console Wrapper
Loader(Installer) of Mirai-Console all versions

View File

@ -1,62 +0,0 @@
plugins {
kotlin("jvm")
kotlin("plugin.serialization")
}
apply(plugin = "com.github.johnrengelman.shadow")
tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
manifest {
attributes["Main-Class"] = "net.mamoe.mirai.console.wrapper.WrapperMain"
}
}
kotlin {
sourceSets {
all {
languageSettings.enableLanguageFeature("InlineClasses")
languageSettings.useExperimentalAnnotation("kotlin.Experimental")
languageSettings.useExperimentalAnnotation("kotlin.OptIn")
}
}
}
dependencies {
api(kotlin("stdlib", Versions.Kotlin.stdlib))
api(kotlin("reflect", Versions.Kotlin.stdlib))
api(kotlinx("coroutines-core", Versions.Kotlin.coroutines))
api(kotlinx("coroutines-swing", Versions.Kotlin.coroutines))
api(ktor("client-cio", Versions.Kotlin.ktor))
api(ktor("client-core", Versions.Kotlin.ktor))
api(ktor("network", Versions.Kotlin.ktor))
api("com.github.ajalt:clikt:2.6.0")
testApi(kotlin("stdlib", Versions.Kotlin.stdlib))
testApi(kotlin("test-junit5"))
}
version = Versions.Mirai.consoleWrapper
description = "Console with plugin support for mirai"
val compileKotlin: org.jetbrains.kotlin.gradle.tasks.KotlinCompile by tasks
compileKotlin.kotlinOptions {
jvmTarget = "1.8"
}
val compileTestKotlin: org.jetbrains.kotlin.gradle.tasks.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"
}

View File

@ -1,172 +0,0 @@
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package net.mamoe.mirai.console.wrapper
import io.ktor.client.request.get
import io.ktor.http.URLProtocol
import java.io.File
import kotlin.math.pow
import kotlin.system.exitProcess
const val CONSOLE_PURE = "Pure"
const val CONSOLE_TERMINAL = "Terminal"
const val CONSOLE_GRAPHICAL = "Graphical"
internal object ConsoleUpdater {
@Suppress("SpellCheckingInspection")
private object Links : HashMap<ConsoleType, Map<String, String>>() {
init {
put(
ConsoleType.Pure, mapOf(
"version" to "/net/mamoe/mirai-console/"
)
)
put(
ConsoleType.Graphical, mapOf(
"version" to "/net/mamoe/mirai-console-graphical/"
)
)
}
}
var consoleType = ConsoleType.Pure
fun getFile(): File? {
contentPath.listFiles()?.forEach { file ->
if (file != null && file.extension == "jar") {
if (file.name.contains("mirai-console")) {
when (consoleType) {
ConsoleType.Pure -> {
if (!file.name.contains("graphical")) {
return file
}
}
ConsoleType.Graphical -> {
if (file.name.contains("graphical")) {
return file
}
}
else -> {
}
}
}
}
}
return null
}
suspend fun versionCheck(type: ConsoleType, strategy: VersionUpdateStrategy) {
this.consoleType = type
println("Fetching Newest Console Version of $type")
val current = getCurrentVersion()
if (current != "0.0.0" && strategy == VersionUpdateStrategy.KEEP) {
println("Stay on current version.")
return
}
val newest = getNewestVersion(
strategy,
Links[consoleType]!!["version"] ?: error("Unknown Console Type")
)
println("Local Console-$type Version: $current | Newest $strategy Console-$type Version: $newest")
if (current != newest) {
println("Updating Console-$type from V$current -> V$newest")
this.getFile()?.delete()
/**
MiraiDownloader.addTask(
"https://raw.githubusercontent.com/mamoe/mirai-repo/master/shadow/${getProjectName()}/${getProjectName()}-$newest.jar",getContent("${getProjectName()}-$newest.jar")
)
*/
MiraiDownloader.addTask(
"https://pan.jasonczc.cn/?/mirai/${getProjectName()}/${getProjectName()}-$newest.mp4",
getContent("${getProjectName()}-$newest.jar")
)
}
}
fun getCurrentVersion(): String {
val file = getFile()
if (file != null) {
return file.name.substringAfter(getProjectName() + "-").substringBefore(".jar")
}
return "0.0.0"
}
private fun getProjectName(): String {
return if (consoleType == ConsoleType.Pure) {
"mirai-console"
} else {
"mirai-console-${consoleType.toString().toLowerCase()}"
}
}
}
suspend fun getNewestVersion(strategy: VersionUpdateStrategy, path: String): String {
try {
return Regex("""rel="nofollow">[0-9][0-9]*(\.[0-9]*)*.*/<""", RegexOption.IGNORE_CASE).findAll(
Http.get<String> {
url {
protocol = URLProtocol.HTTPS
host = "jcenter.bintray.com"
path(path)
}
})
.asSequence()
.map { it.value.substringAfter('>').substringBefore('/') }
.toList()
.let { list ->
if (list.filter { it.startsWith("1.") }.takeIf { it.isNotEmpty() }?.all { it.contains("-") } == true) {
// 只有 1.xxx-EA 版本, 那么也将他看作是正式版
list.filter { it.startsWith("1.") }
} else when (strategy) {
VersionUpdateStrategy.KEEP,
VersionUpdateStrategy.STABLE
-> {
list.filterNot { it.contains("-") } // e.g. "-EA"
}
VersionUpdateStrategy.EA -> {
list
}
}
}
.latestVersion()
} catch (e: Exception) {
println("Failed to fetch newest Console version, please seek for help")
e.printStackTrace()
println("Failed to fetch newest Console version, please seek for help")
exitProcess(1)
}
}
internal fun List<String>.latestVersion(): String {
return sortByVersion().first()
}
internal fun List<String>.sortByVersion(): List<String> {
return sortedByDescending { version ->
version.split('.').let {
if (it.size == 2) it + "0"
else it
}.reversed().foldIndexed(0.0) { index: Int, acc: Double, s: String ->
acc + 1000.0.pow(index) * s.convertPatchVersionToWeight()
}
}
}
internal fun String.convertPatchVersionToWeight(): Double {
return this.split('-').reversed().foldIndexed(0.0) { index: Int, acc: Double, s: String ->
acc + 10.0.pow(index) * (s.toIntOrNull()?.toDouble() ?: -0.5)
}
}

View File

@ -1,91 +0,0 @@
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:Suppress("EXPERIMENTAL_API_USAGE")
package net.mamoe.mirai.console.wrapper
import java.io.File
internal object CoreUpdater {
fun getProtocolLib(): File? {
contentPath.listFiles()?.forEach { file ->
if (file != null && file.extension == "jar" && file.name.contains("qqandroid")) {
return file
}
}
return null
}
suspend fun versionCheck(strategy: VersionUpdateStrategy) {
println("Fetching Newest Core Version .. ")
val current = getCurrentVersion()
if (current != "0.0.0" && strategy == VersionUpdateStrategy.KEEP) {
println("Stay on current version.")
return
}
val newest = getNewestVersion(strategy, "net/mamoe/mirai-core-qqandroid/")
println("Local Core Version: $current | Newest $strategy Core Version: $newest")
if (current != newest) {
println("Updating shadowed-core from V$current -> V$newest")
this.getProtocolLib()?.delete()
MiraiDownloader
.addTask(
"https://pan.jasonczc.cn/?/mirai/mirai-core-qqandroid/mirai-core-qqandroid-$newest.mp4",
getContent("mirai-core-qqandroid-jvm-$newest.jar")
)
//.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"))
}
}
/**
* 判断当前版本
* 默认返回 "0.0.0"
*/
fun getCurrentVersion(): String {
val file = getProtocolLib() ?: return "0.0.0"
return file.name.substringBefore(".jar").substringAfter("mirai-core-qqandroid-jvm-")
}
/*
private suspend fun downloadCore(version: String) {
/**
* from github
*/
/**
* from jcenter
coroutineScope {
launch {
tryNTimesOrQuit(3, "Failed to download newest Protocol lib, please seek for help") {
Http.downloadMavenArchive("net/mamoe", "mirai-core-qqandroid-jvm", version)
.saveToContent("mirai-core-qqandroid-jvm-$version.jar")
}
}
launch {
tryNTimesOrQuit(3, "Failed to download newest core, please seek for help") {
Http.downloadMavenArchive("net/mamoe", "mirai-core-jvm", version)
.saveToContent("mirai-core-jvm-$version.jar")
}
}
}
*/
}
*/
}

View File

@ -1,150 +0,0 @@
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:Suppress("EXPERIMENTAL_API_USAGE")
package net.mamoe.mirai.console.wrapper
import io.ktor.client.HttpClient
import io.ktor.client.engine.cio.CIO
import io.ktor.client.request.get
import io.ktor.client.statement.HttpResponse
import io.ktor.utils.io.ByteReadChannel
import io.ktor.utils.io.jvm.javaio.copyTo
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.File
import kotlin.system.exitProcess
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)
return
} catch (e: Throwable) {
if (lastException == null) {
lastException = e
} else lastException!!.addSuppressed(e)
}
}
println(errorHint)
lastException!!.printStackTrace()
println(errorHint)
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) {
error("File not found")
}
if (this.headers["status"] != null && this.headers["status"] == "404") {
error("File not found")
}
this.content
}
}
private val jcenterPath = "https://jcenter.bintray.com/{group}/{project}/{version}/{project}-{version}.{extension}"
private val aliyunPath =
"https://maven.aliyun.com/nexus/content/repositories/jcenter/{group}/{project}/{version}/{project}-{version}.{extension}"
private fun String.buildPath(
groupName: String,
projectName: String,
version: String,
extension: String
): String {
return this
.replace(
"{group}", groupName
)
.replace(
"{project}", projectName
)
.replace(
"{extension}", extension
)
.replace(
"{version}", version
)
}
internal suspend fun HttpClient.downloadMaven(
groupName: String,
projectName: String,
version: String,
extension: String
): ByteReadChannel {
return kotlin.runCatching {
downloadRequest(
aliyunPath.buildPath(groupName, projectName, version, extension)
)
}.getOrElse {
downloadRequest(
jcenterPath.buildPath(groupName, projectName, version, extension)
)
}
}
internal suspend inline fun HttpClient.downloadMavenArchive(
groupName: String,
projectName: String,
version: String
): ByteReadChannel {
return downloadMaven(groupName, projectName, version, "jar")
}
internal suspend inline fun HttpClient.downloadMavenPom(
groupName: String,
projectName: String,
version: String
): ByteReadChannel {
return downloadMaven(groupName, projectName, version, "pom")
}
internal suspend fun HttpClient.downloadMavenPomAsString(
groupName: String,
projectName: String,
version: String
): String {
return kotlin.runCatching {
this.get<String>(
aliyunPath.buildPath(groupName, projectName, version, "pom")
)
}.getOrElse {
this.get(
aliyunPath.buildPath(groupName, projectName, version, "pom")
)
}
}
/**
* 只要填 content path 后面的就可以
*/
internal suspend fun ByteReadChannel.saveToContent(filepath: String) {
val fileStream = File(contentPath.absolutePath + "/" + filepath).also {
withContext(Dispatchers.IO) {
it.createNewFile()
}
}.outputStream()
withContext(Dispatchers.IO) {
this@saveToContent.copyTo(fileStream)
fileStream.flush()
}
}
internal fun getContent(filepath: String):File{
return File(contentPath, filepath)
}

View File

@ -1,178 +0,0 @@
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package net.mamoe.mirai.console.wrapper
import kotlinx.coroutines.*
import java.io.File
import java.io.FileOutputStream
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(isUI:Boolean){
if(tasks.isNotEmpty()){
if(!isUI) {
MiraiDownloaderImpl(EmptyCoroutineContext, tasks, false, MiraiDownloaderProgressBarInTerminal()).waitUntilFinish()
}else{
MiraiDownloaderImpl(EmptyCoroutineContext, tasks, false, MiraiDownloaderProgressBarInUI()).waitUntilFinish()
}
}
}
}
//background => any print
private class MiraiDownloaderImpl(
override val coroutineContext: CoroutineContext = EmptyCoroutineContext,
tasks: Map<String, File>,
val background:Boolean,
val bar:MiraiDownloadProgressBar
):CoroutineScope {
fun log(any:Any?){
if(!background && any != null){
println(background)
}
}
var totalDownload = AtomicInteger(0)
var totalSize = AtomicInteger(0)
private var isDownloadFinish: Job
init {
bar.ad()
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 con = URL(fromUrl).openConnection() as HttpURLConnection
val input= con.inputStream
totalSize.addAndGet(con.contentLength)
val outputStream = FileOutputStream(file)
var len: Int
val buff = ByteArray(1024)
while (input.read(buff).also { len = it } != -1) {
totalDownload.addAndGet(buff.size)
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)
}
}
}
}
interface MiraiDownloadProgressBar{
fun reset()
fun update(rate: Float, message: String)
fun complete()
fun ad()
}
class MiraiDownloaderProgressBarInTerminal(): MiraiDownloadProgressBar{
override fun reset() {
print('\r')
}
override fun ad(){
println("Mirai Downloader")
println("[Mirai国内镜像] 感谢崔Cloud慷慨提供免费的国内储存分发")
}
private val barLen = 40
override 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")
}
override fun complete(){
println()
}
}
class MiraiDownloaderProgressBarInUI(): MiraiDownloadProgressBar{
override fun reset() {
WrapperMain.uiBarOutput.clear()
}
override fun ad(){
WrapperMain.uiLog("[Mirai国内镜像] 感谢崔Cloud慷慨提供更新服务器")
}
private val barLen = 20
override fun update(rate: Float, message: String) {
reset()
WrapperMain.uiBarOutput.append("Progress: ")
val len = (rate * barLen).toInt()
for (i in 0 until len) {
WrapperMain.uiBarOutput.append("#")
}
for (i in 0 until barLen - len) {
WrapperMain.uiBarOutput.append(" ")
}
WrapperMain.uiBarOutput.append(" | $message")
}
override fun complete() {
}
}

View File

@ -1,288 +0,0 @@
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:Suppress("EXPERIMENTAL_API_USAGE")
package net.mamoe.mirai.console.wrapper
import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.parameters.options.default
import com.github.ajalt.clikt.parameters.options.flag
import com.github.ajalt.clikt.parameters.options.option
import com.github.ajalt.clikt.parameters.types.enum
import kotlinx.coroutines.*
import java.awt.TextArea
import java.io.File
import java.net.URLClassLoader
import java.util.jar.JarFile
import javax.swing.JFrame
import javax.swing.JPanel
val contentPath by lazy {
File(System.getProperty("user.dir"), "content").also {
if (!it.exists()) {
it.mkdirs()
}
}
}
val extendedLibraries by lazy {
val file =
System.getProperty("mirai.libraries")?.let { File(it) } ?: File(System.getProperty("user.dir"), "libraries")
file.also { if (!it.exists()) it.mkdirs() }
}
object WrapperCli : CliktCommand(name = "mirai-warpper") {
private val native by option(
help = """
Start in GRAPHICAL mode without command line outputs
------------------------------------------
以图形界面模式启动
""".trimIndent(),
envvar = "mirai.wrapper.native"
).flag("-n", default = false)
private val update: VersionUpdateStrategy by option(
help = """
Strategy to automatic updates.
"KEEP" to stay on the current version;
"STABLE" to update to the latest stable versions;
"EA" to update to use the newest features but might not be stable.
------------------------------------------
版本升级策略. "KEEP" 为停留在当前版本; "STABLE" 为更新到最新稳定版; "EA" 为更新到最新预览版.
""".trimIndent(),
envvar = "mirai.wrapper.update"
).enum<VersionUpdateStrategy>().default(VersionUpdateStrategy.STABLE)
private val console: ConsoleType by option(
help = """
The type of the console to be started.
"GRAPHICAL" to use JavaFX graphical UI;
"TERMINAL" to use terminal UI for Unix;
"PURE" to use pure CLI.
------------------------------------------
UI 类型. "GRAPHICAL" JavaFX 图形界面; "TERMINAL" Unix 终端界面; "PURE" 为纯命令行.
""".trimIndent(),
envvar = "mirai.wrapper.console"
).enum<ConsoleType>().default(ConsoleType.Pure)
override fun run() {
if (native) {
val f = JFrame("Mirai-Console Version Check")
f.setSize(500, 200)
f.setLocationRelativeTo(null)
f.isResizable = false
val p = JPanel()
f.add(p)
val textArea = TextArea()
p.add(textArea)
textArea.isEditable = false
f.isVisible = true
WrapperMain.uiLog("正在进行版本检查\n")
val dic = System.getProperty("user.dir")
WrapperMain.uiLog("工作目录: ${dic}\n")
WrapperMain.uiLog("扩展库目录: ${extendedLibraries}\n")
WrapperMain.uiLog("若无法启动, 请尝试清除工作目录下/content/文件夹\n")
var uiOpen = true
GlobalScope.launch {
while (isActive && uiOpen) {
delay(16)//60 fps
withContext(Dispatchers.Main) {
textArea.text = WrapperMain.uiLog.toString() + "\n" + WrapperMain.uiBarOutput.toString()
}
}
}
runBlocking {
launch {
CoreUpdater.versionCheck(update)
}
launch {
ConsoleUpdater.versionCheck(ConsoleType.Graphical, update)
}
}
WrapperMain.uiLog("版本检查完成, 启动中\n")
runBlocking {
MiraiDownloader.downloadIfNeed(true)
}
GlobalScope.launch {
delay(3000)
uiOpen = false
f.isVisible = false
}
WrapperMain.start(ConsoleType.Graphical)
} else {
WrapperMain.preStartInNonNative(console, update)
}
}
}
enum class ConsoleType {
Graphical,
Terminal,
Pure
}
enum class VersionUpdateStrategy {
KEEP,
STABLE,
EA
}
object WrapperMain {
internal var uiBarOutput = StringBuilder()
internal val uiLog = StringBuilder()
internal fun uiLog(any: Any?) {
if (any != null) {
uiLog.append(any)
}
}
@JvmStatic
fun main(args: Array<String>) {
gc()
WrapperCli.main(args)
}
internal fun preStartInNonNative(defaultType: ConsoleType, strategy: VersionUpdateStrategy) {
println("You are running Mirai-Console-Wrapper under " + System.getProperty("user.dir"))
println("All additional libraries are located at $extendedLibraries")
var type = ConsoleType.values().firstOrNull { it.name.equals(WrapperProperties.content, ignoreCase = true) }
if (type != null) {
println("Starting Mirai Console $type, reset by clear /content/")
} else {
WrapperProperties.content = defaultType.toString()
type = defaultType
}
println("Starting version check...")
runBlocking {
launch {
CoreUpdater.versionCheck(strategy)
}
launch {
ConsoleUpdater.versionCheck(type, strategy)
}
}
runBlocking {
MiraiDownloader.downloadIfNeed(false)
}
println("Version check complete, starting Mirai")
println("shadow-Protocol:" + CoreUpdater.getProtocolLib()!!)
println("Console :" + ConsoleUpdater.getFile()!!)
println("Root :" + System.getProperty("user.dir") + "/")
start(type)
}
internal fun start(type: ConsoleType) {
val loader = MiraiClassLoader(
CoreUpdater.getProtocolLib()!!,
ConsoleUpdater.getFile()!!,
WrapperMain::class.java.classLoader
)
try {
loader.loadClass("net.mamoe.mirai.BotFactoryJvm")
} catch (e: ClassNotFoundException) {
System.err.println("Found mirai-core file broken, re-downloading...")
loader.close()
CoreUpdater.getProtocolLib()?.delete()
WrapperCli.run()
return
}
try {
loader.loadClass(
when (type) {
ConsoleType.Pure -> "net.mamoe.mirai.console.pure.MiraiConsolePureLoader"
ConsoleType.Graphical -> "net.mamoe.mirai.console.graphical.MiraiConsoleGraphicalLoader"
else -> return
}
).getMethod("load", String::class.java, String::class.java)
.invoke(null, CoreUpdater.getCurrentVersion(), ConsoleUpdater.getCurrentVersion())
} catch (e: ClassNotFoundException) {
System.err.println("Found mirai-console file broken, re-downloading...")
loader.close()
ConsoleUpdater.getFile()?.delete()
WrapperCli.run()
}
}
}
private class MiraiClassLoader(
protocol: File,
console: File,
parent: ClassLoader?
) : URLClassLoader(
arrayOf(
protocol.toURI().toURL(),
console.toURI().toURL()
), null
) {
init {
extendedLibraries.listFiles { file ->
file.isFile && file.extension == "jar"
}?.forEach {
kotlin.runCatching {
/*
Confirm that the current jar is valid
确认当前jar是否有效
*/
JarFile(it).close()
addURL(it.toURI().toURL())
}
}
}
private val parent0: ClassLoader? = parent
override fun findClass(name: String?): Class<*> {
return try {
super.findClass(name)
} catch (exception: ClassNotFoundException) {
if (parent0 == null) throw exception
parent0.loadClass(name)
}
}
}
private object WrapperProperties {
val contentFile by lazy {
File(contentPath, ".wrapper.txt").also {
if (!it.exists()) it.createNewFile()
}
}
var content
get() = contentFile.readText()
set(value) = contentFile.writeText(value)
}
private fun gc() {
GlobalScope.launch {
while (isActive) {
delay(1000 * 60)
System.gc()
}
}
}

View File

@ -1,28 +0,0 @@
package net.mamoe.mirai.console.wrapper
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
internal class ConsoleUpdaterKtTest {
@Test
fun testVersionCompare() {
assertEquals(
listOf(
"1.0.0",
"1.0-EA-2",
"1.0-EA",
"0.40.0"
),
listOf(
"1.0.0",
"0.40.0",
"1.0-EA",
"1.0-EA-2"
).sortByVersion()
)
}
}
fun main() {
ConsoleUpdaterKtTest().testVersionCompare()
}

View File

@ -25,7 +25,6 @@ rootProject.name = 'mirai-console'
include(':mirai-console')
include(':mirai-console-terminal')
include(':mirai-console-wrapper')
try{
def javaVersion = System.getProperty("java.version")