diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotHelper.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotHelper.kt index 82507f639..925a09b30 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotHelper.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotHelper.kt @@ -21,14 +21,15 @@ suspend inline fun Bot.getGroup(id: GroupId): Group = this.contacts.getGroup(id) suspend inline fun Bot.getGroup(internalId: GroupInternalId): Group = this.contacts.getGroup(internalId) /** - * 取得机器人的群成员列表. 当机器人登录后成员列表就会 + * 取得机器人的群成员列表 */ -@Suppress("WRONG_MODIFIER_TARGET") -suspend inline val Bot.groups: ContactList +inline val Bot.groups: ContactList get() = this.contacts.groups -@Suppress("WRONG_MODIFIER_TARGET") -suspend inline val Bot.qqs: ContactList +/** + * 取得机器人的好友列表 + */ +inline val Bot.qqs: ContactList get() = this.contacts.qqs /** @@ -53,5 +54,7 @@ suspend inline fun Bot.login(noinline configuration: BotNetworkConfiguration.() */ suspend inline fun Bot.login(): LoginResult = this.network.login(BotNetworkConfiguration.Default) -//BotAccount +/** + * 取得机器人的 QQ 号 + */ inline val Bot.qqAccount: UInt get() = this.account.id \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotNetworkHandler.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotNetworkHandler.kt index 6a0fea7e6..6454398e7 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotNetworkHandler.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotNetworkHandler.kt @@ -2,6 +2,7 @@ package net.mamoe.mirai.network import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job import kotlinx.coroutines.cancelChildren import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler.BotSocketAdapter import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler.LoginHandler @@ -10,10 +11,11 @@ import net.mamoe.mirai.network.protocol.tim.packet.HeartbeatPacket import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket import net.mamoe.mirai.network.protocol.tim.packet.Packet import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket +import net.mamoe.mirai.network.protocol.tim.packet.event.ServerEventPacket import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult +import net.mamoe.mirai.network.protocol.tim.packet.login.RequestSKeyPacket import net.mamoe.mirai.utils.BotNetworkConfiguration import net.mamoe.mirai.utils.PlatformDatagramChannel -import kotlin.coroutines.ContinuationInterceptor /** * Mirai 的网络处理器, 它承担所有数据包([Packet])的处理任务. @@ -36,7 +38,7 @@ import kotlin.coroutines.ContinuationInterceptor * [BotNetworkHandler] 的协程包含: * - UDP 包接收: [PlatformDatagramChannel.read] * - 心跳 Job [HeartbeatPacket] - * - SKey 刷新 [ReuestSKeyPcket] + * - SKey 刷新 [RequestSKeyPacket] * - 所有数据包处理和发送 * * [BotNetworkHandler.close] 时将会 [取消][kotlin.coroutines.CoroutineContext.cancelChildren] 所有此作用域下的协程 @@ -58,6 +60,7 @@ interface BotNetworkHandler : CoroutineScope { /** * 依次尝试登录到可用的服务器. 在任一服务器登录完成后返回登录结果 + * 本函数将挂起直到登录成功. */ suspend fun login(configuration: BotNetworkConfiguration): LoginResult @@ -79,8 +82,11 @@ interface BotNetworkHandler : CoroutineScope { */ suspend fun awaitDisconnection() + /** + * 关闭网络接口, 停止所有有关协程和任务 + */ suspend fun close(cause: Throwable? = null) { //todo check?? - coroutineContext[ContinuationInterceptor]!!.cancelChildren(CancellationException("handler closed", cause)) + coroutineContext[Job]!!.cancelChildren(CancellationException("handler closed", cause)) } } \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/LoginResult.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/LoginResult.kt index c7082ba2c..c0fdc0576 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/LoginResult.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/LoginResult.kt @@ -1,5 +1,9 @@ package net.mamoe.mirai.network.protocol.tim.packet.login +/** + * 登录结果. 除 [SUCCESS] 外均为失败. + * @see LoginResult.requireSuccess 要求成功 + */ enum class LoginResult { /** * 登录成功 @@ -45,4 +49,19 @@ enum class LoginResult { * 超时 */ TIMEOUT, +} + +/** + * 如果 [this] 不为 [LoginResult.SUCCESS] 就抛出消息为 [lazyMessage] 的 [IllegalStateException] + */ +fun LoginResult.requireSuccess(lazyMessage: (LoginResult) -> String) { + if (this != LoginResult.SUCCESS) error(lazyMessage(this)) +} + + +/** + * 如果 [this] 不为 [LoginResult.SUCCESS] 就抛出消息为 "Login failed $this" 的 [IllegalStateException] + */ +fun LoginResult.requireSuccess() { + if (this != LoginResult.SUCCESS) error("Login failed: $this") } \ No newline at end of file diff --git a/mirai-demos/mirai-demo-1/build.gradle.kts b/mirai-demos/mirai-demo-1/build.gradle.kts deleted file mode 100644 index e69de29bb..000000000 diff --git a/mirai-demos/mirai-demo-1/src/main/java/demo1/Main.kt b/mirai-demos/mirai-demo-1/src/main/java/demo1/Main.kt index 129cc4307..10d308ed9 100644 --- a/mirai-demos/mirai-demo-1/src/main/java/demo1/Main.kt +++ b/mirai-demos/mirai-demo-1/src/main/java/demo1/Main.kt @@ -18,11 +18,13 @@ import net.mamoe.mirai.message.PlainText import net.mamoe.mirai.message.firstOrNull import net.mamoe.mirai.network.protocol.tim.packet.OutgoingRawPacket import net.mamoe.mirai.network.protocol.tim.packet.action.uploadImage -import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult +import net.mamoe.mirai.network.protocol.tim.packet.login.requireSuccess import net.mamoe.mirai.network.session import net.mamoe.mirai.qqAccount -import net.mamoe.mirai.utils.* +import net.mamoe.mirai.utils.hexToBytes import net.mamoe.mirai.utils.io.toUHexString +import net.mamoe.mirai.utils.toByteArray +import net.mamoe.mirai.utils.toExternalImage import java.io.File private fun readTestAccount(): BotAccount? { @@ -45,17 +47,13 @@ suspend fun main() { readTestAccount() ?: BotAccount(//填写你的账号 id = 1994701121u, password = "123456" - ), PlatformLogger() + ) ) + // 覆盖默认的配置 bot.login { randomDeviceName = false - }.let { - if (it != LoginResult.SUCCESS) { - MiraiLogger.logError("Login failed: " + it.name) - bot.close() - } - } + }.requireSuccess() subscribeAlways { if (it.message eq "复读" && it.group.internalId.value == 580266363u) { diff --git a/mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo1/Main.kt b/mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo1/Main.kt index abe7a8098..422b6e132 100644 --- a/mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo1/Main.kt +++ b/mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo1/Main.kt @@ -2,30 +2,10 @@ package demo1 -import kotlinx.coroutines.delay -import kotlinx.coroutines.withTimeoutOrNull import net.mamoe.mirai.Bot import net.mamoe.mirai.BotAccount -import net.mamoe.mirai.event.events.FriendMessageEvent -import net.mamoe.mirai.event.events.GroupMessageEvent -import net.mamoe.mirai.event.subscribeAll -import net.mamoe.mirai.event.subscribeAlways -import net.mamoe.mirai.event.subscribeUntilFalse import net.mamoe.mirai.login -import net.mamoe.mirai.message.Image -import net.mamoe.mirai.message.ImageId -import net.mamoe.mirai.message.PlainText -import net.mamoe.mirai.message.firstOrNull -import net.mamoe.mirai.network.protocol.tim.packet.OutgoingRawPacket -import net.mamoe.mirai.network.protocol.tim.packet.action.uploadImage -import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult -import net.mamoe.mirai.network.session -import net.mamoe.mirai.qqAccount -import net.mamoe.mirai.utils.MiraiLogger -import net.mamoe.mirai.utils.hexToBytes -import net.mamoe.mirai.utils.io.toUHexString -import net.mamoe.mirai.utils.toByteArray -import net.mamoe.mirai.utils.toExternalImage +import net.mamoe.mirai.network.protocol.tim.packet.login.requireSuccess import java.io.File private fun readTestAccount(): BotAccount? { @@ -51,129 +31,7 @@ suspend fun main() { ) ) - bot.login { - randomDeviceName = false - }.let { - if (it != LoginResult.SUCCESS) { - MiraiLogger.logError("Login failed: " + it.name) - bot.close() - } - } - - subscribeAlways { - if (it.message eq "复读" && it.group.internalId.value == 580266363u) { - it.reply(it.message) - } - } - - // 使用 Bot 的扩展方法监听, 将在处理事件时得到一个 this: Bot. - // 这样可以很方便地调用 Bot 内的一些扩展方法如 UInt.qq():QQ - bot.subscribeAlways { - // this: Bot - // it: FriendMessageEvent - - // 获取第一个纯文本消息, 获取不到会抛出 NoSuchElementException - // val firstText = it.message.first() - val firstText = it.message.firstOrNull<PlainText>() - - // 获取第一个图片 - val firstImage = it.message.firstOrNull<Image>() - - when { - it.message eq "你好" -> it.reply("你好!") - - "复读" in it.message -> it.sender.sendMessage(it.message) - - "发群消息" in it.message -> 580266363u.group().sendMessage(it.message.toString().substringAfter("发群消息")) - - "直接发送包" in it.message -> { - val d = - ("01 " + 1994701021u.toByteArray().toUHexString() + " 3E 03 3F A2 00 00 02 BB 00 0A 00 01 00 01 00 5E 4F 53 52 6F 6F 74 3A 43 3A 5C 55 73 65 72 73 5C 48 69 6D 31 38 5C 44 6F 63 75 6D 65 6E 74 73 5C 54 65 6E 63 65 6E 74 20 46 69 6C 65 73 5C 31 30 34 30 34 30 30 32 39 30 5C 49 6D 61 67 65 5C 43 32 43 5C 7B 47 47 42 7E 49 31 5A 4D 43 28 25 49 4D 5A 5F 47 55 51 36 35 5D 51 2E 6A 70 67 00 00 04 7D 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 35 02") - .hexToBytes() - it.bot.network.socket.sendPacket( - OutgoingRawPacket( - 0x01_BDu, - it.bot.qqAccount, - "00 00 00 01 2E 01 00 00 69 35".hexToBytes(), - it.bot.network.session.sessionKey, - d - ) - ) - } - - "上传好友图片" in it.message -> withTimeoutOrNull(5000) { - val filename = it.message.toString().substringAfter("上传好友图片") - val id = 1040400290u.qq() - .uploadImage(File("C:\\Users\\Him18\\Desktop\\$filename").toExternalImage()) - it.reply(id.value) - delay(100) - it.reply(Image(id)) - } - - "上传群图片" in it.message -> withTimeoutOrNull(5000) { - val filename = it.message.toString().substringAfter("上传群图片") - val image = File( - "C:\\Users\\Him18\\Desktop\\$filename" - ).toExternalImage() - 920503456u.group().uploadImage(image) - it.reply(image.groupImageId.value) - delay(100) - 920503456u.group().sendMessage(Image(image.groupImageId)) - } - - "发群图片" in it.message -> { - 920503456u.group().sendMessage(Image(ImageId(it.message.toString().substringAfter("发群图片")))) - } - - "发好友图片" in it.message -> { - it.reply(Image(ImageId(it.message.toString().substringAfter("发好友图片")))) - } - - /*it.event eq "发图片群" -> sendGroupMessage(Group(session.bot, 580266363), PlainText("test") + UnsolvedImage(File("C:\\Users\\Him18\\Desktop\\faceImage_1559564477775.jpg")).also { image -> - image.upload(session, Group(session.bot, 580266363)).of() - })*/ - - it.message eq "发图片群2" -> 580266363u.group().sendMessage(Image(ImageId("{7AA4B3AA-8C3C-0F45-2D9B-7F302A0ACEAA}.jpg"))) - - /* it.event eq "发图片" -> sendFriendMessage(it.sender, PlainText("test") + UnsolvedImage(File("C:\\Users\\Him18\\Desktop\\faceImage_1559564477775.jpg")).also { image -> - image.upload(session, it.sender).of() - })*/ - it.message eq "发图片2" -> it.reply(PlainText("test") + Image(ImageId("{7AA4B3AA-8C3C-0F45-2D9B-7F302A0ACEAA}.jpg"))) - else -> { - - } - } - } - - - //DSL 监听 - subscribeAll<FriendMessageEvent> { - always { - //获取第一个纯文本消息 - val firstText = it.message.firstOrNull<PlainText>() - - } - } - - demo2() + bot.login().requireSuccess() bot.network.awaitDisconnection()//等到直到断开连接 -} - - -/** - * 实现功能: - * 对机器人说 "记笔记", 机器人记录之后的所有消息. - * 对机器人说 "停止", 机器人停止 - */ -suspend fun demo2() { - subscribeAlways<FriendMessageEvent> { event -> - if (event.message eq "记笔记") { - subscribeUntilFalse<FriendMessageEvent> { - it.reply("你发送了 ${it.message}") - - it.message eq "停止" - } - } - } } \ No newline at end of file