Implement MessagePreSendEvent and MessagePostSendEvent.

Deprecate `MessageSendEvent`
Fix #339
This commit is contained in:
Him188 2020-06-14 18:43:21 +08:00
parent 4c79d4cd18
commit 6f0853e6e4
11 changed files with 623 additions and 271 deletions

View File

@ -33,6 +33,7 @@ import net.mamoe.mirai.event.events.ImageUploadEvent
import net.mamoe.mirai.message.MessageReceipt import net.mamoe.mirai.message.MessageReceipt
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.OfflineFriendImage
import net.mamoe.mirai.message.data.isContentNotEmpty import net.mamoe.mirai.message.data.isContentNotEmpty
import net.mamoe.mirai.qqandroid.QQAndroidBot import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.network.highway.postImage import net.mamoe.mirai.qqandroid.network.highway.postImage
@ -87,7 +88,11 @@ internal class FriendImpl(
@Suppress("DuplicatedCode") @Suppress("DuplicatedCode")
override suspend fun sendMessage(message: Message): MessageReceipt<Friend> { override suspend fun sendMessage(message: Message): MessageReceipt<Friend> {
require(message.isContentNotEmpty()) { "message is empty" } require(message.isContentNotEmpty()) { "message is empty" }
return sendMessageImpl(this, message).also { return sendMessageImpl(
message,
friendReceiptConstructor = { MessageReceipt(it, this, null) },
tReceiptConstructor = { MessageReceipt(it, this, null) }
).also {
logMessageSent(message) logMessageSent(message)
} }
} }
@ -101,64 +106,63 @@ internal class FriendImpl(
if (BeforeImageUploadEvent(this, image).broadcast().isCancelled) { if (BeforeImageUploadEvent(this, image).broadcast().isCancelled) {
throw EventCancelledException("cancelled by BeforeImageUploadEvent.ToGroup") throw EventCancelledException("cancelled by BeforeImageUploadEvent.ToGroup")
} }
bot.network.run { val response = bot.network.run {
val response = LongConn.OffPicUp( LongConn.OffPicUp(
bot.client, Cmd0x352.TryUpImgReq( bot.client, Cmd0x352.TryUpImgReq(
srcUin = bot.id.toInt(), srcUin = bot.id.toInt(),
dstUin = id.toInt(), dstUin = id.toInt(),
fileId = 0, fileId = 0,
fileMd5 = @Suppress("INVISIBLE_MEMBER") image.md5, fileMd5 = image.md5,
fileSize = @Suppress("INVISIBLE_MEMBER") fileSize = image.input.size.toInt(),
image.input.size.toInt(), fileName = image.md5.toUHexString("") + "." + ExternalImage.defaultFormatName,
fileName = @Suppress("INVISIBLE_MEMBER") image.md5.toUHexString("") + "." + ExternalImage.defaultFormatName,
imgOriginal = 1 imgOriginal = 1
) )
).sendAndExpect<LongConn.OffPicUp.Response>() ).sendAndExpect<LongConn.OffPicUp.Response>()
}
@Suppress("UNCHECKED_CAST", "DEPRECATION", "INVISIBLE_MEMBER") @Suppress("UNCHECKED_CAST", "DEPRECATION")
return when (response) { when (response) {
is LongConn.OffPicUp.Response.FileExists -> net.mamoe.mirai.message.data.OfflineFriendImage(response.resourceId) is LongConn.OffPicUp.Response.FileExists -> OfflineFriendImage(response.resourceId)
.also { .also {
ImageUploadEvent.Succeed(this@FriendImpl, image, it).broadcast() ImageUploadEvent.Succeed(this@FriendImpl, image, it).broadcast()
}
is LongConn.OffPicUp.Response.RequireUpload -> {
bot.network.logger.verbose {
"[Http] Uploading friend image, size=${image.input.size.sizeToString()}"
}
val time = measureTime {
MiraiPlatformUtils.Http.postImage(
"0x6ff0070",
bot.id,
null,
imageInput = image.input,
uKeyHex = response.uKey.toUHexString("")
)
}
bot.network.logger.verbose {
"[Http] Uploading friend image: succeed at ${(image.input.size.toDouble() / 1024 / time.inSeconds).roundToInt()} KiB/s"
}
/*
HighwayHelper.uploadImageToServers(
bot,
response.serverIp.zip(response.serverPort),
response.uKey,
image,
kind = "friend",
commandId = 1
)*/
// 为什么不能 ??
return net.mamoe.mirai.message.data.OfflineFriendImage(response.resourceId).also {
ImageUploadEvent.Succeed(this@FriendImpl, image, it).broadcast()
}
} }
is LongConn.OffPicUp.Response.Failed -> { is LongConn.OffPicUp.Response.RequireUpload -> {
ImageUploadEvent.Failed(this@FriendImpl, image, -1, response.message).broadcast() bot.network.logger.verbose {
error(response.message) "[Http] Uploading friend image, size=${image.input.size.sizeToString()}"
} }
val time = measureTime {
MiraiPlatformUtils.Http.postImage(
"0x6ff0070",
bot.id,
null,
imageInput = image.input,
uKeyHex = response.uKey.toUHexString("")
)
}
bot.network.logger.verbose {
"[Http] Uploading friend image: succeed at ${(image.input.size.toDouble() / 1024 / time.inSeconds).roundToInt()} KiB/s"
}
/*
HighwayHelper.uploadImageToServers(
bot,
response.serverIp.zip(response.serverPort),
response.uKey,
image,
kind = "friend",
commandId = 1
)*/
// 为什么不能 ??
OfflineFriendImage(response.resourceId).also {
ImageUploadEvent.Succeed(this@FriendImpl, image, it).broadcast()
}
}
is LongConn.OffPicUp.Response.Failed -> {
ImageUploadEvent.Failed(this@FriendImpl, image, -1, response.message).broadcast()
error(response.message)
} }
} }
} finally { } finally {

View File

@ -22,7 +22,6 @@ import net.mamoe.mirai.data.GroupInfo
import net.mamoe.mirai.data.MemberInfo import net.mamoe.mirai.data.MemberInfo
import net.mamoe.mirai.event.broadcast import net.mamoe.mirai.event.broadcast
import net.mamoe.mirai.event.events.* import net.mamoe.mirai.event.events.*
import net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent
import net.mamoe.mirai.message.MessageReceipt import net.mamoe.mirai.message.MessageReceipt
import net.mamoe.mirai.message.data.* import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.qqandroid.QQAndroidBot import net.mamoe.mirai.qqandroid.QQAndroidBot
@ -33,6 +32,7 @@ import net.mamoe.mirai.qqandroid.network.highway.HighwayHelper
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.TroopManagement 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.receive.MessageSvcPbSendMsg import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvcPbSendMsg
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.createToGroup
import net.mamoe.mirai.qqandroid.network.protocol.packet.list.ProfileService import net.mamoe.mirai.qqandroid.network.protocol.packet.list.ProfileService
import net.mamoe.mirai.qqandroid.utils.estimateLength import net.mamoe.mirai.qqandroid.utils.estimateLength
import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.*
@ -304,94 +304,92 @@ internal class GroupImpl(
check(message.nodeList.size < 200) { check(message.nodeList.size < 200) {
throw MessageTooLargeException( throw MessageTooLargeException(
this, message, message, this, message, message,
"ForwardMessage allows up to 200 nodes, but found ${message.nodeList.size}") "ForwardMessage allows up to 200 nodes, but found ${message.nodeList.size}"
)
} }
return bot.lowLevelSendGroupLongOrForwardMessage(this.id, message.nodeList, false, message) return bot.lowLevelSendGroupLongOrForwardMessage(this.id, message.nodeList, false, message)
} }
val msg: MessageChain val msg: MessageChain = if (message !is LongMessage && message !is ForwardMessageInternal) {
val chain = kotlin.runCatching {
GroupMessagePreSendEvent(this, message).broadcast()
}.onSuccess {
check(!it.isCancelled) {
throw EventCancelledException("cancelled by GroupMessagePreSendEvent")
}
}.getOrElse {
throw EventCancelledException("exception thrown when broadcasting GroupMessagePreSendEvent", it)
}.message.asMessageChain()
if (message !is LongMessage && message !is ForwardMessageInternal) { val length = chain.estimateLength(703) // 阈值为700左右限制到3的倍数
val event = GroupMessageSendEvent(this, message.asMessageChain()).broadcast()
if (event.isCancelled) {
throw EventCancelledException("cancelled by GroupMessageSendEvent")
}
val length = event.message.estimateLength(703) // 阈值为700左右限制到3的倍数
var imageCnt = 0 // 通过下方逻辑短路延迟计算 var imageCnt = 0 // 通过下方逻辑短路延迟计算
if (length > 5000 || event.message.count { it is Image }.apply { imageCnt = this } > 50) { if (length > 5000 || chain.count { it is Image }.apply { imageCnt = this } > 50) {
throw MessageTooLargeException( throw MessageTooLargeException(
this, this, message, chain,
message, "message(${chain.joinToString("", limit = 10)}) is too large. Allow up to 50 images or 5000 chars"
event.message,
"message(${event.message.joinToString(
"",
limit = 10
)}) is too large. Allow up to 50 images or 5000 chars"
) )
} }
if (length > 702 || imageCnt > 2) { if (length > 702 || imageCnt > 2) {
return bot.lowLevelSendGroupLongOrForwardMessage(this.id, return bot.lowLevelSendGroupLongOrForwardMessage(
listOf(ForwardMessage.Node( this.id,
senderId = bot.id, listOf(
time = currentTimeSeconds.toInt(), ForwardMessage.Node(
message = event.message, senderId = bot.id,
senderName = bot.nick) time = currentTimeSeconds.toInt(),
message = chain,
senderName = bot.nick
)
), ),
true, null) true, null
)
} }
chain
} else message.asMessageChain()
msg = event.message
} else msg = message.asMessageChain()
msg.firstIsInstanceOrNull<QuoteReply>()?.source?.ensureSequenceIdAvailable() msg.firstIsInstanceOrNull<QuoteReply>()?.source?.ensureSequenceIdAvailable()
lateinit var source: MessageSourceToGroupImpl
bot.network.run { val result = bot.network.runCatching {
val response: MessageSvcPbSendMsg.Response = MessageSvcPbSendMsg.createToGroup( val source: MessageSourceToGroupImpl
MessageSvcPbSendMsg.createToGroup(
bot.client, bot.client,
this@GroupImpl, this@GroupImpl,
msg, msg,
isForward isForward
) { ) {
source = it source = it
}.sendAndExpect() }.sendAndExpect<MessageSvcPbSendMsg.Response>().let {
if (response is MessageSvcPbSendMsg.Response.Failed) { check(it is MessageSvcPbSendMsg.Response.SUCCESS) {
when (response.resultType) { "Send temp message failed: $it"
120 -> throw BotIsBeingMutedException(this@GroupImpl)
34 -> {
kotlin.runCatching { // allow retry once
return bot.lowLevelSendGroupLongOrForwardMessage(
id, listOf(
ForwardMessage.Node(
senderId = bot.id,
time = currentTimeSeconds.toInt(),
message = msg,
senderName = bot.nick
)
), true, null)
}.getOrElse {
throw IllegalStateException("internal error: send message failed(34)", it)
}
}
else -> error("send message failed: $response")
} }
} }
}
try { try {
source.ensureSequenceIdAvailable() source.ensureSequenceIdAvailable()
} catch (e: Exception) { } catch (e: Exception) {
bot.network.logger.warning { bot.network.logger.warning {
"Timeout awaiting sequenceId for group message(${message.contentToString() "Timeout awaiting sequenceId for group message(${message.contentToString()
.take(10)}). Some features may not work properly" .take(10)}). Some features may not work properly"
}
bot.network.logger.warning(e)
} }
bot.network.logger.warning(e)
MessageReceipt(source, this@GroupImpl, botAsMember)
} }
return MessageReceipt(source, this, botAsMember) result.fold(
onSuccess = {
GroupMessagePostSendEvent(this, msg, null, it)
},
onFailure = {
GroupMessagePostSendEvent(this, msg, it, null)
}
).broadcast()
return result.getOrThrow()
} }
@Suppress("DEPRECATION") @Suppress("DEPRECATION")

