mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-05 07:30:09 +08:00
This commit is contained in:
parent
b5d8c708bd
commit
2422aa34b5
@ -9,8 +9,104 @@
|
||||
|
||||
package net.mamoe.mirai.utils
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
|
||||
@TestOnly
|
||||
public fun readResource(url: String): String =
|
||||
Thread.currentThread().contextClassLoader.getResourceAsStream(url)?.readBytes()?.decodeToString()
|
||||
?: error("Could not find resource '$url'")
|
||||
|
||||
public class ResourceAccessLock {
|
||||
public companion object {
|
||||
public const val LOCKED: Int = -2
|
||||
public const val UNINITIALIZED: Int = -1
|
||||
public const val INITIALIZED: Int = 0
|
||||
}
|
||||
|
||||
/*
|
||||
* status > 0 -> Number of holders using resource
|
||||
*/
|
||||
private val status = AtomicInteger(-1)
|
||||
|
||||
/**
|
||||
* ```
|
||||
* if (res.lock.tryToDispose()) {
|
||||
* res.internal.close()
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
public fun tryDispose(): Boolean {
|
||||
return status.compareAndSet(0, -1)
|
||||
}
|
||||
|
||||
/**
|
||||
* ```
|
||||
* if (res.lock.tryInitialize()) {
|
||||
* res.internalRes = download()
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
public fun tryInitialize(): Boolean {
|
||||
return status.compareAndSet(-1, 0)
|
||||
}
|
||||
|
||||
public fun tryUse(): Boolean {
|
||||
val c = status
|
||||
while (true) {
|
||||
val v = c.get()
|
||||
if (v < 0) return false
|
||||
if (c.compareAndSet(v, v + 1)) return true
|
||||
}
|
||||
}
|
||||
|
||||
public fun lockIfNotUsing(): Boolean {
|
||||
val count = this.status
|
||||
while (true) {
|
||||
val value = count.get()
|
||||
if (value != 0) return false
|
||||
if (count.compareAndSet(0, -2)) return true
|
||||
}
|
||||
}
|
||||
|
||||
public fun release() {
|
||||
val count = this.status
|
||||
while (true) {
|
||||
val value = count.get()
|
||||
if (value < 1) throw IllegalStateException("Current resource not in using")
|
||||
|
||||
if (count.compareAndSet(value, value - 1)) return
|
||||
}
|
||||
}
|
||||
|
||||
public fun unlock() {
|
||||
status.compareAndSet(LOCKED, INITIALIZED)
|
||||
}
|
||||
|
||||
public fun setInitialized() {
|
||||
status.set(INITIALIZED)
|
||||
}
|
||||
|
||||
public fun setLocked() {
|
||||
status.set(LOCKED)
|
||||
}
|
||||
|
||||
public fun setDisposed() {
|
||||
setUninitialized()
|
||||
}
|
||||
|
||||
public fun setUninitialized() {
|
||||
status.set(UNINITIALIZED)
|
||||
}
|
||||
|
||||
public fun currentStatus(): Int = status.get()
|
||||
|
||||
override fun toString(): String {
|
||||
return when (val status = status.get()) {
|
||||
0 -> "ResourceAccessLock(INITIALIZED)"
|
||||
-1 -> "ResourceAccessLock(UNINITIALIZED)"
|
||||
-2 -> "ResourceAccessLock(LOCKED)"
|
||||
else -> "ResourceAccessLock($status)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2019-2021 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/dev/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.utils
|
||||
|
||||
public fun <T : Any> unsafeMutableNonNullPropertyOf(
|
||||
name: String = "<unknown>"
|
||||
): UnsafeMutableNonNullProperty<T> {
|
||||
return UnsafeMutableNonNullProperty(name)
|
||||
}
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public class UnsafeMutableNonNullProperty<T : Any>(
|
||||
private val propertyName: String = "<unknown>"
|
||||
) {
|
||||
@JvmField
|
||||
public var value0: T? = null
|
||||
|
||||
public val isInitialized: Boolean get() = value0 !== null
|
||||
public var value: T
|
||||
get() = value0 ?: throw UninitializedPropertyAccessException("Property `$propertyName` not initialized")
|
||||
set(value) {
|
||||
value0 = value
|
||||
}
|
||||
|
||||
public fun clear() {
|
||||
value0 = null
|
||||
}
|
||||
|
||||
public inline operator fun getValue(thiz: Any?, property: Any?): T = value
|
||||
public inline operator fun setValue(thiz: Any?, property: Any?, value: T) {
|
||||
value0 = value
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return value0?.toString() ?: "<uninitialized>"
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2019-2021 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/dev/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.utils
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFails
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
internal class ResourceAccessLockTest {
|
||||
@Test
|
||||
fun testInitializedLockCannotReInit() {
|
||||
val lock = ResourceAccessLock()
|
||||
lock.setInitialized()
|
||||
assertFalse { lock.tryInitialize() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUseFailedIfLockUninitializedOrLocked() {
|
||||
val lock = ResourceAccessLock()
|
||||
lock.setUninitialized()
|
||||
assertFalse { lock.tryUse() }
|
||||
lock.setLocked()
|
||||
assertFalse { lock.tryUse() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLockFailedIfUninitialized() {
|
||||
val lock = ResourceAccessLock()
|
||||
lock.setUninitialized()
|
||||
assertFalse { lock.lockIfNotUsing() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLockFailedIfUsing() {
|
||||
val lock = ResourceAccessLock()
|
||||
lock.setInitialized()
|
||||
assertTrue { lock.tryUse() }
|
||||
assertFalse { lock.lockIfNotUsing() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLockUsedIfInitialized() {
|
||||
val lock = ResourceAccessLock()
|
||||
lock.setInitialized()
|
||||
assertTrue { lock.tryUse() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRelease() {
|
||||
val lock = ResourceAccessLock()
|
||||
lock.setInitialized()
|
||||
assertFails { lock.release() }
|
||||
assertEquals(ResourceAccessLock.INITIALIZED, lock.currentStatus())
|
||||
assertTrue { lock.tryUse() }
|
||||
lock.release()
|
||||
}
|
||||
}
|
@ -57,6 +57,7 @@ import net.mamoe.mirai.internal.network.protocol.packet.sendAndExpect
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.summarycard.SummaryCard
|
||||
import net.mamoe.mirai.internal.network.psKey
|
||||
import net.mamoe.mirai.internal.network.sKey
|
||||
import net.mamoe.mirai.internal.utils.ImagePatcher
|
||||
import net.mamoe.mirai.internal.utils.MiraiProtocolInternal
|
||||
import net.mamoe.mirai.internal.utils.crypto.TEA
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.loadAs
|
||||
@ -762,7 +763,20 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
|
||||
|
||||
override fun createImage(imageId: String): Image {
|
||||
return when {
|
||||
imageId matches IMAGE_ID_REGEX -> OfflineGroupImage(imageId)
|
||||
imageId matches IMAGE_ID_REGEX -> {
|
||||
Bot.instancesSequence.forEach { existsBot ->
|
||||
runCatching {
|
||||
val patcher = existsBot.asQQAndroidBot().components[ImagePatcher]
|
||||
|
||||
patcher.findCacheByImageId(imageId)?.let { cache ->
|
||||
val rsp = cache.cacheOGI.value0
|
||||
cache.accessLock.release()
|
||||
if (rsp != null) return rsp
|
||||
}
|
||||
}
|
||||
}
|
||||
OfflineGroupImage(imageId)
|
||||
}
|
||||
imageId matches IMAGE_RESOURCE_ID_REGEX_1 -> OfflineFriendImage(imageId)
|
||||
imageId matches IMAGE_RESOURCE_ID_REGEX_2 -> OfflineFriendImage(imageId)
|
||||
else ->
|
||||
|
@ -49,6 +49,7 @@ import net.mamoe.mirai.internal.network.notice.priv.FriendNoticeProcessor
|
||||
import net.mamoe.mirai.internal.network.notice.priv.OtherClientNoticeProcessor
|
||||
import net.mamoe.mirai.internal.network.notice.priv.PrivateMessageProcessor
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.login.StatSvc
|
||||
import net.mamoe.mirai.internal.utils.ImagePatcher
|
||||
import net.mamoe.mirai.internal.utils.subLogger
|
||||
import net.mamoe.mirai.utils.BotConfiguration
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
@ -223,6 +224,7 @@ internal open class QQAndroidBot constructor(
|
||||
AccountSecretsManager,
|
||||
configuration.createAccountsSecretsManager(bot.logger.subLogger("AccountSecretsManager")),
|
||||
)
|
||||
set(ImagePatcher, ImagePatcher())
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -44,6 +44,7 @@ import net.mamoe.mirai.internal.network.protocol.packet.chat.voice.voiceCodec
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.list.ProfileService
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.sendAndExpect
|
||||
import net.mamoe.mirai.internal.utils.GroupPkgMsgParsingCache
|
||||
import net.mamoe.mirai.internal.utils.ImagePatcher
|
||||
import net.mamoe.mirai.internal.utils.RemoteFileImpl
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.toByteArray
|
||||
import net.mamoe.mirai.internal.utils.subLogger
|
||||
@ -181,6 +182,12 @@ internal class GroupImpl constructor(
|
||||
if (BeforeImageUploadEvent(this, resource).broadcast().isCancelled) {
|
||||
throw EventCancelledException("cancelled by BeforeImageUploadEvent.ToGroup")
|
||||
}
|
||||
|
||||
fun OfflineGroupImage.putIntoCache() {
|
||||
// We can't understand wny Image(group.uploadImage().imageId)
|
||||
bot.components[ImagePatcher].putCache(this)
|
||||
}
|
||||
|
||||
val imageInfo = runBIO { resource.calculateImageInfo() }
|
||||
bot.network.run<NetworkHandler, Image> {
|
||||
val response: ImgStore.GroupPicUp.Response = ImgStore.GroupPicUp(
|
||||
@ -216,6 +223,7 @@ internal class GroupImpl constructor(
|
||||
.also {
|
||||
it.fileId = response.fileId.toInt()
|
||||
}
|
||||
.also { it.putIntoCache() }
|
||||
.also { ImageUploadEvent.Succeed(this@GroupImpl, resource, it).broadcast() }
|
||||
}
|
||||
is ImgStore.GroupPicUp.Response.RequireUpload -> {
|
||||
@ -244,6 +252,7 @@ internal class GroupImpl constructor(
|
||||
size = resource.size
|
||||
)
|
||||
}.also { it.fileId = response.fileId.toInt() }
|
||||
.also { it.putIntoCache() }
|
||||
.also { ImageUploadEvent.Succeed(this@GroupImpl, resource, it).broadcast() }
|
||||
}
|
||||
}
|
||||
|
@ -28,9 +28,8 @@ import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.FileManagement
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.MusicSharePacket
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.image.ImgStore
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.*
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.sendAndExpect
|
||||
import net.mamoe.mirai.internal.utils.ImagePatcher
|
||||
import net.mamoe.mirai.message.MessageReceipt
|
||||
import net.mamoe.mirai.message.data.*
|
||||
import net.mamoe.mirai.utils.castOrNull
|
||||
@ -141,10 +140,20 @@ internal abstract class SendMessageHandler<C : Contact> {
|
||||
if (resp is MessageSvcPbSendMsg.Response.MessageTooLarge) {
|
||||
return when (step) {
|
||||
SendMessageStep.FIRST -> {
|
||||
sendMessageImpl(originalMessage, transformedMessage, isMiraiInternal, SendMessageStep.LONG_MESSAGE)
|
||||
sendMessageImpl(
|
||||
originalMessage,
|
||||
transformedMessage,
|
||||
isMiraiInternal,
|
||||
SendMessageStep.LONG_MESSAGE,
|
||||
)
|
||||
}
|
||||
SendMessageStep.LONG_MESSAGE -> {
|
||||
sendMessageImpl(originalMessage, transformedMessage, isMiraiInternal, SendMessageStep.FRAGMENTED)
|
||||
sendMessageImpl(
|
||||
originalMessage,
|
||||
transformedMessage,
|
||||
isMiraiInternal,
|
||||
SendMessageStep.FRAGMENTED,
|
||||
)
|
||||
|
||||
}
|
||||
else -> {
|
||||
@ -157,7 +166,7 @@ internal abstract class SendMessageHandler<C : Contact> {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (resp is MessageSvcPbSendMsg.Response.ServiceUnavailable){
|
||||
if (resp is MessageSvcPbSendMsg.Response.ServiceUnavailable) {
|
||||
throw IllegalStateException("Send message to $contact failed, server service is unavailable.")
|
||||
}
|
||||
if (resp is MessageSvcPbSendMsg.Response.Failed) {
|
||||
@ -446,65 +455,11 @@ internal open class GroupSendMessageHandler(
|
||||
|
||||
companion object {
|
||||
private suspend fun GroupImpl.fixImageFileId(image: OfflineGroupImage) {
|
||||
if (image.fileId == null) {
|
||||
val response: ImgStore.GroupPicUp.Response = ImgStore.GroupPicUp(
|
||||
bot.client,
|
||||
uin = bot.id,
|
||||
groupCode = this.id,
|
||||
md5 = image.md5,
|
||||
size = 1,
|
||||
).sendAndExpect(bot)
|
||||
|
||||
when (response) {
|
||||
is ImgStore.GroupPicUp.Response.Failed -> {
|
||||
image.fileId = 0 // Failed
|
||||
}
|
||||
is ImgStore.GroupPicUp.Response.FileExists -> {
|
||||
image.fileId = response.fileId.toInt()
|
||||
}
|
||||
is ImgStore.GroupPicUp.Response.RequireUpload -> {
|
||||
image.fileId = response.fileId.toInt()
|
||||
}
|
||||
}
|
||||
}
|
||||
bot.components[ImagePatcher].patchOfflineGroupImage(this, image)
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures server holds the cache
|
||||
*/
|
||||
private suspend fun GroupImpl.updateFriendImageForGroupMessage(image: FriendImage): OfflineGroupImage {
|
||||
bot.network.run {
|
||||
val response = ImgStore.GroupPicUp(
|
||||
bot.client,
|
||||
uin = bot.id,
|
||||
groupCode = id,
|
||||
md5 = image.md5,
|
||||
size = image.size
|
||||
).sendAndExpect()
|
||||
return OfflineGroupImage(
|
||||
imageId = image.imageId,
|
||||
width = image.width,
|
||||
height = image.height,
|
||||
size = if (response is ImgStore.GroupPicUp.Response.FileExists) {
|
||||
response.fileInfo.fileSize
|
||||
} else {
|
||||
image.size
|
||||
},
|
||||
imageType = image.imageType
|
||||
).also { img ->
|
||||
when (response) {
|
||||
is ImgStore.GroupPicUp.Response.FileExists -> {
|
||||
img.fileId = response.fileId.toInt()
|
||||
}
|
||||
is ImgStore.GroupPicUp.Response.RequireUpload -> {
|
||||
img.fileId = response.fileId.toInt()
|
||||
}
|
||||
is ImgStore.GroupPicUp.Response.Failed -> {
|
||||
img.fileId = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return bot.components[ImagePatcher].patchFriendImageToGroupImage(this, image)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -125,6 +125,8 @@ internal open class MultiMsgUploader(
|
||||
msgChain = convertNestedForwardMessage(nestedForward, msgChain)
|
||||
}
|
||||
|
||||
msgChain = handler.conversionMessageChain(msgChain)
|
||||
|
||||
var seq: Int = -1
|
||||
var uid: Int = -1
|
||||
msg.messageChain.sourceOrNull?.let { source ->
|
||||
|
193
mirai-core/src/commonMain/kotlin/utils/ImagePatcher.kt
Normal file
193
mirai-core/src/commonMain/kotlin/utils/ImagePatcher.kt
Normal file
@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright 2019-2021 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/dev/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.internal.utils
|
||||
|
||||
import net.mamoe.mirai.internal.contact.GroupImpl
|
||||
import net.mamoe.mirai.internal.message.OfflineGroupImage
|
||||
import net.mamoe.mirai.internal.network.component.ComponentKey
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.image.ImgStore
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.sendAndExpect
|
||||
import net.mamoe.mirai.message.data.FriendImage
|
||||
import net.mamoe.mirai.message.data.md5
|
||||
import net.mamoe.mirai.utils.ResourceAccessLock
|
||||
import net.mamoe.mirai.utils.UnsafeMutableNonNullProperty
|
||||
import net.mamoe.mirai.utils.currentTimeMillis
|
||||
import net.mamoe.mirai.utils.unsafeMutableNonNullPropertyOf
|
||||
|
||||
internal open class ImagePatcher {
|
||||
companion object : ComponentKey<ImagePatcher> {
|
||||
inline fun <T> ImageCache.withCache(action: (ImageCache) -> T): T {
|
||||
return try {
|
||||
action(this)
|
||||
} finally {
|
||||
this.accessLock.release()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class ImageCache(
|
||||
var updateTime: Long = 0,
|
||||
val id: UnsafeMutableNonNullProperty<String> = unsafeMutableNonNullPropertyOf(),
|
||||
// OGI: OfflineGroupImage
|
||||
val cacheOGI: UnsafeMutableNonNullProperty<OfflineGroupImage> = unsafeMutableNonNullPropertyOf(),
|
||||
val accessLock: ResourceAccessLock = ResourceAccessLock(),
|
||||
)
|
||||
|
||||
val caches: Array<ImageCache> = Array(20) { ImageCache() }
|
||||
|
||||
fun findCache(id: String): ImageCache? {
|
||||
return caches.firstOrNull { it.id.value0 == id && it.accessLock.tryUse() }
|
||||
}
|
||||
|
||||
fun findCacheByImageId(id: String): ImageCache? = findCache(calcInternalIdByImageId(id))
|
||||
|
||||
fun putCache(image: OfflineGroupImage) {
|
||||
putCache(calcInternalIdByImageId(image.imageId)).cacheOGI.value0 = image
|
||||
}
|
||||
|
||||
fun putCache(id: String): ImageCache {
|
||||
fun ImageCache.postReturn(): ImageCache = also { cache ->
|
||||
cache.updateTime = currentTimeMillis()
|
||||
cache.id.value0 = id
|
||||
}
|
||||
|
||||
caches.forEach { exists ->
|
||||
if (exists.id.value0 == id && exists.accessLock.tryInitialize()) {
|
||||
return exists.postReturn()
|
||||
}
|
||||
}
|
||||
|
||||
// Try to use existing slot
|
||||
caches.forEach { exists ->
|
||||
if (exists.accessLock.tryInitialize()) {
|
||||
return exists.postReturn()
|
||||
}
|
||||
}
|
||||
|
||||
val availableCaches = caches.filter { it.accessLock.lockIfNotUsing() }
|
||||
if (availableCaches.isNotEmpty()) {
|
||||
val target = availableCaches.minByOrNull { it.updateTime }!!
|
||||
availableCaches.forEach { if (it !== target) it.accessLock.unlock() }
|
||||
|
||||
target.accessLock.setInitialized()
|
||||
return target.postReturn()
|
||||
}
|
||||
|
||||
// No available sort. Force to override the last one
|
||||
val newCache = ImageCache()
|
||||
newCache.accessLock.setInitialized()
|
||||
newCache.postReturn()
|
||||
|
||||
var idx = 0
|
||||
var lupd = Long.MAX_VALUE
|
||||
caches.forEachIndexed { index, imageCache ->
|
||||
val upd0 = imageCache.updateTime
|
||||
if (upd0 < lupd) {
|
||||
lupd = upd0
|
||||
idx = index
|
||||
}
|
||||
}
|
||||
caches[idx] = newCache
|
||||
|
||||
return newCache
|
||||
}
|
||||
|
||||
private fun calcInternalIdByImageId(imageId: String): String {
|
||||
return imageId.substring(1, imageId.indexOf('}'))
|
||||
}
|
||||
|
||||
suspend fun patchOfflineGroupImage(
|
||||
group: GroupImpl,
|
||||
image: OfflineGroupImage,
|
||||
) {
|
||||
if (image.fileId != null) return
|
||||
val iid = calcInternalIdByImageId(image.imageId)
|
||||
findCache(iid)?.withCache { cache ->
|
||||
cache.cacheOGI.value0?.let { cachedOGI ->
|
||||
image.fileId = cachedOGI.fileId
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
val bot = group.bot
|
||||
|
||||
val response: ImgStore.GroupPicUp.Response = ImgStore.GroupPicUp(
|
||||
bot.client,
|
||||
uin = bot.id,
|
||||
groupCode = group.id,
|
||||
md5 = image.md5,
|
||||
size = 1,
|
||||
).sendAndExpect(bot)
|
||||
|
||||
when (response) {
|
||||
is ImgStore.GroupPicUp.Response.Failed -> {
|
||||
image.fileId = 0 // Failed
|
||||
}
|
||||
is ImgStore.GroupPicUp.Response.FileExists -> {
|
||||
image.fileId = response.fileId.toInt()
|
||||
}
|
||||
is ImgStore.GroupPicUp.Response.RequireUpload -> {
|
||||
image.fileId = response.fileId.toInt()
|
||||
}
|
||||
}
|
||||
|
||||
putCache(iid).cacheOGI.value0 = image
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures server holds the cache
|
||||
*/
|
||||
suspend fun patchFriendImageToGroupImage(
|
||||
group: GroupImpl,
|
||||
image: FriendImage,
|
||||
): OfflineGroupImage {
|
||||
val iid = calcInternalIdByImageId(image.imageId)
|
||||
findCache(iid)?.withCache { cache ->
|
||||
cache.cacheOGI.value0?.let { return it }
|
||||
}
|
||||
|
||||
val bot = group.bot
|
||||
|
||||
val response = ImgStore.GroupPicUp(
|
||||
bot.client,
|
||||
uin = bot.id,
|
||||
groupCode = group.id,
|
||||
md5 = image.md5,
|
||||
size = image.size
|
||||
).sendAndExpect(bot.network)
|
||||
|
||||
return OfflineGroupImage(
|
||||
imageId = image.imageId,
|
||||
width = image.width,
|
||||
height = image.height,
|
||||
size = if (response is ImgStore.GroupPicUp.Response.FileExists) {
|
||||
response.fileInfo.fileSize
|
||||
} else {
|
||||
image.size
|
||||
},
|
||||
imageType = image.imageType
|
||||
).also { img ->
|
||||
when (response) {
|
||||
is ImgStore.GroupPicUp.Response.FileExists -> {
|
||||
img.fileId = response.fileId.toInt()
|
||||
}
|
||||
is ImgStore.GroupPicUp.Response.RequireUpload -> {
|
||||
img.fileId = response.fileId.toInt()
|
||||
}
|
||||
is ImgStore.GroupPicUp.Response.Failed -> {
|
||||
img.fileId = 0
|
||||
}
|
||||
}
|
||||
}.also { img ->
|
||||
putCache(iid).cacheOGI.value0 = img
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user