Update docs

This commit is contained in:
Him188 2020-12-28 17:40:17 +08:00
parent 9347d6baf6
commit 1600a76aa3
3 changed files with 153 additions and 11 deletions

View File

@ -125,12 +125,19 @@ setLoginSolver(new YourLoginSolver())
要获取更多有关验证码解决器的信息,查看 [LoginSolver.kt](../mirai-core-api/src/commonMain/kotlin/utils/LoginSolver.kt#L32) 要获取更多有关验证码解决器的信息,查看 [LoginSolver.kt](../mirai-core-api/src/commonMain/kotlin/utils/LoginSolver.kt#L32)
### 获取当前所有 `Bot` 实例 ### 获取当前所有 `Bot` 实例
在登录后,`Bot` 实例会被自动记录。可在 `Bot.instances` 获取到当前在线的所有 `Bot` 列表。当 `Bot` 离线,其实例就会被删除。 在登录后,`Bot` 实例会被自动记录。可在 `Bot.instances` 获取到当前在线的所有 `Bot` 列表。当 `Bot` 离线,其实例就会被删除。
## 2. 登录 ## 2. 登录
创建 `Bot` 后不会自动登录,需要手动调用其 `login()` 方法。在 Kotlin 还可以使用 `Bot.alsoLogin()` 扩展,相当于 `bot.apply { login() }` 创建 `Bot` 后不会自动登录,需要手动调用其 `login()` 方法。在 Kotlin 还可以使用 `Bot.alsoLogin()` 扩展,相当于 `bot.apply { login() }`
### 处理滑动验证码
由于服务器正在大力推广滑块验证码,登录时可能需要解决滑动验证码。部分账号可以跳过滑块验证码直接重新登录,服务器就会要求图片验证码。
处理验证码需要浏览器支持,可在 [project-mirai/mirai-login-solver-selenium](https://github.com/project-mirai/mirai-login-solver-selenium) 查看详细处理方案。
### 常见登录失败原因 ### 常见登录失败原因
| 错误信息 | 可能的原因 | 可能的解决方案 | | 错误信息 | 可能的原因 | 可能的解决方案 |
@ -138,7 +145,7 @@ setLoginSolver(new YourLoginSolver())
| 当前版本过低 | 密码错误 | 检查密码 | | 当前版本过低 | 密码错误 | 检查密码 |
| 当前上网环境异常 | 设备锁 | 开启或关闭设备锁后重试登录 | | 当前上网环境异常 | 设备锁 | 开启或关闭设备锁后重试登录 |
若以上方案无法解决问题,请尝试[切换登录协议](#切换登录协议)。 若以上方案无法解决问题,请尝试 [切换登录协议](#切换登录协议)**[处理滑动验证码](#处理滑动验证码)**
### 重新登录 ### 重新登录

View File

@ -19,26 +19,161 @@ Mirai 以事件驱动,使用者需要监听如 `收到消息``收到入群
每个事件都实现接口 [`Event`],且继承 `AbstractEvent` 每个事件都实现接口 [`Event`],且继承 `AbstractEvent`
实现 `CancellableEvent` 的事件可以被取消(`CancellableEvent.cancel`)。 实现 `CancellableEvent` 的事件可以被取消(`CancellableEvent.cancel`)。
[事件列表](../mirai-core-api/src/commonMain/kotlin/event/events/README.md#事件) **[事件列表](../mirai-core-api/src/commonMain/kotlin/event/events/README.md#事件)**
## 监听事件 ## 事件通道
[`EventChannel`]: ../mirai-core-api/src/commonMain/kotlin/event/EventChannel.kt
[事件通道][`EventChannel`]是监听事件的入口。 **在不同的事件通道中可以监听到不同类型的事件**
> 对通道的转换操作可以在使用时查看源码内注释 ([`EventChannel`])。
### 获取事件通道
`GlobalEventChannel` 是最大的通道:所有的事件都可以在 `GlobalEventChannel` 监听到。**因此,`GlobalEventChannel` 会包含来自所有 `Bot` 实例的事件。**
通常不会直接使用 `GlobalEventChannel`,而是使用经过 [通道操作](#通道操作) 操作的子通道。
## 通道操作
`EventChannel` 可以通过一些操作转换。
**一个通道的属性都是*不变的*:每个转换操作都会创建一个新的通道而不会修改原通道。**
### 缩窄(过滤)
`GlobalEventChannel` 包含任何 `Event`,可以通过 `EventChannel.filter` 过滤得到一个只包含期望的事件的 `EventChannel`
```kotlin
var channel = GlobalEventChannel.filter { it is BotEvent && it.bot.id == 123456L } // 筛选来自某一个 Bot 的事件
```
```java
EventChannel channel = GlobalEventChannel.INSTANCE.filter(ev -> ev instanceof BotEvent && ((BotEvent) ev).bot.id == 123456); // 筛选来自某一个 Bot 的事件
```
### 添加 `CoroutineContext`
一个通道持有属性 `defaultCoroutineContext`,将会自动添加给每个事件监听器(见后文)。
可以为通道添加一些 `CoroutineContext`,如 `CoroutineExceptionHandler`
```kotlin
channel.exceptionHandler { exception ->
logger.error(exception)
}
```
```java
channel.exceptionHandler(exception ->
logger.error(exception);
);
```
这本质上是添加了一个 `CoroutineExceptionHandler`。之后当事件监听器出现异常,异常就会被传递到这个 `CoroutineExceptionHandler` 处理。
### 限制作用域
在监听时会创建一些*事件监听器*。*事件监听器*本质上是一个协程 *`Job`*,因此可以有父 `Job`
要指定父 `Job`,请使用 `parentJob``parentScope` 操作。
```kotlin
// parentScope
channel = channel.parentScope(MyApplicationScope)
// parentJob
val job = SupervisorJob()
channel = channel.parentJob(job)
```
在 Kotlin可以使用如下扩展快速在 GlobalEventChannel 创建一个指定协程作用域下的事件通道。
> ```kotlin
> ```kotlin
> > fun CoroutineScope.globalEventChannel(coroutineContext: CoroutineContext = EmptyCoroutineContext): EventChannel<Event> = GlobalEventChannel.parentScope(this, coroutineContext)
> > ```
> ```
```kotlin
val channel = MyApplicationScope.globalEventChannel()
```
作用域限制对于应用生命周期管理会很有用。请看如下 Mirai Console 插件示例。
```kotlin
object MyPluginMain : KotlinPlugin() { // KotlinPlugin 实现了 CoroutineScope
// 插件被启用时调用
override fun onEnable() {
// `this` 是插件的协程作用域
// 在插件协程作用域里创建事件监听。当插件被停用时,插件的协程作用域也会被关闭,事件监听就会被同步停止。
this.globalEventChannel().subscribeAlways<MessageEvent> { event ->
// 处理事件
}
}
}
```
> 有关限制作用域的实现细节,可在使用时阅读源码内文档。
### 链式调用
对通道的操作都会返回 `this`,因此可以链式调用。
```kotlin
val channel = GlobalEventChannel
.filterIsInstance<BotEvent>()
.filter { it.bot.id == 123456L }
.filter { /* some other conditions */ }
.parentScope(MyApplicationScope)
.exceptionHandler { exception ->
exception.printStacktrace()
}
```
## 在 `EventChannel` 监听事件
使用:
- `EventChannel.subscribe`:监听事件并自行觉得何时停止
- `EventChannel.subscribeAlways`:一直监听事件
- `EventChannel.subscribeOnce`:只监听一次事件
```kotlin
bot.eventChannel.subscribeAlways<GroupMessageEvent> { event ->
// this: GroupMessageEvent
// event: GroupMessageEvent
subject.sendMessage("Hello from mirai!")
}
```
```java
bot.eventChannel.subscribeAlways(GroupMessageEvent.class, event -> {
event.getSubject().sendMessage("Hello from mirai!");
})
```
> 有关监听事件的实现细节可在使用时查看源码内注释。
## 监听事件的其他方法
监听都需要在*事件通道*中进行。如下几种方法都本质上会调用上述 `EventChannel.subscribe` 等方法。
有两种方法监听事件:
- [使用 `ListenerHost` 监听事件](#使用-listenerhost-监听事件) - [使用 `ListenerHost` 监听事件](#使用-listenerhost-监听事件)
- [在 Kotlin 函数式监听](#在-kotlin-函数式监听) - [在 Kotlin 函数式监听](#在-kotlin-函数式监听)
- [在 Kotlin 使用 DSL 监听事件](#在-kotlin-使用-dsl-监听事件)
### 使用 `ListenerHost` 监听事件 ### 使用 `ListenerHost` 监听事件
标注一个函数方法为事件监听器。mirai 通过反射获取他们并为之注册事件。 标注一个函数方法为事件监听器。mirai 通过反射获取他们并为之注册事件。
> 详见 [EventHandler](../mirai-core-api/src/commonMain/kotlin/event/JvmMethodListeners.kt#L27-L168) > 详见 [EventHandler](../mirai-core-api/src/commonMain/kotlin/event/JvmMethodListeners.kt#L22-L144)
#### Kotlin 函数 #### Kotlin 函数
Kotlin 函数要求: Kotlin 函数要求:
- 接收者 (英 receiver) 和函数参数: 所标注的 Kotlin 函数必须至少拥有一个接收者或一个函数参数, 或二者都具有. 接收者和函数参数的类型必须相同 (如果二者都存在) - 接收者 (英 receiver) 和函数参数: 所标注的 Kotlin 函数必须至少拥有一个接收者或一个函数参数, 或二者都具有. 接收者和函数参数的类型必须相同 (如果二者都存在)
接收者或函数参数的类型都必须为 `Event` 或其子类. 接收者或函数参数的类型都必须为 `Event` 或其子类.
- 返回值: 为 `Unit` 或不指定返回值时将注册为 `CoroutineScope.subscribeAlways`, 为 `ListeningStatus` 时将注册为 `CoroutineScope.subscribe`. - 返回值: 为 `Unit` 或不指定返回值时将注册为 `EventChannel.subscribeAlways`, 为 `ListeningStatus` 时将注册为 `EventChannel.subscribe`.
任何其他类型的返回值将会在注册时抛出异常. 任何其他类型的返回值将会在注册时抛出异常.
所有 Kotlin 非 `suspend` 的函数都将会在 `Dispatchers.IO` 中调用 所有 Kotlin 非 `suspend` 的函数都将会在 `Dispatchers.IO` 中调用
@ -79,7 +214,7 @@ object MyEvents : ListenerHost {
reply("received") reply("received")
} }
} }
myCoroutineScope.registerEvents(MyEvents) eventChannel.registerListenerHost(MyEvents)
``` ```
`onMessage` 抛出的异常将会交给 `myCoroutineScope` 处理 `onMessage` 抛出的异常将会交给 `myCoroutineScope` 处理
@ -101,7 +236,7 @@ object MyEvents : SimpleListenerHost( /* override coroutineContext here */ ) {
// return ListeningStatus.STOPPED // 表示停止监听事件 // return ListeningStatus.STOPPED // 表示停止监听事件
} }
} }
MyEvents.registerEvents() eventChannel.registerListenerHost(MyEvents)
``` ```
#### Java 方法 #### Java 方法
@ -138,11 +273,11 @@ public class MyEventHandlers extends SimpleListenerHost {
} }
// 注册: // 注册:
// Events.registerEvents(new MyEventHandlers()) // eventChannel.registerListenerHost(new MyEventHandlers())
``` ```
### 在 Kotlin 函数式监听 ### 在 Kotlin 函数式监听
[CoroutineScope.subscribe](../mirai-core-api/src/commonMain/kotlin/event/subscriber.kt#L137-L220) [CoroutineScope.subscribe](../mirai-core-api/src/commonMain/kotlin/event/EventChannelKotlinExtensions.kt)
用法示例: 用法示例:
```kotlin ```kotlin

View File

@ -4,7 +4,7 @@
## 生态 ## 生态
[Mirai 生态概览](mirai-ecology.md) **[Mirai 生态概览](mirai-ecology.md)**
## 确定 SDK ## 确定 SDK