View File

@ -28,6 +28,7 @@ import net.mamoe.mirai.qqandroid.message.firstIsInstanceOrNull
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.StTroopMemberInfo import net.mamoe.mirai.qqandroid.network.protocol.data.jce.StTroopMemberInfo
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.TroopManagement import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.TroopManagement
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvcPbSendMsg import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvcPbSendMsg
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.createToTemp
import net.mamoe.mirai.utils.ExternalImage import net.mamoe.mirai.utils.ExternalImage
import net.mamoe.mirai.utils.currentTimeSeconds import net.mamoe.mirai.utils.currentTimeSeconds
import net.mamoe.mirai.utils.getValue import net.mamoe.mirai.utils.getValue
@ -54,34 +55,59 @@ internal class MemberImpl constructor(
override val id: Long = qq.id override val id: Long = qq.id
override val nick: String = qq.nick override val nick: String = qq.nick
@Suppress("UNCHECKED_CAST")
@JvmSynthetic @JvmSynthetic
override suspend fun sendMessage(message: Message): MessageReceipt<Member> { override suspend fun sendMessage(message: Message): MessageReceipt<Member> {
require(message.isContentNotEmpty()) { "message is empty" } require(message.isContentNotEmpty()) { "message is empty" }
return (this.asFriendOrNull()?.sendMessageImpl(this, message) ?: sendMessageImpl(message)) val asFriend = this.asFriendOrNull()
.also { logMessageSent(message) }
return (asFriend?.sendMessageImpl(
message,
friendReceiptConstructor = { MessageReceipt(it, asFriend, null) },
tReceiptConstructor = { MessageReceipt(it, this, null) }
) ?: sendMessageImpl(message)).also { logMessageSent(message) }
} }
private suspend fun sendMessageImpl(message: Message): MessageReceipt<Member> { private suspend fun sendMessageImpl(message: Message): MessageReceipt<Member> {
val event = MessageSendEvent.TempMessageSendEvent(this, message.asMessageChain()).broadcast() val chain = kotlin.runCatching {
if (event.isCancelled) { TempMessagePreSendEvent(this, message).broadcast()
throw EventCancelledException("cancelled by TempMessageSendEvent") }.onSuccess {
} check(!it.isCancelled) {
event.message.firstIsInstanceOrNull<QuoteReply>()?.source?.ensureSequenceIdAvailable() throw EventCancelledException("cancelled by TempMessagePreSendEvent")
}
}.getOrElse {
throw EventCancelledException("exception thrown when broadcasting TempMessagePreSendEvent", it)
}.message.asMessageChain()
lateinit var source: MessageSourceToTempImpl chain.firstIsInstanceOrNull<QuoteReply>()?.source?.ensureSequenceIdAvailable()
bot.network.run {
check( val result = bot.network.runCatching {
MessageSvcPbSendMsg.createToTemp( val source: MessageSourceToTempImpl
bot.client, MessageSvcPbSendMsg.createToTemp(
this@MemberImpl, bot.client,
message.asMessageChain() this@MemberImpl,
) { chain
source = it ) {
}.sendAndExpect<MessageSvcPbSendMsg.Response>() is MessageSvcPbSendMsg.Response.SUCCESS source = it
) { "send message failed" } }.sendAndExpect<MessageSvcPbSendMsg.Response>().let {
check(it is MessageSvcPbSendMsg.Response.SUCCESS) {
"Send temp message failed: $it"
}
}
MessageReceipt(source, this@MemberImpl, null)
} }
return MessageReceipt(source, this, null)
result.fold(
onSuccess = {
TempMessagePostSendEvent(this, chain, null, it)
},
onFailure = {
TempMessagePostSendEvent(this, chain, it, null)
}
).broadcast()
return result.getOrThrow()
} }
@JvmSynthetic @JvmSynthetic

View File

@ -12,40 +12,72 @@ package net.mamoe.mirai.qqandroid.contact
import net.mamoe.mirai.contact.Contact import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.contact.Friend import net.mamoe.mirai.contact.Friend
import net.mamoe.mirai.contact.User
import net.mamoe.mirai.event.broadcast import net.mamoe.mirai.event.broadcast
import net.mamoe.mirai.event.events.EventCancelledException import net.mamoe.mirai.event.events.EventCancelledException
import net.mamoe.mirai.event.events.MessageSendEvent import net.mamoe.mirai.event.events.FriendMessagePostSendEvent
import net.mamoe.mirai.event.events.FriendMessagePreSendEvent
import net.mamoe.mirai.message.* import net.mamoe.mirai.message.*
import net.mamoe.mirai.message.data.Message import net.mamoe.mirai.message.data.Message
import net.mamoe.mirai.message.data.QuoteReply import net.mamoe.mirai.message.data.QuoteReply
import net.mamoe.mirai.message.data.asMessageChain import net.mamoe.mirai.message.data.asMessageChain
import net.mamoe.mirai.message.data.firstIsInstanceOrNull
import net.mamoe.mirai.qqandroid.asQQAndroidBot import net.mamoe.mirai.qqandroid.asQQAndroidBot
import net.mamoe.mirai.qqandroid.message.MessageSourceToFriendImpl import net.mamoe.mirai.qqandroid.message.MessageSourceToFriendImpl
import net.mamoe.mirai.qqandroid.message.ensureSequenceIdAvailable import net.mamoe.mirai.qqandroid.message.ensureSequenceIdAvailable
import net.mamoe.mirai.qqandroid.message.firstIsInstanceOrNull
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvcPbSendMsg import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvcPbSendMsg
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.createToFriend
import net.mamoe.mirai.utils.verbose import net.mamoe.mirai.utils.verbose
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
internal suspend fun <T : Contact> Friend.sendMessageImpl(generic: T, message: Message): MessageReceipt<T> { internal suspend fun <T : User> Friend.sendMessageImpl(
val event = MessageSendEvent.FriendMessageSendEvent(this, message.asMessageChain()).broadcast() message: Message,
if (event.isCancelled) { friendReceiptConstructor: (MessageSourceToFriendImpl) -> MessageReceipt<Friend>,
throw EventCancelledException("cancelled by FriendMessageSendEvent") tReceiptConstructor: (MessageSourceToFriendImpl) -> MessageReceipt<T>
} ): MessageReceipt<T> {
event.message.firstIsInstanceOrNull<QuoteReply>()?.source?.ensureSequenceIdAvailable() contract { callsInPlace(friendReceiptConstructor, InvocationKind.EXACTLY_ONCE) }
lateinit var source: MessageSourceToFriendImpl
val bot = bot.asQQAndroidBot() val bot = bot.asQQAndroidBot()
bot.network.run {
check( val chain = kotlin.runCatching {
MessageSvcPbSendMsg.createToFriend( FriendMessagePreSendEvent(this, message).broadcast()
bot.asQQAndroidBot().client, }.onSuccess {
this@sendMessageImpl, check(!it.isCancelled) {
event.message throw EventCancelledException("cancelled by FriendMessagePreSendEvent")
) { }
source = it }.getOrElse {
}.sendAndExpect<MessageSvcPbSendMsg.Response>() is MessageSvcPbSendMsg.Response.SUCCESS throw EventCancelledException("exception thrown when broadcasting FriendMessagePreSendEvent", it)
) { "send message failed" } }.message.asMessageChain()
chain.firstIsInstanceOrNull<QuoteReply>()?.source?.ensureSequenceIdAvailable()
lateinit var source: MessageSourceToFriendImpl
val result = bot.network.runCatching {
MessageSvcPbSendMsg.createToFriend(
bot.client,
this@sendMessageImpl,
chain
) {
source = it
}.sendAndExpect<MessageSvcPbSendMsg.Response>().let {
check(it is MessageSvcPbSendMsg.Response.SUCCESS) {
"Send temp message failed: $it"
}
}
friendReceiptConstructor(source)
} }
return MessageReceipt(source, generic, null)
result.fold(
onSuccess = {
FriendMessagePostSendEvent(this, chain, null, it)
},
onFailure = {
FriendMessagePostSendEvent(this, chain, it, null)
}
).broadcast()
result.getOrThrow()
return tReceiptConstructor(source)
} }
internal fun Contact.logMessageSent(message: Message) { internal fun Contact.logMessageSent(message: Message) {

View File

@ -34,6 +34,8 @@ import net.mamoe.mirai.qqandroid.utils.io.serialization.readProtoBuf
import net.mamoe.mirai.qqandroid.utils.io.serialization.toByteArray import net.mamoe.mirai.qqandroid.utils.io.serialization.toByteArray
import net.mamoe.mirai.qqandroid.utils.io.serialization.writeProtoBuf import net.mamoe.mirai.qqandroid.utils.io.serialization.writeProtoBuf
import net.mamoe.mirai.utils.currentTimeSeconds import net.mamoe.mirai.utils.currentTimeSeconds
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.math.absoluteValue import kotlin.math.absoluteValue
import kotlin.random.Random import kotlin.random.Random
@ -52,34 +54,11 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
} }
} }
inline fun createToFriend(
client: QQAndroidClient,
qq: Friend,
message: MessageChain,
crossinline sourceCallback: (MessageSourceToFriendImpl) -> Unit
): OutgoingPacket {
val rand = Random.nextInt().absoluteValue
val source = MessageSourceToFriendImpl(
internalId = rand,
sender = client.bot,
target = qq,
time = currentTimeSeconds.toInt(),
sequenceId = client.nextFriendSeq(),
originalMessage = message
)
sourceCallback(source)
return createToFriend(
client,
qq.id,
message,
source)
}
/** /**
* 发送好友消息 * 发送好友消息
*/ */
@Suppress("FunctionName") @Suppress("FunctionName")
private fun createToFriend( internal fun createToFriendImpl(
client: QQAndroidClient, client: QQAndroidClient,
toUin: Long, toUin: Long,
message: MessageChain, message: MessageChain,
@ -106,33 +85,10 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
} }
inline fun createToTemp(
client: QQAndroidClient,
member: Member,
message: MessageChain,
sourceCallback: (MessageSourceToTempImpl) -> Unit
): OutgoingPacket {
val source = MessageSourceToTempImpl(
internalId = Random.nextInt().absoluteValue,
sender = client.bot,
target = member,
time = currentTimeSeconds.toInt(),
sequenceId = client.atomicNextMessageSequenceId(),
originalMessage = message
)
sourceCallback(source)
return createToTemp(
client,
(member.group as GroupImpl).uin,
member.id,
message,
source)
}
/** /**
* 发送临时消息 * 发送临时消息
*/ */
private fun createToTemp( internal fun createToTempImpl(
client: QQAndroidClient, client: QQAndroidClient,
groupUin: Long, groupUin: Long,
toUin: Long, toUin: Long,
@ -158,37 +114,11 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
} }
inline fun createToGroup(
client: QQAndroidClient,
group: Group,
message: MessageChain,
isForward: Boolean,
sourceCallback: (MessageSourceToGroupImpl) -> Unit
): OutgoingPacket {
val source = MessageSourceToGroupImpl(
group,
internalId = Random.nextInt().absoluteValue,
sender = client.bot,
target = group,
time = currentTimeSeconds.toInt(),
originalMessage = message//,
// sourceMessage = message
)
sourceCallback(source)
return createToGroup(
client,
group.id,
message,
isForward,
source)
}
/** /**
* 发送群消息 * 发送群消息
*/ */
@Suppress("FunctionName") @Suppress("FunctionName")
private fun createToGroup( internal fun createToGroupImpl(
client: QQAndroidClient, client: QQAndroidClient,
groupCode: Long, groupCode: Long,
message: MessageChain, message: MessageChain,
@ -231,7 +161,91 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
Response.Failed( Response.Failed(
response.result, response.result,
response.errtype, response.errtype,
response.errmsg) response.errmsg
)
} }
} }
} }
internal inline fun MessageSvcPbSendMsg.createToTemp(
client: QQAndroidClient,
member: Member,
message: MessageChain,
crossinline sourceCallback: (MessageSourceToTempImpl) -> Unit
): OutgoingPacket {
contract {
callsInPlace(sourceCallback, InvocationKind.EXACTLY_ONCE)
}
val source = MessageSourceToTempImpl(
internalId = Random.nextInt().absoluteValue,
sender = client.bot,
target = member,
time = currentTimeSeconds.toInt(),
sequenceId = client.atomicNextMessageSequenceId(),
originalMessage = message
)
sourceCallback(source)
return createToTempImpl(
client,
(member.group as GroupImpl).uin,
member.id,
message,
source
)
}
internal inline fun MessageSvcPbSendMsg.createToFriend(
client: QQAndroidClient,
qq: Friend,
message: MessageChain,
crossinline sourceCallback: (MessageSourceToFriendImpl) -> Unit
): OutgoingPacket {
contract {
callsInPlace(sourceCallback, InvocationKind.EXACTLY_ONCE)
}
val rand = Random.nextInt().absoluteValue
val source = MessageSourceToFriendImpl(
internalId = rand,
sender = client.bot,
target = qq,
time = currentTimeSeconds.toInt(),
sequenceId = client.nextFriendSeq(),
originalMessage = message
)
sourceCallback(source)
return createToFriendImpl(
client,
qq.id,
message,
source
)
}
internal inline fun MessageSvcPbSendMsg.createToGroup(
client: QQAndroidClient,
group: Group,
message: MessageChain,
isForward: Boolean,
crossinline sourceCallback: (MessageSourceToGroupImpl) -> Unit
): OutgoingPacket {
contract {
callsInPlace(sourceCallback, InvocationKind.EXACTLY_ONCE)
}
val source = MessageSourceToGroupImpl(
group,
internalId = Random.nextInt().absoluteValue,
sender = client.bot,
target = group,
time = currentTimeSeconds.toInt(),
originalMessage = message//,
// sourceMessage = message
)
sourceCallback(source)
return createToGroupImpl(
client,
group.id,
message,
isForward,
source
)
}

