Jelajahi Sumber

Improve KDoc

Him188 5 tahun lalu
induk
melakukan
1542b73fa9

+ 2 - 0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt

@@ -74,6 +74,8 @@ abstract class Contact : CoroutineScope, ContactJavaFriendlyAPI(), Identified {
     /**
      * 上传一个图片以备发送.
      *
+     * @see Image 查看更多信息
+     *
      * @see BeforeImageUploadEvent 图片发送前事件, cancellable
      * @see ImageUploadEvent 图片发送完成事件
      *

+ 9 - 3
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/HummerMessage.kt

@@ -11,6 +11,7 @@
 
 package net.mamoe.mirai.message.data
 
+import net.mamoe.mirai.message.data.PokeMessage.Types
 import net.mamoe.mirai.utils.MiraiExperimentalAPI
 import net.mamoe.mirai.utils.MiraiInternalAPI
 import net.mamoe.mirai.utils.SinceMirai
@@ -40,15 +41,18 @@ sealed class HummerMessage : MessageContent {
 
 /**
  * 戳一戳. 可以发送给好友或群.
+ *
+ * @see Types 使用伴生对象中的常量
  */
 @SinceMirai("0.31.0")
 @OptIn(MiraiInternalAPI::class)
-data class PokeMessage @MiraiInternalAPI(message = "使用伴生对象中的常量") constructor(
-    @MiraiExperimentalAPI
+data class PokeMessage internal constructor(
+    @MiraiExperimentalAPI("may change in future")
     val type: Int,
-    @MiraiExperimentalAPI
+    @MiraiExperimentalAPI("may change in future")
     val id: Int
 ) : HummerMessage() {
+    @Suppress("DEPRECATION_ERROR", "DEPRECATION", "INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
     companion object Types : Message.Key<PokeMessage> {
         override val typeName: String
             get() = "PokeMessage"
@@ -117,6 +121,8 @@ data class PokeMessage @MiraiInternalAPI(message = "使用伴生对象中的常
  * 闪照
  *
  * @see Image.flash 转换普通图片为闪照
+ *
+ * @see Image 查看图片相关信息
  */
 @SinceMirai("0.33.0")
 sealed class FlashImage : MessageContent, HummerMessage() {

+ 4 - 81
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Image.kt

@@ -29,13 +29,14 @@ import kotlin.jvm.JvmSynthetic
 /**
  * 自定义表情 (收藏的表情), 图片
  *
+ * 查看平台 actual 定义以获取更多说明.
+ *
  * @see FlashImage 闪照
  * @see Image.flash 转换普通图片为闪照
  */
-interface Image : Message, MessageContent {
+expect interface Image : Message, MessageContent {
     companion object Key : Message.Key<Image> {
         override val typeName: String
-            get() = "Image"
     }
 
     /**
@@ -64,7 +65,7 @@ interface Image : Message, MessageContent {
 fun Image(imageId: String): Image = when {
     imageId.startsWith('/') -> OfflineFriendImage(imageId) // /f8f1ab55-bf8e-4236-b55e-955848d7069f
     imageId.length == 42 || imageId.startsWith('{') && imageId.endsWith('}') -> OfflineGroupImage(imageId) // {01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.png
-    else -> throw IllegalArgumentException("Bad imageId, expecting length=37 or 42, got ${imageId.length}")
+    else -> throw IllegalArgumentException("illegal imageId: $imageId. $ILLEGAL_IMAGE_ID_EXCEPTION_MESSAGE")
 }
 
 @MiraiInternalAPI("使用 Image")
@@ -286,82 +287,4 @@ data class OfflineFriendImage(
  */
 abstract class OnlineFriendImage : FriendImage(), OnlineImage
 
-
-// endregion
-
-
-//////////////////////
-// region internal
-//////////////////////
-
-
-private val EMPTY_BYTE_ARRAY = ByteArray(0)
-
-
-// /000000000-3814297509-BFB7027B9354B8F899A062061D74E206
-private val FRIEND_IMAGE_ID_REGEX_1 = Regex("""/[0-9]*-[0-9]*-[0-9a-zA-Z]{32}""")
-
-// /f8f1ab55-bf8e-4236-b55e-955848d7069f
-private val FRIEND_IMAGE_ID_REGEX_2 = Regex("""/.{8}-(.{4}-){3}.{12}""")
-
-// {01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.png
-private val GROUP_IMAGE_ID_REGEX = Regex("""\{.{8}-(.{4}-){3}.{12}}\..*""")
-
-@Suppress("NOTHING_TO_INLINE") // no stack waste
-internal inline fun Char.hexDigitToByte(): Int {
-    return when (this) {
-        in '0'..'9' -> this - '0'
-        in 'A'..'F' -> 10 + (this - 'A')
-        in 'a'..'f' -> 10 + (this - 'a')
-        else -> throw IllegalArgumentException("illegal hex digit: $this")
-    }
-}
-
-internal fun String.skipToSecondHyphen(): Int {
-    var count = 0
-    this.forEachIndexed { index, c ->
-        if (c == '-' && ++count == 2) return index
-    }
-    error("cannot find two hyphens")
-}
-
-internal fun String.imageIdToMd5(offset: Int): ByteArray {
-    val result = ByteArray(16)
-    var cur = 0
-    var hasCurrent = false
-    var lastChar: Char = 0.toChar()
-    for (index in offset..this.lastIndex) {
-        val char = this[index]
-        if (char == '-') continue
-        if (hasCurrent) {
-            result[cur++] = (lastChar.hexDigitToByte().shl(4) or char.hexDigitToByte()).toByte()
-            if (cur == 16) return result
-            hasCurrent = false
-        } else {
-            lastChar = char
-            hasCurrent = true
-        }
-    }
-    error("No enough chars")
-}
-
-@OptIn(ExperimentalStdlibApi::class)
-internal fun calculateImageMd5ByImageId(imageId: String): ByteArray {
-    return when {
-        imageId.matches(FRIEND_IMAGE_ID_REGEX_1) -> imageId.imageIdToMd5(imageId.skipToSecondHyphen() + 1)
-        imageId.matches(FRIEND_IMAGE_ID_REGEX_2) ->
-            imageId.imageIdToMd5(1)
-        imageId.matches(GROUP_IMAGE_ID_REGEX) -> {
-            imageId.imageIdToMd5(1)
-        }
-        else -> error(
-            "illegal imageId: $imageId. " +
-                    "ImageId must matches Regex `${FRIEND_IMAGE_ID_REGEX_1.pattern}`, " +
-                    "`${FRIEND_IMAGE_ID_REGEX_2.pattern}` or " +
-                    "`${GROUP_IMAGE_ID_REGEX.pattern}`"
-        )
-    }
-}
-
-
 // endregion

+ 30 - 13
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt

@@ -113,7 +113,7 @@ interface Message {
      * [GroupImage]: "[mirai:image:{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.png]"
      * [FriendImage]: "[mirai:image:/f8f1ab55-bf8e-4236-b55e-955848d7069f]"
      * [PokeMessage]: "[mirai:poke:1,-1]"
-     * [MessageChain]: 直接无间隔地连接所有元素 (`joinToString("")`)
+     * [MessageChain]: 无间隔地连接所有元素 (`joinToString("")`)
      *
      * @see contentToString
      */
@@ -122,10 +122,13 @@ interface Message {
     /**
      * 转为最接近官方格式的字符串. 如 `At(member) + "test"` 将转为 `"@群名片 test"`.
      *
-     * 对于 [NullMessageChain], 这个函数返回空字符串 "";
-     * 对于其他 [MessageChain], 这个函数返回值同 [toString].
+     * 在使用消息相关 DSL 和扩展时, 一些内容比较的实现均使用 [contentToString] 而不是 [toString]
      *
-     * 在使用消息相关 DSL 和扩展时, 一些内容比较的实现均使用的是 [contentToString] 而不是 [toString]
+     * 各个 [SingleMessage] 的转换示例:
+     * [PlainText]: "Hello"
+     * [Image]: "\[图片\]"
+     * [PokeMessage]: "\[戳一戳\]"
+     * [MessageChain]: 无间隔地连接所有元素 (`joinToString("", transformer=Message::contentToString)`)
      */
     @SinceMirai("0.34.0")
     fun contentToString(): String
@@ -234,25 +237,39 @@ inline operator fun Message.times(count: Int): MessageChain = this.repeat(count)
 
 @Suppress("OverridingDeprecatedMember")
 interface SingleMessage : Message, CharSequence, Comparable<String> {
-    /**
-     * 即 `sub in this.contentToString()`
-     */
+    @PlannedRemoval("1.0.0")
+    @JvmSynthetic
+    @Deprecated(
+        "有歧义, 自行使用 contentToString() 比较",
+        ReplaceWith("this.contentToString() == other"),
+        DeprecationLevel.ERROR
+    )
     /* final */ override operator fun contains(sub: String): Boolean = sub in this.contentToString()
 
-    /**
-     * 比较两个消息的 [contentToString]
-     */
+    @PlannedRemoval("1.0.0")
+    @JvmSynthetic
+    @Deprecated(
+        "有歧义, 自行使用 contentToString() 比较",
+        ReplaceWith("this.contentToString() == other"),
+        DeprecationLevel.ERROR
+    )
     /* final */ override infix fun eq(other: Message): Boolean = this.contentToString() == other.contentToString()
 
-    /**
-     * 将 [contentToString] 与 [other] 比较
-     */
+    @PlannedRemoval("1.0.0")
+    @JvmSynthetic
+    @Deprecated(
+        "有歧义, 自行使用 contentToString() 比较",
+        ReplaceWith("this.contentToString() == other"),
+        DeprecationLevel.ERROR
+    )
     /* final */ override infix fun eq(other: String): Boolean = this.contentToString() == other
 }
 
 /**
  * 消息元数据, 即不含内容的元素.
  * 包括: [MessageSource]
+ *
+ * @see ConstrainSingle 约束一个 [MessageChain] 中只存在这一种类型的元素
  */
 interface MessageMetadata : SingleMessage {
     override val length: Int get() = 0

+ 77 - 0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/impl.kt

@@ -262,3 +262,80 @@ internal class SingleMessageChainImpl constructor(
     override fun iterator(): Iterator<SingleMessage> = iterator { yield(delegate) }
 }
 
+
+//////////////////////
+// region Image impl
+//////////////////////
+
+
+internal val EMPTY_BYTE_ARRAY = ByteArray(0)
+
+
+// /000000000-3814297509-BFB7027B9354B8F899A062061D74E206
+private val FRIEND_IMAGE_ID_REGEX_1 = Regex("""/[0-9]*-[0-9]*-[0-9a-zA-Z]{32}""")
+
+// /f8f1ab55-bf8e-4236-b55e-955848d7069f
+private val FRIEND_IMAGE_ID_REGEX_2 = Regex("""/.{8}-(.{4}-){3}.{12}""")
+
+// {01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.png
+private val GROUP_IMAGE_ID_REGEX = Regex("""\{.{8}-(.{4}-){3}.{12}}\..*""")
+
+@Suppress("NOTHING_TO_INLINE") // no stack waste
+internal inline fun Char.hexDigitToByte(): Int {
+    return when (this) {
+        in '0'..'9' -> this - '0'
+        in 'A'..'F' -> 10 + (this - 'A')
+        in 'a'..'f' -> 10 + (this - 'a')
+        else -> throw IllegalArgumentException("illegal hex digit: $this")
+    }
+}
+
+internal fun String.skipToSecondHyphen(): Int {
+    var count = 0
+    this.forEachIndexed { index, c ->
+        if (c == '-' && ++count == 2) return index
+    }
+    error("cannot find two hyphens")
+}
+
+internal fun String.imageIdToMd5(offset: Int): ByteArray {
+    val result = ByteArray(16)
+    var cur = 0
+    var hasCurrent = false
+    var lastChar: Char = 0.toChar()
+    for (index in offset..this.lastIndex) {
+        val char = this[index]
+        if (char == '-') continue
+        if (hasCurrent) {
+            result[cur++] = (lastChar.hexDigitToByte().shl(4) or char.hexDigitToByte()).toByte()
+            if (cur == 16) return result
+            hasCurrent = false
+        } else {
+            lastChar = char
+            hasCurrent = true
+        }
+    }
+    error("No enough chars")
+}
+
+@OptIn(ExperimentalStdlibApi::class)
+internal fun calculateImageMd5ByImageId(imageId: String): ByteArray {
+    return when {
+        imageId.matches(FRIEND_IMAGE_ID_REGEX_1) -> imageId.imageIdToMd5(imageId.skipToSecondHyphen() + 1)
+        imageId.matches(FRIEND_IMAGE_ID_REGEX_2) ->
+            imageId.imageIdToMd5(1)
+        imageId.matches(GROUP_IMAGE_ID_REGEX) -> {
+            imageId.imageIdToMd5(1)
+        }
+        else -> error(
+            "illegal imageId: $imageId. $ILLEGAL_IMAGE_ID_EXCEPTION_MESSAGE"
+        )
+    }
+}
+
+internal val ILLEGAL_IMAGE_ID_EXCEPTION_MESSAGE =
+    "ImageId must matches Regex `${FRIEND_IMAGE_ID_REGEX_1.pattern}`, " +
+            "`${FRIEND_IMAGE_ID_REGEX_2.pattern}` or " +
+            "`${GROUP_IMAGE_ID_REGEX.pattern}`"
+
+// endregion

+ 3 - 3
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/ExternalImage.kt

@@ -133,7 +133,7 @@ class ExternalImage private constructor(
      *  PNG:    1001
      *  WEBP:   1002
      *  BMP:    1005
-     *  GIG:    2000
+     *  GIG:    2000 // TODO gig? gif?
      *  APNG:   2001
      *  SHARPP: 1004
      */
@@ -148,7 +148,7 @@ class ExternalImage private constructor(
 }
 
 /**
- * 将图片发送给指定联系人
+ * 将图片作为单独的消息发送给指定联系人
  */
 @JvmSynthetic
 suspend fun <C : Contact> ExternalImage.sendTo(contact: C): MessageReceipt<C> = when (contact) {
@@ -171,7 +171,7 @@ suspend fun ExternalImage.upload(contact: Contact): OfflineImage = when (contact
 }
 
 /**
- * 将图片发送给 [this]
+ * 将图片作为单独的消息发送给 [this]
  */
 @JvmSynthetic
 suspend inline fun <C : Contact> C.sendImage(image: ExternalImage): MessageReceipt<C> = image.sendTo(this)

+ 62 - 0
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/data/Image.kt

@@ -0,0 +1,62 @@
+/*
+ * Copyright 2020 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/master/LICENSE
+ */
+
+@file:JvmMultifileClass
+@file:JvmName("MessageUtils")
+
+package net.mamoe.mirai.message.data
+
+import kotlinx.io.core.Input
+import net.mamoe.mirai.contact.Contact
+import java.io.File
+import java.io.InputStream
+import java.net.URL
+
+/**
+ * 自定义表情 (收藏的表情) 和普通图片.
+ *
+ * ### 上传和发送图片
+ * @see Contact.uploadImage 上传图片并得到 [Image] 消息
+ * @see Contact.sendImage 上传并发送单个图片作为一条消息
+ * @see Image.sendTo 上传图片并得到 [Image] 消息
+ *
+ * @see File.uploadAsImage
+ * @see InputStream.uploadAsImage
+ * @see Input.uploadAsImage
+ * @see URL.uploadAsImage
+ *
+ * @see File.sendAsImageTo
+ * @see InputStream.sendAsImageTo
+ * @see Input.sendAsImageTo
+ * @see URL.sendAsImageTo
+ *
+ *
+ *
+ * @see FlashImage 闪照
+ * @see Image.flash 转换普通图片为闪照
+ */
+actual interface Image : Message, MessageContent {
+    actual companion object Key : Message.Key<Image> {
+        actual override val typeName: String
+            get() = "Image"
+    }
+
+    /**
+     * 图片的 id.
+     * 图片 id 不一定会长时间保存, 因此不建议使用 id 发送图片.
+     * 图片 id 主要根据图片文件 md5 计算得到.
+     *
+     * 示例:
+     * 好友图片的 id: `/f8f1ab55-bf8e-4236-b55e-955848d7069f` 或 `/000000000-3814297509-BFB7027B9354B8F899A062061D74E206`
+     * 群图片的 id: `{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.png`
+     *
+     * @see Image 使用 id 构造图片
+     */
+    actual val imageId: String
+}