Update docs

This commit is contained in:
Him188 2020-12-19 16:01:58 +08:00
parent 59eea052be
commit 4fa7867e6a
4 changed files with 183 additions and 13 deletions

View File

@ -37,4 +37,5 @@ Bot bot = BotFactory.INSTANCE.newBot( );
> 下一步,[Contacts](Contacts.md)
>
> [回到 Mirai 文档索引](README.md)

View File

@ -7,4 +7,5 @@
可通过 `Bot.getFriend``Bot.getGroup` 获取相关对象。
> 下一步,[Events](Events.md)
>
> [回到 Mirai 文档索引](README.md)

View File

@ -1,25 +1,39 @@
# Mirai - Events
## 目录
- [使用 `ListenerHost` 监听事件](#使用-listenerhost-监听事件)
- [在 Kotlin 函数式监听](#在-kotlin-函数式监听)
- [事件列表](#事件列表)
- [事件系统](#事件系统)
- [监听事件](#监听事件)
- [使用 `ListenerHost` 监听事件](#使用-listenerhost-监听事件)
- [在 Kotlin 函数式监听](#在-kotlin-函数式监听)
- [实现事件](#实现事件)
- [工具函数Kotlin](#工具函数kotlin)
## 事件系统
Mirai 以事件驱动,使用者需要监听如 `收到消息``收到入群申请` 等事件。
[`Event`]: ../mirai-core-api/src/commonMain/kotlin/event/Event.kt#L21-L62
每个事件都实现接口 [`Event`],且继承 `AbstractEvent`
实现 `CancellableEvent` 的事件可以被取消(`CancellableEvent.cancel`)。
[事件列表](../mirai-core-api/src/commonMain/kotlin/event/events/README.md#事件)
## 监听事件
有两种方法监听事件:
- [使用 `ListenerHost` 监听事件](#使用-listenerhost-监听事件)
- [在 Kotlin 函数式监听](#在-kotlin-函数式监听)
## 使用 `ListenerHost` 监听事件
### 使用 `ListenerHost` 监听事件
标注一个函数方法为事件监听器。mirai 通过反射获取他们并为之注册事件。
> 详见 [EventHandler](../mirai-core-api/src/commonMain/kotlin/event/JvmMethodListeners.kt#L27-L168)
### Kotlin 函数
#### Kotlin 函数
Kotlin 函数要求:
- 接收者 (英 receiver) 和函数参数: 所标注的 Kotlin 函数必须至少拥有一个接收者或一个函数参数, 或二者都具有. 接收者和函数参数的类型必须相同 (如果二者都存在)
@ -89,7 +103,7 @@ object MyEvents : SimpleListenerHost( /* override coroutineContext here */ ) {
}
MyEvents.registerEvents()
```
### Java 方法
#### Java 方法
所有 Java 方法都会在 `Dispatchers.IO` 中调用,因此在 Java 可以调用阻塞方法。
@ -127,15 +141,15 @@ public class MyEventHandlers extends SimpleListenerHost {
// Events.registerEvents(new MyEventHandlers())
```
## 在 Kotlin 函数式监听
### 在 Kotlin 函数式监听
[CoroutineScope.subscribe](../mirai-core-api/src/commonMain/kotlin/event/subscriber.kt#L137-L220)
用法示例:
```kotlin
object YourApplication : CoroutineScope by CoroutineScope(SupervisorJob())
object MyApplication : CoroutineScope by CoroutineScope(SupervisorJob())
// 启动事件监听器
YourApplication.subscribeAlways<GroupMessageEvent> {
MyApplication.subscribeAlways<GroupMessageEvent> {
// this: GroupMessageEvent
// it: GroupMessageEvent
// lambda 的 this 和参数都是 GroupMessageEvent
@ -148,7 +162,7 @@ YourApplication.subscribeAlways<GroupMessageEvent> {
Mirai 也支持传递函数引用:
```kotlin
YourApplication.subscribeAlways<GroupMessageEvent> {
MyApplication.subscribeAlways<GroupMessageEvent> {
// this: GroupMessageEvent
// it: GroupMessageEvent
// lambda 的 this 和参数都是 GroupMessageEvent
@ -157,6 +171,159 @@ YourApplication.subscribeAlways<GroupMessageEvent> {
}
```
## 事件列表
### 在 Kotlin 使用 DSL 监听事件
> **警告:此节内容需要坚实的 Kotlin 技能,盲目使用会导致问题**
[事件列表](../mirai-core-api/src/commonMain/kotlin/event/events/README.md#事件)
[subscribeMessages](../mirai-core-api/src/commonMain/kotlin/event/subscribeMessages.kt#L37-L64)
示例:
```
MyApplication.subscribeMessages {
"test" {
// 当消息内容为 "test" 时执行
// this: MessageEvent
reply("test!")
}
"Hello" reply "Hi" // 当消息内容为 "Hello" 时回复 "Hi"
"quote me" quoteReply "ok" // 当消息内容为 "quote me" 时引用该消息并回复 "ok"
"quote me2" quoteReply {
// lambda 也是允许的:
// 返回值接受 Any?
// 为 Unit 时不发送任何内容;
// 为 Message 时直接发送;
// 为 String 时发送为 PlainText
// 否则 toString 并发送为 PlainText
"ok"
}
case("iGNorECase", ignoreCase=true) reply "OK" // 忽略大小写
startsWith("-") reply { cmd ->
// 当消息内容以 "-" 开头时执行
// cmd 为消息去除开头 "-" 的内容
}
val listener: Listener<MessageEvent> = "1" reply "2"
// 每个语句都会被注册为事件监听器,可以这样获取监听器
listener.complete() // 停止 "1" reply "2" 这个事件监听
}
```
## 实现事件
只要实现接口 `Event` 并继承 `AbstractEvent` 的对象就可以被广播。
要广播一个事件,使用 `Event.broadcast()`Kotlin`EventKt.broadcast(Event)`Java
## 工具函数Kotlin
*可能需要较好的 Kotlin 技能才能理解以下内容。*
基于 Kotlin 协程特性mirai 提供 `
### 线性同步(`syncFromEvent`
[linear.kt](../mirai-core-api/src/commonMain/kotlin/event/linear.kt)
挂起协程并获取下一个戳 Bot 的对象:
```kotlin
val target: UserOrBot = syncFromEvent<BotNudgedEvent> { sender }
```
带超时版本:
```kotlin
val target: UserOrBot = syncFromEvent<BotNudgedEvent>(5000) { sender } // 5000ms
```
异步 `async` 版本:
```kotlin
val target: Deferred<UserOrBot> = coroutineScope.asyncFromEvent<BotNudgedEvent> { sender }
```
### 线性同步(`nextEvent`
[nextEvent.kt](../mirai-core-api/src/commonMain/kotlin/event/nextEvent.kt)
挂起协程并获取下一个指定事件:
```kotlin
val event: BotNudgedEvent = nextEvent<BotNudgedEvent>()
```
带超时和过滤器版本:
```kotlin
val event: BotNudgedEvent = nextEvent<BotNudgedEvent>(5000) { it.bot.id == 123456L }
```
### 条件选择(`selectMessages`
> **警告:此节内容需要坚实的 Kotlin 技能,盲目使用会导致问题**
[select.kt](../mirai-core-api/src/commonMain/kotlin/event/select.kt)
类似于 Kotlin 协程 `select`mirai 也提供类似的功能。
`selectMessages`:挂起当前协程,等待任意一个事件监听器触发后返回其返回值。
```kotlin
MyCoroutineScope.subscribeAlways<GroupMessageEvent> {
if (message.contentEquals("ocr")) {
reply("请发送你要进行 OCR 的图片或图片链接")
val image: InputStream = selectMessages {
has<Image> { URL(it.queryUrl()).openStream() }
has<PlainText> { URL(it.content).openStream() }
defaultReply { "请发送图片或图片链接" }
timeout(30_000) { event.quoteReply("请在 30 秒内发送图片或图片链接"); null }
} ?: return@subscribeAlways
val result = ocr(image)
quoteReply(result)
}
}
```
这种语法就相当于(伪代码):
```
val image = when (下一条消息) {
包含图片 { 查询图片链接() }
包含纯文本 { 下载图片() }
其他情况 { 引用回复() }
超时 { 引用回复() }
}
```
### 循环条件选择(`whileSelectMessages`
> **警告:此节内容需要坚实的 Kotlin 技能,盲目使用会导致问题**
[select.kt](../mirai-core-api/src/commonMain/kotlin/event/select.kt)
类似于 Kotlin 协程 `whileSelect`mirai 也提供类似的功能。
`whileSelectMessages`:挂起当前协程,等待任意一个事件监听器返回 `false` 后返回。
```kotlin
reply("开启复读模式")
whileSelectMessages {
"stop" {
reply("已关闭复读")
false // 停止循环
}
// 也可以使用 startsWith("") { true } 等 DSL
default {
reply(message)
true // 继续循环
}
timeout(3000) {
// on
true
}
} // 等待直到 `false`
reply("复读模式结束")
```
> 下一步,[Messages](Messages.md)
>
> [回到 Mirai 文档索引](README.md)

View File

@ -66,5 +66,6 @@ mirai 官方提供 Kotlin/Java 等 JVM 平台语言开发支持。如果你不
***本文档正在更新中***
- [创建 Bot](CreatingBots.md)
- [Bots](Bots.md)
- [Contacts](Contacts.md)
- [Events](Events.md)