Commit b9eacbcf authored by jiahua.liu's avatar jiahua.liu

Merge remote-tracking branch 'origin/master'

parents ef9938a0 b28a786e
...@@ -26,6 +26,9 @@ internal class QQImpl(bot: QQAndroidBot, override val coroutineContext: Coroutin ...@@ -26,6 +26,9 @@ internal class QQImpl(bot: QQAndroidBot, override val coroutineContext: Coroutin
TODO("not implemented") TODO("not implemented")
} }
override val isOnline: Boolean
get() = true
override suspend fun queryProfile(): Profile { override suspend fun queryProfile(): Profile {
TODO("not implemented") TODO("not implemented")
} }
...@@ -40,11 +43,16 @@ internal class QQImpl(bot: QQAndroidBot, override val coroutineContext: Coroutin ...@@ -40,11 +43,16 @@ internal class QQImpl(bot: QQAndroidBot, override val coroutineContext: Coroutin
} }
internal class MemberImpl(bot: QQAndroidBot, group: Group, override val coroutineContext: CoroutineContext, override val id: Long) : ContactImpl(), Member { internal class MemberImpl(
override val group: Group by group.unsafeWeakRef() qq: QQImpl,
group: GroupImpl,
override val coroutineContext: CoroutineContext
) : ContactImpl(), Member, QQ by qq {
override val group: GroupImpl by group.unsafeWeakRef()
val qq: QQImpl by qq.unsafeWeakRef()
override val permission: MemberPermission override val permission: MemberPermission
get() = TODO("not implemented") get() = TODO("not implemented")
override val bot: QQAndroidBot by bot.unsafeWeakRef()
override suspend fun mute(durationSeconds: Int): Boolean { override suspend fun mute(durationSeconds: Int): Boolean {
TODO("not implemented") TODO("not implemented")
...@@ -54,26 +62,6 @@ internal class MemberImpl(bot: QQAndroidBot, group: Group, override val coroutin ...@@ -54,26 +62,6 @@ internal class MemberImpl(bot: QQAndroidBot, group: Group, override val coroutin
TODO("not implemented") TODO("not implemented")
} }
override suspend fun queryProfile(): Profile {
TODO("not implemented")
}
override suspend fun queryPreviousNameList(): PreviousNameList {
TODO("not implemented")
}
override suspend fun queryRemark(): FriendNameRemark {
TODO("not implemented")
}
override suspend fun sendMessage(message: MessageChain) {
TODO("not implemented")
}
override suspend fun uploadImage(image: ExternalImage): ImageId {
TODO("not implemented")
}
} }
...@@ -89,7 +77,7 @@ internal class GroupImpl(bot: QQAndroidBot, override val coroutineContext: Corou ...@@ -89,7 +77,7 @@ internal class GroupImpl(bot: QQAndroidBot, override val coroutineContext: Corou
override val members: ContactList<Member> = ContactList(LockFreeLinkedList()) override val members: ContactList<Member> = ContactList(LockFreeLinkedList())
override fun getMember(id: Long): Member = override fun getMember(id: Long): Member =
members.delegate.filteringGetOrAdd({ it.id == id }, { MemberImpl(bot as QQAndroidBot, this, coroutineContext, id) }) members.delegate.filteringGetOrAdd({ it.id == id }, { MemberImpl(bot.getQQ(id) as QQImpl, this, coroutineContext) })
override suspend fun updateGroupInfo(): GroupInfo { override suspend fun updateGroupInfo(): GroupInfo {
TODO("not implemented") TODO("not implemented")
......
...@@ -14,17 +14,11 @@ import net.mamoe.mirai.event.broadcast ...@@ -14,17 +14,11 @@ import net.mamoe.mirai.event.broadcast
import net.mamoe.mirai.network.BotNetworkHandler import net.mamoe.mirai.network.BotNetworkHandler
import net.mamoe.mirai.qqandroid.QQAndroidBot import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.event.PacketReceivedEvent import net.mamoe.mirai.qqandroid.event.PacketReceivedEvent
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.GetFriendListReq import net.mamoe.mirai.qqandroid.network.protocol.packet.*
import net.mamoe.mirai.qqandroid.network.protocol.packet.KnownPacketFactories
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory
import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketLogger
import net.mamoe.mirai.qqandroid.network.protocol.packet.list.FriendList
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.LoginPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.login.LoginPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.LoginPacket.LoginPacketResponse.* import net.mamoe.mirai.qqandroid.network.protocol.packet.login.LoginPacket.LoginPacketResponse.*
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.StatSvc import net.mamoe.mirai.qqandroid.network.protocol.packet.login.StatSvc
import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.cryptor.contentToString
import net.mamoe.mirai.utils.io.* import net.mamoe.mirai.utils.io.*
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
...@@ -56,7 +50,9 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -56,7 +50,9 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
is Captcha -> when (response) { is Captcha -> when (response) {
is Captcha.Picture -> { is Captcha.Picture -> {
var result = bot.configuration.loginSolver.onSolvePicCaptcha(bot, response.data) var result = response.data.withUse {
bot.configuration.loginSolver.onSolvePicCaptcha(bot, this)
}
if (result == null || result.length != 4) { if (result == null || result.length != 4) {
//refresh captcha //refresh captcha
result = "ABCD" result = "ABCD"
...@@ -325,19 +321,33 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -325,19 +321,33 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
/** /**
* 发送一个包, 并挂起直到接收到指定的返回包或超时(3000ms) * 发送一个包, 并挂起直到接收到指定的返回包或超时(3000ms)
*/ */
suspend fun <E : Packet> OutgoingPacket.sendAndExpect(timoutMillis: Long = 3000): E { suspend fun <E : Packet> OutgoingPacket.sendAndExpect(timeoutMillis: Long = 3000, retry: Int = 1): E {
require(timeoutMillis > 0) { "timeoutMillis must > 0" }
require(retry >= 0) { "retry must >= 0" }
val handler = PacketListener(commandName = commandName, sequenceId = sequenceId) val handler = PacketListener(commandName = commandName, sequenceId = sequenceId)
packetListeners.addLast(handler) packetListeners.addLast(handler)
bot.logger.info("Send: ${this.commandName}") bot.logger.info("Send: ${this.commandName}")
var lastException: Exception? = null
repeat(retry + 1) {
try {
return doSendAndReceive(timeoutMillis, handler)
} catch (e: Exception) {
lastException = e
}
}
throw lastException!!
}
private suspend inline fun <E : Packet> OutgoingPacket.doSendAndReceive(timeoutMillis: Long = 3000, handler: PacketListener): E {
channel.send(delegate) channel.send(delegate)
return withTimeoutOrNull(timoutMillis) { return withTimeoutOrNull(timeoutMillis) {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
handler.await() as E handler.await() as E
// 不要 `withTimeout`. timeout 的异常会不知道去哪了. // 不要 `withTimeout`. timeout 的异常会不知道去哪了.
} ?: net.mamoe.mirai.qqandroid.utils.inline { } ?: net.mamoe.mirai.qqandroid.utils.inline {
packetListeners.remove(handler) packetListeners.remove(handler)
error("timeout when sending ${commandName}") error("timeout when sending $commandName")
} }
} }
......
...@@ -139,6 +139,9 @@ internal class QQImpl @PublishedApi internal constructor(bot: TIMPCBot, override ...@@ -139,6 +139,9 @@ internal class QQImpl @PublishedApi internal constructor(bot: TIMPCBot, override
} }
} }
override val isOnline: Boolean
get() = true
override suspend fun queryProfile(): Profile = withTIMPCBot { override suspend fun queryProfile(): Profile = withTIMPCBot {
RequestProfileDetailsPacket(bot.uin, id, sessionKey).sendAndExpect<RequestProfileDetailsResponse>().profile RequestProfileDetailsPacket(bot.uin, id, sessionKey).sendAndExpect<RequestProfileDetailsResponse>().profile
} }
......
...@@ -15,12 +15,7 @@ actual var defaultLoginSolver: LoginSolver = object : LoginSolver() { ...@@ -15,12 +15,7 @@ actual var defaultLoginSolver: LoginSolver = object : LoginSolver() {
error("should be implemented manually by you") error("should be implemented manually by you")
} }
override suspend fun onGetPhoneNumber(): String { override suspend fun onSolveUnsafeDeviceLoginVerify(bot: Bot, url: String): String? {
error("should be implemented manually by you") error("should be implemented manually by you")
} }
override suspend fun onGetSMSVerifyCode(): String {
error("should be implemented manually by you")
}
} }
\ No newline at end of file
...@@ -34,6 +34,14 @@ actual class PlatformSocket : Closeable { ...@@ -34,6 +34,14 @@ actual class PlatformSocket : Closeable {
@PublishedApi @PublishedApi
internal lateinit var readChannel: ByteReadChannel internal lateinit var readChannel: ByteReadChannel
actual suspend inline fun send(packet: ByteArray, offset: Int, length: Int) {
try {
writeChannel.writeFully(packet, offset, length)
} catch (e: Exception) {
throw SendPacketInternalException(e)
}
}
/** /**
* @throws SendPacketInternalException * @throws SendPacketInternalException
*/ */
......
...@@ -98,7 +98,15 @@ abstract class BotImpl<N : BotNetworkHandler> constructor( ...@@ -98,7 +98,15 @@ abstract class BotImpl<N : BotNetworkHandler> constructor(
} }
_network = createNetworkHandler(this.coroutineContext) _network = createNetworkHandler(this.coroutineContext)
_network.login() while (true){
try {
return _network.login()
} catch (e: Exception){
e.logStacktrace("Exception when login")
}
delay(3000)
logger.warning("Login failed. Retrying in 3s...")
}
} }
protected abstract fun createNetworkHandler(coroutineContext: CoroutineContext): N protected abstract fun createNetworkHandler(coroutineContext: CoroutineContext): N
......
...@@ -13,6 +13,7 @@ interface Member : QQ, Contact { ...@@ -13,6 +13,7 @@ interface Member : QQ, Contact {
/** /**
* 所在的群 * 所在的群
*/ */
@WeakRefProperty
val group: Group val group: Group
/** /**
......
...@@ -21,6 +21,11 @@ import net.mamoe.mirai.data.Profile ...@@ -21,6 +21,11 @@ import net.mamoe.mirai.data.Profile
* @author Him188moe * @author Him188moe
*/ */
interface QQ : Contact, CoroutineScope { interface QQ : Contact, CoroutineScope {
/**
* 是否在线. 这个属性的值将会与服务器同步更新.
*/
val isOnline: Boolean
/** /**
* 请求头像下载链接 * 请求头像下载链接
*/ */
......
...@@ -12,6 +12,11 @@ import net.mamoe.mirai.utils.MiraiInternalAPI ...@@ -12,6 +12,11 @@ import net.mamoe.mirai.utils.MiraiInternalAPI
expect class PlatformSocket() : Closeable { expect class PlatformSocket() : Closeable {
suspend fun connect(serverHost: String, serverPort: Int) suspend fun connect(serverHost: String, serverPort: Int)
/**
* @throws SendPacketInternalException
*/
suspend inline fun send(packet: ByteArray, offset: Int = 0, length: Int = packet.size - offset)
/** /**
* @throws SendPacketInternalException * @throws SendPacketInternalException
*/ */
......
...@@ -29,8 +29,7 @@ actual var defaultLoginSolver: LoginSolver = DefaultLoginSolver() ...@@ -29,8 +29,7 @@ actual var defaultLoginSolver: LoginSolver = DefaultLoginSolver()
class DefaultLoginSolver : LoginSolver() { class DefaultLoginSolver : LoginSolver() {
override suspend fun onSolvePicCaptcha(bot: Bot, data: IoBuffer): String? { override suspend fun onSolvePicCaptcha(bot: Bot, data: IoBuffer): String? = loginSolverLock.withLock {
loginSolverLock.withLock {
val tempFile: File = createTempFile(suffix = ".png").apply { deleteOnExit() } val tempFile: File = createTempFile(suffix = ".png").apply { deleteOnExit() }
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
tempFile.createNewFile() tempFile.createNewFile()
...@@ -53,12 +52,11 @@ class DefaultLoginSolver : LoginSolver() { ...@@ -53,12 +52,11 @@ class DefaultLoginSolver : LoginSolver() {
} }
bot.logger.info("请输入 4 位字母验证码. 若要更换验证码, 请直接回车") bot.logger.info("请输入 4 位字母验证码. 若要更换验证码, 请直接回车")
return readLine()?.takeUnless { it.isEmpty() || it.length != 4 }.also { return readLine()?.takeUnless { it.isEmpty() || it.length != 4 }.also {
bot.logger.info("正在提交[" + it +"]中...") bot.logger.info("正在提交[$it]中...")
}
} }
} }
override suspend fun onSolveSliderCaptcha(bot: Bot, url: String): String? { override suspend fun onSolveSliderCaptcha(bot: Bot, url: String): String? = loginSolverLock.withLock {
bot.logger.info("需要滑动验证码") bot.logger.info("需要滑动验证码")
bot.logger.info("请在任意浏览器中打开以下链接并完成验证码. ") bot.logger.info("请在任意浏览器中打开以下链接并完成验证码. ")
bot.logger.info("完成后请输入任意字符 ") bot.logger.info("完成后请输入任意字符 ")
...@@ -68,7 +66,7 @@ class DefaultLoginSolver : LoginSolver() { ...@@ -68,7 +66,7 @@ class DefaultLoginSolver : LoginSolver() {
} }
} }
override suspend fun onSolveUnsafeDeviceLoginVerify(bot: Bot, url: String): String? { override suspend fun onSolveUnsafeDeviceLoginVerify(bot: Bot, url: String): String? = loginSolverLock.withLock {
bot.logger.info("需要进行账户安全认证") bot.logger.info("需要进行账户安全认证")
bot.logger.info("该账户有[设备锁]/[不常用登陆地点]/[不常用设备登陆]的问题") bot.logger.info("该账户有[设备锁]/[不常用登陆地点]/[不常用设备登陆]的问题")
bot.logger.info("完成以下账号认证即可成功登陆|理论本认证在mirai每个账户中最多出现1次") bot.logger.info("完成以下账号认证即可成功登陆|理论本认证在mirai每个账户中最多出现1次")
......
...@@ -34,6 +34,14 @@ actual class PlatformSocket : Closeable { ...@@ -34,6 +34,14 @@ actual class PlatformSocket : Closeable {
@PublishedApi @PublishedApi
internal lateinit var readChannel: ByteReadChannel internal lateinit var readChannel: ByteReadChannel
actual suspend inline fun send(packet: ByteArray, offset: Int, length: Int) {
try {
writeChannel.writeFully(packet, offset, length)
} catch (e: Exception) {
throw SendPacketInternalException(e)
}
}
/** /**
* @throws SendPacketInternalException * @throws SendPacketInternalException
*/ */
......
...@@ -57,11 +57,7 @@ class MiraiService : Service() { ...@@ -57,11 +57,7 @@ class MiraiService : Service() {
TODO("not implemented") TODO("not implemented")
} }
override suspend fun onGetPhoneNumber(): String { override suspend fun onSolveUnsafeDeviceLoginVerify(bot: Bot, url: String): String? {
TODO("not implemented")
}
override suspend fun onGetSMSVerifyCode(): String {
TODO("not implemented") TODO("not implemented")
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment