Fix ambiguous message event names. Fix #299.

Binary compatibility until 1.2.0.

Migrations:
- `MessagePacket` deprecated in favor of `MessageEvent`
- `MessagePacketBase` deprecated in favor of `MessageEvent`
- `ContactMessage` -> `MessageEvent`
- `FriendMessage` -> `FriendMessageEvent`
- `GroupMessage` -> `GroupMessageEvent`
- `TempMessage` -> `TempMessageEvent`
This commit is contained in:
Him188 2020-05-05 13:55:01 +08:00
parent 66da881ebb
commit 4ee27f2069
18 changed files with 585 additions and 483 deletions

View File

@ -59,17 +59,17 @@ internal fun Contact.logMessageSent(message: Message) {
} }
@OptIn(MiraiInternalAPI::class, MiraiExperimentalAPI::class) @OptIn(MiraiInternalAPI::class, MiraiExperimentalAPI::class)
internal fun ContactMessage.logMessageReceived() { internal fun MessageEvent.logMessageReceived() {
when (this) { when (this) {
is GroupMessage -> bot.logger.verbose { is GroupMessageEvent -> bot.logger.verbose {
"[${group.name.singleLine()}(${group.id})] ${senderName.singleLine()}(${sender.id}) -> ${message.toString() "[${group.name.singleLine()}(${group.id})] ${senderName.singleLine()}(${sender.id}) -> ${message.toString()
.singleLine()}" .singleLine()}"
} }
is TempMessage -> bot.logger.verbose { is TempMessageEvent -> bot.logger.verbose {
"[${group.name.singleLine()}(${group.id})] ${senderName.singleLine()}(Temp ${sender.id}) -> ${message.toString() "[${group.name.singleLine()}(${group.id})] ${senderName.singleLine()}(Temp ${sender.id}) -> ${message.toString()
.singleLine()}" .singleLine()}"
} }
is FriendMessage -> bot.logger.verbose { is FriendMessageEvent -> bot.logger.verbose {
"${sender.nick.singleLine()}(${sender.id}) -> ${message.toString().singleLine()}" "${sender.nick.singleLine()}(${sender.id}) -> ${message.toString().singleLine()}"
} }
} }

View File

@ -22,7 +22,7 @@ import kotlinx.io.core.use
import net.mamoe.mirai.event.* import net.mamoe.mirai.event.*
import net.mamoe.mirai.event.events.BotOfflineEvent import net.mamoe.mirai.event.events.BotOfflineEvent
import net.mamoe.mirai.event.events.BotOnlineEvent import net.mamoe.mirai.event.events.BotOnlineEvent
import net.mamoe.mirai.message.ContactMessage import net.mamoe.mirai.message.MessageEvent
import net.mamoe.mirai.network.BotNetworkHandler import net.mamoe.mirai.network.BotNetworkHandler
import net.mamoe.mirai.network.UnsupportedSMSLoginException import net.mamoe.mirai.network.UnsupportedSMSLoginException
import net.mamoe.mirai.network.WrongPasswordException import net.mamoe.mirai.network.WrongPasswordException
@ -495,7 +495,7 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
is Packet.NoLog -> { is Packet.NoLog -> {
// nothing to do // nothing to do
} }
is ContactMessage -> packet.logMessageReceived() is MessageEvent -> packet.logMessageReceived()
is Event -> bot.logger.verbose { "Event: ${packet.toString().singleLine()}" } is Event -> bot.logger.verbose { "Event: ${packet.toString().singleLine()}" }
else -> logger.verbose { "Packet: ${packet.toString().singleLine()}" } else -> logger.verbose { "Packet: ${packet.toString().singleLine()}" }
} }

View File

