Rework core/console updating, implement command args

This commit is contained in:
Him188 2020-05-06 14:40:53 +08:00
parent 0b1089c10d
commit fa8eb466e7
8 changed files with 272 additions and 141 deletions

View File

@ -11,10 +11,10 @@ import org.gradle.kotlin.dsl.DependencyHandlerScope
object Versions {
object Mirai {
const val core = "0.39.1"
const val core = "1.0-RC"
const val console = "0.4.11"
const val consoleGraphical = "0.0.7"
const val consoleWrapper = "0.2.0"
const val consoleWrapper = "1.0.0"
}
object Kotlin {

View File

@ -28,13 +28,35 @@ dependencies {
api(kotlin("reflect", Versions.Kotlin.stdlib))
api(kotlinx("coroutines-core", Versions.Kotlin.coroutines))
api(kotlinx("coroutines-swing",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"
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,3 +1,11 @@
/*
* 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
@ -14,15 +22,15 @@ const val CONSOLE_GRAPHICAL = "Graphical"
internal object ConsoleUpdater {
@Suppress("SpellCheckingInspection")
private object Links : HashMap<String, Map<String, String>>() {
private object Links : HashMap<ConsoleType, Map<String, String>>() {
init {
put(
CONSOLE_PURE, mapOf(
ConsoleType.Pure, mapOf(
"version" to "/net/mamoe/mirai-console/"
)
)
put(
CONSOLE_GRAPHICAL, mapOf(
ConsoleType.Graphical, mapOf(
"version" to "/net/mamoe/mirai-console-graphical/"
)
)
@ -30,23 +38,26 @@ internal object ConsoleUpdater {
}
var consoleType = CONSOLE_PURE
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) {
CONSOLE_PURE -> {
if(!file.name.contains("graphical")) {
ConsoleType.Pure -> {
if (!file.name.contains("graphical")) {
return file
}
}
CONSOLE_GRAPHICAL -> {
if(file.name.contains("graphical")) {
ConsoleType.Graphical -> {
if (file.name.contains("graphical")) {
return file
}
}
else -> {
}
}
}
}
@ -54,52 +65,35 @@ internal object ConsoleUpdater {
return null
}
suspend fun versionCheck(type: String) {
suspend fun versionCheck(type: ConsoleType, strategy: VersionUpdateStrategy) {
this.consoleType = type
println("Fetching Newest Console Version of $type")
val newest = getNewestVersion()
val current = getCurrentVersion()
println("Local Console-$type Version: $current | Newest Console-$type Version: $newest")
val current = CoreUpdater.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 is a force update")
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")
"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")
"https://pan.jasonczc.cn/?/mirai/${getProjectName()}/${getProjectName()}-$newest.mp4",
getContent("${getProjectName()}-$newest.jar")
)
}
}
private suspend fun getNewestVersion(): String {
try {
return """>([0-9])*\.([0-9])*\.([0-9])*/""".toRegex().findAll(
Http.get<String> {
url {
protocol = URLProtocol.HTTPS
host = "jcenter.bintray.com"
path(Links[consoleType]!!["version"] ?: error("Unknown Console Type"))
}
}
).asSequence()
.map { it.value.drop(1).dropLast(1) }
.maxBy {
it.split('.').foldRightIndexed(0) { index: Int, s: String, acc: Int ->
acc + 100.0.pow(2 - index).toInt() * (s.toIntOrNull() ?: 0)
}
}!!
} 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)
}
}
fun getCurrentVersion(): String {
val file = getFile()
if (file != null) {
@ -112,11 +106,70 @@ internal object ConsoleUpdater {
}
private fun getProjectName(): String {
return if (consoleType == CONSOLE_PURE) {
return if (consoleType == ConsoleType.Pure) {
"mirai-console"
} else {
"mirai-console-${consoleType.toLowerCase()}"
"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

@ -11,11 +11,7 @@
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
internal object CoreUpdater {
@ -29,13 +25,18 @@ internal object CoreUpdater {
}
suspend fun versionCheck() {
suspend fun versionCheck(strategy: VersionUpdateStrategy) {
println("Fetching Newest Core Version .. ")
val newest = getNewestVersion()
val current = getCurrentVersion()
println("Local Core Version: $current | Newest Core Version: $newest")
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 is a force update")
println("Updating shadowed-core from V$current -> V$newest")
this.getProtocolLib()?.delete()
MiraiDownloader
.addTask(
@ -47,33 +48,6 @@ internal object CoreUpdater {
}
}
/**
* 判断最新版本
* */
private suspend fun getNewestVersion(): String {
try {
return """>([0-9])*\.([0-9])*\.([0-9])*/""".toRegex().findAll(
Http.get<String> {
url {
protocol = URLProtocol.HTTPS
host = "jcenter.bintray.com"
path("net/mamoe/mirai-core-qqandroid/")
}
}).asSequence()
.map { it.value.drop(1).dropLast(1) }
.maxBy {
it.split('.').foldRightIndexed(0) { index: Int, s: String, acc: Int ->
acc + 100.0.pow(2 - index).toInt() * (s.toIntOrNull() ?: 0)
}
}!!
} catch (e: Exception) {
println("Failed to fetch newest Core version, please seek for help")
e.printStackTrace()
println("Failed to fetch newest Core version, please seek for help")
exitProcess(1)
}
}
/**
* 判断当前版本
* 默认返回 "0.0.0"

View File

@ -1,3 +1,11 @@
/*
* 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
@ -137,7 +145,6 @@ internal suspend fun ByteReadChannel.saveToContent(filepath: String) {
}
internal fun getContent(filepath: String):File{
return File(contentPath, filepath)
}

View File

@ -1,3 +1,11 @@
/*
* 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.*
@ -146,6 +154,7 @@ class MiraiDownloaderProgressBarInUI(): MiraiDownloadProgressBar{
override fun ad(){
WrapperMain.uiLog("[Mirai国内镜像] 感谢崔Cloud慷慨提供更新服务器")
}
private val barLen = 20
override fun update(rate: Float, message: String) {

View File

@ -10,11 +10,15 @@
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.*
import java.util.jar.JarFile
import javax.swing.JFrame
import javax.swing.JPanel
@ -34,19 +38,43 @@ val extendedLibraries by lazy {
file.also { if (!it.exists()) it.mkdirs() }
}
object WrapperMain {
internal var uiBarOutput = StringBuilder()
private val uilog = StringBuilder()
internal fun uiLog(any: Any?) {
if (any != null) {
uilog.append(any)
}
}
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)
@JvmStatic
fun main(args: Array<String>) {
gc()
if (args.contains("native") || args.contains("-native")) {
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)
@ -60,29 +88,29 @@ object WrapperMain {
f.isVisible = true
uiLog("正在进行版本检查\n")
WrapperMain.uiLog("正在进行版本检查\n")
val dic = System.getProperty("user.dir")
uiLog("工作目录: ${dic}\n")
uiLog("扩展库目录: ${extendedLibraries}\n")
uiLog("若无法启动, 请尝试清除工作目录下/content/文件夹\n")
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 = uilog.toString() + "\n" + uiBarOutput.toString()
textArea.text = WrapperMain.uiLog.toString() + "\n" + WrapperMain.uiBarOutput.toString()
}
}
}
runBlocking {
launch {
CoreUpdater.versionCheck()
CoreUpdater.versionCheck(update)
}
launch {
ConsoleUpdater.versionCheck(CONSOLE_GRAPHICAL)
ConsoleUpdater.versionCheck(ConsoleType.Graphical, update)
}
}
uiLog("版本检查完成, 启动中\n")
WrapperMain.uiLog("版本检查完成, 启动中\n")
runBlocking {
MiraiDownloader.downloadIfNeed(true)
@ -93,41 +121,61 @@ object WrapperMain {
f.isVisible = false
}
start(CONSOLE_GRAPHICAL)
WrapperMain.start(ConsoleType.Graphical)
} else {
preStartInNonNative()
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)
}
private fun preStartInNonNative() {
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 = WrapperProperties.determineConsoleType(WrapperProperties.content)
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 {
println("Please select Console Type")
println("请选择 Console 版本")
println("=> Pure : pure console")
println("=> Graphical : graphical UI except unix")
println("=> Terminal : [Not Supported Yet] console in unix")
val scanner = Scanner(System.`in`)
while (type == null) {
var input = scanner.next()
input = input.toUpperCase()[0] + input.toLowerCase().substring(1)
println("Selecting $input")
type = WrapperProperties.determineConsoleType(input)
}
WrapperProperties.content = type
WrapperProperties.content = defaultType.toString()
type = defaultType
}
println("Starting version check...")
runBlocking {
launch {
CoreUpdater.versionCheck()
CoreUpdater.versionCheck(strategy)
}
launch {
ConsoleUpdater.versionCheck(type)
ConsoleUpdater.versionCheck(type, strategy)
}
}
@ -143,7 +191,7 @@ object WrapperMain {
start(type)
}
private fun start(type: String) {
internal fun start(type: ConsoleType) {
val loader = MiraiClassLoader(
CoreUpdater.getProtocolLib()!!,
ConsoleUpdater.getFile()!!,
@ -152,12 +200,12 @@ object WrapperMain {
loader.loadClass("net.mamoe.mirai.BotFactoryJvm")
loader.loadClass(
when (type) {
CONSOLE_PURE -> "net.mamoe.mirai.console.pure.MiraiConsolePureLoader"
CONSOLE_GRAPHICAL -> "net.mamoe.mirai.console.graphical.MiraiConsoleGraphicalLoader"
else -> return
}
).getMethod("load", String::class.java, String::class.java)
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())
}
@ -211,16 +259,6 @@ private object WrapperProperties {
var content
get() = contentFile.readText()
set(value) = contentFile.writeText(value)
fun determineConsoleType(
type: String
): String? {
if (type == CONSOLE_PURE || type == CONSOLE_GRAPHICAL || type == CONSOLE_TERMINAL) {
return type
}
return null
}
}
private fun gc() {

View File

@ -0,0 +1,28 @@
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()
}