Extract LoginCommand implementation and fix tests

This commit is contained in:
Him188 2022-03-16 16:04:10 +00:00
parent ab9c2ef2b2
commit 446cf84272
3 changed files with 131 additions and 80 deletions

View File

@ -9,7 +9,10 @@
package net.mamoe.mirai.console.command
import kotlinx.coroutines.*
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import net.mamoe.mirai.Bot
@ -25,15 +28,14 @@ import net.mamoe.mirai.console.command.descriptor.PermitteeIdValueArgumentParser
import net.mamoe.mirai.console.command.descriptor.buildCommandArgumentContext
import net.mamoe.mirai.console.extensions.PermissionServiceProvider
import net.mamoe.mirai.console.internal.MiraiConsoleBuildConstants
import net.mamoe.mirai.console.internal.command.builtin.LoginCommandImpl
import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig
import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig.Account.*
import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig.Account.PasswordKind.MD5
import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig.Account.PasswordKind.PLAIN
import net.mamoe.mirai.console.internal.data.builtins.DataScope
import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage
import net.mamoe.mirai.console.internal.permission.BuiltInPermissionService
import net.mamoe.mirai.console.internal.pluginManagerImpl
import net.mamoe.mirai.console.internal.util.autoHexToBytes
import net.mamoe.mirai.console.internal.util.runIgnoreException
import net.mamoe.mirai.console.permission.Permission
import net.mamoe.mirai.console.permission.Permission.Companion.parentsWithSelf
@ -46,15 +48,13 @@ import net.mamoe.mirai.console.permission.PermissionService.Companion.permit
import net.mamoe.mirai.console.permission.PermitteeId
import net.mamoe.mirai.console.plugin.name
import net.mamoe.mirai.console.plugin.version
import net.mamoe.mirai.console.util.*
import net.mamoe.mirai.console.util.AnsiMessageBuilder
import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import net.mamoe.mirai.console.util.ConsoleInternalApi
import net.mamoe.mirai.console.util.sendAnsiMessage
import net.mamoe.mirai.event.events.EventCancelledException
import net.mamoe.mirai.message.nextMessageOrNull
import net.mamoe.mirai.utils.BotConfiguration
import net.mamoe.mirai.utils.Either
import net.mamoe.mirai.utils.Either.Companion.flatMapNull
import net.mamoe.mirai.utils.Either.Companion.fold
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.secondsToMillis
import java.lang.management.ManagementFactory
import java.lang.management.MemoryUsage
import java.time.ZoneId
@ -187,16 +187,12 @@ public object BuiltInCommands {
}
}
private val loginCommandInstance = LoginCommandImpl()
public object LoginCommand : SimpleCommand(
ConsoleCommandOwner, "login", "登录",
description = "登录一个账号",
ConsoleCommandOwner, loginCommandInstance.primaryName, * loginCommandInstance.secondaryNames,
description = loginCommandInstance.description,
), BuiltInCommandInternal {
internal var doLogin: suspend Bot.() -> Bot = {
kotlin.runCatching {
login()
this
}.onFailure { close() }.getOrThrow()
} // workaround since LoginCommand is object
@Handler
@JvmOverloads
@ -205,48 +201,9 @@ public object BuiltInCommands {
password: String? = null,
protocol: BotConfiguration.MiraiProtocol? = null,
) {
fun BotConfiguration.setup(protocol: BotConfiguration.MiraiProtocol?): BotConfiguration {
if (protocol != null) this.protocol = protocol
return this
loginCommandInstance.run {
handle(id, password, protocol)
}
fun getPassword(id: Long): Either<ByteArray, String?> {
val config = DataScope.get<AutoLoginConfig>()
val acc = config.accounts.firstOrNull { it.account == id.toString() } ?: return Either.right(null)
val strv = acc.password.value
return if (acc.password.kind == MD5) Either.left(strv.autoHexToBytes()) else Either.right(strv)
}
val pwd = Either.right<ByteArray, String?>(password).flatMapNull { getPassword(id) }
kotlin.runCatching {
pwd.fold(
onLeft = { pass ->
MiraiConsole.addBot(id, pass) { setup(protocol) }.doLogin()
},
onRight = { pass ->
if (pass == null) {
sendMessage("Could not find '$id' in AutoLogin config. Please specify password.")
return
}
MiraiConsole.addBot(id, pass) { setup(protocol) }.doLogin()
}
)
}.fold(
onSuccess = { scopeWith(ConsoleCommandSender).sendMessage("${it.nick} ($id) Login successful") },
onFailure = { throwable ->
scopeWith(ConsoleCommandSender).sendMessage(
"Login failed: ${throwable.localizedMessage ?: throwable.message ?: throwable.toString()}" +
if (this is CommandSenderOnMessage<*>) {
MiraiConsole.launch(CoroutineName("stacktrace delayer from Login")) {
fromEvent.nextMessageOrNull(60.secondsToMillis) { it.message.contentEquals("stacktrace") }
}
"\n 1 分钟内发送 stacktrace 以获取堆栈信息"
} else ""
)
throw throwable
}
)
}
}

View File

@ -0,0 +1,91 @@
/*
* Copyright 2019-2022 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/dev/LICENSE
*/
package net.mamoe.mirai.console.internal.command.builtin
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.launch
import net.mamoe.mirai.Bot
import net.mamoe.mirai.console.MiraiConsole
import net.mamoe.mirai.console.MiraiConsoleImplementation.ConsoleDataScope.Companion.get
import net.mamoe.mirai.console.command.*
import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig
import net.mamoe.mirai.console.internal.data.builtins.DataScope
import net.mamoe.mirai.console.internal.util.autoHexToBytes
import net.mamoe.mirai.console.util.scopeWith
import net.mamoe.mirai.message.nextMessageOrNull
import net.mamoe.mirai.utils.BotConfiguration
import net.mamoe.mirai.utils.Either
import net.mamoe.mirai.utils.Either.Companion.flatMapNull
import net.mamoe.mirai.utils.Either.Companion.fold
import net.mamoe.mirai.utils.secondsToMillis
internal open class LoginCommandImpl : SimpleCommand(
ConsoleCommandOwner, "login", "登录",
description = "登录一个账号",
), BuiltInCommandInternal {
internal open suspend fun doLogin(bot: Bot) {
kotlin.runCatching {
bot.login()
this
}.onFailure { bot.close() }.getOrThrow()
} // workaround since LoginCommand is object
@Handler
suspend fun CommandSender.handle(
id: Long,
password: String? = null,
protocol: BotConfiguration.MiraiProtocol? = null,
) {
fun BotConfiguration.setup(protocol: BotConfiguration.MiraiProtocol?): BotConfiguration {
if (protocol != null) this.protocol = protocol
return this
}
fun getPassword(id: Long): Either<ByteArray, String?> {
val config = DataScope.get<AutoLoginConfig>()
val acc = config.accounts.firstOrNull { it.account == id.toString() } ?: return Either.right(null)
val strv = acc.password.value
return if (acc.password.kind == AutoLoginConfig.Account.PasswordKind.MD5) Either.left(strv.autoHexToBytes()) else Either.right(
strv
)
}
val pwd = Either.right<ByteArray, String?>(password).flatMapNull { getPassword(id) }
kotlin.runCatching {
pwd.fold(
onLeft = { pass ->
MiraiConsole.addBot(id, pass) { setup(protocol) }.also { doLogin(it) }
},
onRight = { pass ->
if (pass == null) {
sendMessage("Could not find '$id' in AutoLogin config. Please specify password.")
return
}
MiraiConsole.addBot(id, pass) { setup(protocol) }.also { doLogin(it) }
}
)
}.fold(
onSuccess = { scopeWith(ConsoleCommandSender).sendMessage("${it.nick} ($id) Login successful") },
onFailure = { throwable ->
scopeWith(ConsoleCommandSender).sendMessage(
"Login failed: ${throwable.localizedMessage ?: throwable.message ?: throwable.toString()}" +
if (this is CommandSenderOnMessage<*>) {
MiraiConsole.launch(CoroutineName("stacktrace delayer from Login")) {
fromEvent.nextMessageOrNull(60.secondsToMillis) { it.message.contentEquals("stacktrace") }
}
"\n 1 分钟内发送 stacktrace 以获取堆栈信息"
} else ""
)
throw throwable
}
)
}
}

View File

@ -13,11 +13,14 @@ package net.mamoe.mirai.console.command
import kotlinx.coroutines.CompletableDeferred
import me.him188.kotlin.jvm.blocking.bridge.JvmBlockingBridge
import net.mamoe.mirai.console.command.BuiltInCommands.LoginCommand
import net.mamoe.mirai.Bot
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.register
import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
import net.mamoe.mirai.console.internal.command.builtin.LoginCommandImpl
import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig
import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig.Account
import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig.Account.PasswordKind
import net.mamoe.mirai.internal.QQAndroidBot
import net.mamoe.mirai.utils.md5
import net.mamoe.mirai.utils.toUHexString
import org.junit.jupiter.api.Test
@ -33,14 +36,14 @@ internal class LoginCommandTest : AbstractCommandTest() {
val myId = 123L
val myPwd = "password001"
val bot = awaitDeferred<net.mamoe.mirai.internal.QQAndroidBot> { cont ->
LoginCommand.doLogin = {
val bot = bot as net.mamoe.mirai.internal.QQAndroidBot
cont.complete(bot)
bot
val bot = awaitDeferred<QQAndroidBot> { cont ->
val command = object : LoginCommandImpl() {
override suspend fun doLogin(bot: Bot) {
cont.complete(bot as QQAndroidBot)
}
}
LoginCommand.execute(consoleSender, "$myId $myPwd")
command.register(true)
command.execute(consoleSender, "$myId $myPwd")
}
val account = bot.account
@ -62,14 +65,14 @@ internal class LoginCommandTest : AbstractCommandTest() {
)
})
val bot = awaitDeferred<net.mamoe.mirai.internal.QQAndroidBot> { cont ->
LoginCommand.doLogin = {
val bot = bot as net.mamoe.mirai.internal.QQAndroidBot
cont.complete(bot)
bot
val bot = awaitDeferred<QQAndroidBot> { cont ->
val command = object : LoginCommandImpl() {
override suspend fun doLogin(bot: Bot) {
cont.complete(bot as QQAndroidBot)
}
}
LoginCommand.execute(consoleSender, "$myId")
command.register(true)
command.execute(consoleSender, "$myId")
}
val account = bot.account
@ -91,14 +94,14 @@ internal class LoginCommandTest : AbstractCommandTest() {
)
})
val bot = awaitDeferred<net.mamoe.mirai.internal.QQAndroidBot> { cont ->
LoginCommand.doLogin = {
val bot = bot as net.mamoe.mirai.internal.QQAndroidBot
cont.complete(bot)
bot
val bot = awaitDeferred<QQAndroidBot> { cont ->
val command = object : LoginCommandImpl() {
override suspend fun doLogin(bot: Bot) {
cont.complete(bot as QQAndroidBot)
}
}
LoginCommand.execute(consoleSender, "$myId")
command.register(true)
command.execute(consoleSender, "$myId")
}
val account = bot.account