@ -29,8 +29,8 @@ import net.mamoe.mirai.event.events.BotJoinGroupEvent
import net.mamoe.mirai.event.events.BotOfflineEvent import net.mamoe.mirai.event.events.BotOfflineEvent
import net.mamoe.mirai.event.events.MemberJoinEvent import net.mamoe.mirai.event.events.MemberJoinEvent
import net.mamoe.mirai.getFriendOrNull import net.mamoe.mirai.getFriendOrNull
import net.mamoe.mirai.message.FriendMessage import net.mamoe.mirai.message.FriendMessageEvent
import net.mamoe.mirai.message.TempMessage import net.mamoe.mirai.message.TempMessageEvent
import net.mamoe.mirai.message.data.MessageChain import net.mamoe.mirai.message.data.MessageChain
import net.mamoe.mirai.qqandroid.QQAndroidBot import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.contact.GroupImpl import net.mamoe.mirai.qqandroid.contact.GroupImpl
@ -274,7 +274,7 @@ internal class MessageSvc {
friend.lastMessageSequence.loop { instant -> friend.lastMessageSequence.loop { instant ->
if (msg.msgHead.msgSeq > instant) { if (msg.msgHead.msgSeq > instant) {
if (friend.lastMessageSequence.compareAndSet(instant, msg.msgHead.msgSeq)) { if (friend.lastMessageSequence.compareAndSet(instant, msg.msgHead.msgSeq)) {
return@mapNotNull FriendMessage( return@mapNotNull FriendMessageEvent(
friend, friend,
msg.toMessageChain(bot, groupIdOrZero = 0, onlineSource = true), msg.toMessageChain(bot, groupIdOrZero = 0, onlineSource = true),
msg.msgHead.msgTime msg.msgHead.msgTime
@ -297,7 +297,7 @@ internal class MessageSvc {
member.lastMessageSequence.loop { instant -> member.lastMessageSequence.loop { instant ->
if (msg.msgHead.msgSeq > instant) { if (msg.msgHead.msgSeq > instant) {
if (member.lastMessageSequence.compareAndSet(instant, msg.msgHead.msgSeq)) { if (member.lastMessageSequence.compareAndSet(instant, msg.msgHead.msgSeq)) {
return@mapNotNull TempMessage( return@mapNotNull TempMessageEvent(
member, member,
msg.toMessageChain( msg.toMessageChain(
bot, bot,

View File

@ -23,7 +23,7 @@ import net.mamoe.mirai.event.broadcast
import net.mamoe.mirai.event.events.* import net.mamoe.mirai.event.events.*
import net.mamoe.mirai.getFriendOrNull import net.mamoe.mirai.getFriendOrNull
import net.mamoe.mirai.getGroupOrNull import net.mamoe.mirai.getGroupOrNull
import net.mamoe.mirai.message.GroupMessage import net.mamoe.mirai.message.GroupMessageEvent
import net.mamoe.mirai.qqandroid.QQAndroidBot import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.contact.* import net.mamoe.mirai.qqandroid.contact.*
import net.mamoe.mirai.qqandroid.message.contextualBugReportException import net.mamoe.mirai.qqandroid.message.contextualBugReportException
@ -109,7 +109,7 @@ internal class OnlinePush {
} }
val flags = extraInfo?.flags ?: 0 val flags = extraInfo?.flags ?: 0
return GroupMessage( return GroupMessageEvent(
senderName = name.also { senderName = name.also {
if (it != sender.nameCard) { if (it != sender.nameCard) {
val origin = sender._nameCard val origin = sender._nameCard

View File

@ -16,7 +16,7 @@ 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.MessageSendEvent.FriendMessageSendEvent
import net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent import net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent
import net.mamoe.mirai.message.FriendMessage 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.toMessage import net.mamoe.mirai.message.data.toMessage
@ -29,7 +29,7 @@ import kotlin.jvm.JvmSynthetic
* 对于同一个 [Bot], 任何一个人的 [Friend] 实例都是单一的. * 对于同一个 [Bot], 任何一个人的 [Friend] 实例都是单一的.
* [Friend] 无法通过任何方式直接构造. 任何时候都应从 [Bot.getFriend] 或事件中获取. * [Friend] 无法通过任何方式直接构造. 任何时候都应从 [Bot.getFriend] 或事件中获取.
* *
* @see FriendMessage * @see FriendMessageEvent
*/ */
@Suppress("DEPRECATION_ERROR") @Suppress("DEPRECATION_ERROR")
abstract class Friend : User(), CoroutineScope { abstract class Friend : User(), CoroutineScope {

View File

@ -17,10 +17,10 @@ package net.mamoe.mirai.event
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.contact.* import net.mamoe.mirai.contact.*
import net.mamoe.mirai.event.internal.* import net.mamoe.mirai.event.internal.*
import net.mamoe.mirai.message.ContactMessage import net.mamoe.mirai.message.FriendMessageEvent
import net.mamoe.mirai.message.FriendMessage import net.mamoe.mirai.message.GroupMessageEvent
import net.mamoe.mirai.message.GroupMessage import net.mamoe.mirai.message.MessageEvent
import net.mamoe.mirai.message.TempMessage import net.mamoe.mirai.message.TempMessageEvent
import net.mamoe.mirai.message.data.* import net.mamoe.mirai.message.data.*
import kotlin.jvm.JvmName import kotlin.jvm.JvmName
import kotlin.jvm.JvmOverloads import kotlin.jvm.JvmOverloads
@ -31,7 +31,7 @@ import kotlin.jvm.JvmSynthetic
* 消息事件的处理器. * 消息事件的处理器.
* *
* : * :
* 接受者 T [ContactMessage] * 接受者 T [MessageEvent]
* 参数 String 转为字符串了的消息 ([Message.toString]) * 参数 String 转为字符串了的消息 ([Message.toString])
*/ */
typealias MessageListener<T, R> = @MessageDsl suspend T.(String) -> R typealias MessageListener<T, R> = @MessageDsl suspend T.(String) -> R
@ -47,7 +47,7 @@ typealias MessageListener<T, R> = @MessageDsl suspend T.(String) -> R
* @see subscribeFriendMessages * @see subscribeFriendMessages
*/ */
@MessageDsl @MessageDsl
open class MessageSubscribersBuilder<M : ContactMessage, out Ret, R : RR, RR>( open class MessageSubscribersBuilder<M : MessageEvent, out Ret, R : RR, RR>(
/** /**
* 用于 [MessageListener] 无返回值的替代. * 用于 [MessageListener] 无返回值的替代.
*/ */
@ -231,7 +231,7 @@ open class MessageSubscribersBuilder<M : ContactMessage, out Ret, R : RR, RR>(
/** 如果是这个人发的消息. 消息目前只会是群消息 */ /** 如果是这个人发的消息. 消息目前只会是群消息 */
@MessageDsl @MessageDsl
fun sentBy(name: String): ListeningFilter = content { this is GroupMessage && this.senderName == name } fun sentBy(name: String): ListeningFilter = content { this is GroupMessageEvent && this.senderName == name }
/** 如果是这个人发的消息. 消息可以是好友消息也可以是群消息 */ /** 如果是这个人发的消息. 消息可以是好友消息也可以是群消息 */
@MessageDsl @MessageDsl
@ -247,36 +247,37 @@ open class MessageSubscribersBuilder<M : ContactMessage, out Ret, R : RR, RR>(
/** 如果是好友发来的消息 */ /** 如果是好友发来的消息 */
@MessageDsl @MessageDsl
fun sentByFriend(onEvent: MessageListener<FriendMessage, R>): Ret = fun sentByFriend(onEvent: MessageListener<FriendMessageEvent, R>): Ret =
content({ this is FriendMessage }) { onEvent(this as FriendMessage, it) } content({ this is FriendMessageEvent }) { onEvent(this as FriendMessageEvent, it) }
/** 如果是好友发来的消息 */ /** 如果是好友发来的消息 */
@MessageDsl @MessageDsl
fun sentByFriend(): ListeningFilter = newListeningFilter { this is FriendMessage } fun sentByFriend(): ListeningFilter = newListeningFilter { this is FriendMessageEvent }
/** 如果是好友发来的消息 */ /** 如果是群临时会话消息 */
@MessageDsl @MessageDsl
fun sentByTemp(): ListeningFilter = newListeningFilter { this is TempMessage } fun sentByTemp(): ListeningFilter = newListeningFilter { this is TempMessageEvent }
/** 如果是管理员或群主发的消息 */ /** 如果是管理员或群主发的消息 */
@MessageDsl @MessageDsl
fun sentByOperator(): ListeningFilter = content { this is GroupMessage && sender.permission.isOperator() } fun sentByOperator(): ListeningFilter = content { this is GroupMessageEvent && sender.permission.isOperator() }
/** 如果是管理员发的消息 */ /** 如果是管理员发的消息 */
@MessageDsl @MessageDsl
fun sentByAdministrator(): ListeningFilter = content { this is GroupMessage && sender.permission.isAdministrator() } fun sentByAdministrator(): ListeningFilter =
content { this is GroupMessageEvent && sender.permission.isAdministrator() }
/** 如果是群主发的消息 */ /** 如果是群主发的消息 */
@MessageDsl @MessageDsl
fun sentByOwner(): ListeningFilter = content { this is GroupMessage && sender.isOwner() } fun sentByOwner(): ListeningFilter = content { this is GroupMessageEvent && sender.isOwner() }
/** 如果是来自这个群的消息 */ /** 如果是来自这个群的消息 */
@MessageDsl @MessageDsl
fun sentFrom(groupId: Long): ListeningFilter = content { this is GroupMessage && group.id == groupId } fun sentFrom(groupId: Long): ListeningFilter = content { this is GroupMessageEvent && group.id == groupId }
/** 如果是来自这个群的消息 */ /** 如果是来自这个群的消息 */
@MessageDsl @MessageDsl
fun sentFrom(group: Group): ListeningFilter = content { this is GroupMessage && group.id == group.id } fun sentFrom(group: Group): ListeningFilter = content { this is GroupMessageEvent && group.id == group.id }
/** [消息内容][Message.contentToString]包含目标为 [Bot] 的 [At] */ /** [消息内容][Message.contentToString]包含目标为 [Bot] 的 [At] */
@MessageDsl @MessageDsl

View File

@ -12,7 +12,7 @@ package net.mamoe.mirai.event.internal
import net.mamoe.mirai.event.MessageDsl import net.mamoe.mirai.event.MessageDsl
import net.mamoe.mirai.event.MessageListener import net.mamoe.mirai.event.MessageListener
import net.mamoe.mirai.event.MessageSubscribersBuilder import net.mamoe.mirai.event.MessageSubscribersBuilder
import net.mamoe.mirai.message.ContactMessage import net.mamoe.mirai.message.MessageEvent
/* /*
@ -20,13 +20,13 @@ import net.mamoe.mirai.message.ContactMessage
*/ */
@MessageDsl @MessageDsl
internal fun <M : ContactMessage, Ret, R : RR, RR> MessageSubscribersBuilder<M, Ret, R, RR>.content( internal fun <M : MessageEvent, Ret, R : RR, RR> MessageSubscribersBuilder<M, Ret, R, RR>.content(
filter: M.(String) -> Boolean, filter: M.(String) -> Boolean,
onEvent: MessageListener<M, RR> onEvent: MessageListener<M, RR>
): Ret = ): Ret =
subscriber(filter) { onEvent(this, it) } subscriber(filter) { onEvent(this, it) }
internal fun <M : ContactMessage, Ret, R : RR, RR> MessageSubscribersBuilder<M, Ret, R, RR>.endsWithImpl( internal fun <M : MessageEvent, Ret, R : RR, RR> MessageSubscribersBuilder<M, Ret, R, RR>.endsWithImpl(
suffix: String, suffix: String,
removeSuffix: Boolean = true, removeSuffix: Boolean = true,
trim: Boolean = true, trim: Boolean = true,
@ -46,7 +46,7 @@ internal fun <M : ContactMessage, Ret, R : RR, RR> MessageSubscribersBuilder<M,
} }
} }
internal fun <M : ContactMessage, Ret, R : RR, RR> MessageSubscribersBuilder<M, Ret, R, RR>.startsWithImpl( internal fun <M : MessageEvent, Ret, R : RR, RR> MessageSubscribersBuilder<M, Ret, R, RR>.startsWithImpl(
prefix: String, prefix: String,
removePrefix: Boolean = true, removePrefix: Boolean = true,
trim: Boolean = true, trim: Boolean = true,
@ -64,7 +64,7 @@ internal fun <M : ContactMessage, Ret, R : RR, RR> MessageSubscribersBuilder<M,
} }
} }
internal fun <M : ContactMessage, Ret, R : RR, RR> MessageSubscribersBuilder<M, Ret, R, RR>.containsAllImpl( internal fun <M : MessageEvent, Ret, R : RR, RR> MessageSubscribersBuilder<M, Ret, R, RR>.containsAllImpl(
sub: Array<out String>, sub: Array<out String>,
ignoreCase: Boolean = false, ignoreCase: Boolean = false,
trim: Boolean = true trim: Boolean = true
@ -76,7 +76,7 @@ internal fun <M : ContactMessage, Ret, R : RR, RR> MessageSubscribersBuilder<M,
content { sub.all { toCheck -> it.contains(toCheck, ignoreCase = ignoreCase) } } content { sub.all { toCheck -> it.contains(toCheck, ignoreCase = ignoreCase) } }
} }
internal fun <M : ContactMessage, Ret, R : RR, RR> MessageSubscribersBuilder<M, Ret, R, RR>.containsAnyImpl( internal fun <M : MessageEvent, Ret, R : RR, RR> MessageSubscribersBuilder<M, Ret, R, RR>.containsAnyImpl(
vararg sub: String, vararg sub: String,
ignoreCase: Boolean = false, ignoreCase: Boolean = false,
trim: Boolean = true trim: Boolean = true
@ -86,7 +86,7 @@ internal fun <M : ContactMessage, Ret, R : RR, RR> MessageSubscribersBuilder<M,
content { list.any { toCheck -> it.contains(toCheck, ignoreCase = ignoreCase) } } content { list.any { toCheck -> it.contains(toCheck, ignoreCase = ignoreCase) } }
} else content { sub.any { toCheck -> it.contains(toCheck, ignoreCase = ignoreCase) } } } else content { sub.any { toCheck -> it.contains(toCheck, ignoreCase = ignoreCase) } }
internal fun <M : ContactMessage, Ret, R : RR, RR> MessageSubscribersBuilder<M, Ret, R, RR>.caseImpl( internal fun <M : MessageEvent, Ret, R : RR, RR> MessageSubscribersBuilder<M, Ret, R, RR>.caseImpl(
equals: String, equals: String,
ignoreCase: Boolean = false, ignoreCase: Boolean = false,
trim: Boolean = true trim: Boolean = true
@ -99,7 +99,7 @@ internal fun <M : ContactMessage, Ret, R : RR, RR> MessageSubscribersBuilder<M,
} }
} }
internal fun <M : ContactMessage, Ret, R : RR, RR> MessageSubscribersBuilder<M, Ret, R, RR>.containsImpl( internal fun <M : MessageEvent, Ret, R : RR, RR> MessageSubscribersBuilder<M, Ret, R, RR>.containsImpl(
sub: String, sub: String,
ignoreCase: Boolean = false, ignoreCase: Boolean = false,
trim: Boolean = true, trim: Boolean = true,

View File

@ -12,7 +12,7 @@
package net.mamoe.mirai.event package net.mamoe.mirai.event
import kotlinx.coroutines.* import kotlinx.coroutines.*
import net.mamoe.mirai.message.ContactMessage import net.mamoe.mirai.message.MessageEvent
import net.mamoe.mirai.message.data.Message import net.mamoe.mirai.message.data.Message
import net.mamoe.mirai.message.data.PlainText import net.mamoe.mirai.message.data.PlainText
import net.mamoe.mirai.message.isContextIdenticalWith import net.mamoe.mirai.message.isContextIdenticalWith
@ -61,7 +61,7 @@ import kotlin.jvm.JvmSynthetic
*/ */
@SinceMirai("0.29.0") @SinceMirai("0.29.0")
@Suppress("unused") @Suppress("unused")
suspend inline fun <reified T : ContactMessage> T.whileSelectMessages( suspend inline fun <reified T : MessageEvent> T.whileSelectMessages(
timeoutMillis: Long = -1, timeoutMillis: Long = -1,
filterContext: Boolean = true, filterContext: Boolean = true,
crossinline selectBuilder: @MessageDsl MessageSelectBuilder<T, Boolean>.() -> Unit crossinline selectBuilder: @MessageDsl MessageSelectBuilder<T, Boolean>.() -> Unit
@ -74,7 +74,7 @@ suspend inline fun <reified T : ContactMessage> T.whileSelectMessages(
@MiraiExperimentalAPI @MiraiExperimentalAPI
@SinceMirai("0.29.0") @SinceMirai("0.29.0")
@JvmName("selectMessages1") @JvmName("selectMessages1")
suspend inline fun <reified T : ContactMessage> T.selectMessagesUnit( suspend inline fun <reified T : MessageEvent> T.selectMessagesUnit(
timeoutMillis: Long = -1, timeoutMillis: Long = -1,
filterContext: Boolean = true, filterContext: Boolean = true,
crossinline selectBuilder: @MessageDsl MessageSelectBuilderUnit<T, Unit>.() -> Unit crossinline selectBuilder: @MessageDsl MessageSelectBuilderUnit<T, Unit>.() -> Unit
@ -104,7 +104,7 @@ suspend inline fun <reified T : ContactMessage> T.selectMessagesUnit(
@SinceMirai("0.29.0") @SinceMirai("0.29.0")
@Suppress("unused") // false positive @Suppress("unused") // false positive
// @BuilderInference // https://youtrack.jetbrains.com/issue/KT-37716 // @BuilderInference // https://youtrack.jetbrains.com/issue/KT-37716
suspend inline fun <reified T : ContactMessage, R> T.selectMessages( suspend inline fun <reified T : MessageEvent, R> T.selectMessages(
timeoutMillis: Long = -1, timeoutMillis: Long = -1,
filterContext: Boolean = true, filterContext: Boolean = true,
// @BuilderInference // @BuilderInference
@ -121,7 +121,7 @@ suspend inline fun <reified T : ContactMessage, R> T.selectMessages(
*/ */
@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE") @Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE")
@SinceMirai("0.29.0") @SinceMirai("0.29.0")
abstract class MessageSelectBuilder<M : ContactMessage, R> @PublishedApi internal constructor( abstract class MessageSelectBuilder<M : MessageEvent, R> @PublishedApi internal constructor(
ownerMessagePacket: M, ownerMessagePacket: M,
stub: Any?, stub: Any?,
subscriber: (M.(String) -> Boolean, MessageListener<M, Any?>) -> Unit subscriber: (M.(String) -> Boolean, MessageListener<M, Any?>) -> Unit
@ -236,7 +236,7 @@ abstract class MessageSelectBuilder<M : ContactMessage, R> @PublishedApi interna
* @see MessageSubscribersBuilder 查看上层 API * @see MessageSubscribersBuilder 查看上层 API
*/ */
@SinceMirai("0.29.0") @SinceMirai("0.29.0")
abstract class MessageSelectBuilderUnit<M : ContactMessage, R> @PublishedApi internal constructor( abstract class MessageSelectBuilderUnit<M : MessageEvent, R> @PublishedApi internal constructor(
private val ownerMessagePacket: M, private val ownerMessagePacket: M,
stub: Any?, stub: Any?,
subscriber: (M.(String) -> Boolean, MessageListener<M, Any?>) -> Unit subscriber: (M.(String) -> Boolean, MessageListener<M, Any?>) -> Unit
@ -480,7 +480,7 @@ internal val ExceptionHandlerIgnoringCancellationException = CoroutineExceptionH
@PublishedApi @PublishedApi
@BuilderInference @BuilderInference
@OptIn(ExperimentalTypeInference::class) @OptIn(ExperimentalTypeInference::class)
internal suspend inline fun <reified T : ContactMessage, R> T.selectMessagesImpl( internal suspend inline fun <reified T : MessageEvent, R> T.selectMessagesImpl(
timeoutMillis: Long = -1, timeoutMillis: Long = -1,
isUnit: Boolean, isUnit: Boolean,
filterContext: Boolean = true, filterContext: Boolean = true,
@ -579,7 +579,7 @@ internal suspend inline fun <reified T : ContactMessage, R> T.selectMessagesImpl
@Suppress("unused") @Suppress("unused")
@PublishedApi @PublishedApi
internal suspend inline fun <reified T : ContactMessage> T.whileSelectMessagesImpl( internal suspend inline fun <reified T : MessageEvent> T.whileSelectMessagesImpl(
timeoutMillis: Long = -1, timeoutMillis: Long = -1,
filterContext: Boolean = true, filterContext: Boolean = true,
crossinline selectBuilder: @MessageDsl MessageSelectBuilder<T, Boolean>.() -> Unit crossinline selectBuilder: @MessageDsl MessageSelectBuilder<T, Boolean>.() -> Unit

View File

@ -17,10 +17,10 @@ import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.ReceiveChannel import kotlinx.coroutines.channels.ReceiveChannel
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.event.events.BotEvent import net.mamoe.mirai.event.events.BotEvent
import net.mamoe.mirai.message.ContactMessage import net.mamoe.mirai.message.FriendMessageEvent
import net.mamoe.mirai.message.FriendMessage import net.mamoe.mirai.message.GroupMessageEvent
import net.mamoe.mirai.message.GroupMessage import net.mamoe.mirai.message.MessageEvent
import net.mamoe.mirai.message.TempMessage import net.mamoe.mirai.message.TempMessageEvent
import net.mamoe.mirai.utils.SinceMirai import net.mamoe.mirai.utils.SinceMirai
import kotlin.contracts.ExperimentalContracts import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind import kotlin.contracts.InvocationKind
@ -28,7 +28,7 @@ import kotlin.contracts.contract
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext import kotlin.coroutines.EmptyCoroutineContext
typealias MessagePacketSubscribersBuilder = MessageSubscribersBuilder<ContactMessage, Listener<ContactMessage>, Unit, Unit> typealias MessagePacketSubscribersBuilder = MessageSubscribersBuilder<MessageEvent, Listener<MessageEvent>, Unit, Unit>
/** /**
* 订阅来自所有 [Bot] 的所有联系人的消息事件. 联系人可以是任意群或任意好友或临时会话. * 订阅来自所有 [Bot] 的所有联系人的消息事件. 联系人可以是任意群或任意好友或临时会话.
@ -47,7 +47,7 @@ fun <R> CoroutineScope.subscribeMessages(
} }
return MessagePacketSubscribersBuilder(Unit) return MessagePacketSubscribersBuilder(Unit)
{ filter, messageListener: MessageListener<ContactMessage, Unit> -> { filter, messageListener: MessageListener<MessageEvent, Unit> ->
// subscribeAlways 即注册一个监听器. 这个监听器收到消息后就传递给 [messageListener] // subscribeAlways 即注册一个监听器. 这个监听器收到消息后就传递给 [messageListener]
// messageListener 即为 DSL 里 `contains(...) { }`, `startsWith(...) { }` 的代码块. // messageListener 即为 DSL 里 `contains(...) { }`, `startsWith(...) { }` 的代码块.
subscribeAlways(coroutineContext, concurrencyKind) { subscribeAlways(coroutineContext, concurrencyKind) {
@ -59,7 +59,7 @@ fun <R> CoroutineScope.subscribeMessages(
}.run(listeners) }.run(listeners)
} }
typealias GroupMessageSubscribersBuilder = MessageSubscribersBuilder<GroupMessage, Listener<GroupMessage>, Unit, Unit> typealias GroupMessageSubscribersBuilder = MessageSubscribersBuilder<GroupMessageEvent, Listener<GroupMessageEvent>, Unit, Unit>
/** /**
* 订阅来自所有 [Bot] 的所有群消息事件 * 订阅来自所有 [Bot] 的所有群消息事件
@ -84,7 +84,7 @@ fun <R> CoroutineScope.subscribeGroupMessages(
}.run(listeners) }.run(listeners)
} }
typealias FriendMessageSubscribersBuilder = MessageSubscribersBuilder<FriendMessage, Listener<FriendMessage>, Unit, Unit> typealias FriendMessageSubscribersBuilder = MessageSubscribersBuilder<FriendMessageEvent, Listener<FriendMessageEvent>, Unit, Unit>
/** /**
* 订阅来自所有 [Bot] 的所有好友消息事件 * 订阅来自所有 [Bot] 的所有好友消息事件
@ -109,7 +109,7 @@ fun <R> CoroutineScope.subscribeFriendMessages(
}.run(listeners) }.run(listeners)
} }
typealias TempMessageSubscribersBuilder = MessageSubscribersBuilder<TempMessage, Listener<TempMessage>, Unit, Unit> typealias TempMessageSubscribersBuilder = MessageSubscribersBuilder<TempMessageEvent, Listener<TempMessageEvent>, Unit, Unit>
/** /**
* 订阅来自所有 [Bot] 的所有临时会话消息事件 * 订阅来自所有 [Bot] 的所有临时会话消息事件

View File

@ -1,383 +0,0 @@
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:Suppress(
"EXPERIMENTAL_UNSIGNED_LITERALS",
"EXPERIMENTAL_API_USAGE",
"unused",
"INVISIBLE_REFERENCE",
"INVISIBLE_MEMBER"
)
@file:OptIn(MiraiInternalAPI::class)
package net.mamoe.mirai.message
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.TimeoutCancellationException
import kotlinx.coroutines.async
import net.mamoe.mirai.Bot
import net.mamoe.mirai.contact.*
import net.mamoe.mirai.event.*
import net.mamoe.mirai.event.events.BotEvent
import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.qqandroid.network.Packet
import net.mamoe.mirai.utils.*
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.jvm.JvmName
import kotlin.jvm.JvmSynthetic
/**
* 一个消息事件.
*
* 它是一个 [BotEvent], 因此可以被 [监听][Bot.subscribe]
*
* 支持的消息类型:
* - [群消息事件][GroupMessage]
* - [好友消息事件][FriendMessage]
* - [临时会话消息事件][TempMessage]
*
* @see isContextIdenticalWith 判断语境是否相同
*/
@Suppress("DEPRECATION")
@SinceMirai("0.32.0")
abstract class ContactMessage : MessagePacket<User, Contact>(), BotEvent
/**
* 一条从服务器接收到的消息事件.
* 请查看各平台的 `actual` 实现的说明.
*/
@Suppress("DEPRECATION")
@Deprecated(
message = "use ContactMessage",
replaceWith = ReplaceWith("ContactMessage", "net.mamoe.mirai.message.ContactMessage")
)
expect abstract class MessagePacket<TSender : User, TSubject : Contact> constructor() :
MessagePacketBase<TSender, TSubject>
/**
* 仅内部使用, 请使用 [ContactMessage]
*/ // Tips: 在 IntelliJ 中 (左侧边栏) 打开 `Structure`, 可查看类结构
@Deprecated(
message = "use ContactMessage",
replaceWith = ReplaceWith("ContactMessage", "net.mamoe.mirai.message.ContactMessage")
)
@Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST")
abstract class MessagePacketBase<out TSender : User, out TSubject : Contact> : Packet, BotEvent, AbstractEvent() {
/**
* 接受到这条消息的
*/
abstract override val bot: Bot
/**
* 消息事件主体.
*
* - 对于好友消息, 这个属性为 [Friend] 的实例, [sender] 引用相同;
* - 对于临时会话消息, 这个属性为 [Member] 的实例, [sender] 引用相同;
* - 对于群消息, 这个属性为 [Group] 的实例, [GroupMessage.group] 引用相同
*
* 在回复消息时, 可通过 [subject] 作为回复对象
*/
abstract val subject: TSubject
/**
* 发送人.
*
* 在好友消息时为 [Friend] 的实例, 在群消息时为 [Member] 的实例
*/
abstract val sender: TSender
abstract val senderName: String
/**
* 消息内容
*/
abstract val message: MessageChain
/**
* 消息发送时间 (由服务器提供)
*/
@SinceMirai("0.39.0")
abstract val time: Int
/**
* 消息源
*/
open val source: OnlineMessageSource.Incoming get() = message.source as OnlineMessageSource.Incoming
// region 发送 Message
/**
* 给这个消息事件的主体发送消息
* 对于好友消息事件, 这个方法将会给好友 ([subject]) 发送消息
* 对于群消息事件, 这个方法将会给群 ([subject]) 发送消息
*/
suspend inline fun reply(message: Message): MessageReceipt<TSubject> =
subject.sendMessage(message.asMessageChain()) as MessageReceipt<TSubject>
suspend inline fun reply(plain: String): MessageReceipt<TSubject> =
subject.sendMessage(plain.toMessage().asMessageChain()) as MessageReceipt<TSubject>
// endregion
// region 图片
suspend inline fun ExternalImage.upload(): Image = this.upload(subject)
suspend inline fun ExternalImage.send(): MessageReceipt<TSubject> = this.sendTo(subject)
suspend inline fun Image.send(): MessageReceipt<TSubject> = this.sendTo(subject)
suspend inline fun Message.send(): MessageReceipt<TSubject> = this.sendTo(subject)
suspend inline fun String.send(): MessageReceipt<TSubject> = this.toMessage().sendTo(subject)
// endregion
// region 引用回复
/**
* 给这个消息事件的主体发送引用回复消息
* 对于好友消息事件, 这个方法将会给好友 ([subject]) 发送消息
* 对于群消息事件, 这个方法将会给群 ([subject]) 发送消息
*/
suspend inline fun quoteReply(message: MessageChain): MessageReceipt<TSubject> =
reply(this.message.quote() + message)
suspend inline fun quoteReply(message: Message): MessageReceipt<TSubject> = reply(this.message.quote() + message)
suspend inline fun quoteReply(plain: String): MessageReceipt<TSubject> = reply(this.message.quote() + plain)
@JvmName("reply2")
suspend inline fun String.quoteReply(): MessageReceipt<TSubject> = quoteReply(this)
@JvmName("reply2")
suspend inline fun Message.quoteReply(): MessageReceipt<TSubject> = quoteReply(this)
@JvmName("reply2")
suspend inline fun MessageChain.quoteReply(): MessageReceipt<TSubject> = quoteReply(this)
// endregion
inline operator fun <M : Message> get(at: Message.Key<M>): M {
return this.message[at]
}
inline fun At.isBot(): Boolean = target == bot.id
// endregion
// region 下载图片
/**
* 获取图片下载链接
*
* @return "http://gchat.qpic.cn/gchatpic_new/..."
*/
suspend inline fun Image.url(): String = bot.queryImageUrl(this@url)
// endregion
}
/**
* 判断两个 [MessagePacket] [MessagePacket.sender] [MessagePacket.subject] 是否相同
*/
@SinceMirai("0.29.0")
fun ContactMessage.isContextIdenticalWith(another: ContactMessage): Boolean {
return this.sender == another.sender && this.subject == another.subject && this.bot == another.bot
}
/**
* 挂起当前协程, 等待下一条 [MessagePacket.sender] [MessagePacket.subject] [this] 相同且通过 [筛选][filter] [MessagePacket]
*
* [filter] 抛出了一个异常, 本函数会立即抛出这个异常.
*
* @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制
* @param filter 过滤器. 返回非 null 则代表得到了需要的值. [syncFromEvent] 会返回这个值
*
* @see syncFromEvent
*/
@JvmSynthetic
suspend inline fun <reified P : ContactMessage> P.nextMessage(
timeoutMillis: Long = -1,
crossinline filter: suspend P.(P) -> Boolean
): MessageChain {
return syncFromEvent<P, P>(timeoutMillis) {
takeIf { this.isContextIdenticalWith(this@nextMessage) }?.takeIf { filter(it, it) }
}.message
}
/**
* 挂起当前协程, 等待下一条 [MessagePacket.sender] [MessagePacket.subject] [this] 相同且通过 [筛选][filter] [MessagePacket]
*
* [filter] 抛出了一个异常, 本函数会立即抛出这个异常.
*
* @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制
* @param filter 过滤器. 返回非 null 则代表得到了需要的值. [syncFromEvent] 会返回这个值
* @return 消息链. 超时时返回 `null`
*
* @see syncFromEventOrNull
*/
@JvmSynthetic
suspend inline fun <reified P : ContactMessage> P.nextMessageOrNull(
timeoutMillis: Long = -1,
crossinline filter: suspend P.(P) -> Boolean
): MessageChain? {
return syncFromEventOrNull<P, P>(timeoutMillis) {
takeIf { this.isContextIdenticalWith(this@nextMessageOrNull) }?.takeIf { filter(it, it) }
}?.message
}
/**
* 挂起当前协程, 等待下一条 [MessagePacket.sender] [MessagePacket.subject] [this] 相同的 [MessagePacket]
*
* @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制
*
* @throws TimeoutCancellationException
*
* @see syncFromEvent
*/
@JvmSynthetic
suspend inline fun <reified P : ContactMessage> P.nextMessage(
timeoutMillis: Long = -1
): MessageChain {
return syncFromEvent<P, P>(timeoutMillis) {
takeIf { this.isContextIdenticalWith(this@nextMessage) }
}.message
}
/**
* @see nextMessage
* @throws TimeoutCancellationException
*/
@JvmSynthetic
inline fun <reified P : ContactMessage> P.nextMessageAsync(
timeoutMillis: Long = -1,
coroutineContext: CoroutineContext = EmptyCoroutineContext
): Deferred<MessageChain> {
return this.bot.async(coroutineContext) {
syncFromEvent<P, P>(timeoutMillis) {
takeIf { this.isContextIdenticalWith(this@nextMessageAsync) }
}.message
}
}
/**
* @see nextMessage
*/
@JvmSynthetic
inline fun <reified P : ContactMessage> P.nextMessageAsync(
timeoutMillis: Long = -1,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
crossinline filter: suspend P.(P) -> Boolean
): Deferred<MessageChain> {
return this.bot.async(coroutineContext) {
syncFromEvent<P, P>(timeoutMillis) {
takeIf { this.isContextIdenticalWith(this@nextMessageAsync) }
.takeIf { filter(this, this) }
}.message
}
}
/**
* 挂起当前协程, 等待下一条 [MessagePacket.sender] [MessagePacket.subject] [this] 相同的 [MessagePacket]
*
* [filter] 抛出了一个异常, 本函数会立即抛出这个异常.
*
* @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制
* @return 消息链. 超时时返回 `null`
*
* @see syncFromEventOrNull
*/
@JvmSynthetic
suspend inline fun <reified P : ContactMessage> P.nextMessageOrNull(
timeoutMillis: Long = -1
): MessageChain? {
return syncFromEventOrNull<P, P>(timeoutMillis) {
takeIf { this.isContextIdenticalWith(this@nextMessageOrNull) }
}?.message
}
/**
* @see nextMessageOrNull
*/
@JvmSynthetic
inline fun <reified P : ContactMessage> P.nextMessageOrNullAsync(
timeoutMillis: Long = -1,
coroutineContext: CoroutineContext = EmptyCoroutineContext
): Deferred<MessageChain?> {
return this.bot.async(coroutineContext) {
syncFromEventOrNull<P, P>(timeoutMillis) {
takeIf { this.isContextIdenticalWith(this@nextMessageOrNullAsync) }
}?.message
}
}
/**
* 挂起当前协程, 等待下一条 [MessagePacket.sender] [MessagePacket.subject] [this] 相同的 [MessagePacket]
*
* [filter] 抛出了一个异常, 本函数会立即抛出这个异常.
*
* @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制
*
* @see syncFromEvent
* @see whileSelectMessages
* @see selectMessages
*/
@JvmSynthetic
suspend inline fun <reified M : Message> ContactMessage.nextMessageContaining(
timeoutMillis: Long = -1
): M {
return syncFromEvent<ContactMessage, ContactMessage>(timeoutMillis) {
takeIf { this.isContextIdenticalWith(this@nextMessageContaining) }
.takeIf { this.message.anyIsInstance<M>() }
}.message.firstIsInstance()
}
@JvmSynthetic
inline fun <reified M : Message> ContactMessage.nextMessageContainingAsync(
timeoutMillis: Long = -1,
coroutineContext: CoroutineContext = EmptyCoroutineContext
): Deferred<M> {
return this.bot.async(coroutineContext) {
@Suppress("RemoveExplicitTypeArguments")
syncFromEvent<ContactMessage, ContactMessage>(timeoutMillis) {
takeIf { this.isContextIdenticalWith(this@nextMessageContainingAsync) }
.takeIf { this.message.anyIsInstance<M>() }
}.message.firstIsInstance<M>()
}
}
/**
* 挂起当前协程, 等待下一条 [MessagePacket.sender] [MessagePacket.subject] [this] 相同并含有 [M] 类型的消息的 [MessagePacket]
*
* [filter] 抛出了一个异常, 本函数会立即抛出这个异常.
*
* @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制
* @return 指定类型的消息. 超时时返回 `null`
*
* @see syncFromEventOrNull
*/
@JvmSynthetic
suspend inline fun <reified M : Message> ContactMessage.nextMessageContainingOrNull(
timeoutMillis: Long = -1
): M? {
return syncFromEventOrNull<ContactMessage, ContactMessage>(timeoutMillis) {
takeIf { this.isContextIdenticalWith(this@nextMessageContainingOrNull) }
.takeIf { this.message.anyIsInstance<M>() }
}?.message?.firstIsInstance()
}
@JvmSynthetic
inline fun <reified M : Message> ContactMessage.nextMessageContainingOrNullAsync(
timeoutMillis: Long = -1,
coroutineContext: CoroutineContext = EmptyCoroutineContext
): Deferred<M?> {
return this.bot.async(coroutineContext) {
syncFromEventOrNull<ContactMessage, ContactMessage>(timeoutMillis) {
takeIf { this.isContextIdenticalWith(this@nextMessageContainingOrNullAsync) }
.takeIf { this.message.anyIsInstance<M>() }
}?.message?.firstIsInstance<M>()
}
}

View File

@ -18,17 +18,21 @@ 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.message.data.OnlineMessageSource import net.mamoe.mirai.message.data.OnlineMessageSource
import net.mamoe.mirai.message.data.source import net.mamoe.mirai.message.data.source
import net.mamoe.mirai.utils.PlannedRemoval
/** /**
* 好友消息事件 * 机器人收到的好友消息的事件
*
* @see MessageEvent
*/ */
class FriendMessage constructor( class FriendMessageEvent constructor(
override val sender: Friend, override val sender: Friend,
override val message: MessageChain, override val message: MessageChain,
override val time: Int override val time: Int
) : ContactMessage(), BroadcastControllable { ) : @PlannedRemoval("1.2.0") FriendMessage(), BroadcastControllable {
init { init {
val source = message.getOrNull(MessageSource) ?: error("Cannot find MessageSource from message") val source =
message.getOrNull(MessageSource) ?: throw IllegalArgumentException("Cannot find MessageSource from message")
check(source is OnlineMessageSource.Incoming.FromFriend) { "source provided to a FriendMessage must be an instance of OnlineMessageSource.Incoming.FromFriend" } check(source is OnlineMessageSource.Incoming.FromFriend) { "source provided to a FriendMessage must be an instance of OnlineMessageSource.Incoming.FromFriend" }
} }
@ -37,5 +41,5 @@ class FriendMessage constructor(
override val senderName: String get() = sender.nick override val senderName: String get() = sender.nick
override val source: OnlineMessageSource.Incoming.FromFriend get() = message.source as OnlineMessageSource.Incoming.FromFriend override val source: OnlineMessageSource.Incoming.FromFriend get() = message.source as OnlineMessageSource.Incoming.FromFriend
override fun toString(): String = "FriendMessage(sender=${sender.id}, message=$message)" override fun toString(): String = "FriendMessageEvent(sender=${sender.id}, message=$message)"
} }

View File

@ -7,6 +7,8 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE * https://github.com/mamoe/mirai/blob/master/LICENSE
*/ */
@file:Suppress("DEPRECATION_ERROR", "unused", "NOTHING_TO_INLINE")
package net.mamoe.mirai.message package net.mamoe.mirai.message
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
@ -15,14 +17,14 @@ import net.mamoe.mirai.contact.Member
import net.mamoe.mirai.contact.MemberPermission import net.mamoe.mirai.contact.MemberPermission
import net.mamoe.mirai.event.Event import net.mamoe.mirai.event.Event
import net.mamoe.mirai.message.data.* import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.utils.PlannedRemoval
/** /**
* 群消息事件 * 机器人收到的群消息事件
* *
* @see ContactMessage * @see MessageEvent
*/ */
@Suppress("unused", "NOTHING_TO_INLINE") class GroupMessageEvent(
class GroupMessage(
override val senderName: String, override val senderName: String,
/** /**
* 发送方权限. * 发送方权限.
@ -31,13 +33,13 @@ class GroupMessage(
override val sender: Member, override val sender: Member,
override val message: MessageChain, override val message: MessageChain,
override val time: Int override val time: Int
) : ContactMessage(), Event { ) : @PlannedRemoval("1.2.0") GroupMessage(), Event {
init { init {
val source = message.getOrNull(MessageSource) ?: error("Cannot find MessageSource from message") val source = message.getOrNull(MessageSource) ?: error("Cannot find MessageSource from message")
check(source is OnlineMessageSource.Incoming.FromGroup) { "source provided to a GroupMessage must be an instance of OnlineMessageSource.Incoming.FromGroup" } check(source is OnlineMessageSource.Incoming.FromGroup) { "source provided to a GroupMessage must be an instance of OnlineMessageSource.Incoming.FromGroup" }
} }
val group: Group get() = sender.group inline val group: Group get() = sender.group
override val bot: Bot get() = sender.bot override val bot: Bot get() = sender.bot
override val subject: Group get() = group override val subject: Group get() = group
@ -47,5 +49,5 @@ class GroupMessage(
inline fun At.asMember(): Member = group[this.target] inline fun At.asMember(): Member = group[this.target]
override fun toString(): String = override fun toString(): String =
"GroupMessage(group=${group.id}, senderName=$senderName, sender=${sender.id}, permission=${permission.name}, message=$message)" "GroupMessageEvent(group=${group.id}, senderName=$senderName, sender=${sender.id}, permission=${permission.name}, message=$message)"
} }

View File

@ -0,0 +1,221 @@
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:Suppress(
"EXPERIMENTAL_UNSIGNED_LITERALS",
"EXPERIMENTAL_API_USAGE",
"unused",
"DECLARATION_CANT_BE_INLINED", "UNCHECKED_CAST", "NOTHING_TO_INLINE"
)
@file:OptIn(MiraiInternalAPI::class)
@file:JvmMultifileClass
@file:JvmName("MessageEventKt")
package net.mamoe.mirai.message
import net.mamoe.mirai.Bot
import net.mamoe.mirai.contact.*
import net.mamoe.mirai.event.AbstractEvent
import net.mamoe.mirai.event.events.BotEvent
import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.qqandroid.network.Packet
import net.mamoe.mirai.utils.*
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
import kotlin.jvm.JvmSynthetic
/**
* 一个 (收到的) 消息事件.
*
* 它是一个 [BotEvent], 因此可以被 [监听][Bot.subscribe]
*
* 支持的消息类型:
* - [群消息事件][GroupMessageEvent]
* - [好友消息事件][FriendMessageEvent]
* - [临时会话消息事件][TempMessageEvent]
*
* @see isContextIdenticalWith 判断语境是否相同
*/
@Suppress("DEPRECATION_ERROR")
@SinceMirai("0.32.0")
abstract class MessageEvent : @PlannedRemoval("1.2.0") ContactMessage(),
BotEvent, MessageEventExtensions<User, Contact> {
/**
* 与这个消息事件相关的 [Bot]
*/
abstract override val bot: Bot
/**
* 消息事件主体.
*
* - 对于好友消息, 这个属性为 [Friend] 的实例, [sender] 引用相同;
* - 对于临时会话消息, 这个属性为 [Member] 的实例, [sender] 引用相同;
* - 对于群消息, 这个属性为 [Group] 的实例, [GroupMessageEvent.group] 引用相同
*
* 在回复消息时, 可通过 [subject] 作为回复对象
*/
abstract override val subject: Contact
/**
* 发送人.
*
* 在好友消息时为 [Friend] 的实例, 在群消息时为 [Member] 的实例
*/
abstract override val sender: User
abstract val senderName: String
/** 消息内容 */
abstract override val message: MessageChain
/** 消息发送时间 (由服务器提供) */
@SinceMirai("0.39.0")
abstract val time: Int
/** 消息源 */
open val source: OnlineMessageSource.Incoming get() = message.source as OnlineMessageSource.Incoming
}
/** 消息事件的扩展函数 */
@Suppress("EXPOSED_SUPER_INTERFACE") // Functions are visible
interface MessageEventExtensions<out TSender : User, out TSubject : Contact> :
MessageEventPlatformExtensions<TSender, TSubject> {
// region 发送 Message
/**
* 给这个消息事件的主体发送消息
* 对于好友消息事件, 这个方法将会给好友 ([subject]) 发送消息
* 对于群消息事件, 这个方法将会给群 ([subject]) 发送消息
*/
@JvmSynthetic
suspend inline fun reply(message: Message): MessageReceipt<TSubject> =
subject.sendMessage(message.asMessageChain()) as MessageReceipt<TSubject>
@JvmSynthetic
suspend inline fun reply(plain: String): MessageReceipt<TSubject> =
subject.sendMessage(plain.toMessage().asMessageChain()) as MessageReceipt<TSubject>
// endregion
@JvmSynthetic
suspend inline fun ExternalImage.upload(): Image = this.upload(subject)
@JvmSynthetic
suspend inline fun ExternalImage.send(): MessageReceipt<TSubject> = this.sendTo(subject)
@JvmSynthetic
suspend inline fun Image.send(): MessageReceipt<TSubject> = this.sendTo(subject)
@JvmSynthetic
suspend inline fun Message.send(): MessageReceipt<TSubject> = this.sendTo(subject)
@JvmSynthetic
suspend inline fun String.send(): MessageReceipt<TSubject> = this.toMessage().sendTo(subject)
// region 引用回复
/**
* 给这个消息事件的主体发送引用回复消息
* 对于好友消息事件, 这个方法将会给好友 ([subject]) 发送消息
* 对于群消息事件, 这个方法将会给群 ([subject]) 发送消息
*/
@JvmSynthetic
suspend inline fun quoteReply(message: MessageChain): MessageReceipt<TSubject> =
reply(this.message.quote() + message)
@JvmSynthetic
suspend inline fun quoteReply(message: Message): MessageReceipt<TSubject> = reply(this.message.quote() + message)
@JvmSynthetic
suspend inline fun quoteReply(plain: String): MessageReceipt<TSubject> = reply(this.message.quote() + plain)
@JvmSynthetic
inline operator fun <M : Message> get(at: Message.Key<M>): M {
return this.message[at]
}
@JvmSynthetic
inline fun At.isBot(): Boolean = target == bot.id
/**
* 获取图片下载链接
* @return "http://gchat.qpic.cn/gchatpic_new/..."
*/
@JvmSynthetic
suspend inline fun Image.url(): String = bot.queryImageUrl(this@url)
}
/** 一个消息事件在各平台的相关扩展. 请使用 [MessageEventExtensions] */
internal expect interface MessageEventPlatformExtensions<out TSender : User, out TSubject : Contact> {
val subject: TSubject
val sender: TSender
val message: MessageChain
val bot: Bot
}
/**
* 已废弃, 请使用 [MessageEvent]
*/
@PlannedRemoval("1.2.0")
@Deprecated(
message = "use MessageEvent",
replaceWith = ReplaceWith("MessageEvent", "net.mamoe.mirai.message.MessageEvent"),
level = DeprecationLevel.ERROR
)
abstract class MessagePacketBase<out TSender : User, out TSubject : Contact> : Packet, BotEvent, AbstractEvent()
@PlannedRemoval("1.2.0")
@Deprecated(
message = "Ambiguous name. Use MessageEvent instead",
replaceWith = ReplaceWith("MessageEvent", "net.mamoe.mirai.message.MessageEvent"),
level = DeprecationLevel.ERROR
)
@Suppress("DEPRECATION_ERROR")
abstract class MessagePacket : MessagePacketBase<User, Contact>(),
BotEvent, MessageEventExtensions<User, Contact>
@PlannedRemoval("1.2.0")
@Deprecated(
message = "Ambiguous name. Use MessageEvent instead",
replaceWith = ReplaceWith("MessageEvent", "net.mamoe.mirai.message.MessageEvent"),
level = DeprecationLevel.ERROR
)
@Suppress("DEPRECATION_ERROR")
abstract class ContactMessage : MessagePacket(),
BotEvent, MessageEventExtensions<User, Contact>
@PlannedRemoval("1.2.0")
@Deprecated(
message = "Ambiguous name. Use FriendMessageEvent instead",
replaceWith = ReplaceWith("FriendMessageEvent", "net.mamoe.mirai.message.FriendMessageEvent"),
level = DeprecationLevel.ERROR
)
@Suppress("DEPRECATION_ERROR")
abstract class FriendMessage : MessageEvent()
@PlannedRemoval("1.2.0")
@Deprecated(
message = "Ambiguous name. Use GroupMessageEvent instead",
replaceWith = ReplaceWith("GroupMessageEvent", "net.mamoe.mirai.message.GroupMessageEvent"),
level = DeprecationLevel.ERROR
)
@Suppress("DEPRECATION_ERROR")
abstract class GroupMessage : MessageEvent()
@PlannedRemoval("1.2.0")
@Deprecated(
message = "Ambiguous name. Use TempMessageEvent instead",
replaceWith = ReplaceWith("TempMessageEvent", "net.mamoe.mirai.message.TempMessageEvent"),
level = DeprecationLevel.ERROR
)
abstract class TempMessage : MessageEvent()

View File

@ -1,3 +1,5 @@
@file:Suppress("DEPRECATION_ERROR", "unused", "NOTHING_TO_INLINE")
package net.mamoe.mirai.message package net.mamoe.mirai.message
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
@ -12,14 +14,16 @@ import net.mamoe.mirai.message.data.source
import net.mamoe.mirai.utils.SinceMirai import net.mamoe.mirai.utils.SinceMirai
/** /**
* 临时会话消息 * 机器人收到的群临时会话消息的事件
*
* @see MessageEvent
*/ */
@SinceMirai("0.35.0") @SinceMirai("0.35.0")
class TempMessage( class TempMessageEvent(
override val sender: Member, override val sender: Member,
override val message: MessageChain, override val message: MessageChain,
override val time: Int override val time: Int
) : ContactMessage(), BroadcastControllable { ) : TempMessage(), BroadcastControllable {
init { init {
val source = message.getOrNull(MessageSource) ?: error("Cannot find MessageSource from message") val source = message.getOrNull(MessageSource) ?: error("Cannot find MessageSource from message")
check(source is OnlineMessageSource.Incoming.FromTemp) { "source provided to a TempMessage must be an instance of OnlineMessageSource.Incoming.FromTemp" } check(source is OnlineMessageSource.Incoming.FromTemp) { "source provided to a TempMessage must be an instance of OnlineMessageSource.Incoming.FromTemp" }
@ -32,5 +36,5 @@ class TempMessage(
override val source: OnlineMessageSource.Incoming.FromTemp get() = message.source as OnlineMessageSource.Incoming.FromTemp override val source: OnlineMessageSource.Incoming.FromTemp get() = message.source as OnlineMessageSource.Incoming.FromTemp
override fun toString(): String = override fun toString(): String =
"TempMessage(sender=${sender.id} from group(${sender.group.id}), message=$message)" "TempMessageEvent(sender=${sender.id} from group(${sender.group.id}), message=$message)"
} }

View File

@ -12,8 +12,11 @@
package net.mamoe.mirai.message.data package net.mamoe.mirai.message.data
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.contact.* import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.message.ContactMessage import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.User
import net.mamoe.mirai.contact.nameCardOrNick
import net.mamoe.mirai.message.MessageEvent
import net.mamoe.mirai.message.data.ForwardMessage.DisplayStrategy import net.mamoe.mirai.message.data.ForwardMessage.DisplayStrategy
import net.mamoe.mirai.utils.MiraiExperimentalAPI import net.mamoe.mirai.utils.MiraiExperimentalAPI
import net.mamoe.mirai.utils.SinceMirai import net.mamoe.mirai.utils.SinceMirai
@ -72,7 +75,7 @@ import kotlin.jvm.JvmSynthetic
* *
* ### 构造 * ### 构造
* - 使用 [DSL][buildForwardMessage] * - 使用 [DSL][buildForwardMessage]
* - 通过 [ContactMessage] 集合转换: [toForwardMessage] * - 通过 [MessageEvent] 集合转换: [toForwardMessage]
* *
* @see buildForwardMessage * @see buildForwardMessage
*/ */
@ -186,7 +189,7 @@ class ForwardMessage @JvmOverloads constructor(
*/ */
@SinceMirai("0.39.0") @SinceMirai("0.39.0")
@JvmOverloads @JvmOverloads
fun Iterable<ContactMessage>.toForwardMessage(displayStrategy: DisplayStrategy = DisplayStrategy): ForwardMessage { fun Iterable<MessageEvent>.toForwardMessage(displayStrategy: DisplayStrategy = DisplayStrategy): ForwardMessage {
val iterator = this.iterator() val iterator = this.iterator()
if (!iterator.hasNext()) return ForwardMessage(emptyList(), displayStrategy) if (!iterator.hasNext()) return ForwardMessage(emptyList(), displayStrategy)
return ForwardMessage( return ForwardMessage(
@ -236,7 +239,7 @@ inline fun buildForwardMessage(
*/ */
@SinceMirai("0.39.0") @SinceMirai("0.39.0")
@JvmSynthetic @JvmSynthetic
inline fun ContactMessage.buildForwardMessage( inline fun MessageEvent.buildForwardMessage(
context: Contact = this.subject, context: Contact = this.subject,
displayStrategy: DisplayStrategy = DisplayStrategy, displayStrategy: DisplayStrategy = DisplayStrategy,
block: ForwardMessageBuilder.() -> Unit block: ForwardMessageBuilder.() -> Unit

View File

@ -16,7 +16,7 @@ package net.mamoe.mirai.message.data
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.contact.* import net.mamoe.mirai.contact.*
import net.mamoe.mirai.message.ContactMessage import net.mamoe.mirai.message.MessageEvent
import net.mamoe.mirai.message.MessageReceipt import net.mamoe.mirai.message.MessageReceipt
import net.mamoe.mirai.recallIn import net.mamoe.mirai.recallIn
import net.mamoe.mirai.utils.LazyProperty import net.mamoe.mirai.utils.LazyProperty
@ -159,7 +159,7 @@ sealed class MessageSource : Message, MessageMetadata, ConstrainSingle<MessageSo
* 此回执的 [消息源][MessageReceipt.source] 即为一个 [外向消息源][OnlineMessageSource.Outgoing], 代表着刚刚发出的那条消息的来源. * 此回执的 [消息源][MessageReceipt.source] 即为一个 [外向消息源][OnlineMessageSource.Outgoing], 代表着刚刚发出的那条消息的来源.
* *
* #### 机器人接受消息 * #### 机器人接受消息
* 当机器人接收一条消息 [ContactMessage], 这条消息包含一个 [内向消息源][OnlineMessageSource.Incoming], 代表着接收到的这条消息的来源. * 当机器人接收一条消息 [MessageEvent], 这条消息包含一个 [内向消息源][OnlineMessageSource.Incoming], 代表着接收到的这条消息的来源.
* *
* *
* ### 实现 * ### 实现
@ -356,7 +356,7 @@ fun MessageSource.quote(): QuoteReply {
} }
/** /**
* 引用这条消息. 仅从服务器接收的消息 (即来自 [ContactMessage]) 才可以通过这个方式被引用. * 引用这条消息. 仅从服务器接收的消息 (即来自 [MessageEvent]) 才可以通过这个方式被引用.
* @see QuoteReply * @see QuoteReply
*/ */
fun MessageChain.quote(): QuoteReply { fun MessageChain.quote(): QuoteReply {

View File

@ -0,0 +1,243 @@
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:JvmMultifileClass
@file:JvmName("MessageEventKt")
@file:Suppress("unused")
package net.mamoe.mirai.message
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.TimeoutCancellationException
import kotlinx.coroutines.async
import net.mamoe.mirai.event.selectMessages
import net.mamoe.mirai.event.syncFromEvent
import net.mamoe.mirai.event.syncFromEventOrNull
import net.mamoe.mirai.event.whileSelectMessages
import net.mamoe.mirai.message.data.Message
import net.mamoe.mirai.message.data.MessageChain
import net.mamoe.mirai.message.data.anyIsInstance
import net.mamoe.mirai.message.data.firstIsInstance
import net.mamoe.mirai.utils.PlannedRemoval
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
import kotlin.jvm.JvmSynthetic
/**
* 判断两个 [MessageEvent] [MessageEvent.sender] [MessageEvent.subject] 是否相同
*/
fun MessageEvent.isContextIdenticalWith(another: MessageEvent): Boolean {
return this.sender == another.sender && this.subject == another.subject
}
/**
* 挂起当前协程, 等待下一条 [MessageEvent.sender] [MessageEvent.subject] [this] 相同且通过 [筛选][filter] [MessageEvent]
*
* [filter] 抛出了一个异常, 本函数会立即抛出这个异常.
*
* @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制
* @param filter 过滤器. 返回非 null 则代表得到了需要的值. [syncFromEvent] 会返回这个值
*
* @see syncFromEvent
*/
@JvmSynthetic
suspend inline fun <reified P : MessageEvent> P.nextMessage(
timeoutMillis: Long = -1,
crossinline filter: suspend P.(P) -> Boolean
): MessageChain {
return syncFromEvent<P, P>(timeoutMillis) {
takeIf { this.isContextIdenticalWith(this@nextMessage) }?.takeIf { filter(it, it) }
}.message
}
/**
* 挂起当前协程, 等待下一条 [MessageEvent.sender] [MessageEvent.subject] [this] 相同且通过 [筛选][filter] [MessageEvent]
*
* [filter] 抛出了一个异常, 本函数会立即抛出这个异常.
*
* @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制
* @param filter 过滤器. 返回非 null 则代表得到了需要的值. [syncFromEvent] 会返回这个值
* @return 消息链. 超时时返回 `null`
*
* @see syncFromEventOrNull
*/
@JvmSynthetic
suspend inline fun <reified P : MessageEvent> P.nextMessageOrNull(
timeoutMillis: Long = -1,
crossinline filter: suspend P.(P) -> Boolean
): MessageChain? {
return syncFromEventOrNull<P, P>(timeoutMillis) {
takeIf { this.isContextIdenticalWith(this@nextMessageOrNull) }?.takeIf { filter(it, it) }
}?.message
}
/**
* 挂起当前协程, 等待下一条 [MessageEvent.sender] [MessageEvent.subject] [this] 相同的 [MessageEvent]
*
* @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制
*
* @throws TimeoutCancellationException
*
* @see syncFromEvent
*/
@JvmSynthetic
suspend inline fun <reified P : MessageEvent> P.nextMessage(
timeoutMillis: Long = -1
): MessageChain {
return syncFromEvent<P, P>(timeoutMillis) {
takeIf { this.isContextIdenticalWith(this@nextMessage) }
}.message
}
/**
* @see nextMessage
* @throws TimeoutCancellationException
*/
@JvmSynthetic
inline fun <reified P : MessageEvent> P.nextMessageAsync(
timeoutMillis: Long = -1,
coroutineContext: CoroutineContext = EmptyCoroutineContext
): Deferred<MessageChain> {
return this.bot.async(coroutineContext) {
syncFromEvent<P, P>(timeoutMillis) {
takeIf { this.isContextIdenticalWith(this@nextMessageAsync) }
}.message
}
}
/**
* @see nextMessage
*/
@JvmSynthetic
inline fun <reified P : MessageEvent> P.nextMessageAsync(
timeoutMillis: Long = -1,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
crossinline filter: suspend P.(P) -> Boolean
): Deferred<MessageChain> {
return this.bot.async(coroutineContext) {
syncFromEvent<P, P>(timeoutMillis) {
takeIf { this.isContextIdenticalWith(this@nextMessageAsync) }
.takeIf { filter(this, this) }
}.message
}
}
/**
* 挂起当前协程, 等待下一条 [MessageEvent.sender] [MessageEvent.subject] [this] 相同的 [MessageEvent]
*
* [filter] 抛出了一个异常, 本函数会立即抛出这个异常.
*
* @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制
* @return 消息链. 超时时返回 `null`
*
* @see syncFromEventOrNull
*/
@JvmSynthetic
suspend inline fun <reified P : MessageEvent> P.nextMessageOrNull(
timeoutMillis: Long = -1
): MessageChain? {
return syncFromEventOrNull<P, P>(timeoutMillis) {
takeIf { this.isContextIdenticalWith(this@nextMessageOrNull) }
}?.message
}
/**
* @see nextMessageOrNull
*/
@JvmSynthetic
inline fun <reified P : MessageEvent> P.nextMessageOrNullAsync(
timeoutMillis: Long = -1,
coroutineContext: CoroutineContext = EmptyCoroutineContext
): Deferred<MessageChain?> {
return this.bot.async(coroutineContext) {
syncFromEventOrNull<P, P>(timeoutMillis) {
takeIf { this.isContextIdenticalWith(this@nextMessageOrNullAsync) }
}?.message
}
}
/**
* 挂起当前协程, 等待下一条 [MessageEvent.sender] [MessageEvent.subject] [this] 相同的 [MessageEvent]
*
* [filter] 抛出了一个异常, 本函数会立即抛出这个异常.
*
* @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制
*
* @see syncFromEvent
* @see whileSelectMessages
* @see selectMessages
*/
@JvmSynthetic
suspend inline fun <reified M : Message> MessageEvent.nextMessageContaining(
timeoutMillis: Long = -1
): M {
return syncFromEvent<MessageEvent, MessageEvent>(timeoutMillis) {
takeIf { this.isContextIdenticalWith(this@nextMessageContaining) }
.takeIf { this.message.anyIsInstance<M>() }
}.message.firstIsInstance()
}
@JvmSynthetic
inline fun <reified M : Message> MessageEvent.nextMessageContainingAsync(
timeoutMillis: Long = -1,
coroutineContext: CoroutineContext = EmptyCoroutineContext
): Deferred<M> {
return this.bot.async(coroutineContext) {
@Suppress("RemoveExplicitTypeArguments")
syncFromEvent<MessageEvent, MessageEvent>(timeoutMillis) {
takeIf { this.isContextIdenticalWith(this@nextMessageContainingAsync) }
.takeIf { this.message.anyIsInstance<M>() }
}.message.firstIsInstance<M>()
}
}
/**
* 挂起当前协程, 等待下一条 [MessageEvent.sender] [MessageEvent.subject] [this] 相同并含有 [M] 类型的消息的 [MessageEvent]
*
* [filter] 抛出了一个异常, 本函数会立即抛出这个异常.
*
* @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制
* @return 指定类型的消息. 超时时返回 `null`
*
* @see syncFromEventOrNull
*/
@JvmSynthetic
suspend inline fun <reified M : Message> MessageEvent.nextMessageContainingOrNull(
timeoutMillis: Long = -1
): M? {
return syncFromEventOrNull<MessageEvent, MessageEvent>(timeoutMillis) {
takeIf { this.isContextIdenticalWith(this@nextMessageContainingOrNull) }
.takeIf { this.message.anyIsInstance<M>() }
}?.message?.firstIsInstance()
}
@JvmSynthetic
inline fun <reified M : Message> MessageEvent.nextMessageContainingOrNullAsync(
timeoutMillis: Long = -1,
coroutineContext: CoroutineContext = EmptyCoroutineContext
): Deferred<M?> {
return this.bot.async(coroutineContext) {
syncFromEventOrNull<MessageEvent, MessageEvent>(timeoutMillis) {
takeIf { this.isContextIdenticalWith(this@nextMessageContainingOrNullAsync) }
.takeIf { this.message.anyIsInstance<M>() }
}?.message?.firstIsInstance<M>()
}
}
@PlannedRemoval("1.2.0")
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
@Suppress("DEPRECATION_ERROR")
@JvmSynthetic
fun ContactMessage.isContextIdenticalWith(another: ContactMessage): Boolean {
return this.sender == another.sender && this.subject == another.subject && this.bot == another.bot
}

View File

@ -7,50 +7,45 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE * https://github.com/mamoe/mirai/blob/master/LICENSE
*/ */
@file:Suppress("unused") @file:Suppress("unused", "DECLARATION_CANT_BE_INLINED")
package net.mamoe.mirai.message package net.mamoe.mirai.message
import kotlinx.coroutines.io.ByteWriteChannel
import kotlinx.io.core.Input import kotlinx.io.core.Input
import kotlinx.io.core.Output import net.mamoe.mirai.Bot
import kotlinx.io.core.use
import net.mamoe.mirai.contact.Contact import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.contact.Friend
import net.mamoe.mirai.contact.User import net.mamoe.mirai.contact.User
import net.mamoe.mirai.message.data.Image import net.mamoe.mirai.message.data.Image
import net.mamoe.mirai.utils.MiraiExperimentalAPI import net.mamoe.mirai.message.data.MessageChain
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.copyAndClose
import net.mamoe.mirai.utils.copyTo
import java.awt.image.BufferedImage import java.awt.image.BufferedImage
import java.io.File import java.io.File
import java.io.InputStream import java.io.InputStream
import java.io.OutputStream
import java.net.URL import java.net.URL
/** /**
* 一条从服务器接收到的消息事件. * 消息事件在 JVM 平台的扩展
* JVM 平台相关扩展 * @see MessageEventExtensions
*/ */
@Suppress("DEPRECATION") internal actual interface MessageEventPlatformExtensions<out TSender : User, out TSubject : Contact> {
@Deprecated( actual val subject: TSubject
message = "use ContactMessage", actual val sender: TSender
replaceWith = ReplaceWith("ContactMessage", "net.mamoe.mirai.message.ContactMessage") actual val message: MessageChain
) actual val bot: Bot
@OptIn(MiraiInternalAPI::class, MiraiExperimentalAPI::class)
actual abstract class MessagePacket<TSender : User, TSubject : Contact> actual constructor() :
MessagePacketBase<TSender, TSubject>() {
// region 上传图片 // region 上传图片
@JvmSynthetic @JvmSynthetic
suspend inline fun uploadImage(image: BufferedImage): Image = subject.uploadImage(image) suspend inline fun uploadImage(image: BufferedImage): Image = subject.uploadImage(image)
@JvmSynthetic @JvmSynthetic
suspend inline fun uploadImage(image: URL): Image = subject.uploadImage(image) suspend inline fun uploadImage(image: URL): Image = subject.uploadImage(image)
@JvmSynthetic @JvmSynthetic
suspend inline fun uploadImage(image: Input): Image = subject.uploadImage(image) suspend inline fun uploadImage(image: Input): Image = subject.uploadImage(image)
@JvmSynthetic @JvmSynthetic
suspend inline fun uploadImage(image: InputStream): Image = subject.uploadImage(image) suspend inline fun uploadImage(image: InputStream): Image = subject.uploadImage(image)
@JvmSynthetic @JvmSynthetic
suspend inline fun uploadImage(image: File): Image = subject.uploadImage(image) suspend inline fun uploadImage(image: File): Image = subject.uploadImage(image)
// endregion // endregion
@ -58,12 +53,16 @@ actual abstract class MessagePacket<TSender : User, TSubject : Contact> actual c
// region 发送图片 // region 发送图片
@JvmSynthetic @JvmSynthetic
suspend inline fun sendImage(image: BufferedImage): MessageReceipt<TSubject> = subject.sendImage(image) suspend inline fun sendImage(image: BufferedImage): MessageReceipt<TSubject> = subject.sendImage(image)
@JvmSynthetic @JvmSynthetic
suspend inline fun sendImage(image: URL): MessageReceipt<TSubject> = subject.sendImage(image) suspend inline fun sendImage(image: URL): MessageReceipt<TSubject> = subject.sendImage(image)
@JvmSynthetic @JvmSynthetic
suspend inline fun sendImage(image: Input): MessageReceipt<TSubject> = subject.sendImage(image) suspend inline fun sendImage(image: Input): MessageReceipt<TSubject> = subject.sendImage(image)
@JvmSynthetic @JvmSynthetic
suspend inline fun sendImage(image: InputStream): MessageReceipt<TSubject> = subject.sendImage(image) suspend inline fun sendImage(image: InputStream): MessageReceipt<TSubject> = subject.sendImage(image)
@JvmSynthetic @JvmSynthetic
suspend inline fun sendImage(image: File): MessageReceipt<TSubject> = subject.sendImage(image) suspend inline fun sendImage(image: File): MessageReceipt<TSubject> = subject.sendImage(image)
// endregion // endregion
@ -71,12 +70,16 @@ actual abstract class MessagePacket<TSender : User, TSubject : Contact> actual c
// region 上传图片 (扩展) // region 上传图片 (扩展)
@JvmSynthetic @JvmSynthetic
suspend inline fun BufferedImage.upload(): Image = upload(subject) suspend inline fun BufferedImage.upload(): Image = upload(subject)
@JvmSynthetic @JvmSynthetic
suspend inline fun URL.uploadAsImage(): Image = uploadAsImage(subject) suspend inline fun URL.uploadAsImage(): Image = uploadAsImage(subject)
@JvmSynthetic @JvmSynthetic
suspend inline fun Input.uploadAsImage(): Image = uploadAsImage(subject) suspend inline fun Input.uploadAsImage(): Image = uploadAsImage(subject)
@JvmSynthetic @JvmSynthetic
suspend inline fun InputStream.uploadAsImage(): Image = uploadAsImage(subject) suspend inline fun InputStream.uploadAsImage(): Image = uploadAsImage(subject)
@JvmSynthetic @JvmSynthetic
suspend inline fun File.uploadAsImage(): Image = uploadAsImage(subject) suspend inline fun File.uploadAsImage(): Image = uploadAsImage(subject)
// endregion 上传图片 (扩展) // endregion 上传图片 (扩展)
@ -84,12 +87,16 @@ actual abstract class MessagePacket<TSender : User, TSubject : Contact> actual c
// region 发送图片 (扩展) // region 发送图片 (扩展)
@JvmSynthetic @JvmSynthetic
suspend inline fun BufferedImage.send(): MessageReceipt<TSubject> = sendTo(subject) suspend inline fun BufferedImage.send(): MessageReceipt<TSubject> = sendTo(subject)
@JvmSynthetic @JvmSynthetic
suspend inline fun URL.sendAsImage(): MessageReceipt<TSubject> = sendAsImageTo(subject) suspend inline fun URL.sendAsImage(): MessageReceipt<TSubject> = sendAsImageTo(subject)
@JvmSynthetic @JvmSynthetic
suspend inline fun Input.sendAsImage(): MessageReceipt<TSubject> = sendAsImageTo(subject) suspend inline fun Input.sendAsImage(): MessageReceipt<TSubject> = sendAsImageTo(subject)
@JvmSynthetic @JvmSynthetic
suspend inline fun InputStream.sendAsImage(): MessageReceipt<TSubject> = sendAsImageTo(subject) suspend inline fun InputStream.sendAsImage(): MessageReceipt<TSubject> = sendAsImageTo(subject)
@JvmSynthetic @JvmSynthetic
suspend inline fun File.sendAsImage(): MessageReceipt<TSubject> = sendAsImageTo(subject) suspend inline fun File.sendAsImage(): MessageReceipt<TSubject> = sendAsImageTo(subject)
// endregion 发送图片 (扩展) // endregion 发送图片 (扩展)