Commit 61b10db8 authored by Him188's avatar Him188

Profile suppport

parent 849f5caf
...@@ -33,6 +33,7 @@ Mirai 在 JVM 平台采用插件模式运行,同时提供独立的跨平台核 ...@@ -33,6 +33,7 @@ Mirai 在 JVM 平台采用插件模式运行,同时提供独立的跨平台核
- 上传并发送好友/群图片(10/21, 10/26) - 上传并发送好友/群图片(10/21, 10/26)
- 群员权限改变(11/2) - 群员权限改变(11/2)
- 发起会话(11/2) - 发起会话(11/2)
- 个人资料(11/2)
计划中: 添加好友 计划中: 添加好友
......
...@@ -105,10 +105,10 @@ class Bot(val account: BotAccount, val logger: MiraiLogger) { ...@@ -105,10 +105,10 @@ class Bot(val account: BotAccount, val logger: MiraiLogger) {
* *
* 注: 这个方法是线程安全的 * 注: 这个方法是线程安全的
*/ */
suspend fun getQQ(account: UInt): QQ = suspend fun getQQ(id: UInt): QQ =
if (qqs.containsKey(account)) qqs[account]!! if (qqs.containsKey(id)) qqs[id]!!
else qqsLock.withLock { else qqsLock.withLock {
qqs.getOrPut(account) { QQ(this@Bot, account) } qqs.getOrPut(id) { QQ(this@Bot, id) }
} }
/** /**
...@@ -129,6 +129,7 @@ class Bot(val account: BotAccount, val logger: MiraiLogger) { ...@@ -129,6 +129,7 @@ class Bot(val account: BotAccount, val logger: MiraiLogger) {
groups.getOrPut(it) { Group(this@Bot, id) } groups.getOrPut(it) { Group(this@Bot, id) }
} }
} }
} }
suspend inline fun Int.qq(): QQ = getQQ(this.coerceAtLeastOrFail(0).toUInt()) suspend inline fun Int.qq(): QQ = getQQ(this.coerceAtLeastOrFail(0).toUInt())
...@@ -150,4 +151,9 @@ class Bot(val account: BotAccount, val logger: MiraiLogger) { ...@@ -150,4 +151,9 @@ class Bot(val account: BotAccount, val logger: MiraiLogger) {
companion object { companion object {
val instances: MutableList<Bot> = mutableListOf() val instances: MutableList<Bot> = mutableListOf()
} }
} }
\ No newline at end of file
/**
* 添加一个好友
*/
suspend fun ContactSystem.addFriend(id: UInt): Nothing = TODO()
\ No newline at end of file
@file:Suppress("EXPERIMENTAL_API_USAGE", "unused") @file:Suppress("EXPERIMENTAL_API_USAGE", "unused", "MemberVisibilityCanBePrivate")
package net.mamoe.mirai.contact package net.mamoe.mirai.contact
import com.soywiz.klock.Date
import kotlinx.coroutines.Deferred
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.message.Message import net.mamoe.mirai.message.Message
import net.mamoe.mirai.message.MessageChain import net.mamoe.mirai.message.MessageChain
import net.mamoe.mirai.message.singleChain import net.mamoe.mirai.message.singleChain
import net.mamoe.mirai.network.BotSession import net.mamoe.mirai.network.BotSession
import net.mamoe.mirai.network.protocol.tim.handler.EventPacketHandler import net.mamoe.mirai.network.protocol.tim.handler.EventPacketHandler
import net.mamoe.mirai.network.protocol.tim.packet.action.RequestProfileDetailsPacket
import net.mamoe.mirai.qqAccount
import net.mamoe.mirai.utils.SuspendLazy
import net.mamoe.mirai.utils.internal.coerceAtLeastOrFail import net.mamoe.mirai.utils.internal.coerceAtLeastOrFail
import net.mamoe.mirai.withSession import net.mamoe.mirai.withSession
...@@ -23,6 +28,9 @@ class ContactList<C : Contact> : MutableMap<UInt, C> by mutableMapOf() ...@@ -23,6 +28,9 @@ class ContactList<C : Contact> : MutableMap<UInt, C> by mutableMapOf()
*/ */
sealed class Contact(val bot: Bot, val id: UInt) { sealed class Contact(val bot: Bot, val id: UInt) {
/**
* 向这个对象发送消息. 速度太快会被服务器拒绝(无响应)
*/
abstract suspend fun sendMessage(message: MessageChain) abstract suspend fun sendMessage(message: MessageChain)
...@@ -102,11 +110,40 @@ inline fun <R> Contact.withSession(block: BotSession.() -> R): R = bot.withSessi ...@@ -102,11 +110,40 @@ inline fun <R> Contact.withSession(block: BotSession.() -> R): R = bot.withSessi
* @author Him188moe * @author Him188moe
*/ */
open class QQ internal constructor(bot: Bot, id: UInt) : Contact(bot, id) { open class QQ internal constructor(bot: Bot, id: UInt) : Contact(bot, id) {
val profile: Deferred<Profile> by bot.network.SuspendLazy { updateProfile() }
override suspend fun sendMessage(message: MessageChain) { override suspend fun sendMessage(message: MessageChain) {
bot.network[EventPacketHandler].sendFriendMessage(this, message) bot.network[EventPacketHandler].sendFriendMessage(this, message)
} }
/**
* 更新个人资料.
*
* 这个方法会尽可能更新已有的 [Profile] 对象的值, 而不是用新的对象替换
* 若 [QQ.profile] 已经初始化, 则在获取到新的 profile 时通过 [Profile.copyFrom] 来更新已有的 [QQ.profile]. 仍然返回 [QQ.profile]
* 因此, 对于以下代码:
* ```kotlin
* val old = qq.profile
* qq.updateProfile() === old // true, 因为只是更新了 qq.profile 的值
* ```
*/
suspend fun updateProfile(): Profile = bot.withSession {
RequestProfileDetailsPacket(bot.qqAccount, id, sessionKey)
.sendAndExpect<RequestProfileDetailsPacket.Response, Profile> { it.profile }
.await().let {
@Suppress("UNCHECKED_CAST")
if ((::profile as SuspendLazy<Profile>).isInitialized()) {
profile.await().apply { copyFrom(it) }
} else it
}
}
suspend fun QQ.addAsFriend() {
}
} }
/** /**
* 群成员 * 群成员
*/ */
...@@ -114,4 +151,39 @@ class Member internal constructor(bot: Bot, id: UInt, val group: Group) : QQ(bot ...@@ -114,4 +151,39 @@ class Member internal constructor(bot: Bot, id: UInt, val group: Group) : QQ(bot
init { init {
TODO("Group member implementation") TODO("Group member implementation")
} }
}
/**
* 个人资料
*/
class Profile// inline class Date
(qq: UInt, nickname: String, zipCode: String?, phone: String?, gender: Gender, var birthday: Date?) {
var qq: UInt = qq
internal set
var nickname: String = nickname
internal set
var zipCode: String? = zipCode
internal set
var phone: String? = phone
internal set
var gender: Gender = gender
internal set
}
fun Profile.copyFrom(another: Profile) {
this.qq = another.qq
this.nickname = another.nickname
this.zipCode = another.zipCode
this.phone = another.phone
this.gender = another.gender
}
/**
* 性别
*/
enum class Gender {
SECRET,
MALE,
FEMALE;
} }
\ No newline at end of file
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
package net.mamoe.mirai.event.events package net.mamoe.mirai.event.events
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.contact.Profile
import net.mamoe.mirai.contact.QQ import net.mamoe.mirai.contact.QQ
import net.mamoe.mirai.message.Message import net.mamoe.mirai.message.Message
import net.mamoe.mirai.message.MessageChain import net.mamoe.mirai.message.MessageChain
...@@ -34,4 +35,9 @@ class FriendConversationInitializedEvent(bot: Bot, sender: QQ) : FriendEvent(bot ...@@ -34,4 +35,9 @@ class FriendConversationInitializedEvent(bot: Bot, sender: QQ) : FriendEvent(bot
/** /**
* 好友在线状态改变事件 * 好友在线状态改变事件
*/ */
class FriendOnlineStatusChangedEvent(bot: Bot, sender: QQ, val newStatus: OnlineStatus) : FriendEvent(bot, sender) class FriendOnlineStatusChangedEvent(bot: Bot, sender: QQ, val newStatus: OnlineStatus) : FriendEvent(bot, sender)
\ No newline at end of file
/**
* 好友个人资料更新
*/
class FriendProfileUpdatedEvent(bot: Bot, qq: QQ, val profile: Profile) : FriendEvent(bot, qq)
\ No newline at end of file
...@@ -146,7 +146,7 @@ fun String.singleChain(): MessageChain = this.toMessage().singleChain() ...@@ -146,7 +146,7 @@ fun String.singleChain(): MessageChain = this.toMessage().singleChain()
* *
* @param id 这个图片的 [ImageId] * @param id 这个图片的 [ImageId]
*/ */
inline class Image(val id: ImageId) : Message { inline class Image(inline val id: ImageId) : Message {
override val stringValue: String get() = "[${id.value}]" override val stringValue: String get() = "[${id.value}]"
override fun toString(): String = stringValue override fun toString(): String = stringValue
...@@ -161,7 +161,7 @@ inline class Image(val id: ImageId) : Message { ...@@ -161,7 +161,7 @@ inline class Image(val id: ImageId) : Message {
* @see ExternalImage.groupImageId 群图片的 [ImageId] 获取 * @see ExternalImage.groupImageId 群图片的 [ImageId] 获取
* @see FriendImageIdRequestPacket.Response.imageId 好友图片的 [ImageId] 获取 * @see FriendImageIdRequestPacket.Response.imageId 好友图片的 [ImageId] 获取
*/ */
inline class ImageId(val value: String) inline class ImageId(inline val value: String)
fun ImageId.image(): Image = Image(this) fun ImageId.image(): Image = Image(this)
......
...@@ -8,7 +8,9 @@ import kotlinx.io.core.ByteReadPacket ...@@ -8,7 +8,9 @@ import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.use import kotlinx.io.core.use
import kotlinx.io.core.writeUShort import kotlinx.io.core.writeUShort
import net.mamoe.mirai.network.protocol.tim.TIMProtocol import net.mamoe.mirai.network.protocol.tim.TIMProtocol
import net.mamoe.mirai.utils.io.encryptAndWrite
import net.mamoe.mirai.utils.io.writeHex import net.mamoe.mirai.utils.io.writeHex
import net.mamoe.mirai.utils.io.writeQQ
import kotlin.jvm.JvmOverloads import kotlin.jvm.JvmOverloads
/** /**
...@@ -55,6 +57,7 @@ interface OutgoingPacketBuilder { ...@@ -55,6 +57,7 @@ interface OutgoingPacketBuilder {
/** /**
* 构造一个待发送给服务器的数据包. * 构造一个待发送给服务器的数据包.
*
* 若不提供参数 [id], 则会通过注解 [AnnotatedId] 获取 id. * 若不提供参数 [id], 则会通过注解 [AnnotatedId] 获取 id.
*/ */
@JvmOverloads @JvmOverloads
...@@ -76,4 +79,27 @@ fun OutgoingPacketBuilder.buildOutgoingPacket( ...@@ -76,4 +79,27 @@ fun OutgoingPacketBuilder.buildOutgoingPacket(
} }
return OutgoingPacket(name, id, sequenceId, it.build()) return OutgoingPacket(name, id, sequenceId, it.build())
} }
}
/**
* 构造一个待发送给服务器的会话数据包.
*
* 若不提供参数 [id], 则会通过注解 [AnnotatedId] 获取 id.
*/
@JvmOverloads
fun OutgoingPacketBuilder.buildSessionPacket(
bot: UInt,
sessionKey: ByteArray,
name: String? = null,
id: PacketId = this.annotatedId.id,
sequenceId: UShort = OutgoingPacketBuilder.atomicNextSequenceId(),
headerSizeHint: Int = 0,
block: BytePacketBuilder.() -> Unit
): OutgoingPacket = buildOutgoingPacket(name, id, sequenceId, headerSizeHint) {
writeQQ(bot)
writeHex(TIMProtocol.version0x02)
encryptAndWrite(sessionKey) {
block()
}
} }
\ No newline at end of file
...@@ -86,7 +86,8 @@ enum class KnownPacketId(override inline val value: UShort, internal inline val ...@@ -86,7 +86,8 @@ enum class KnownPacketId(override inline val value: UShort, internal inline val
inline GROUP_IMAGE_ID(0x0388u, GroupImageIdRequestPacket), inline GROUP_IMAGE_ID(0x0388u, GroupImageIdRequestPacket),
inline FRIEND_IMAGE_ID(0x0352u, FriendImageIdRequestPacket), inline FRIEND_IMAGE_ID(0x0352u, FriendImageIdRequestPacket),
inline REQUEST_PROFILE(0x00_31u, RequestProfilePicturePacket), inline REQUEST_PROFILE_AVATAR(0x00_31u, RequestProfilePicturePacket),
inline REQUEST_PROFILE_DETAILS(0x00_3Cu, RequestProfilePicturePacket),
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
inline SUBMIT_IMAGE_FILE_NAME(0x01_BDu, SubmitImageFilenamePacket), inline SUBMIT_IMAGE_FILE_NAME(0x01_BDu, SubmitImageFilenamePacket),
......
@file:Suppress("EXPERIMENTAL_UNSIGNED_LITERALS")
package net.mamoe.mirai.network.protocol.tim.packet.action
import net.mamoe.mirai.network.protocol.tim.packet.*
// 用户资料的头像
/**
* 请求获取头像
*/
@AnnotatedId(KnownPacketId.REQUEST_PROFILE)
object RequestProfilePicturePacket : OutgoingPacketBuilder {
operator fun invoke(): OutgoingPacket = buildOutgoingPacket {
}
}
\ No newline at end of file
...@@ -12,8 +12,8 @@ import net.mamoe.mirai.network.protocol.tim.packet.PacketVersion ...@@ -12,8 +12,8 @@ import net.mamoe.mirai.network.protocol.tim.packet.PacketVersion
import net.mamoe.mirai.utils.MiraiLogger import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.io.printTLVMap import net.mamoe.mirai.utils.io.printTLVMap
import net.mamoe.mirai.utils.io.read import net.mamoe.mirai.utils.io.read
import net.mamoe.mirai.utils.io.readLVByteArray
import net.mamoe.mirai.utils.io.readTLVMap import net.mamoe.mirai.utils.io.readTLVMap
import net.mamoe.mirai.utils.io.readUShortLVByteArray
import kotlin.properties.Delegates import kotlin.properties.Delegates
...@@ -43,13 +43,13 @@ class GroupMessageEventPacket(input: ByteReadPacket, eventIdentity: EventPacketI ...@@ -43,13 +43,13 @@ class GroupMessageEventPacket(input: ByteReadPacket, eventIdentity: EventPacketI
qq = readUInt() qq = readUInt()
discardExact(48) discardExact(48)
readLVByteArray() readUShortLVByteArray()
discardExact(2)//2个0x00 discardExact(2)//2个0x00
message = readMessageChain() message = readMessageChain()
val map = readTLVMap(true) val map = readTLVMap(true)
if (map.containsKey(18)) { if (map.containsKey(18u)) {
map.getValue(18).read { map.getValue(18u).read {
val tlv = readTLVMap(true) val tlv = readTLVMap(true)
//tlv.printTLVMap("消息结尾 tag=18 的 TLV") //tlv.printTLVMap("消息结尾 tag=18 的 TLV")
////群主的18: 05 00 04 00 00 00 03 08 00 04 00 00 00 04 01 00 09 48 69 6D 31 38 38 6D 6F 65 03 00 01 04 04 00 04 00 00 00 08 ////群主的18: 05 00 04 00 00 00 03 08 00 04 00 00 00 04 01 00 09 48 69 6D 31 38 38 6D 6F 65 03 00 01 04 04 00 04 00 00 00 08
...@@ -61,7 +61,7 @@ class GroupMessageEventPacket(input: ByteReadPacket, eventIdentity: EventPacketI ...@@ -61,7 +61,7 @@ class GroupMessageEventPacket(input: ByteReadPacket, eventIdentity: EventPacketI
// 没有4, 群员 // 没有4, 群员
// 4=10, 管理员 // 4=10, 管理员
senderPermission = when (tlv.takeIf { it.containsKey(0x04) }?.get(0x04)?.getOrNull(3)?.toUInt()) { senderPermission = when (tlv.takeIf { it.containsKey(0x04u) }?.get(0x04u)?.getOrNull(3)?.toUInt()) {
null -> SenderPermission.MEMBER null -> SenderPermission.MEMBER
0x08u -> SenderPermission.OWNER 0x08u -> SenderPermission.OWNER
0x10u -> SenderPermission.OPERATOR 0x10u -> SenderPermission.OPERATOR
...@@ -73,8 +73,8 @@ class GroupMessageEventPacket(input: ByteReadPacket, eventIdentity: EventPacketI ...@@ -73,8 +73,8 @@ class GroupMessageEventPacket(input: ByteReadPacket, eventIdentity: EventPacketI
} }
senderName = when { senderName = when {
tlv.containsKey(0x01) -> kotlinx.io.core.String(tlv.getValue(0x01))//这个人的qq昵称 tlv.containsKey(0x01u) -> kotlinx.io.core.String(tlv.getValue(0x01u))//这个人的qq昵称
tlv.containsKey(0x02) -> kotlinx.io.core.String(tlv.getValue(0x02))//这个人的群名片 tlv.containsKey(0x02u) -> kotlinx.io.core.String(tlv.getValue(0x02u))//这个人的群名片
else -> { else -> {
tlv.printTLVMap("TLV(tag=18) Map") tlv.printTLVMap("TLV(tag=18) Map")
MiraiLogger.warning("Could not determine senderName") MiraiLogger.warning("Could not determine senderName")
...@@ -113,7 +113,7 @@ class FriendMessageEventPacket(input: ByteReadPacket, eventIdentity: EventPacket ...@@ -113,7 +113,7 @@ class FriendMessageEventPacket(input: ByteReadPacket, eventIdentity: EventPacket
//java.io.EOFException: Only 49 bytes were discarded of 69 requested //java.io.EOFException: Only 49 bytes were discarded of 69 requested
//抖动窗口消息 //抖动窗口消息
discardExact(69) discardExact(69)
readLVByteArray()//font readUShortLVByteArray()//font
discardExact(2)//2个0x00 discardExact(2)//2个0x00
message = readMessageChain() message = readMessageChain()
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
package net.mamoe.mirai.network.protocol.tim.packet.login package net.mamoe.mirai.network.protocol.tim.packet.login
import kotlinx.io.core.* import kotlinx.io.core.*
import net.mamoe.mirai.contact.Gender
import net.mamoe.mirai.network.protocol.tim.TIMProtocol import net.mamoe.mirai.network.protocol.tim.TIMProtocol
import net.mamoe.mirai.network.protocol.tim.packet.* import net.mamoe.mirai.network.protocol.tim.packet.*
import net.mamoe.mirai.utils.Tested import net.mamoe.mirai.utils.Tested
...@@ -50,11 +51,6 @@ class LoginResponseKeyExchangeResponsePacket(input: ByteReadPacket) : ServerLogi ...@@ -50,11 +51,6 @@ class LoginResponseKeyExchangeResponsePacket(input: ByteReadPacket) : ServerLogi
} }
} }
enum class Gender(val id: Boolean) {
MALE(false),
FEMALE(true);
}
@AnnotatedId(KnownPacketId.LOGIN) @AnnotatedId(KnownPacketId.LOGIN)
class LoginResponseSuccessPacket(input: ByteReadPacket) : ServerLoginResponsePacket(input) { class LoginResponseSuccessPacket(input: ByteReadPacket) : ServerLoginResponsePacket(input) {
lateinit var sessionResponseDecryptionKey: IoBuffer//16 bytes| lateinit var sessionResponseDecryptionKey: IoBuffer//16 bytes|
...@@ -119,7 +115,6 @@ class LoginResponseSuccessPacket(input: ByteReadPacket) : ServerLoginResponsePac ...@@ -119,7 +115,6 @@ class LoginResponseSuccessPacket(input: ByteReadPacket) : ServerLoginResponsePac
class Encrypted(input: ByteReadPacket) : ServerPacket(input) { class Encrypted(input: ByteReadPacket) : ServerPacket(input) {
fun decrypt(privateKey: ByteArray): LoginResponseSuccessPacket = LoginResponseSuccessPacket(this.decryptBy(TIMProtocol.shareKey, privateKey)).applySequence(sequenceId) fun decrypt(privateKey: ByteArray): LoginResponseSuccessPacket = LoginResponseSuccessPacket(this.decryptBy(TIMProtocol.shareKey, privateKey)).applySequence(sequenceId)
} }
} }
/** /**
......
...@@ -35,27 +35,30 @@ class GentleImage { ...@@ -35,27 +35,30 @@ class GentleImage {
lateinit var contact: Contact lateinit var contact: Contact
// Deferred<Image?> 将导致 kotlin 内部错误
val image: Deferred<Image> by lazy { val image: Deferred<Image> by lazy {
GlobalScope.async { GlobalScope.async {
delay((Math.random() * 5000L).toLong()) //delay((Math.random() * 5000L).toLong())
withContext(Dispatchers.IO) { class Result {
class Result { var id: String = ""
var id: String = "" }
}
withTimeoutOrNull(5 * 1000) {
withContext(Dispatchers.IO) {
val result = JSON.parseObject(
Jsoup.connect("http://dev.itxtech.org:10322/v2/randomImg.uue").ignoreContentType(true).timeout(10_0000).get().body().text(),
Result::class.java
)
val result = JSON.parseObject( Jsoup.connect("http://dev.itxtech.org:10322/img.uue?size=large&id=${result.id}")
Jsoup.connect("http://dev.itxtech.org:10322/v2/randomImg.uue").ignoreContentType(true).get().body().text(), .userAgent(UserAgent.randomUserAgent)
Result::class.java .timeout(10_0000)
) .ignoreContentType(true)
.maxBodySize(Int.MAX_VALUE)
Jsoup.connect("http://dev.itxtech.org:10322/img.uue?size=large&id=${result.id}") .execute()
.userAgent(UserAgent.randomUserAgent) .bodyStream()
.timeout(20_0000) }
.ignoreContentType(true) }?.upload(contact) ?: error("Unable to download image")
.maxBodySize(Int.MAX_VALUE)
.execute()
.bodyStream()
}.upload(contact)
} }
} }
......
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
package demo.gentleman package demo.gentleman
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.BotAccount import net.mamoe.mirai.BotAccount
import net.mamoe.mirai.event.Event import net.mamoe.mirai.event.Event
...@@ -13,6 +13,7 @@ import net.mamoe.mirai.event.subscribeMessages ...@@ -13,6 +13,7 @@ import net.mamoe.mirai.event.subscribeMessages
import net.mamoe.mirai.login import net.mamoe.mirai.login
import net.mamoe.mirai.network.protocol.tim.packet.login.requireSuccess import net.mamoe.mirai.network.protocol.tim.packet.login.requireSuccess
import java.io.File import java.io.File
import kotlin.random.Random
private fun readTestAccount(): BotAccount? { private fun readTestAccount(): BotAccount? {
val file = File("testAccount.txt") val file = File("testAccount.txt")
...@@ -46,6 +47,9 @@ suspend fun main() { ...@@ -46,6 +47,9 @@ suspend fun main() {
bot.subscribeMessages { bot.subscribeMessages {
"你好" reply "你好!" "你好" reply "你好!"
"profile" reply {
sender.profile.await().toString()
}
/* /*
has<Image> { has<Image> {
...@@ -53,16 +57,15 @@ suspend fun main() { ...@@ -53,16 +57,15 @@ suspend fun main() {
}*/ }*/
startsWith("随机图片", removePrefix = true) { startsWith("随机图片", removePrefix = true) {
withContext(Dispatchers.Default) { try {
try { repeat(it.toIntOrNull() ?: 1) {
repeat(it.toIntOrNull() ?: 1) { GlobalScope.launch {
launch { delay(Random.Default.nextLong(100, 1000))
Gentlemen.provide(subject).receive().image.await().send() Gentlemen.provide(subject).receive().image.await().send()
}
} }
} catch (e: Exception) {
reply(e.message ?: "exception: null")
} }
} catch (e: Exception) {
reply(e.message ?: "exception: null")
} }
} }
......
package demo.gentleman
import kotlin.reflect.KClass
@Throws(TryFailedException::class)
inline fun <T> tryNTimes(
tryTimes: Int,
vararg expectingExceptions: KClass<out Exception> = Array<KClass<out Exception>>(1) { Exception::class },
expectingHandler: (Exception) -> Unit = { },
unexpectingHandler: (Exception) -> Unit = { throw it },
block: () -> T
): T {
require(tryTimes > 0) { "tryTimes must be greater than 0" }
var lastE: java.lang.Exception? = null
repeat(tryTimes) {
try {
return block()
} catch (e: Exception) {
if (lastE != null && lastE !== e) {
e.addSuppressed(lastE)
}
lastE = e
if (expectingExceptions.any { it.isInstance(e) }) {
expectingHandler(e)
} else {
unexpectingHandler(e)
}
}
}
if (lastE != null) {
throw TryFailedException(lastE!!)
}
throw TryFailedException()
}
class TryFailedException : RuntimeException {
constructor() : super()
constructor(e: Exception) : super(e)
}
\ No newline at end of file
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