mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-27 17:00:14 +08:00
Update docs
This commit is contained in:
parent
9347d6baf6
commit
1600a76aa3
@ -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())
|
|||||||
| 当前版本过低 | 密码错误 | 检查密码 |
|
| 当前版本过低 | 密码错误 | 检查密码 |
|
||||||
| 当前上网环境异常 | 设备锁 | 开启或关闭设备锁后重试登录 |
|
| 当前上网环境异常 | 设备锁 | 开启或关闭设备锁后重试登录 |
|
||||||
|
|
||||||
若以上方案无法解决问题,请尝试[切换登录协议](#切换登录协议)。
|
若以上方案无法解决问题,请尝试 [切换登录协议](#切换登录协议) 和 **[处理滑动验证码](#处理滑动验证码)**。
|
||||||
|
|
||||||
### 重新登录
|
### 重新登录
|
||||||
|
|
||||||
|
153
docs/Events.md
153
docs/Events.md
@ -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
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
## 生态
|
## 生态
|
||||||
|
|
||||||
[Mirai 生态概览](mirai-ecology.md)
|
**[Mirai 生态概览](mirai-ecology.md)**
|
||||||
|
|
||||||
## 确定 SDK
|
## 确定 SDK
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user