Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Image.isUploaded, #1671

Merged
merged 2 commits into from
Nov 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
121 changes: 105 additions & 16 deletions mirai-core-api/src/commonMain/kotlin/message/data/Image.kt
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public interface Image : Message, MessageContent, CodableMessage {
public val height: Int

/**
* 图片的大小(字节), 当无法获取时为 0
* 图片的大小(字节), 当无法获取时为 0. 可用于 [isUploaded].
*
* @since 2.8.0
*/
Expand All @@ -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 },
Expand All @@ -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"

Expand All @@ -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 正则表达式
Expand Down Expand Up @@ -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
Expand All @@ -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)


/**
Expand Down Expand Up @@ -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"
)
}
}
}
16 changes: 0 additions & 16 deletions mirai-core-api/src/commonMain/kotlin/message/data/impl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import net.mamoe.mirai.message.data.Image.Key.IMAGE_RESOURCE_ID_REGEX_1
import net.mamoe.mirai.message.data.Image.Key.IMAGE_RESOURCE_ID_REGEX_2
import net.mamoe.mirai.utils.MiraiExperimentalApi
import net.mamoe.mirai.utils.replaceAllKotlin
import kotlin.native.concurrent.SharedImmutable

// region image

Expand Down Expand Up @@ -200,7 +199,6 @@ internal fun MessageChainImplBySequence(
//////////////////////


@SharedImmutable
@get:JvmSynthetic
internal val EMPTY_BYTE_ARRAY = ByteArray(0)

Expand Down Expand Up @@ -246,20 +244,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 " +
Expand Down
14 changes: 7 additions & 7 deletions mirai-core-api/src/commonTest/kotlin/message.data/ImageTest.kt
Original file line number Diff line number Diff line change
@@ -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")

Expand Down Expand Up @@ -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()
)

}
Expand Down