mirror of
https://github.com/mamoe/mirai.git
synced 2025-03-14 07:10:09 +08:00
Extract mirai-console-wrapper from mirai-console repository, close #81
This commit is contained in:
parent
dd55f9d0bd
commit
042e8094f1
@ -1,5 +0,0 @@
|
||||
## Mirai Console Wrapper
|
||||
|
||||
Loader(Installer) of Mirai-Console all versions
|
||||
|
||||
|
@ -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"
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
}
|
@ -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)
|
||||
}
|
@ -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() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
@ -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")
|
||||
|
Loading…
Reference in New Issue
Block a user