View File

@ -16,13 +16,11 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.JavaFriendlyAPI import net.mamoe.mirai.JavaFriendlyAPI
import net.mamoe.mirai.event.events.BeforeImageUploadEvent import net.mamoe.mirai.event.events.*
import net.mamoe.mirai.event.events.EventCancelledException
import net.mamoe.mirai.event.events.ImageUploadEvent
import net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent
import net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent
import net.mamoe.mirai.message.MessageReceipt import net.mamoe.mirai.message.MessageReceipt
import net.mamoe.mirai.message.data.* import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.message.quote
import net.mamoe.mirai.message.recall
import net.mamoe.mirai.recall import net.mamoe.mirai.recall
import net.mamoe.mirai.recallIn import net.mamoe.mirai.recallIn
import net.mamoe.mirai.utils.ExternalImage import net.mamoe.mirai.utils.ExternalImage
@ -57,8 +55,8 @@ abstract class Contact : ContactOrBot, CoroutineScope, ContactJavaFriendlyAPI {
* *
* 单条消息最大可发送 4500 字符或 50 张图片. * 单条消息最大可发送 4500 字符或 50 张图片.
* *
* @see FriendMessageSendEvent 发送好友信息事件, cancellable * @see MessagePreSendEvent 发送消息前事件
* @see GroupMessageSendEvent 发送消息事件. cancellable * @see MessagePostSendEvent 发送消息事件
* *
* @throws EventCancelledException 当发送消息事件被取消时抛出 * @throws EventCancelledException 当发送消息事件被取消时抛出
* @throws BotIsBeingMutedException 发送群消息时若 [Bot] 被禁言抛出 * @throws BotIsBeingMutedException 发送群消息时若 [Bot] 被禁言抛出
@ -71,7 +69,7 @@ abstract class Contact : ContactOrBot, CoroutineScope, ContactJavaFriendlyAPI {
abstract suspend fun sendMessage(message: Message): MessageReceipt<Contact> abstract suspend fun sendMessage(message: Message): MessageReceipt<Contact>
@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 // purely virtual @kotlin.internal.InlineOnly
@JvmSynthetic @JvmSynthetic
suspend inline fun sendMessage(message: String): MessageReceipt<Contact> { suspend inline fun sendMessage(message: String): MessageReceipt<Contact> {
return sendMessage(message.toMessage()) return sendMessage(message.toMessage())

View File

@ -14,12 +14,14 @@ package net.mamoe.mirai.contact
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.event.events.EventCancelledException import net.mamoe.mirai.event.events.EventCancelledException
import net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent import net.mamoe.mirai.event.events.FriendMessagePostSendEvent
import net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent 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.data.Message import net.mamoe.mirai.message.data.Message
import net.mamoe.mirai.message.data.isContentEmpty
import net.mamoe.mirai.message.data.toMessage import net.mamoe.mirai.message.data.toMessage
import net.mamoe.mirai.message.recall
import kotlin.jvm.JvmSynthetic import kotlin.jvm.JvmSynthetic
/** /**
@ -55,8 +57,8 @@ abstract class Friend : User(), CoroutineScope {
* *
* 单条消息最大可发送 4500 字符或 50 张图片. * 单条消息最大可发送 4500 字符或 50 张图片.
* *
* @see FriendMessageSendEvent 发送好友信息事件, cancellable * @see FriendMessagePreSendEvent 发送消息前事件
* @see GroupMessageSendEvent 发送群消息事件. cancellable * @see FriendMessagePostSendEvent 发送消息后事件
* *
* @throws EventCancelledException 当发送消息事件被取消时抛出 * @throws EventCancelledException 当发送消息事件被取消时抛出
* @throws BotIsBeingMutedException 发送群消息时若 [Bot] 被禁言抛出 * @throws BotIsBeingMutedException 发送群消息时若 [Bot] 被禁言抛出
@ -69,7 +71,7 @@ abstract class Friend : User(), CoroutineScope {
abstract override suspend fun sendMessage(message: Message): MessageReceipt<Friend> abstract override suspend fun sendMessage(message: Message): MessageReceipt<Friend>
@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 // purely virtual @kotlin.internal.InlineOnly
@JvmSynthetic @JvmSynthetic
suspend inline fun sendMessage(message: String): MessageReceipt<Friend> { suspend inline fun sendMessage(message: String): MessageReceipt<Friend> {
return sendMessage(message.toMessage()) return sendMessage(message.toMessage())

View File

@ -17,12 +17,12 @@ import net.mamoe.mirai.JavaFriendlyAPI
import net.mamoe.mirai.LowLevelAPI import net.mamoe.mirai.LowLevelAPI
import net.mamoe.mirai.data.MemberInfo import net.mamoe.mirai.data.MemberInfo
import net.mamoe.mirai.event.events.* import net.mamoe.mirai.event.events.*
import net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent
import net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent
import net.mamoe.mirai.message.MessageReceipt import net.mamoe.mirai.message.MessageReceipt
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.isContentEmpty
import net.mamoe.mirai.message.data.toMessage import net.mamoe.mirai.message.data.toMessage
import net.mamoe.mirai.message.recall
import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.internal.runBlocking import net.mamoe.mirai.utils.internal.runBlocking
import kotlin.jvm.JvmName import kotlin.jvm.JvmName
@ -137,8 +137,8 @@ abstract class Group : Contact(), CoroutineScope {
* *
* 单条消息最大可发送 4500 字符或 50 张图片. * 单条消息最大可发送 4500 字符或 50 张图片.
* *
* @see FriendMessageSendEvent 发送好友信息事件, cancellable * @see GroupMessagePreSendEvent 发送消息前事件
* @see GroupMessageSendEvent 发送消息事件. cancellable * @see GroupMessagePostSendEvent 发送消息事件
* *
* @throws EventCancelledException 当发送消息事件被取消时抛出 * @throws EventCancelledException 当发送消息事件被取消时抛出
* @throws BotIsBeingMutedException 发送群消息时若 [Bot] 被禁言抛出 * @throws BotIsBeingMutedException 发送群消息时若 [Bot] 被禁言抛出
@ -154,7 +154,7 @@ abstract class Group : Contact(), CoroutineScope {
* @see sendMessage * @see sendMessage
*/ */
@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 // purely virtual @kotlin.internal.InlineOnly
@JvmSynthetic @JvmSynthetic
suspend inline fun sendMessage(message: String): MessageReceipt<Group> { suspend inline fun sendMessage(message: String): MessageReceipt<Group> {
return sendMessage(message.toMessage()) return sendMessage(message.toMessage())

View File

@ -17,7 +17,12 @@ 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.data.Message import net.mamoe.mirai.message.data.Message
import net.mamoe.mirai.message.data.isContentEmpty
import net.mamoe.mirai.message.data.toMessage import net.mamoe.mirai.message.data.toMessage
import net.mamoe.mirai.message.recall
import net.mamoe.mirai.utils.hoursToSeconds
import net.mamoe.mirai.utils.daysToSeconds
import net.mamoe.mirai.utils.minutesToSeconds
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
@ -139,8 +144,11 @@ abstract class Member : MemberJavaFriendlyAPI, User() {
* *
* 单条消息最大可发送 4500 字符或 50 张图片. * 单条消息最大可发送 4500 字符或 50 张图片.
* *
* @see MessageSendEvent.FriendMessageSendEvent 发送好友信息事件, cancellable * @see FriendMessagePreSendEvent 当此成员是好友时发送消息前事件
* @see MessageSendEvent.GroupMessageSendEvent 发送群消息事件. cancellable * @see FriendMessagePostSendEvent 当此成员是好友时发送消息后事件
*
* @see TempMessagePreSendEvent 当此成员不是好友时发送消息前事件
* @see TempMessagePostSendEvent 当此成员不是好友时发送消息后事件
* *
* @throws EventCancelledException 当发送消息事件被取消时抛出 * @throws EventCancelledException 当发送消息事件被取消时抛出
* @throws BotIsBeingMutedException 发送群消息时若 [Bot] 被禁言抛出 * @throws BotIsBeingMutedException 发送群消息时若 [Bot] 被禁言抛出
@ -156,7 +164,7 @@ abstract class Member : MemberJavaFriendlyAPI, User() {
* @see sendMessage * @see sendMessage
*/ */
@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 // purely virtual @kotlin.internal.InlineOnly
@JvmSynthetic @JvmSynthetic
suspend inline fun sendMessage(message: String): MessageReceipt<Member> { suspend inline fun sendMessage(message: String): MessageReceipt<Member> {
return sendMessage(message.toMessage()) return sendMessage(message.toMessage())

View File

@ -13,11 +13,7 @@ package net.mamoe.mirai.contact
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.event.events.BeforeImageUploadEvent import net.mamoe.mirai.event.events.*
import net.mamoe.mirai.event.events.EventCancelledException
import net.mamoe.mirai.event.events.ImageUploadEvent
import net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent
import net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent
import net.mamoe.mirai.message.MessageReceipt import net.mamoe.mirai.message.MessageReceipt
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
@ -58,8 +54,8 @@ abstract class User : Contact(), CoroutineScope {
* *
* 单条消息最大可发送 4500 字符或 50 张图片. * 单条消息最大可发送 4500 字符或 50 张图片.
* *
* @see FriendMessageSendEvent 发送好友信息事件, cancellable * @see UserMessagePreSendEvent 发送消息前事件
* @see GroupMessageSendEvent 发送群消息事件. cancellable * @see UserMessagePostSendEvent 发送消息后事件
* *
* @throws EventCancelledException 当发送消息事件被取消时抛出 * @throws EventCancelledException 当发送消息事件被取消时抛出
* @throws BotIsBeingMutedException 发送群消息时若 [Bot] 被禁言抛出 * @throws BotIsBeingMutedException 发送群消息时若 [Bot] 被禁言抛出
@ -75,7 +71,7 @@ abstract class User : Contact(), CoroutineScope {
* @see sendMessage * @see sendMessage
*/ */
@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 // purely virtual @kotlin.internal.InlineOnly
@JvmSynthetic @JvmSynthetic
suspend inline fun sendMessage(message: String): MessageReceipt<User> { suspend inline fun sendMessage(message: String): MessageReceipt<User> {
return sendMessage(message.toMessage()) return sendMessage(message.toMessage())

View File

@ -9,7 +9,7 @@
@file:JvmMultifileClass @file:JvmMultifileClass
@file:JvmName("BotEventsKt") @file:JvmName("BotEventsKt")
@file:Suppress("unused") @file:Suppress("unused", "INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "RESULT_CLASS_IN_RETURN_TYPE")
package net.mamoe.mirai.event.events package net.mamoe.mirai.event.events
@ -19,41 +19,253 @@ import net.mamoe.mirai.event.AbstractEvent
import net.mamoe.mirai.event.CancellableEvent import net.mamoe.mirai.event.CancellableEvent
import net.mamoe.mirai.event.events.ImageUploadEvent.Failed import net.mamoe.mirai.event.events.ImageUploadEvent.Failed
import net.mamoe.mirai.event.events.ImageUploadEvent.Succeed import net.mamoe.mirai.event.events.ImageUploadEvent.Succeed
import net.mamoe.mirai.message.MessageReceipt
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.MessageChain import net.mamoe.mirai.message.data.MessageChain
import net.mamoe.mirai.message.data.MessageSource import net.mamoe.mirai.message.data.MessageSource
import net.mamoe.mirai.qqandroid.network.Packet import net.mamoe.mirai.qqandroid.network.Packet
import net.mamoe.mirai.utils.ExternalImage import net.mamoe.mirai.utils.ExternalImage
import net.mamoe.mirai.utils.PlannedRemoval
import net.mamoe.mirai.utils.SinceMirai
import kotlin.internal.InlineOnly
import kotlin.jvm.JvmMultifileClass import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName import kotlin.jvm.JvmName
import kotlin.jvm.JvmSynthetic
// region MessagePreSendEvent
/** /**
* 主动发送消息 * 在发送消息前广播的事件. 可被 [取消][CancellableEvent.cancel].
*
* 此事件总是在 [MessagePostSendEvent] 之前广播.
*
* [MessagePreSendEvent] [取消][CancellableEvent.cancel] :
* - [MessagePostSendEvent] 不会广播
* - 消息不会发送.
* - [Contact.sendMessage] 会抛出异常 [EventCancelledException]
* *
* @see Contact.sendMessage 发送消息. 为广播这个事件的唯一途径 * @see Contact.sendMessage 发送消息. 为广播这个事件的唯一途径
*/ */
sealed class MessageSendEvent : BotEvent, BotActiveEvent, AbstractEvent() { @SinceMirai("1.1.0")
sealed class MessagePreSendEvent : BotEvent, BotActiveEvent, AbstractEvent(), CancellableEvent {
/** 发信目标. */
abstract val target: Contact abstract val target: Contact
final override val bot: Bot final override val bot: Bot get() = target.bot
get() = target.bot
data class GroupMessageSendEvent internal constructor( /** 待发送的消息. 修改后将会同时应用于发送. */
override val target: Group, abstract var message: Message
var message: MessageChain
) : MessageSendEvent(), CancellableEvent
data class FriendMessageSendEvent internal constructor(
override val target: Friend,
var message: MessageChain
) : MessageSendEvent(), CancellableEvent
data class TempMessageSendEvent internal constructor(
override val target: Member,
var message: MessageChain
) : MessageSendEvent(), CancellableEvent
} }
/**
* 在发送群消息前广播的事件.
* @see MessagePreSendEvent
*/
@SinceMirai("1.1.0")
data class GroupMessagePreSendEvent internal constructor(
/** 发信目标. */
override val target: Group,
/** 待发送的消息. 修改后将会同时应用于发送. */
override var message: Message
) : MessagePreSendEvent()
/**
* 在发送好友或群临时会话消息前广播的事件.
* @see MessagePreSendEvent
*/
@SinceMirai("1.1.0")
sealed class UserMessagePreSendEvent : MessagePreSendEvent() {
/** 发信目标. */
abstract override val target: User
}
/**
* 在发送好友消息前广播的事件.
* @see MessagePreSendEvent
*/
@SinceMirai("1.1.0")
data class FriendMessagePreSendEvent internal constructor(
/** 发信目标. */
override val target: Friend,
/** 待发送的消息. 修改后将会同时应用于发送. */
override var message: Message
) : UserMessagePreSendEvent()
/**
* 在发送群临时会话消息前广播的事件.
* @see MessagePreSendEvent
*/
@SinceMirai("1.1.0")
data class TempMessagePreSendEvent internal constructor(
/** 发信目标. */
override val target: Member,
/** 待发送的消息. 修改后将会同时应用于发送. */
override var message: Message
) : UserMessagePreSendEvent() {
val group get() = target.group
}
// endregion
// region MessagePostSendEvent
/**
* 在发送消息后广播的事件, 总是在 [MessagePreSendEvent] 之后广播.
*
* 只要 [MessagePreSendEvent] 未被 [取消][CancellableEvent.cancel], [MessagePostSendEvent] 就一定会被广播, 并携带 [发送时产生的异常][MessagePostSendEvent.exception] (如果有).
*
* 在此事件广播前, 消息一定已经发送成功, 或产生一个异常.
*
* @see Contact.sendMessage 发送消息. 为广播这个事件的唯一途径
* @see MessagePreSendEvent
*/
@SinceMirai("1.1.0")
sealed class MessagePostSendEvent<C : Contact> : BotEvent, BotActiveEvent, AbstractEvent() {
/** 发信目标. */
abstract val target: C
final override val bot: Bot get() = target.bot
/** 待发送的消息. 此为 [MessagePreSendEvent.message] 的最终值. */
abstract val message: MessageChain
/**
* 发送消息时抛出的异常. `null` 表示消息成功发送.
* @see result
*/
abstract val exception: Throwable?
/**
* 发送消息成功时的回执. `null` 表示消息发送失败.
* @see result
*/
abstract val receipt: MessageReceipt<C>?
}
/**
* 获取指代这条已经发送的消息的 [MessageSource]. 若消息发送失败, 返回 `null`
* @see MessagePostSendEvent.sourceResult
*/
@get:JvmSynthetic
@SinceMirai("1.1.0")
inline val MessagePostSendEvent<*>.source: MessageSource?
get() = receipt?.source
/**
* 获取指代这条已经发送的消息的 [MessageSource], 并包装为 [kotlin.Result]
* @see MessagePostSendEvent.result
*/
@get:JvmSynthetic
@SinceMirai("1.1.0")
inline val MessagePostSendEvent<*>.sourceResult: Result<MessageSource>
get() = result.map { it.source }
/**
* 在此消息发送成功时返回 `true`.
* @see MessagePostSendEvent.exception
* @see MessagePostSendEvent.result
*/
@get:JvmSynthetic
@SinceMirai("1.1.0")
inline val MessagePostSendEvent<*>.isSuccess: Boolean
get() = exception == null
/**
* 在此消息发送失败时返回 `true`.
* @see MessagePostSendEvent.exception
* @see MessagePostSendEvent.result
*/
@get:JvmSynthetic
@SinceMirai("1.1.0")
inline val MessagePostSendEvent<*>.isFailure: Boolean
get() = exception != null
/**
* [MessagePostSendEvent.exception] [MessagePostSendEvent.receipt] 表示为 [Result]
*/
@InlineOnly
@SinceMirai("1.1.0")
inline val <C : Contact> MessagePostSendEvent<C>.result: Result<MessageReceipt<C>>
get() = exception.let { exception -> if (exception != null) Result.failure(exception) else Result.success(receipt!!) }
/**
* 在群消息发送后广播的事件.
* @see MessagePostSendEvent
*/
@SinceMirai("1.1.0")
data class GroupMessagePostSendEvent internal constructor(
/** 发信目标. */
override val target: Group,
/** 待发送的消息. 此为 [MessagePreSendEvent.message] 的最终值. */
override val message: MessageChain,
/**
* 发送消息时抛出的异常. `null` 表示消息成功发送.
* @see result
*/
override val exception: Throwable?,
/**
* 发送消息成功时的回执. `null` 表示消息发送失败.
* @see result
*/
override val receipt: MessageReceipt<Group>?
) : MessagePostSendEvent<Group>()
/**
* 在好友或群临时会话消息发送后广播的事件.
* @see MessagePostSendEvent
*/
@SinceMirai("1.1.0")
sealed class UserMessagePostSendEvent<C : User> : MessagePostSendEvent<C>()
/**
* 在好友消息发送后广播的事件.
* @see MessagePostSendEvent
*/
@SinceMirai("1.1.0")
data class FriendMessagePostSendEvent internal constructor(
/** 发信目标. */
override val target: Friend,
/** 待发送的消息. 此为 [MessagePreSendEvent.message] 的最终值. */
override val message: MessageChain,
/**
* 发送消息时抛出的异常. `null` 表示消息成功发送.
* @see result
*/
override val exception: Throwable?,
/**
* 发送消息成功时的回执. `null` 表示消息发送失败.
* @see result
*/
override val receipt: MessageReceipt<Friend>?
) : UserMessagePostSendEvent<Friend>()
/**
* 在群临时会话消息发送后广播的事件.
* @see MessagePostSendEvent
*/
@SinceMirai("1.1.0")
data class TempMessagePostSendEvent internal constructor(
/** 发信目标. */
override val target: Member,
/** 待发送的消息. 此为 [MessagePreSendEvent.message] 的最终值. */
override val message: MessageChain,
/**
* 发送消息时抛出的异常. `null` 表示消息成功发送.
* @see result
*/
override val exception: Throwable?,
/**
* 发送消息成功时的回执. `null` 表示消息发送失败.
* @see result
*/
override val receipt: MessageReceipt<Member>?
) : UserMessagePostSendEvent<Member>() {
val group get() = target.group
}
// endregion
/** /**
* 消息撤回事件. 可是任意消息被任意人撤回. * 消息撤回事件. 可是任意消息被任意人撤回.
* *
@ -177,3 +389,65 @@ sealed class ImageUploadEvent : BotEvent, BotActiveEvent, AbstractEvent() {
) : ImageUploadEvent() ) : ImageUploadEvent()
} }
// region deprecated
/**
* 主动发送消息
*
* @see Contact.sendMessage 发送消息. 为广播这个事件的唯一途径
*/
@Suppress("DEPRECATION")
@PlannedRemoval("1.3.0") // arise deprecation level to ERROR in 1.2.0.
@Deprecated(
message = """
MessagePreSendEvent MessagePostSendEvent 替换.
""",
replaceWith = ReplaceWith("MessagePreSendEvent", "net.mamoe.mirai.event.events.MessagePreSendEvent"),
level = DeprecationLevel.WARNING
)
sealed class MessageSendEvent : BotEvent, BotActiveEvent, AbstractEvent() {
abstract val target: Contact
final override val bot: Bot
get() = target.bot
@Deprecated(
message = """
GroupMessagePreSendEvent GroupMessagePostSendEvent 替换.
""",
replaceWith = ReplaceWith("GroupMessagePreSendEvent", "net.mamoe.mirai.event.events.GroupMessagePreSendEvent"),
level = DeprecationLevel.WARNING
)
data class GroupMessageSendEvent internal constructor(
override val target: Group,
var message: MessageChain
) : MessageSendEvent(), CancellableEvent
@Deprecated(
message = """
FriendMessagePreSendEvent FriendMessagePostSendEvent 替换.
""",
replaceWith = ReplaceWith(
"FriendMessagePreSendEvent",
"net.mamoe.mirai.event.events.FriendMessagePreSendEvent"
),
level = DeprecationLevel.WARNING
)
data class FriendMessageSendEvent internal constructor(
override val target: Friend,
var message: MessageChain
) : MessageSendEvent(), CancellableEvent
@Deprecated(
message = """
TempMessagePreSendEvent TempMessagePostSendEvent 替换.
""",
replaceWith = ReplaceWith("TempMessagePreSendEvent", "net.mamoe.mirai.event.events.TempMessagePreSendEvent"),
level = DeprecationLevel.WARNING
)
data class TempMessageSendEvent internal constructor(
override val target: Member,
var message: MessageChain
) : MessageSendEvent(), CancellableEvent
}
// endregion