diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt index 2b7997125..fd55a1722 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt @@ -19,6 +19,9 @@ import net.mamoe.mirai.utils.BotConfiguration import net.mamoe.mirai.utils.DefaultLogger import net.mamoe.mirai.utils.MiraiLogger import net.mamoe.mirai.utils.internal.coerceAtLeastOrFail +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract import kotlin.coroutines.CoroutineContext import kotlin.jvm.JvmOverloads @@ -228,29 +231,36 @@ Mirai 22:04:48 : Packet received: UnknownEventPacket(id=00 D6, identity=(2092749 * @param lazyMessage 若需要验证请求时的验证消息. * @param lazyRemark 好友备注 */ -suspend fun ContactSystem.addFriend(id: UInt, lazyMessage: () -> String = { "" }, lazyRemark: () -> String = { "" }): AddFriendResult = bot.withSession { - when (CanAddFriendPacket(bot.qqAccount, id, bot.sessionKey).sendAndExpect()) { - is CanAddFriendResponse.AlreadyAdded -> AddFriendResult.ALREADY_ADDED - is CanAddFriendResponse.Rejected -> AddFriendResult.REJECTED +@UseExperimental(ExperimentalContracts::class) +suspend fun ContactSystem.addFriend(id: UInt, lazyMessage: () -> String = { "" }, lazyRemark: () -> String = { "" }): AddFriendResult { + contract { + callsInPlace(lazyMessage, InvocationKind.AT_MOST_ONCE) + callsInPlace(lazyRemark, InvocationKind.AT_MOST_ONCE) + } + return bot.withSession { + when (CanAddFriendPacket(bot.qqAccount, id, bot.sessionKey).sendAndExpect()) { + is CanAddFriendResponse.AlreadyAdded -> AddFriendResult.ALREADY_ADDED + is CanAddFriendResponse.Rejected -> AddFriendResult.REJECTED - is CanAddFriendResponse.ReadyToAdd, - is CanAddFriendResponse.RequireVerification -> { - val key = RequestFriendAdditionKeyPacket(bot.qqAccount, id, sessionKey).sendAndExpect().key - AddFriendPacket(bot.qqAccount, id, sessionKey, lazyMessage(), lazyRemark(), key).sendAndExpect() - return AddFriendResult.WAITING_FOR_APPROVE - } - //这个做的是需要验证消息的情况, 不确定 ReadyToAdd 的是啥 + is CanAddFriendResponse.ReadyToAdd, + is CanAddFriendResponse.RequireVerification -> { + val key = RequestFriendAdditionKeyPacket(bot.qqAccount, id, sessionKey).sendAndExpect().key + AddFriendPacket(bot.qqAccount, id, sessionKey, lazyMessage(), lazyRemark(), key).sendAndExpect() + return AddFriendResult.WAITING_FOR_APPROVE + } + //这个做的是需要验证消息的情况, 不确定 ReadyToAdd 的是啥 - // 似乎 RequireVerification 和 ReadyToAdd 判断错了. 需要重新检查一下 + // 似乎 RequireVerification 和 ReadyToAdd 判断错了. 需要重新检查一下 - // TODO: 2019/11/11 需要验证问题的情况 + // TODO: 2019/11/11 需要验证问题的情况 - /*is CanAddFriendResponse.ReadyToAdd -> { + /*is CanAddFriendResponse.ReadyToAdd -> { // TODO: 2019/11/11 这不需要验证信息的情况 //AddFriendPacket(bot.qqAccount, id, bot.sessionKey, ).sendAndExpectAsync().await() TODO() }*/ + } } } 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 06ff06ea3..21e7b549c 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotHelper.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotHelper.kt @@ -7,10 +7,14 @@ import net.mamoe.mirai.network.BotNetworkHandler import net.mamoe.mirai.network.BotSession import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket 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.utils.BotConfiguration import net.mamoe.mirai.utils.internal.PositiveNumbers import net.mamoe.mirai.utils.internal.coerceAtLeastOrFail +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract import kotlin.jvm.JvmOverloads /* @@ -43,7 +47,13 @@ inline val Bot.qqs: ContactList * 以 [BotSession] 作为接收器 (receiver) 并调用 [block], 返回 [block] 的返回值. * 这个方法将能帮助使用在 [BotSession] 中定义的一些扩展方法, 如 [BotSession.sendAndExpectAsync] */ -inline fun Bot.withSession(block: BotSession.() -> R): R = with(this.network.session) { block() } +@UseExperimental(ExperimentalContracts::class) +inline fun Bot.withSession(block: BotSession.() -> R): R { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return with(this.network.session) { block() } +} /** * 发送数据包 @@ -54,18 +64,43 @@ suspend inline fun Bot.sendPacket(packet: OutgoingPacket) = this.network.sendPac /** * 使用在默认配置基础上修改的配置进行登录 */ -suspend inline fun Bot.login(noinline configuration: BotConfiguration.() -> Unit): LoginResult = this.network.login(BotConfiguration().apply(configuration)) +@UseExperimental(ExperimentalContracts::class) +suspend inline fun Bot.login(noinline configuration: BotConfiguration.() -> Unit): LoginResult { + contract { + callsInPlace(configuration, InvocationKind.EXACTLY_ONCE) + } + return this.network.login(BotConfiguration().apply(configuration)) +} /** * 使用默认的配置 ([BotConfiguration.Default]) 登录 */ suspend inline fun Bot.login(): LoginResult = this.network.login(BotConfiguration.Default) +/** + * 使用默认的配置 ([BotConfiguration.Default]) 登录 + */ +@UseExperimental(ExperimentalContracts::class) +suspend inline fun Bot.alsoLogin(lazyMessageWhenLoginFailed: (LoginResult) -> String): Bot { + contract { + callsInPlace(lazyMessageWhenLoginFailed, InvocationKind.AT_MOST_ONCE) + } + return this.apply { + login().requireSuccess(lazyMessageWhenLoginFailed) + } +} + /** * 添加好友 */ +@UseExperimental(ExperimentalContracts::class) @JvmOverloads -suspend inline fun Bot.addFriend(id: UInt, noinline lazyMessage: () -> String = { "" }): AddFriendResult = this.contacts.addFriend(id, lazyMessage) +suspend inline fun Bot.addFriend(id: UInt, noinline lazyMessage: () -> String = { "" }, noinline lazyRemark: () -> String = { "" }): AddFriendResult { + contract { + callsInPlace(lazyMessage, InvocationKind.AT_MOST_ONCE) + } + return this.contacts.addFriend(id, lazyMessage, lazyRemark) +} /** * 取得机器人的 QQ 号 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 d0a274f8a..e434a2ba2 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,6 +1,9 @@ package net.mamoe.mirai.network.protocol.tim.packet.login import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult.SUCCESS +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract /** * 登录结果. 除 [SUCCESS] 外均为失败. @@ -56,7 +59,11 @@ enum class LoginResult { /** * 如果 [this] 不为 [LoginResult.SUCCESS] 就抛出消息为 [lazyMessage] 的 [IllegalStateException] */ -fun LoginResult.requireSuccess(lazyMessage: (LoginResult) -> String) { +@UseExperimental(ExperimentalContracts::class) +inline fun LoginResult.requireSuccess(lazyMessage: (LoginResult) -> String) { + contract { + callsInPlace(lazyMessage, InvocationKind.AT_MOST_ONCE) + } if (this != SUCCESS) error(lazyMessage(this)) } @@ -86,5 +93,10 @@ fun LoginResult.requireSuccessOrNull(): Unit? = * * @return 成功时 [Unit], 失败时 `null` */ -inline fun LoginResult.ifFail(block: (LoginResult) -> R): R? = - if (this != SUCCESS) block(this) else null +@UseExperimental(ExperimentalContracts::class) +inline fun LoginResult.ifFail(block: (LoginResult) -> R): R? { + contract { + callsInPlace(block, InvocationKind.AT_MOST_ONCE) + } + return if (this != SUCCESS) block(this) else null +} diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/SuspendLazy.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/SuspendLazy.kt index dbbd6b0f5..cbc9b2f2c 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/SuspendLazy.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/SuspendLazy.kt @@ -16,7 +16,7 @@ fun CoroutineScope.SuspendLazy(initializer: suspend () -> R): Lazy