mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-10 02:20:14 +08:00
Merge remote-tracking branch 'origin'
This commit is contained in:
commit
5c287faf4e
@ -166,7 +166,7 @@ internal class QQImpl(
|
||||
}
|
||||
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate", "DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE")
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
internal class MemberImpl(
|
||||
qq: QQImpl,
|
||||
group: GroupImpl,
|
||||
@ -286,6 +286,20 @@ internal class MemberImpl(
|
||||
}
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = bot.hashCode()
|
||||
result = 31 * result + id.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
@Suppress("DuplicatedCode")
|
||||
override fun equals(other: Any?): Boolean { // 不要删除. trust me
|
||||
if (this === other) return true
|
||||
if (other !is Contact) return false
|
||||
if (this::class != other::class) return false
|
||||
return this.id == other.id && this.bot == other.bot
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "Member($id)"
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive
|
||||
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.io.core.discardExact
|
||||
@ -19,11 +19,10 @@ import net.mamoe.mirai.contact.MemberPermission
|
||||
import net.mamoe.mirai.data.MemberInfo
|
||||
import net.mamoe.mirai.data.MultiPacket
|
||||
import net.mamoe.mirai.data.Packet
|
||||
import net.mamoe.mirai.event.ListeningStatus
|
||||
import net.mamoe.mirai.event.events.BotJoinGroupEvent
|
||||
import net.mamoe.mirai.event.events.BotOfflineEvent
|
||||
import net.mamoe.mirai.event.events.MemberJoinEvent
|
||||
import net.mamoe.mirai.event.subscribe
|
||||
import net.mamoe.mirai.event.subscribingGetAsync
|
||||
import net.mamoe.mirai.message.FriendMessage
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
import net.mamoe.mirai.message.data.MessageSource
|
||||
@ -279,17 +278,14 @@ internal class MessageSvc {
|
||||
override val groupId: Long,
|
||||
override val sourceMessage: MessageChain
|
||||
) : MessageSource {
|
||||
lateinit var sequenceIdDeferred: CompletableDeferred<Int>
|
||||
lateinit var sequenceIdDeferred: Deferred<Int>
|
||||
|
||||
@UseExperimental(MiraiExperimentalAPI::class)
|
||||
fun startWaitingSequenceId(contact: Contact) {
|
||||
sequenceIdDeferred = CompletableDeferred()
|
||||
contact.subscribe<OnlinePush.PbPushGroupMsg.SendGroupMessageReceipt> { event ->
|
||||
if (event.messageRandom == messageUid.toInt()) {
|
||||
sequenceIdDeferred.complete(event.sequenceId)
|
||||
return@subscribe ListeningStatus.STOPPED
|
||||
}
|
||||
|
||||
return@subscribe ListeningStatus.LISTENING
|
||||
sequenceIdDeferred = contact.subscribingGetAsync<OnlinePush.PbPushGroupMsg.SendGroupMessageReceipt, Int> {
|
||||
if (it.messageRandom == messageUid.toInt()) {
|
||||
it.sequenceId
|
||||
} else null
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,6 +72,9 @@ interface Member : QQ, Contact {
|
||||
/**
|
||||
* 禁言.
|
||||
*
|
||||
* QQ 中最小操作和显示的时间都是一分钟.
|
||||
* 机器人可以实现精确到秒, 会被客户端显示为 1 分钟但不影响实际禁言时间.
|
||||
*
|
||||
* 管理员可禁言成员, 群主可禁言管理员和群员.
|
||||
*
|
||||
* @param durationSeconds 持续时间. 精确到秒. 范围区间表示为 `(0s, 30days]`. 超过范围则会抛出异常.
|
||||
|
@ -9,3 +9,104 @@
|
||||
|
||||
package net.mamoe.mirai.event
|
||||
|
||||
import kotlinx.coroutines.*
|
||||
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
|
||||
/**
|
||||
* 挂起当前协程, 监听这个事件, 并尝试从这个事件中获取一个值.
|
||||
*
|
||||
* 若 [filter] 抛出了一个异常, 本函数会立即抛出这个异常.
|
||||
*
|
||||
* @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制
|
||||
* @param filter 过滤器. 返回非 null 则代表得到了需要的值. [subscribingGet] 会返回这个值
|
||||
*
|
||||
* @see subscribingGetAsync 本函数的异步版本
|
||||
*/
|
||||
@MiraiExperimentalAPI
|
||||
suspend inline fun <reified E : Event, R : Any> subscribingGet(
|
||||
timeoutMillis: Long = -1,
|
||||
noinline filter: E.(E) -> R? // 不要 crossinline: crossinline 后 stacktrace 会不正常
|
||||
): R {
|
||||
require(timeoutMillis == -1L || timeoutMillis > 0) { "timeoutMillis must be -1 or > 0" }
|
||||
return subscribingGetOrNull(timeoutMillis, filter) ?: error("timeout subscribingGet")
|
||||
}
|
||||
|
||||
/**
|
||||
* 挂起当前协程, 监听这个事件, 并尝试从这个事件中获取一个值.
|
||||
*
|
||||
* 若 [filter] 抛出了一个异常, 本函数会立即抛出这个异常.
|
||||
*
|
||||
* @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制
|
||||
* @param filter 过滤器. 返回非 null 则代表得到了需要的值. [subscribingGet] 会返回这个值
|
||||
*
|
||||
* @see subscribingGetAsync 本函数的异步版本
|
||||
*/
|
||||
@MiraiExperimentalAPI
|
||||
suspend inline fun <reified E : Event, R : Any> subscribingGetOrNull(
|
||||
timeoutMillis: Long = -1,
|
||||
noinline filter: E.(E) -> R? // 不要 crossinline: crossinline 后 stacktrace 会不正常
|
||||
): R? {
|
||||
require(timeoutMillis == -1L || timeoutMillis > 0) { "timeoutMillis must be -1 or > 0" }
|
||||
var result: R? = null
|
||||
var resultThrowable: Throwable? = null
|
||||
|
||||
if (timeoutMillis == -1L) {
|
||||
@Suppress("DuplicatedCode") // for better performance
|
||||
coroutineScope {
|
||||
var listener: Listener<E>? = null
|
||||
listener = this.subscribe {
|
||||
val value = try {
|
||||
filter.invoke(this, it)
|
||||
} catch (e: Exception) {
|
||||
resultThrowable = e
|
||||
return@subscribe ListeningStatus.STOPPED.also { listener!!.complete() }
|
||||
}
|
||||
|
||||
if (value != null) {
|
||||
result = value
|
||||
return@subscribe ListeningStatus.STOPPED.also { listener!!.complete() }
|
||||
} else return@subscribe ListeningStatus.LISTENING
|
||||
}
|
||||
}
|
||||
} else {
|
||||
withTimeoutOrNull(timeoutMillis) {
|
||||
var listener: Listener<E>? = null
|
||||
@Suppress("DuplicatedCode") // for better performance
|
||||
listener = this.subscribe {
|
||||
val value = try {
|
||||
filter.invoke(this, it)
|
||||
} catch (e: Exception) {
|
||||
resultThrowable = e
|
||||
return@subscribe ListeningStatus.STOPPED.also { listener!!.complete() }
|
||||
}
|
||||
|
||||
if (value != null) {
|
||||
result = value
|
||||
return@subscribe ListeningStatus.STOPPED.also { listener!!.complete() }
|
||||
} else return@subscribe ListeningStatus.LISTENING
|
||||
}
|
||||
}
|
||||
}
|
||||
resultThrowable?.let { throw it }
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步监听这个事件, 并尝试从这个事件中获取一个值.
|
||||
*
|
||||
* 若 [filter] 抛出了一个异常, [Deferred.await] 会抛出这个异常或.
|
||||
*
|
||||
* @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制
|
||||
* @param coroutineContext 额外的 [CoroutineContext]
|
||||
* @param filter 过滤器. 返回非 null 则代表得到了需要的值. [subscribingGet] 会返回这个值
|
||||
*/
|
||||
@MiraiExperimentalAPI
|
||||
inline fun <reified E : Event, R : Any> CoroutineScope.subscribingGetAsync(
|
||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||
timeoutMillis: Long = -1,
|
||||
noinline filter: E.(E) -> R? // 不要 crossinline: crossinline 后 stacktrace 会不正常
|
||||
): Deferred<R> = this.async(coroutineContext) {
|
||||
subscribingGet(timeoutMillis, filter)
|
||||
}
|
@ -101,6 +101,9 @@ interface Listener<in E : Event> : CompletableJob {
|
||||
*
|
||||
* @param coroutineContext 给事件监听协程的额外的 [CoroutineContext]
|
||||
*
|
||||
* @see subscribingGet 监听一个事件, 并尝试从这个事件中获取一个值.
|
||||
* @see subscribingGetAsync 异步监听一个事件, 并尝试从这个事件中获取一个值.
|
||||
*
|
||||
* @see subscribeAlways 一直监听
|
||||
* @see subscribeOnce 只监听一次
|
||||
*
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
package net.mamoe.mirai.message
|
||||
|
||||
import kotlinx.coroutines.Job
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.contact.*
|
||||
import net.mamoe.mirai.event.Event
|
||||
@ -44,25 +45,25 @@ class GroupMessage(
|
||||
* 对于好友消息事件, 这个方法将会给好友 ([subject]) 发送消息
|
||||
* 对于群消息事件, 这个方法将会给群 ([subject]) 发送消息
|
||||
*/
|
||||
suspend inline fun quoteReply(message: MessageChain) = reply(this.message.quote() + message)
|
||||
suspend inline fun quoteReply(message: MessageChain): MessageReceipt<Group> = reply(this.message.quote() + message)
|
||||
|
||||
suspend inline fun quoteReply(message: Message) = reply(this.message.quote() + message)
|
||||
suspend inline fun quoteReply(plain: String) = reply(this.message.quote() + plain)
|
||||
suspend inline fun quoteReply(message: Message): MessageReceipt<Group> = reply(this.message.quote() + message)
|
||||
suspend inline fun quoteReply(plain: String): MessageReceipt<Group> = reply(this.message.quote() + plain)
|
||||
|
||||
|
||||
@JvmName("reply2")
|
||||
suspend inline fun String.quoteReply() = quoteReply(this)
|
||||
suspend inline fun String.quoteReply(): MessageReceipt<Group> = quoteReply(this)
|
||||
|
||||
@JvmName("reply2")
|
||||
suspend inline fun Message.quoteReply() = quoteReply(this)
|
||||
suspend inline fun Message.quoteReply(): MessageReceipt<Group> = quoteReply(this)
|
||||
|
||||
@JvmName("reply2")
|
||||
suspend inline fun MessageChain.quoteReply() = quoteReply(this)
|
||||
suspend inline fun MessageChain.quoteReply(): MessageReceipt<Group> = quoteReply(this)
|
||||
|
||||
suspend inline fun MessageChain.recall() = group.recall(this)
|
||||
suspend inline fun MessageSource.recall() = group.recall(this)
|
||||
inline fun MessageSource.recallIn(delay: Long) = group.recallIn(this, delay)
|
||||
inline fun MessageChain.recallIn(delay: Long) = group.recallIn(this, delay)
|
||||
inline fun MessageSource.recallIn(delay: Long): Job = group.recallIn(this, delay)
|
||||
inline fun MessageChain.recallIn(delay: Long): Job = group.recallIn(this, delay)
|
||||
|
||||
override fun toString(): String =
|
||||
"GroupMessage(group=${group.id}, senderName=$senderName, sender=${sender.id}, permission=${permission.name}, message=$message)"
|
||||
|
@ -21,6 +21,8 @@ import net.mamoe.mirai.contact.Member
|
||||
import net.mamoe.mirai.contact.QQ
|
||||
import net.mamoe.mirai.data.Packet
|
||||
import net.mamoe.mirai.event.events.BotEvent
|
||||
import net.mamoe.mirai.event.subscribingGet
|
||||
import net.mamoe.mirai.event.subscribingGetAsync
|
||||
import net.mamoe.mirai.message.data.*
|
||||
import net.mamoe.mirai.utils.*
|
||||
import kotlin.jvm.JvmName
|
||||
@ -109,6 +111,10 @@ abstract class MessagePacketBase<TSender : QQ, TSubject : Contact>(_bot: Bot) :
|
||||
suspend inline fun String.send() = this.toMessage().sendTo(subject)
|
||||
// endregion
|
||||
|
||||
operator fun <M : Message> get(at: Message.Key<M>): M {
|
||||
return this.message[at]
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 @ 这个账号的消息. 当且仅当消息为群消息时可用. 否则将会抛出 [IllegalArgumentException]
|
||||
*/
|
||||
@ -134,4 +140,47 @@ abstract class MessagePacketBase<TSender : QQ, TSubject : Contact>(_bot: Bot) :
|
||||
*/
|
||||
suspend inline fun Image.download(): ByteReadPacket = bot.run { download() }
|
||||
// endregion
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断两个 [MessagePacket] 的 [MessagePacket.sender] 和 [MessagePacket.subject] 是否相同
|
||||
*/
|
||||
fun MessagePacket<*, *>.isContextIdenticalWith(another: MessagePacket<*, *>): Boolean {
|
||||
return this.sender == another.sender && this.subject == another.subject
|
||||
}
|
||||
|
||||
/**
|
||||
* 挂起当前协程, 等待下一条 [MessagePacket.sender] 和 [MessagePacket.subject] 与 [P] 相同且通过 [筛选][filter] 的 [MessagePacket]
|
||||
*
|
||||
* 若 [filter] 抛出了一个异常, 本函数会立即抛出这个异常.
|
||||
*
|
||||
* @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制
|
||||
* @param filter 过滤器. 返回非 null 则代表得到了需要的值. [subscribingGet] 会返回这个值
|
||||
*
|
||||
* @see subscribingGetAsync 本函数的异步版本
|
||||
*/
|
||||
suspend inline fun <reified P : MessagePacket<*, *>> P.nextMessage(
|
||||
timeoutMillis: Long = -1,
|
||||
crossinline filter: P.(P) -> Boolean
|
||||
): P {
|
||||
return subscribingGet<P, P>(timeoutMillis) {
|
||||
takeIf { this.isContextIdenticalWith(this@nextMessage) }?.takeIf { filter(it, it) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 挂起当前协程, 等待下一条 [MessagePacket.sender] 和 [MessagePacket.subject] 与 [P] 相同的 [MessagePacket]
|
||||
*
|
||||
* 若 [filter] 抛出了一个异常, 本函数会立即抛出这个异常.
|
||||
*
|
||||
* @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制
|
||||
*
|
||||
* @see subscribingGetAsync 本函数的异步版本
|
||||
*/
|
||||
suspend inline fun <reified P : MessagePacket<*, *>> P.nextMessage(
|
||||
timeoutMillis: Long = -1
|
||||
): P {
|
||||
return subscribingGet<P, P>(timeoutMillis) {
|
||||
takeIf { this.isContextIdenticalWith(this@nextMessage) }
|
||||
}
|
||||
}
|
@ -16,17 +16,14 @@ import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.BotAccount
|
||||
import net.mamoe.mirai.alsoLogin
|
||||
import net.mamoe.mirai.contact.QQ
|
||||
import net.mamoe.mirai.contact.isOperator
|
||||
import net.mamoe.mirai.contact.sendMessage
|
||||
import net.mamoe.mirai.event.*
|
||||
import net.mamoe.mirai.message.FriendMessage
|
||||
import net.mamoe.mirai.message.GroupMessage
|
||||
import net.mamoe.mirai.message.data.AtAll
|
||||
import net.mamoe.mirai.message.data.Image
|
||||
import net.mamoe.mirai.message.data.PlainText
|
||||
import net.mamoe.mirai.message.data.firstOrNull
|
||||
import net.mamoe.mirai.message.data.*
|
||||
import net.mamoe.mirai.message.nextMessage
|
||||
import net.mamoe.mirai.message.sendAsImageTo
|
||||
import net.mamoe.mirai.qqandroid.Bot
|
||||
import net.mamoe.mirai.qqandroid.QQAndroid
|
||||
import net.mamoe.mirai.utils.FileBasedDeviceInfo
|
||||
import net.mamoe.mirai.utils.MiraiInternalAPI
|
||||
import java.io.File
|
||||
@ -49,7 +46,7 @@ private fun readTestAccount(): BotAccount? {
|
||||
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
suspend fun main() {
|
||||
val bot = QQAndroid.Bot( // JVM 下也可以不写 `QQAndroid.` 引用顶层函数
|
||||
val bot = Bot( // JVM 下也可以不写 `QQAndroid.` 引用顶层函数
|
||||
123456789,
|
||||
"123456"
|
||||
) {
|
||||
@ -207,6 +204,25 @@ fun Bot.messageDSL() {
|
||||
// sender: QQ
|
||||
// it: String (来自 MessageChain.toString)
|
||||
// group: Group
|
||||
|
||||
case("recall") {
|
||||
reply("😎").recallIn(3000) // 3 秒后自动撤回这条消息
|
||||
}
|
||||
|
||||
case("禁言") {
|
||||
// 挂起当前协程, 等待下一条满足条件的消息.
|
||||
// 发送 "禁言" 后需要再发送一条消息 at 一个人.
|
||||
val value: At = nextMessage { message.any(At) }[At]
|
||||
value.member().mute(10)
|
||||
}
|
||||
|
||||
startsWith("群名=") {
|
||||
if (!sender.isOperator()) {
|
||||
sender.mute(5)
|
||||
return@startsWith
|
||||
}
|
||||
group.name = it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user