mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-03 02:53:52 +08:00
* Introduce UserInfo and change uin to id * Stranger api: List and asStranger * Stranger api: Events * Stranger api: MessageDSL and MessageSource * Update docs * Improve LoginSolver fix project-mirai/mirai-login-solver-selenium#4 * Improve SeleniumLoginSolver loading * Fix MessageChain.fragmented * 2.0-M2-1 * Stranger api change: StrangerRelationChangeEvent * Stranger impl: list and asStranger * Stranger impl: get stranger list and del stranger protocol * Stranger impl: add stranger protocol * Stranger impl: MessageSource refactor and sending&receiving message * Stranger impl: Dropping long message support (server rejected) * Stranger impl: sending stranger message when member is stranger * Fix wrong key Co-authored-by: Him188 <Him188@mamoe.net> * Add @LowLevelApi Co-authored-by: Him188 <Him188@mamoe.net> * Remove redundant val modifier * Replace nudge if statement to when statement * Move list seq to QQAndroidClient * Replace id with uin in UserInfo and fix build error * Using by lazy in asStranger * Fix wrong wordings * Fix wrong wordings in uploading image * Fix nudge Co-authored-by: Him188 <Him188@mamoe.net> Co-authored-by: Karlatemp <karlatemp@vip.qq.com>
This commit is contained in:
parent
6aa71daad2
commit
1117c14c7d
@ -93,11 +93,34 @@ public interface Bot : CoroutineScope, ContactOrBot, UserOrBot {
|
||||
*/
|
||||
public val asFriend: Friend
|
||||
|
||||
/**
|
||||
* [User.id] 与 [Bot.id] 相同的 [Stranger] 实例
|
||||
*/
|
||||
public val asStranger: Stranger
|
||||
|
||||
|
||||
/**
|
||||
* 陌生人列表. 与服务器同步更新.
|
||||
*/
|
||||
public val strangers: ContactList<Stranger>
|
||||
|
||||
/**
|
||||
* 以 [对方 QQ 号码][id] 获取一个陌生人对象, 在获取失败时返回 `null`.
|
||||
*/
|
||||
public fun getStranger(id: Long): Stranger? =
|
||||
strangers.firstOrNull { it.id == id }
|
||||
|
||||
/**
|
||||
* 以 [对方 QQ 号码][id] 获取一个陌生人对象, 在获取失败时抛出 [NoSuchElementException].
|
||||
*/
|
||||
public fun getStrangerOrFail(id: Long): Stranger = getStranger(id) ?: throw NoSuchElementException("stranger $id")
|
||||
|
||||
/**
|
||||
* 好友列表. 与服务器同步更新.
|
||||
*/
|
||||
public val friends: ContactList<Friend>
|
||||
|
||||
|
||||
/**
|
||||
* 以 [对方 QQ 号码][id] 获取一个好友对象, 在获取失败时返回 `null`.
|
||||
* 在 [id] 与 [Bot.id] 相同时返回 [Bot.asFriend]
|
||||
|
@ -137,6 +137,12 @@ public fun Member.asFriend(): Friend = this.bot.getFriend(this.id) ?: error("$th
|
||||
*/
|
||||
public fun Member.asFriendOrNull(): Friend? = this.bot.getFriend(this.id)
|
||||
|
||||
/**
|
||||
* 得到此成员作为陌生人的对象, 当此成员不是陌生人时返回 `null`
|
||||
*/
|
||||
public fun Member.asStrangerOrNull(): Stranger? = this.bot.getStranger(this.id)
|
||||
|
||||
|
||||
/**
|
||||
* 判断此成员是否为好友
|
||||
*/
|
||||
|
96
mirai-core-api/src/commonMain/kotlin/contact/Stranger.kt
Normal file
96
mirai-core-api/src/commonMain/kotlin/contact/Stranger.kt
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2019-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
|
||||
*/
|
||||
|
||||
@file:Suppress("EXPERIMENTAL_API_USAGE", "unused", "UnusedImport")
|
||||
|
||||
package net.mamoe.mirai.contact
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import net.mamoe.kjbb.JvmBlockingBridge
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.event.events.*
|
||||
import net.mamoe.mirai.message.MessageReceipt
|
||||
import net.mamoe.mirai.message.action.Nudge
|
||||
import net.mamoe.mirai.message.action.StrangerNudge
|
||||
import net.mamoe.mirai.message.data.Message
|
||||
import net.mamoe.mirai.message.data.isContentEmpty
|
||||
import net.mamoe.mirai.message.data.toPlainText
|
||||
import net.mamoe.mirai.utils.MiraiExperimentalApi
|
||||
|
||||
/**
|
||||
* 代表一位陌生人.
|
||||
*
|
||||
* 一个 [Stranger] 实例并不是独立的, 它属于一个 [Bot].
|
||||
* 对于同一个 [Bot], 任何一个人的 [Stranger] 实例都是单一的.
|
||||
* [Stranger] 无法通过任何方式直接构造. 任何时候都应从 [Bot.getStranger] 或事件中获取.
|
||||
*
|
||||
* 陌生人的来源:当将添加好友设置为
|
||||
* ‘任何人可添加为好友’或‘需要回答对验证问题时’
|
||||
* 且被他人成功添加时此人会成为陌生人
|
||||
*
|
||||
* 陌生人需要主动添加好友才能构成好友关系
|
||||
* 但 Mirai 将不会提供此功能
|
||||
* 请手动在其他客户端添加好友
|
||||
*
|
||||
* @see StrangerMessageEvent
|
||||
*/
|
||||
public interface Stranger : User, CoroutineScope {
|
||||
/**
|
||||
* QQ 号码
|
||||
*/
|
||||
public override val id: Long
|
||||
|
||||
/**
|
||||
* 昵称
|
||||
*/
|
||||
public override val nick: String
|
||||
|
||||
|
||||
/**
|
||||
* 向这个对象发送消息.
|
||||
*
|
||||
* 单条消息最大可发送 4500 字符或 50 张图片.
|
||||
*
|
||||
* @see FriendMessagePreSendEvent 发送消息前事件
|
||||
* @see FriendMessagePostSendEvent 发送消息后事件
|
||||
*
|
||||
* @throws EventCancelledException 当发送消息事件被取消时抛出
|
||||
* @throws BotIsBeingMutedException 发送群消息时若 [Bot] 被禁言抛出
|
||||
* @throws MessageTooLargeException 当消息过长时抛出
|
||||
* @throws IllegalArgumentException 当消息内容为空时抛出 (详见 [Message.isContentEmpty])
|
||||
*
|
||||
* @return 消息回执. 可进行撤回 ([MessageReceipt.recall])
|
||||
*/
|
||||
@JvmBlockingBridge
|
||||
public override suspend fun sendMessage(message: Message): MessageReceipt<Stranger>
|
||||
|
||||
/**
|
||||
* 删除并屏蔽该陌生人, 屏蔽后对方将无法发送临时会话消息
|
||||
*
|
||||
* @see StrangerRelationChangeEvent.Deleted 陌生人删除事件
|
||||
*/
|
||||
@JvmBlockingBridge
|
||||
public suspend fun delete()
|
||||
|
||||
/**
|
||||
* 发送纯文本消息
|
||||
* @see sendMessage
|
||||
*/
|
||||
@JvmBlockingBridge
|
||||
public override suspend fun sendMessage(message: String): MessageReceipt<Stranger> =
|
||||
this.sendMessage(message.toPlainText())
|
||||
|
||||
/**
|
||||
* 创建一个 "戳一戳" 消息
|
||||
*
|
||||
* @see Nudge.sendTo 发送这个戳一戳消息
|
||||
*/
|
||||
@MiraiExperimentalApi
|
||||
public override fun nudge(): StrangerNudge = StrangerNudge(this)
|
||||
}
|
@ -12,12 +12,12 @@ package net.mamoe.mirai.data
|
||||
import net.mamoe.mirai.LowLevelApi
|
||||
|
||||
@LowLevelApi
|
||||
public interface FriendInfo {
|
||||
public val uin: Long
|
||||
public interface FriendInfo : UserInfo {
|
||||
public override val uin: Long
|
||||
|
||||
public val nick: String
|
||||
public override val nick: String
|
||||
|
||||
public val remark: String
|
||||
public override val remark: String
|
||||
}
|
||||
|
||||
@LowLevelApi
|
||||
|
@ -13,7 +13,7 @@ import net.mamoe.mirai.LowLevelApi
|
||||
import net.mamoe.mirai.contact.MemberPermission
|
||||
|
||||
@LowLevelApi
|
||||
public interface MemberInfo : FriendInfo {
|
||||
public interface MemberInfo : UserInfo {
|
||||
public val nameCard: String
|
||||
|
||||
public val permission: MemberPermission
|
||||
|
24
mirai-core-api/src/commonMain/kotlin/data/StrangerInfo.kt
Normal file
24
mirai-core-api/src/commonMain/kotlin/data/StrangerInfo.kt
Normal file
@ -0,0 +1,24 @@
|
||||
package net.mamoe.mirai.data
|
||||
|
||||
import net.mamoe.mirai.LowLevelApi
|
||||
|
||||
@LowLevelApi
|
||||
public interface StrangerInfo : UserInfo {
|
||||
/**
|
||||
* 陌生人的QQ号码
|
||||
*/
|
||||
public override val uin: Long
|
||||
|
||||
/**
|
||||
* 陌生人的昵称
|
||||
*
|
||||
*/
|
||||
public override val nick: String
|
||||
|
||||
/**
|
||||
* 陌生人来源的群
|
||||
*
|
||||
* 当不是来源于群时为0
|
||||
*/
|
||||
public val fromGroup: Long
|
||||
}
|
12
mirai-core-api/src/commonMain/kotlin/data/UserInfo.kt
Normal file
12
mirai-core-api/src/commonMain/kotlin/data/UserInfo.kt
Normal file
@ -0,0 +1,12 @@
|
||||
package net.mamoe.mirai.data
|
||||
|
||||
import net.mamoe.mirai.LowLevelApi
|
||||
|
||||
@LowLevelApi
|
||||
public interface UserInfo {
|
||||
public val uin: Long
|
||||
|
||||
public val nick: String
|
||||
|
||||
public val remark: String
|
||||
}
|
@ -258,6 +258,15 @@ public open class MessageSubscribersBuilder<M : MessageEvent, out Ret, R : RR, R
|
||||
@MessageDsl
|
||||
public fun sentByFriend(): ListeningFilter = newListeningFilter { this is FriendMessageEvent }
|
||||
|
||||
/** 如果是陌生人发来的消息 */
|
||||
@MessageDsl
|
||||
public fun sentByStranger(onEvent: MessageListener<StrangerMessageEvent, R>): Ret =
|
||||
content({ this is StrangerMessageEvent }) { onEvent(this as StrangerMessageEvent, it) }
|
||||
|
||||
/** 如果是陌生人发来的消息 */
|
||||
@MessageDsl
|
||||
public fun sentByStranger(): ListeningFilter = newListeningFilter { this is StrangerMessageEvent }
|
||||
|
||||
/** 如果是群临时会话消息 */
|
||||
@MessageDsl
|
||||
public fun sentByTemp(): ListeningFilter = newListeningFilter { this is TempMessageEvent }
|
||||
|
@ -171,33 +171,55 @@ public sealed class BotNudgedEvent : AbstractEvent(), BotEvent, Packet {
|
||||
|
||||
@MiraiExperimentalApi
|
||||
/** [Bot] 在私聊中被戳 */
|
||||
public sealed class InPrivateSession : BotNudgedEvent(), FriendEvent {
|
||||
abstract override val from: Friend
|
||||
public sealed class InPrivateSession : BotNudgedEvent() {
|
||||
abstract override val from: User
|
||||
override val bot: Bot get() = from.bot
|
||||
override val friend: Friend get() = from
|
||||
|
||||
/** 在私聊中 [Friend] 戳了 [Bot] */
|
||||
public data class ByFriend internal constructor(
|
||||
override val friend: Friend,
|
||||
override val action: String,
|
||||
override val suffix: String
|
||||
) : InPrivateSession() {
|
||||
) : InPrivateSession(), FriendEvent {
|
||||
override val from: Friend get() = friend
|
||||
override val bot: Bot get() = from.bot
|
||||
|
||||
override fun toString(): String {
|
||||
return "BotNudgedEvent.InPrivateSession.ByFriend(friend=$friend, action=$action, suffix=$suffix)"
|
||||
}
|
||||
}
|
||||
|
||||
/** 在私聊中 [Stranger] 戳了 [Bot] */
|
||||
public data class ByStranger internal constructor(
|
||||
override val stranger: Stranger,
|
||||
override val action: String,
|
||||
override val suffix: String
|
||||
) : InPrivateSession(), StrangerEvent {
|
||||
override val from: Stranger get() = stranger
|
||||
override val bot: Bot get() = stranger.bot
|
||||
|
||||
override fun toString(): String {
|
||||
return "BotNudgedEvent.InPrivateSession.ByFriend(friend=$stranger, action=$action, suffix=$suffix)"
|
||||
}
|
||||
}
|
||||
|
||||
/** [Bot] 在私聊中自己戳了自己 */
|
||||
public data class ByBot internal constructor(
|
||||
/** [Bot] 的对话对象 */
|
||||
override val friend: Friend,
|
||||
/** 可能是 [Stranger] 或 [Friend] */
|
||||
val user: User,
|
||||
override val action: String,
|
||||
override val suffix: String
|
||||
) : InPrivateSession() {
|
||||
override val from: Friend get() = bot.asFriend
|
||||
) : InPrivateSession(), BotEvent {
|
||||
override val from: User
|
||||
get() = if (user is Stranger) {
|
||||
bot.asStranger
|
||||
} else {
|
||||
bot.asFriend
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "BotNudgedEvent.InPrivateSession.ByBot(friend=$friend, action=$action, suffix=$suffix)"
|
||||
return "BotNudgedEvent.InPrivateSession.ByBot(friend=$user, action=$action, suffix=$suffix)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ public data class FriendAddEvent internal constructor(
|
||||
) : FriendEvent, Packet, AbstractEvent()
|
||||
|
||||
/**
|
||||
* 好友已被删除的事件.
|
||||
* 好友已被删除或主动删除的事件.
|
||||
*/
|
||||
public data class FriendDeleteEvent internal constructor(
|
||||
public override val friend: Friend
|
||||
@ -146,9 +146,9 @@ public sealed class FriendNudgedEvent : AbstractEvent(), FriendEvent, Packet {
|
||||
/** 在 [Bot] 与 [Friend] 的对话中 [Friend] 戳了自己事件 */
|
||||
@MiraiExperimentalApi
|
||||
public data class NudgedByHimself internal constructor(
|
||||
override val friend: Friend,
|
||||
override val action: String,
|
||||
override val suffix: String,
|
||||
override val friend: Friend
|
||||
override val suffix: String
|
||||
) : FriendNudgedEvent() {
|
||||
override fun toString(): String {
|
||||
return "FriendNudgedEvent.NudgedByHimself(friend=$friend, action=$action, suffix=$suffix)"
|
||||
@ -161,9 +161,9 @@ public sealed class FriendNudgedEvent : AbstractEvent(), FriendEvent, Packet {
|
||||
/** [Bot] 戳了 [Friend] */
|
||||
@MiraiExperimentalApi
|
||||
public data class NudgedByBot internal constructor(
|
||||
override val friend: Friend,
|
||||
override val action: String,
|
||||
override val suffix: String,
|
||||
override val friend: Friend
|
||||
override val suffix: String
|
||||
) : FriendNudgedEvent() {
|
||||
override fun toString(): String {
|
||||
return "FriendNudgedEvent.NudgedByBot(friend=$friend, action=$action, suffix=$suffix)"
|
||||
|
@ -103,6 +103,16 @@ public data class TempMessagePreSendEvent @MiraiInternalApi constructor(
|
||||
public val group: Group get() = target.group
|
||||
}
|
||||
|
||||
/**
|
||||
* 在发送陌生人消息前广播的事件.
|
||||
* @see MessagePreSendEvent
|
||||
*/
|
||||
public data class StrangerMessagePreSendEvent @MiraiInternalApi constructor(
|
||||
/** 发信目标. */
|
||||
public override val target: Stranger,
|
||||
/** 待发送的消息. 修改后将会同时应用于发送. */
|
||||
public override var message: Message
|
||||
) : UserMessagePreSendEvent()
|
||||
|
||||
// endregion
|
||||
|
||||
@ -251,6 +261,27 @@ public data class TempMessagePostSendEvent @MiraiInternalApi constructor(
|
||||
public val group: Group get() = target.group
|
||||
}
|
||||
|
||||
/**
|
||||
* 在陌生人消息发送后广播的事件.
|
||||
* @see MessagePostSendEvent
|
||||
*/
|
||||
public data class StrangerMessagePostSendEvent @MiraiInternalApi constructor(
|
||||
/** 发信目标. */
|
||||
public override val target: Stranger,
|
||||
/** 待发送的消息. 此为 [MessagePreSendEvent.message] 的最终值. */
|
||||
public override val message: MessageChain,
|
||||
/**
|
||||
* 发送消息时抛出的异常. `null` 表示消息成功发送.
|
||||
* @see result
|
||||
*/
|
||||
public override val exception: Throwable?,
|
||||
/**
|
||||
* 发送消息成功时的回执. `null` 表示消息发送失败.
|
||||
* @see result
|
||||
*/
|
||||
public override val receipt: MessageReceipt<Stranger>?
|
||||
) : UserMessagePostSendEvent<Stranger>()
|
||||
|
||||
// endregion
|
||||
|
||||
// region MessageRecallEvent
|
||||
@ -620,6 +651,32 @@ public class TempMessageEvent(
|
||||
"TempMessageEvent(sender=${sender.id} from group(${sender.group.id}), message=$message)"
|
||||
}
|
||||
|
||||
/**
|
||||
* 机器人收到的陌生人消息的事件
|
||||
*
|
||||
* @see MessageEvent
|
||||
*/
|
||||
@Suppress("DEPRECATION")
|
||||
public class StrangerMessageEvent constructor(
|
||||
public override val sender: Stranger,
|
||||
public override val message: MessageChain,
|
||||
public override val time: Int
|
||||
) : AbstractMessageEvent(), MessageEvent, MessageEventExtensions<User, Contact>, BroadcastControllable, StrangerEvent {
|
||||
init {
|
||||
val source =
|
||||
message[MessageSource] ?: throw IllegalArgumentException("Cannot find MessageSource from message")
|
||||
check(source is OnlineMessageSource.Incoming.FromStranger) { "source provided to a StrangerMessage must be an instance of OnlineMessageSource.Incoming.FromStranger" }
|
||||
}
|
||||
|
||||
public override val stranger: Stranger get() = sender
|
||||
public override val bot: Bot get() = super.bot
|
||||
public override val subject: Stranger get() = sender
|
||||
public override val senderName: String get() = sender.nick
|
||||
public override val source: OnlineMessageSource.Incoming.FromStranger get() = message.source as OnlineMessageSource.Incoming.FromStranger
|
||||
|
||||
public override fun toString(): String = "StrangerMessageEvent(sender=${sender.id}, message=$message)"
|
||||
}
|
||||
|
||||
/**
|
||||
* 来自 [User] 的消息
|
||||
*
|
||||
|
114
mirai-core-api/src/commonMain/kotlin/event/events/stranger.kt
Normal file
114
mirai-core-api/src/commonMain/kotlin/event/events/stranger.kt
Normal file
@ -0,0 +1,114 @@
|
||||
package net.mamoe.mirai.event.events
|
||||
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.contact.Friend
|
||||
import net.mamoe.mirai.contact.Stranger
|
||||
import net.mamoe.mirai.event.AbstractEvent
|
||||
import net.mamoe.mirai.internal.network.Packet
|
||||
import net.mamoe.mirai.message.action.Nudge
|
||||
import net.mamoe.mirai.utils.MiraiExperimentalApi
|
||||
|
||||
/**
|
||||
* 新增陌生人的事件
|
||||
*
|
||||
*/
|
||||
public data class StrangerAddEvent internal constructor(
|
||||
/**
|
||||
* 新的陌生人. 已经添加到 [Bot.strangers]
|
||||
*/
|
||||
public override val stranger: Stranger
|
||||
) : StrangerEvent, Packet, AbstractEvent()
|
||||
|
||||
|
||||
/**
|
||||
* 陌生人关系改变事件
|
||||
*
|
||||
*/
|
||||
public abstract class StrangerRelationChangeEvent(
|
||||
public override val stranger: Stranger
|
||||
) : StrangerEvent, Packet, AbstractEvent() {
|
||||
/**
|
||||
* 主动删除陌生人或陌生人被删除的事件
|
||||
*
|
||||
* 除主动删除外,此事件为惰性广播,无法确保实时性
|
||||
* 目前被动删除仅会在陌生人二次添加时才会进行广播
|
||||
*/
|
||||
public class Deleted(
|
||||
/**
|
||||
* 被删除的陌生人
|
||||
*/
|
||||
stranger: Stranger
|
||||
) : StrangerRelationChangeEvent(stranger)
|
||||
|
||||
/**
|
||||
* 与陌生人成为好友
|
||||
*/
|
||||
public class Friended(
|
||||
/**
|
||||
* 成为好友的陌生人
|
||||
*
|
||||
* 成为好友后该陌生人会从陌生人列表中删除
|
||||
*/
|
||||
public override val stranger: Stranger,
|
||||
/**
|
||||
* 成为好友后的实例
|
||||
*
|
||||
* 已经添加到Bot的好友列表中
|
||||
*/
|
||||
public val friend: Friend
|
||||
) : StrangerRelationChangeEvent(stranger)
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 在 [Stranger] 与 [Bot] 的对话中, [Stranger] 被 [戳][Nudge] 事件
|
||||
*
|
||||
* 注: 此事件仅可能在私聊中发生
|
||||
*/
|
||||
@MiraiExperimentalApi
|
||||
public sealed class StrangerNudgedEvent : AbstractEvent(), StrangerEvent, Packet {
|
||||
/**
|
||||
* 戳一戳的发起人, 为 [Bot] 的某一好友, 或是 [Bot.asFriend]
|
||||
*/
|
||||
public abstract val from: Stranger
|
||||
|
||||
/**
|
||||
* 戳一戳的动作名称
|
||||
*/
|
||||
public abstract val action: String
|
||||
|
||||
/**
|
||||
* 戳一戳中设置的自定义后缀
|
||||
*/
|
||||
public abstract val suffix: String
|
||||
|
||||
/** 在 [Bot] 与 [Stranger] 的对话中 [Stranger] 戳了自己事件 */
|
||||
@MiraiExperimentalApi
|
||||
public data class NudgedByHimself internal constructor(
|
||||
override val stranger: Stranger,
|
||||
override val action: String,
|
||||
override val suffix: String
|
||||
) : StrangerNudgedEvent() {
|
||||
override fun toString(): String {
|
||||
return "StrangerNudgedEvent.NudgedByHimself(stranger=$stranger, action=$action, suffix=$suffix)"
|
||||
}
|
||||
|
||||
override val from: Stranger
|
||||
get() = stranger
|
||||
}
|
||||
|
||||
/** [Bot] 戳了 [Stranger] */
|
||||
@MiraiExperimentalApi
|
||||
public data class NudgedByBot internal constructor(
|
||||
override val stranger: Stranger,
|
||||
override val action: String,
|
||||
override val suffix: String
|
||||
) : StrangerNudgedEvent() {
|
||||
override fun toString(): String {
|
||||
return "StrangerNudgedEvent.NudgedByBot(stranger=$stranger, action=$action, suffix=$suffix)"
|
||||
}
|
||||
|
||||
override val from: Stranger
|
||||
get() = bot.asStranger
|
||||
}
|
||||
}
|
@ -17,6 +17,7 @@ import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.contact.Friend
|
||||
import net.mamoe.mirai.contact.Group
|
||||
import net.mamoe.mirai.contact.Member
|
||||
import net.mamoe.mirai.contact.Stranger
|
||||
import net.mamoe.mirai.event.Event
|
||||
import kotlin.internal.HidesMembers
|
||||
|
||||
@ -91,4 +92,12 @@ public inline val GroupOperableEvent.operatorOrBot: Member
|
||||
public interface FriendEvent : BotEvent {
|
||||
public val friend: Friend
|
||||
public override val bot: Bot get() = friend.bot
|
||||
}
|
||||
|
||||
/**
|
||||
* 有关陌生人的事件
|
||||
*/
|
||||
public interface StrangerEvent : BotEvent {
|
||||
public val stranger: Stranger
|
||||
public override val bot: Bot get() = stranger.bot
|
||||
}
|
@ -13,6 +13,7 @@ import kotlinx.coroutines.Job
|
||||
import net.mamoe.mirai.contact.AnonymousMember
|
||||
import net.mamoe.mirai.contact.Friend
|
||||
import net.mamoe.mirai.contact.Group
|
||||
import net.mamoe.mirai.contact.Stranger
|
||||
import net.mamoe.mirai.data.*
|
||||
import net.mamoe.mirai.utils.MiraiExperimentalApi
|
||||
import net.mamoe.mirai.utils.WeakRef
|
||||
@ -51,6 +52,15 @@ public interface LowLevelApiAccessor {
|
||||
@LowLevelApi
|
||||
public fun _lowLevelNewFriend(bot: Bot, friendInfo: FriendInfo): Friend
|
||||
|
||||
/**
|
||||
* 构造一个 [Stranger] 对象. 它持有对 [Bot] 的弱引用([WeakRef]).
|
||||
*
|
||||
* [Bot] 无法管理这个对象, 但这个对象会以 [Bot] 的 [Job] 作为父 Job.
|
||||
* 因此, 当 [Bot] 被关闭后, 这个对象也会被关闭.
|
||||
*/
|
||||
@LowLevelApi
|
||||
public fun _lowLevelNewStranger(bot: Bot, strangerInfo: StrangerInfo): Stranger
|
||||
|
||||
/**
|
||||
* 向服务器查询群列表. 返回值高 32 bits 为 uin, 低 32 bits 为 groupCode
|
||||
*/
|
||||
|
@ -99,4 +99,12 @@ public data class MemberNudge(
|
||||
*/
|
||||
public data class FriendNudge(
|
||||
public override val target: Friend
|
||||
) : UserNudge()
|
||||
|
||||
/**
|
||||
* @see Stranger.nudge
|
||||
* @see Nudge
|
||||
*/
|
||||
public data class StrangerNudge(
|
||||
public override val target: UserOrBot
|
||||
) : UserNudge()
|
@ -27,6 +27,7 @@ import net.mamoe.mirai.message.MessageReceipt
|
||||
import net.mamoe.mirai.message.MessageSourceSerializerImpl
|
||||
import net.mamoe.mirai.message.data.MessageSource.Key.isAboutFriend
|
||||
import net.mamoe.mirai.message.data.MessageSource.Key.isAboutGroup
|
||||
import net.mamoe.mirai.message.data.MessageSource.Key.isAboutStranger
|
||||
import net.mamoe.mirai.message.data.MessageSource.Key.isAboutTemp
|
||||
import net.mamoe.mirai.message.data.MessageSource.Key.quote
|
||||
import net.mamoe.mirai.utils.LazyProperty
|
||||
@ -225,6 +226,17 @@ public sealed class MessageSource : Message, MessageMetadata, ConstrainSingle {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否是发送给陌生人 或从陌生人接收的消息的消息源
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun MessageSource.isAboutStranger(): Boolean {
|
||||
return when (this) {
|
||||
is OnlineMessageSource -> subject is Stranger
|
||||
is OfflineMessageSource -> kind == MessageSourceKind.STRANGER
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否是发送给临时会话, 或从临时会话接收的消息的消息源
|
||||
*/
|
||||
@ -348,6 +360,14 @@ public sealed class OnlineMessageSource : MessageSource() {
|
||||
// final override fun toString(): String = "OnlineMessageSource.ToFriend(target=${target.ids})"
|
||||
}
|
||||
|
||||
public abstract class ToStranger : Outgoing() {
|
||||
public companion object Key : AbstractPolymorphicMessageKey<Outgoing, ToStranger>(Outgoing, { it.safeCast() })
|
||||
|
||||
public abstract override val target: Stranger
|
||||
public final override val subject: Stranger get() = target
|
||||
// final override fun toString(): String = "OnlineMessageSource.ToFriend(target=${target.ids})"
|
||||
}
|
||||
|
||||
public abstract class ToTemp : Outgoing() {
|
||||
public companion object Key : AbstractPolymorphicMessageKey<Outgoing, ToTemp>(Outgoing, { it.safeCast() })
|
||||
|
||||
@ -393,6 +413,15 @@ public sealed class OnlineMessageSource : MessageSource() {
|
||||
public final override val target: Bot get() = sender.bot
|
||||
}
|
||||
|
||||
public abstract class FromStranger : Incoming() {
|
||||
public companion object Key :
|
||||
AbstractPolymorphicMessageKey<Incoming, FromStranger>(Incoming, { it.safeCast() })
|
||||
|
||||
public abstract override val sender: Stranger
|
||||
public final override val subject: Stranger get() = sender
|
||||
public final override val target: Bot get() = sender.bot
|
||||
}
|
||||
|
||||
public abstract class FromGroup : Incoming() {
|
||||
public companion object Key :
|
||||
AbstractPolymorphicMessageKey<Incoming, FromGroup>(Incoming, { it.safeCast() })
|
||||
@ -428,7 +457,8 @@ public abstract class OfflineMessageSource : MessageSource() {
|
||||
public enum class MessageSourceKind {
|
||||
GROUP,
|
||||
FRIEND,
|
||||
TEMP
|
||||
TEMP,
|
||||
STRANGER
|
||||
}
|
||||
|
||||
public val MessageSource.kind: MessageSourceKind
|
||||
@ -442,6 +472,7 @@ public val OnlineMessageSource.kind: MessageSourceKind
|
||||
isAboutGroup() -> MessageSourceKind.GROUP
|
||||
isAboutFriend() -> MessageSourceKind.FRIEND
|
||||
isAboutTemp() -> MessageSourceKind.TEMP
|
||||
isAboutStranger() -> MessageSourceKind.STRANGER
|
||||
else -> error("Internal error: OnlineMessageSource.kind reached an unexpected clause")
|
||||
}
|
||||
|
||||
@ -511,4 +542,4 @@ public inline val MessageChain.source: MessageSource
|
||||
*/
|
||||
@get:JvmSynthetic
|
||||
public inline val MessageChain.sourceOrNull: MessageSource?
|
||||
get() = this[MessageSource]
|
||||
get() = this[MessageSource]
|
||||
|
@ -15,10 +15,7 @@ package net.mamoe.mirai.message.data
|
||||
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.Mirai
|
||||
import net.mamoe.mirai.contact.ContactOrBot
|
||||
import net.mamoe.mirai.contact.Friend
|
||||
import net.mamoe.mirai.contact.Group
|
||||
import net.mamoe.mirai.contact.Member
|
||||
import net.mamoe.mirai.contact.*
|
||||
import net.mamoe.mirai.message.data.MessageSource.Key.isAboutFriend
|
||||
import net.mamoe.mirai.message.data.MessageSource.Key.isAboutGroup
|
||||
import net.mamoe.mirai.message.data.MessageSource.Key.isAboutTemp
|
||||
@ -238,6 +235,7 @@ internal class MessageSourceBuilderImpl : MessageSourceBuilder() {
|
||||
this is Member || target is Member -> MessageSourceKind.TEMP
|
||||
this is Bot && target is Friend -> MessageSourceKind.FRIEND
|
||||
this is Friend && target is Bot -> MessageSourceKind.FRIEND
|
||||
this is Stranger || target is Stranger -> MessageSourceKind.STRANGER
|
||||
else -> throw IllegalArgumentException("Cannot determine source kind for sender $this and target $target")
|
||||
}
|
||||
return this@MessageSourceBuilderImpl
|
||||
|
@ -236,6 +236,15 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
|
||||
)
|
||||
}
|
||||
|
||||
@LowLevelApi
|
||||
override fun _lowLevelNewStranger(bot: Bot, strangerInfo: StrangerInfo): Stranger {
|
||||
return StrangerImpl(
|
||||
bot.asQQAndroidBot(),
|
||||
bot.coroutineContext + SupervisorJob(bot.supervisorJob),
|
||||
strangerInfo
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@OptIn(LowLevelApi::class)
|
||||
override suspend fun _lowLevelQueryGroupList(bot: Bot): Sequence<Long> {
|
||||
@ -308,7 +317,9 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
|
||||
}
|
||||
}
|
||||
is MessageSourceFromFriendImpl,
|
||||
is MessageSourceToFriendImpl
|
||||
is MessageSourceToFriendImpl,
|
||||
is MessageSourceFromStrangerImpl,
|
||||
is MessageSourceToStrangerImpl,
|
||||
-> network.run {
|
||||
check(source.fromId == bot.id) {
|
||||
"can only recall a message sent by bot"
|
||||
@ -339,7 +350,7 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
|
||||
}
|
||||
is OfflineMessageSource -> network.run {
|
||||
when (source.kind) {
|
||||
MessageSourceKind.FRIEND -> {
|
||||
MessageSourceKind.FRIEND, MessageSourceKind.STRANGER -> {
|
||||
check(source.fromId == bot.id) {
|
||||
"can only recall a message sent by bot"
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import net.mamoe.mirai.Mirai
|
||||
import net.mamoe.mirai.contact.*
|
||||
import net.mamoe.mirai.data.*
|
||||
import net.mamoe.mirai.internal.contact.OtherClientImpl
|
||||
import net.mamoe.mirai.internal.contact.StrangerInfoImpl
|
||||
import net.mamoe.mirai.internal.contact.checkIsGroupImpl
|
||||
import net.mamoe.mirai.internal.contact.uin
|
||||
import net.mamoe.mirai.internal.message.*
|
||||
@ -116,6 +117,8 @@ internal class QQAndroidBot constructor(
|
||||
get() = client.wLoginSigInfo.sKey.data
|
||||
.fold(5381) { acc: Int, b: Byte -> acc + acc.shl(5) + b.toInt() }
|
||||
.and(Int.MAX_VALUE)
|
||||
override val asStranger: Stranger by lazy { Mirai._lowLevelNewStranger(bot, StrangerInfoImpl(bot.id, bot.nick)) }
|
||||
override val strangers: ContactList<Stranger> = ContactList()
|
||||
}
|
||||
|
||||
internal val EMPTY_BYTE_ARRAY = ByteArray(0)
|
||||
|
@ -10,7 +10,11 @@
|
||||
package net.mamoe.mirai.internal.contact
|
||||
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.contact.Friend
|
||||
import net.mamoe.mirai.contact.Member
|
||||
import net.mamoe.mirai.contact.Stranger
|
||||
import net.mamoe.mirai.contact.User
|
||||
import net.mamoe.mirai.data.UserInfo
|
||||
import net.mamoe.mirai.event.broadcast
|
||||
import net.mamoe.mirai.event.events.BeforeImageUploadEvent
|
||||
import net.mamoe.mirai.event.events.EventCancelledException
|
||||
@ -29,14 +33,17 @@ import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.time.measureTime
|
||||
|
||||
internal open class UserInfoImpl(override val uin: Long, override val nick: String, override val remark: String = "") :
|
||||
UserInfo
|
||||
|
||||
internal abstract class AbstractUser(
|
||||
bot: Bot,
|
||||
coroutineContext: CoroutineContext,
|
||||
friendInfo: net.mamoe.mirai.data.FriendInfo,
|
||||
userInfo: UserInfo,
|
||||
) : User, AbstractContact(bot, coroutineContext) {
|
||||
final override val id: Long = friendInfo.uin
|
||||
final override var nick: String = friendInfo.nick
|
||||
final override val remark: String = friendInfo.remark
|
||||
final override val id: Long = userInfo.uin
|
||||
final override var nick: String = userInfo.nick
|
||||
final override val remark: String = userInfo.remark
|
||||
|
||||
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
||||
override suspend fun uploadImage(resource: ExternalResource): Image {
|
||||
@ -57,6 +64,12 @@ internal abstract class AbstractUser(
|
||||
).sendAndExpect<LongConn.OffPicUp.Response>()
|
||||
}
|
||||
|
||||
val kind = when (this) {
|
||||
is Stranger -> "stranger"
|
||||
is Friend -> "friend"
|
||||
is Member -> "temp"
|
||||
else -> "unknown"
|
||||
}
|
||||
return when (response) {
|
||||
is LongConn.OffPicUp.Response.FileExists -> OfflineFriendImage(response.resourceId)
|
||||
.also {
|
||||
@ -64,7 +77,7 @@ internal abstract class AbstractUser(
|
||||
}
|
||||
is LongConn.OffPicUp.Response.RequireUpload -> {
|
||||
bot.network.logger.verbose {
|
||||
"[Http] Uploading friend image, size=${resource.size.sizeToString()}"
|
||||
"[Http] Uploading $kind image, size=${resource.size.sizeToString()}"
|
||||
}
|
||||
|
||||
val time = measureTime {
|
||||
@ -78,7 +91,7 @@ internal abstract class AbstractUser(
|
||||
}
|
||||
|
||||
bot.network.logger.verbose {
|
||||
"[Http] Uploading friend image: succeed at ${(resource.size.toDouble() / 1024 / time.inSeconds).roundToInt()} KiB/s"
|
||||
"[Http] Uploading $kind image: succeed at ${(resource.size.toDouble() / 1024 / time.inSeconds).roundToInt()} KiB/s"
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -10,7 +10,6 @@
|
||||
package net.mamoe.mirai.internal.contact
|
||||
|
||||
import net.mamoe.mirai.contact.MemberPermission
|
||||
import net.mamoe.mirai.data.FriendInfoImpl
|
||||
import net.mamoe.mirai.data.MemberInfo
|
||||
import net.mamoe.mirai.internal.network.protocol.data.jce.StTroopMemberInfo
|
||||
|
||||
@ -23,7 +22,7 @@ internal class MemberInfoImpl(
|
||||
override val specialTitle: String,
|
||||
override val muteTimestamp: Int,
|
||||
override val anonymousId: String?,
|
||||
) : MemberInfo, FriendInfoImpl(uin, nick, remark) {
|
||||
) : MemberInfo, UserInfoImpl(uin, nick, remark) {
|
||||
constructor(
|
||||
jceInfo: StTroopMemberInfo,
|
||||
groupOwnerId: Long
|
||||
|
@ -54,11 +54,16 @@ internal class NormalMemberImpl constructor(
|
||||
require(message.isContentNotEmpty()) { "message is empty" }
|
||||
|
||||
val asFriend = this.asFriendOrNull()
|
||||
val asStranger = this.asStrangerOrNull()
|
||||
|
||||
return (asFriend?.sendMessageImpl(
|
||||
message,
|
||||
friendReceiptConstructor = { MessageReceipt(it, asFriend) },
|
||||
tReceiptConstructor = { MessageReceipt(it, this) }
|
||||
) ?: asStranger?.sendMessageImpl(
|
||||
message,
|
||||
strangerReceiptConstructor = { MessageReceipt(it, asStranger) },
|
||||
tReceiptConstructor = { MessageReceipt(it, this) }
|
||||
) ?: sendMessageImpl(message)).also { logMessageSent(message) }
|
||||
}
|
||||
|
||||
|
91
mirai-core/src/commonMain/kotlin/contact/StrangerImpl.kt
Normal file
91
mirai-core/src/commonMain/kotlin/contact/StrangerImpl.kt
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2019-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
|
||||
*/
|
||||
@file:OptIn(LowLevelApi::class)
|
||||
@file:Suppress(
|
||||
"EXPERIMENTAL_API_USAGE",
|
||||
"DEPRECATION_ERROR",
|
||||
"NOTHING_TO_INLINE",
|
||||
"INVISIBLE_MEMBER",
|
||||
"INVISIBLE_REFERENCE"
|
||||
)
|
||||
|
||||
package net.mamoe.mirai.internal.contact
|
||||
|
||||
import kotlinx.atomicfu.AtomicInt
|
||||
import kotlinx.atomicfu.atomic
|
||||
import net.mamoe.mirai.LowLevelApi
|
||||
import net.mamoe.mirai.contact.Stranger
|
||||
import net.mamoe.mirai.data.FriendInfoImpl
|
||||
import net.mamoe.mirai.data.StrangerInfo
|
||||
import net.mamoe.mirai.internal.QQAndroidBot
|
||||
import net.mamoe.mirai.message.MessageReceipt
|
||||
import net.mamoe.mirai.message.data.Message
|
||||
import net.mamoe.mirai.message.data.isContentNotEmpty
|
||||
import network.protocol.packet.list.StrangerList
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
|
||||
internal class StrangerInfoImpl(
|
||||
override val uin: Long, override val nick: String, override val fromGroup: Long = 0,
|
||||
override val remark: String = ""
|
||||
) : StrangerInfo
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
internal inline fun StrangerInfo.checkIsInfoImpl(): FriendInfoImpl {
|
||||
contract {
|
||||
returns() implies (this@checkIsInfoImpl is StrangerInfoImpl)
|
||||
}
|
||||
check(this is FriendInfoImpl) { "A StrangerInfo instance is not instance of StrangerInfoImpl. Your instance: ${this::class.qualifiedName}" }
|
||||
return this
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
internal inline fun Stranger.checkIsImpl(): StrangerImpl {
|
||||
contract {
|
||||
returns() implies (this@checkIsImpl is StrangerImpl)
|
||||
}
|
||||
check(this is StrangerImpl) { "A Stranger instance is not instance of StrangerImpl. Your instance: ${this::class.qualifiedName}" }
|
||||
return this
|
||||
}
|
||||
|
||||
internal class StrangerImpl(
|
||||
bot: QQAndroidBot,
|
||||
coroutineContext: CoroutineContext,
|
||||
internal val strangerInfo: StrangerInfo
|
||||
) : Stranger, AbstractUser(bot, coroutineContext, strangerInfo) {
|
||||
@Suppress("unused") // bug
|
||||
val lastMessageSequence: AtomicInt = atomic(-1)
|
||||
override suspend fun delete() {
|
||||
check(bot.strangers[this.id] != null) {
|
||||
"Stranger ${this.id} had already been deleted"
|
||||
}
|
||||
bot.network.run {
|
||||
StrangerList.DelStranger(bot.client, this@StrangerImpl)
|
||||
.sendAndExpect<StrangerList.DelStranger.Response>().also {
|
||||
check(it.isSuccess) { "delete Stranger failed: ${it.result}" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("DuplicatedCode")
|
||||
override suspend fun sendMessage(message: Message): MessageReceipt<Stranger> {
|
||||
require(message.isContentNotEmpty()) { "message is empty" }
|
||||
return sendMessageImpl(
|
||||
message,
|
||||
strangerReceiptConstructor = { MessageReceipt(it, this) },
|
||||
tReceiptConstructor = { MessageReceipt(it, this) }
|
||||
).also {
|
||||
logMessageSent(message)
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String = "Stranger($id)"
|
||||
}
|
@ -17,9 +17,11 @@ import net.mamoe.mirai.event.broadcast
|
||||
import net.mamoe.mirai.event.events.*
|
||||
import net.mamoe.mirai.internal.asQQAndroidBot
|
||||
import net.mamoe.mirai.internal.message.MessageSourceToFriendImpl
|
||||
import net.mamoe.mirai.internal.message.MessageSourceToStrangerImpl
|
||||
import net.mamoe.mirai.internal.message.ensureSequenceIdAvailable
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.MessageSvcPbSendMsg
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.createToFriend
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.createToStranger
|
||||
import net.mamoe.mirai.internal.utils.estimateLength
|
||||
import net.mamoe.mirai.message.*
|
||||
import net.mamoe.mirai.message.data.*
|
||||
@ -85,6 +87,56 @@ internal suspend fun <T : User> Friend.sendMessageImpl(
|
||||
return tReceiptConstructor(source)
|
||||
}
|
||||
|
||||
internal suspend fun <T : User> Stranger.sendMessageImpl(
|
||||
message: Message,
|
||||
strangerReceiptConstructor: (MessageSourceToStrangerImpl) -> MessageReceipt<Stranger>,
|
||||
tReceiptConstructor: (MessageSourceToStrangerImpl) -> MessageReceipt<T>
|
||||
): MessageReceipt<T> {
|
||||
contract { callsInPlace(strangerReceiptConstructor, InvocationKind.EXACTLY_ONCE) }
|
||||
val bot = bot.asQQAndroidBot()
|
||||
|
||||
val chain = kotlin.runCatching {
|
||||
StrangerMessagePreSendEvent(this, message).broadcast()
|
||||
}.onSuccess {
|
||||
check(!it.isCancelled) {
|
||||
throw EventCancelledException("cancelled by StrangerMessagePreSendEvent")
|
||||
}
|
||||
}.getOrElse {
|
||||
throw EventCancelledException("exception thrown when broadcasting StrangerMessagePreSendEvent", it)
|
||||
}.message.asMessageChain()
|
||||
chain.verityLength(message, this, {}, {})
|
||||
|
||||
chain.firstIsInstanceOrNull<QuoteReply>()?.source?.ensureSequenceIdAvailable()
|
||||
|
||||
lateinit var source: MessageSourceToStrangerImpl
|
||||
val result = bot.network.runCatching {
|
||||
MessageSvcPbSendMsg.createToStranger(
|
||||
bot.client,
|
||||
this@sendMessageImpl,
|
||||
chain,
|
||||
) {
|
||||
source = it
|
||||
}.sendAndExpect<MessageSvcPbSendMsg.Response>().let {
|
||||
check(it is MessageSvcPbSendMsg.Response.SUCCESS) {
|
||||
"Send stranger message failed: $it"
|
||||
}
|
||||
}
|
||||
strangerReceiptConstructor(source)
|
||||
}
|
||||
|
||||
result.fold(
|
||||
onSuccess = {
|
||||
StrangerMessagePostSendEvent(this, chain, null, it)
|
||||
},
|
||||
onFailure = {
|
||||
StrangerMessagePostSendEvent(this, chain, it, null)
|
||||
}
|
||||
).broadcast()
|
||||
|
||||
result.getOrThrow()
|
||||
return tReceiptConstructor(source)
|
||||
}
|
||||
|
||||
internal fun Contact.logMessageSent(message: Message) {
|
||||
if (message !is LongMessage) {
|
||||
bot.logger.verbose("$this <- $message".replaceMagicCodes())
|
||||
@ -128,6 +180,9 @@ internal fun net.mamoe.mirai.event.events.MessageEvent.logMessageReceived() {
|
||||
is net.mamoe.mirai.event.events.TempMessageEvent -> bot.logger.verbose {
|
||||
"[${group.name}(${group.id})] $senderName(Temp ${sender.id}) -> $message".replaceMagicCodes()
|
||||
}
|
||||
is net.mamoe.mirai.event.events.StrangerMessageEvent -> bot.logger.verbose {
|
||||
"[$senderName(Stranger ${sender.id}) -> $message".replaceMagicCodes()
|
||||
}
|
||||
is net.mamoe.mirai.event.events.FriendMessageEvent -> bot.logger.verbose {
|
||||
"${sender.nick}(${sender.id}) -> $message".replaceMagicCodes()
|
||||
}
|
||||
|
@ -238,27 +238,26 @@ private val PB_RESERVE_FOR_PTT =
|
||||
private val PB_RESERVE_FOR_DOUTU = "78 00 90 01 01 F8 01 00 A0 02 00 C8 02 00".hexToBytes()
|
||||
private val PB_RESERVE_FOR_ELSE = "78 00 F8 01 00 C8 02 00".hexToBytes()
|
||||
|
||||
|
||||
internal fun MsgComm.Msg.toMessageChain(
|
||||
bot: Bot,
|
||||
groupIdOrZero: Long,
|
||||
onlineSource: Boolean,
|
||||
isTemp: Boolean = false
|
||||
): MessageChain = listOf(this).toMessageChain(bot, bot.id, groupIdOrZero, onlineSource, isTemp)
|
||||
messageSourceKind: MessageSourceKind
|
||||
): MessageChain = listOf(this).toMessageChain(bot, bot.id, groupIdOrZero, onlineSource, messageSourceKind)
|
||||
|
||||
internal fun List<MsgOnlinePush.PbPushMsg>.toMessageChain(
|
||||
bot: Bot,
|
||||
groupIdOrZero: Long,
|
||||
onlineSource: Boolean,
|
||||
isTemp: Boolean = false
|
||||
): MessageChain = map { it.msg }.toMessageChain(bot, bot.id, groupIdOrZero, onlineSource, isTemp)
|
||||
messageSourceKind: MessageSourceKind
|
||||
): MessageChain = map { it.msg }.toMessageChain(bot, bot.id, groupIdOrZero, onlineSource, messageSourceKind)
|
||||
|
||||
internal fun List<MsgComm.Msg>.toMessageChain(
|
||||
bot: Bot?,
|
||||
botId: Long,
|
||||
groupIdOrZero: Long,
|
||||
onlineSource: Boolean,
|
||||
isTemp: Boolean = false
|
||||
messageSourceKind: MessageSourceKind
|
||||
): MessageChain {
|
||||
val elements = this.flatMap { it.msgBody.richText.elems }
|
||||
|
||||
@ -277,13 +276,15 @@ internal fun List<MsgComm.Msg>.toMessageChain(
|
||||
return buildMessageChain(elements.size + 1 + ptts.size) {
|
||||
if (onlineSource) {
|
||||
checkNotNull(bot) { "bot is null" }
|
||||
when {
|
||||
isTemp -> +MessageSourceFromTempImpl(bot, this@toMessageChain)
|
||||
groupIdOrZero != 0L -> +MessageSourceFromGroupImpl(bot, this@toMessageChain)
|
||||
else -> +MessageSourceFromFriendImpl(bot, this@toMessageChain)
|
||||
|
||||
when (messageSourceKind) {
|
||||
MessageSourceKind.TEMP -> +MessageSourceFromTempImpl(bot, this@toMessageChain)
|
||||
MessageSourceKind.GROUP -> +MessageSourceFromGroupImpl(bot, this@toMessageChain)
|
||||
MessageSourceKind.FRIEND -> +MessageSourceFromFriendImpl(bot, this@toMessageChain)
|
||||
MessageSourceKind.STRANGER -> +MessageSourceFromStrangerImpl(bot, this@toMessageChain)
|
||||
}
|
||||
} else {
|
||||
+OfflineMessageSourceImplByMsg(this@toMessageChain, botId)
|
||||
+OfflineMessageSourceImplByMsg(bot, this@toMessageChain, botId)
|
||||
}
|
||||
elements.joinToMessageChain(groupIdOrZero, botId, this)
|
||||
addAll(ptts)
|
||||
|
@ -16,6 +16,7 @@ import kotlinx.serialization.Transient
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.contact.Friend
|
||||
import net.mamoe.mirai.contact.Member
|
||||
import net.mamoe.mirai.contact.Stranger
|
||||
import net.mamoe.mirai.internal.contact.GroupImpl
|
||||
import net.mamoe.mirai.internal.contact.newAnonymous
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
|
||||
@ -25,10 +26,7 @@ import net.mamoe.mirai.internal.network.protocol.packet.EMPTY_BYTE_ARRAY
|
||||
import net.mamoe.mirai.internal.utils._miraiContentToString
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.toByteArray
|
||||
import net.mamoe.mirai.message.MessageSourceSerializerImpl
|
||||
import net.mamoe.mirai.message.data.Message
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
import net.mamoe.mirai.message.data.MessageSource
|
||||
import net.mamoe.mirai.message.data.OnlineMessageSource
|
||||
import net.mamoe.mirai.message.data.*
|
||||
import net.mamoe.mirai.utils.encodeToBase64
|
||||
import net.mamoe.mirai.utils.encodeToString
|
||||
import net.mamoe.mirai.utils.mapToIntArray
|
||||
@ -85,15 +83,51 @@ internal class MessageSourceFromFriendImpl(
|
||||
it.msgBody.richText.attr?.random ?: 0
|
||||
} // other client 消息的这个是0
|
||||
override val time: Int get() = msg.first().msgHead.msgTime
|
||||
override val originalMessage: MessageChain by lazy { msg.toMessageChain(bot, bot.id, 0, false) }
|
||||
override val originalMessage: MessageChain by lazy {
|
||||
msg.toMessageChain(
|
||||
bot,
|
||||
bot.id,
|
||||
0,
|
||||
false,
|
||||
MessageSourceKind.FRIEND
|
||||
)
|
||||
}
|
||||
override val sender: Friend get() = bot.getFriendOrFail(msg.first().msgHead.fromUin)
|
||||
|
||||
private val jceData by lazy { msg.toJceDataFriendOrTemp(internalIds) }
|
||||
private val jceData by lazy { msg.toJceDataPrivate(internalIds) }
|
||||
|
||||
override fun toJceData(): ImMsgBody.SourceMsg = jceData
|
||||
}
|
||||
|
||||
private fun List<MsgComm.Msg>.toJceDataFriendOrTemp(ids: IntArray): ImMsgBody.SourceMsg {
|
||||
internal class MessageSourceFromStrangerImpl(
|
||||
override val bot: Bot,
|
||||
val msg: List<MsgComm.Msg>
|
||||
) : OnlineMessageSource.Incoming.FromStranger(), MessageSourceInternal {
|
||||
override val sequenceIds: IntArray get() = msg.mapToIntArray { it.msgHead.msgSeq }
|
||||
override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
|
||||
override val ids: IntArray get() = sequenceIds// msg.msgBody.richText.attr!!.random
|
||||
override val internalIds: IntArray
|
||||
get() = msg.mapToIntArray {
|
||||
it.msgBody.richText.attr?.random ?: 0
|
||||
} // other client 消息的这个是0
|
||||
override val time: Int get() = msg.first().msgHead.msgTime
|
||||
override val originalMessage: MessageChain by lazy {
|
||||
msg.toMessageChain(
|
||||
bot,
|
||||
bot.id,
|
||||
0,
|
||||
false,
|
||||
MessageSourceKind.STRANGER
|
||||
)
|
||||
}
|
||||
override val sender: Stranger get() = bot.getStrangerOrFail(msg.first().msgHead.fromUin)
|
||||
|
||||
private val jceData by lazy { msg.toJceDataPrivate(internalIds) }
|
||||
|
||||
override fun toJceData(): ImMsgBody.SourceMsg = jceData
|
||||
}
|
||||
|
||||
private fun List<MsgComm.Msg>.toJceDataPrivate(ids: IntArray): ImMsgBody.SourceMsg {
|
||||
val elements = flatMap { it.msgBody.richText.elems }.toMutableList().also {
|
||||
if (it.last().elemFlags2 == null) it.add(ImMsgBody.Elem(elemFlags2 = ImMsgBody.ElemFlags2()))
|
||||
}
|
||||
@ -144,7 +178,7 @@ internal class MessageSourceFromTempImpl(
|
||||
bot.id,
|
||||
groupIdOrZero = 0,
|
||||
onlineSource = false,
|
||||
isTemp = false,
|
||||
MessageSourceKind.TEMP
|
||||
)
|
||||
}
|
||||
override val sender: Member
|
||||
@ -152,7 +186,7 @@ internal class MessageSourceFromTempImpl(
|
||||
bot.getGroupOrFail(c2cTmpMsgHead!!.groupUin).getOrFail(fromUin)
|
||||
}
|
||||
|
||||
private val jceData by lazy { msg.toJceDataFriendOrTemp(internalIds) }
|
||||
private val jceData by lazy { msg.toJceDataPrivate(internalIds) }
|
||||
override fun toJceData(): ImMsgBody.SourceMsg = jceData
|
||||
}
|
||||
|
||||
@ -170,7 +204,7 @@ internal data class MessageSourceFromGroupImpl(
|
||||
override val ids: IntArray get() = sequenceIds
|
||||
override val time: Int get() = msg.first().msgHead.msgTime
|
||||
override val originalMessage: MessageChain by lazy {
|
||||
msg.toMessageChain(bot, bot.id, groupIdOrZero = group.id, onlineSource = false)
|
||||
msg.toMessageChain(bot, bot.id, groupIdOrZero = group.id, onlineSource = false, MessageSourceKind.GROUP)
|
||||
}
|
||||
|
||||
override val sender: Member by lazy {
|
||||
|
@ -13,6 +13,7 @@ package net.mamoe.mirai.internal.message
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.Transient
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.SourceMsg
|
||||
@ -91,11 +92,25 @@ internal data class OfflineMessageSourceImplData(
|
||||
|
||||
internal class OfflineMessageSourceImplByMsg(
|
||||
// from other sources' originalMessage
|
||||
bot: Bot?,
|
||||
val delegate: List<MsgComm.Msg>,
|
||||
override val botId: Long,
|
||||
) : OfflineMessageSource(), MessageSourceInternal {
|
||||
override val kind: MessageSourceKind =
|
||||
if (delegate.first().msgHead.groupInfo != null) MessageSourceKind.GROUP else MessageSourceKind.FRIEND
|
||||
when {
|
||||
delegate.first().msgHead.groupInfo != null -> {
|
||||
MessageSourceKind.GROUP
|
||||
}
|
||||
delegate.first().msgHead.c2cTmpMsgHead != null -> {
|
||||
MessageSourceKind.TEMP
|
||||
}
|
||||
bot?.getStranger(delegate.first().msgHead.fromUin) != null -> {
|
||||
MessageSourceKind.STRANGER
|
||||
}
|
||||
else -> {
|
||||
MessageSourceKind.FRIEND
|
||||
}
|
||||
}
|
||||
override val ids: IntArray get() = sequenceIds
|
||||
override val internalIds: IntArray = delegate.mapToIntArray { it.msgHead.msgUid.toInt() }
|
||||
override val time: Int
|
||||
@ -110,7 +125,7 @@ internal class OfflineMessageSourceImplByMsg(
|
||||
botId,
|
||||
groupIdOrZero = delegate.first().msgHead.groupInfo?.groupCode ?: 0,
|
||||
onlineSource = false,
|
||||
isTemp = delegate.first().msgHead.c2cTmpMsgHead != null
|
||||
messageSourceKind = kind
|
||||
)
|
||||
}
|
||||
override val sequenceIds: IntArray = delegate.mapToIntArray { it.msgHead.msgSeq }
|
||||
|
@ -16,10 +16,7 @@ import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.Mirai
|
||||
import net.mamoe.mirai.contact.ContactOrBot
|
||||
import net.mamoe.mirai.contact.Friend
|
||||
import net.mamoe.mirai.contact.Group
|
||||
import net.mamoe.mirai.contact.Member
|
||||
import net.mamoe.mirai.contact.*
|
||||
import net.mamoe.mirai.event.asyncFromEventOrNull
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
|
||||
@ -92,6 +89,23 @@ internal class MessageSourceToFriendImpl(
|
||||
override fun toJceData(): ImMsgBody.SourceMsg = jceData
|
||||
}
|
||||
|
||||
internal class MessageSourceToStrangerImpl(
|
||||
override val sequenceIds: IntArray,
|
||||
override val internalIds: IntArray,
|
||||
override val time: Int,
|
||||
override val originalMessage: MessageChain,
|
||||
override val sender: Bot,
|
||||
override val target: Stranger
|
||||
) : OnlineMessageSource.Outgoing.ToStranger(), MessageSourceInternal {
|
||||
override val bot: Bot
|
||||
get() = sender
|
||||
override val ids: IntArray
|
||||
get() = sequenceIds
|
||||
override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
|
||||
private val jceData by lazy { toJceDataImpl(subject) }
|
||||
override fun toJceData(): ImMsgBody.SourceMsg = jceData
|
||||
}
|
||||
|
||||
internal class MessageSourceToTempImpl(
|
||||
override val sequenceIds: IntArray,
|
||||
override val internalIds: IntArray,
|
||||
|
@ -44,6 +44,7 @@ import net.mamoe.mirai.internal.network.protocol.packet.login.WtLogin
|
||||
import net.mamoe.mirai.internal.utils.*
|
||||
import net.mamoe.mirai.network.*
|
||||
import net.mamoe.mirai.utils.*
|
||||
import network.protocol.packet.list.StrangerList
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
@ -292,6 +293,7 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
|
||||
|
||||
private var initFriendOk = false
|
||||
private var initGroupOk = false
|
||||
private var initStrangerOk = false
|
||||
|
||||
/**
|
||||
* Don't use concurrently
|
||||
@ -352,6 +354,28 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
|
||||
}.getOrThrow()
|
||||
}
|
||||
|
||||
suspend fun reloadStrangerList() {
|
||||
if (initStrangerOk) {
|
||||
return
|
||||
}
|
||||
var currentCount = 0
|
||||
logger.info { "Start loading stranger list..." }
|
||||
val response = StrangerList.GetStrangerList(bot.client)
|
||||
.sendAndExpect<StrangerList.GetStrangerList.Response>(timeoutMillis = 5000, retry = 2)
|
||||
|
||||
if (response.result == 0) {
|
||||
response.strangerList.forEach {
|
||||
// atomic
|
||||
bot.strangers.delegate.add(
|
||||
StrangerImpl(bot, bot.coroutineContext, StrangerInfoImpl(it.uin, it.nick.decodeToString()))
|
||||
).also { currentCount++ }
|
||||
}
|
||||
}
|
||||
logger.info { "Successfully loaded stranger list: $currentCount in total" }
|
||||
initStrangerOk = true
|
||||
|
||||
}
|
||||
|
||||
suspend fun reloadGroupList() {
|
||||
if (initGroupOk) {
|
||||
return
|
||||
@ -386,6 +410,9 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
|
||||
if (!initGroupOk) {
|
||||
bot.groups.delegate.removeAll { it.cancel(reInitCancellationException); true }
|
||||
}
|
||||
if (!initStrangerOk) {
|
||||
bot.strangers.delegate.removeAll { it.cancel(reInitCancellationException); true }
|
||||
}
|
||||
}
|
||||
|
||||
if (!pendingEnabled) {
|
||||
@ -396,6 +423,7 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
|
||||
coroutineScope {
|
||||
launch { reloadFriendList() }
|
||||
launch { reloadGroupList() }
|
||||
launch { reloadStrangerList() }
|
||||
}
|
||||
|
||||
this@QQAndroidBotNetworkHandler.launch(CoroutineName("Awaiting ConfigPushSvc.PushReq")) {
|
||||
|
@ -81,6 +81,7 @@ internal open class QQAndroidClient(
|
||||
val subAppId: Long
|
||||
get() = protocol.id
|
||||
|
||||
internal var strangerSeq: Int = 0
|
||||
internal val serverList: MutableList<Pair<String, Int>> = DefaultServerList.toMutableList()
|
||||
|
||||
val keys: Map<String, ByteArray> by lazy {
|
||||
|
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2019-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
|
||||
*/
|
||||
|
||||
@file:Suppress("unused", "SpellCheckingInspection")
|
||||
|
||||
package net.mamoe.mirai.internal.network.protocol.data.proto
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
||||
import net.mamoe.mirai.internal.utils.io.ProtoBuf
|
||||
|
||||
internal class FrdSysMsg {
|
||||
@Serializable
|
||||
internal class AddFrdSNInfo(
|
||||
@JvmField @ProtoNumber(1) val notSeeDynamic: Int = 0,
|
||||
@JvmField @ProtoNumber(2) val setSn: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class AddFriendVerifyInfo(
|
||||
@JvmField @ProtoNumber(1) val type: Int = 0,
|
||||
@JvmField @ProtoNumber(2) val url: String = "",
|
||||
@JvmField @ProtoNumber(3) val verifyInfo: String = ""
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class AddtionInfo(
|
||||
@JvmField @ProtoNumber(1) val poke: Int = 0,
|
||||
@JvmField @ProtoNumber(2) val format: Int = 0,
|
||||
@JvmField @ProtoNumber(3) val entityCategory: String = "",
|
||||
@JvmField @ProtoNumber(4) val entityName: String = "",
|
||||
@JvmField @ProtoNumber(5) val entityUrl: String = ""
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class DiscussInfo(
|
||||
@JvmField @ProtoNumber(1) val discussUin: Long = 0L,
|
||||
@JvmField @ProtoNumber(2) val discussName: String = "",
|
||||
@JvmField @ProtoNumber(3) val discussNick: String = ""
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class EimInfo(
|
||||
@JvmField @ProtoNumber(1) val eimFuin: Long = 0L,
|
||||
@JvmField @ProtoNumber(2) val eimId: String = "",
|
||||
@JvmField @ProtoNumber(3) val eimTelno: String = "",
|
||||
@JvmField @ProtoNumber(4) val groupId: Long = 0L
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class FriendHelloInfo(
|
||||
@JvmField @ProtoNumber(1) val sourceName: String = ""
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class FriendMiscInfo(
|
||||
@JvmField @ProtoNumber(1) val fromuinNick: String = ""
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class FriendSysMsg(
|
||||
@JvmField @ProtoNumber(11) val msgGroupExt: GroupInfoExt? = null,
|
||||
@JvmField @ProtoNumber(12) val msgIntiteInfo: InviteInfo? = null,
|
||||
@JvmField @ProtoNumber(13) val msgSchoolInfo: SchoolInfo? = null,
|
||||
@JvmField @ProtoNumber(100) val doubtFlag: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class GroupInfo(
|
||||
@JvmField @ProtoNumber(1) val groupUin: Long = 0L,
|
||||
@JvmField @ProtoNumber(2) val groupName: String = "",
|
||||
@JvmField @ProtoNumber(3) val groupNick: String = ""
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class GroupInfoExt(
|
||||
@JvmField @ProtoNumber(1) val notifyType: Int = 0,
|
||||
@JvmField @ProtoNumber(2) val groupCode: Long = 0L,
|
||||
@JvmField @ProtoNumber(3) val fromGroupadmlist: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class InviteInfo(
|
||||
@JvmField @ProtoNumber(1) val recommendUin: Long = 0L
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class MsgEncodeFlag(
|
||||
@JvmField @ProtoNumber(1) val isUtf8: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class SchoolInfo(
|
||||
@JvmField @ProtoNumber(1) val schoolId: String = "",
|
||||
@JvmField @ProtoNumber(2) val schoolName: String = ""
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class TongXunLuNickInfo(
|
||||
@JvmField @ProtoNumber(1) val fromuin: Long = 0L,
|
||||
@JvmField @ProtoNumber(2) val touin: Long = 0L,
|
||||
@JvmField @ProtoNumber(3) val tongxunluNickname: String = ""
|
||||
) : ProtoBuf
|
||||
}
|
@ -14,6 +14,94 @@ import kotlinx.serialization.protobuf.ProtoNumber
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.EMPTY_BYTE_ARRAY
|
||||
import net.mamoe.mirai.internal.utils.io.ProtoBuf
|
||||
|
||||
internal class Oidb0x5d4 : ProtoBuf {
|
||||
@Serializable
|
||||
internal class DelResult(
|
||||
@JvmField @ProtoNumber(1) val uin: Long = 0L,
|
||||
@JvmField @ProtoNumber(2) val res: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class ReqBody(
|
||||
@JvmField @ProtoNumber(1) val uinList: List<Long> = emptyList()
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class RspBody(
|
||||
@JvmField @ProtoNumber(1) val seq: Int = 0,
|
||||
@JvmField @ProtoNumber(2) val result: List<DelResult> = emptyList()
|
||||
) : ProtoBuf
|
||||
}
|
||||
|
||||
internal class Oidb0x5d2 : ProtoBuf {
|
||||
@Serializable
|
||||
internal class FriendInfo(
|
||||
@JvmField @ProtoNumber(1) val uin: Long = 0L,
|
||||
@JvmField @ProtoNumber(2) val gender: Int = 0,
|
||||
@JvmField @ProtoNumber(3) val age: Int = 0,
|
||||
@JvmField @ProtoNumber(4) val group: Int = 0,
|
||||
@JvmField @ProtoNumber(5) val login: Int = 0,
|
||||
@JvmField @ProtoNumber(6) val remark: ByteArray = EMPTY_BYTE_ARRAY
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class FriendEntry(
|
||||
@JvmField @ProtoNumber(1) val uin: Long = 0L,
|
||||
@JvmField @ProtoNumber(2) val nick: ByteArray = EMPTY_BYTE_ARRAY
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class GroupInfo(
|
||||
@JvmField @ProtoNumber(1) val id: Int = 0,
|
||||
@JvmField @ProtoNumber(2) val name: ByteArray = EMPTY_BYTE_ARRAY
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class LoginInfo(
|
||||
@JvmField @ProtoNumber(1) val id: Int = 0,
|
||||
@JvmField @ProtoNumber(2) val name: ByteArray = EMPTY_BYTE_ARRAY
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class ReqBody(
|
||||
@JvmField @ProtoNumber(1) val subCmd: Int = 0,
|
||||
@JvmField @ProtoNumber(2) val reqGetList: ReqGetList? = null,
|
||||
@JvmField @ProtoNumber(3) val reqGetInfo: ReqGetInfo? = null
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class ReqGetInfo(
|
||||
@JvmField @ProtoNumber(1) val uinList: List<Long> = emptyList()
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class ReqGetList(
|
||||
@JvmField @ProtoNumber(1) val seq: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class RspBody(
|
||||
@JvmField @ProtoNumber(1) val subCmd: Int = 0,
|
||||
@JvmField @ProtoNumber(2) val rspGetList: RspGetList? = null,
|
||||
@JvmField @ProtoNumber(3) val rspGetInfo: RspGetInfo? = null
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class RspGetInfo(
|
||||
@JvmField @ProtoNumber(1) val groupInfo: List<GroupInfo> = emptyList(),
|
||||
@JvmField @ProtoNumber(2) val loginInfo: List<LoginInfo> = emptyList(),
|
||||
@JvmField @ProtoNumber(3) val time: Int = 0,
|
||||
@JvmField @ProtoNumber(4) val frdInfo: List<FriendInfo> = emptyList(),
|
||||
@JvmField @ProtoNumber(5) val frdDelete: List<Long> = emptyList()
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class RspGetList(
|
||||
@JvmField @ProtoNumber(1) val seq: Int = 0,
|
||||
@JvmField @ProtoNumber(2) val list: List<FriendEntry> = emptyList()
|
||||
) : ProtoBuf
|
||||
}
|
||||
|
||||
@Serializable
|
||||
internal class Oidb0x8a0 : ProtoBuf {
|
||||
@Serializable
|
||||
|
@ -28,6 +28,7 @@ import net.mamoe.mirai.internal.network.readUShortLVByteArray
|
||||
import net.mamoe.mirai.internal.utils.crypto.TEA
|
||||
import net.mamoe.mirai.internal.utils.crypto.adjustToPublicKey
|
||||
import net.mamoe.mirai.utils.*
|
||||
import network.protocol.packet.list.StrangerList
|
||||
|
||||
internal sealed class PacketFactory<TPacket : Packet?> {
|
||||
/**
|
||||
@ -149,7 +150,9 @@ internal object KnownPacketFactories {
|
||||
MultiMsg.ApplyUp,
|
||||
NewContact.SystemMsgNewFriend,
|
||||
NewContact.SystemMsgNewGroup,
|
||||
ProfileService.GroupMngReq
|
||||
ProfileService.GroupMngReq,
|
||||
StrangerList.GetStrangerList,
|
||||
StrangerList.DelStranger
|
||||
)
|
||||
|
||||
object IncomingFactories : List<IncomingPacketFactory<*>> by mutableListOf(
|
||||
|
@ -19,6 +19,8 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.io.core.discardExact
|
||||
import kotlinx.io.core.readUByte
|
||||
import kotlinx.io.core.readUShort
|
||||
import net.mamoe.mirai.Mirai
|
||||
import net.mamoe.mirai.contact.Group
|
||||
import net.mamoe.mirai.contact.MemberPermission
|
||||
@ -27,6 +29,7 @@ import net.mamoe.mirai.contact.appId
|
||||
import net.mamoe.mirai.data.MemberInfo
|
||||
import net.mamoe.mirai.event.AbstractEvent
|
||||
import net.mamoe.mirai.event.Event
|
||||
import net.mamoe.mirai.event.broadcast
|
||||
import net.mamoe.mirai.event.events.*
|
||||
import net.mamoe.mirai.internal.QQAndroidBot
|
||||
import net.mamoe.mirai.internal.contact.*
|
||||
@ -35,6 +38,7 @@ import net.mamoe.mirai.internal.message.toMessageChain
|
||||
import net.mamoe.mirai.internal.network.MultiPacket
|
||||
import net.mamoe.mirai.internal.network.Packet
|
||||
import net.mamoe.mirai.internal.network.QQAndroidClient
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.FrdSysMsg
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgSvc
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.SubMsgType0x7
|
||||
@ -49,6 +53,7 @@ import net.mamoe.mirai.internal.utils.*
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.loadAs
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.readProtoBuf
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.writeProtoBuf
|
||||
import net.mamoe.mirai.message.data.MessageSourceKind
|
||||
import net.mamoe.mirai.message.data.PlainText
|
||||
import net.mamoe.mirai.message.data.buildMessageChain
|
||||
import net.mamoe.mirai.utils.*
|
||||
@ -353,7 +358,8 @@ internal suspend fun MsgComm.Msg.transform(bot: QQAndroidBot): Packet? {
|
||||
}
|
||||
*/
|
||||
|
||||
166 -> {
|
||||
//167 单向好友
|
||||
166, 167 -> {
|
||||
if (msgHead.fromUin == bot.id) {
|
||||
loop@ while (true) {
|
||||
val instance = bot.client.getFriendSeq()
|
||||
@ -365,25 +371,40 @@ internal suspend fun MsgComm.Msg.transform(bot: QQAndroidBot): Packet? {
|
||||
}
|
||||
return null
|
||||
}
|
||||
val friend = bot.getFriend(msgHead.fromUin) ?: return null
|
||||
friend.checkIsFriendImpl()
|
||||
|
||||
if (!bot.firstLoginSucceed) {
|
||||
return null
|
||||
}
|
||||
friend.lastMessageSequence.loop {
|
||||
return if (friend.lastMessageSequence.compareAndSet(
|
||||
it,
|
||||
msgHead.msgSeq
|
||||
) && contentHead?.autoReply != 1
|
||||
) {
|
||||
FriendMessageEvent(
|
||||
friend,
|
||||
toMessageChain(bot, groupIdOrZero = 0, onlineSource = true),
|
||||
msgHead.msgTime
|
||||
)
|
||||
} else null
|
||||
}
|
||||
bot.getFriend(msgHead.fromUin)?.let { friend ->
|
||||
friend.checkIsFriendImpl()
|
||||
friend.lastMessageSequence.loop {
|
||||
return if (friend.lastMessageSequence.compareAndSet(
|
||||
it,
|
||||
msgHead.msgSeq
|
||||
) && contentHead?.autoReply != 1
|
||||
) {
|
||||
FriendMessageEvent(
|
||||
friend,
|
||||
toMessageChain(bot, groupIdOrZero = 0, onlineSource = true, MessageSourceKind.FRIEND),
|
||||
msgHead.msgTime
|
||||
)
|
||||
} else null
|
||||
}
|
||||
} ?: bot.getStranger(msgHead.fromUin)?.let { stranger ->
|
||||
stranger.checkIsImpl()
|
||||
stranger.lastMessageSequence.loop {
|
||||
return if (stranger.lastMessageSequence.compareAndSet(
|
||||
it,
|
||||
msgHead.msgSeq
|
||||
) && contentHead?.autoReply != 1
|
||||
) {
|
||||
StrangerMessageEvent(
|
||||
stranger,
|
||||
toMessageChain(bot, groupIdOrZero = 0, onlineSource = true, MessageSourceKind.STRANGER),
|
||||
msgHead.msgTime
|
||||
)
|
||||
} else null
|
||||
}
|
||||
} ?: return null
|
||||
}
|
||||
208 -> {
|
||||
// friend ptt
|
||||
@ -448,7 +469,7 @@ internal suspend fun MsgComm.Msg.transform(bot: QQAndroidBot): Packet? {
|
||||
bot,
|
||||
groupIdOrZero = 0,
|
||||
onlineSource = true,
|
||||
isTemp = true
|
||||
MessageSourceKind.TEMP
|
||||
),
|
||||
msgHead.msgTime
|
||||
)
|
||||
@ -468,12 +489,50 @@ internal suspend fun MsgComm.Msg.transform(bot: QQAndroidBot): Packet? {
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
732 -> {
|
||||
// unknown
|
||||
// 前 4 byte 是群号
|
||||
return null
|
||||
}
|
||||
//陌生人添加信息
|
||||
191 -> {
|
||||
var fromGroup = 0L
|
||||
var pbNick = ""
|
||||
msgBody.msgContent.read {
|
||||
readUByte()// version
|
||||
discardExact(readUByte().toInt())//skip
|
||||
readUShort()//source id
|
||||
readUShort()//SourceSubID
|
||||
discardExact(readUShort().toLong())//skip size
|
||||
if (readUShort().toInt() != 0) {//hasExtraInfo
|
||||
discardExact(readUShort().toInt())//mail address info, skip
|
||||
}
|
||||
discardExact(4 + readUShort().toInt())//skip
|
||||
for (i in 1..readUByte().toInt()) {//pb size
|
||||
val type = readUShort().toInt()
|
||||
val pbArray = ByteArray(readUShort().toInt() and 0xFF)
|
||||
readAvailable(pbArray)
|
||||
when (type) {
|
||||
1000 -> pbArray.loadAs(FrdSysMsg.GroupInfo.serializer()).let { fromGroup = it.groupUin }
|
||||
1002 -> pbArray.loadAs(FrdSysMsg.FriendMiscInfo.serializer()).let { pbNick = it.fromuinNick }
|
||||
else -> {
|
||||
}//ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
val nick = sequenceOf(msgHead.fromNick, msgHead.authNick, pbNick).filter { it.isNotEmpty() }.firstOrNull()
|
||||
?: return null
|
||||
val id = sequenceOf(msgHead.fromUin, msgHead.authUin).filter { it != 0L }.firstOrNull() ?: return null//对方QQ
|
||||
Mirai._lowLevelNewStranger(bot, StrangerInfoImpl(id, nick, fromGroup)).let {
|
||||
bot.getStranger(id)?.let { previous ->
|
||||
bot.strangers.remove(id)
|
||||
StrangerRelationChangeEvent.Deleted(previous).broadcast()
|
||||
}
|
||||
bot.strangers.delegate.add(it)
|
||||
|
||||
return StrangerAddEvent(it)
|
||||
}
|
||||
}
|
||||
// 732: 27 0B 60 E7 0C 01 3E 03 3F A2 5E 90 60 E2 00 01 44 71 47 90 00 00 02 58
|
||||
// 732: 27 0B 60 E7 11 00 40 08 07 20 E7 C1 AD B8 02 5A 36 08 B4 E7 E0 F0 09 1A 1A 08 9C D4 16 10 F7 D2 D8 F5 05 18 D0 E2 85 F4 06 20 00 28 00 30 B4 E7 E0 F0 09 2A 0E 08 00 12 0A 08 9C D4 16 10 00 18 01 20 00 30 00 38 00
|
||||
// 732: 27 0B 60 E7 11 00 33 08 07 20 E7 C1 AD B8 02 5A 29 08 EE 97 85 E9 01 1A 19 08 EE D6 16 10 FF F2 D8 F5 05 18 E9 E7 A3 05 20 00 28 00 30 EE 97 85 E9 01 2A 02 08 00 30 00 38 00
|
||||
|
@ -14,13 +14,11 @@ import kotlinx.io.core.toByteArray
|
||||
import net.mamoe.mirai.contact.Friend
|
||||
import net.mamoe.mirai.contact.Group
|
||||
import net.mamoe.mirai.contact.Member
|
||||
import net.mamoe.mirai.contact.Stranger
|
||||
import net.mamoe.mirai.internal.QQAndroidBot
|
||||
import net.mamoe.mirai.internal.contact.groupCode
|
||||
import net.mamoe.mirai.internal.contact.uin
|
||||
import net.mamoe.mirai.internal.message.MessageSourceToFriendImpl
|
||||
import net.mamoe.mirai.internal.message.MessageSourceToGroupImpl
|
||||
import net.mamoe.mirai.internal.message.MessageSourceToTempImpl
|
||||
import net.mamoe.mirai.internal.message.toRichTextElems
|
||||
import net.mamoe.mirai.internal.message.*
|
||||
import net.mamoe.mirai.internal.network.Packet
|
||||
import net.mamoe.mirai.internal.network.QQAndroidClient
|
||||
import net.mamoe.mirai.internal.network.QQAndroidClient.MessageSvcSyncData.PendingGroupMessageReceiptSyncId
|
||||
@ -137,6 +135,36 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
|
||||
return response
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送陌生人消息
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
internal inline fun createToStrangerImpl(
|
||||
client: QQAndroidClient,
|
||||
target: Stranger,
|
||||
message: MessageChain,
|
||||
source: MessageSourceToStrangerImpl
|
||||
): OutgoingPacket = buildOutgoingUniPacket(client) {
|
||||
///writeFully("0A 08 0A 06 08 89 FC A6 8C 0B 12 06 08 01 10 00 18 00 1A 1F 0A 1D 12 08 0A 06 0A 04 F0 9F 92 A9 12 11 AA 02 0E 88 01 00 9A 01 08 78 00 F8 01 00 C8 02 00 20 9B 7A 28 F4 CA 9B B8 03 32 34 08 92 C2 C4 F1 05 10 92 C2 C4 F1 05 18 E6 ED B9 C3 02 20 89 FE BE A4 06 28 89 84 F9 A2 06 48 DE 8C EA E5 0E 58 D9 BD BB A0 09 60 1D 68 92 C2 C4 F1 05 70 00 40 01".hexToBytes())
|
||||
|
||||
///return@buildOutgoingUniPacket
|
||||
writeProtoBuf(
|
||||
MsgSvc.PbSendMsgReq.serializer(), MsgSvc.PbSendMsgReq(
|
||||
routingHead = MsgSvc.RoutingHead(c2c = MsgSvc.C2C(toUin = target.uin)),
|
||||
contentHead = MsgComm.ContentHead(pkgNum = 1),
|
||||
msgBody = ImMsgBody.MsgBody(
|
||||
richText = ImMsgBody.RichText(
|
||||
elems = message.toRichTextElems(messageTarget = target, withGeneralFlags = true)
|
||||
)
|
||||
),
|
||||
msgSeq = source.sequenceIds.single(),
|
||||
msgRand = source.internalIds.single(),
|
||||
syncCookie = client.syncingController.syncCookie ?: byteArrayOf()
|
||||
// msgVia = 1
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送好友消息
|
||||
*/
|
||||
@ -348,6 +376,32 @@ internal inline fun MessageSvcPbSendMsg.createToTemp(
|
||||
)
|
||||
}
|
||||
|
||||
internal inline fun MessageSvcPbSendMsg.createToStranger(
|
||||
client: QQAndroidClient,
|
||||
stranger: Stranger,
|
||||
message: MessageChain,
|
||||
crossinline sourceCallback: (MessageSourceToStrangerImpl) -> Unit
|
||||
): OutgoingPacket {
|
||||
contract {
|
||||
callsInPlace(sourceCallback, InvocationKind.EXACTLY_ONCE)
|
||||
}
|
||||
val source = MessageSourceToStrangerImpl(
|
||||
internalIds = intArrayOf(Random.nextInt().absoluteValue),
|
||||
sender = client.bot,
|
||||
target = stranger,
|
||||
time = currentTimeSeconds().toInt(),
|
||||
sequenceIds = intArrayOf(client.atomicNextMessageSequenceId()),
|
||||
originalMessage = message
|
||||
)
|
||||
sourceCallback(source)
|
||||
return createToStrangerImpl(
|
||||
client,
|
||||
stranger,
|
||||
message,
|
||||
source
|
||||
)
|
||||
}
|
||||
|
||||
internal inline fun MessageSvcPbSendMsg.createToFriend(
|
||||
client: QQAndroidClient,
|
||||
qq: Friend,
|
||||
|
@ -35,6 +35,7 @@ import net.mamoe.mirai.internal.network.protocol.packet.IncomingPacketFactory
|
||||
import net.mamoe.mirai.internal.utils._miraiContentToString
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.loadAs
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.readProtoBuf
|
||||
import net.mamoe.mirai.message.data.MessageSourceKind
|
||||
import net.mamoe.mirai.utils.*
|
||||
|
||||
/**
|
||||
@ -106,7 +107,12 @@ internal object OnlinePushPbPushGroupMsg : IncomingPacketFactory<Packet?>("Onlin
|
||||
|
||||
if (isFromSelfAccount) {
|
||||
return GroupMessageSyncEvent(
|
||||
message = msgs.toMessageChain(bot, groupIdOrZero = group.id, onlineSource = true),
|
||||
message = msgs.toMessageChain(
|
||||
bot,
|
||||
groupIdOrZero = group.id,
|
||||
onlineSource = true,
|
||||
MessageSourceKind.GROUP
|
||||
),
|
||||
time = msgHead.msgTime,
|
||||
group = group,
|
||||
sender = sender,
|
||||
@ -119,7 +125,12 @@ internal object OnlinePushPbPushGroupMsg : IncomingPacketFactory<Packet?>("Onlin
|
||||
return GroupMessageEvent(
|
||||
senderName = name,
|
||||
sender = sender,
|
||||
message = msgs.toMessageChain(bot, groupIdOrZero = group.id, onlineSource = true),
|
||||
message = msgs.toMessageChain(
|
||||
bot,
|
||||
groupIdOrZero = group.id,
|
||||
onlineSource = true,
|
||||
MessageSourceKind.GROUP
|
||||
),
|
||||
permission = findMemberPermission(extraInfo?.flags ?: 0, sender, bot),
|
||||
time = msgHead.msgTime
|
||||
)
|
||||
|
@ -22,12 +22,9 @@ import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
||||
import net.mamoe.mirai.JavaFriendlyAPI
|
||||
import net.mamoe.mirai.Mirai
|
||||
import net.mamoe.mirai.contact.Friend
|
||||
import net.mamoe.mirai.contact.Member
|
||||
import net.mamoe.mirai.contact.NormalMember
|
||||
import net.mamoe.mirai.data.FriendInfo
|
||||
import net.mamoe.mirai.data.GroupHonorType
|
||||
import net.mamoe.mirai.contact.*
|
||||
import net.mamoe.mirai.data.FriendInfoImpl
|
||||
import net.mamoe.mirai.data.GroupHonorType
|
||||
import net.mamoe.mirai.event.events.*
|
||||
import net.mamoe.mirai.internal.QQAndroidBot
|
||||
import net.mamoe.mirai.internal.contact.*
|
||||
@ -38,11 +35,9 @@ import net.mamoe.mirai.internal.network.protocol.data.jce.MsgInfo
|
||||
import net.mamoe.mirai.internal.network.protocol.data.jce.MsgType0x210
|
||||
import net.mamoe.mirai.internal.network.protocol.data.jce.OnlinePushPack
|
||||
import net.mamoe.mirai.internal.network.protocol.data.jce.RequestPacket
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.Submsgtype0x115
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.Submsgtype0x122
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.*
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.Submsgtype0x27.SubMsgType0x27.*
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.Submsgtype0x44.Submsgtype0x44
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.Submsgtype0xb3
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.TroopTips0x857
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.IncomingPacketFactory
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
|
||||
@ -488,7 +483,10 @@ internal object Transformers528 : Map<Long, Lambda528> by mapOf(
|
||||
)
|
||||
)
|
||||
bot.friends.delegate.add(new)
|
||||
return@lambda528 sequenceOf(FriendAddEvent(new))
|
||||
return@lambda528 bot.getStranger(new.id)?.let {
|
||||
bot.strangers.remove(new.id)
|
||||
sequenceOf(StrangerRelationChangeEvent.Friended(it, new), FriendAddEvent(new))
|
||||
} ?: sequenceOf(FriendAddEvent(new))
|
||||
},
|
||||
0xE2L to lambda528 { _ ->
|
||||
// TODO: unknown. maybe messages.
|
||||
@ -532,38 +530,66 @@ internal object Transformers528 : Map<Long, Lambda528> by mapOf(
|
||||
return@lambda528 emptySequence()
|
||||
},
|
||||
//戳一戳信息等
|
||||
0x122L to lambda528 { bot, _ ->
|
||||
0x122L to lambda528 { bot, msgInfo ->
|
||||
val body = vProtobuf.loadAs(Submsgtype0x122.Submsgtype0x122.MsgBody.serializer())
|
||||
when (body.templId) {
|
||||
//戳一戳
|
||||
1132L, 1133L, 1134L, 1135L, 1136L, 10043L -> {
|
||||
//预置数据,服务器将不会提供己方已知消息
|
||||
var from: Friend = bot.asFriend
|
||||
var from: User? = null
|
||||
var action = ""
|
||||
var target: Friend = bot.asFriend
|
||||
var target: User? = null
|
||||
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()) ?: return@lambda528 emptySequence()
|
||||
"uin_str2" -> target = bot.getFriend(value.toLong()) ?: return@lambda528 emptySequence()
|
||||
"uin_str1" -> from = bot.getFriend(value.toLong()) ?: bot.getStranger(value.toLong())
|
||||
?: return@lambda528 emptySequence()
|
||||
"uin_str2" -> target = bot.getFriend(value.toLong()) ?: bot.getStranger(value.toLong())
|
||||
?: return@lambda528 emptySequence()
|
||||
"suffix_str" -> suffix = value
|
||||
}
|
||||
}
|
||||
|
||||
return@lambda528 sequenceOf(
|
||||
if (target.id == bot.id) {
|
||||
if (from.id == bot.id)
|
||||
BotNudgedEvent.InPrivateSession.ByBot(target, action, suffix)
|
||||
else
|
||||
BotNudgedEvent.InPrivateSession.ByFriend(target, action, suffix)
|
||||
} else {
|
||||
if (from.id == bot.id)
|
||||
FriendNudgedEvent.NudgedByBot(action, suffix, target)
|
||||
else
|
||||
FriendNudgedEvent.NudgedByHimself(action, suffix, target)
|
||||
val subject: User = bot.getFriend(msgInfo.lFromUin) ?: bot.getStranger(msgInfo.lFromUin)
|
||||
?: return@lambda528 emptySequence()
|
||||
//机器人自己戳自己
|
||||
if ((target == null && from == null) || (target?.id == from?.id && from?.id == bot.id)) {
|
||||
sequenceOf(BotNudgedEvent.InPrivateSession.ByBot(subject, action, suffix))
|
||||
} else sequenceOf(
|
||||
when (subject) {
|
||||
is Friend -> when {
|
||||
//机器人自身为目标
|
||||
target == null || target!!.id == bot.id -> BotNudgedEvent.InPrivateSession.ByFriend(
|
||||
subject,
|
||||
action,
|
||||
suffix
|
||||
)
|
||||
//机器人自身为发起者
|
||||
from == null || from!!.id == bot.id -> FriendNudgedEvent.NudgedByBot(
|
||||
subject,
|
||||
action,
|
||||
suffix
|
||||
)
|
||||
else -> FriendNudgedEvent.NudgedByHimself(subject, action, suffix)
|
||||
}
|
||||
is Stranger -> when {
|
||||
//机器人自身为目标
|
||||
target == null || target!!.id == bot.id -> BotNudgedEvent.InPrivateSession.ByStranger(
|
||||
subject,
|
||||
action,
|
||||
suffix
|
||||
)
|
||||
//机器人自身为发起者
|
||||
from == null || from!!.id == bot.id -> StrangerNudgedEvent.NudgedByBot(
|
||||
subject,
|
||||
action,
|
||||
suffix
|
||||
)
|
||||
else -> StrangerNudgedEvent.NudgedByHimself(subject, action, suffix)
|
||||
}
|
||||
else -> error("Internal Error: Unable to find nudge type")
|
||||
}
|
||||
)
|
||||
}
|
||||
@ -602,6 +628,7 @@ internal object Transformers528 : Map<Long, Lambda528> by mapOf(
|
||||
|
||||
fun DelFriend.transform(bot: QQAndroidBot): Sequence<Packet> {
|
||||
return this.uint64Uins.asSequence().mapNotNull {
|
||||
|
||||
val friend = bot.getFriend(it) ?: return@mapNotNull null
|
||||
if (bot.friends.delegate.remove(friend)) {
|
||||
FriendDeleteEvent(friend)
|
||||
@ -727,7 +754,6 @@ internal object Transformers528 : Map<Long, Lambda528> by mapOf(
|
||||
val from = info.nick
|
||||
when (info) {
|
||||
is FriendInfoImpl -> info.nick = to
|
||||
is MemberInfoImpl -> info.nick = to
|
||||
else -> {
|
||||
bot.network.logger.debug {
|
||||
"Unknown how to update nick for $info"
|
||||
|
@ -0,0 +1,106 @@
|
||||
package network.protocol.packet.list;
|
||||
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import net.mamoe.mirai.contact.Stranger
|
||||
import net.mamoe.mirai.event.broadcast
|
||||
import net.mamoe.mirai.event.events.StrangerRelationChangeEvent
|
||||
import net.mamoe.mirai.internal.QQAndroidBot
|
||||
import net.mamoe.mirai.internal.network.Packet
|
||||
import net.mamoe.mirai.internal.network.QQAndroidClient
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.Oidb0x5d2
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.Oidb0x5d4
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.OidbSso
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacketFactory
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.buildOutgoingUniPacket
|
||||
import net.mamoe.mirai.internal.utils._miraiContentToString
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.loadAs
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.readProtoBuf
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.toByteArray
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.writeProtoBuf
|
||||
|
||||
internal class StrangerList {
|
||||
object GetStrangerList : OutgoingPacketFactory<GetStrangerList.Response>("OidbSvc.0x5d2_0") {
|
||||
|
||||
class Response(val result: Int, val strangerList: List<Oidb0x5d2.FriendEntry>) : Packet
|
||||
|
||||
operator fun invoke(
|
||||
client: QQAndroidClient,
|
||||
): OutgoingPacket {
|
||||
return buildOutgoingUniPacket(client) {
|
||||
writeProtoBuf(
|
||||
OidbSso.OIDBSSOPkg.serializer(),
|
||||
OidbSso.OIDBSSOPkg(
|
||||
command = 1490,
|
||||
serviceType = 0,
|
||||
bodybuffer = Oidb0x5d2.ReqBody(
|
||||
subCmd = 1,
|
||||
reqGetList = Oidb0x5d2.ReqGetList(
|
||||
seq = client.strangerSeq
|
||||
)
|
||||
).toByteArray(Oidb0x5d2.ReqBody.serializer())
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
|
||||
readProtoBuf(OidbSso.OIDBSSOPkg.serializer()).let { pkg ->
|
||||
if (pkg.result == 0) {
|
||||
pkg.bodybuffer.loadAs(Oidb0x5d2.RspBody.serializer()).also {
|
||||
pkg._miraiContentToString()
|
||||
}.rspGetList!!.let {
|
||||
bot.client.strangerSeq = it.seq
|
||||
return Response(pkg.result, it.list)
|
||||
}
|
||||
}
|
||||
return Response(pkg.result, emptyList())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object DelStranger : OutgoingPacketFactory<DelStranger.Response>("OidbSvc.0x5d4_0") {
|
||||
class Response(val result: Int) : Packet {
|
||||
val isSuccess = result == 0
|
||||
override fun toString(): String = "DelStranger.Response(success=${result == 0})"
|
||||
}
|
||||
|
||||
operator fun invoke(
|
||||
client: QQAndroidClient,
|
||||
stranger: Stranger
|
||||
): OutgoingPacket {
|
||||
return buildOutgoingUniPacket(client) {
|
||||
writeProtoBuf(
|
||||
OidbSso.OIDBSSOPkg.serializer(),
|
||||
OidbSso.OIDBSSOPkg(
|
||||
command = 1492,
|
||||
serviceType = 0,
|
||||
result = 0,
|
||||
bodybuffer = Oidb0x5d4.ReqBody(
|
||||
uinList = listOf(stranger.id)
|
||||
).toByteArray(Oidb0x5d4.ReqBody.serializer())
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
|
||||
readProtoBuf(OidbSso.OIDBSSOPkg.serializer()).let { pkg ->
|
||||
if (pkg.result == 0) {
|
||||
pkg.bodybuffer.loadAs(Oidb0x5d4.RspBody.serializer()).also {
|
||||
pkg._miraiContentToString()
|
||||
}.result.forEach { delResult ->
|
||||
bot.getStranger(delResult.uin)?.let {
|
||||
bot.strangers.remove(delResult.uin)
|
||||
StrangerRelationChangeEvent.Deleted(it).broadcast()
|
||||
}
|
||||
}
|
||||
}
|
||||
return Response(pkg.result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user