diff --git a/.github/机器人和联系人架构.png b/.github/机器人和联系人架构.png new file mode 100644 index 000000000..a92865f78 Binary files /dev/null and b/.github/机器人和联系人架构.png differ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 73f41116d..8fde54efb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,6 +6,8 @@ mirai 欢迎一切形式的代码贡献。你可以通过以下几种途径向 m ## 主仓库 `mirai-core` +**阅读文档**: [docs/mirai.md](docs/mirai.md) + ### 代码优化 优化功能设计或实现, 或是引入一个新的设计(建议先通过 issue 与我们达成共识) @@ -13,15 +15,10 @@ mirai 欢迎一切形式的代码贡献。你可以通过以下几种途径向 m 为 mirai 添加更广泛的协议支持。 ### 注意事项 -- mirai 框架已经把实现协议需要做的工作最小化. 为避免工作重复, 请务必熟悉 `net.mamoe.mirai.utils` 和 `net.mamoe.mirai.qqandroid.utils` 中工具类 - mirai 使用 [`kotlinx.io`](https://github.com/Kotlin/kotlinx-io) IO 库 -- mirai 为多平台项目, 请务必考虑多平台兼容性 -- mirai 为全协程实现, 请在有必要的时候考虑并发安全性 - 尽量不要引用新的库 - 遵守 Kotlin 代码规范(提交前使用 IDE 格式化代码 (commit 时勾选 'Reformat code')) -- 熟悉 [`PacketFactory`](https://github.com/mamoe/mirai/blob/master/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt) 架构 - 不要手动拆解数据包. 请一定使用 `kotlinx.serialization` 拆解 ProtoBuf, 使用 mirai 的 `Jce` 序列化器拆解 Jce 数据包, 使用 `kotlinx.serialization` 拆解 Json 数据. -- 必须保证高代码效率(使用 `ByteArrayPool`,`WeakRef` 等) ## 社区 diff --git a/README.md b/README.md index 71b2f7e26..bed859ce8 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ mirai 既可以作为项目中的 QQ 协议支持库, 也可以作为单独的 ### 开发者 -**了解 mirai 架构**: [Wiki](https://github.com/mamoe/mirai/wiki/Home) +**阅读文档**: [docs/mirai.md](docs/mirai.md) #### 使用 mirai 作为服务器,为 mirai 开发插件 @@ -130,10 +130,9 @@ Demos: [mirai-demos](https://github.com/mamoe/mirai-demos) ## 更新日志 -* 在 [Project](https://github.com/mamoe/mirai/projects/3) 查看已支持功能和计划 * 在 [CHANGELOG](https://github.com/mamoe/mirai/blob/master/CHANGELOG.md) 查看版本更新记录 (仅发布的版本) -## [贡献](https://github.com/mamoe/mirai/blob/master/CONTRIBUTING.md) +## [贡献](CONTRIBUTING.md) 我们欢迎一切形式的贡献。 我们也期待有更多人能加入 mirai 的开发。 diff --git a/docs/.mirai_images/d548dae5.png b/docs/.mirai_images/d548dae5.png new file mode 100644 index 000000000..ba958f3b4 Binary files /dev/null and b/docs/.mirai_images/d548dae5.png differ diff --git a/docs/.mirai_images/e02dc13d.png b/docs/.mirai_images/e02dc13d.png new file mode 100644 index 000000000..88a55007c Binary files /dev/null and b/docs/.mirai_images/e02dc13d.png differ diff --git a/docs/guide_quick_start.md b/docs/guide_quick_start.md index 771a6ae17..7b9062fc1 100644 --- a/docs/guide_quick_start.md +++ b/docs/guide_quick_start.md @@ -1,14 +1,12 @@ # Mirai Guide - Quick Start -由于 mirai 项目在快速推进中,因此内容时有变动,本文档的最后更新日期为```2020/3/26```,对应版本```0.30.1``` +由于 mirai 项目在快速推进中,因此内容时有变动,本文档的最后更新日期为```2020/5/11```,对应版本```1.0-RC2-1``` 本文适用于对 Kotlin 较熟悉的开发者, 使用 mirai 作为第三方依赖库引用任意一个 Kotlin, Java 或其他 JVM 平台的项目 **若你希望一份更基础的教程**, 请参阅: [mirai-guide-getting-started](guide_getting_started.md) -**若你希望使用 Java 开发**, 请参阅: [mirai-japt](https://github.com/mamoe/mirai-japt) - ## 构建需求 - Kotlin 1.3.71 (必须) @@ -76,7 +74,6 @@ implementation("net.mamoe:mirai-core-qqandroid-common:VERSION") **android** (Android 平台源集) **注意**: 在 [KT-37152](https://youtrack.jetbrains.com/issue/KT-37152) 修复前, mirai 无法支持 Android 平台目标. - ```kotlin implementation("net.mamoe:mirai-core-qqandroid-android:VERSION") ``` @@ -85,12 +82,16 @@ implementation("net.mamoe:mirai-core-qqandroid-android:VERSION") ```kotlin val bot = Bot(qqId, password).alsoLogin() -bot.subscribeMessages { - "你好" reply "你好!" - contains("图片"){ File("C:\\image.png").sendAsImage() } +bot.subscribeAlways { event -> + if (event.message.content.contains("你好")) { + reply("你好!") + } else if (event.message.content.contains("你好")) { + File("C:\\image.png").uploadAsImage() + } } -bot.subscribeAlways { - if (it.kind == BECOME_OPERATOR) - reply("${it.member.id} 成为了管理员") + +bot.subscribeAlways { event -> + if (event.kind == BECOME_OPERATOR) + reply("${event.member.id} 成为了管理员") } ``` diff --git a/docs/mirai.md b/docs/mirai.md new file mode 100644 index 000000000..dea61d4d1 --- /dev/null +++ b/docs/mirai.md @@ -0,0 +1,112 @@ +# mirai +欢迎来到 mirai 文档. + +本文档基于 mirai 1.0.0, 最后修改时间为 2020/5/11 + +## 声明 +1. mirai 为完全免费的开源项目. mirai 项目维护者和贡献者 (下文简称 '我们') 不通过任何方式收取任何费用, 也不提供任何稳定性保障. +2. mirai 不允许被用于任何违反相关法律法规的工作, 包括但不限于: 盗取账号密码, 盗窃用户资金, 群发违禁内容. 因此我们没有支持设备锁验证, 也没有支持免密登录 (在非常用地点登录会频繁要求输入验证码). +3. mirai 不提供任何可能促进上述违法行为的功能, 包括但不限于: 收发红包, 收发转账, 主动添加好友. +4. mirai 不公开任何协议接口. 不支持任何协议扩展. + +## 项目整体架构 +mirai 项目整体由 核心 (`mirai-core`) 与 控制台(`mirai-console`) 组成. + + +- [`mirai-core`](../mirai-core) 是机器人服务支持**库**. 提供所有机器人相关 API. **本身只包含抽象类和接口, 具体由协议模块实现**. + 可用的协议模块: + - [`mirai-core-qqandroid`](../mirai-core-qqandroid): Android QQ 8.3.0 版本协议实现. + + `mirai-core` 设计为一个 **`支持库`**, 意味着它可以被独立依赖, 在任意项目中使用. 详见下文. + + +- `mirai-core-qqandroid` 继承 `mirai-core`, 是 Android QQ 协议的实现. 在使用时只需参考 `mirai-core` 的 API. + + +- [`mirai-console`](https://github.com/mamoe/mirai-console) 是基于 `mirai-core` 的, 支持插件加载, 指令系统, 和配置等的**控制台框架**. + console 由 '后端' 和 '前端' 组成. + `mirai-console` 即为后端, 包含所有开发时需要用到的功能. + 可用的前端: + - 命令行: `mirai-console` 内置命令行后端. + - 基于 JavaFX 的图形端: [`mirai-console-graphical`](https://github.com/mamoe/mirai-console/tree/master/mirai-console-graphical) + - Unix 友好的终端: [`mirai-console-terminal`](https://github.com/mamoe/mirai-console/tree/master/mirai-console-terminal) + + +**注意**: `mirai-core` 于 2020 年 6 月发布的 `1.0.0` 版本正式进入稳定更新阶段, +**而 `mirai-console` 仍处于快速迭代阶段, 任何 API 都有可能在不经过警告的情况下改动, 任何 API 都不具有任何稳定性.** + +## `mirai-core` + +`mirai-core` 仅包含抽象类和接口和一些扩展方法, 且拥有非常完整的 KDoc (源码内文档). 此处没有必要过多赘述. + +你可以在这里快速地大致了解 mirai 的全部 API. + +要能看懂下文, 建议至少学习 Java, Kotlin 或 C# 其中一门语言. + +### 准备 + +mirai 全部使用 Kotlin, 若你无法理解部分 API, 可先简略阅读 Kotlin 参考: [kotlincn.net](https://www.kotlincn.net/docs/reference/) +有关协程 (`suspend`)部分, mirai 做了大量的兼容性转换以让 Java 使用相同的 API 阻塞地调用一个协程函数. +因此, 对于函数如 `suspend fun sendMessage(Message)`, Java 使用者也可以直接调用它. + +### 开始 + +1. [实验性 API 注解 MiraiExperimentalAPI](../mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/Annotations.kt#L41-L54) + +2. '机器人' 和 '联系人' + 1. [ContactOrBot](../mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/ContactOrBot.kt) + 2. [机器人对象 Bot](../mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt) + 3. [Contact](../mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt) + 4. [用户对象 User](../mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/User.kt) + 5. [好友对象 Friend](../mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Friend.kt) + 6. [群对象 Group](../mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt) + 7. [群成员对象 Member](../mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt) + + 总结: [机器人和联系人架构](../.github/机器人和联系人架构.png). 其中 `CoroutineScope` 为 Kotlin 协程作用域, Java 使用者可忽略. + + +3. '消息' + 1. [消息对象 Message](../mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt) + 特别注意, `Message` 分为 单个消息(`SingleMessage`) 和 多个消息, 即消息链(`MessageChain` ). + // TODO 此处还有更详细的扩展 API 解释, 待更新 + 2. [消息链 MessageChain](../mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt) + // TODO 此处还有更详细的扩展 API 解释, 待更新 + 3. 接下来可按需阅读各类型消息 [各类型消息](../mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/). 一个文件包含一种消息. + + +4. '事件' + mirai 支持异步的事件系统. + 1. [事件接口 Event](../mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Event.kt) + 2. [广播事件 Event.broadcast](../mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Event.kt) + 3. - Kotlin: [函数式监听事件 subscribe](../mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/subscriber.kt) + - Kotlin & Java: [方法反射监听事件 JvmMethodListeners](../mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/event/JvmMethodListeners.kt) + 4. 内建事件列表 [README](../mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/README.md). + 注意: mirai 将接收到的消息事件独立放置在 `net.mamoe.mirai.message` 下, 并命名为 `MessageEvent`. 并为他们实现了一些扩展. 详见 [MessageEvent.kt](../mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessageEvent.kt) + 5. 事件工具类和工具函数 (仅 Kotlin) (可以跳过本节): + 标注 (*) 的几种处理方式可能需要比较好的 Kotlin 技能才能理解并正确使用. 建议在不熟悉时不要使用它们. + - 挂起当前协程, 直到返回下一个事件实例: [nextEvent](../mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/nextEvent.kt) + - 挂起当前协程, 并从一个事件中同步一个值: [syncFromEvent](../mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/linear.kt) + - (*) 消息事件监听 DSL: [subscribeMessages](../mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/subscribeMessages.kt) + - (*) 协程 `select` 语法的监听方式: [selectMessages](../mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/select.kt) + - (*) 挂起协程并等待下一个与 `this` 语境相同的事件 [MessageEvent.nextMessage](../mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/utils.kt#L50) + + + +一切准备就绪. 现在开始构造 `Bot` 实例: + +1. `Bot` 的配置: [BotConfiguration](../mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt) + 可大致了解或跳过. 一般使用默认属性即可. +2. 构造 `Bot` 实例: [BotFactory](../mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/BotFactory.kt#L23), [newBot](../mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/BotFactory.kt#L53) + +另外地, 你还可以了解 mirai 提供的多平台日志系统 (为了同时支持控制台和独立依赖): [MiraiLogger](../mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/MiraiLogger.kt), 也可以跳过这个内容 + +### 使用 + +使用 mirai 作为一个依赖库: 阅读 [Quick Start](../docs/guide_quick_start.md) 配置依赖. +使用 mirai 作为控制台框架: 使用 [mirai-console](https://github.com/mamoe/mirai-console) 开发插件 + +## `mirai-core-qqandroid` +`mirai-core` 的实现部分. 不提供任何说明. 使用者无需考虑任何协议实现过程. + +## `mirai-console` +此模块处于实验性阶段, 可能没有很好地文档支持, 详见 [mirai-console](https://github.com/mamoe/mirai-console) \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/ContactOrBot.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/ContactOrBot.kt index dd76a4cd3..766ce8d99 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/ContactOrBot.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/ContactOrBot.kt @@ -9,6 +9,7 @@ package net.mamoe.mirai.contact +import kotlinx.coroutines.CoroutineScope import net.mamoe.mirai.Bot /** @@ -18,7 +19,7 @@ import net.mamoe.mirai.Bot * @see Contact * @see Bot */ -interface ContactOrBot { +interface ContactOrBot : CoroutineScope { /** * QQ 号或群号. */ diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Event.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Event.kt index 9f5c91f52..8328f73d6 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Event.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Event.kt @@ -12,9 +12,12 @@ package net.mamoe.mirai.event import kotlinx.coroutines.CoroutineScope +import net.mamoe.mirai.JavaFriendlyAPI import net.mamoe.mirai.event.internal.broadcastInternal import net.mamoe.mirai.utils.MiraiExperimentalAPI import net.mamoe.mirai.utils.SinceMirai +import net.mamoe.mirai.utils.internal.runBlocking +import kotlin.jvm.JvmName import kotlin.jvm.JvmSynthetic import kotlin.jvm.Volatile @@ -32,6 +35,8 @@ import kotlin.jvm.Volatile * * @see [broadcast] 广播事件 * @see [CoroutineScope.subscribe] 监听事件 + * + * @see CancellableEvent 可被取消的事件 */ interface Event { /** @@ -140,7 +145,9 @@ interface CancellableEvent : Event { /** * 广播一个事件的唯一途径. + * @see __broadcastJava */ +@JvmSynthetic suspend fun E.broadcast(): E = apply { if (this is BroadcastControllable && !this.shouldBroadcast) { return@apply @@ -148,6 +155,21 @@ suspend fun E.broadcast(): E = apply { this@broadcast.broadcastInternal() // inline, no extra cost } +/** + * 在 Java 广播一个事件的唯一途径. + * + * 调用方法: `EventKt.broadcast(event)` + */ +@Suppress("FunctionName") +@JvmName("broadcast") +@JavaFriendlyAPI +fun E.__broadcastJava(): E = apply { + if (this is BroadcastControllable && !this.shouldBroadcast) { + return@apply + } + runBlocking { this@__broadcastJava.broadcastInternal() } +} + /** * 设置为 `true` 以关闭事件. * 所有的 `subscribe` 都能正常添加到监听器列表, 但所有的广播都会直接返回. diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/MiraiLogger.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/MiraiLogger.kt index 19303e301..82c19fec2 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/MiraiLogger.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/MiraiLogger.kt @@ -28,6 +28,8 @@ import kotlin.jvm.JvmOverloads * **注意:** 请为日志做好分类, 即不同的模块使用不同的 [MiraiLogger]. * 如, [Bot] 中使用 identity 为 "Bot(qqId)" 的 [MiraiLogger] * 而 [Bot] 的网络处理中使用 identity 为 "BotNetworkHandler" 的. + * + * Java 调用: `Utils.getDefaultLogger().invoke(identity)` */ var DefaultLogger: (identity: String?) -> MiraiLogger = { PlatformLogger(it) } diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/BotFactory.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/BotFactory.kt index 0bb569206..cb9d4c579 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/BotFactory.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/BotFactory.kt @@ -47,6 +47,8 @@ actual interface BotFactory { /** * 自动加载现有协议的 [BotFactory], 并使用指定的 [配置][configuration] 构造 [Bot] 实例 + * + * Java 调用方式: `BotFactoryJvm.newBot(...)` */ @JvmName("newBot") @JvmOverloads @@ -63,6 +65,8 @@ inline fun Bot(context: Context, qq: Long, password: String, configuration: (Bot /** * 自动加载现有协议的 [BotFactory], 并使用指定的 [配置][configuration] 构造 [Bot] 实例 + * + * Java 调用方式: `BotFactoryJvm.newBot(...)` */ @JvmName("newBot") @JvmOverloads @@ -79,6 +83,8 @@ inline fun Bot(qq: Long, password: String, configuration: (BotConfiguration.() - /** * 自动加载现有协议的 [BotFactory], 并使用指定的 [配置][configuration] 构造 [Bot] 实例 + * + * Java 调用方式: `BotFactoryJvm.newBot(...)` */ @JvmName("newBot") @JvmOverloads @@ -100,6 +106,8 @@ inline fun Bot(context: Context, qq: Long, passwordMd5: ByteArray, configuration /** * 自动加载现有协议的 [BotFactory], 并使用指定的 [配置][configuration] 构造 [Bot] 实例 + * + * Java 调用方式: `BotFactoryJvm.newBot(...)` */ @JvmName("newBot") @JvmOverloads @@ -114,9 +122,6 @@ inline fun Bot(qq: Long, passwordMd5: ByteArray, configuration: (BotConfiguratio factory.Bot(ContextImpl(), qq, passwordMd5, BotConfiguration().apply(configuration)) - - - // Do not use ServiceLoader. Probably not working on MPP @PublishedApi internal val factory: BotFactory = run { diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/BotFactoryJvm.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/BotFactoryJvm.kt deleted file mode 100644 index 726ca00f2..000000000 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/BotFactoryJvm.kt +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2020 Mamoe Technologies and contributors. - * - * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. - * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. - * - * https://github.com/mamoe/mirai/blob/master/LICENSE - */ - -@file:JvmName("BotFactoryJvm") -@file:Suppress("FunctionName", "unused") - -package net.mamoe.mirai - -import net.mamoe.mirai.utils.BotConfiguration -import net.mamoe.mirai.utils.Context -import net.mamoe.mirai.utils.ContextImpl