mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-05 07:30:09 +08:00
Merge branch 'dev'
This commit is contained in:
commit
9eed2b94ae
30
CHANGELOG.md
30
CHANGELOG.md
@ -1,5 +1,35 @@
|
|||||||
# Version 1.x
|
# Version 1.x
|
||||||
|
|
||||||
|
## `1.3.0` 2020/9/16
|
||||||
|
|
||||||
|
### 新特性
|
||||||
|
|
||||||
|
- 支持群恢复相关事件: `MemberJoinEvent.Retrieve`, `BotJoinGroupEvent.Retrieve` (#531 by @Karlatemp)
|
||||||
|
- 群荣耀获取 (`Bot._lowLevelGetGroupHonorListData`) (#501 by @yyuueexxiinngg)
|
||||||
|
- 戳一戳事件: `FriendNudgedEvent`, `MemberNudgedEvent`, `BotNudgedEvent`.(#600 by @sandtechnology)
|
||||||
|
- 发送戳一戳: `Bot.nudge()`, `User.nudge()`
|
||||||
|
- 为 `BotFactory` 添加伴生对象. 在顶层方法不方便使用时可使用伴生对象的 `Bot` 构建方法
|
||||||
|
|
||||||
|
### 优化和修复
|
||||||
|
- **修复好友消息和事件同步相关问题: **
|
||||||
|
- 部分情况下无法同步好友消息 (#249)
|
||||||
|
- BotInvitedJoinGroupRequestEvent 重复执行两次 (#449)
|
||||||
|
- 群消息可能发送失败 (#527)
|
||||||
|
- 机器人启动后第二次被拉入群聊不会刷新群列表 (#580)
|
||||||
|
- 新群员入群事件只触发一次 (#590)
|
||||||
|
- 入群申请 MemberJoinRequestEvent 没有广播 (#542)
|
||||||
|
- 新成员入群未处理 (#567)
|
||||||
|
- 修复 `At` 之后的多余空格的问题 (#557)
|
||||||
|
- 修复 `QuoteReply` 前多余 `At` 和空格的问题 (#524)
|
||||||
|
- 修复群信息初始值 (`isMuteAll`, `isAllowMemberInvite`, ...) (#286)
|
||||||
|
- 修复 `Voice.url` 的域名缺失问题 (#584 by @Hieuzest)
|
||||||
|
- 修复日志颜色污染的问题 (#596 by @Karlatemp)
|
||||||
|
- 修复 `Bot.nick` 无法获取的问题 (#566)
|
||||||
|
- 修复登录时 `IndexOutOfBoundsException` 的问题 (#598)
|
||||||
|
- 修复 Bot 被踢出群收到的事件类型错误的问题 (#358) (#509 by @sandtechnology)
|
||||||
|
- 修复 `Bot.close` 后必须收到一个数据包才会关闭的问题 (#557)
|
||||||
|
- 优化 `PermissionDeniedException` 的消息内容
|
||||||
|
|
||||||
## `1.2.3` 2020/9/11
|
## `1.2.3` 2020/9/11
|
||||||
- 在同步事件失败时添加重试, 改善 #249, #482, #542, #567, #590
|
- 在同步事件失败时添加重试, 改善 #249, #482, #542, #567, #590
|
||||||
- 修复不断重连同一个服务器的问题 (#589)
|
- 修复不断重连同一个服务器的问题 (#589)
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
object Versions {
|
object Versions {
|
||||||
object Mirai {
|
object Mirai {
|
||||||
const val version = "1.2.3"
|
const val version = "1.3.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
object Kotlin {
|
object Kotlin {
|
||||||
|
@ -27,6 +27,7 @@ import net.mamoe.mirai.event.subscribeAlways
|
|||||||
import net.mamoe.mirai.network.ForceOfflineException
|
import net.mamoe.mirai.network.ForceOfflineException
|
||||||
import net.mamoe.mirai.network.LoginFailedException
|
import net.mamoe.mirai.network.LoginFailedException
|
||||||
import net.mamoe.mirai.qqandroid.network.BotNetworkHandler
|
import net.mamoe.mirai.qqandroid.network.BotNetworkHandler
|
||||||
|
import net.mamoe.mirai.qqandroid.network.DefaultServerList
|
||||||
import net.mamoe.mirai.qqandroid.network.closeAndJoin
|
import net.mamoe.mirai.qqandroid.network.closeAndJoin
|
||||||
import net.mamoe.mirai.supervisorJob
|
import net.mamoe.mirai.supervisorJob
|
||||||
import net.mamoe.mirai.utils.*
|
import net.mamoe.mirai.utils.*
|
||||||
@ -91,7 +92,11 @@ internal abstract class BotImpl<N : BotNetworkHandler> constructor(
|
|||||||
}
|
}
|
||||||
bot.logger.info { "Connection lost, retrying login" }
|
bot.logger.info { "Connection lost, retrying login" }
|
||||||
|
|
||||||
bot.asQQAndroidBot().client.serverList.removeAt(0)
|
bot.asQQAndroidBot().client.run {
|
||||||
|
if (serverList.isEmpty()) {
|
||||||
|
serverList.addAll(DefaultServerList)
|
||||||
|
} else serverList.removeAt(0)
|
||||||
|
}
|
||||||
|
|
||||||
var failed = false
|
var failed = false
|
||||||
val time = measureTime {
|
val time = measureTime {
|
||||||
|
@ -32,6 +32,7 @@ import net.mamoe.mirai.event.events.NewFriendRequestEvent
|
|||||||
import net.mamoe.mirai.event.internal.MiraiAtomicBoolean
|
import net.mamoe.mirai.event.internal.MiraiAtomicBoolean
|
||||||
import net.mamoe.mirai.getGroupOrNull
|
import net.mamoe.mirai.getGroupOrNull
|
||||||
import net.mamoe.mirai.message.MessageReceipt
|
import net.mamoe.mirai.message.MessageReceipt
|
||||||
|
import net.mamoe.mirai.message.action.Nudge
|
||||||
import net.mamoe.mirai.message.data.*
|
import net.mamoe.mirai.message.data.*
|
||||||
import net.mamoe.mirai.network.LoginFailedException
|
import net.mamoe.mirai.network.LoginFailedException
|
||||||
import net.mamoe.mirai.qqandroid.contact.FriendImpl
|
import net.mamoe.mirai.qqandroid.contact.FriendImpl
|
||||||
@ -42,6 +43,7 @@ import net.mamoe.mirai.qqandroid.message.*
|
|||||||
import net.mamoe.mirai.qqandroid.network.QQAndroidBotNetworkHandler
|
import net.mamoe.mirai.qqandroid.network.QQAndroidBotNetworkHandler
|
||||||
import net.mamoe.mirai.qqandroid.network.QQAndroidClient
|
import net.mamoe.mirai.qqandroid.network.QQAndroidClient
|
||||||
import net.mamoe.mirai.qqandroid.network.highway.HighwayHelper
|
import net.mamoe.mirai.qqandroid.network.highway.HighwayHelper
|
||||||
|
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.StTroopNum
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.ImMsgBody
|
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.ImMsgBody
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.LongMsg
|
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.LongMsg
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.*
|
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.*
|
||||||
@ -226,6 +228,30 @@ internal class QQAndroidBot constructor(
|
|||||||
accept = accept
|
accept = accept
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("CANNOT_OVERRIDE_INVISIBLE_MEMBER")
|
||||||
|
override suspend fun sendNudge(nudge: Nudge, receiver: Contact): Boolean {
|
||||||
|
if (configuration.protocol != BotConfiguration.MiraiProtocol.ANDROID_PHONE) {
|
||||||
|
throw UnsupportedOperationException("nudge is supported only with protocol ANDROID_PHONE")
|
||||||
|
}
|
||||||
|
|
||||||
|
network.run {
|
||||||
|
return if (receiver is Group) {
|
||||||
|
receiver.checkIsGroupImpl()
|
||||||
|
NudgePacket.troopInvoke(
|
||||||
|
client = client,
|
||||||
|
messageReceiverGroupCode = receiver.id,
|
||||||
|
nudgeTargetId = nudge.target.id,
|
||||||
|
).sendAndExpect<NudgePacket.Response>().success
|
||||||
|
} else {
|
||||||
|
NudgePacket.friendInvoke(
|
||||||
|
client = client,
|
||||||
|
messageReceiverUin = receiver.id,
|
||||||
|
nudgeTargetId = nudge.target.id,
|
||||||
|
).sendAndExpect<NudgePacket.Response>().success
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -250,10 +276,15 @@ internal abstract class QQAndroidBotBase constructor(
|
|||||||
|
|
||||||
override val friends: ContactList<Friend> = ContactList(LockFreeLinkedList())
|
override val friends: ContactList<Friend> = ContactList(LockFreeLinkedList())
|
||||||
|
|
||||||
@JvmField internal var cachedNick: String? = null
|
override lateinit var nick: String
|
||||||
override val nick: String get() = cachedNick ?: selfInfo.nick.also { cachedNick = it }
|
|
||||||
|
|
||||||
internal lateinit var selfInfo: JceFriendInfo
|
internal var selfInfo: JceFriendInfo? = null
|
||||||
|
get() = field ?: error("selfInfo is not yet initialized")
|
||||||
|
set(it) {
|
||||||
|
checkNotNull(it)
|
||||||
|
field = it
|
||||||
|
nick = it.nick
|
||||||
|
}
|
||||||
|
|
||||||
override val selfQQ: Friend by lazy {
|
override val selfQQ: Friend by lazy {
|
||||||
@OptIn(LowLevelAPI::class)
|
@OptIn(LowLevelAPI::class)
|
||||||
@ -311,12 +342,22 @@ internal abstract class QQAndroidBotBase constructor(
|
|||||||
}.groups.asSequence().map { it.groupUin.shl(32) and it.groupCode }
|
}.groups.asSequence().map { it.groupUin.shl(32) and it.groupCode }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress(
|
||||||
|
"DeprecatedCallableAddReplaceWith",
|
||||||
|
"FunctionName",
|
||||||
|
"RedundantSuspendModifier",
|
||||||
|
"unused",
|
||||||
|
"unused_parameter"
|
||||||
|
)
|
||||||
|
@Deprecated("")
|
||||||
@OptIn(LowLevelAPI::class)
|
@OptIn(LowLevelAPI::class)
|
||||||
override suspend fun _lowLevelQueryGroupInfo(groupCode: Long): GroupInfo = network.run {
|
suspend fun _lowLevelQueryGroupInfo(groupCode: Long, stTroopNum: StTroopNum): GroupInfo = network.run {
|
||||||
|
error("This should not be invoked")
|
||||||
|
/*
|
||||||
TroopManagement.GetGroupInfo(
|
TroopManagement.GetGroupInfo(
|
||||||
client = bot.client,
|
client = bot.client,
|
||||||
groupCode = groupCode
|
groupCode = groupCode
|
||||||
).sendAndExpect<GroupInfoImpl>(retry = 3)
|
).sendAndExpect<GroupInfoImpl>(retry = 3).also { it.stTroopNum = stTroopNum }*/
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(LowLevelAPI::class)
|
@OptIn(LowLevelAPI::class)
|
||||||
@ -608,6 +649,30 @@ internal abstract class QQAndroidBotBase constructor(
|
|||||||
return json.decodeFromString(GroupActiveData.serializer(), rep)
|
return json.decodeFromString(GroupActiveData.serializer(), rep)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@LowLevelAPI
|
||||||
|
@MiraiExperimentalAPI
|
||||||
|
override suspend fun _lowLevelGetGroupHonorListData(groupId: Long, type: GroupHonorType): GroupHonorListData? {
|
||||||
|
val data = network.async {
|
||||||
|
MiraiPlatformUtils.Http.get<String> {
|
||||||
|
url("https://qun.qq.com/interactive/honorlist")
|
||||||
|
parameter("gc", groupId)
|
||||||
|
parameter("type", type.value)
|
||||||
|
headers {
|
||||||
|
append(
|
||||||
|
"cookie",
|
||||||
|
"uin=o${id};" +
|
||||||
|
" skey=${client.wLoginSigInfo.sKey.data.encodeToString()};" +
|
||||||
|
" p_uin=o${id};" +
|
||||||
|
" p_skey=${client.wLoginSigInfo.psKeyMap["qun.qq.com"]?.data?.encodeToString()}; "
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val rep = data.await()
|
||||||
|
val jsonText = Regex("""window.__INITIAL_STATE__=(.+?)</script>""").find(rep)?.groupValues?.get(1)
|
||||||
|
return jsonText?.let { json.decodeFromString(GroupHonorListData.serializer(), it) }
|
||||||
|
}
|
||||||
|
|
||||||
@JvmSynthetic
|
@JvmSynthetic
|
||||||
@LowLevelAPI
|
@LowLevelAPI
|
||||||
@MiraiExperimentalAPI
|
@MiraiExperimentalAPI
|
||||||
|
@ -124,6 +124,9 @@ internal class MemberImpl constructor(
|
|||||||
@Suppress("PropertyName")
|
@Suppress("PropertyName")
|
||||||
var _muteTimestamp: Int = memberInfo.muteTimestamp
|
var _muteTimestamp: Int = memberInfo.muteTimestamp
|
||||||
|
|
||||||
|
@Suppress("PropertyName")
|
||||||
|
var _nudgeTimestamp: Long = 0L
|
||||||
|
|
||||||
override val muteTimeRemaining: Int
|
override val muteTimeRemaining: Int
|
||||||
get() = if (_muteTimestamp == 0 || _muteTimestamp == 0xFFFFFFFF.toInt()) {
|
get() = if (_muteTimestamp == 0 || _muteTimestamp == 0xFFFFFFFF.toInt()) {
|
||||||
0
|
0
|
||||||
@ -197,7 +200,7 @@ internal class MemberImpl constructor(
|
|||||||
private fun checkBotPermissionHigherThanThis(operationName: String) {
|
private fun checkBotPermissionHigherThanThis(operationName: String) {
|
||||||
check(group.botPermission > this.permission) {
|
check(group.botPermission > this.permission) {
|
||||||
throw PermissionDeniedException(
|
throw PermissionDeniedException(
|
||||||
"`$operationName` operation requires a higher permission, while" +
|
"`$operationName` operation requires a higher permission, while " +
|
||||||
"${group.botPermission} < ${this.permission}"
|
"${group.botPermission} < ${this.permission}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -219,7 +222,6 @@ internal class MemberImpl constructor(
|
|||||||
net.mamoe.mirai.event.events.MemberUnmuteEvent(this@MemberImpl, null).broadcast()
|
net.mamoe.mirai.event.events.MemberUnmuteEvent(this@MemberImpl, null).broadcast()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@JvmSynthetic
|
@JvmSynthetic
|
||||||
override suspend fun kick(message: String) {
|
override suspend fun kick(message: String) {
|
||||||
checkBotPermissionHigherThanThis("kick")
|
checkBotPermissionHigherThanThis("kick")
|
||||||
|
@ -113,7 +113,9 @@ internal fun MessageChain.toRichTextElems(forGroup: Boolean, withGeneralFlags: B
|
|||||||
}
|
}
|
||||||
is At -> {
|
is At -> {
|
||||||
elements.add(ImMsgBody.Elem(text = it.toJceData()))
|
elements.add(ImMsgBody.Elem(text = it.toJceData()))
|
||||||
elements.add(ImMsgBody.Elem(text = ImMsgBody.Text(str = " ")))
|
// elements.add(ImMsgBody.Elem(text = ImMsgBody.Text(str = " ")))
|
||||||
|
// removed by https://github.com/mamoe/mirai/issues/524
|
||||||
|
// 发送 QuoteReply 消息时无可避免的产生多余空格 #524
|
||||||
}
|
}
|
||||||
is PokeMessage -> {
|
is PokeMessage -> {
|
||||||
elements.add(
|
elements.add(
|
||||||
@ -151,7 +153,9 @@ internal fun MessageChain.toRichTextElems(forGroup: Boolean, withGeneralFlags: B
|
|||||||
when (val source = it.source) {
|
when (val source = it.source) {
|
||||||
is OnlineMessageSource.Incoming.FromGroup -> {
|
is OnlineMessageSource.Incoming.FromGroup -> {
|
||||||
transformOneMessage(At(source.sender))
|
transformOneMessage(At(source.sender))
|
||||||
transformOneMessage(PlainText(" "))
|
// transformOneMessage(PlainText(" "))
|
||||||
|
// removed by https://github.com/mamoe/mirai/issues/524
|
||||||
|
// 发送 QuoteReply 消息时无可避免的产生多余空格 #524
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -297,6 +301,17 @@ private fun MessageChain.cleanupRubbishMessageElements(): MessageChain {
|
|||||||
return@forEach
|
return@forEach
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (element is QuoteReply) {
|
||||||
|
// 客户端为兼容早期不支持 QuoteReply 的客户端而添加的 At
|
||||||
|
removeLastOrNull()?.let { rm ->
|
||||||
|
if ((rm as? PlainText)?.content != " ") add(rm)
|
||||||
|
else removeLastOrNull()?.let { rm2 ->
|
||||||
|
if (rm2 !is At) add(rm2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
add(element)
|
add(element)
|
||||||
last = element
|
last = element
|
||||||
}
|
}
|
||||||
@ -316,7 +331,7 @@ internal val MIRAI_CUSTOM_ELEM_TYPE = "mirai".hashCode() // 103904510
|
|||||||
|
|
||||||
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
|
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
|
||||||
internal fun List<ImMsgBody.Elem>.joinToMessageChain(groupIdOrZero: Long, bot: Bot, list: MessageChainBuilder) {
|
internal fun List<ImMsgBody.Elem>.joinToMessageChain(groupIdOrZero: Long, bot: Bot, list: MessageChainBuilder) {
|
||||||
// (this._miraiContentToString())
|
// (this._miraiContentToString().soutv())
|
||||||
this.forEach { element ->
|
this.forEach { element ->
|
||||||
when {
|
when {
|
||||||
element.srcMsg != null -> {
|
element.srcMsg != null -> {
|
||||||
|
@ -246,7 +246,6 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
|
|||||||
|
|
||||||
// self info
|
// self info
|
||||||
data.selfInfo?.run {
|
data.selfInfo?.run {
|
||||||
bot.cachedNick = null
|
|
||||||
bot.selfInfo = this
|
bot.selfInfo = this
|
||||||
// bot.remark = remark ?: ""
|
// bot.remark = remark ?: ""
|
||||||
// bot.sex = sex
|
// bot.sex = sex
|
||||||
@ -272,28 +271,11 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
|
|||||||
suspend fun StTroopNum.reloadGroup() {
|
suspend fun StTroopNum.reloadGroup() {
|
||||||
retryCatching(3) {
|
retryCatching(3) {
|
||||||
bot.groups.delegate.addLast(
|
bot.groups.delegate.addLast(
|
||||||
@Suppress("DuplicatedCode")
|
|
||||||
GroupImpl(
|
GroupImpl(
|
||||||
bot = bot,
|
bot = bot,
|
||||||
coroutineContext = bot.coroutineContext,
|
coroutineContext = bot.coroutineContext,
|
||||||
id = groupCode,
|
id = groupCode,
|
||||||
groupInfo = bot._lowLevelQueryGroupInfo(groupCode).apply {
|
groupInfo = GroupInfoImpl(this),
|
||||||
this as GroupInfoImpl
|
|
||||||
|
|
||||||
if (this.delegate.groupName == null) {
|
|
||||||
this.delegate.groupName = groupName
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.delegate.groupMemo == null) {
|
|
||||||
this.delegate.groupMemo = groupMemo
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.delegate.groupUin == null) {
|
|
||||||
this.delegate.groupUin = groupUin
|
|
||||||
}
|
|
||||||
|
|
||||||
this.delegate.groupCode = this@reloadGroup.groupCode
|
|
||||||
},
|
|
||||||
members = bot._lowLevelQueryGroupMemberList(
|
members = bot._lowLevelQueryGroupMemberList(
|
||||||
groupUin,
|
groupUin,
|
||||||
groupCode,
|
groupCode,
|
||||||
|
@ -20,6 +20,7 @@ import net.mamoe.mirai.network.LoginFailedException
|
|||||||
import net.mamoe.mirai.network.NoServerAvailableException
|
import net.mamoe.mirai.network.NoServerAvailableException
|
||||||
import net.mamoe.mirai.qqandroid.BotAccount
|
import net.mamoe.mirai.qqandroid.BotAccount
|
||||||
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
||||||
|
import net.mamoe.mirai.qqandroid.network.protocol.SyncingCacheList
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.FileStoragePushFSSvcListFuckKotlin
|
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.FileStoragePushFSSvcListFuckKotlin
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
|
import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketLogger
|
import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketLogger
|
||||||
@ -191,9 +192,6 @@ internal open class QQAndroidClient(
|
|||||||
private val highwayDataTransSequenceIdForApplyUp: AtomicInt = atomic(77918)
|
private val highwayDataTransSequenceIdForApplyUp: AtomicInt = atomic(77918)
|
||||||
internal fun nextHighwayDataTransSequenceIdForApplyUp(): Int = highwayDataTransSequenceIdForApplyUp.getAndAdd(2)
|
internal fun nextHighwayDataTransSequenceIdForApplyUp(): Int = highwayDataTransSequenceIdForApplyUp.getAndAdd(2)
|
||||||
|
|
||||||
internal val onlinePushCacheList: AtomicResizeCacheList<Short> = AtomicResizeCacheList(20.secondsToMillis)
|
|
||||||
internal val pbPushTransMsgCacheList: AtomicResizeCacheList<Int> = AtomicResizeCacheList(20.secondsToMillis)
|
|
||||||
|
|
||||||
val appClientVersion: Int = 0
|
val appClientVersion: Int = 0
|
||||||
|
|
||||||
var networkType: NetworkType = NetworkType.WIFI
|
var networkType: NetworkType = NetworkType.WIFI
|
||||||
@ -205,16 +203,49 @@ internal open class QQAndroidClient(
|
|||||||
*/
|
*/
|
||||||
val protocolVersion: Short = 8001
|
val protocolVersion: Short = 8001
|
||||||
|
|
||||||
class C2cMessageSyncData {
|
class MessageSvcSyncData {
|
||||||
val firstNotify: AtomicBoolean = atomic(true)
|
val firstNotify: AtomicBoolean = atomic(true)
|
||||||
|
|
||||||
@Volatile
|
@Volatile
|
||||||
var syncCookie: ByteArray? = null
|
var syncCookie: ByteArray? = null
|
||||||
var pubAccountCookie = EMPTY_BYTE_ARRAY
|
var pubAccountCookie = EMPTY_BYTE_ARRAY
|
||||||
var msgCtrlBuf: ByteArray = EMPTY_BYTE_ARRAY
|
var msgCtrlBuf: ByteArray = EMPTY_BYTE_ARRAY
|
||||||
|
|
||||||
|
|
||||||
|
internal data class PbGetMessageSyncId(
|
||||||
|
val uid: Long,
|
||||||
|
val sequence: Int,
|
||||||
|
val time: Int
|
||||||
|
)
|
||||||
|
|
||||||
|
val pbGetMessageCacheList = SyncingCacheList<PbGetMessageSyncId>()
|
||||||
|
|
||||||
|
internal data class SystemMsgNewGroupSyncId(
|
||||||
|
val sequence: Long,
|
||||||
|
val time: Long
|
||||||
|
)
|
||||||
|
|
||||||
|
val systemMsgNewGroupCacheList = SyncingCacheList<SystemMsgNewGroupSyncId>(10)
|
||||||
|
|
||||||
|
|
||||||
|
internal data class PbPushTransMsgSyncId(
|
||||||
|
val uid: Long,
|
||||||
|
val sequence: Int,
|
||||||
|
val time: Int
|
||||||
|
)
|
||||||
|
|
||||||
|
val pbPushTransMsgCacheList = SyncingCacheList<PbPushTransMsgSyncId>(10)
|
||||||
|
|
||||||
|
internal data class OnlinePushReqPushSyncId(
|
||||||
|
val uid: Long,
|
||||||
|
val sequence: Short,
|
||||||
|
val time: Long
|
||||||
|
)
|
||||||
|
|
||||||
|
val onlinePushReqPushCacheList = SyncingCacheList<OnlinePushReqPushSyncId>(50)
|
||||||
}
|
}
|
||||||
|
|
||||||
val c2cMessageSync = C2cMessageSyncData()
|
val syncingController = MessageSvcSyncData()
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 以下登录使用
|
* 以下登录使用
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* * Copyright 2020 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/master/LICENSE
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.mamoe.mirai.qqandroid.network.protocol
|
||||||
|
|
||||||
|
import net.mamoe.mirai.qqandroid.utils.LinkedList
|
||||||
|
import kotlin.jvm.Synchronized
|
||||||
|
|
||||||
|
internal class SyncingCacheList<E>(private val size: Int = 50) {
|
||||||
|
private val packetIdList = LinkedList<E>()
|
||||||
|
|
||||||
|
@Synchronized // faster than suspending Mutex
|
||||||
|
fun addCache(element: E): Boolean {
|
||||||
|
if (packetIdList.contains(element)) return false // duplicate
|
||||||
|
packetIdList.addLast(element)
|
||||||
|
if (packetIdList.size >= size) packetIdList.removeFirst()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
@ -172,13 +172,13 @@ internal class Oidb0x88d : ProtoBuf {
|
|||||||
@ProtoNumber(12) @JvmField val groupDefaultPage: Int? = null,
|
@ProtoNumber(12) @JvmField val groupDefaultPage: Int? = null,
|
||||||
@ProtoNumber(13) @JvmField val groupInfoSeq: Int? = null,
|
@ProtoNumber(13) @JvmField val groupInfoSeq: Int? = null,
|
||||||
@ProtoNumber(14) @JvmField val groupRoamingTime: Int? = null,
|
@ProtoNumber(14) @JvmField val groupRoamingTime: Int? = null,
|
||||||
@ProtoNumber(15) var groupName: String? = null,
|
@ProtoNumber(15) @JvmField val groupName: String? = null,
|
||||||
@ProtoNumber(16) var groupMemo: String? = null,
|
@ProtoNumber(16) @JvmField val groupMemo: String? = null,
|
||||||
@ProtoNumber(17) @JvmField val ingGroupFingerMemo: String? = null,
|
@ProtoNumber(17) @JvmField val ingGroupFingerMemo: String? = null,
|
||||||
@ProtoNumber(18) @JvmField val ingGroupClassText: String? = null,
|
@ProtoNumber(18) @JvmField val ingGroupClassText: String? = null,
|
||||||
@ProtoNumber(19) @JvmField val groupAllianceCode: List<Int>? = null,
|
@ProtoNumber(19) @JvmField val groupAllianceCode: List<Int>? = null,
|
||||||
@ProtoNumber(20) @JvmField val groupExtraAdmNum: Int? = null,
|
@ProtoNumber(20) @JvmField val groupExtraAdmNum: Int? = null,
|
||||||
@ProtoNumber(21) var groupUin: Long? = null,
|
@ProtoNumber(21) @JvmField val groupUin: Long? = null,
|
||||||
@ProtoNumber(22) @JvmField val groupCurMsgSeq: Int? = null,
|
@ProtoNumber(22) @JvmField val groupCurMsgSeq: Int? = null,
|
||||||
@ProtoNumber(23) @JvmField val groupLastMsgTime: Int? = null,
|
@ProtoNumber(23) @JvmField val groupLastMsgTime: Int? = null,
|
||||||
@ProtoNumber(24) @JvmField val ingGroupQuestion: String? = null,
|
@ProtoNumber(24) @JvmField val ingGroupQuestion: String? = null,
|
||||||
@ -258,7 +258,6 @@ internal class Oidb0x88d : ProtoBuf {
|
|||||||
@ProtoNumber(98) @JvmField val cmduinRingtoneId: Int? = null,
|
@ProtoNumber(98) @JvmField val cmduinRingtoneId: Int? = null,
|
||||||
@ProtoNumber(99) @JvmField val groupFlagext4: Int? = null,
|
@ProtoNumber(99) @JvmField val groupFlagext4: Int? = null,
|
||||||
@ProtoNumber(100) @JvmField val groupFreezeReason: Int? = null,
|
@ProtoNumber(100) @JvmField val groupFreezeReason: Int? = null,
|
||||||
@ProtoNumber(101) var groupCode: Long? = null // mirai 添加
|
|
||||||
) : ProtoBuf
|
) : ProtoBuf
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@ -2423,3 +2422,17 @@ internal class Cmd0x6ce : ProtoBuf {
|
|||||||
) : ProtoBuf
|
) : ProtoBuf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
internal class Cmd0xed3 : ProtoBuf {
|
||||||
|
@Serializable
|
||||||
|
internal class RspBody : ProtoBuf
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
internal class ReqBody(
|
||||||
|
@ProtoNumber(1) @JvmField val toUin: Long = 0L,
|
||||||
|
@ProtoNumber(2) @JvmField val groupCode: Long = 0L,
|
||||||
|
@ProtoNumber(3) @JvmField val msgSeq: Int = 0,
|
||||||
|
@ProtoNumber(4) @JvmField val msgRandom: Int = 0,
|
||||||
|
@ProtoNumber(5) @JvmField val aioUin: Long = 0L
|
||||||
|
) : ProtoBuf
|
||||||
|
}
|
@ -13,10 +13,7 @@ import kotlinx.io.core.*
|
|||||||
import net.mamoe.mirai.event.Event
|
import net.mamoe.mirai.event.Event
|
||||||
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
||||||
import net.mamoe.mirai.qqandroid.network.Packet
|
import net.mamoe.mirai.qqandroid.network.Packet
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.MultiMsg
|
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.*
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.NewContact
|
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.PbMessageSvc
|
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.TroopManagement
|
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.ImgStore
|
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.ImgStore
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.LongConn
|
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.LongConn
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.*
|
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.*
|
||||||
@ -148,9 +145,10 @@ internal object KnownPacketFactories {
|
|||||||
TroopManagement.EditSpecialTitle,
|
TroopManagement.EditSpecialTitle,
|
||||||
TroopManagement.Mute,
|
TroopManagement.Mute,
|
||||||
TroopManagement.GroupOperation,
|
TroopManagement.GroupOperation,
|
||||||
TroopManagement.GetGroupInfo,
|
// TroopManagement.GetGroupInfo,
|
||||||
TroopManagement.EditGroupNametag,
|
TroopManagement.EditGroupNametag,
|
||||||
TroopManagement.Kick,
|
TroopManagement.Kick,
|
||||||
|
NudgePacket,
|
||||||
Heartbeat.Alive,
|
Heartbeat.Alive,
|
||||||
PbMessageSvc.PbMsgWithDraw,
|
PbMessageSvc.PbMsgWithDraw,
|
||||||
MultiMsg.ApplyUp,
|
MultiMsg.ApplyUp,
|
||||||
|
@ -58,7 +58,7 @@ internal class NewContact {
|
|||||||
|
|
||||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): NewFriendRequestEvent? {
|
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): NewFriendRequestEvent? {
|
||||||
readBytes().loadAs(Structmsg.RspSystemMsgNew.serializer()).run {
|
readBytes().loadAs(Structmsg.RspSystemMsgNew.serializer()).run {
|
||||||
val struct = friendmsgs?.firstOrNull()
|
val struct = friendmsgs?.firstOrNull()// 会有重复且无法过滤, 不要用 map
|
||||||
return struct?.msg?.run {
|
return struct?.msg?.run {
|
||||||
NewFriendRequestEvent(
|
NewFriendRequestEvent(
|
||||||
bot,
|
bot,
|
||||||
@ -145,9 +145,16 @@ internal class NewContact {
|
|||||||
|
|
||||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Packet? {
|
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Packet? {
|
||||||
readBytes().loadAs(Structmsg.RspSystemMsgNew.serializer()).run {
|
readBytes().loadAs(Structmsg.RspSystemMsgNew.serializer()).run {
|
||||||
val struct = groupmsgs?.firstOrNull()
|
val struct = groupmsgs?.firstOrNull() ?: return null // 会有重复且无法过滤, 不要用 map
|
||||||
|
|
||||||
return struct?.msg?.run {
|
if (!bot.client.syncingController.systemMsgNewGroupCacheList.addCache(
|
||||||
|
QQAndroidClient.MessageSvcSyncData.SystemMsgNewGroupSyncId(struct.msgSeq, struct.msgTime)
|
||||||
|
)
|
||||||
|
) { // duplicate
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return struct.msg?.run {
|
||||||
//this.soutv("SystemMsg")
|
//this.soutv("SystemMsg")
|
||||||
when (subType) {
|
when (subType) {
|
||||||
1 -> { // 处理被邀请入群 或 处理成员入群申请
|
1 -> { // 处理被邀请入群 或 处理成员入群申请
|
||||||
|
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||||
|
*
|
||||||
|
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||||
|
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
||||||
|
*
|
||||||
|
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat
|
||||||
|
|
||||||
|
import kotlinx.io.core.ByteReadPacket
|
||||||
|
import kotlinx.io.core.readBytes
|
||||||
|
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
||||||
|
import net.mamoe.mirai.qqandroid.network.Packet
|
||||||
|
import net.mamoe.mirai.qqandroid.network.QQAndroidClient
|
||||||
|
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Cmd0xed3
|
||||||
|
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.OidbSso
|
||||||
|
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.utils.io.serialization.loadAs
|
||||||
|
import net.mamoe.mirai.qqandroid.utils.io.serialization.toByteArray
|
||||||
|
import net.mamoe.mirai.qqandroid.utils.io.serialization.writeProtoBuf
|
||||||
|
|
||||||
|
internal object NudgePacket : OutgoingPacketFactory<NudgePacket.Response>("OidbSvc.0xed3") {
|
||||||
|
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
|
||||||
|
with(readBytes().loadAs(OidbSso.OIDBSSOPkg.serializer())) {
|
||||||
|
return Response(result == 0, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Response(val success: Boolean, val code: Int) : Packet {
|
||||||
|
override fun toString(): String = "NudgeResponse(success=$success,code=$code)"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun friendInvoke(
|
||||||
|
client: QQAndroidClient,
|
||||||
|
nudgeTargetId: Long,
|
||||||
|
messageReceiverUin: Long,
|
||||||
|
): OutgoingPacket {
|
||||||
|
return buildOutgoingUniPacket(client) {
|
||||||
|
writeProtoBuf(
|
||||||
|
OidbSso.OIDBSSOPkg.serializer(),
|
||||||
|
OidbSso.OIDBSSOPkg(
|
||||||
|
command = 3795,
|
||||||
|
serviceType = 1,
|
||||||
|
result = 0,
|
||||||
|
bodybuffer = Cmd0xed3.ReqBody(
|
||||||
|
toUin = nudgeTargetId,
|
||||||
|
aioUin = messageReceiverUin
|
||||||
|
).toByteArray(Cmd0xed3.ReqBody.serializer())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun troopInvoke(
|
||||||
|
client: QQAndroidClient,
|
||||||
|
messageReceiverGroupCode: Long,
|
||||||
|
nudgeTargetId: Long,
|
||||||
|
): OutgoingPacket {
|
||||||
|
return buildOutgoingUniPacket(client) {
|
||||||
|
writeProtoBuf(
|
||||||
|
OidbSso.OIDBSSOPkg.serializer(),
|
||||||
|
OidbSso.OIDBSSOPkg(
|
||||||
|
command = 3795,
|
||||||
|
serviceType = 1,
|
||||||
|
result = 0,
|
||||||
|
bodybuffer = Cmd0xed3.ReqBody(
|
||||||
|
toUin = nudgeTargetId,
|
||||||
|
groupCode = messageReceiverGroupCode
|
||||||
|
).toByteArray(Cmd0xed3.ReqBody.serializer())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -14,13 +14,13 @@ import kotlinx.io.core.buildPacket
|
|||||||
import kotlinx.io.core.readBytes
|
import kotlinx.io.core.readBytes
|
||||||
import kotlinx.io.core.toByteArray
|
import kotlinx.io.core.toByteArray
|
||||||
import net.mamoe.mirai.LowLevelAPI
|
import net.mamoe.mirai.LowLevelAPI
|
||||||
import net.mamoe.mirai.contact.Group
|
|
||||||
import net.mamoe.mirai.contact.Member
|
import net.mamoe.mirai.contact.Member
|
||||||
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
||||||
import net.mamoe.mirai.qqandroid.network.Packet
|
import net.mamoe.mirai.qqandroid.network.Packet
|
||||||
import net.mamoe.mirai.qqandroid.network.QQAndroidClient
|
import net.mamoe.mirai.qqandroid.network.QQAndroidClient
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.ModifyGroupCardReq
|
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.ModifyGroupCardReq
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.RequestPacket
|
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.RequestPacket
|
||||||
|
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.StTroopNum
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.stUinInfo
|
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.stUinInfo
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.*
|
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.*
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
|
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
|
||||||
@ -32,19 +32,19 @@ import net.mamoe.mirai.data.GroupInfo as MiraiGroupInfo
|
|||||||
|
|
||||||
@OptIn(LowLevelAPI::class)
|
@OptIn(LowLevelAPI::class)
|
||||||
internal class GroupInfoImpl(
|
internal class GroupInfoImpl(
|
||||||
internal val delegate: Oidb0x88d.GroupInfo
|
private val stTroopNum: StTroopNum
|
||||||
) : MiraiGroupInfo, Packet, Packet.NoLog {
|
) : MiraiGroupInfo, Packet, Packet.NoLog {
|
||||||
override val uin: Long get() = delegate.groupUin ?: error("cannot find groupUin")
|
override val uin: Long get() = stTroopNum.groupUin
|
||||||
override val owner: Long get() = delegate.groupOwner ?: error("cannot find groupOwner")
|
override val owner: Long get() = stTroopNum.dwGroupOwnerUin
|
||||||
override val groupCode: Long get() = Group.calculateGroupCodeByGroupUin(uin)
|
override val groupCode: Long get() = stTroopNum.groupCode
|
||||||
override val memo: String get() = delegate.groupMemo ?: error("cannot find groupMemo")
|
override val memo: String get() = stTroopNum.groupMemo
|
||||||
override val name: String get() = delegate.groupName ?: delegate.longGroupName ?: error("cannot find groupName")
|
override val name: String get() = stTroopNum.groupName
|
||||||
override val allowMemberInvite get() = delegate.groupFlagExt?.and(0x000000c0) != 0
|
override val allowMemberInvite get() = stTroopNum.dwGroupFlagExt?.and(0x000000c0) != 0L
|
||||||
override val allowAnonymousChat get() = delegate.groupFlagExt?.and(0x40000000) == 0
|
override val allowAnonymousChat get() = stTroopNum.dwGroupFlagExt?.and(0x40000000) == 0L
|
||||||
override val autoApprove get() = delegate.groupFlagext3?.and(0x00100000) == 0
|
override val autoApprove get() = stTroopNum.dwGroupFlagExt3?.and(0x00100000) == 0L
|
||||||
override val confessTalk get() = delegate.groupFlagext3?.and(0x00002000) == 0
|
override val confessTalk get() = stTroopNum.dwGroupFlagExt3?.and(0x00002000) == 0L
|
||||||
override val muteAll: Boolean get() = delegate.shutupTimestamp != 0
|
override val muteAll: Boolean get() = stTroopNum.dwShutUpTimestamp != 0L
|
||||||
override val botMuteTimestamp: Int get() = delegate.shutupTimestampMe ?: 0
|
override val botMuteTimestamp: Int get() = stTroopNum.dwMyShutUpTimestamp?.toInt() ?: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class TroopManagement {
|
internal class TroopManagement {
|
||||||
@ -88,6 +88,7 @@ internal class TroopManagement {
|
|||||||
|
|
||||||
|
|
||||||
internal object GetGroupInfo : OutgoingPacketFactory<GroupInfoImpl>("OidbSvc.0x88d_7") {
|
internal object GetGroupInfo : OutgoingPacketFactory<GroupInfoImpl>("OidbSvc.0x88d_7") {
|
||||||
|
@Deprecated("")
|
||||||
operator fun invoke(
|
operator fun invoke(
|
||||||
client: QQAndroidClient,
|
client: QQAndroidClient,
|
||||||
groupCode: Long
|
groupCode: Long
|
||||||
@ -107,8 +108,8 @@ internal class TroopManagement {
|
|||||||
groupFlagExt = 0,
|
groupFlagExt = 0,
|
||||||
groupFlagext4 = 0,
|
groupFlagext4 = 0,
|
||||||
groupFlag = 0,
|
groupFlag = 0,
|
||||||
groupFlagext3 = 0,//获取confess
|
groupFlagext3 = 1,//获取confess
|
||||||
noFingerOpenFlag = 0,
|
noFingerOpenFlag = 1,
|
||||||
cmduinFlagEx2 = 0,
|
cmduinFlagEx2 = 0,
|
||||||
groupTypeFlag = 0,
|
groupTypeFlag = 0,
|
||||||
appPrivilegeFlag = 0,
|
appPrivilegeFlag = 0,
|
||||||
@ -135,12 +136,14 @@ internal class TroopManagement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): GroupInfoImpl {
|
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): GroupInfoImpl {
|
||||||
|
error("deprecated")
|
||||||
|
/*
|
||||||
with(
|
with(
|
||||||
this.readBytes()
|
this.readBytes()
|
||||||
.loadAs(OidbSso.OIDBSSOPkg.serializer()).bodybuffer.loadAs(Oidb0x88d.RspBody.serializer()).stzrspgroupinfo!![0].stgroupinfo!!
|
.loadAs(OidbSso.OIDBSSOPkg.serializer()).bodybuffer.loadAs(Oidb0x88d.RspBody.serializer()).stzrspgroupinfo!![0].stgroupinfo!!
|
||||||
) {
|
) {
|
||||||
return GroupInfoImpl(this)
|
return GroupInfoImpl()
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,6 @@ import kotlinx.coroutines.FlowPreview
|
|||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.sync.Mutex
|
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import kotlinx.io.core.ByteReadPacket
|
import kotlinx.io.core.ByteReadPacket
|
||||||
import kotlinx.io.core.discardExact
|
import kotlinx.io.core.discardExact
|
||||||
@ -63,10 +62,6 @@ import kotlin.random.Random
|
|||||||
internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Response>("MessageSvc.PbGetMsg") {
|
internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Response>("MessageSvc.PbGetMsg") {
|
||||||
|
|
||||||
|
|
||||||
private val msgUidQueue = ArrayDeque<Long>()
|
|
||||||
private val msgUidSet = hashSetOf<Long>()
|
|
||||||
private val msgQueueMutex = Mutex()
|
|
||||||
|
|
||||||
@Suppress("SpellCheckingInspection")
|
@Suppress("SpellCheckingInspection")
|
||||||
operator fun invoke(
|
operator fun invoke(
|
||||||
client: QQAndroidClient,
|
client: QQAndroidClient,
|
||||||
@ -88,7 +83,7 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
|
|||||||
whisperSessionId = 0,
|
whisperSessionId = 0,
|
||||||
syncFlag = syncFlag,
|
syncFlag = syncFlag,
|
||||||
// serverBuf = from.serverBuf ?: EMPTY_BYTE_ARRAY,
|
// serverBuf = from.serverBuf ?: EMPTY_BYTE_ARRAY,
|
||||||
syncCookie = syncCookie ?: client.c2cMessageSync.syncCookie
|
syncCookie = syncCookie ?: client.syncingController.syncCookie
|
||||||
?: byteArrayOf()//.also { client.c2cMessageSync.syncCookie = it },
|
?: byteArrayOf()//.also { client.c2cMessageSync.syncCookie = it },
|
||||||
// syncFlag = client.c2cMessageSync.syncFlag,
|
// syncFlag = client.c2cMessageSync.syncFlag,
|
||||||
//msgCtrlBuf = client.c2cMessageSync.msgCtrlBuf,
|
//msgCtrlBuf = client.c2cMessageSync.msgCtrlBuf,
|
||||||
@ -137,6 +132,17 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun QQAndroidBot.createGroupForBot(groupUin: Long): Group? {
|
||||||
|
val group = getGroupByUinOrNull(groupUin)
|
||||||
|
if (group != null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return getNewGroup(Group.calculateGroupCodeByGroupUin(groupUin))?.apply {
|
||||||
|
groups.delegate.addLast(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@OptIn(FlowPreview::class)
|
@OptIn(FlowPreview::class)
|
||||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
|
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
|
||||||
// 00 00 01 0F 08 00 12 00 1A 34 08 FF C1 C4 F1 05 10 FF C1 C4 F1 05 18 E6 ED B9 C3 02 20 89 FE BE A4 06 28 8A CA 91 D1 0C 48 9B A5 BD 9B 0A 58 DE 9D 99 F8 08 60 1D 68 FF C1 C4 F1 05 70 00 20 02 2A 9D 01 08 F3 C1 C4 F1 05 10 A2 FF 8C F0 03 18 01 22 8A 01 0A 2A 08 A2 FF 8C F0 03 10 DD F1 92 B7 07 18 A6 01 20 0B 28 AE F9 01 30 F4 C1 C4 F1 05 38 A7 E3 D8 D4 84 80 80 80 01 B8 01 CD B5 01 12 08 08 01 10 00 18 00 20 00 1A 52 0A 50 0A 27 08 00 10 F4 C1 C4 F1 05 18 A7 E3 D8 D4 04 20 00 28 0C 30 00 38 86 01 40 22 4A 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 12 08 0A 06 0A 04 4E 4D 53 4C 12 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 12 04 4A 02 08 00 30 01 2A 15 08 97 A2 C1 F1 05 10 95 A6 F5 E5 0C 18 01 30 01 40 01 48 81 01 2A 10 08 D3 F7 B5 F1 05 10 DD F1 92 B7 07 18 01 30 01 38 00 42 00 48 00
|
// 00 00 01 0F 08 00 12 00 1A 34 08 FF C1 C4 F1 05 10 FF C1 C4 F1 05 18 E6 ED B9 C3 02 20 89 FE BE A4 06 28 8A CA 91 D1 0C 48 9B A5 BD 9B 0A 58 DE 9D 99 F8 08 60 1D 68 FF C1 C4 F1 05 70 00 20 02 2A 9D 01 08 F3 C1 C4 F1 05 10 A2 FF 8C F0 03 18 01 22 8A 01 0A 2A 08 A2 FF 8C F0 03 10 DD F1 92 B7 07 18 A6 01 20 0B 28 AE F9 01 30 F4 C1 C4 F1 05 38 A7 E3 D8 D4 84 80 80 80 01 B8 01 CD B5 01 12 08 08 01 10 00 18 00 20 00 1A 52 0A 50 0A 27 08 00 10 F4 C1 C4 F1 05 18 A7 E3 D8 D4 04 20 00 28 0C 30 00 38 86 01 40 22 4A 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 12 08 0A 06 0A 04 4E 4D 53 4C 12 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 12 04 4A 02 08 00 30 01 2A 15 08 97 A2 C1 F1 05 10 95 A6 F5 E5 0C 18 01 30 01 40 01 48 81 01 2A 10 08 D3 F7 B5 F1 05 10 DD F1 92 B7 07 18 01 30 01 38 00 42 00 48 00
|
||||||
@ -155,14 +161,14 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
|
|||||||
}
|
}
|
||||||
when (resp.msgRspType) {
|
when (resp.msgRspType) {
|
||||||
0 -> {
|
0 -> {
|
||||||
bot.client.c2cMessageSync.syncCookie = resp.syncCookie
|
bot.client.syncingController.syncCookie = resp.syncCookie
|
||||||
bot.client.c2cMessageSync.pubAccountCookie = resp.pubAccountCookie
|
bot.client.syncingController.pubAccountCookie = resp.pubAccountCookie
|
||||||
}
|
}
|
||||||
1 -> {
|
1 -> {
|
||||||
bot.client.c2cMessageSync.syncCookie = resp.syncCookie
|
bot.client.syncingController.syncCookie = resp.syncCookie
|
||||||
}
|
}
|
||||||
2 -> {
|
2 -> {
|
||||||
bot.client.c2cMessageSync.pubAccountCookie = resp.pubAccountCookie
|
bot.client.syncingController.pubAccountCookie = resp.pubAccountCookie
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -170,7 +176,7 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
|
|||||||
// bot.logger.debug(resp.msgRspType._miraiContentToString())
|
// bot.logger.debug(resp.msgRspType._miraiContentToString())
|
||||||
// bot.logger.debug(resp.syncCookie._miraiContentToString())
|
// bot.logger.debug(resp.syncCookie._miraiContentToString())
|
||||||
|
|
||||||
bot.client.c2cMessageSync.msgCtrlBuf = resp.msgCtrlBuf
|
bot.client.syncingController.msgCtrlBuf = resp.msgCtrlBuf
|
||||||
|
|
||||||
if (resp.uinPairMsgs == null) {
|
if (resp.uinPairMsgs == null) {
|
||||||
return EmptyResponse
|
return EmptyResponse
|
||||||
@ -184,37 +190,22 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
|
|||||||
}.also {
|
}.also {
|
||||||
MessageSvcPbDeleteMsg.delete(bot, it) // 删除消息
|
MessageSvcPbDeleteMsg.delete(bot, it) // 删除消息
|
||||||
}
|
}
|
||||||
.mapNotNull<MsgComm.Msg, Packet> { msg ->
|
.mapNotNull { msg ->
|
||||||
|
if (!bot.client.syncingController.pbGetMessageCacheList.addCache(
|
||||||
msgQueueMutex.lock()
|
QQAndroidClient.MessageSvcSyncData.PbGetMessageSyncId(
|
||||||
val msgUid = msg.msgHead.msgUid
|
uid = msg.msgHead.msgUid,
|
||||||
if (msgUidSet.size > 50) {
|
sequence = msg.msgHead.msgSeq,
|
||||||
msgUidSet.remove(msgUidQueue.removeFirst())
|
time = msg.msgHead.msgTime
|
||||||
}
|
)
|
||||||
if (!msgUidSet.add(msgUid)) {
|
)
|
||||||
msgQueueMutex.unlock()
|
) return@mapNotNull null
|
||||||
return@mapNotNull null
|
|
||||||
}
|
|
||||||
msgQueueMutex.unlock()
|
|
||||||
msgUidQueue.addLast(msgUid)
|
|
||||||
|
|
||||||
suspend fun createGroupForBot(groupUin: Long): Group? {
|
|
||||||
val group = bot.getGroupByUinOrNull(groupUin)
|
|
||||||
if (group != null) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return bot.getNewGroup(Group.calculateGroupCodeByGroupUin(groupUin))?.apply {
|
|
||||||
bot.groups.delegate.addLast(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
when (msg.msgHead.msgType) {
|
when (msg.msgHead.msgType) {
|
||||||
33 -> bot.groupListModifyLock.withLock {
|
33 -> bot.groupListModifyLock.withLock {
|
||||||
|
|
||||||
if (msg.msgHead.authUin == bot.id) {
|
if (msg.msgHead.authUin == bot.id) {
|
||||||
// 邀请入群
|
// 邀请入群
|
||||||
return@mapNotNull createGroupForBot(msg.msgHead.fromUin)?.let {
|
return@mapNotNull bot.createGroupForBot(msg.msgHead.fromUin)?.let {
|
||||||
// package: 27 0B 60 E7 01 CA CC 69 8B 83 44 71 47 90 06 B9 DC C0 ED D4 B1 00 30 33 44 30 42 38 46 30 39 37 32 38 35 43 34 31 38 30 33 36 41 34 36 31 36 31 35 32 37 38 46 46 43 30 41 38 30 36 30 36 45 38 31 43 39 41 34 38 37
|
// package: 27 0B 60 E7 01 CA CC 69 8B 83 44 71 47 90 06 B9 DC C0 ED D4 B1 00 30 33 44 30 42 38 46 30 39 37 32 38 35 43 34 31 38 30 33 36 41 34 36 31 36 31 35 32 37 38 46 46 43 30 41 38 30 36 30 36 45 38 31 43 39 41 34 38 37
|
||||||
// package: groupUin + 01 CA CC 69 8B 83 + invitorUin + length(06) + string + magicKey
|
// package: groupUin + 01 CA CC 69 8B 83 + invitorUin + length(06) + string + magicKey
|
||||||
val invitorUin = msg.msgBody.msgContent.sliceArray(10..13).toInt().toLong()
|
val invitorUin = msg.msgBody.msgContent.sliceArray(10..13).toInt().toLong()
|
||||||
@ -256,7 +247,7 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
38 -> bot.groupListModifyLock.withLock { // 建群
|
38 -> bot.groupListModifyLock.withLock { // 建群
|
||||||
return@mapNotNull createGroupForBot(msg.msgHead.fromUin)
|
return@mapNotNull bot.createGroupForBot(msg.msgHead.fromUin)
|
||||||
?.let { BotJoinGroupEvent.Active(it) }
|
?.let { BotJoinGroupEvent.Active(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,7 +256,7 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
|
|||||||
// msg.msgHead.authUin: 处理人
|
// msg.msgHead.authUin: 处理人
|
||||||
|
|
||||||
return@mapNotNull if (msg.msgHead.toUin == bot.id) {
|
return@mapNotNull if (msg.msgHead.toUin == bot.id) {
|
||||||
createGroupForBot(msg.msgHead.fromUin)
|
bot.createGroupForBot(msg.msgHead.fromUin)
|
||||||
?.let { BotJoinGroupEvent.Active(it) }
|
?.let { BotJoinGroupEvent.Active(it) }
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
@ -427,7 +418,7 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
|
|||||||
MessageSvcPbGetMsg(
|
MessageSvcPbGetMsg(
|
||||||
client,
|
client,
|
||||||
MsgSvc.SyncFlag.CONTINUE,
|
MsgSvc.SyncFlag.CONTINUE,
|
||||||
bot.client.c2cMessageSync.syncCookie
|
bot.client.syncingController.syncCookie
|
||||||
).sendAndExpect<Packet>()
|
).sendAndExpect<Packet>()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@ -438,7 +429,7 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
|
|||||||
MessageSvcPbGetMsg(
|
MessageSvcPbGetMsg(
|
||||||
client,
|
client,
|
||||||
MsgSvc.SyncFlag.CONTINUE,
|
MsgSvc.SyncFlag.CONTINUE,
|
||||||
bot.client.c2cMessageSync.syncCookie
|
bot.client.syncingController.syncCookie
|
||||||
).sendAndExpect<Packet>()
|
).sendAndExpect<Packet>()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@ -454,28 +445,11 @@ internal suspend fun QQAndroidBot.getNewGroup(groupCode: Long): Group? {
|
|||||||
.sendAndExpect<FriendList.GetTroopListSimplify.Response>(timeoutMillis = 10_000, retry = 5)
|
.sendAndExpect<FriendList.GetTroopListSimplify.Response>(timeoutMillis = 10_000, retry = 5)
|
||||||
}.groups.firstOrNull { it.groupCode == groupCode } ?: return null
|
}.groups.firstOrNull { it.groupCode == groupCode } ?: return null
|
||||||
|
|
||||||
@Suppress("DuplicatedCode")
|
|
||||||
return GroupImpl(
|
return GroupImpl(
|
||||||
bot = this,
|
bot = this,
|
||||||
coroutineContext = coroutineContext,
|
coroutineContext = coroutineContext,
|
||||||
id = groupCode,
|
id = groupCode,
|
||||||
groupInfo = _lowLevelQueryGroupInfo(troopNum.groupCode).apply {
|
groupInfo = GroupInfoImpl(troopNum),
|
||||||
this as GroupInfoImpl
|
|
||||||
|
|
||||||
if (this.delegate.groupName == null) {
|
|
||||||
this.delegate.groupName = troopNum.groupName
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.delegate.groupMemo == null) {
|
|
||||||
this.delegate.groupMemo = troopNum.groupMemo
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.delegate.groupUin == null) {
|
|
||||||
this.delegate.groupUin = troopNum.groupUin
|
|
||||||
}
|
|
||||||
|
|
||||||
this.delegate.groupCode = troopNum.groupCode
|
|
||||||
},
|
|
||||||
members = _lowLevelQueryGroupMemberList(
|
members = _lowLevelQueryGroupMemberList(
|
||||||
troopNum.groupUin,
|
troopNum.groupUin,
|
||||||
troopNum.groupCode,
|
troopNum.groupCode,
|
||||||
|
@ -80,7 +80,7 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
|
|||||||
),
|
),
|
||||||
msgSeq = source.sequenceId,
|
msgSeq = source.sequenceId,
|
||||||
msgRand = source.internalId,
|
msgRand = source.internalId,
|
||||||
syncCookie = client.c2cMessageSync.syncCookie ?: byteArrayOf()
|
syncCookie = client.syncingController.syncCookie ?: byteArrayOf()
|
||||||
// msgVia = 1
|
// msgVia = 1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -110,7 +110,7 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
|
|||||||
),
|
),
|
||||||
msgSeq = source.sequenceId,
|
msgSeq = source.sequenceId,
|
||||||
msgRand = source.internalId,
|
msgRand = source.internalId,
|
||||||
syncCookie = client.c2cMessageSync.syncCookie ?: byteArrayOf()
|
syncCookie = client.syncingController.syncCookie ?: byteArrayOf()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -31,13 +31,13 @@ internal object MessageSvcPushNotify : IncomingPacketFactory<RequestPushNotify>(
|
|||||||
|
|
||||||
override suspend fun QQAndroidBot.handle(packet: RequestPushNotify, sequenceId: Int): OutgoingPacket? {
|
override suspend fun QQAndroidBot.handle(packet: RequestPushNotify, sequenceId: Int): OutgoingPacket? {
|
||||||
|
|
||||||
client.c2cMessageSync.firstNotify.loop { firstNotify ->
|
client.syncingController.firstNotify.loop { firstNotify ->
|
||||||
network.run {
|
network.run {
|
||||||
return MessageSvcPbGetMsg(
|
return MessageSvcPbGetMsg(
|
||||||
client,
|
client,
|
||||||
MsgSvc.SyncFlag.START,
|
MsgSvc.SyncFlag.START,
|
||||||
if (firstNotify) {
|
if (firstNotify) {
|
||||||
if (!client.c2cMessageSync.firstNotify.compareAndSet(firstNotify, false)) {
|
if (!client.syncingController.firstNotify.compareAndSet(firstNotify, false)) {
|
||||||
return@loop
|
return@loop
|
||||||
}
|
}
|
||||||
null
|
null
|
||||||
|
@ -20,15 +20,16 @@ import kotlinx.io.core.readUByte
|
|||||||
import kotlinx.io.core.readUInt
|
import kotlinx.io.core.readUInt
|
||||||
import net.mamoe.mirai.JavaFriendlyAPI
|
import net.mamoe.mirai.JavaFriendlyAPI
|
||||||
import net.mamoe.mirai.contact.MemberPermission
|
import net.mamoe.mirai.contact.MemberPermission
|
||||||
import net.mamoe.mirai.event.events.BotGroupPermissionChangeEvent
|
import net.mamoe.mirai.data.MemberInfo
|
||||||
import net.mamoe.mirai.event.events.MemberLeaveEvent
|
import net.mamoe.mirai.event.events.*
|
||||||
import net.mamoe.mirai.event.events.MemberPermissionChangeEvent
|
|
||||||
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
||||||
import net.mamoe.mirai.qqandroid.contact.GroupImpl
|
import net.mamoe.mirai.qqandroid.contact.GroupImpl
|
||||||
import net.mamoe.mirai.qqandroid.contact.MemberImpl
|
import net.mamoe.mirai.qqandroid.contact.MemberImpl
|
||||||
import net.mamoe.mirai.qqandroid.contact.checkIsMemberImpl
|
import net.mamoe.mirai.qqandroid.contact.checkIsMemberImpl
|
||||||
import net.mamoe.mirai.qqandroid.message.contextualBugReportException
|
import net.mamoe.mirai.qqandroid.message.contextualBugReportException
|
||||||
|
import net.mamoe.mirai.qqandroid.network.MultiPacketByIterable
|
||||||
import net.mamoe.mirai.qqandroid.network.Packet
|
import net.mamoe.mirai.qqandroid.network.Packet
|
||||||
|
import net.mamoe.mirai.qqandroid.network.QQAndroidClient
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.OnlinePushTrans
|
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.OnlinePushTrans
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.IncomingPacketFactory
|
import net.mamoe.mirai.qqandroid.network.protocol.packet.IncomingPacketFactory
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
|
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
|
||||||
@ -45,52 +46,156 @@ internal object OnlinePushPbPushTransMsg :
|
|||||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): Packet? {
|
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): Packet? {
|
||||||
val content = this.readProtoBuf(OnlinePushTrans.PbMsgInfo.serializer())
|
val content = this.readProtoBuf(OnlinePushTrans.PbMsgInfo.serializer())
|
||||||
|
|
||||||
|
if (!bot.client.syncingController.pbPushTransMsgCacheList.addCache(
|
||||||
if (!bot.client.pbPushTransMsgCacheList.ensureNoDuplication(content.msgSeq)) {
|
content.run {
|
||||||
|
QQAndroidClient.MessageSvcSyncData.PbPushTransMsgSyncId(msgUid, msgSeq, msgTime)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
// bot.network.logger.debug { content._miraiContentToString() }
|
||||||
|
|
||||||
|
|
||||||
content.msgData.read<Unit> {
|
content.msgData.read<Unit> {
|
||||||
when (content.msgType) {
|
when (content.msgType) {
|
||||||
44 -> {
|
44 -> {
|
||||||
|
// 3D C4 33 DD 01 FF CD 76 F4 03 C3 7E 2E 34
|
||||||
|
// 群转让
|
||||||
|
// start with 3D C4 33 DD 01 FF
|
||||||
|
// 3D C4 33 DD 01 FF C3 7E 2E 34 CD 76 F4 03
|
||||||
|
// 权限变更
|
||||||
|
// 3D C4 33 DD 01 00/01 .....
|
||||||
|
// 3D C4 33 DD 01 01 C3 7E 2E 34 01
|
||||||
this.discardExact(5)
|
this.discardExact(5)
|
||||||
val var4 = readByte().toInt()
|
when (val mode = readUByte().toInt()) {
|
||||||
var var5 = 0L
|
0xFF -> {
|
||||||
val target = readUInt().toLong()
|
// 群转让 / huifu.qq.com
|
||||||
if (var4 != 0 && var4 != 1) {
|
// From -> to
|
||||||
var5 = readUInt().toLong()
|
val from = readUInt().toLong()
|
||||||
}
|
val to = readUInt().toLong()
|
||||||
|
val results = ArrayList<Packet>()
|
||||||
val group = bot.getGroupByUin(content.fromUin) as GroupImpl
|
// println("$from -> $to")
|
||||||
|
if (to == bot.id) {
|
||||||
if (var5 == 0L && this.remaining == 1L) {//管理员变更
|
if (bot.getGroupByUinOrNull(content.fromUin) == null) {
|
||||||
val newPermission =
|
MessageSvcPbGetMsg.run {
|
||||||
if (this.readByte().toInt() == 1) MemberPermission.ADMINISTRATOR
|
results.add(
|
||||||
else MemberPermission.MEMBER
|
BotJoinGroupEvent.Retrieve(
|
||||||
|
bot.createGroupForBot(content.fromUin)!!
|
||||||
if (target == bot.id) {
|
)
|
||||||
if (group.botPermission == newPermission) {
|
)
|
||||||
return null
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val group = bot.getGroupByUin(content.fromUin) as GroupImpl
|
||||||
|
if (from == bot.id) {
|
||||||
|
if (group.botPermission != MemberPermission.MEMBER)
|
||||||
|
results.add(
|
||||||
|
BotGroupPermissionChangeEvent(
|
||||||
|
group, group.botPermission.also {
|
||||||
|
group.botAsMember.checkIsMemberImpl().permission =
|
||||||
|
MemberPermission.MEMBER
|
||||||
|
},
|
||||||
|
MemberPermission.MEMBER
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
val member = group[from] as MemberImpl
|
||||||
|
if (member.permission != MemberPermission.MEMBER) {
|
||||||
|
results.add(
|
||||||
|
MemberPermissionChangeEvent(
|
||||||
|
member,
|
||||||
|
member.permission.also { member.permission = MemberPermission.MEMBER },
|
||||||
|
MemberPermission.MEMBER
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (to == bot.id) {
|
||||||
|
if (group.botPermission != MemberPermission.OWNER) {
|
||||||
|
results.add(
|
||||||
|
BotGroupPermissionChangeEvent(
|
||||||
|
group,
|
||||||
|
group.botAsMember.permission.also {
|
||||||
|
group.botAsMember.checkIsMemberImpl().permission =
|
||||||
|
MemberPermission.OWNER
|
||||||
|
},
|
||||||
|
MemberPermission.OWNER
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val newOwner = group.getOrNull(to) ?: group.newMember(object : MemberInfo {
|
||||||
|
override val nameCard: String
|
||||||
|
get() = ""
|
||||||
|
override val permission: MemberPermission
|
||||||
|
get() = MemberPermission.OWNER
|
||||||
|
override val specialTitle: String
|
||||||
|
get() = ""
|
||||||
|
override val muteTimestamp: Int
|
||||||
|
get() = 0
|
||||||
|
override val uin: Long
|
||||||
|
get() = to
|
||||||
|
override val nick: String
|
||||||
|
get() = ""
|
||||||
|
}).also { owner ->
|
||||||
|
owner.checkIsMemberImpl().permission = MemberPermission.OWNER
|
||||||
|
group.members.delegate.addLast(owner)
|
||||||
|
results.add(MemberJoinEvent.Retrieve(owner))
|
||||||
|
}
|
||||||
|
if (newOwner.permission != MemberPermission.OWNER) {
|
||||||
|
results.add(
|
||||||
|
MemberPermissionChangeEvent(
|
||||||
|
newOwner,
|
||||||
|
newOwner.permission.also {
|
||||||
|
newOwner.checkIsMemberImpl().permission = MemberPermission.OWNER
|
||||||
|
},
|
||||||
|
MemberPermission.OWNER
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MultiPacketByIterable(results)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
var var5 = 0L
|
||||||
|
val target = readUInt().toLong()
|
||||||
|
if (mode != 0 && mode != 1) {
|
||||||
|
var5 = readUInt().toLong()
|
||||||
}
|
}
|
||||||
|
|
||||||
return BotGroupPermissionChangeEvent(
|
val group = bot.getGroupByUin(content.fromUin) as GroupImpl
|
||||||
group,
|
|
||||||
group.botPermission.also {
|
|
||||||
group.botAsMember.checkIsMemberImpl().permission = newPermission
|
|
||||||
},
|
|
||||||
newPermission
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
val member = group[target] as MemberImpl
|
|
||||||
if (member.permission == newPermission) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return MemberPermissionChangeEvent(
|
if (var5 == 0L && this.remaining == 1L) {//管理员变更
|
||||||
member,
|
val newPermission =
|
||||||
member.permission.also { member.permission = newPermission },
|
if (this.readByte().toInt() == 1) MemberPermission.ADMINISTRATOR
|
||||||
newPermission
|
else MemberPermission.MEMBER
|
||||||
)
|
|
||||||
|
if (target == bot.id) {
|
||||||
|
if (group.botPermission == newPermission) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return BotGroupPermissionChangeEvent(
|
||||||
|
group,
|
||||||
|
group.botPermission.also {
|
||||||
|
group.botAsMember.checkIsMemberImpl().permission = newPermission
|
||||||
|
},
|
||||||
|
newPermission
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
val member = group[target] as MemberImpl
|
||||||
|
if (member.permission == newPermission) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return MemberPermissionChangeEvent(
|
||||||
|
member,
|
||||||
|
member.permission.also { member.permission = newPermission },
|
||||||
|
newPermission
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -108,28 +213,41 @@ internal object OnlinePushPbPushTransMsg :
|
|||||||
A8 32 51 A1
|
A8 32 51 A1
|
||||||
83 3E 03 3F A2 06 B4 B4 BD A8 D5 DF 00 30 39 32 46 45 30 36 31 41 33 37 36 43 44 35 37 35 37 39 45 37 32 34 44 37 37 30 36 46 39 39 43 35 35 33 33 31 34 44 32 44 46 35 45 42 43 31 31 36
|
83 3E 03 3F A2 06 B4 B4 BD A8 D5 DF 00 30 39 32 46 45 30 36 31 41 33 37 36 43 44 35 37 35 37 39 45 37 32 34 44 37 37 30 36 46 39 39 43 35 35 33 33 31 34 44 32 44 46 35 45 42 43 31 31 36
|
||||||
*/
|
*/
|
||||||
readUInt().toLong() // group, uin or code ?
|
readUInt().toLong() // groupUin
|
||||||
|
readByte().toInt() // follow type
|
||||||
discardExact(1)
|
|
||||||
val target = readUInt().toLong()
|
val target = readUInt().toLong()
|
||||||
val type = readUByte().toInt()
|
val type = readUByte().toInt()
|
||||||
val operator = readUInt().toLong()
|
val operator = readUInt().toLong()
|
||||||
val groupUin = content.fromUin
|
val groupUin = content.fromUin
|
||||||
|
|
||||||
when (type) {
|
when (type) {
|
||||||
0x82 -> bot.getGroupByUinOrNull(groupUin)?.let { group ->
|
2, 0x82 -> bot.getGroupByUinOrNull(groupUin)?.let { group ->
|
||||||
val member = group.getOrNull(target) as? MemberImpl ?: return null
|
if (target == bot.id) {
|
||||||
return MemberLeaveEvent.Quit(member.also {
|
return BotLeaveEvent.Active(group).also {
|
||||||
member.cancel(CancellationException("Leaved actively"))
|
group.cancel(CancellationException("Leaved actively"))
|
||||||
group.members.delegate.remove(member)
|
bot.groups.delegate.remove(group)
|
||||||
})
|
}
|
||||||
|
} else {
|
||||||
|
val member = group.getOrNull(target) as? MemberImpl ?: return null
|
||||||
|
return MemberLeaveEvent.Quit(member.also {
|
||||||
|
member.cancel(CancellationException("Leaved actively"))
|
||||||
|
group.members.delegate.remove(member)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
0x83 -> bot.getGroupByUin(groupUin).let { group ->
|
3, 0x83 -> bot.getGroupByUin(groupUin).let { group ->
|
||||||
val member = group.getOrNull(target) as? MemberImpl ?: return null
|
if (target == bot.id) {
|
||||||
return MemberLeaveEvent.Kick(member.also {
|
return BotLeaveEvent.Kick(group.members[operator]).also {
|
||||||
member.cancel(CancellationException("Leaved actively"))
|
group.cancel(CancellationException("Being kicked"))
|
||||||
group.members.delegate.remove(member)
|
bot.groups.delegate.remove(group)
|
||||||
}, group.members[operator])
|
}
|
||||||
|
} else {
|
||||||
|
val member = group.getOrNull(target) as? MemberImpl ?: return null
|
||||||
|
return MemberLeaveEvent.Kick(member.also {
|
||||||
|
member.cancel(CancellationException("Being kicked"))
|
||||||
|
group.members.delegate.remove(member)
|
||||||
|
}, group.members[operator])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,6 @@
|
|||||||
|
|
||||||
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive
|
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive
|
||||||
|
|
||||||
import kotlinx.coroutines.CancellationException
|
|
||||||
import kotlinx.coroutines.cancel
|
|
||||||
import kotlinx.io.core.ByteReadPacket
|
import kotlinx.io.core.ByteReadPacket
|
||||||
import kotlinx.io.core.discardExact
|
import kotlinx.io.core.discardExact
|
||||||
import kotlinx.io.core.readBytes
|
import kotlinx.io.core.readBytes
|
||||||
@ -23,6 +21,8 @@ import kotlinx.io.core.readUInt
|
|||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.protobuf.ProtoNumber
|
import kotlinx.serialization.protobuf.ProtoNumber
|
||||||
import net.mamoe.mirai.JavaFriendlyAPI
|
import net.mamoe.mirai.JavaFriendlyAPI
|
||||||
|
import net.mamoe.mirai.contact.Friend
|
||||||
|
import net.mamoe.mirai.contact.Member
|
||||||
import net.mamoe.mirai.data.FriendInfo
|
import net.mamoe.mirai.data.FriendInfo
|
||||||
import net.mamoe.mirai.event.events.*
|
import net.mamoe.mirai.event.events.*
|
||||||
import net.mamoe.mirai.getFriendOrNull
|
import net.mamoe.mirai.getFriendOrNull
|
||||||
@ -37,8 +37,9 @@ import net.mamoe.mirai.qqandroid.network.protocol.data.jce.MsgType0x210
|
|||||||
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.OnlinePushPack
|
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.OnlinePushPack
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.RequestPacket
|
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.RequestPacket
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Submsgtype0x115
|
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Submsgtype0x115
|
||||||
|
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Submsgtype0x122
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Submsgtype0x27.SubMsgType0x27.*
|
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Submsgtype0x27.SubMsgType0x27.*
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Submsgtype0x44
|
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Submsgtype0x44.Submsgtype0x44
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Submsgtype0xb3
|
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Submsgtype0xb3
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.TroopTips0x857
|
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.TroopTips0x857
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.IncomingPacketFactory
|
import net.mamoe.mirai.qqandroid.network.protocol.packet.IncomingPacketFactory
|
||||||
@ -66,7 +67,11 @@ internal object OnlinePushReqPush : IncomingPacketFactory<OnlinePushReqPush.ReqP
|
|||||||
mapper: ByteReadPacket.(msgInfo: MsgInfo) -> Sequence<Packet>
|
mapper: ByteReadPacket.(msgInfo: MsgInfo) -> Sequence<Packet>
|
||||||
): Sequence<Packet> {
|
): Sequence<Packet> {
|
||||||
return asSequence().filter { msg ->
|
return asSequence().filter { msg ->
|
||||||
client.onlinePushCacheList.ensureNoDuplication(msg.shMsgSeq)
|
!client.syncingController.onlinePushReqPushCacheList.addCache(
|
||||||
|
QQAndroidClient.MessageSvcSyncData.OnlinePushReqPushSyncId(
|
||||||
|
uid = msg.lMsgUid ?: 0, sequence = msg.shMsgSeq, time = msg.uMsgTime
|
||||||
|
)
|
||||||
|
)
|
||||||
}.flatMap { it.vMsg.read { mapper(it) } }
|
}.flatMap { it.vMsg.read { mapper(it) } }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +106,7 @@ internal object OnlinePushReqPush : IncomingPacketFactory<OnlinePushReqPush.ReqP
|
|||||||
528 -> {
|
528 -> {
|
||||||
val notifyMsgBody = readJceStruct(MsgType0x210.serializer())
|
val notifyMsgBody = readJceStruct(MsgType0x210.serializer())
|
||||||
Transformers528[notifyMsgBody.uSubMsgType]
|
Transformers528[notifyMsgBody.uSubMsgType]
|
||||||
?.let { processor -> processor(notifyMsgBody, bot) }
|
?.let { processor -> processor(notifyMsgBody, bot, msgInfo) }
|
||||||
?: kotlin.run {
|
?: kotlin.run {
|
||||||
bot.network.logger.debug {
|
bot.network.logger.debug {
|
||||||
"unknown group 528 type 0x${notifyMsgBody.uSubMsgType.toUHexString("")}, data: " + notifyMsgBody.vProtobuf.toUHexString()
|
"unknown group 528 type 0x${notifyMsgBody.uSubMsgType.toUHexString("")}, data: " + notifyMsgBody.vProtobuf.toUHexString()
|
||||||
@ -231,6 +236,44 @@ private object Transformers732 : Map<Int, Lambda732> by mapOf(
|
|||||||
return@lambda732 sequenceOf(GroupAllowAnonymousChatEvent(!new, new, group, operator))
|
return@lambda732 sequenceOf(GroupAllowAnonymousChatEvent(!new, new, group, operator))
|
||||||
},
|
},
|
||||||
|
|
||||||
|
//系统提示
|
||||||
|
0x14 to lambda732 { group: GroupImpl, bot: QQAndroidBot ->
|
||||||
|
|
||||||
|
discardExact(1)
|
||||||
|
val grayTip = readProtoBuf(TroopTips0x857.NotifyMsgBody.serializer()).optGeneralGrayTip
|
||||||
|
when (grayTip?.templId) {
|
||||||
|
//戳一戳
|
||||||
|
10043L, 1134L, 1135L -> {
|
||||||
|
//预置数据,服务器将不会提供己方已知消息
|
||||||
|
var action = ""
|
||||||
|
var from: Member = group.botAsMember
|
||||||
|
var target: Member = group.botAsMember
|
||||||
|
var suffix = ""
|
||||||
|
grayTip.msgTemplParam?.map {
|
||||||
|
Pair(it.name.decodeToString(), it.value.decodeToString())
|
||||||
|
}?.asSequence()?.forEach { (key, value) ->
|
||||||
|
run {
|
||||||
|
when (key) {
|
||||||
|
"action_str" -> action = value
|
||||||
|
"uin_str1" -> from = group[value.toLong()]
|
||||||
|
"uin_str2" -> target = group[value.toLong()]
|
||||||
|
"suffix_str" -> suffix = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (target.id == bot.id) {
|
||||||
|
return@lambda732 sequenceOf(BotNudgedEvent(from, action, suffix))
|
||||||
|
}
|
||||||
|
return@lambda732 sequenceOf(MemberNudgedEvent(from, target, action, suffix))
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
bot.network.logger.debug {
|
||||||
|
"Unknown Transformers528 0x14 template\ntemplId=${grayTip?.templId}\nPermList=${grayTip?.msgTemplParam?._miraiContentToString()}"
|
||||||
|
}
|
||||||
|
return@lambda732 emptySequence()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
// 传字符串信息
|
// 传字符串信息
|
||||||
0x10 to lambda732 { group: GroupImpl, bot: QQAndroidBot ->
|
0x10 to lambda732 { group: GroupImpl, bot: QQAndroidBot ->
|
||||||
val dataBytes = readBytes(26)
|
val dataBytes = readBytes(26)
|
||||||
@ -329,17 +372,28 @@ private object Transformers732 : Map<Int, Lambda732> by mapOf(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
internal val ignoredLambda528: Lambda528 = lambda528 { emptySequence() }
|
internal val ignoredLambda528: Lambda528 = lambda528 { _, _ -> emptySequence() }
|
||||||
|
|
||||||
internal interface Lambda528 {
|
internal interface Lambda528 {
|
||||||
operator fun invoke(msg: MsgType0x210, bot: QQAndroidBot): Sequence<Packet>
|
operator fun invoke(msg: MsgType0x210, bot: QQAndroidBot, msgInfo: MsgInfo): Sequence<Packet>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@kotlin.internal.LowPriorityInOverloadResolution
|
||||||
internal inline fun lambda528(crossinline block: MsgType0x210.(QQAndroidBot) -> Sequence<Packet>): Lambda528 {
|
internal inline fun lambda528(crossinline block: MsgType0x210.(QQAndroidBot) -> Sequence<Packet>): Lambda528 {
|
||||||
return object : Lambda528 {
|
return object : Lambda528 {
|
||||||
override fun invoke(msg: MsgType0x210, bot: QQAndroidBot): Sequence<Packet> {
|
override fun invoke(msg: MsgType0x210, bot: QQAndroidBot, msgInfo: MsgInfo): Sequence<Packet> {
|
||||||
return block(msg, bot)
|
return block(msg, bot)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal inline fun lambda528(crossinline block: MsgType0x210.(QQAndroidBot, MsgInfo) -> Sequence<Packet>): Lambda528 {
|
||||||
|
return object : Lambda528 {
|
||||||
|
override fun invoke(msg: MsgType0x210, bot: QQAndroidBot, msgInfo: MsgInfo): Sequence<Packet> {
|
||||||
|
return block(msg, bot, msgInfo)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -353,7 +407,7 @@ internal object Transformers528 : Map<Long, Lambda528> by mapOf(
|
|||||||
|
|
||||||
0x8AL to lambda528 { bot ->
|
0x8AL to lambda528 { bot ->
|
||||||
@Serializable
|
@Serializable
|
||||||
data class Sub8AMsgInfo(
|
class Sub8AMsgInfo(
|
||||||
@ProtoNumber(1) val fromUin: Long,
|
@ProtoNumber(1) val fromUin: Long,
|
||||||
@ProtoNumber(2) val botUin: Long,
|
@ProtoNumber(2) val botUin: Long,
|
||||||
@ProtoNumber(3) val srcId: Int,
|
@ProtoNumber(3) val srcId: Int,
|
||||||
@ -367,7 +421,7 @@ internal object Transformers528 : Map<Long, Lambda528> by mapOf(
|
|||||||
) : ProtoBuf
|
) : ProtoBuf
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class Sub8A(
|
class Sub8A(
|
||||||
@ProtoNumber(1) val msgInfo: List<Sub8AMsgInfo>,
|
@ProtoNumber(1) val msgInfo: List<Sub8AMsgInfo>,
|
||||||
@ProtoNumber(2) val appId: Int, // 1
|
@ProtoNumber(2) val appId: Int, // 1
|
||||||
@ProtoNumber(3) val instId: Int, // 1
|
@ProtoNumber(3) val instId: Int, // 1
|
||||||
@ -403,7 +457,7 @@ internal object Transformers528 : Map<Long, Lambda528> by mapOf(
|
|||||||
bot.friends.delegate.addLast(new)
|
bot.friends.delegate.addLast(new)
|
||||||
return@lambda528 sequenceOf(FriendAddEvent(new))
|
return@lambda528 sequenceOf(FriendAddEvent(new))
|
||||||
},
|
},
|
||||||
0xE2L to lambda528 {
|
0xE2L to lambda528 { _ ->
|
||||||
// TODO: unknown. maybe messages.
|
// TODO: unknown. maybe messages.
|
||||||
// 0A 35 08 00 10 A2 FF 8C F0 03 1A 1B E5 90 8C E6 84 8F E4 BD A0 E7 9A 84 E5 8A A0 E5 A5 BD E5 8F 8B E8 AF B7 E6 B1 82 22 0C E6 BD 9C E6 B1 9F E7 BE A4 E5 8F 8B 28 01
|
// 0A 35 08 00 10 A2 FF 8C F0 03 1A 1B E5 90 8C E6 84 8F E4 BD A0 E7 9A 84 E5 8A A0 E5 A5 BD E5 8F 8B E8 AF B7 E6 B1 82 22 0C E6 BD 9C E6 B1 9F E7 BE A4 E5 8F 8B 28 01
|
||||||
// vProtobuf.loadAs(Msgtype0x210.serializer())
|
// vProtobuf.loadAs(Msgtype0x210.serializer())
|
||||||
@ -411,7 +465,7 @@ internal object Transformers528 : Map<Long, Lambda528> by mapOf(
|
|||||||
return@lambda528 emptySequence()
|
return@lambda528 emptySequence()
|
||||||
},
|
},
|
||||||
0x44L to lambda528 { bot ->
|
0x44L to lambda528 { bot ->
|
||||||
val msg = vProtobuf.loadAs(Submsgtype0x44.Submsgtype0x44.MsgBody.serializer())
|
val msg = vProtobuf.loadAs(Submsgtype0x44.MsgBody.serializer())
|
||||||
when {
|
when {
|
||||||
msg.msgCleanCountMsg != null -> {
|
msg.msgCleanCountMsg != null -> {
|
||||||
|
|
||||||
@ -426,20 +480,55 @@ internal object Transformers528 : Map<Long, Lambda528> by mapOf(
|
|||||||
return@lambda528 emptySequence()
|
return@lambda528 emptySequence()
|
||||||
},
|
},
|
||||||
// bot 在其他客户端被踢或主动退出而同步情况
|
// bot 在其他客户端被踢或主动退出而同步情况
|
||||||
0xD4L to lambda528 { bot ->
|
0xD4L to lambda528 { _ ->
|
||||||
// this.soutv("0x210")
|
// this.soutv("0x210")
|
||||||
@Serializable
|
/* @Serializable
|
||||||
data class SubD4(
|
data class SubD4(
|
||||||
// ok
|
// ok
|
||||||
val uin: Long
|
val uin: Long
|
||||||
) : ProtoBuf
|
) : ProtoBuf
|
||||||
|
|
||||||
val uin = vProtobuf.loadAs(SubD4.serializer()).uin
|
val uin = vProtobuf.loadAs(SubD4.serializer()).uin
|
||||||
val group = bot.getGroupByUinOrNull(uin) ?: bot.getGroupOrNull(uin)
|
val group = bot.getGroupByUinOrNull(uin) ?: bot.getGroupOrNull(uin)
|
||||||
return@lambda528 if (group != null && bot.groups.delegate.remove(group)) {
|
return@lambda528 if (group != null && bot.groups.delegate.remove(group)) {
|
||||||
group.cancel(CancellationException("Being kicked"))
|
group.cancel(CancellationException("Being kicked"))
|
||||||
sequenceOf(BotLeaveEvent.Active(group))
|
sequenceOf(BotLeaveEvent.Active(group))
|
||||||
} else emptySequence()
|
} else emptySequence()*/
|
||||||
|
|
||||||
|
//ignore
|
||||||
|
return@lambda528 emptySequence()
|
||||||
|
},
|
||||||
|
//戳一戳信息等
|
||||||
|
0x122L to lambda528 { bot, _ ->
|
||||||
|
val body = vProtobuf.loadAs(Submsgtype0x122.Submsgtype0x122.MsgBody.serializer())
|
||||||
|
when (body.templId) {
|
||||||
|
//戳一戳
|
||||||
|
1134L, 1135L, 1136L, 10043L -> {
|
||||||
|
//预置数据,服务器将不会提供己方已知消息
|
||||||
|
var from: Friend = bot.selfQQ
|
||||||
|
var action = ""
|
||||||
|
var target: Friend = bot.selfQQ
|
||||||
|
var suffix = ""
|
||||||
|
body.msgTemplParam?.asSequence()?.map {
|
||||||
|
it.name.decodeToString() to it.value.decodeToString()
|
||||||
|
}?.forEach { (key, value) ->
|
||||||
|
when (key) {
|
||||||
|
"action_str" -> action = value
|
||||||
|
"uin_str1" -> from = bot.getFriend(value.toLong())
|
||||||
|
"uin_str2" -> target = bot.getFriend(value.toLong())
|
||||||
|
"suffix_str" -> suffix = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return@lambda528 sequenceOf(BotNudgedEvent(from, action, suffix))
|
||||||
|
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
bot.logger.debug {
|
||||||
|
"Unknown Transformers528 0x122L template\ntemplId=${body.templId}\nPermList=${body.msgTemplParam?._miraiContentToString()}"
|
||||||
|
}
|
||||||
|
return@lambda528 emptySequence()
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
//好友输入状态
|
//好友输入状态
|
||||||
0x115L to lambda528 { bot ->
|
0x115L to lambda528 { bot ->
|
||||||
@ -579,12 +668,10 @@ internal object Transformers528 : Map<Long, Lambda528> by mapOf(
|
|||||||
val to = value.encodeToString()
|
val to = value.encodeToString()
|
||||||
if (uin == bot.id) {
|
if (uin == bot.id) {
|
||||||
val from = bot.nick
|
val from = bot.nick
|
||||||
bot.cachedNick = to
|
if (from != to) {
|
||||||
add(
|
bot.nick = to
|
||||||
BotNickChangedEvent(
|
add(BotNickChangedEvent(bot, from, to))
|
||||||
bot, from, to
|
}
|
||||||
)
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
val friend = (bot.getFriendOrNull(uin) ?: return@forEach) as FriendImpl
|
val friend = (bot.getFriendOrNull(uin) ?: return@forEach) as FriendImpl
|
||||||
val info = friend.friendInfo
|
val info = friend.friendInfo
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||||
|
*
|
||||||
|
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||||
|
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
||||||
|
*
|
||||||
|
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.mamoe.mirai.qqandroid.utils
|
||||||
|
|
||||||
|
// We target JVM and Android only.
|
||||||
|
internal expect class LinkedList<E>() : List<E>, Queue<E>, Deque<E>
|
||||||
|
|
||||||
|
internal interface Queue<E> : MutableCollection<E> {
|
||||||
|
override fun add(element: E): Boolean
|
||||||
|
fun offer(element: E): Boolean
|
||||||
|
fun remove(): E
|
||||||
|
fun poll(): E
|
||||||
|
fun element(): E
|
||||||
|
fun peek(): E
|
||||||
|
}
|
||||||
|
|
||||||
|
internal interface Deque<E> : Queue<E> {
|
||||||
|
fun addFirst(e: E)
|
||||||
|
fun addLast(e: E)
|
||||||
|
fun offerFirst(e: E): Boolean
|
||||||
|
fun offerLast(e: E): Boolean
|
||||||
|
fun removeFirst(): E
|
||||||
|
fun removeLast(): E
|
||||||
|
fun pollFirst(): E
|
||||||
|
fun pollLast(): E
|
||||||
|
val first: E
|
||||||
|
val last: E
|
||||||
|
fun peekFirst(): E
|
||||||
|
fun peekLast(): E
|
||||||
|
fun removeFirstOccurrence(o: E): Boolean
|
||||||
|
fun removeLastOccurrence(o: E): Boolean
|
||||||
|
fun push(e: E)
|
||||||
|
fun pop(): E
|
||||||
|
fun descendingIterator(): Iterator<E>
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* * Copyright 2020 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/master/LICENSE
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.mamoe.mirai.qqandroid.utils
|
||||||
|
|
||||||
|
import java.util.LinkedList
|
||||||
|
|
||||||
|
@Suppress("ACTUAL_WITHOUT_EXPECT")
|
||||||
|
internal actual typealias LinkedList<E> = LinkedList<E>
|
@ -10,6 +10,7 @@
|
|||||||
package net.mamoe.mirai.qqandroid.utils
|
package net.mamoe.mirai.qqandroid.utils
|
||||||
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.io.core.ByteReadPacket
|
import kotlinx.io.core.ByteReadPacket
|
||||||
import kotlinx.io.core.Closeable
|
import kotlinx.io.core.Closeable
|
||||||
@ -20,6 +21,7 @@ import java.io.BufferedInputStream
|
|||||||
import java.io.BufferedOutputStream
|
import java.io.BufferedOutputStream
|
||||||
import java.net.Socket
|
import java.net.Socket
|
||||||
import java.net.SocketException
|
import java.net.SocketException
|
||||||
|
import java.util.concurrent.Executors
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,6 +40,7 @@ internal actual class PlatformSocket : Closeable {
|
|||||||
if (::socket.isInitialized) {
|
if (::socket.isInitialized) {
|
||||||
socket.close()
|
socket.close()
|
||||||
}
|
}
|
||||||
|
thread.shutdownNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
@PublishedApi
|
@PublishedApi
|
||||||
@ -67,15 +70,17 @@ internal actual class PlatformSocket : Closeable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val thread = Executors.newSingleThreadExecutor()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws ReadPacketInternalException
|
* @throws ReadPacketInternalException
|
||||||
*/
|
*/
|
||||||
actual suspend fun read(): ByteReadPacket {
|
actual suspend fun read(): ByteReadPacket = suspendCancellableCoroutine { cont ->
|
||||||
return withContext(Dispatchers.IO) {
|
thread.submit {
|
||||||
try {
|
kotlin.runCatching {
|
||||||
readChannel.readPacketAtMost(Long.MAX_VALUE)
|
readChannel.readPacketAtMost(Long.MAX_VALUE)
|
||||||
} catch (e: IOException) {
|
}.let {
|
||||||
throw ReadPacketInternalException(e)
|
cont.resumeWith(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,9 @@ import net.mamoe.mirai.event.events.BotInvitedJoinGroupRequestEvent
|
|||||||
import net.mamoe.mirai.event.events.MemberJoinRequestEvent
|
import net.mamoe.mirai.event.events.MemberJoinRequestEvent
|
||||||
import net.mamoe.mirai.event.events.NewFriendRequestEvent
|
import net.mamoe.mirai.event.events.NewFriendRequestEvent
|
||||||
import net.mamoe.mirai.message.MessageReceipt
|
import net.mamoe.mirai.message.MessageReceipt
|
||||||
|
import net.mamoe.mirai.message.action.BotNudge
|
||||||
|
import net.mamoe.mirai.message.action.MemberNudge
|
||||||
|
import net.mamoe.mirai.message.action.Nudge
|
||||||
import net.mamoe.mirai.message.data.*
|
import net.mamoe.mirai.message.data.*
|
||||||
import net.mamoe.mirai.network.LoginFailedException
|
import net.mamoe.mirai.network.LoginFailedException
|
||||||
import net.mamoe.mirai.utils.*
|
import net.mamoe.mirai.utils.*
|
||||||
@ -216,6 +219,15 @@ public abstract class Bot internal constructor(
|
|||||||
@JvmSynthetic
|
@JvmSynthetic
|
||||||
public abstract suspend fun recall(source: MessageSource)
|
public abstract suspend fun recall(source: MessageSource)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个 "戳一戳" 消息
|
||||||
|
*
|
||||||
|
* @see MemberNudge.sendTo 发送这个戳一戳消息
|
||||||
|
*/
|
||||||
|
@MiraiExperimentalAPI
|
||||||
|
@SinceMirai("1.3.0")
|
||||||
|
public fun nudge(): BotNudge = BotNudge(this)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取图片下载链接
|
* 获取图片下载链接
|
||||||
*
|
*
|
||||||
@ -339,6 +351,14 @@ public abstract class Bot internal constructor(
|
|||||||
@JvmSynthetic
|
@JvmSynthetic
|
||||||
public abstract suspend fun ignoreInvitedJoinGroupRequest(event: BotInvitedJoinGroupRequestEvent)
|
public abstract suspend fun ignoreInvitedJoinGroupRequest(event: BotInvitedJoinGroupRequestEvent)
|
||||||
|
|
||||||
|
@Deprecated(
|
||||||
|
"use member function.",
|
||||||
|
replaceWith = ReplaceWith("nudge.sendTo(contact)"),
|
||||||
|
level = DeprecationLevel.ERROR
|
||||||
|
)
|
||||||
|
@SinceMirai("1.3.0")
|
||||||
|
public abstract suspend fun sendNudge(nudge: Nudge, receiver: Contact): Boolean
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -13,6 +13,7 @@ package net.mamoe.mirai
|
|||||||
|
|
||||||
import net.mamoe.mirai.utils.BotConfiguration
|
import net.mamoe.mirai.utils.BotConfiguration
|
||||||
import net.mamoe.mirai.utils.Context
|
import net.mamoe.mirai.utils.Context
|
||||||
|
import net.mamoe.mirai.utils.SinceMirai
|
||||||
import kotlin.jvm.JvmName
|
import kotlin.jvm.JvmName
|
||||||
import kotlin.jvm.JvmSynthetic
|
import kotlin.jvm.JvmSynthetic
|
||||||
|
|
||||||
@ -45,6 +46,9 @@ public expect interface BotFactory {
|
|||||||
passwordMd5: ByteArray,
|
passwordMd5: ByteArray,
|
||||||
configuration: BotConfiguration = BotConfiguration.Default
|
configuration: BotConfiguration = BotConfiguration.Default
|
||||||
): Bot
|
): Bot
|
||||||
|
|
||||||
|
@SinceMirai("1.3.0")
|
||||||
|
public companion object INSTANCE : BotFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18,10 +18,13 @@ import net.mamoe.mirai.event.events.FriendMessagePostSendEvent
|
|||||||
import net.mamoe.mirai.event.events.FriendMessagePreSendEvent
|
import net.mamoe.mirai.event.events.FriendMessagePreSendEvent
|
||||||
import net.mamoe.mirai.message.FriendMessageEvent
|
import net.mamoe.mirai.message.FriendMessageEvent
|
||||||
import net.mamoe.mirai.message.MessageReceipt
|
import net.mamoe.mirai.message.MessageReceipt
|
||||||
|
import net.mamoe.mirai.message.action.FriendNudge
|
||||||
import net.mamoe.mirai.message.data.Message
|
import net.mamoe.mirai.message.data.Message
|
||||||
import net.mamoe.mirai.message.data.PlainText
|
import net.mamoe.mirai.message.data.PlainText
|
||||||
import net.mamoe.mirai.message.data.isContentEmpty
|
import net.mamoe.mirai.message.data.isContentEmpty
|
||||||
import net.mamoe.mirai.message.recall
|
import net.mamoe.mirai.message.recall
|
||||||
|
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||||
|
import net.mamoe.mirai.utils.SinceMirai
|
||||||
import kotlin.jvm.JvmSynthetic
|
import kotlin.jvm.JvmSynthetic
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -70,6 +73,15 @@ public abstract class Friend : User(), CoroutineScope {
|
|||||||
@JvmSynthetic
|
@JvmSynthetic
|
||||||
abstract override suspend fun sendMessage(message: Message): MessageReceipt<Friend>
|
abstract override suspend fun sendMessage(message: Message): MessageReceipt<Friend>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个 "戳一戳" 消息
|
||||||
|
*
|
||||||
|
* @see FriendNudge.sendTo 发送这个戳一戳消息
|
||||||
|
*/
|
||||||
|
@MiraiExperimentalAPI
|
||||||
|
@SinceMirai("1.3.0")
|
||||||
|
public final override fun nudge(): FriendNudge = FriendNudge(this)
|
||||||
|
|
||||||
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "VIRTUAL_MEMBER_HIDDEN", "OVERRIDE_BY_INLINE")
|
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "VIRTUAL_MEMBER_HIDDEN", "OVERRIDE_BY_INLINE")
|
||||||
@kotlin.internal.InlineOnly
|
@kotlin.internal.InlineOnly
|
||||||
@JvmSynthetic
|
@JvmSynthetic
|
||||||
|
@ -16,10 +16,14 @@ import net.mamoe.mirai.JavaFriendlyAPI
|
|||||||
import net.mamoe.mirai.event.events.*
|
import net.mamoe.mirai.event.events.*
|
||||||
import net.mamoe.mirai.getFriendOrNull
|
import net.mamoe.mirai.getFriendOrNull
|
||||||
import net.mamoe.mirai.message.MessageReceipt
|
import net.mamoe.mirai.message.MessageReceipt
|
||||||
|
import net.mamoe.mirai.message.action.MemberNudge
|
||||||
|
import net.mamoe.mirai.message.action.Nudge
|
||||||
import net.mamoe.mirai.message.data.Message
|
import net.mamoe.mirai.message.data.Message
|
||||||
import net.mamoe.mirai.message.data.PlainText
|
import net.mamoe.mirai.message.data.PlainText
|
||||||
import net.mamoe.mirai.message.data.isContentEmpty
|
import net.mamoe.mirai.message.data.isContentEmpty
|
||||||
import net.mamoe.mirai.message.recall
|
import net.mamoe.mirai.message.recall
|
||||||
|
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||||
|
import net.mamoe.mirai.utils.SinceMirai
|
||||||
import net.mamoe.mirai.utils.WeakRefProperty
|
import net.mamoe.mirai.utils.WeakRefProperty
|
||||||
import kotlin.jvm.JvmSynthetic
|
import kotlin.jvm.JvmSynthetic
|
||||||
import kotlin.time.Duration
|
import kotlin.time.Duration
|
||||||
@ -157,6 +161,15 @@ public abstract class Member : MemberJavaFriendlyAPI, User() {
|
|||||||
@JvmSynthetic
|
@JvmSynthetic
|
||||||
public abstract override suspend fun sendMessage(message: Message): MessageReceipt<Member>
|
public abstract override suspend fun sendMessage(message: Message): MessageReceipt<Member>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个 "戳一戳" 消息
|
||||||
|
*
|
||||||
|
* @see MemberNudge.sendTo 发送这个戳一戳消息
|
||||||
|
*/
|
||||||
|
@MiraiExperimentalAPI
|
||||||
|
@SinceMirai("1.3.0")
|
||||||
|
public final override fun nudge(): Nudge = MemberNudge(this)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see sendMessage
|
* @see sendMessage
|
||||||
*/
|
*/
|
||||||
|
@ -15,11 +15,17 @@ import kotlinx.coroutines.CoroutineScope
|
|||||||
import net.mamoe.mirai.Bot
|
import net.mamoe.mirai.Bot
|
||||||
import net.mamoe.mirai.event.events.*
|
import net.mamoe.mirai.event.events.*
|
||||||
import net.mamoe.mirai.message.MessageReceipt
|
import net.mamoe.mirai.message.MessageReceipt
|
||||||
|
import net.mamoe.mirai.message.action.FriendNudge
|
||||||
|
import net.mamoe.mirai.message.action.Nudge
|
||||||
import net.mamoe.mirai.message.data.Image
|
import net.mamoe.mirai.message.data.Image
|
||||||
import net.mamoe.mirai.message.data.Message
|
import net.mamoe.mirai.message.data.Message
|
||||||
import net.mamoe.mirai.message.data.PlainText
|
import net.mamoe.mirai.message.data.PlainText
|
||||||
|
import net.mamoe.mirai.message.data.isContentEmpty
|
||||||
|
import net.mamoe.mirai.message.recall
|
||||||
import net.mamoe.mirai.utils.ExternalImage
|
import net.mamoe.mirai.utils.ExternalImage
|
||||||
|
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||||
import net.mamoe.mirai.utils.OverFileSizeMaxException
|
import net.mamoe.mirai.utils.OverFileSizeMaxException
|
||||||
|
import net.mamoe.mirai.utils.SinceMirai
|
||||||
import kotlin.jvm.JvmSynthetic
|
import kotlin.jvm.JvmSynthetic
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -67,6 +73,15 @@ public abstract class User : Contact(), CoroutineScope {
|
|||||||
@JvmSynthetic
|
@JvmSynthetic
|
||||||
public abstract override suspend fun sendMessage(message: Message): MessageReceipt<User>
|
public abstract override suspend fun sendMessage(message: Message): MessageReceipt<User>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个 "戳一戳" 消息
|
||||||
|
*
|
||||||
|
* @see FriendNudge.sendTo 发送这个戳一戳消息
|
||||||
|
*/
|
||||||
|
@MiraiExperimentalAPI
|
||||||
|
@SinceMirai("1.3.0")
|
||||||
|
public abstract fun nudge(): Nudge
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see sendMessage
|
* @see sendMessage
|
||||||
*/
|
*/
|
||||||
|
@ -0,0 +1,237 @@
|
|||||||
|
package net.mamoe.mirai.data
|
||||||
|
|
||||||
|
import kotlinx.serialization.*
|
||||||
|
import kotlinx.serialization.descriptors.PrimitiveKind
|
||||||
|
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
|
||||||
|
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||||
|
import kotlinx.serialization.encoding.Decoder
|
||||||
|
import kotlinx.serialization.encoding.Encoder
|
||||||
|
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||||
|
import net.mamoe.mirai.utils.SinceMirai
|
||||||
|
import kotlin.jvm.JvmStatic
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 群荣誉信息
|
||||||
|
*/
|
||||||
|
@MiraiExperimentalAPI
|
||||||
|
@SinceMirai("1.3.0")
|
||||||
|
public enum class GroupHonorType(public val value: Int) {
|
||||||
|
TALKATIVE(1), // 龙王
|
||||||
|
PERFORMER(2), // 群聊之火
|
||||||
|
LEGEND(3), // 群聊炽焰
|
||||||
|
STRONG_NEWBIE(5), // 冒尖小春笋
|
||||||
|
EMOTION(6), // 快乐源泉
|
||||||
|
ACTIVE(7), // 活跃头衔
|
||||||
|
EXCLUSIVE(8), // 特殊头衔
|
||||||
|
MANAGE(9); // 管理头衔
|
||||||
|
internal companion object {
|
||||||
|
@JvmStatic
|
||||||
|
internal fun deserializeFromInt(value: Int): GroupHonorType = values().first { it.value == value }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@MiraiExperimentalAPI
|
||||||
|
@SinceMirai("1.3.0")
|
||||||
|
@Serializable
|
||||||
|
public data class GroupHonorListData(
|
||||||
|
@SerialName("acceptLanguages")
|
||||||
|
val acceptLanguages: List<Language?>? = null,
|
||||||
|
|
||||||
|
@SerialName("gc")
|
||||||
|
val gc: String?,
|
||||||
|
|
||||||
|
@Serializable(with = GroupHonorTypeSerializer::class)
|
||||||
|
@SerialName("type")
|
||||||
|
val type: GroupHonorType?,
|
||||||
|
|
||||||
|
@SerialName("uin")
|
||||||
|
val uin: String?,
|
||||||
|
|
||||||
|
@SerialName("talkativeList")
|
||||||
|
val talkativeList: List<Talkative?>? = null,
|
||||||
|
|
||||||
|
@SerialName("currentTalkative")
|
||||||
|
val currentTalkative: CurrentTalkative? = null,
|
||||||
|
|
||||||
|
@SerialName("actorList")
|
||||||
|
val actorList: List<Actor?>? = null,
|
||||||
|
|
||||||
|
@SerialName("legendList")
|
||||||
|
val legendList: List<Actor?>? = null,
|
||||||
|
|
||||||
|
@SerialName("newbieList")
|
||||||
|
val newbieList: List<Actor?>? = null,
|
||||||
|
|
||||||
|
@SerialName("strongnewbieList")
|
||||||
|
val strongNewbieList: List<Actor?>? = null,
|
||||||
|
|
||||||
|
@SerialName("emotionList")
|
||||||
|
val emotionList: List<Actor?>? = null,
|
||||||
|
|
||||||
|
@SerialName("levelname")
|
||||||
|
val levelName: LevelName? = null,
|
||||||
|
|
||||||
|
@SerialName("manageList")
|
||||||
|
val manageList: List<Tag?>? = null,
|
||||||
|
|
||||||
|
@SerialName("exclusiveList")
|
||||||
|
val exclusiveList: List<Tag?>? = null,
|
||||||
|
|
||||||
|
@SerialName("activeObj")
|
||||||
|
val activeObj: Map<String, List<Tag?>?>? = null, // Key为活跃等级名, 如`冒泡`
|
||||||
|
|
||||||
|
@SerialName("showActiveObj")
|
||||||
|
val showActiveObj: Map<String, Boolean?>? = null,
|
||||||
|
|
||||||
|
@SerialName("myTitle")
|
||||||
|
val myTitle: String?,
|
||||||
|
|
||||||
|
@SerialName("myIndex")
|
||||||
|
val myIndex: Int? = 0,
|
||||||
|
|
||||||
|
@SerialName("myAvatar")
|
||||||
|
val myAvatar: String?,
|
||||||
|
|
||||||
|
@SerialName("hasServerError")
|
||||||
|
val hasServerError: Boolean?,
|
||||||
|
|
||||||
|
@SerialName("hwExcellentList")
|
||||||
|
val hwExcellentList: List<Actor?>? = null
|
||||||
|
) {
|
||||||
|
@Serializable
|
||||||
|
public data class Language(
|
||||||
|
@SerialName("code")
|
||||||
|
val code: String? = null,
|
||||||
|
|
||||||
|
@SerialName("script")
|
||||||
|
val script: String? = null,
|
||||||
|
|
||||||
|
@SerialName("region")
|
||||||
|
val region: String? = null,
|
||||||
|
|
||||||
|
@SerialName("quality")
|
||||||
|
val quality: Double? = null
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
public data class Actor(
|
||||||
|
@SerialName("uin")
|
||||||
|
val uin: Long? = 0,
|
||||||
|
|
||||||
|
@SerialName("avatar")
|
||||||
|
val avatar: String? = null,
|
||||||
|
|
||||||
|
@SerialName("name")
|
||||||
|
val name: String? = null,
|
||||||
|
|
||||||
|
@SerialName("desc")
|
||||||
|
val desc: String? = null,
|
||||||
|
|
||||||
|
@SerialName("btnText")
|
||||||
|
val btnText: String? = null,
|
||||||
|
|
||||||
|
@SerialName("text")
|
||||||
|
val text: String? = null,
|
||||||
|
|
||||||
|
@SerialName("icon")
|
||||||
|
val icon: Int?
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
public data class Talkative(
|
||||||
|
@SerialName("uin")
|
||||||
|
val uin: Long? = 0,
|
||||||
|
|
||||||
|
@SerialName("avatar")
|
||||||
|
val avatar: String? = null,
|
||||||
|
|
||||||
|
@SerialName("name")
|
||||||
|
val name: String? = null,
|
||||||
|
|
||||||
|
@SerialName("desc")
|
||||||
|
val desc: String? = null,
|
||||||
|
|
||||||
|
@SerialName("btnText")
|
||||||
|
val btnText: String? = null,
|
||||||
|
|
||||||
|
@SerialName("text")
|
||||||
|
val text: String? = null
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
public data class CurrentTalkative(
|
||||||
|
@SerialName("uin")
|
||||||
|
val uin: Long? = 0,
|
||||||
|
|
||||||
|
@SerialName("day_count")
|
||||||
|
val dayCount: Int? = null,
|
||||||
|
|
||||||
|
@SerialName("avatar")
|
||||||
|
val avatar: String? = null,
|
||||||
|
|
||||||
|
@SerialName("avatar_size")
|
||||||
|
val avatarSize: Int? = null,
|
||||||
|
|
||||||
|
@SerialName("nick")
|
||||||
|
val nick: String? = null
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
public data class LevelName(
|
||||||
|
@SerialName("lvln1")
|
||||||
|
val lv1: String? = null,
|
||||||
|
|
||||||
|
@SerialName("lvln2")
|
||||||
|
val lv2: String? = null,
|
||||||
|
|
||||||
|
@SerialName("lvln3")
|
||||||
|
val lv3: String? = null,
|
||||||
|
|
||||||
|
@SerialName("lvln4")
|
||||||
|
val lv4: String? = null,
|
||||||
|
|
||||||
|
@SerialName("lvln5")
|
||||||
|
val lv5: String? = null,
|
||||||
|
|
||||||
|
@SerialName("lvln6")
|
||||||
|
val lv6: String? = null
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
public data class Tag(
|
||||||
|
@SerialName("uin")
|
||||||
|
val uin: Long? = 0,
|
||||||
|
|
||||||
|
@SerialName("avatar")
|
||||||
|
val avatar: String? = null,
|
||||||
|
|
||||||
|
@SerialName("name")
|
||||||
|
val name: String? = null,
|
||||||
|
|
||||||
|
@SerialName("btnText")
|
||||||
|
val btnText: String? = null,
|
||||||
|
|
||||||
|
@SerialName("text")
|
||||||
|
val text: String? = null,
|
||||||
|
|
||||||
|
@SerialName("tag")
|
||||||
|
val tag: String? = null, // 头衔
|
||||||
|
|
||||||
|
@SerialName("tagColor")
|
||||||
|
val tagColor: String? = null
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializer(forClass = GroupHonorType::class)
|
||||||
|
public object GroupHonorTypeSerializer : KSerializer<GroupHonorType> {
|
||||||
|
override val descriptor: SerialDescriptor =
|
||||||
|
PrimitiveSerialDescriptor("GroupHonorTypeSerializer", PrimitiveKind.INT)
|
||||||
|
|
||||||
|
override fun serialize(encoder: Encoder, value: GroupHonorType) {
|
||||||
|
encoder.encodeInt(value.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun deserialize(decoder: Decoder): GroupHonorType {
|
||||||
|
return GroupHonorType.deserializeFromInt(decoder.decodeInt())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -9,13 +9,10 @@
|
|||||||
|
|
||||||
package net.mamoe.mirai.data
|
package net.mamoe.mirai.data
|
||||||
|
|
||||||
import net.mamoe.mirai.Bot
|
|
||||||
import net.mamoe.mirai.LowLevelAPI
|
import net.mamoe.mirai.LowLevelAPI
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 群资料.
|
* 群资料.
|
||||||
*
|
|
||||||
* 通过 [Bot._lowLevelQueryGroupInfo] 得到
|
|
||||||
*/
|
*/
|
||||||
@LowLevelAPI
|
@LowLevelAPI
|
||||||
public interface GroupInfo {
|
public interface GroupInfo {
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
- 服务器主动要求更换另一个服务器: RequireReconnect
|
- 服务器主动要求更换另一个服务器: RequireReconnect
|
||||||
- Bot 重新登录: BotReloginEvent
|
- Bot 重新登录: BotReloginEvent
|
||||||
- Bot 头像改变: BotAvatarChangedEvent
|
- Bot 头像改变: BotAvatarChangedEvent
|
||||||
|
- (`1.2.0+`) Bot 昵称改变: BotNickChangedEvent
|
||||||
|
- (`1.3.0+`) Bot 被戳: BotNudgedEvent
|
||||||
|
|
||||||
### [消息](message.kt)
|
### [消息](message.kt)
|
||||||
- (`1.1.0-`) 主动发送消息: MessageSendEvent
|
- (`1.1.0-`) 主动发送消息: MessageSendEvent
|
||||||
@ -81,9 +83,10 @@
|
|||||||
##### 成员权限
|
##### 成员权限
|
||||||
- 成员权限改变: MemberPermissionChangeEvent
|
- 成员权限改变: MemberPermissionChangeEvent
|
||||||
|
|
||||||
##### 禁言
|
##### 动作
|
||||||
- 群成员被禁言: MemberMuteEvent
|
- 群成员被禁言: MemberMuteEvent
|
||||||
- 群成员被取消禁言: MemberUnmuteEvent
|
- 群成员被取消禁言: MemberUnmuteEvent
|
||||||
|
- (`1.3.0+`) 群员被戳: MemberNudgedEvent
|
||||||
|
|
||||||
### [好友](friend.kt)
|
### [好友](friend.kt)
|
||||||
- 好友昵称改变: FriendRemarkChangeEvent
|
- 好友昵称改变: FriendRemarkChangeEvent
|
||||||
@ -91,3 +94,6 @@
|
|||||||
- 好友已被删除: FriendDeleteEvent
|
- 好友已被删除: FriendDeleteEvent
|
||||||
- 一个账号请求添加机器人为好友: NewFriendRequestEvent
|
- 一个账号请求添加机器人为好友: NewFriendRequestEvent
|
||||||
- 好友头像改变: FriendAvatarChangedEvent
|
- 好友头像改变: FriendAvatarChangedEvent
|
||||||
|
- (`1.2.0+`) 好友昵称改变: FriendNickChangedEvent
|
||||||
|
- (`1.2.0+`) 好友输入状态改变: FriendInputStatusChangedEvent
|
||||||
|
- (`1.3.0+`) 好友被戳: FriendNudgedEvent
|
||||||
|
@ -14,7 +14,9 @@
|
|||||||
package net.mamoe.mirai.event.events
|
package net.mamoe.mirai.event.events
|
||||||
|
|
||||||
import net.mamoe.mirai.Bot
|
import net.mamoe.mirai.Bot
|
||||||
|
import net.mamoe.mirai.contact.User
|
||||||
import net.mamoe.mirai.event.AbstractEvent
|
import net.mamoe.mirai.event.AbstractEvent
|
||||||
|
import net.mamoe.mirai.message.action.Nudge
|
||||||
import net.mamoe.mirai.qqandroid.network.Packet
|
import net.mamoe.mirai.qqandroid.network.Packet
|
||||||
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||||
import net.mamoe.mirai.utils.MiraiInternalAPI
|
import net.mamoe.mirai.utils.MiraiInternalAPI
|
||||||
@ -124,6 +126,31 @@ public data class BotNickChangedEvent(
|
|||||||
public val to: String
|
public val to: String
|
||||||
) : BotEvent, Packet, AbstractEvent()
|
) : BotEvent, Packet, AbstractEvent()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [Bot] 被 [戳][Nudge] 的事件.
|
||||||
|
*/
|
||||||
|
@MiraiExperimentalAPI
|
||||||
|
@SinceMirai("1.3.0")
|
||||||
|
public data class BotNudgedEvent internal constructor(
|
||||||
|
/**
|
||||||
|
* 戳一戳的发起人,为 [Bot] 的某一好友, 或某一群员
|
||||||
|
*/
|
||||||
|
public val from: User,
|
||||||
|
/**
|
||||||
|
* 戳一戳的动作名称
|
||||||
|
*/
|
||||||
|
public val action: String,
|
||||||
|
/**
|
||||||
|
* 戳一戳中设置的自定义后缀
|
||||||
|
*/
|
||||||
|
public val suffix: String,
|
||||||
|
) : BotEvent, Packet, AbstractEvent() {
|
||||||
|
/**
|
||||||
|
* 戳一戳的目标
|
||||||
|
*/
|
||||||
|
public override val bot: Bot get() = from.bot
|
||||||
|
}
|
||||||
|
|
||||||
// region 图片
|
// region 图片
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
@ -112,8 +112,6 @@ public data class FriendAvatarChangedEvent internal constructor(
|
|||||||
public override val friend: Friend
|
public override val friend: Friend
|
||||||
) : FriendEvent, Packet, AbstractEvent()
|
) : FriendEvent, Packet, AbstractEvent()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [Friend] 昵称改变事件, 在此事件广播时好友已经完成改名
|
* [Friend] 昵称改变事件, 在此事件广播时好友已经完成改名
|
||||||
* @see BotNickChangedEvent
|
* @see BotNickChangedEvent
|
||||||
|
@ -22,8 +22,10 @@ import net.mamoe.mirai.contact.MemberPermission
|
|||||||
import net.mamoe.mirai.event.AbstractEvent
|
import net.mamoe.mirai.event.AbstractEvent
|
||||||
import net.mamoe.mirai.event.BroadcastControllable
|
import net.mamoe.mirai.event.BroadcastControllable
|
||||||
import net.mamoe.mirai.event.internal.MiraiAtomicBoolean
|
import net.mamoe.mirai.event.internal.MiraiAtomicBoolean
|
||||||
|
import net.mamoe.mirai.message.action.Nudge
|
||||||
import net.mamoe.mirai.qqandroid.network.Packet
|
import net.mamoe.mirai.qqandroid.network.Packet
|
||||||
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||||
|
import net.mamoe.mirai.utils.SinceMirai
|
||||||
import net.mamoe.mirai.utils.internal.runBlocking
|
import net.mamoe.mirai.utils.internal.runBlocking
|
||||||
import kotlin.internal.LowPriorityInOverloadResolution
|
import kotlin.internal.LowPriorityInOverloadResolution
|
||||||
import kotlin.jvm.*
|
import kotlin.jvm.*
|
||||||
@ -130,6 +132,18 @@ public sealed class BotJoinGroupEvent : GroupEvent, BotPassiveEvent, Packet, Abs
|
|||||||
return "BotJoinGroupEvent.Invite(invitor=$invitor)"
|
return "BotJoinGroupEvent.Invite(invitor=$invitor)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 原群主通过 https://huifu.qq.com/ 恢复原来群主身份并入群,
|
||||||
|
* [Bot] 是原群主
|
||||||
|
*/
|
||||||
|
@MiraiExperimentalAPI
|
||||||
|
@SinceMirai("1.3.0")
|
||||||
|
public data class Retrieve internal constructor(
|
||||||
|
public override val group: Group
|
||||||
|
) : BotJoinGroupEvent() {
|
||||||
|
override fun toString(): String = "MemberJoinEvent.Retrieve(group=${group.id})"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// region 群设置
|
// region 群设置
|
||||||
@ -260,6 +274,17 @@ public sealed class MemberJoinEvent(
|
|||||||
) : MemberJoinEvent(member) {
|
) : MemberJoinEvent(member) {
|
||||||
public override fun toString(): String = "MemberJoinEvent.Active(member=${member.id})"
|
public override fun toString(): String = "MemberJoinEvent.Active(member=${member.id})"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 原群主通过 https://huifu.qq.com/ 恢复原来群主身份并入群,
|
||||||
|
* 此时 [member] 的 [Member.permission] 肯定是 [MemberPermission.OWNER]
|
||||||
|
*/
|
||||||
|
@SinceMirai("1.3.0")
|
||||||
|
public data class Retrieve internal constructor(
|
||||||
|
public override val member: Member
|
||||||
|
) : MemberJoinEvent(member) {
|
||||||
|
override fun toString(): String = "MemberJoinEvent.Retrieve(member=${member.id})"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -487,4 +512,33 @@ public data class MemberUnmuteEvent internal constructor(
|
|||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
|
// region 戳一戳
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [Member] 被 [戳][Nudge] 的事件.
|
||||||
|
*/
|
||||||
|
@MiraiExperimentalAPI
|
||||||
|
@SinceMirai("1.3.0")
|
||||||
|
public data class MemberNudgedEvent internal constructor(
|
||||||
|
/**
|
||||||
|
* 戳一戳的发起人, 不可能是 bot
|
||||||
|
*/
|
||||||
|
public val from: Member,
|
||||||
|
/**
|
||||||
|
* 戳一戳的目标 (被戳的群员), 不可能是 bot
|
||||||
|
*/
|
||||||
|
public override val member: Member,
|
||||||
|
/**
|
||||||
|
* 戳一戳的动作名称
|
||||||
|
*/
|
||||||
|
public val action: String,
|
||||||
|
/**
|
||||||
|
* 戳一戳中设置的自定义后缀
|
||||||
|
*/
|
||||||
|
public val suffix: String,
|
||||||
|
) : GroupMemberEvent, BotPassiveEvent, Packet, AbstractEvent()
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
@ -55,13 +55,6 @@ public interface LowLevelBotAPIAccessor {
|
|||||||
@LowLevelAPI
|
@LowLevelAPI
|
||||||
public suspend fun _lowLevelQueryGroupList(): Sequence<Long>
|
public suspend fun _lowLevelQueryGroupList(): Sequence<Long>
|
||||||
|
|
||||||
/**
|
|
||||||
* 向服务器查询群资料. 获得的仅为当前时刻的资料.
|
|
||||||
* 请优先使用 [Bot.getGroup] 然后查看群资料.
|
|
||||||
*/
|
|
||||||
@LowLevelAPI
|
|
||||||
public suspend fun _lowLevelQueryGroupInfo(groupCode: Long): GroupInfo
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 向服务器查询群成员列表.
|
* 向服务器查询群成员列表.
|
||||||
* 请优先使用 [Bot.getGroup], [Group.members] 查看群成员.
|
* 请优先使用 [Bot.getGroup], [Group.members] 查看群成员.
|
||||||
@ -122,6 +115,15 @@ public interface LowLevelBotAPIAccessor {
|
|||||||
public suspend fun _lowLevelGetGroupActiveData(groupId: Long, page: Int = -1): GroupActiveData
|
public suspend fun _lowLevelGetGroupActiveData(groupId: Long, page: Int = -1): GroupActiveData
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取群荣誉信息
|
||||||
|
*/
|
||||||
|
@SinceMirai("1.3.0")
|
||||||
|
@LowLevelAPI
|
||||||
|
@MiraiExperimentalAPI
|
||||||
|
public suspend fun _lowLevelGetGroupHonorListData(groupId: Long, type: GroupHonorType): GroupHonorListData?
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理一个账号请求添加机器人为好友的事件
|
* 处理一个账号请求添加机器人为好友的事件
|
||||||
*/
|
*/
|
||||||
|
@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* * Copyright 2020 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/master/LICENSE
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.mamoe.mirai.message.action
|
||||||
|
|
||||||
|
import net.mamoe.kjbb.JvmBlockingBridge
|
||||||
|
import net.mamoe.mirai.Bot
|
||||||
|
import net.mamoe.mirai.contact.*
|
||||||
|
import net.mamoe.mirai.event.events.BotNudgedEvent
|
||||||
|
import net.mamoe.mirai.event.events.MemberNudgedEvent
|
||||||
|
import net.mamoe.mirai.utils.BotConfiguration
|
||||||
|
import net.mamoe.mirai.utils.BotConfiguration.MiraiProtocol
|
||||||
|
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||||
|
import net.mamoe.mirai.utils.SinceMirai
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一个 "戳一戳" 消息.
|
||||||
|
*
|
||||||
|
* 仅在手机 QQ 8.4.0 左右版本才受支持. 其他客户端会忽略这些消息.
|
||||||
|
*
|
||||||
|
* @see User.nudge 创建 [Nudge] 对象
|
||||||
|
* @see Bot.nudge 创建 [Nudge] 对象
|
||||||
|
*/
|
||||||
|
@MiraiExperimentalAPI
|
||||||
|
@SinceMirai("1.3.0")
|
||||||
|
public sealed class Nudge {
|
||||||
|
/**
|
||||||
|
* 戳的对象. 即 "A 戳了 B" 中的 "B".
|
||||||
|
*/
|
||||||
|
public abstract val target: ContactOrBot // User or Bot
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送戳一戳该成员的消息.
|
||||||
|
*
|
||||||
|
* 需要 [使用协议][BotConfiguration.protocol] [MiraiProtocol.ANDROID_PHONE].
|
||||||
|
*
|
||||||
|
* @param receiver 这条 "戳一戳" 消息的接收对象. (不是 "戳" 动作的对象, 而是接收 "A 戳了 B" 这条消息的对象)
|
||||||
|
*
|
||||||
|
* @see MemberNudgedEvent 成员被戳事件
|
||||||
|
* @see BotNudgedEvent [Bot] 被戳事件
|
||||||
|
*
|
||||||
|
* @throws UnsupportedOperationException 当未使用 [安卓协议][MiraiProtocol.ANDROID_PHONE] 时抛出
|
||||||
|
*
|
||||||
|
* @return 成功发送时为 `true`. 若对方禁用 "戳一戳" 功能, 返回 `false`.
|
||||||
|
*/
|
||||||
|
@JvmBlockingBridge
|
||||||
|
@MiraiExperimentalAPI
|
||||||
|
public suspend fun sendTo(receiver: Contact): Boolean {
|
||||||
|
@Suppress("DEPRECATION_ERROR")
|
||||||
|
return receiver.bot.sendNudge(this, receiver)
|
||||||
|
}
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
/**
|
||||||
|
* 发送戳一戳该成员的消息.
|
||||||
|
*
|
||||||
|
* 需要 [使用协议][BotConfiguration.protocol] [MiraiProtocol.ANDROID_PHONE].
|
||||||
|
*
|
||||||
|
* @see MemberNudgedEvent 成员被戳事件
|
||||||
|
* @see BotNudgedEvent [Bot] 被戳事件
|
||||||
|
*
|
||||||
|
* @throws UnsupportedOperationException 当未使用 [安卓协议][MiraiProtocol.ANDROID_PHONE] 时抛出
|
||||||
|
*
|
||||||
|
* @return 成功发送时为 `true`. 若对方禁用 "戳一戳" 功能, 返回 `false`.
|
||||||
|
*/
|
||||||
|
@MiraiExperimentalAPI
|
||||||
|
@JvmBlockingBridge
|
||||||
|
public suspend fun Contact.sendNudge(nudge: Nudge): Boolean = nudge.sendTo(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Bot.nudge
|
||||||
|
* @see Nudge
|
||||||
|
*/
|
||||||
|
@MiraiExperimentalAPI
|
||||||
|
@SinceMirai("1.3.0")
|
||||||
|
public data class BotNudge(
|
||||||
|
public override val target: Bot
|
||||||
|
) : Nudge()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see User.nudge
|
||||||
|
* @see Nudge
|
||||||
|
*/
|
||||||
|
@MiraiExperimentalAPI
|
||||||
|
@SinceMirai("1.3.0")
|
||||||
|
public sealed class UserNudge : Nudge() {
|
||||||
|
public abstract override val target: User
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Member.nudge
|
||||||
|
* @see Nudge
|
||||||
|
*/
|
||||||
|
@MiraiExperimentalAPI
|
||||||
|
@SinceMirai("1.3.0")
|
||||||
|
public data class MemberNudge(
|
||||||
|
public override val target: Member
|
||||||
|
) : UserNudge()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Friend.nudge
|
||||||
|
* @see Nudge
|
||||||
|
*/
|
||||||
|
@MiraiExperimentalAPI
|
||||||
|
@SinceMirai("1.3.0")
|
||||||
|
public data class FriendNudge(
|
||||||
|
public override val target: Friend
|
||||||
|
) : UserNudge()
|
@ -47,9 +47,11 @@ public class Voice @MiraiInternalAPI constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
public val url: String?
|
public val url: String?
|
||||||
get() =
|
get() = when {
|
||||||
if (_url.startsWith("http")) _url
|
_url.isBlank() -> null
|
||||||
else null
|
_url.startsWith("http") -> _url
|
||||||
|
else -> "http://grouptalk.c2c.qq.com$_url"
|
||||||
|
}
|
||||||
|
|
||||||
private var _stringValue: String? = null
|
private var _stringValue: String? = null
|
||||||
get() = field ?: kotlin.run {
|
get() = field ?: kotlin.run {
|
||||||
|
@ -15,6 +15,7 @@ package net.mamoe.mirai
|
|||||||
import net.mamoe.mirai.utils.BotConfiguration
|
import net.mamoe.mirai.utils.BotConfiguration
|
||||||
import net.mamoe.mirai.utils.Context
|
import net.mamoe.mirai.utils.Context
|
||||||
import net.mamoe.mirai.utils.ContextImpl
|
import net.mamoe.mirai.utils.ContextImpl
|
||||||
|
import net.mamoe.mirai.utils.SinceMirai
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造 [Bot] 的工厂. 这是 [Bot] 唯一的构造方式.
|
* 构造 [Bot] 的工厂. 这是 [Bot] 唯一的构造方式.
|
||||||
@ -52,6 +53,16 @@ public actual interface BotFactory {
|
|||||||
configuration: BotConfiguration
|
configuration: BotConfiguration
|
||||||
): Bot
|
): Bot
|
||||||
|
|
||||||
|
@SinceMirai("1.3.0")
|
||||||
|
public actual companion object INSTANCE : BotFactory {
|
||||||
|
override fun Bot(context: Context, qq: Long, password: String, configuration: BotConfiguration): Bot {
|
||||||
|
return factory.Bot(context, qq, password, configuration)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun Bot(context: Context, qq: Long, passwordMd5: ByteArray, configuration: BotConfiguration): Bot {
|
||||||
|
return factory.Bot(context, qq, passwordMd5, configuration)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -61,7 +72,12 @@ public actual interface BotFactory {
|
|||||||
*/
|
*/
|
||||||
@JvmName("newBot")
|
@JvmName("newBot")
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
public fun Bot(context: Context, qq: Long, password: String, configuration: BotConfiguration = BotConfiguration.Default): Bot =
|
public fun Bot(
|
||||||
|
context: Context,
|
||||||
|
qq: Long,
|
||||||
|
password: String,
|
||||||
|
configuration: BotConfiguration = BotConfiguration.Default
|
||||||
|
): Bot =
|
||||||
factory.Bot(context, qq, password, configuration)
|
factory.Bot(context, qq, password, configuration)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -109,7 +125,12 @@ public fun Bot(
|
|||||||
* 自动加载现有协议的 [BotFactory], 并使用指定的 [配置][configuration] 构造 [Bot] 实例
|
* 自动加载现有协议的 [BotFactory], 并使用指定的 [配置][configuration] 构造 [Bot] 实例
|
||||||
*/
|
*/
|
||||||
@JvmSynthetic
|
@JvmSynthetic
|
||||||
public inline fun Bot(context: Context, qq: Long, passwordMd5: ByteArray, configuration: (BotConfiguration.() -> Unit)): Bot =
|
public inline fun Bot(
|
||||||
|
context: Context,
|
||||||
|
qq: Long,
|
||||||
|
passwordMd5: ByteArray,
|
||||||
|
configuration: (BotConfiguration.() -> Unit)
|
||||||
|
): Bot =
|
||||||
factory.Bot(context, qq, passwordMd5, BotConfiguration().apply(configuration))
|
factory.Bot(context, qq, passwordMd5, BotConfiguration().apply(configuration))
|
||||||
|
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ public actual open class PlatformLogger @JvmOverloads constructor(
|
|||||||
*/
|
*/
|
||||||
@SinceMirai("1.1.0")
|
@SinceMirai("1.1.0")
|
||||||
protected open fun printLog(message: String?, priority: SimpleLogger.LogPriority) {
|
protected open fun printLog(message: String?, priority: SimpleLogger.LogPriority) {
|
||||||
if (isColored) output("${priority.color}$currentTimeFormatted ${priority.simpleName}/$identity: $message")
|
if (isColored) output("${priority.color}$currentTimeFormatted ${priority.simpleName}/$identity: $message${Color.RESET}")
|
||||||
else output("$currentTimeFormatted ${priority.simpleName}/$identity: $message")
|
else output("$currentTimeFormatted ${priority.simpleName}/$identity: $message")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user