Commit 146615e6 authored by Him188's avatar Him188

Change Bot to interface, implement Bot as BotImpl, fix #20

parent f3cbb6e4
......@@ -20,7 +20,6 @@ import net.mamoe.mirai.Bot
import net.mamoe.mirai.addFriend
import net.mamoe.mirai.contact.sendMessage
import net.mamoe.mirai.getGroup
import net.mamoe.mirai.getQQ
import net.mamoe.mirai.utils.io.hexToBytes
import net.mamoe.mirai.utils.io.hexToUBytes
......@@ -81,6 +80,7 @@ suspend inline fun ApplicationCall.ok() = this.respond(HttpStatusCode.OK, "OK")
/**
* 错误请求. 抛出这个异常后将会返回错误给一个请求
*/
@Suppress("unused")
open class IllegalAccessException : Exception {
override val message: String get() = super.message!!
......
@file:Suppress("EXPERIMENTAL_API_USAGE")
package net.mamoe.mirai
data class BotAccount(
val id: UInt,
val password: String
) {
constructor(id: Long, password: String) : this(id.toUInt(), password)
}
\ No newline at end of file
......@@ -68,15 +68,15 @@ Mirai 22:04:48 : Packet received: UnknownEventPacket(id=00 D6, identity=(2092749
* @param remark 好友备注
*/
@UseExperimental(ExperimentalContracts::class)
suspend fun Bot.ContactSystem.addFriend(id: UInt, message: String? = null, remark: String? = null): AddFriendResult = bot.withSession {
return when (CanAddFriendPacket(bot.qqAccount, id, bot.sessionKey).sendAndExpect<CanAddFriendResponse>()) {
suspend fun Bot.addFriend(id: UInt, message: String? = null, remark: String? = null): AddFriendResult = withSession {
return when (CanAddFriendPacket(qqAccount, id, sessionKey).sendAndExpect<CanAddFriendResponse>()) {
is CanAddFriendResponse.AlreadyAdded -> AddFriendResult.ALREADY_ADDED
is CanAddFriendResponse.Rejected -> AddFriendResult.REJECTED
is CanAddFriendResponse.ReadyToAdd,
is CanAddFriendResponse.RequireVerification -> {
val key = RequestFriendAdditionKeyPacket(bot.qqAccount, id, sessionKey).sendAndExpect<RequestFriendAdditionKeyPacket.Response>().key
AddFriendPacket.RequestAdd(bot.qqAccount, id, sessionKey, message, remark, key).sendAndExpect<AddFriendPacket.Response>()
val key = RequestFriendAdditionKeyPacket(qqAccount, id, sessionKey).sendAndExpect<RequestFriendAdditionKeyPacket.Response>().key
AddFriendPacket.RequestAdd(qqAccount, id, sessionKey, message, remark, key).sendAndExpect<AddFriendPacket.Response>()
AddFriendResult.WAITING_FOR_APPROVE
} //这个做的是需要验证消息的情况, 不确定 ReadyToAdd 的是啥
......@@ -87,7 +87,7 @@ suspend fun Bot.ContactSystem.addFriend(id: UInt, message: String? = null, remar
/*is CanAddFriendResponse.ReadyToAdd -> {
// TODO: 2019/11/11 这不需要验证信息的情况
//AddFriendPacket(bot.qqAccount, id, bot.sessionKey, ).sendAndExpectAsync<AddFriendPacket.Response>().await()
//AddFriendPacket(qqAccount, id, sessionKey, ).sendAndExpectAsync<AddFriendPacket.Response>().await()
TODO()
}*/
}
......
......@@ -26,25 +26,8 @@ import kotlin.jvm.JvmOverloads
*/
//Contacts
inline fun Bot.getQQ(@PositiveNumbers number: Long): QQ = this.contacts.getQQ(number)
inline fun Bot.getQQ(number: UInt): QQ = this.contacts.getQQ(number)
suspend inline fun Bot.getGroup(id: UInt): Group = this.getGroup(GroupId(id))
suspend inline fun Bot.getGroup(id: UInt): Group = this.contacts.getGroup(GroupId(id))
suspend inline fun Bot.getGroup(@PositiveNumbers id: Long): Group =
this.contacts.getGroup(GroupId(id.coerceAtLeastOrFail(0).toUInt()))
suspend inline fun Bot.getGroup(id: GroupId): Group = this.contacts.getGroup(id)
suspend inline fun Bot.getGroup(internalId: GroupInternalId): Group = this.contacts.getGroup(internalId)
/**
* 取得群列表
*/
inline val Bot.groups: ContactList<Group> get() = this.contacts.groups
/**
* 取得好友列表
*/
inline val Bot.qqs: ContactList<QQ> get() = this.contacts.qqs
/**
* 以 [BotSession] 作为接收器 (receiver) 并调用 [block], 返回 [block] 的返回值.
......@@ -107,14 +90,6 @@ suspend inline fun Bot.alsoLogin(message: String): Bot {
}
}
/**
* 添加好友
*/
@UseExperimental(ExperimentalContracts::class)
@JvmOverloads
suspend inline fun Bot.addFriend(id: UInt, message: String? = null, remark: String? = null): AddFriendResult =
contacts.addFriend(id, message, remark)
/**
* 取得机器人的 QQ 号
*/
......
@file:Suppress("EXPERIMENTAL_API_USAGE")
package net.mamoe.mirai
import kotlinx.coroutines.*
import net.mamoe.mirai.contact.*
import net.mamoe.mirai.contact.internal.Group
import net.mamoe.mirai.contact.internal.QQ
import net.mamoe.mirai.network.BotNetworkHandler
import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler
import net.mamoe.mirai.network.protocol.tim.packet.KnownPacketId
import net.mamoe.mirai.network.protocol.tim.packet.action.GroupNotFound
import net.mamoe.mirai.network.protocol.tim.packet.action.GroupPacket
import net.mamoe.mirai.network.protocol.tim.packet.action.RawGroupInfo
import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult
import net.mamoe.mirai.network.protocol.tim.packet.login.isSuccess
import net.mamoe.mirai.network.qqAccount
import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.internal.PositiveNumbers
import net.mamoe.mirai.utils.internal.coerceAtLeastOrFail
import net.mamoe.mirai.utils.io.inline
import net.mamoe.mirai.utils.io.logStacktrace
import kotlin.coroutines.CoroutineContext
import kotlin.jvm.JvmSynthetic
@PublishedApi
internal class BotImpl @PublishedApi internal constructor(
override val account: BotAccount,
override val logger: MiraiLogger = DefaultLogger("Bot(" + account.id + ")"),
context: CoroutineContext
) : Bot, CoroutineScope {
private val supervisorJob = SupervisorJob(context[Job])
override val coroutineContext: CoroutineContext =
context + supervisorJob + CoroutineExceptionHandler { _, e -> e.logStacktrace("An exception was thrown under a coroutine of Bot") }
init {
launch {
instances.addLast(this@BotImpl)
}
}
companion object {
init {
KnownPacketId.values() /* load id classes */
}
@PublishedApi
internal val instances: LockFreeLinkedList<Bot> = LockFreeLinkedList()
inline fun forEachInstance(block: (Bot) -> Unit) = instances.forEach(block)
fun instanceWhose(qq: UInt): Bot {
instances.forEach {
if (it.qqAccount == qq) {
return it
}
}
throw NoSuchElementException()
}
}
override fun toString(): String = "Bot(${account.id})"
// region network
override val network: BotNetworkHandler<*> get() = _network
private lateinit var _network: BotNetworkHandler<*>
override fun tryReinitializeNetworkHandler(// shouldn't be suspend!! This function MUST NOT inherit the context from the caller because the caller(NetworkHandler) is going to close
configuration: BotConfiguration,
cause: Throwable?
): Job = launch {
repeat(configuration.reconnectionRetryTimes) {
if (reinitializeNetworkHandlerAsync(configuration, cause).await().isSuccess()) {
logger.info("Reconnected successfully")
return@launch
} else {
delay(configuration.reconnectPeriodMillis)
}
}
}
override suspend fun reinitializeNetworkHandler(
configuration: BotConfiguration,
cause: Throwable?
): LoginResult {
logger.info("BotAccount: ${qqAccount.toLong()}")
logger.info("Initializing BotNetworkHandler")
try {
if (::_network.isInitialized) {
_network.close(cause)
}
} catch (e: Exception) {
logger.error("Cannot close network handler", e)
}
_network = TIMBotNetworkHandler(this.coroutineContext + configuration, this)
return _network.login()
}
override fun reinitializeNetworkHandlerAsync(
configuration: BotConfiguration,
cause: Throwable?
): Deferred<LoginResult> = async { reinitializeNetworkHandler(configuration, cause) }
// endregion
// region contacts
@UseExperimental(MiraiInternalAPI::class)
override val groups: ContactList<Group> = ContactList(MutableContactList())
@UseExperimental(MiraiInternalAPI::class)
override val qqs: ContactList<QQ> = ContactList(MutableContactList())
/**
* 线程安全地获取缓存的 QQ 对象. 若没有对应的缓存, 则会创建一个.
*/
@UseExperimental(MiraiInternalAPI::class)
@JvmSynthetic
override fun getQQ(id: UInt): QQ = qqs.delegate.getOrAdd(id) { QQ(this, id, coroutineContext) }
// NO INLINE!! to help Java
@UseExperimental(MiraiInternalAPI::class)
override fun getQQ(@PositiveNumbers id: Long): QQ = getQQ(id.coerceAtLeastOrFail(0).toUInt())
override suspend fun getGroup(internalId: GroupInternalId): Group = getGroup(internalId.toId())
@UseExperimental(MiraiInternalAPI::class, ExperimentalUnsignedTypes::class)
override suspend fun getGroup(id: GroupId): Group = groups.delegate.getOrNull(id.value) ?: inline {
val info: RawGroupInfo = try {
when (val response =
withSession { GroupPacket.QueryGroupInfo(qqAccount, id.toInternalId(), sessionKey).sendAndExpect<GroupPacket.InfoResponse>() }) {
is RawGroupInfo -> response
is GroupNotFound -> throw GroupNotFoundException("id=${id.value.toLong()}")
else -> assertUnreachable()
}
} catch (e: Exception) {
throw IllegalStateException("Cannot obtain group info for id ${id.value.toLong()}", e)
}
return groups.delegate.getOrAdd(id.value) { Group(this, id, info, coroutineContext) }
}
// NO INLINE!! to help Java
@UseExperimental(MiraiInternalAPI::class)
override suspend fun getGroup(@PositiveNumbers id: Long): Group = id.coerceAtLeastOrFail(0).toUInt().let {
groups.delegate.getOrNull(it) ?: inline {
val info: RawGroupInfo = try {
withSession { GroupPacket.QueryGroupInfo(qqAccount, GroupId(it).toInternalId(), sessionKey).sendAndExpect() }
} catch (e: Exception) {
e.logStacktrace()
error("Cannot obtain group info for id ${it.toLong()}")
}
return groups.delegate.getOrAdd(it) { Group(this, GroupId(it), info, coroutineContext) }
}
}
// endregion
@UseExperimental(MiraiInternalAPI::class)
override fun close() {
_network.close()
this.supervisorJob.complete()
groups.delegate.clear()
qqs.delegate.clear()
}
}
......@@ -85,7 +85,7 @@ internal data class GroupImpl internal constructor(override val bot: Bot, val gr
}
@Suppress("FunctionName", "NOTHING_TO_INLINE")
inline fun CoroutineScope.QQ(bot: Bot, id: UInt, coroutineContext: CoroutineContext): QQ = QQImpl(bot, id, coroutineContext).apply { launch { startUpdater() } }
internal inline fun CoroutineScope.QQ(bot: Bot, id: UInt, coroutineContext: CoroutineContext): QQ = QQImpl(bot, id, coroutineContext).apply { launch { startUpdater() } }
@PublishedApi
internal data class QQImpl @PublishedApi internal constructor(override val bot: Bot, override val id: UInt, override val coroutineContext: CoroutineContext) :
......@@ -115,7 +115,7 @@ internal data class QQImpl @PublishedApi internal constructor(override val bot:
}
@Suppress("FunctionName", "NOTHING_TO_INLINE")
inline fun Group.Member(delegate: QQ, permission: MemberPermission, coroutineContext: CoroutineContext): Member =
internal inline fun Group.Member(delegate: QQ, permission: MemberPermission, coroutineContext: CoroutineContext): Member =
MemberImpl(delegate, this, permission, coroutineContext).apply { launch { startUpdater() } }
/**
......
......@@ -7,7 +7,6 @@ import kotlinx.io.core.discardExact
import kotlinx.io.core.readUByte
import kotlinx.io.core.readUInt
import net.mamoe.mirai.contact.QQ
import net.mamoe.mirai.getQQ
import net.mamoe.mirai.network.BotNetworkHandler
import net.mamoe.mirai.network.protocol.tim.packet.KnownPacketId
import net.mamoe.mirai.network.protocol.tim.packet.PacketId
......
......@@ -13,7 +13,6 @@ import net.mamoe.mirai.contact.internal.MemberImpl
import net.mamoe.mirai.event.Subscribable
import net.mamoe.mirai.event.broadcast
import net.mamoe.mirai.getGroup
import net.mamoe.mirai.getQQ
import net.mamoe.mirai.network.BotNetworkHandler
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.io.discardExact
......
......@@ -76,8 +76,7 @@ sealed class UnmuteEvent : EventOfMute() {
// endregion
@Suppress("ClassName")
internal object `Unknown0x02DCPacket_falg=0x0E_MaybeMutePacket` : EventOfMute() {
internal object Unknown0x02DCPacketFlag0x0EMaybeMutePacket : EventOfMute() {
override val operator: Member get() = error("Getting a field from Unknown0x02DCPacket_MaybeMutePacket")
override val group: Group get() = error("Getting a field from Unknown0x02DCPacket_MaybeMutePacket")
override fun toString(): String = "`Unknown0x02DCPacket_falg=0x0E_MaybeMutePacket`"
......@@ -124,7 +123,7 @@ internal object MemberMuteEventPacketParserAndHandler : KnownEventParserAndHandl
0x0Eu -> {
//00 00 00 0E 00 08 00 02 00 01 00
// 0A 00 04 01 00 00 00 35 DB 60 A2 11 00 3E 08 07 20 A2 C1 ED AE 03 5A 34 08 A2 FF 8C F0 03 1A 19 08 F4 0E 10 FE 8C D3 EF 05 18 84 A1 F8 F9 06 20 00 28 00 30 A2 FF 8C F0 03 2A 0D 08 00 12 09 08 F4 0E 10 00 18 01 20 00 30 00 38 00
`Unknown0x02DCPacket_falg=0x0E_MaybeMutePacket`
Unknown0x02DCPacketFlag0x0EMaybeMutePacket
}
0x11u -> {
......
......@@ -11,7 +11,6 @@ import net.mamoe.mirai.contact.*
import net.mamoe.mirai.event.BroadcastControllable
import net.mamoe.mirai.event.events.BotEvent
import net.mamoe.mirai.getGroup
import net.mamoe.mirai.getQQ
import net.mamoe.mirai.message.*
import net.mamoe.mirai.message.internal.readMessageChain
import net.mamoe.mirai.network.protocol.tim.packet.PacketVersion
......
......@@ -2,6 +2,8 @@
package net.mamoe.mirai.utils
import net.mamoe.mirai.contact.Group
/**
* 在获取 [Group] 对象等操作时可能出现的异常
*/
......
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