From 4fa7867e6a2c3cc6a9a334f474d4bab8e203971e Mon Sep 17 00:00:00 2001 From: Him188 Date: Sat, 19 Dec 2020 16:01:58 +0800 Subject: [PATCH] Update docs --- docs/{CreatingBots.md => Bots.md} | 1 + docs/Contacts.md | 1 + docs/Events.md | 191 ++++++++++++++++++++++++++++-- docs/README.md | 3 +- 4 files changed, 183 insertions(+), 13 deletions(-) rename docs/{CreatingBots.md => Bots.md} (99%) diff --git a/docs/CreatingBots.md b/docs/Bots.md similarity index 99% rename from docs/CreatingBots.md rename to docs/Bots.md index 276335724..4e641f261 100644 --- a/docs/CreatingBots.md +++ b/docs/Bots.md @@ -37,4 +37,5 @@ Bot bot = BotFactory.INSTANCE.newBot( ); > 下一步,[Contacts](Contacts.md) +> > [回到 Mirai 文档索引](README.md) diff --git a/docs/Contacts.md b/docs/Contacts.md index 48c5671af..718eb06f3 100644 --- a/docs/Contacts.md +++ b/docs/Contacts.md @@ -7,4 +7,5 @@ 可通过 `Bot.getFriend` 或 `Bot.getGroup` 获取相关对象。 > 下一步,[Events](Events.md) +> > [回到 Mirai 文档索引](README.md) \ No newline at end of file diff --git a/docs/Events.md b/docs/Events.md index 107856dc3..f9ea86a47 100644 --- a/docs/Events.md +++ b/docs/Events.md @@ -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 { +MyApplication.subscribeAlways { // this: GroupMessageEvent // it: GroupMessageEvent // lambda 的 this 和参数都是 GroupMessageEvent @@ -148,7 +162,7 @@ YourApplication.subscribeAlways { Mirai 也支持传递函数引用: ```kotlin -YourApplication.subscribeAlways { +MyApplication.subscribeAlways { // this: GroupMessageEvent // it: GroupMessageEvent // lambda 的 this 和参数都是 GroupMessageEvent @@ -157,6 +171,159 @@ YourApplication.subscribeAlways { } ``` -## 事件列表 +### 在 Kotlin 使用 DSL 监听事件 +> **警告:此节内容需要坚实的 Kotlin 技能,盲目使用会导致问题** -[事件列表](../mirai-core-api/src/commonMain/kotlin/event/events/README.md#事件) \ No newline at end of file +[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 = "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 { sender } +``` + +带超时版本: +```kotlin +val target: UserOrBot = syncFromEvent(5000) { sender } // 5000ms +``` + +异步 `async` 版本: + +```kotlin +val target: Deferred = coroutineScope.asyncFromEvent { sender } +``` + +### 线性同步(`nextEvent`) +[nextEvent.kt](../mirai-core-api/src/commonMain/kotlin/event/nextEvent.kt) + +挂起协程并获取下一个指定事件: + +```kotlin +val event: BotNudgedEvent = nextEvent() +``` + +带超时和过滤器版本: + +```kotlin +val event: BotNudgedEvent = nextEvent(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 { + if (message.contentEquals("ocr")) { + reply("请发送你要进行 OCR 的图片或图片链接") + val image: InputStream = selectMessages { + has { URL(it.queryUrl()).openStream() } + has { 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) \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index bf3425ca5..5c5e3bb0f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -66,5 +66,6 @@ mirai 官方提供 Kotlin/Java 等 JVM 平台语言开发支持。如果你不 ***本文档正在更新中*** -- [创建 Bot](CreatingBots.md) +- [Bots](Bots.md) - [Contacts](Contacts.md) +- [Events](Events.md)