mirror of
https://github.com/mamoe/mirai.git
synced 2025-03-03 15:10:14 +08:00
Powerful subscribers
This commit is contained in:
parent
0a471e9b31
commit
de86041d44
309
README.md
309
README.md
@ -1,64 +1,287 @@
|
||||
# Mirai
|
||||
[](http://hits.dwyl.io/him188/mamoe/mirai) [](https://www.codacy.com/manual/Him188/mirai?utm_source=github.com&utm_medium=referral&utm_content=mamoe/mirai&utm_campaign=Badge_Grade)
|
||||
|
||||
一个以 **TIM PC协议(非web)** 驱动的跨平台QQ机器人服务端核心, 虽然目前仅支持 JVM
|
||||
采用服务端-插件模式运行,同时提供独立的跨平台核心库.
|
||||
Mirai 的所有模块均开源
|
||||
一个以 **TIM PC协议(非web)** 驱动的跨平台开源 QQ 机器人服务端核心, 目前仅支持 JVM
|
||||
Mirai 在 JVM 平台采用插件模式运行,同时提供独立的跨平台核心库.
|
||||
未来会在 Native(Win32) 平台提供目前比较流行的几种机器人软件的 API 转接
|
||||
|
||||
项目处于开发阶段, 还有很多未完善的地方. 欢迎任何的代码贡献, 或是 issue.
|
||||
若您有任何意见或建议, 欢迎提交 issue.
|
||||
|
||||
部分协议来自网络上开源项目
|
||||
|
||||
**一切开发旨在学习,请勿用于非法用途**
|
||||
|
||||
## 抢先体验
|
||||
核心框架结构已经开发完毕,一些核心功能也测试完成。
|
||||
仅需几分钟就可以测试 Mirai.
|
||||
## Try
|
||||
|
||||
现在您可以开始体验低付出高效率的 Mirai
|
||||
|
||||
目前还没有写构建,请使用 IDE 运行单个 main 函数。
|
||||
1. Clone
|
||||
2. Import as Gradle project
|
||||
3. Run demo main [Demo 1 Main](mirai-demos/mirai-demo-1/src/main/java/demo1/Main.kt#L22)
|
||||
3. Run demo main [Demo 1 Main](mirai-demos/mirai-demo-1/src/main/java/demo/subscribe/SubscribeSamples.kt)
|
||||
|
||||
### 事件
|
||||
**转到[开发文档](#Development-Guide---Kotlin)**
|
||||
|
||||
#### 使用 Kotlin
|
||||
这里只演示进行不终止地监听。
|
||||
##### Top-level reified
|
||||
多数情况下这是最好的方式。
|
||||
## Update log
|
||||
|
||||
- 发送好友/群消息(10/14)
|
||||
- 接受解析好友消息(10/14)
|
||||
- 接收解析群消息(10/14)
|
||||
- 成员昵称(10/18)
|
||||
- 成员权限(10/18, 计划优化)
|
||||
- 好友在线状态改变(10/14)
|
||||
- Android客户端上线/下线(10/18)
|
||||
- 上传并发送好友/群图片(10/21, 10/26)
|
||||
|
||||
计划中: 添加好友
|
||||
|
||||
## Requirements
|
||||
|
||||
所有平台:
|
||||
- Kotlin 1.3.50
|
||||
|
||||
JVM 平台:
|
||||
- Java 8
|
||||
|
||||
#### Libraries used
|
||||
Mirai 使用以下开源库:
|
||||
- kotlin-stdlib
|
||||
- kotlinx-coroutines
|
||||
- kotlinx-io
|
||||
- kotlin-reflect
|
||||
- pcap4j
|
||||
- atomicfu
|
||||
- ktor
|
||||
- klock
|
||||
- tornadofx
|
||||
- javafx
|
||||
|
||||
## Development Guide - Kotlin
|
||||
|
||||
平台通用开发帮助(不含协议层).
|
||||
|
||||
您需要有一定 Kotlin 基础才能读懂以下内容.
|
||||
若您对本文档有建议, 请告诉我们
|
||||
|
||||
目录:
|
||||
- [Introduction](#Introduction) Mirai 介绍
|
||||
- [Modules](#Modules) 模块介绍
|
||||
- [mirai-core](#mirai-core) 核心模块
|
||||
- [mirai-console](#mirai-console) JVM 控制台
|
||||
- [mirai-demo](#mirai-demo) 示例和演示程序
|
||||
- [mirai-debug](#mirai-debug) 抓包工具和分析工具\
|
||||
- [Logger](#Logger) 日志系统
|
||||
- [Bot](#Bot) 机器人类
|
||||
- [Contact](#Contact) 联系人
|
||||
- [Message](#Message) 消息
|
||||
- [MessageChain](#MessageChain) `MessageChain`
|
||||
- [Types](#Types) 消息类型
|
||||
- [Operators](#Operators) `Message` 一般用法
|
||||
- [Extensions](#Extensions) `Message` 的常用扩展方法
|
||||
- [Image](#Image) 图片
|
||||
- [Image JVM](#Image-JVM) JVM 平台扩展实现
|
||||
- [Event](#Event) 事件
|
||||
- [Subscription](#Subscription) 事件监听(订阅)
|
||||
- [Message Event](#Message-Event) 针对消息事件的订阅实现
|
||||
|
||||
### Introduction
|
||||
|
||||
Mirai 目前为快速流转(Moving fast)状态, 增量版本之间可能不具有兼容性,任何功能都可能在没有警告的情况下添加、删除或者更改。
|
||||
|
||||
### Modules
|
||||
Mirai 的模块组成
|
||||
|
||||
#### mirai-core
|
||||
Mirai 的核心部分.
|
||||
|
||||
- 独立的跨平台设计, 可以被以库的形式内置在任意项目内.
|
||||
- 现有 JVM 支持
|
||||
- 未来计划 Android, Native 支持
|
||||
|
||||
#### mirai-console
|
||||
- 仅 JVM 平台
|
||||
- 仅命令行
|
||||
- Jar 插件支持
|
||||
|
||||
#### mirai-demo
|
||||
Samples and demos.
|
||||
目前仅有 [SubscribeSamples](mirai-demos/mirai-demo-1/src/main/java/demo/subscribe/SubscribeSamples.kt)
|
||||
|
||||
#### mirai-debug
|
||||
抓包工具和分析工具. 不会进行稳定性维护.
|
||||
|
||||
- 抓包自动解密和分析
|
||||
- Hex 着色比较器
|
||||
- GUI Hex 调试器(值转换)
|
||||
|
||||
### Logger
|
||||
[Contact](mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/MiraiLogger.kt)
|
||||
Mirai 维护跨平台日志系统, 针对平台的实现为 `expect class PlatformLogger`,
|
||||
一般推荐使用顶层的 `var DefaultLogger: (identity: String?) -> PlatformLogger` 通过 `DefaultLogger( ... )` 来创建日志记录器.
|
||||
每个 `Bot` 都拥有一个日志记录器, 可通过 `Bot.logger` 获取
|
||||
|
||||
-日志记录尚不完善, 以后可能会修改-
|
||||
|
||||
### Bot
|
||||
[Bot](mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt) 为机器人
|
||||
一个机器人实例只有一个账号.
|
||||
一个机器人实例由多个模块构成.
|
||||
- `BotNetworkHandler` (管理所有网络方面事务, 本文不介绍)
|
||||
- `ContactSystem` (管理联系人, 维护一个 `QQ` 列表和一个 `Group` 列表)
|
||||
|
||||
Mirai 能同时维护多个机器人账号.
|
||||
|
||||
[BotHelper](mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotHelper.kt) 中存在一些快捷方法
|
||||
|
||||
### Contact
|
||||
[Contact](mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt) 为联系人.
|
||||
虽是联系人, 但它包含 `QQ` 和 `Group`.
|
||||
联系人并不是独立的, 它必须隶属于某个 `Bot`
|
||||
|
||||
**共有方法**:
|
||||
- `sendMessage`(`String`|`Message`|`MessageChain`)
|
||||
|
||||
**共有属性**:
|
||||
- id (即 QQ 号和群号)
|
||||
|
||||
注: 为减少出错概率, 联系人的 `id` 均使用无符号整型 `UInt`, 这是 Kotlin 1.3 的一个实验性类型
|
||||
我们建议您在开发中也使用 `UInt`, 以避免产生一些难以发现的问题
|
||||
|
||||
### Message
|
||||
Mirai 中所有的消息均为对象化的 [Message](mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/Message.kt)
|
||||
实际上, 所有的 `Message` 都是 `inline class`, 保证无性能损失的前提下又不失使用的严谨性和便捷性.
|
||||
`Message` 有大量扩展和相关函数. 本文只介绍使用较多的一部分. 其他函数您也将会在实际开发中通过注释指引了解到.
|
||||
|
||||
#### MessageChain
|
||||
|
||||
一条消息为一个 `MessageChain` 对象.
|
||||
`MessageChain` 也是 `Message` 的一种
|
||||
`MessageChain` 实现 `MutableList` 接口.
|
||||
它有多种实现:
|
||||
- `inline class MessageChainImpl` 通常的 `MutableList<Message>` 实现
|
||||
- `inline class SingleMessageChain` 单个消息的不可变代表包装
|
||||
- `object NullMessageChain` 空的不可变实现. 用于替代 `null` 情况
|
||||
|
||||
仅 `NullMessageChain` 是公开(public)的. 在开发中无需考虑另外两个的存在, 他们将会在 Mirai 内部合适地使用.
|
||||
|
||||
#### Types
|
||||
现支持的消息类型:
|
||||
- `PlainText` 纯文本
|
||||
- `Image` 图片 (将会有独立章节来说明图片的上传等)
|
||||
- `Face` 表情 (QQ 自带表情)
|
||||
|
||||
计划中:
|
||||
- `At` (仅限群, 将会被 QQ 显示为蓝色的连接)
|
||||
- `XML`
|
||||
- `File` (文件上传)
|
||||
|
||||
#### Operators
|
||||
|
||||
| 操作表示 | 说明 |
|
||||
|---| ---|
|
||||
| Message + Message | 连接 `Message`, 得到 `MessageChain` |
|
||||
| Message + String | 连接 `Message` 与 `String`(`PlainText`) 为 `MessageChain` |
|
||||
| Message eq String | 可读字符串如 "\[@10000\]" 判断 |
|
||||
| String in Message | 内容包含判断 |
|
||||
|
||||
#### Extensions
|
||||
|
||||
| 扩展方法 | 说明 |
|
||||
|---| ---|
|
||||
|String.toChain():MessageChain| PlainText(this) |
|
||||
|Message.toChain():MessageChain| 构造上文提到的 SingleMessageChain |
|
||||
|suspend Message.sendTo(Contact)| 发送给联系人 |
|
||||
|
||||
### Image
|
||||
考虑到协议需求和内存消耗, Mirai 的所有 API 均使用 [ExternalImage](mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/ExternalImage.kt)
|
||||
`ExternalImage` 包含图片长宽、大小、格式、文件数据
|
||||
您只需通过扩展函数处理图片.
|
||||
|
||||
| 扩展函数 | 说明 |
|
||||
|---| ---|
|
||||
|suspend ExternalImage.sendTo(Contact)| 上传图片并以纯图片消息发送给联系人 |
|
||||
|suspend ExternalImage.upload():Image | 上传图片并得到 [Image] 消息 |
|
||||
|suspend Contact.sendImage(ExternalImage) | 上传图片并发送给指定联系人 |
|
||||
|
||||
注: 使用 `upload` 而不是 `toMessage` 作为函数名是为了强调它是一个耗时的过程.
|
||||
|
||||
#### Image JVM
|
||||
|
||||
对于 JVM 平台, Mirai 提供额外的足以应对大多数情况的扩展函数:
|
||||
[ExternalImageJvm](mirai-core/src/jvmMain/kotlin/net.mamoe.mirai/utils/ExternalImageJvm.kt)
|
||||
若有必要, 这些函数将会创建临时文件以避免使用内存缓存图片
|
||||
一下内容中, `IMAGE` 可替换为 `ExternalImage`, `BufferedImage`, `File`, `InputStream`, `URL` 或 `Input` (来自 `kotlinx.io`)
|
||||
|
||||
转为 `ExternalImage`
|
||||
- `suspend IMAGE.toExternalImage():ExternalImage`
|
||||
|
||||
直接发送
|
||||
- `suspend IMAGE.sendTo(Contact)`
|
||||
- `suspend Contact.sendImage(IMAGE)`
|
||||
|
||||
转为 Message
|
||||
- `suspend IMAGE.upload(Contact)`
|
||||
- `suspend Contact.upload(IMAGE)`
|
||||
|
||||
只要语义上正确的函数, 在 Mirai 都是可行的.
|
||||
|
||||
### Event
|
||||
|
||||
#### Subscription
|
||||
|
||||
[查看相关监听代码](mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribers.kt)
|
||||
|
||||
您可以通过顶层 (top-level) 方法 `subscribeXXX` 对某个事件进行监听, 其中 `XXX` 可以是
|
||||
- Always (不断监听)
|
||||
- Once (一次监听)
|
||||
- Until / While (条件监听)
|
||||
|
||||
例:
|
||||
```kotlin
|
||||
inline fun <reified E: Event> subscribeAlways(handler: (E) -> Unit)
|
||||
|
||||
subscribeAlways<FriendMessageEvent>{
|
||||
//it: FriendMessageEvent
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
#### Message Event
|
||||
|
||||
### 图片测试
|
||||
现在可以接收图片消息(并解析为消息链):
|
||||

|
||||

|
||||
对于消息事件, Mirai 还提供了更强大的 DSL 监听方式.
|
||||
[MessageSubscribersBuilder](mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/MessageSubscribers.kt#L140)
|
||||
可用条件方法为:
|
||||
- case (内容相等)
|
||||
- contains
|
||||
- startsWith
|
||||
- endsWith
|
||||
- sentBy (特定发送者)
|
||||
|
||||
上传发送图片已经完成, 您可以在 Demo 中找到发送方式.
|
||||
机器人可以转发图片消息.详情查看 [Image.kt](mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/Message.kt#L81)
|
||||
|
||||
## 现已支持
|
||||
|
||||
- 发送好友/群消息(10/14)
|
||||
- 接受解析好友消息(10/14)
|
||||
- 接收解析群消息(10/14)
|
||||
- 成员权限, 昵称(10/18)
|
||||
- 好友在线状态改变(10/14)
|
||||
- Android客户端上线/下线(10/18)
|
||||
- 上传并发送好友/群图片(10/26)
|
||||
|
||||
## 使用方法
|
||||
### 要求
|
||||
- Kotlin 1.3+
|
||||
#### 用于 JVM 平台
|
||||
- Java 8
|
||||
## 插件开发
|
||||
``` text
|
||||
to be continued
|
||||
...
|
||||
```kotlin
|
||||
// 监听所有群和好友消息
|
||||
subscribeMessages {// this: MessageSubscribersBuilder
|
||||
case("你好"){
|
||||
// this: SenderAndMessage
|
||||
// message: MessageChain
|
||||
// sender: QQ
|
||||
// it: String (来自 MessageChain.toString)
|
||||
// group: Group (如果是群消息)
|
||||
reply("你好!")// reply将发送给这个事件的主体(群消息的群, 好友消息的好友)
|
||||
}
|
||||
|
||||
replyCase("你好"){ "你好!" } // lambda 的返回值将会作为回复消息
|
||||
|
||||
"Hello" reply "World" // 收到 "Hello" 回复 "World"
|
||||
}
|
||||
```
|
||||
|
||||
当然, 您也可以仅监听来自群或好友的消息
|
||||
```kotlin
|
||||
// 监听所有好友消息
|
||||
subscribeFriendMessages { }
|
||||
//监听所有群消息
|
||||
subscribeGroupMessages { }
|
||||
```
|
||||
|
||||
另外, 由于 Mirai 可同时维护多个机器人账号, Mirai 也提供了对单个机器人的事件的监听.
|
||||
为了限制只监听来自某个机器人账号的事件, 您只需要在 `subscribeMessages` 前添加 `bot.` 将其修改为调用扩展方法.
|
||||
例:
|
||||
```kotlin
|
||||
bot.subscribeMessages { }
|
||||
```
|
@ -13,6 +13,7 @@ import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult
|
||||
import net.mamoe.mirai.utils.BotNetworkConfiguration
|
||||
import net.mamoe.mirai.utils.DefaultLogger
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
import net.mamoe.mirai.utils.internal.coerceAtLeastOrFail
|
||||
import net.mamoe.mirai.utils.log
|
||||
import kotlin.jvm.JvmOverloads
|
||||
|
||||
@ -52,7 +53,7 @@ data class BotAccount(
|
||||
* @see net.mamoe.mirai.contact.Contact
|
||||
*/
|
||||
class Bot(val account: BotAccount, val logger: MiraiLogger) {
|
||||
constructor(id: UInt, password: String) : this(BotAccount(id, password))
|
||||
constructor(qq: UInt, password: String) : this(BotAccount(qq, password))
|
||||
constructor(account: BotAccount) : this(account, DefaultLogger("Bot(" + account.id + ")"))
|
||||
|
||||
val contacts = ContactSystem()
|
||||
@ -131,8 +132,12 @@ class Bot(val account: BotAccount, val logger: MiraiLogger) {
|
||||
}
|
||||
}
|
||||
|
||||
suspend inline fun Int.qq(): QQ = getQQ(this.coerceAtLeastOrFail(0).toUInt())
|
||||
suspend inline fun Long.qq(): QQ = getQQ(this.coerceAtLeastOrFail(0))
|
||||
suspend inline fun UInt.qq(): QQ = getQQ(this)
|
||||
|
||||
suspend inline fun Int.group(): Group = getGroup(this.coerceAtLeastOrFail(0).toUInt())
|
||||
suspend inline fun Long.group(): Group = getGroup(this.coerceAtLeastOrFail(0))
|
||||
suspend inline fun UInt.group(): Group = getGroup(GroupId(this))
|
||||
suspend inline fun GroupId.group(): Group = getGroup(this)
|
||||
suspend inline fun GroupInternalId.group(): Group = getGroup(this)
|
||||
|
@ -9,14 +9,19 @@ import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult
|
||||
import net.mamoe.mirai.network.session
|
||||
import net.mamoe.mirai.utils.BotNetworkConfiguration
|
||||
import net.mamoe.mirai.utils.internal.PositiveNumbers
|
||||
import net.mamoe.mirai.utils.internal.coerceAtLeastOrFail
|
||||
|
||||
/*
|
||||
* 在 [Bot] 中的方法的捷径
|
||||
*/
|
||||
|
||||
//Contacts
|
||||
suspend inline fun Bot.getQQ(@PositiveNumbers number: Long): QQ = this.contacts.getQQ(number.coerceAtLeastOrFail(0).toUInt())
|
||||
suspend inline fun Bot.getQQ(number: UInt): QQ = this.contacts.getQQ(number)
|
||||
|
||||
suspend inline fun Bot.getGroup(id: UInt): Group = this.contacts.getGroup(GroupId(id))
|
||||
suspend inline fun Bot.getGroup(@PositiveNumbers id: Long): Group = this.contacts.getGroup(GroupId(id.coerceAtLeastOrFail(0).toUInt()))
|
||||
suspend inline fun Bot.getGroup(id: GroupId): Group = this.contacts.getGroup(id)
|
||||
suspend inline fun Bot.getGroup(internalId: GroupInternalId): Group = this.contacts.getGroup(internalId)
|
||||
|
||||
|
@ -27,12 +27,14 @@ sealed class Contact(val bot: Bot, val id: UInt) {
|
||||
abstract suspend fun sendMessage(message: MessageChain)
|
||||
|
||||
abstract suspend fun sendXMLMessage(message: String)
|
||||
|
||||
|
||||
//这两个方法写在 Contact 里面更适合. 因为 import 不便
|
||||
suspend fun sendMessage(plain: String) = sendMessage(PlainText(plain))
|
||||
|
||||
suspend fun sendMessage(message: Message) = sendMessage(message.toChain())
|
||||
}
|
||||
|
||||
suspend fun Contact.sendMessage(plain: String) = sendMessage(PlainText(plain))
|
||||
suspend fun Contact.sendMessage(message: Message) = sendMessage(message.toChain())
|
||||
|
||||
|
||||
/**
|
||||
* 一般的用户可见的 ID.
|
||||
* 在 TIM/QQ 客户端中所看到的的号码均是这个 ID.
|
||||
|
@ -0,0 +1,171 @@
|
||||
@file:Suppress("EXPERIMENTAL_API_USAGE", "MemberVisibilityCanBePrivate", "unused")
|
||||
|
||||
package net.mamoe.mirai.event
|
||||
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.contact.Group
|
||||
import net.mamoe.mirai.contact.QQ
|
||||
import net.mamoe.mirai.event.events.BotEvent
|
||||
import net.mamoe.mirai.event.events.FriendMessageEvent
|
||||
import net.mamoe.mirai.event.events.GroupMessageEvent
|
||||
import net.mamoe.mirai.message.*
|
||||
import kotlin.jvm.JvmName
|
||||
|
||||
/**
|
||||
* 消息事件时创建的临时容器.
|
||||
* @see
|
||||
*/
|
||||
abstract class SenderAndMessage(
|
||||
val sender: QQ,
|
||||
val message: MessageChain
|
||||
) {
|
||||
/**
|
||||
* 给这个消息事件的主体发送消息
|
||||
* 对于好友消息事件, 这个方法将会给好友 ([sender]) 发送消息
|
||||
* 对于群消息事件, 这个方法将会给群 ([sender]) 发送消息
|
||||
*/
|
||||
abstract suspend fun reply(message: MessageChain)
|
||||
|
||||
suspend fun reply(plain: String) = reply(PlainText(plain))
|
||||
suspend fun reply(message: Message) = reply(message.toChain())
|
||||
}
|
||||
|
||||
class FriendSenderAndMessage(
|
||||
sender: QQ,
|
||||
message: MessageChain
|
||||
) : SenderAndMessage(sender, message) {
|
||||
override suspend fun reply(message: MessageChain) = sender.sendMessage(message)
|
||||
}
|
||||
|
||||
class GroupSenderAndMessage(
|
||||
val group: Group,
|
||||
sender: QQ,
|
||||
message: MessageChain
|
||||
) : SenderAndMessage(sender, message) {
|
||||
override suspend fun reply(message: MessageChain) = group.sendMessage(message)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 订阅来自所有 [Bot] 的所有联系人的消息事件. 联系人可以是任意群或任意好友或临时会话.
|
||||
*/
|
||||
@MessageListenerDsl
|
||||
suspend inline fun subscribeMessages(noinline listeners: suspend MessageSubscribersBuilder<SenderAndMessage>.() -> Unit) {
|
||||
MessageSubscribersBuilder<SenderAndMessage> { listener ->
|
||||
subscribeAlways<BotEvent> {
|
||||
when (it) {
|
||||
is FriendMessageEvent -> listener(FriendSenderAndMessage(it.sender, it.message))
|
||||
is GroupMessageEvent -> listener(GroupSenderAndMessage(it.group, it.sender, it.message))
|
||||
}
|
||||
}
|
||||
}.apply { listeners() }
|
||||
}
|
||||
|
||||
/**
|
||||
* 订阅来自所有 [Bot] 的所有群消息事件
|
||||
*/
|
||||
@MessageListenerDsl
|
||||
suspend inline fun subscribeGroupMessages(noinline listeners: suspend MessageSubscribersBuilder<GroupSenderAndMessage>.() -> Unit) {
|
||||
MessageSubscribersBuilder<GroupSenderAndMessage> { listener ->
|
||||
subscribeAlways<GroupMessageEvent> {
|
||||
listener(GroupSenderAndMessage(it.group, it.sender, it.message))
|
||||
}
|
||||
}.apply { listeners() }
|
||||
}
|
||||
|
||||
/**
|
||||
* 订阅来自所有 [Bot] 的所有好友消息事件
|
||||
*/
|
||||
@MessageListenerDsl
|
||||
suspend inline fun subscribeFriendMessages(noinline listeners: suspend MessageSubscribersBuilder<FriendSenderAndMessage>.() -> Unit) {
|
||||
MessageSubscribersBuilder<FriendSenderAndMessage> { listener ->
|
||||
subscribeAlways<FriendMessageEvent> {
|
||||
listener(FriendSenderAndMessage(it.sender, it.message))
|
||||
}
|
||||
}.apply { listeners() }
|
||||
}
|
||||
|
||||
/**
|
||||
* 订阅来自这个 [Bot] 的所有联系人的消息事件. 联系人可以是任意群或任意好友或临时会话.
|
||||
*/
|
||||
@MessageListenerDsl
|
||||
suspend inline fun Bot.subscribeMessages(noinline listeners: suspend MessageSubscribersBuilder<SenderAndMessage>.() -> Unit) {
|
||||
MessageSubscribersBuilder<SenderAndMessage> { listener ->
|
||||
this.subscribeAlways<BotEvent> {
|
||||
when (it) {
|
||||
is FriendMessageEvent -> listener(FriendSenderAndMessage(it.sender, it.message))
|
||||
is GroupMessageEvent -> listener(GroupSenderAndMessage(it.group, it.sender, it.message))
|
||||
}
|
||||
}
|
||||
}.apply { listeners() }
|
||||
}
|
||||
|
||||
/**
|
||||
* 订阅来自这个 [Bot] 的所有群消息事件
|
||||
*/
|
||||
@MessageListenerDsl
|
||||
suspend inline fun Bot.subscribeGroupMessages(noinline listeners: suspend MessageSubscribersBuilder<GroupSenderAndMessage>.() -> Unit) {
|
||||
MessageSubscribersBuilder<GroupSenderAndMessage> { listener ->
|
||||
this.subscribeAlways<GroupMessageEvent> {
|
||||
listener(GroupSenderAndMessage(it.group, it.sender, it.message))
|
||||
}
|
||||
}.apply { listeners() }
|
||||
}
|
||||
|
||||
/**
|
||||
* 订阅来自这个 [Bot] 的所有好友消息事件.
|
||||
*/
|
||||
@MessageListenerDsl
|
||||
suspend inline fun Bot.subscribeFriendMessages(noinline listeners: suspend MessageSubscribersBuilder<FriendSenderAndMessage>.() -> Unit) {
|
||||
MessageSubscribersBuilder<FriendSenderAndMessage> { listener ->
|
||||
this.subscribeAlways<FriendMessageEvent> {
|
||||
listener(FriendSenderAndMessage(it.sender, it.message))
|
||||
}
|
||||
}.apply { listeners() }
|
||||
}
|
||||
|
||||
internal typealias MessageListener<T> = @MessageListenerDsl suspend T.(String) -> Unit
|
||||
|
||||
internal typealias MessageReplier<T> = @MessageListenerDsl suspend T.(String) -> String
|
||||
|
||||
internal suspend inline operator fun <T : SenderAndMessage> MessageListener<T>.invoke(t: T) = this.invoke(t, t.message.toString())
|
||||
@JvmName("invoke1") //Avoid Platform declaration clash
|
||||
internal suspend inline operator fun <T : SenderAndMessage> MessageReplier<T>.invoke(t: T) = this.invoke(t, t.message.toString())
|
||||
|
||||
/**
|
||||
* 消息订阅构造器
|
||||
*
|
||||
* @see subscribeFriendMessages
|
||||
* @sample demo.subscribe.messageDSL
|
||||
*/
|
||||
@Suppress("unused")
|
||||
@MessageListenerDsl
|
||||
inline class MessageSubscribersBuilder<T : SenderAndMessage>(
|
||||
val handlerConsumer: suspend (MessageListener<T>) -> Unit
|
||||
) {
|
||||
suspend inline fun case(equals: String, trim: Boolean = true, noinline listener: MessageListener<T>) = content({ equals == if (trim) it.trim() else it }, listener)
|
||||
suspend inline fun contains(value: String, noinline listener: MessageListener<T>) = content({ value in it }, listener)
|
||||
suspend inline fun replyEndsWith(value: String, noinline replier: MessageReplier<T>) = content({ it.endsWith(value) }) { replier(this) }
|
||||
suspend inline fun startsWith(start: String, noinline listener: MessageListener<T>) = content({ it.startsWith(start) }, listener)
|
||||
suspend inline fun endsWith(start: String, noinline listener: MessageListener<T>) = content({ it.endsWith(start) }, listener)
|
||||
suspend inline fun sentBy(id: UInt, noinline listener: MessageListener<T>) = content({ sender.id == id }, listener)
|
||||
suspend inline fun sentBy(id: Long, noinline listener: MessageListener<T>) = sentBy(id.toUInt(), listener)
|
||||
suspend inline fun <reified M : Message> has(noinline listener: MessageListener<T>) = handlerConsumer { if (message.any<M>()) listener(this) }
|
||||
suspend inline fun content(noinline filter: T.(String) -> Boolean, noinline listener: MessageListener<T>) =
|
||||
handlerConsumer { if (this.filter(message.toString())) listener(this) }
|
||||
|
||||
|
||||
suspend inline fun replyCase(equals: String, trim: Boolean = true, noinline replier: MessageReplier<T>) = case(equals, trim) { reply(replier(this)) }
|
||||
suspend inline fun replyContains(value: String, noinline replier: MessageReplier<T>) = content({ value in it }) { replier(this) }
|
||||
suspend inline fun replyStartsWith(value: String, noinline replier: MessageReplier<T>) = content({ it.startsWith(value) }) { replier(this) }
|
||||
|
||||
suspend infix fun String.reply(reply: String) = case(this) { this.reply(reply) }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* DSL 标记. 将能让 IDE 阻止一些错误的方法调用.
|
||||
*/
|
||||
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS, AnnotationTarget.TYPE)
|
||||
@DslMarker
|
||||
internal annotation class MessageListenerDsl
|
@ -72,6 +72,7 @@ suspend fun <E : Event> KClass<E>.subscribeWhileNull(listener: suspend (E) -> An
|
||||
* 监听一个事件. 可同时进行多种方式的监听
|
||||
* @see ListenerBuilder
|
||||
*/
|
||||
@ListenersBuilderDsl
|
||||
suspend fun <E : Event> KClass<E>.subscribeAll(listeners: suspend ListenerBuilder<E>.() -> Unit) {
|
||||
with(ListenerBuilder<E> { this.subscribeInternal(it) }) {
|
||||
listeners()
|
||||
@ -82,6 +83,7 @@ suspend fun <E : Event> KClass<E>.subscribeAll(listeners: suspend ListenerBuilde
|
||||
* 监听一个事件. 可同时进行多种方式的监听
|
||||
* @see ListenerBuilder
|
||||
*/
|
||||
@ListenersBuilderDsl
|
||||
suspend inline fun <reified E : Event> subscribeAll(noinline listeners: suspend ListenerBuilder<E>.() -> Unit) = E::class.subscribeAll(listeners)
|
||||
|
||||
/**
|
||||
@ -100,6 +102,7 @@ suspend inline fun <reified E : Event> subscribeAll(noinline listeners: suspend
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
@ListenersBuilderDsl
|
||||
@Suppress("MemberVisibilityCanBePrivate", "unused")
|
||||
inline class ListenerBuilder<out E : Event>(
|
||||
private val handlerConsumer: suspend (Handler<in E>) -> Unit
|
||||
@ -125,4 +128,7 @@ inline class ListenerBuilder<out E : Event>(
|
||||
suspend fun once(block: suspend (E) -> Unit) = handler { block(it); ListeningStatus.STOPPED }
|
||||
}
|
||||
|
||||
@DslMarker
|
||||
annotation class ListenersBuilderDsl
|
||||
|
||||
// endregion
|
@ -3,6 +3,7 @@
|
||||
package net.mamoe.mirai.event
|
||||
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.event.events.BotEvent
|
||||
import net.mamoe.mirai.event.internal.HandlerWithBot
|
||||
import net.mamoe.mirai.event.internal.subscribeInternal
|
||||
import kotlin.reflect.KClass
|
||||
@ -16,48 +17,66 @@ import kotlin.reflect.KClass
|
||||
|
||||
// region 顶层方法
|
||||
|
||||
suspend inline fun <reified E : Event> Bot.subscribe(noinline handler: suspend Bot.(E) -> ListeningStatus) = E::class.subscribe(this, handler)
|
||||
suspend inline fun <reified E : BotEvent> Bot.subscribe(noinline handler: suspend Bot.(E) -> ListeningStatus) = E::class.subscribe(this, handler)
|
||||
|
||||
suspend inline fun <reified E : Event> Bot.subscribeAlways(noinline listener: suspend Bot.(E) -> Unit) = E::class.subscribeAlways(this, listener)
|
||||
suspend inline fun <reified E : BotEvent> Bot.subscribeAlways(noinline listener: suspend Bot.(E) -> Unit) = E::class.subscribeAlways(this, listener)
|
||||
|
||||
suspend inline fun <reified E : Event> Bot.subscribeOnce(noinline listener: suspend Bot.(E) -> Unit) = E::class.subscribeOnce(this, listener)
|
||||
suspend inline fun <reified E : BotEvent> Bot.subscribeOnce(noinline listener: suspend Bot.(E) -> Unit) = E::class.subscribeOnce(this, listener)
|
||||
|
||||
suspend inline fun <reified E : Event, T> Bot.subscribeUntil(valueIfStop: T, noinline listener: suspend Bot.(E) -> T) = E::class.subscribeUntil(this, valueIfStop, listener)
|
||||
suspend inline fun <reified E : Event> Bot.subscribeUntilFalse(noinline listener: suspend Bot.(E) -> Boolean) = E::class.subscribeUntilFalse(this, listener)
|
||||
suspend inline fun <reified E : Event> Bot.subscribeUntilTrue(noinline listener: suspend Bot.(E) -> Boolean) = E::class.subscribeUntilTrue(this, listener)
|
||||
suspend inline fun <reified E : Event> Bot.subscribeUntilNull(noinline listener: suspend Bot.(E) -> Any?) = E::class.subscribeUntilNull(this, listener)
|
||||
suspend inline fun <reified E : BotEvent, T> Bot.subscribeUntil(valueIfStop: T, noinline listener: suspend Bot.(E) -> T) = E::class.subscribeUntil(this, valueIfStop, listener)
|
||||
suspend inline fun <reified E : BotEvent> Bot.subscribeUntilFalse(noinline listener: suspend Bot.(E) -> Boolean) = E::class.subscribeUntilFalse(this, listener)
|
||||
suspend inline fun <reified E : BotEvent> Bot.subscribeUntilTrue(noinline listener: suspend Bot.(E) -> Boolean) = E::class.subscribeUntilTrue(this, listener)
|
||||
suspend inline fun <reified E : BotEvent> Bot.subscribeUntilNull(noinline listener: suspend Bot.(E) -> Any?) = E::class.subscribeUntilNull(this, listener)
|
||||
|
||||
|
||||
suspend inline fun <reified E : Event, T> Bot.subscribeWhile(valueIfContinue: T, noinline listener: suspend Bot.(E) -> T) = E::class.subscribeWhile(this, valueIfContinue, listener)
|
||||
suspend inline fun <reified E : Event> Bot.subscribeWhileFalse(noinline listener: suspend Bot.(E) -> Boolean) = E::class.subscribeWhileFalse(this, listener)
|
||||
suspend inline fun <reified E : Event> Bot.subscribeWhileTrue(noinline listener: suspend Bot.(E) -> Boolean) = E::class.subscribeWhileTrue(this, listener)
|
||||
suspend inline fun <reified E : Event> Bot.subscribeWhileNull(noinline listener: suspend Bot.(E) -> Any?) = E::class.subscribeWhileNull(this, listener)
|
||||
suspend inline fun <reified E : BotEvent, T> Bot.subscribeWhile(valueIfContinue: T, noinline listener: suspend Bot.(E) -> T) =
|
||||
E::class.subscribeWhile(this, valueIfContinue, listener)
|
||||
|
||||
suspend inline fun <reified E : BotEvent> Bot.subscribeWhileFalse(noinline listener: suspend Bot.(E) -> Boolean) = E::class.subscribeWhileFalse(this, listener)
|
||||
suspend inline fun <reified E : BotEvent> Bot.subscribeWhileTrue(noinline listener: suspend Bot.(E) -> Boolean) = E::class.subscribeWhileTrue(this, listener)
|
||||
suspend inline fun <reified E : BotEvent> Bot.subscribeWhileNull(noinline listener: suspend Bot.(E) -> Any?) = E::class.subscribeWhileNull(this, listener)
|
||||
|
||||
// endregion
|
||||
|
||||
|
||||
// region KClass 的扩展方法 (不推荐)
|
||||
// region KClass 的扩展方法 (仅内部使用)
|
||||
|
||||
suspend fun <E : Event> KClass<E>.subscribe(bot: Bot, handler: suspend Bot.(E) -> ListeningStatus) = this.subscribeInternal(HandlerWithBot(bot, handler))
|
||||
@PublishedApi
|
||||
internal suspend fun <E : BotEvent> KClass<E>.subscribe(bot: Bot, handler: suspend Bot.(E) -> ListeningStatus) = this.subscribeInternal(HandlerWithBot(bot, handler))
|
||||
|
||||
suspend fun <E : Event> KClass<E>.subscribeAlways(bot: Bot, listener: suspend Bot.(E) -> Unit) =
|
||||
@PublishedApi
|
||||
internal suspend fun <E : BotEvent> KClass<E>.subscribeAlways(bot: Bot, listener: suspend Bot.(E) -> Unit) =
|
||||
this.subscribeInternal(HandlerWithBot(bot) { listener(it); ListeningStatus.LISTENING })
|
||||
|
||||
suspend fun <E : Event> KClass<E>.subscribeOnce(bot: Bot, listener: suspend Bot.(E) -> Unit) = this.subscribeInternal(HandlerWithBot(bot) { listener(it); ListeningStatus.STOPPED })
|
||||
@PublishedApi
|
||||
internal suspend fun <E : BotEvent> KClass<E>.subscribeOnce(bot: Bot, listener: suspend Bot.(E) -> Unit) =
|
||||
this.subscribeInternal(HandlerWithBot(bot) { listener(it); ListeningStatus.STOPPED })
|
||||
|
||||
suspend fun <E : Event, T> KClass<E>.subscribeUntil(bot: Bot, valueIfStop: T, listener: suspend Bot.(E) -> T) =
|
||||
@PublishedApi
|
||||
internal suspend fun <E : BotEvent, T> KClass<E>.subscribeUntil(bot: Bot, valueIfStop: T, listener: suspend Bot.(E) -> T) =
|
||||
subscribeInternal(HandlerWithBot(bot) { if (listener(it) === valueIfStop) ListeningStatus.STOPPED else ListeningStatus.LISTENING })
|
||||
|
||||
suspend fun <E : Event> KClass<E>.subscribeUntilFalse(bot: Bot, listener: suspend Bot.(E) -> Boolean) = subscribeUntil(bot, false, listener)
|
||||
suspend fun <E : Event> KClass<E>.subscribeUntilTrue(bot: Bot, listener: suspend Bot.(E) -> Boolean) = subscribeUntil(bot, true, listener)
|
||||
suspend fun <E : Event> KClass<E>.subscribeUntilNull(bot: Bot, listener: suspend Bot.(E) -> Any?) = subscribeUntil(bot, null, listener)
|
||||
@PublishedApi
|
||||
internal suspend fun <E : BotEvent> KClass<E>.subscribeUntilFalse(bot: Bot, listener: suspend Bot.(E) -> Boolean) = subscribeUntil(bot, false, listener)
|
||||
|
||||
@PublishedApi
|
||||
internal suspend fun <E : BotEvent> KClass<E>.subscribeUntilTrue(bot: Bot, listener: suspend Bot.(E) -> Boolean) = subscribeUntil(bot, true, listener)
|
||||
|
||||
@PublishedApi
|
||||
internal suspend fun <E : BotEvent> KClass<E>.subscribeUntilNull(bot: Bot, listener: suspend Bot.(E) -> Any?) = subscribeUntil(bot, null, listener)
|
||||
|
||||
|
||||
suspend fun <E : Event, T> KClass<E>.subscribeWhile(bot: Bot, valueIfContinue: T, listener: suspend Bot.(E) -> T) =
|
||||
@PublishedApi
|
||||
internal suspend fun <E : BotEvent, T> KClass<E>.subscribeWhile(bot: Bot, valueIfContinue: T, listener: suspend Bot.(E) -> T) =
|
||||
subscribeInternal(HandlerWithBot(bot) { if (listener(it) !== valueIfContinue) ListeningStatus.STOPPED else ListeningStatus.LISTENING })
|
||||
|
||||
suspend fun <E : Event> KClass<E>.subscribeWhileFalse(bot: Bot, listener: suspend Bot.(E) -> Boolean) = subscribeWhile(bot, false, listener)
|
||||
suspend fun <E : Event> KClass<E>.subscribeWhileTrue(bot: Bot, listener: suspend Bot.(E) -> Boolean) = subscribeWhile(bot, true, listener)
|
||||
suspend fun <E : Event> KClass<E>.subscribeWhileNull(bot: Bot, listener: suspend Bot.(E) -> Any?) = subscribeWhile(bot, null, listener)
|
||||
@PublishedApi
|
||||
internal suspend fun <E : BotEvent> KClass<E>.subscribeWhileFalse(bot: Bot, listener: suspend Bot.(E) -> Boolean) = subscribeWhile(bot, false, listener)
|
||||
|
||||
@PublishedApi
|
||||
internal suspend fun <E : BotEvent> KClass<E>.subscribeWhileTrue(bot: Bot, listener: suspend Bot.(E) -> Boolean) = subscribeWhile(bot, true, listener)
|
||||
|
||||
@PublishedApi
|
||||
internal suspend fun <E : BotEvent> KClass<E>.subscribeWhileNull(bot: Bot, listener: suspend Bot.(E) -> Any?) = subscribeWhile(bot, null, listener)
|
||||
|
||||
// endregion
|
@ -2,7 +2,6 @@ package net.mamoe.mirai.event.events
|
||||
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.contact.QQ
|
||||
import net.mamoe.mirai.contact.sendMessage
|
||||
import net.mamoe.mirai.message.Message
|
||||
import net.mamoe.mirai.message.MessageChain
|
||||
|
||||
|
@ -3,7 +3,6 @@ package net.mamoe.mirai.event.events
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.contact.Group
|
||||
import net.mamoe.mirai.contact.QQ
|
||||
import net.mamoe.mirai.contact.sendMessage
|
||||
import net.mamoe.mirai.message.Message
|
||||
import net.mamoe.mirai.message.MessageChain
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.event.SenderPermission
|
||||
@ -12,13 +11,14 @@ import net.mamoe.mirai.network.protocol.tim.packet.event.SenderPermission
|
||||
abstract class GroupEvent(bot: Bot, val group: Group) : BotEvent(bot)
|
||||
|
||||
|
||||
@Suppress("unused")
|
||||
class GroupMessageEvent(
|
||||
bot: Bot,
|
||||
group: Group,
|
||||
val sender: QQ,
|
||||
val message: MessageChain,
|
||||
val senderPermission: SenderPermission,
|
||||
val senderName: String//若他有群名片就是群名片, 没有就是昵称
|
||||
bot: Bot,
|
||||
group: Group,
|
||||
val sender: QQ,
|
||||
val message: MessageChain,
|
||||
val senderPermission: SenderPermission,
|
||||
val senderName: String//若他有群名片就是群名片, 没有就是昵称
|
||||
) : GroupEvent(bot, group) {
|
||||
suspend inline fun reply(message: Message) = group.sendMessage(message)
|
||||
|
||||
|
@ -7,6 +7,7 @@ import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.event.Event
|
||||
import net.mamoe.mirai.event.EventScope
|
||||
import net.mamoe.mirai.event.ListeningStatus
|
||||
import net.mamoe.mirai.event.events.BotEvent
|
||||
import net.mamoe.mirai.utils.internal.inlinedRemoveIf
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@ -62,9 +63,22 @@ class Handler<E : Event>(val handler: suspend (E) -> ListeningStatus) : Listener
|
||||
override suspend fun onEvent(event: E): ListeningStatus = handler.invoke(event)
|
||||
}
|
||||
|
||||
/**
|
||||
* 带有 bot 筛选的监听器.
|
||||
* 所有的非 [BotEvent] 的事件都不会被处理
|
||||
* 所有的 [BotEvent.bot] `!==` `bot` 的事件都不会被处理
|
||||
*/
|
||||
class HandlerWithBot<E : Event>(val bot: Bot, val handler: suspend Bot.(E) -> ListeningStatus) : Listener<E>() {
|
||||
override suspend fun onEvent(event: E): ListeningStatus = with(bot) {
|
||||
handler(event)
|
||||
if (event !is BotEvent || event.bot !== this) {
|
||||
return ListeningStatus.LISTENING
|
||||
}
|
||||
|
||||
return if (bot !== this) {
|
||||
ListeningStatus.LISTENING
|
||||
} else {
|
||||
handler(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,22 +1,15 @@
|
||||
@file:Suppress("EXPERIMENTAL_UNSIGNED_LITERALS", "EXPERIMENTAL_API_USAGE")
|
||||
|
||||
package demo1
|
||||
package demo.subscribe
|
||||
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.BotAccount
|
||||
import net.mamoe.mirai.contact.sendMessage
|
||||
import net.mamoe.mirai.event.*
|
||||
import net.mamoe.mirai.event.events.FriendMessageEvent
|
||||
import net.mamoe.mirai.event.events.GroupMessageEvent
|
||||
import net.mamoe.mirai.event.subscribeAll
|
||||
import net.mamoe.mirai.event.subscribeAlways
|
||||
import net.mamoe.mirai.event.subscribeUntilFalse
|
||||
import net.mamoe.mirai.login
|
||||
import net.mamoe.mirai.message.Image
|
||||
import net.mamoe.mirai.message.ImageId
|
||||
import net.mamoe.mirai.message.PlainText
|
||||
import net.mamoe.mirai.message.firstOrNull
|
||||
import net.mamoe.mirai.message.*
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingRawPacket
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.action.uploadImage
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.login.requireSuccess
|
||||
@ -42,34 +35,104 @@ private fun readTestAccount(): BotAccount? {
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
suspend fun main() {
|
||||
val bot = Bot(
|
||||
readTestAccount() ?: BotAccount(//填写你的账号
|
||||
id = 1994701121u,
|
||||
password = "123456"
|
||||
)
|
||||
)
|
||||
/**
|
||||
* 使用 dsl 监听消息事件
|
||||
*
|
||||
* @see subscribeFriendMessages
|
||||
* @see subscribeMessages
|
||||
* @see subscribeGroupMessages
|
||||
*
|
||||
* @see MessageSubscribersBuilder
|
||||
*/
|
||||
suspend fun Bot.messageDSL() {
|
||||
//监听所有 bot 的来自所有群和好友的消息
|
||||
subscribeMessages {
|
||||
replyCase("你好") { "你好" }
|
||||
|
||||
// 覆盖默认的配置
|
||||
bot.login {
|
||||
randomDeviceName = false
|
||||
}.requireSuccess()
|
||||
has<Image> {
|
||||
// this: SenderAndMessage
|
||||
// message: MessageChain
|
||||
// sender: QQ
|
||||
// it: String (MessageChain.toString)
|
||||
|
||||
subscribeAlways<GroupMessageEvent> {
|
||||
if (it.message eq "复读" && it.group.internalId.value == 580266363u) {
|
||||
it.reply(it.message)
|
||||
if (this is GroupSenderAndMessage) {
|
||||
//如果是群消息
|
||||
// group: Group
|
||||
this.group.sendMessage("你在一个群里")
|
||||
}
|
||||
|
||||
reply("你发送了一个图片, ID为 ${message[Image].id}, 我要复读了")
|
||||
reply(message)
|
||||
}
|
||||
|
||||
replyContains("123") { "你的消息里面包含 123" }
|
||||
|
||||
replyCase("我的qq") { sender.id.toString() }
|
||||
|
||||
sentBy(1040400290) {
|
||||
reply("是你!")
|
||||
}
|
||||
|
||||
contains("复读") {
|
||||
reply(message)
|
||||
}
|
||||
|
||||
case("上传好友图片") {
|
||||
val filename = it.toString().substringAfter("上传好友图片")
|
||||
File("C:\\Users\\Him18\\Desktop\\$filename").sendAsImageTo(1040400290u.qq())
|
||||
}
|
||||
|
||||
case("上传群图片") {
|
||||
val filename = it.toString().substringAfter("上传好友图片")
|
||||
File("C:\\Users\\Him18\\Desktop\\$filename").sendAsImageTo(920503456u.group())
|
||||
}
|
||||
}
|
||||
|
||||
subscribeMessages {
|
||||
case("你好") {
|
||||
// this: SenderAndMessage
|
||||
// message: MessageChain
|
||||
// sender: QQ
|
||||
// it: String (来自 MessageChain.toString)
|
||||
// group: Group (如果是群消息)
|
||||
reply("你好")
|
||||
}
|
||||
}
|
||||
|
||||
subscribeFriendMessages {
|
||||
contains("A") {
|
||||
// this: FriendSenderAndMessage
|
||||
// message: MessageChain
|
||||
// sender: QQ
|
||||
// it: String (来自 MessageChain.toString)
|
||||
reply("B")
|
||||
}
|
||||
}
|
||||
|
||||
subscribeGroupMessages {
|
||||
// this: FriendSenderAndMessage
|
||||
// message: MessageChain
|
||||
// sender: QQ
|
||||
// it: String (来自 MessageChain.toString)
|
||||
// group: Group
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听单个事件
|
||||
*/
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
suspend fun directlySubscribe(bot: Bot) {
|
||||
// 手动处理消息
|
||||
// 使用 Bot 的扩展方法监听, 将在处理事件时得到一个 this: Bot.
|
||||
// 这样可以很方便地调用 Bot 内的一些扩展方法如 UInt.qq():QQ
|
||||
// 这样可以调用 Bot 内的一些扩展方法如 UInt.qq():QQ
|
||||
bot.subscribeAlways<FriendMessageEvent> {
|
||||
// this: Bot
|
||||
// it: FriendMessageEvent
|
||||
|
||||
// 获取第一个纯文本消息, 获取不到会抛出 NoSuchElementException
|
||||
// val firstText = it.message.first<PlainText>()
|
||||
|
||||
val firstText = it.message.firstOrNull<PlainText>()
|
||||
|
||||
// 获取第一个图片
|
||||
@ -97,15 +160,6 @@ suspend fun main() {
|
||||
)
|
||||
}
|
||||
|
||||
"上传好友图片" in it.message -> withTimeoutOrNull(5000) {
|
||||
val filename = it.message.toString().substringAfter("上传好友图片")
|
||||
val id = 1040400290u.qq()
|
||||
.uploadImage(File("C:\\Users\\Him18\\Desktop\\$filename").toExternalImage())
|
||||
it.reply(id.value)
|
||||
delay(100)
|
||||
it.reply(Image(id))
|
||||
}
|
||||
|
||||
"上传群图片" in it.message -> withTimeoutOrNull(5000) {
|
||||
val filename = it.message.toString().substringAfter("上传群图片")
|
||||
val image = File(
|
||||
@ -131,8 +185,8 @@ suspend fun main() {
|
||||
|
||||
it.message eq "发图片群2" -> 580266363u.group().sendMessage(Image(ImageId("{7AA4B3AA-8C3C-0F45-2D9B-7F302A0ACEAA}.jpg")))
|
||||
|
||||
/* it.event eq "发图片" -> sendFriendMessage(it.sender, PlainText("test") + UnsolvedImage(File("C:\\Users\\Him18\\Desktop\\faceImage_1559564477775.jpg")).also { image ->
|
||||
image.upload(session, it.sender).of()
|
||||
/* it.event eq "发图片" -> sendFriendMessage(it.sentBy, PlainText("test") + UnsolvedImage(File("C:\\Users\\Him18\\Desktop\\faceImage_1559564477775.jpg")).also { image ->
|
||||
image.upload(session, it.sentBy).of()
|
||||
})*/
|
||||
it.message eq "发图片2" -> it.reply(PlainText("test") + Image(ImageId("{7AA4B3AA-8C3C-0F45-2D9B-7F302A0ACEAA}.jpg")))
|
||||
else -> {
|
||||
@ -140,7 +194,24 @@ suspend fun main() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
suspend fun main() {
|
||||
val bot = Bot(
|
||||
readTestAccount() ?: BotAccount(//填写你的账号
|
||||
id = 1994701121u,
|
||||
password = "123456"
|
||||
)
|
||||
)
|
||||
|
||||
// 覆盖默认的配置
|
||||
bot.login {
|
||||
randomDeviceName = false
|
||||
}.requireSuccess()
|
||||
|
||||
bot.messageDSL()
|
||||
directlySubscribe(bot)
|
||||
|
||||
//DSL 监听
|
||||
subscribeAll<FriendMessageEvent> {
|
@ -1,9 +1,11 @@
|
||||
@file:Suppress("EXPERIMENTAL_UNSIGNED_LITERALS", "EXPERIMENTAL_API_USAGE")
|
||||
|
||||
package demo1
|
||||
package demo.gentleman
|
||||
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.BotAccount
|
||||
import net.mamoe.mirai.event.events.FriendMessageEvent
|
||||
import net.mamoe.mirai.event.subscribeAlways
|
||||
import net.mamoe.mirai.login
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.login.requireSuccess
|
||||
import java.io.File
|
||||
@ -25,7 +27,7 @@ private fun readTestAccount(): BotAccount? {
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
suspend fun main() {
|
||||
val bot = Bot(
|
||||
readTestAccount() ?: BotAccount(//填写你的账号
|
||||
readTestAccount() ?: BotAccount(
|
||||
id = 1994701121u,
|
||||
password = "123456"
|
||||
)
|
||||
@ -33,5 +35,11 @@ suspend fun main() {
|
||||
|
||||
bot.login().requireSuccess()
|
||||
|
||||
bot.subscribeAlways<FriendMessageEvent> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
bot.network.awaitDisconnection()//等到直到断开连接
|
||||
}
|
Loading…
Reference in New Issue
Block a user