Commit a9a0e621 authored by Him188's avatar Him188

Add contracts

parent 2697ac8f
...@@ -19,6 +19,9 @@ import net.mamoe.mirai.utils.BotConfiguration ...@@ -19,6 +19,9 @@ import net.mamoe.mirai.utils.BotConfiguration
import net.mamoe.mirai.utils.DefaultLogger import net.mamoe.mirai.utils.DefaultLogger
import net.mamoe.mirai.utils.MiraiLogger import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.internal.coerceAtLeastOrFail 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.coroutines.CoroutineContext
import kotlin.jvm.JvmOverloads import kotlin.jvm.JvmOverloads
...@@ -228,29 +231,36 @@ Mirai 22:04:48 : Packet received: UnknownEventPacket(id=00 D6, identity=(2092749 ...@@ -228,29 +231,36 @@ Mirai 22:04:48 : Packet received: UnknownEventPacket(id=00 D6, identity=(2092749
* @param lazyMessage 若需要验证请求时的验证消息. * @param lazyMessage 若需要验证请求时的验证消息.
* @param lazyRemark 好友备注 * @param lazyRemark 好友备注
*/ */
suspend fun ContactSystem.addFriend(id: UInt, lazyMessage: () -> String = { "" }, lazyRemark: () -> String = { "" }): AddFriendResult = bot.withSession { @UseExperimental(ExperimentalContracts::class)
when (CanAddFriendPacket(bot.qqAccount, id, bot.sessionKey).sendAndExpect<CanAddFriendResponse>()) { suspend fun ContactSystem.addFriend(id: UInt, lazyMessage: () -> String = { "" }, lazyRemark: () -> String = { "" }): AddFriendResult {
is CanAddFriendResponse.AlreadyAdded -> AddFriendResult.ALREADY_ADDED contract {
is CanAddFriendResponse.Rejected -> AddFriendResult.REJECTED callsInPlace(lazyMessage, InvocationKind.AT_MOST_ONCE)
callsInPlace(lazyRemark, InvocationKind.AT_MOST_ONCE)
is CanAddFriendResponse.ReadyToAdd, }
is CanAddFriendResponse.RequireVerification -> { return bot.withSession {
val key = RequestFriendAdditionKeyPacket(bot.qqAccount, id, sessionKey).sendAndExpect<RequestFriendAdditionKeyPacket.Response>().key when (CanAddFriendPacket(bot.qqAccount, id, bot.sessionKey).sendAndExpect<CanAddFriendResponse>()) {
AddFriendPacket(bot.qqAccount, id, sessionKey, lazyMessage(), lazyRemark(), key).sendAndExpect<AddFriendPacket.Response>() is CanAddFriendResponse.AlreadyAdded -> AddFriendResult.ALREADY_ADDED
return AddFriendResult.WAITING_FOR_APPROVE is CanAddFriendResponse.Rejected -> AddFriendResult.REJECTED
}
//这个做的是需要验证消息的情况, 不确定 ReadyToAdd 的是啥 is CanAddFriendResponse.ReadyToAdd,
is CanAddFriendResponse.RequireVerification -> {
val key = RequestFriendAdditionKeyPacket(bot.qqAccount, id, sessionKey).sendAndExpect<RequestFriendAdditionKeyPacket.Response>().key
AddFriendPacket(bot.qqAccount, id, sessionKey, lazyMessage(), lazyRemark(), key).sendAndExpect<AddFriendPacket.Response>()
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 这不需要验证信息的情况 // TODO: 2019/11/11 这不需要验证信息的情况
//AddFriendPacket(bot.qqAccount, id, bot.sessionKey, ).sendAndExpectAsync<AddFriendPacket.Response>().await() //AddFriendPacket(bot.qqAccount, id, bot.sessionKey, ).sendAndExpectAsync<AddFriendPacket.Response>().await()
TODO() TODO()
}*/ }*/
}
} }
} }
......
...@@ -7,10 +7,14 @@ import net.mamoe.mirai.network.BotNetworkHandler ...@@ -7,10 +7,14 @@ import net.mamoe.mirai.network.BotNetworkHandler
import net.mamoe.mirai.network.BotSession import net.mamoe.mirai.network.BotSession
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket 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.LoginResult
import net.mamoe.mirai.network.protocol.tim.packet.login.requireSuccess
import net.mamoe.mirai.network.session import net.mamoe.mirai.network.session
import net.mamoe.mirai.utils.BotConfiguration import net.mamoe.mirai.utils.BotConfiguration
import net.mamoe.mirai.utils.internal.PositiveNumbers import net.mamoe.mirai.utils.internal.PositiveNumbers
import net.mamoe.mirai.utils.internal.coerceAtLeastOrFail import net.mamoe.mirai.utils.internal.coerceAtLeastOrFail
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.jvm.JvmOverloads import kotlin.jvm.JvmOverloads
/* /*
...@@ -43,7 +47,13 @@ inline val Bot.qqs: ContactList<QQ> ...@@ -43,7 +47,13 @@ inline val Bot.qqs: ContactList<QQ>
* 以 [BotSession] 作为接收器 (receiver) 并调用 [block], 返回 [block] 的返回值. * 以 [BotSession] 作为接收器 (receiver) 并调用 [block], 返回 [block] 的返回值.
* 这个方法将能帮助使用在 [BotSession] 中定义的一些扩展方法, 如 [BotSession.sendAndExpectAsync] * 这个方法将能帮助使用在 [BotSession] 中定义的一些扩展方法, 如 [BotSession.sendAndExpectAsync]
*/ */
inline fun <R> Bot.withSession(block: BotSession.() -> R): R = with(this.network.session) { block() } @UseExperimental(ExperimentalContracts::class)
inline fun <R> 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 ...@@ -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]) 登录 * 使用默认的配置 ([BotConfiguration.Default]) 登录
*/ */
suspend inline fun Bot.login(): LoginResult = this.network.login(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 @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 号 * 取得机器人的 QQ 号
......
package net.mamoe.mirai.network.protocol.tim.packet.login package net.mamoe.mirai.network.protocol.tim.packet.login
import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult.SUCCESS import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult.SUCCESS
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
/** /**
* 登录结果. 除 [SUCCESS] 外均为失败. * 登录结果. 除 [SUCCESS] 外均为失败.
...@@ -56,7 +59,11 @@ enum class LoginResult { ...@@ -56,7 +59,11 @@ enum class LoginResult {
/** /**
* 如果 [this] 不为 [LoginResult.SUCCESS] 就抛出消息为 [lazyMessage] 的 [IllegalStateException] * 如果 [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)) if (this != SUCCESS) error(lazyMessage(this))
} }
...@@ -86,5 +93,10 @@ fun LoginResult.requireSuccessOrNull(): Unit? = ...@@ -86,5 +93,10 @@ fun LoginResult.requireSuccessOrNull(): Unit? =
* *
* @return 成功时 [Unit], 失败时 `null` * @return 成功时 [Unit], 失败时 `null`
*/ */
inline fun <R> LoginResult.ifFail(block: (LoginResult) -> R): R? = @UseExperimental(ExperimentalContracts::class)
if (this != SUCCESS) block(this) else null inline fun <R> LoginResult.ifFail(block: (LoginResult) -> R): R? {
contract {
callsInPlace(block, InvocationKind.AT_MOST_ONCE)
}
return if (this != SUCCESS) block(this) else null
}
...@@ -16,7 +16,7 @@ fun <R> CoroutineScope.SuspendLazy(initializer: suspend () -> R): Lazy<Deferred< ...@@ -16,7 +16,7 @@ fun <R> CoroutineScope.SuspendLazy(initializer: suspend () -> R): Lazy<Deferred<
/** /**
* 挂起初始化的 [lazy], 是属性不能 `suspend` 的替代品. * 挂起初始化的 [lazy], 是属性不能 `suspend` 的替代品.
* *
* 本对象代表值初始化时将会通过 [CoroutineScope.async] 运行 [initializer] * 本对象代表值初始化时将会通过 [CoroutineScope.async] 运行 [valueUpdater]
* *
* [SuspendLazy] 是: * [SuspendLazy] 是:
* - 线程安全 * - 线程安全
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment