Support Image.isUploaded, (#1671)

* Support `Image.isUploaded`,
add member `Image.md5`,
add `Image.calculateImageMd5ByImageId`,
close #1401

* Update docs
This commit is contained in:
Him188 2021-11-16 10:50:17 +00:00 committed by GitHub
parent 79d92a0114
commit bd041e43d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 332 additions and 41 deletions

View File

@ -4445,9 +4445,14 @@ public abstract interface class net/mamoe/mirai/message/data/Image : net/mamoe/m
public static fun getImageResourceIdRegex1 ()Lkotlin/text/Regex;
public static fun getImageResourceIdRegex2 ()Lkotlin/text/Regex;
public abstract fun getImageType ()Lnet/mamoe/mirai/message/data/ImageType;
public fun getMd5 ()[B
public abstract fun getSize ()J
public abstract fun getWidth ()I
public fun isEmoji ()Z
public static fun isUploaded (Lnet/mamoe/mirai/Bot;[BJ)Z
public static fun isUploaded (Lnet/mamoe/mirai/Bot;[BJLkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static fun isUploaded (Lnet/mamoe/mirai/message/data/Image;Lnet/mamoe/mirai/Bot;)Z
public static fun isUploaded (Lnet/mamoe/mirai/message/data/Image;Lnet/mamoe/mirai/Bot;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static fun queryUrl (Lnet/mamoe/mirai/message/data/Image;)Ljava/lang/String;
public static fun queryUrl (Lnet/mamoe/mirai/message/data/Image;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}
@ -4463,10 +4468,15 @@ public final class net/mamoe/mirai/message/data/Image$AsStringSerializer : kotli
public final class net/mamoe/mirai/message/data/Image$Key : net/mamoe/mirai/message/data/AbstractMessageKey {
public static final field SERIAL_NAME Ljava/lang/String;
public final fun calculateImageMd5ByImageId (Ljava/lang/String;)[B
public final fun fromId (Ljava/lang/String;)Lnet/mamoe/mirai/message/data/Image;
public final fun getImageIdRegex ()Lkotlin/text/Regex;
public final fun getImageResourceIdRegex1 ()Lkotlin/text/Regex;
public final fun getImageResourceIdRegex2 ()Lkotlin/text/Regex;
public final fun isUploaded (Lnet/mamoe/mirai/Bot;[BJ)Z
public final fun isUploaded (Lnet/mamoe/mirai/Bot;[BJLkotlin/coroutines/Continuation;)Ljava/lang/Object;
public final fun isUploaded (Lnet/mamoe/mirai/message/data/Image;Lnet/mamoe/mirai/Bot;)Z
public final fun isUploaded (Lnet/mamoe/mirai/message/data/Image;Lnet/mamoe/mirai/Bot;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public final fun queryUrl (Lnet/mamoe/mirai/message/data/Image;)Ljava/lang/String;
public final fun queryUrl (Lnet/mamoe/mirai/message/data/Image;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}
@ -4488,6 +4498,7 @@ public final class net/mamoe/mirai/message/data/ImageType : java/lang/Enum {
public static final field JPG Lnet/mamoe/mirai/message/data/ImageType;
public static final field PNG Lnet/mamoe/mirai/message/data/ImageType;
public static final field UNKNOWN Lnet/mamoe/mirai/message/data/ImageType;
public final fun getFormatName ()Ljava/lang/String;
public static final fun match (Ljava/lang/String;)Lnet/mamoe/mirai/message/data/ImageType;
public static final fun matchOrNull (Ljava/lang/String;)Lnet/mamoe/mirai/message/data/ImageType;
public static fun valueOf (Ljava/lang/String;)Lnet/mamoe/mirai/message/data/ImageType;
@ -4853,7 +4864,7 @@ public final class net/mamoe/mirai/message/data/MessageUtils {
public static final fun buildMessageChain (Lkotlin/jvm/functions/Function1;)Lnet/mamoe/mirai/message/data/MessageChain;
public static final synthetic fun buildMessageSource (Lnet/mamoe/mirai/Bot;Lnet/mamoe/mirai/message/data/MessageSourceKind;Lkotlin/jvm/functions/Function1;)Lnet/mamoe/mirai/message/data/OfflineMessageSource;
public static final synthetic fun buildMessageSource (Lnet/mamoe/mirai/IMirai;JLnet/mamoe/mirai/message/data/MessageSourceKind;Lkotlin/jvm/functions/Function1;)Lnet/mamoe/mirai/message/data/OfflineMessageSource;
public static final fun calculateImageMd5 (Lnet/mamoe/mirai/message/data/Image;)[B
public static final synthetic fun calculateImageMd5 (Lnet/mamoe/mirai/message/data/Image;)[B
public static final fun contentsList (Lnet/mamoe/mirai/message/data/MessageChain;)Ljava/util/List;
public static final synthetic fun contentsSequence (Lnet/mamoe/mirai/message/data/MessageChain;)Lkotlin/sequences/Sequence;
public static final fun copySource (Lnet/mamoe/mirai/message/data/MessageSource;Lkotlin/jvm/functions/Function1;)Lnet/mamoe/mirai/message/data/OfflineMessageSource;

View File

@ -4445,9 +4445,14 @@ public abstract interface class net/mamoe/mirai/message/data/Image : net/mamoe/m
public static fun getImageResourceIdRegex1 ()Lkotlin/text/Regex;
public static fun getImageResourceIdRegex2 ()Lkotlin/text/Regex;
public abstract fun getImageType ()Lnet/mamoe/mirai/message/data/ImageType;
public fun getMd5 ()[B
public abstract fun getSize ()J
public abstract fun getWidth ()I
public fun isEmoji ()Z
public static fun isUploaded (Lnet/mamoe/mirai/Bot;[BJ)Z
public static fun isUploaded (Lnet/mamoe/mirai/Bot;[BJLkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static fun isUploaded (Lnet/mamoe/mirai/message/data/Image;Lnet/mamoe/mirai/Bot;)Z
public static fun isUploaded (Lnet/mamoe/mirai/message/data/Image;Lnet/mamoe/mirai/Bot;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static fun queryUrl (Lnet/mamoe/mirai/message/data/Image;)Ljava/lang/String;
public static fun queryUrl (Lnet/mamoe/mirai/message/data/Image;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}
@ -4463,10 +4468,15 @@ public final class net/mamoe/mirai/message/data/Image$AsStringSerializer : kotli
public final class net/mamoe/mirai/message/data/Image$Key : net/mamoe/mirai/message/data/AbstractMessageKey {
public static final field SERIAL_NAME Ljava/lang/String;
public final fun calculateImageMd5ByImageId (Ljava/lang/String;)[B
public final fun fromId (Ljava/lang/String;)Lnet/mamoe/mirai/message/data/Image;
public final fun getImageIdRegex ()Lkotlin/text/Regex;
public final fun getImageResourceIdRegex1 ()Lkotlin/text/Regex;
public final fun getImageResourceIdRegex2 ()Lkotlin/text/Regex;
public final fun isUploaded (Lnet/mamoe/mirai/Bot;[BJ)Z
public final fun isUploaded (Lnet/mamoe/mirai/Bot;[BJLkotlin/coroutines/Continuation;)Ljava/lang/Object;
public final fun isUploaded (Lnet/mamoe/mirai/message/data/Image;Lnet/mamoe/mirai/Bot;)Z
public final fun isUploaded (Lnet/mamoe/mirai/message/data/Image;Lnet/mamoe/mirai/Bot;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public final fun queryUrl (Lnet/mamoe/mirai/message/data/Image;)Ljava/lang/String;
public final fun queryUrl (Lnet/mamoe/mirai/message/data/Image;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}
@ -4488,6 +4498,7 @@ public final class net/mamoe/mirai/message/data/ImageType : java/lang/Enum {
public static final field JPG Lnet/mamoe/mirai/message/data/ImageType;
public static final field PNG Lnet/mamoe/mirai/message/data/ImageType;
public static final field UNKNOWN Lnet/mamoe/mirai/message/data/ImageType;
public final fun getFormatName ()Ljava/lang/String;
public static final fun match (Ljava/lang/String;)Lnet/mamoe/mirai/message/data/ImageType;
public static final fun matchOrNull (Ljava/lang/String;)Lnet/mamoe/mirai/message/data/ImageType;
public static fun valueOf (Ljava/lang/String;)Lnet/mamoe/mirai/message/data/ImageType;
@ -4853,7 +4864,7 @@ public final class net/mamoe/mirai/message/data/MessageUtils {
public static final fun buildMessageChain (Lkotlin/jvm/functions/Function1;)Lnet/mamoe/mirai/message/data/MessageChain;
public static final synthetic fun buildMessageSource (Lnet/mamoe/mirai/Bot;Lnet/mamoe/mirai/message/data/MessageSourceKind;Lkotlin/jvm/functions/Function1;)Lnet/mamoe/mirai/message/data/OfflineMessageSource;
public static final synthetic fun buildMessageSource (Lnet/mamoe/mirai/IMirai;JLnet/mamoe/mirai/message/data/MessageSourceKind;Lkotlin/jvm/functions/Function1;)Lnet/mamoe/mirai/message/data/OfflineMessageSource;
public static final fun calculateImageMd5 (Lnet/mamoe/mirai/message/data/Image;)[B
public static final synthetic fun calculateImageMd5 (Lnet/mamoe/mirai/message/data/Image;)[B
public static final fun contentsList (Lnet/mamoe/mirai/message/data/MessageChain;)Ljava/util/List;
public static final synthetic fun contentsSequence (Lnet/mamoe/mirai/message/data/MessageChain;)Lkotlin/sequences/Sequence;
public static final fun copySource (Lnet/mamoe/mirai/message/data/MessageSource;Lkotlin/jvm/functions/Function1;)Lnet/mamoe/mirai/message/data/OfflineMessageSource;

View File

@ -100,7 +100,7 @@ public interface Image : Message, MessageContent, CodableMessage {
public val height: Int
/**
* 图片的大小字节, 当无法获取时为 0
* 图片的大小字节, 当无法获取时为 0. 可用于 [isUploaded].
*
* @since 2.8.0
*/
@ -122,6 +122,15 @@ public interface Image : Message, MessageContent, CodableMessage {
*/
public val isEmoji: Boolean get() = false
/**
* 图片文件 MD5. 可用于 [isUploaded].
*
* @return 16 bytes
* @see isUploaded
* @since 2.9.0
*/ // was an extension on Image before 2.9.0-M1.
public val md5: ByteArray get() = calculateImageMd5ByImageId(imageId)
public object AsStringSerializer : KSerializer<Image> by String.serializer().mapPrimitive(
SERIAL_NAME,
serialize = { imageId },
@ -143,6 +152,7 @@ public interface Image : Message, MessageContent, CodableMessage {
)
}
@JvmBlockingBridge
public companion object Key : AbstractMessageKey<Image>({ it.safeCast() }) {
public const val SERIAL_NAME: String = "Image"
@ -166,12 +176,56 @@ public interface Image : Message, MessageContent, CodableMessage {
* @throws IllegalStateException 当无任何 [Bot] 在线时抛出 (因为无法获取相关协议)
*/
@JvmStatic
@JvmBlockingBridge
public suspend fun Image.queryUrl(): String {
val bot = Bot.instancesSequence.firstOrNull() ?: error("No Bot available to query image url")
return Mirai.queryImageUrl(bot, this)
}
/**
* 当图片在服务器上存在时返回 `true`, 这意味着图片可以直接发送给 [contact].
*
* 若返回 `false`, 则图片需要用 [ExternalResource] 重新上传 ([Contact.uploadImage]).
*
* @since 2.9.0
*/
@JvmStatic
public suspend fun Image.isUploaded(bot: Bot): Boolean =
InternalImageProtocol.instance.isUploaded(bot, md5, size, null, imageType, width, height)
/**
* 当图片在服务器上存在时返回 `true`, 这意味着图片可以直接发送给 [contact].
*
* 若返回 `false`, 则图片需要用 [ExternalResource] 重新上传 ([Contact.uploadImage]).
*
* @param md5 图片文件 MD5. 可通过 [Image.md5] 获得.
* @param size 图片文件大小.
*
* @since 2.9.0
*/
@JvmStatic
public suspend fun isUploaded(
bot: Bot,
md5: ByteArray,
size: Long,
): Boolean = InternalImageProtocol.instance.isUploaded(bot, md5, size, null)
/**
* [Image.imageId] 计算 [Image.md5].
*
* @since 2.9.0
*/
public fun calculateImageMd5ByImageId(imageId: String): ByteArray {
@Suppress("DEPRECATION")
return when {
imageId matches IMAGE_ID_REGEX -> imageId.imageIdToMd5(1)
imageId matches IMAGE_RESOURCE_ID_REGEX_2 -> imageId.imageIdToMd5(imageId.skipToSecondHyphen() + 1)
imageId matches IMAGE_RESOURCE_ID_REGEX_1 -> imageId.imageIdToMd5(1)
else -> throw IllegalArgumentException(
"Illegal imageId: '$imageId'. $ILLEGAL_IMAGE_ID_EXCEPTION_MESSAGE"
)
}
}
/**
* 统一 ID 正则表达式
@ -222,17 +276,24 @@ public interface Image : Message, MessageContent, CodableMessage {
@JvmSynthetic
public inline fun Image(imageId: String): Image = Image.fromId(imageId)
public enum class ImageType {
PNG,
BMP,
JPG,
GIF,
public enum class ImageType(
/**
* @since 2.9.0
*/
@MiraiInternalApi public val formatName: String,
) {
PNG("png"),
BMP("bmp"),
JPG("jpg"),
GIF("gif"),
//WEBP, //Unsupported by pc client
APNG,
UNKNOWN;
APNG("png"),
UNKNOWN("gif"); // bad design, should use `null` to represent unknown, but we cannot change it anymore.
public companion object {
private val IMAGE_TYPE_ENUM_LIST = values()
@JvmStatic
public fun match(str: String): ImageType {
return matchOrNull(str) ?: UNKNOWN
@ -250,15 +311,12 @@ public enum class ImageType {
// Internals
///////////////////////////////////////////////////////////////////////////
/**
* 计算图片的 md5 校验值.
*
* Java 使用: `MessageUtils.calculateImageMd5(image)`
*/
@Deprecated("Use member function", level = DeprecationLevel.HIDDEN) // safe since it was internal
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
@MiraiInternalApi
@get:JvmName("calculateImageMd5")
public val Image.md5: ByteArray
get() = calculateImageMd5ByImageId(imageId)
get() = Image.calculateImageMd5ByImageId(imageId)
/**
@ -320,4 +378,35 @@ public abstract class FriendImage @MiraiInternalApi public constructor() :
public abstract class GroupImage @MiraiInternalApi public constructor() :
AbstractImage() { // change to sealed in the future.
public companion object
}
}
/**
* 内部图片协议实现
* @since 2.9.0-M1
*/
@MiraiInternalApi
public interface InternalImageProtocol { // naming it Internal* to assign it a lower priority when resolving Image*
/**
* @param context 用于检查的 [Contact]. 群图片与好友图片是两个通道, 建议使用欲发送到的 [Contact] 对象作为 [contact] 参数, 但目前不提供此参数时也可以检查.
*/
public suspend fun isUploaded(
bot: Bot,
md5: ByteArray,
size: Long,
context: Contact? = null,
type: ImageType = ImageType.UNKNOWN,
width: Int = 0,
height: Int = 0
): Boolean
@MiraiInternalApi
public companion object {
public val instance: InternalImageProtocol by lazy {
loadService(
InternalImageProtocol::class,
"net.mamoe.mirai.internal.message.InternalImageProtocolImpl"
)
}
}
}

View File

@ -20,7 +20,6 @@ import net.mamoe.mirai.message.data.Image.Key.IMAGE_RESOURCE_ID_REGEX_2
import net.mamoe.mirai.utils.MiraiExperimentalApi
import net.mamoe.mirai.utils.asImmutable
import net.mamoe.mirai.utils.replaceAllKotlin
import kotlin.native.concurrent.SharedImmutable
// region image
@ -201,7 +200,6 @@ internal fun MessageChainImplBySequence(
//////////////////////
@SharedImmutable
@get:JvmSynthetic
internal val EMPTY_BYTE_ARRAY = ByteArray(0)
@ -247,20 +245,6 @@ internal fun String.imageIdToMd5(offset: Int): ByteArray {
error("Internal error: failed imageIdToMd5, no enough chars. Input=$this, offset=$offset")
}
@OptIn(ExperimentalStdlibApi::class)
internal fun calculateImageMd5ByImageId(imageId: String): ByteArray {
@Suppress("DEPRECATION")
return when {
imageId matches IMAGE_ID_REGEX -> imageId.imageIdToMd5(1)
imageId matches IMAGE_RESOURCE_ID_REGEX_2 -> imageId.imageIdToMd5(imageId.skipToSecondHyphen() + 1)
imageId matches IMAGE_RESOURCE_ID_REGEX_1 -> imageId.imageIdToMd5(1)
else -> error(
"illegal imageId: $imageId. $ILLEGAL_IMAGE_ID_EXCEPTION_MESSAGE"
)
}
}
internal val ILLEGAL_IMAGE_ID_EXCEPTION_MESSAGE: String =
"ImageId must match Regex `${IMAGE_RESOURCE_ID_REGEX_1.pattern}`, " +
"`${IMAGE_RESOURCE_ID_REGEX_2.pattern}` or " +

View File

@ -1,10 +1,10 @@
/*
* Copyright 2019-2020 Mamoe Technologies and contributors.
* 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.
* 此源代码的使用受 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/master/LICENSE
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
@file:Suppress("EXPERIMENTAL_API_USAGE")
@ -35,17 +35,17 @@ internal class ImageTest {
fun testCalculateImageMd5ByImageId() {
assertEquals(
"01E9451B-70ED-EAE3-B37C-101F1EEBF5B5".filterNot { it == '-' }.autoHexToBytes().contentToString(),
calculateImageMd5ByImageId("{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.mirai").contentToString()
Image.calculateImageMd5ByImageId("{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.mirai").contentToString()
)
assertEquals(
"f8f1ab55-bf8e-4236-b55e-955848d7069f".filterNot { it == '-' }.autoHexToBytes().contentToString(),
calculateImageMd5ByImageId("/f8f1ab55-bf8e-4236-b55e-955848d7069f").contentToString()
Image.calculateImageMd5ByImageId("/f8f1ab55-bf8e-4236-b55e-955848d7069f").contentToString()
)
assertEquals(
"BFB7027B9354B8F899A062061D74E206".filterNot { it == '-' }.autoHexToBytes().contentToString(),
calculateImageMd5ByImageId("/000000000-3814297509-BFB7027B9354B8F899A062061D74E206").contentToString()
Image.calculateImageMd5ByImageId("/000000000-3814297509-BFB7027B9354B8F899A062061D74E206").contentToString()
)
}

View File

@ -0,0 +1,159 @@
/*
* 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.message
import net.mamoe.mirai.Bot
import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.User
import net.mamoe.mirai.internal.QQAndroidBot
import net.mamoe.mirai.internal.asQQAndroidBot
import net.mamoe.mirai.internal.network.protocol.data.proto.Cmd0x352
import net.mamoe.mirai.internal.network.protocol.packet.chat.image.ImgStore
import net.mamoe.mirai.internal.network.protocol.packet.chat.image.LongConn
import net.mamoe.mirai.internal.network.protocol.packet.sendAndExpect
import net.mamoe.mirai.message.data.ImageType
import net.mamoe.mirai.message.data.InternalImageProtocol
import net.mamoe.mirai.utils.cast
import net.mamoe.mirai.utils.toUHexString
internal class InternalImageProtocolImpl : InternalImageProtocol {
/**
* Test Notes:
*
* - 查图片只需要 md5 size
* - 上传给群的图片可以通过 GroupPicUp(groupCode=user.id) OffPicUp(dstUin=user.id) 查询
* - 上传给好友的图片可以通过 GroupPicUp(groupCode=group.id) OffPicUp(dstUin=group.id) 查询
*/
fun interface ImageUploadedChecker<C : Contact?> {
suspend fun isUploaded(
bot: QQAndroidBot,
context: C,
md5: ByteArray,
type: ImageType,
size: Long,
width: Int,
height: Int
): Boolean
companion object {
val checkers = mapOf(
Group::class to ImageUploadedCheckerGroup(),
User::class to ImageUploadedCheckerUser(),
null to ImageUploadedCheckerFallback()
)
}
}
class ImageUploadedCheckerGroup : ImageUploadedChecker<Group> {
override suspend fun isUploaded(
bot: QQAndroidBot,
context: Group,
md5: ByteArray,
type: ImageType,
size: Long,
width: Int,
height: Int
): Boolean {
val response: ImgStore.GroupPicUp.Response = ImgStore.GroupPicUp(
bot.client,
uin = bot.id,
groupCode = context.id,
md5 = md5,
size = size,
filename = "${md5.toUHexString("")}.${type.formatName}",
picWidth = width,
picHeight = height,
picType = getIdByImageType(type),
originalPic = 1
).sendAndExpect(bot)
return response is ImgStore.GroupPicUp.Response.FileExists
}
}
class ImageUploadedCheckerUser : ImageUploadedChecker<User> {
override suspend fun isUploaded(
bot: QQAndroidBot,
context: User,
md5: ByteArray,
type: ImageType,
size: Long,
width: Int,
height: Int
): Boolean {
val resp = LongConn.OffPicUp(
bot.client,
Cmd0x352.TryUpImgReq(
buType = 1,
srcUin = bot.id,
dstUin = context.id,
fileMd5 = md5,
fileSize = size,
imgWidth = width,
imgHeight = height,
imgType = getIdByImageType(type),
fileName = "${md5.toUHexString("")}.${type.formatName}",
imgOriginal = true,
buildVer = bot.client.buildVer,
),
).sendAndExpect<LongConn.OffPicUp.Response>(bot)
return resp is LongConn.OffPicUp.Response.FileExists
}
}
class ImageUploadedCheckerFallback : ImageUploadedChecker<Nothing?> {
override suspend fun isUploaded(
bot: QQAndroidBot,
context: Nothing?,
md5: ByteArray,
type: ImageType,
size: Long,
width: Int,
height: Int
): Boolean {
val response: ImgStore.GroupPicUp.Response = ImgStore.GroupPicUp(
bot.client,
uin = bot.id,
groupCode = 1,
md5 = md5,
size = size,
filename = "${md5.toUHexString("")}.${type.formatName}",
picWidth = width,
picHeight = height,
picType = getIdByImageType(type),
originalPic = 1
).sendAndExpect(bot)
return response is ImgStore.GroupPicUp.Response.FileExists
}
}
override suspend fun isUploaded(
bot: Bot,
md5: ByteArray,
size: Long,
context: Contact?,
type: ImageType,
width: Int,
height: Int
): Boolean {
val checker = findChecker(context) ?: return false
checker.cast<ImageUploadedChecker<Contact?>>()
return checker.isUploaded(bot.asQQAndroidBot(), context.cast<Contact?>(), md5, type, size, width, height)
}
fun findChecker(context: Contact?) = ImageUploadedChecker.checkers.asSequence()
.find { bothNull(it.key, context) || it.key?.isInstance(context) == true }?.value
private fun bothNull(a: Any?, b: Any?) = a == null && b == null
}

View File

@ -0,0 +1,10 @@
#
# 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
#
net.mamoe.mirai.internal.message.InternalImageProtocolImpl

View File

@ -0,0 +1,27 @@
/*
* 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.message
import net.mamoe.mirai.internal.notice.processors.AbstractNoticeProcessorTest
import kotlin.test.Test
import kotlin.test.assertIs
internal class InternalImageProtocolImplTest : AbstractNoticeProcessorTest() { // borrow Bot testkit
val instance = InternalImageProtocolImpl()
@Test
fun testFindChecker() {
assertIs<InternalImageProtocolImpl.ImageUploadedCheckerGroup>(instance.findChecker(setBot(1).addGroup(2, 3)))
assertIs<InternalImageProtocolImpl.ImageUploadedCheckerUser>(instance.findChecker(setBot(1).addFriend(2)))
assertIs<InternalImageProtocolImpl.ImageUploadedCheckerFallback>(instance.findChecker(null))
// these 3 tests are complete -- no need to add more when adding more checkers.
}
}