mirror of
https://github.com/mamoe/mirai.git
synced 2025-02-27 12:40:10 +08:00
[core] Code improvement
This commit is contained in:
parent
2ab424c989
commit
bf50e8a770
@ -18,51 +18,71 @@ import net.mamoe.mirai.internal.network.QRCodeLoginData
|
||||
import net.mamoe.mirai.internal.network.component.ComponentKey
|
||||
import net.mamoe.mirai.internal.network.handler.NetworkHandler
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.login.WtLogin
|
||||
import net.mamoe.mirai.utils.*
|
||||
import net.mamoe.mirai.internal.utils.MiraiProtocolInternal.Companion.asInternal
|
||||
import net.mamoe.mirai.utils.LoginSolver
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
import net.mamoe.mirai.utils.debug
|
||||
import net.mamoe.mirai.utils.toUHexString
|
||||
|
||||
internal interface QRCodeLoginProcessor {
|
||||
suspend fun process(handler: NetworkHandler, client: QQAndroidClient): QRCodeLoginData
|
||||
suspend fun process(handler: NetworkHandler, client: QQAndroidClient): QRCodeLoginData = error("Not implemented")
|
||||
|
||||
/**
|
||||
* Allocate a special processor for once login request
|
||||
*/
|
||||
fun prepareProcess(handler: NetworkHandler, client: QQAndroidClient): QRCodeLoginProcessor =
|
||||
error("Not implemented")
|
||||
|
||||
companion object : ComponentKey<QRCodeLoginProcessor> {
|
||||
internal val NOOP = object : QRCodeLoginProcessor {
|
||||
|
||||
override suspend fun process(handler: NetworkHandler, client: QQAndroidClient): QRCodeLoginData {
|
||||
error("NOOP")
|
||||
}
|
||||
}
|
||||
internal val NOOP = object : QRCodeLoginProcessor {}
|
||||
|
||||
//TODO: these exception should throw in network instead here.
|
||||
fun parse(ssoContext: SsoProcessorContext, logger: MiraiLogger): QRCodeLoginProcessor {
|
||||
if (!ssoContext.bot.configuration.qrCodeLogin) return NOOP
|
||||
check(ssoContext.bot.configuration.protocol == BotConfiguration.MiraiProtocol.ANDROID_WATCH) {
|
||||
if (!ssoContext.bot.configuration.doQRCodeLogin) return NOOP
|
||||
check(ssoContext.bot.configuration.protocol.asInternal.canDoQRCodeLogin) {
|
||||
"The login protocol must be ANDROID_WATCH while enabling qrcode login." +
|
||||
"Set it by `bot.configuration.protocol = BotConfiguration.MiraiProtocol.ANDROID_WATCH`."
|
||||
}
|
||||
val loginSolver = ssoContext.bot.configuration.loginSolver
|
||||
?: throw IllegalStateException("No LoginSolver found while enabling qrcode login. " +
|
||||
"Please provide by BotConfiguration.loginSolver. " +
|
||||
"For example use `BotFactory.newBot(...) { loginSolver = yourLoginSolver}` in Kotlin, " +
|
||||
"use `BotFactory.newBot(..., new BotConfiguration() {{ setLoginSolver(yourLoginSolver) }})` in Java.")
|
||||
val qrCodeLoginListener = loginSolver.qrCodeLoginListener
|
||||
?: throw IllegalStateException("No QRCodeLoginListener provided in LoginSolver while enabling qrcode login.")
|
||||
return QRCodeLoginProcessorImpl(qrCodeLoginListener, logger)
|
||||
return QRCodeLoginProcessorPreLoaded(ssoContext, logger)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class QRCodeLoginProcessorPreLoaded(
|
||||
private val ssoContext: SsoProcessorContext,
|
||||
private val logger: MiraiLogger,
|
||||
) : QRCodeLoginProcessor {
|
||||
override fun prepareProcess(handler: NetworkHandler, client: QQAndroidClient): QRCodeLoginProcessor {
|
||||
val loginSolver = ssoContext.bot.configuration.loginSolver
|
||||
?: throw IllegalStateException(
|
||||
"No LoginSolver found while enabling qrcode login. " +
|
||||
"Please provide by BotConfiguration.loginSolver. " +
|
||||
"For example use `BotFactory.newBot(...) { loginSolver = yourLoginSolver}` in Kotlin, " +
|
||||
"use `BotFactory.newBot(..., new BotConfiguration() {{ setLoginSolver(yourLoginSolver) }})` in Java."
|
||||
)
|
||||
|
||||
val qrCodeLoginListener = loginSolver.createQRCodeLoginListener(client.bot)
|
||||
|
||||
return QRCodeLoginProcessorImpl(qrCodeLoginListener, logger)
|
||||
}
|
||||
}
|
||||
|
||||
internal class QRCodeLoginProcessorImpl(
|
||||
private val listener: LoginSolver.QRCodeLoginListener,
|
||||
private val qrCodeLoginListener: LoginSolver.QRCodeLoginListener,
|
||||
private val logger: MiraiLogger,
|
||||
) : QRCodeLoginProcessor {
|
||||
|
||||
private val lock = Mutex(false)
|
||||
private var state by atomic(LoginSolver.QRCodeLoginListener.State.DEFAULT)
|
||||
private var state = atomic(LoginSolver.QRCodeLoginListener.State.DEFAULT)
|
||||
|
||||
private suspend fun requestQRCode(handler: NetworkHandler, client: QQAndroidClient) : WtLogin.TransEmp.TransEmpResponse.FetchQRCode {
|
||||
private suspend fun requestQRCode(
|
||||
handler: NetworkHandler,
|
||||
client: QQAndroidClient
|
||||
): WtLogin.TransEmp.TransEmpResponse.FetchQRCode {
|
||||
logger.debug { "requesting qrcode." }
|
||||
val resp = handler.sendAndExpect(WtLogin.TransEmp.FetchQRCode(client), attempts = 1)
|
||||
check(resp is WtLogin.TransEmp.TransEmpResponse.FetchQRCode) { "Cannot fetch qrcode, resp=$resp" }
|
||||
listener.onFetchQRCode(handler.context.bot, resp.imageData)
|
||||
qrCodeLoginListener.onFetchQRCode(handler.context.bot, resp.imageData)
|
||||
return resp
|
||||
}
|
||||
|
||||
@ -70,19 +90,20 @@ internal class QRCodeLoginProcessorImpl(
|
||||
handler: NetworkHandler,
|
||||
client: QQAndroidClient,
|
||||
sig: ByteArray
|
||||
) : WtLogin.TransEmp.TransEmpResponse {
|
||||
): WtLogin.TransEmp.TransEmpResponse {
|
||||
logger.debug { "querying qrcode state. sig=${sig.toUHexString()}" }
|
||||
val resp = handler.sendAndExpect(WtLogin.TransEmp.QueryQRCodeStatus(client, sig), attempts = 1, timeout = 500)
|
||||
|
||||
check(
|
||||
resp is WtLogin.TransEmp.TransEmpResponse.QRCodeStatus ||
|
||||
resp is WtLogin.TransEmp.TransEmpResponse.QRCodeConfirmed
|
||||
resp is WtLogin.TransEmp.TransEmpResponse.QRCodeStatus || resp is WtLogin.TransEmp.TransEmpResponse.QRCodeConfirmed
|
||||
) { "Cannot query qrcode status, resp=$resp" }
|
||||
|
||||
lock.withLock {
|
||||
val currState = resp.mapProtocolState()
|
||||
if (currState != state) {
|
||||
state = currState
|
||||
val currentState = state.value
|
||||
val newState = resp.mapProtocolState()
|
||||
if (currentState != newState && state.compareAndSet(currentState, newState)) {
|
||||
logger.debug { "qrcode state changed: $state" }
|
||||
listener.onStatusChanged(handler.context.bot, state)
|
||||
qrCodeLoginListener.onStatusChanged(handler.context.bot, newState)
|
||||
}
|
||||
}
|
||||
return resp
|
||||
@ -92,19 +113,21 @@ internal class QRCodeLoginProcessorImpl(
|
||||
main@ while (true) { // TODO: add new bot config property to set times of fetching qrcode
|
||||
val qrCodeData = requestQRCode(handler, client)
|
||||
state@ while (true) {
|
||||
when(val status = queryQRCodeStatus(handler, client, qrCodeData.sig)) {
|
||||
when (val status = queryQRCodeStatus(handler, client, qrCodeData.sig)) {
|
||||
is WtLogin.TransEmp.TransEmpResponse.QRCodeConfirmed -> {
|
||||
return status.data
|
||||
}
|
||||
is WtLogin.TransEmp.TransEmpResponse.QRCodeStatus -> when(status.state) {
|
||||
is WtLogin.TransEmp.TransEmpResponse.QRCodeStatus -> when (status.state) {
|
||||
WtLogin.TransEmp.TransEmpResponse.QRCodeStatus.State.TIMEOUT,
|
||||
WtLogin.TransEmp.TransEmpResponse.QRCodeStatus.State.CANCELLED -> {
|
||||
break@state
|
||||
}
|
||||
else -> { } // WAITING_FOR_SCAN or WAITING_FOR_CONFIRM
|
||||
else -> {} // WAITING_FOR_SCAN or WAITING_FOR_CONFIRM
|
||||
}
|
||||
// status is FetchQRCode, which is unreachable.
|
||||
else -> { error("query qrcode status packet should not be FetchQRCode.") }
|
||||
else -> {
|
||||
error("query qrcode status packet should not be FetchQRCode.")
|
||||
}
|
||||
}
|
||||
delay(5000)
|
||||
}
|
||||
@ -113,7 +136,7 @@ internal class QRCodeLoginProcessorImpl(
|
||||
|
||||
private fun WtLogin.TransEmp.TransEmpResponse.mapProtocolState(): LoginSolver.QRCodeLoginListener.State {
|
||||
return when (this) {
|
||||
is WtLogin.TransEmp.TransEmpResponse.QRCodeStatus -> when(this.state) {
|
||||
is WtLogin.TransEmp.TransEmpResponse.QRCodeStatus -> when (this.state) {
|
||||
WtLogin.TransEmp.TransEmpResponse.QRCodeStatus.State.WAITING_FOR_SCAN ->
|
||||
LoginSolver.QRCodeLoginListener.State.WAITING_FOR_SCAN
|
||||
|
||||
|
@ -165,7 +165,7 @@ internal class SsoProcessorImpl(
|
||||
|
||||
val qrCodeLoginProcessor = ssoContext.bot.components[QRCodeLoginProcessor]
|
||||
if (qrCodeLoginProcessor !== QRCodeLoginProcessor.NOOP) {
|
||||
val qrcodeLoginData = qrCodeLoginProcessor.process(handler, client)
|
||||
val qrcodeLoginData = qrCodeLoginProcessor.prepareProcess(handler, client).process(handler, client)
|
||||
SlowLoginImpl(handler, LoginType.QRCode(qrcodeLoginData)).doLogin()
|
||||
} else {
|
||||
SlowLoginImpl(handler, LoginType.Password).doLogin()
|
||||
@ -229,7 +229,7 @@ internal class SsoProcessorImpl(
|
||||
|
||||
private inner class SlowLoginImpl(
|
||||
handler: NetworkHandler,
|
||||
private val type: LoginType
|
||||
private val loginType: LoginType
|
||||
) : LoginStrategy(handler) {
|
||||
|
||||
private fun loginSolverNotNull(): LoginSolver {
|
||||
@ -270,14 +270,15 @@ internal class SsoProcessorImpl(
|
||||
|
||||
override suspend fun doLogin() = withExceptionCollector {
|
||||
|
||||
fun QQAndroidClient.getWtLogin9Packet(allowSlider: Boolean, type: LoginType) = when(type) {
|
||||
is LoginType.Password -> WtLogin9.Password(this, allowSlider)
|
||||
is LoginType.QRCode -> WtLogin9.QRCode(this, type.qrCodeLoginData)
|
||||
@Suppress("FunctionName")
|
||||
fun SSOWtLogin9(allowSlider: Boolean) = when (loginType) {
|
||||
is LoginType.Password -> WtLogin9.Password(client, allowSlider)
|
||||
is LoginType.QRCode -> WtLogin9.QRCode(client, loginType.qrCodeLoginData)
|
||||
}
|
||||
|
||||
var allowSlider = sliderSupported || bot.configuration.protocol == MiraiProtocol.ANDROID_PHONE
|
||||
|
||||
var response: LoginPacketResponse = client.getWtLogin9Packet(allowSlider, type).sendAndExpect()
|
||||
var response: LoginPacketResponse = SSOWtLogin9(allowSlider).sendAndExpect()
|
||||
|
||||
mainloop@ while (true) {
|
||||
when (response) {
|
||||
@ -297,7 +298,7 @@ internal class SsoProcessorImpl(
|
||||
check(result is DeviceVerificationResultImpl)
|
||||
response = when (result) {
|
||||
is UrlDeviceVerificationResult -> {
|
||||
client.getWtLogin9Packet(allowSlider, type).sendAndExpect()
|
||||
SSOWtLogin9(allowSlider).sendAndExpect()
|
||||
}
|
||||
|
||||
is SmsDeviceVerificationResult -> {
|
||||
@ -324,7 +325,7 @@ internal class SsoProcessorImpl(
|
||||
collectThrow(error)
|
||||
}
|
||||
response = if (ticket == null) {
|
||||
client.getWtLogin9Packet(allowSlider, type).sendAndExpect()
|
||||
SSOWtLogin9(allowSlider).sendAndExpect()
|
||||
} else {
|
||||
WtLogin2.SubmitSliderCaptcha(client, ticket).sendAndExpect()
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ internal class MiraiProtocolInternal(
|
||||
@JvmField internal val sign: String,
|
||||
@JvmField internal val buildTime: Long,
|
||||
@JvmField internal val ssoVersion: Int,
|
||||
@JvmField internal val canDoQRCodeLogin: Boolean = false,
|
||||
) {
|
||||
internal companion object {
|
||||
internal val protocols = EnumMap<MiraiProtocol, MiraiProtocolInternal>(MiraiProtocol::class)
|
||||
@ -70,6 +71,7 @@ internal class MiraiProtocolInternal(
|
||||
"A6 B7 45 BF 24 A2 C2 77 52 77 16 F6 F3 6E B6 8D",
|
||||
1559564731L,
|
||||
5,
|
||||
canDoQRCodeLogin = true,
|
||||
)
|
||||
protocols[MiraiProtocol.IPAD] = MiraiProtocolInternal(
|
||||
"com.tencent.minihd.qq",
|
||||
@ -96,5 +98,7 @@ internal class MiraiProtocolInternal(
|
||||
7,
|
||||
)
|
||||
}
|
||||
|
||||
inline val MiraiProtocol.asInternal: MiraiProtocolInternal get() = get(this)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user