Use groupCode as primary key

This commit is contained in:
Him188 2020-02-03 02:45:40 +08:00
parent d9e5805255
commit 8c69eefcde
16 changed files with 70 additions and 111 deletions

View File

@ -77,7 +77,7 @@ internal class MemberImpl(
internal class GroupImpl(
bot: QQAndroidBot, override val coroutineContext: CoroutineContext,
override val id: Long,
override val groupCode: Long,
val uin: Long,
override var name: String,
override var announcement: String,
override var members: ContactList<Member>

View File

@ -51,13 +51,13 @@ internal abstract class QQAndroidBotBase constructor(
override val groups: ContactList<Group> = ContactList(LockFreeLinkedList())
override fun getGroupByID(id: Long): Group {
return groups.delegate.getOrNull(id) ?: throw NoSuchElementException("Can not found group with ID=${id}")
fun getGroupByUin(uin: Long): Group {
return groups.delegate.filteringGetOrNull { (it as GroupImpl).uin == uin } ?: throw NoSuchElementException("Can not found group with ID=${uin}")
}
override fun getGroupByGroupCode(groupCode: Long): Group {
return groups.delegate.filteringGetOrNull { it.groupCode == groupCode }
?: throw NoSuchElementException("Can not found group with GroupCode=${groupCode}")
override fun getGroup(id: Long): Group {
return groups.delegate.getOrNull(id)
?: throw NoSuchElementException("Can not found group with GroupCode=${id}")
}
override suspend fun addFriend(id: Long, message: String?, remark: String?): AddFriendResult {

View File

@ -31,7 +31,6 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.login.StatSvc
import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.io.*
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.jvm.Volatile
@Suppress("MemberVisibilityCanBePrivate")
@ -103,13 +102,11 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
}
}
// println("d2key=${bot.client.wLoginSigInfo.d2Key.toUHexString()}")
StatSvc.Register(bot.client).sendAndExpect<StatSvc.Register.Response>(6000)
// println("d2key=${bot.client.wLoginSigInfo.d2Key.toUHexString()}")
StatSvc.Register(bot.client).sendAndExpect<StatSvc.Register.Response>(6000) // it's slow
}
override suspend fun init() {
MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendWithoutExpect()
this@QQAndroidBotNetworkHandler.subscribeAlways<ForceOfflineEvent> {
if (this@QQAndroidBotNetworkHandler.bot == this.bot) {
close()
@ -159,26 +156,26 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
val troopData = FriendList.GetTroopListSimplify(
bot.client
).sendAndExpect<FriendList.GetTroopListSimplify.Response>(timeoutMillis = 1000)
println("获取到群数量" + troopData.groups.size)
// println("获取到群数量" + troopData.groups.size)
val toGet: MutableMap<GroupImpl, ContactList<Member>> = mutableMapOf()
troopData.groups.forEach {
val contactList = ContactList(LockFreeLinkedList<Member>())
val group =
GroupImpl(
bot,
this.coroutineContext,
it.groupUin,
it.groupCode,
it.groupName,
it.groupMemo,
contactList
bot = bot,
coroutineContext = this.coroutineContext,
id = it.groupCode,
uin = it.groupUin,
name = it.groupName,
announcement = it.groupMemo,
members = contactList
)
group.owner =
MemberImpl(
bot.QQ(it.dwGroupOwnerUin) as QQImpl,
group,
group.coroutineContext,
MemberPermission.OWNER
qq = bot.QQ(it.dwGroupOwnerUin) as QQImpl,
group = group,
coroutineContext = group.coroutineContext,
permission = MemberPermission.OWNER
)
toGet[group] = contactList
bot.groups.delegate.addLast(group)
@ -186,10 +183,10 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
toGet.forEach {
try {
getTroopMemberList(it.key, it.value, it.key.owner.id)
groupInfo[it.key.groupCode] = it.value.size
groupInfo[it.key.uin] = it.value.size
} catch (e: Exception) {
groupInfo[it.key.groupCode] = -1
bot.logger.info("${it.key.groupCode}的列表拉取失败, 将采用动态加入")
groupInfo[it.key.uin] = -1
bot.logger.info("${it.key.uin}的列表拉取失败, 将采用动态加入")
}
//delay(200)
}
@ -221,36 +218,32 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
}
}
bot.logger.info("====================Mirai Bot List初始化完毕====================")
MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendWithoutExpect()
}
suspend fun getTroopMemberList(group: GroupImpl, list: ContactList<Member>, owner: Long): ContactList<Member> {
bot.logger.info("开始获取群[${group.groupCode}]成员列表")
bot.logger.info("开始获取群[${group.uin}]成员列表")
var size = 0
var nextUin = 0L
while (true) {
val data = FriendList.GetTroopMemberList(
bot.client,
group.id,
group.groupCode,
nextUin
client = bot.client,
targetGroupUin = group.uin,
targetGroupCode = group.id,
nextUin = nextUin
).sendAndExpect<FriendList.GetTroopMemberList.Response>(timeoutMillis = 3000)
data.members.forEach {
if (it.memberUin != bot.uin) {
list.delegate.addLast(
MemberImpl(
bot.QQ(it.memberUin) as QQImpl,
group,
EmptyCoroutineContext,
when {
it.memberUin == owner -> {
MemberPermission.OWNER
}
it.dwFlag == 1L -> {
MemberPermission.ADMINISTRATOR
}
else -> {
MemberPermission.MEMBER
}
qq = bot.QQ(it.memberUin) as QQImpl,
group = group,
coroutineContext = group.coroutineContext,
permission = when {
it.memberUin == owner -> MemberPermission.OWNER
it.dwFlag == 1L -> MemberPermission.ADMINISTRATOR
else -> MemberPermission.MEMBER
}
)
)
@ -261,9 +254,9 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
if (nextUin == 0L) {
break
}
println("已获取群[${group.groupCode}]成员列表前" + size + "个成员")
//println("已获取群[${group.uin}]成员列表前" + size + "个成员")
}
println("群[${group.groupCode}]成员全部获取完成, 共${list.size}个成员")
//println("群[${group.uin}]成员全部获取完成, 共${list.size}个成员")
return list
}

View File

@ -214,7 +214,7 @@ internal class MessageSvc {
*/
fun ToGroup(
client: QQAndroidClient,
groupId: Long,
groupCode: Long,
message: MessageChain
): OutgoingPacket = buildOutgoingUniPacket(client) {
@ -224,7 +224,7 @@ internal class MessageSvc {
///return@buildOutgoingUniPacket
writeProtoBuf(
MsgSvc.PbSendMsgReq.serializer(), MsgSvc.PbSendMsgReq(
routingHead = MsgSvc.RoutingHead(grp = MsgSvc.Grp(groupCode = groupId)), // TODO: 2020/1/30 确认这里是 id 还是 internalId
routingHead = MsgSvc.RoutingHead(grp = MsgSvc.Grp(groupCode = groupCode)), // TODO: 2020/1/30 确认这里是 id 还是 internalId
contentHead = MsgComm.ContentHead(pkgNum = 1, divSeq = seq),
msgBody = ImMsgBody.MsgBody(
richText = ImMsgBody.RichText(

View File

@ -38,7 +38,7 @@ internal class OnlinePush {
return GroupMessageOrNull(null)
}
val group = bot.getGroupByGroupCode(pbPushMsg.msg.msgHead.groupInfo!!.groupCode)
val group = bot.getGroup(pbPushMsg.msg.msgHead.groupInfo!!.groupCode)
val flags = extraInfo?.flags ?: 0
return GroupMessageOrNull(

View File

@ -14,11 +14,7 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.list.FriendList.GetFriendGroupList.decode
import net.mamoe.mirai.utils.io.debugIfFail
import net.mamoe.mirai.utils.io.debugPrintThis
import net.mamoe.mirai.utils.io.debugPrintln
import net.mamoe.mirai.utils.io.discardExact
internal class FriendList {
@ -35,7 +31,7 @@ internal class FriendList {
operator fun invoke(
client: QQAndroidClient,
targetGroupId: Long,
targetGroupUin: Long,
targetGroupCode: Long,
nextUin: Long = 0
): OutgoingPacket {
@ -53,7 +49,7 @@ internal class FriendList {
GetTroopMemberListReq(
uin = client.uin,
groupCode = targetGroupCode,
groupUin = targetGroupId,
groupUin = targetGroupUin,
nextUin = nextUin,
reqType = 0,
version = 2

View File

@ -21,7 +21,7 @@ import net.mamoe.mirai.utils.WeakRef
import net.mamoe.mirai.utils.io.transferTo
/**
* Mirai 机器人. 一个机器人实例登录一个 QQ 账号.
* 机器人对象. 一个机器人实例登录一个 QQ 账号.
* Mirai 为多账号设计, 可同时维护多个机器人.
*
* @see Contact
@ -78,12 +78,7 @@ abstract class Bot : CoroutineScope {
/**
* 获取一个机器人加入的群. 若没有这个群, 则会抛出异常 [NoSuchElementException]
*/
abstract fun getGroupByID(id: Long): Group
/**
* 获取一个机器人加入的群. 若没有这个群, 则会抛出异常 [NoSuchElementException]
*/
abstract fun getGroupByGroupCode(groupCode: Long): Group
abstract fun getGroup(id: Long): Group
// 目前还不能构造群对象. 这将在以后支持
@ -131,8 +126,10 @@ abstract class Bot : CoroutineScope {
/**
* 关闭这个 [Bot], 停止一切相关活动. 不可重新登录.
*
* @param cause 原因. null 时视为正常关闭, null 时视为异常关闭
*/
abstract fun dispose(throwable: Throwable?)
abstract fun close(cause: Throwable? = null)
// region extensions

View File

@ -133,15 +133,15 @@ abstract class BotImpl<N : BotNetworkHandler> constructor(
// endregion
@UseExperimental(MiraiInternalAPI::class)
override fun dispose(throwable: Throwable?) {
if (throwable == null) {
override fun close(cause: Throwable?) {
if (cause == null) {
network.close()
this.botJob.complete()
groups.delegate.clear()
qqs.delegate.clear()
} else {
network.close(throwable)
this.botJob.completeExceptionally(throwable)
network.close(cause)
this.botJob.completeExceptionally(cause)
groups.delegate.clear()
qqs.delegate.clear()
}

View File

@ -25,7 +25,7 @@ interface Contact : CoroutineScope {
val bot: Bot // weak ref
/**
* 可以是 QQ 号码或者群号码 [GroupId].
* 可以是 QQ 号码或者群号码.
*/
val id: Long

View File

@ -7,32 +7,25 @@ import kotlinx.coroutines.CoroutineScope
/**
* . QQ Android 中叫做 "Troop"
*
* Group UIN Group Code 并不是同一个值.
* Group Code是在客户端显示的code
* Group Uin是QQ内部的群ID[在Mirai中则为 id]
* 但是有的时候 两个是相同的value
* 在网络调用层 Code与Uin会被混用
* 但在开发层 你应该只关注Group Code
*/
interface Group : Contact, CoroutineScope {
/**
* 同为 groupCode, 用户看到的群号码.
*/
override val id: Long
val groupCode: Long
/**
* 群主 (同步事件更新)
* 进行 [updateGroupInfo] 时将会更新这个值.
*/
val owner: Member
/**
* 群名称 (同步事件更新)
* 进行 [updateGroupInfo] 时将会更新这个值.
*/
val name: String
/**
* 入群公告, 没有时为空字符串. (同步事件更新)
* 进行 [updateGroupInfo] 时将会更新这个值.
*/
val announcement: String
@ -45,7 +38,7 @@ interface Group : Contact, CoroutineScope {
/**
* 获取群成员实例. 若此 ID 的成员不存在, 则会抛出 [kotlin.NoSuchElementException]
* 获取群成员实例. 若此 id 的成员不存在, 则会抛出 [kotlin.NoSuchElementException]
*/
operator fun get(id: Long): Member

View File

@ -63,6 +63,8 @@ abstract class BotNetworkHandler : CoroutineScope {
/**
* 关闭网络接口, 停止所有有关协程和任务
*
* @param cause 关闭的原因. null 时视为正常关闭, null 时视为异常关闭.
*/
open fun close(cause: Throwable? = null) {
if (supervisor.isActive) {
@ -75,7 +77,7 @@ abstract class BotNetworkHandler : CoroutineScope {
}
}
suspend fun BotNetworkHandler.closeAndJoin(cause: Throwable? = null){
suspend fun BotNetworkHandler.closeAndJoin(cause: Throwable? = null) {
this.close(cause)
this.supervisor.join()
}

View File

@ -1,14 +0,0 @@
package net.mamoe.mirai.contact
import net.mamoe.mirai.test.shouldBeEqualTo
import org.junit.Test
@UseExperimental(ExperimentalUnsignedTypes::class)
internal class GroupIdConversionsKtTest {
@Test
fun checkToInternalId() {
GroupId(221056495).toInternalId().value shouldBeEqualTo 4111056495
// 61 056495
//4111 056495
}
}

View File

@ -217,7 +217,9 @@ suspend fun directlySubscribe(bot: Bot) {
"复读" in message -> sender.sendMessage(message)
"发群消息" in message -> 580266363.group().sendMessage(message.toString().substringAfter("发群消息"))
"发群消息" in message -> {
bot.getGroup(580266363).sendMessage(message.toString().substringAfter("发群消息"))
}
}
}
}

View File

@ -50,10 +50,6 @@ suspend fun main() {
// 订阅来自这个 bot 的群消息事件
bot.subscribeGroupMessages {
"群资料" reply {
group.updateGroupInfo().toString().reply()
}
startsWith("mute") {
val at: At by message
at.member().mute(30)

View File

@ -5,7 +5,6 @@ import net.mamoe.mirai.BotAccount;
import net.mamoe.mirai.data.AddFriendResult;
import net.mamoe.mirai.message.data.Image;
import net.mamoe.mirai.network.BotNetworkHandler;
import net.mamoe.mirai.utils.GroupNotFoundException;
import net.mamoe.mirai.utils.MiraiInternalAPI;
import net.mamoe.mirai.utils.MiraiLogger;
import org.jetbrains.annotations.NotNull;
@ -15,6 +14,9 @@ import java.util.List;
@SuppressWarnings("unused")
public interface BlockingBot {
// TODO: 2020/2/3 需要更新
/**
* 账号信息
*/
@ -55,17 +57,11 @@ public interface BlockingBot {
/**
* 获取缓存的群对象. 若没有对应的缓存, 则会线程安全地创建一个.
* {@code id} 无效, 将会抛出 {@link GroupNotFoundException}
* {@code id} 无效, 将会抛出 {@link java.util.NoSuchElementException}
*/
@NotNull
BlockingGroup getGroup(long id);
/**
* 获取缓存的群对象. 若没有对应的缓存, 则会线程安全地创建一个.
* {@code internalId} 无效, 将会抛出 {@link GroupNotFoundException}
*/
@NotNull
BlockingGroup getGroupByInternalId(long internalId);
// endregion

View File

@ -4,7 +4,6 @@ import kotlinx.coroutines.runBlocking
import kotlinx.io.core.ByteReadPacket
import net.mamoe.mirai.Bot
import net.mamoe.mirai.BotAccount
import net.mamoe.mirai.contact.GroupInternalId
import net.mamoe.mirai.data.AddFriendResult
import net.mamoe.mirai.japt.BlockingBot
import net.mamoe.mirai.japt.BlockingGroup
@ -29,12 +28,11 @@ internal class BlockingBotImpl(private val bot: Bot) : BlockingBot {
override fun getGroups(): List<BlockingGroup> = bot.groups.delegate.toList().map { it.blocking() }
override fun getGroup(id: Long): BlockingGroup = runBlocking { bot.getGroup(id).blocking() }
override fun getGroupByInternalId(internalId: Long): BlockingGroup = runBlocking { bot.getGroup(GroupInternalId(internalId)).blocking() }
override fun getNetwork(): BotNetworkHandler = bot.network
override fun login() = runBlocking { bot.login() }
override fun downloadAsByteArray(image: Image): ByteArray = bot.run { runBlocking { image.downloadAsByteArray() } }
override fun download(image: Image): ByteReadPacket = bot.run { runBlocking { image.download() } }
override fun addFriend(id: Long, message: String?, remark: String?): AddFriendResult = runBlocking { bot.addFriend(id, message, remark) }
override fun approveFriendAddRequest(id: Long, remark: String?) = runBlocking { bot.approveFriendAddRequest(id, remark) }
override fun dispose(throwable: Throwable?) = bot.dispose(throwable)
override fun dispose(throwable: Throwable?) = bot.close(throwable)
}