mirai icon indicating copy to clipboard operation
mirai copied to clipboard

ImageId 重设计提案

Open Karlatemp opened this issue 3 years ago • 19 comments

根据已有相关 issue 可得目前 imageId 格式不能很好的满足图片的发送, 需要对 imageId 的格式进行更新以携带更多 core 发送图片需要的相关必要信息


目标

  • 解决通过 imageId 发送图片造成的各种问题
  • 使新格式最大程度兼容原有格式
  • 使用户迁移工作量最小

最终修改方向

// 未定


提案

以下内容仅为提案,不代表最终修改方向

为 Image 提供两种 id, 分别为带有详细信息的 完整 id 以及 原格式 id

public interface Image {

// 返回原 id 格式
@Deprecated
public val imageId: String

// 返回新 id 格式
public val imageIdNew: String

}

新 ID 格式

{12345678-90AB-CDEF-1234-567890ABCDEF}.ext+[MIRAI INTERNAL METADATA] (其中 [MIM] 由且仅由 mirai 内部识别)

internal metadata format

Format 1

metadata 可包含多条信息,以某个分隔符分割 (暂定为 |),

为了避免编码问题, 信息应该可使用 ASCII 编码

为了字段最简化, 每条信息采用此格式 [识别名][参数](如 a20212912), 其中 [识别名]0-9A-Za-z, 识别名 mirai 内部可识, 剩余内容为该信息的参数. 当 [识别名] == 'Z' 时, 继续识别下一个字符, 此后更多字段以此类推

至此, 新的 imageId 应该会为像这样的格式 {12345678-90AB-CDEF-1234-567890ABCDEF}.jpeg+s1440x900|b2ABABE

Format 2

metadata 直接存储为二进制数据 (protobuf), 并使用 base64 编码为 ASCII

至此, 新的 imageId 应该会为像这样的格式

// Metadata compressed
{12345678-90AB-CDEF-1234-567890ABCDEF}.jpeg+AAAAAAAAAAAAA
// Metadata uncompressed
{12345678-90AB-CDEF-1234-567890ABCDEF}.jpeg+AAAAAAAAAAAAA

其他细节

public interface Image {

// 需要确定: 严格比较全部数据 (包括metadata)还是仅比较 md5
fun equals(other: Any?)
fun hashCode(): Int

// 需要确定:使用 imageIdNew / legacyId
fun toString(): String

// 使用 imageIdNew
fun toMiraiCode(): String

}

Karlatemp avatar Dec 29 '21 10:12 Karlatemp

mitadata 既然只供内部使用,那用 ProtoBuf 编码不就最小了?(其实主要还是简单)

Him188 avatar Dec 29 '21 13:12 Him188

使用 jvm 参数修改行为不太好,这种有格式的属性必须在编译期固定格式

Him188 avatar Dec 29 '21 13:12 Him188

既然根据经验,图片不包含大小和长宽就不能发送,就没没太大必要支持旧版 id 了。用户使用这种 id 一般都是为了储存或者通信,这些情况都需要保留数据

但由于用户有可能会处理 imageId 的内容,不能影响已经编译的代码。

一个绝对兼容的更新方式是保留 imageId 及其特性,新增 imageIdNew 或者其他较短命名的属性返回新版本。

另一个要有一些迁移才能兼容,但可以让 imageId 将来返回新版本的方式是:

  1. 添加一个属性返回新版本
  2. 修改 val imageId, inline get() = 旧版本,标注 deprecated
  3. 在一些版本后将 imageId 的 getter 改名为新版本的函数名,并返回新版本;添加 fun getImageId 标注 deprecated HIDDEN,返回旧版本

Him188 avatar Dec 29 '21 13:12 Him188

mitadata 既然只供内部使用,那用 ProtoBuf 编码不就最小了?(其实主要还是简单)

主要考虑到最终给出去的是一个 String, 直接 protobuf 需要经过一层 Hex/Base64/..., 可能会导致更长, 不过经过 gzip 后应该不会太长也行

就没没太大必要支持旧版 id 了

我觉得还是可以支持一下,提供最低限度的支持

Karlatemp avatar Dec 29 '21 14:12 Karlatemp

但由于用户有可能会处理 imageId 的内容,不能影响已经编译的代码。

ID对用户的主要场景应该是作为标识,任何直接从ID中解析metadata或md5的行为都可能妨碍扩展性(可以另行讨论其必要性) 出于扩展性的考虑,提议新ID不做出过分具体的格式承诺,给出黑盒的String(为了便于序列化等场合,可承诺只包含字母及部分特定符号),并提供版本标号

mitadata 既然只供内部使用,那用 ProtoBuf 编码不就最小了?(其实主要还是简单)

即使如此,使id基本可读仍然可能有助于调试分析等场合

AdoptOSS avatar Dec 29 '21 14:12 AdoptOSS

另需考虑id的唯一性比较意义在新ID如何成立 考虑是否需要规定比较行为使用 mainID or fullID(特别是考虑到服务器提供的metadata可能不可靠的情况下)

AdoptOSS avatar Dec 29 '21 14:12 AdoptOSS

另需考虑id的唯一性比较意义在新ID如何成立 考虑是否需要规定比较行为使用 mainID or fullID(特别是考虑到服务器提供的metadata可能不可靠的情况下)

从底层来看 metadata 不一致也就是图片也是不相同的, 从此角度看满足 id 的意义 当然从最终显示效果来看, 是只比较图片文件内容的, 已经存在且已公开 Image.md5, 可满足此角度判断, 可能需要再开个名为 contentId 的字段

Karlatemp avatar Dec 29 '21 14:12 Karlatemp

我赞成将旧 id 定名为 contentId

Him188 avatar Dec 29 '21 14:12 Him188

其实这是不是就是在序列化图片?

Him188 avatar Dec 29 '21 14:12 Him188

其实这是不是就是在序列化图片?

Karlatemp avatar Dec 29 '21 14:12 Karlatemp

的确相当于序列化,但是在许多场合,紧凑设计的image id 比多字段的Mirai code 或 JSON 要方便得多

AdoptOSS avatar Dec 29 '21 14:12 AdoptOSS

能不能 generally 定义可读的序列化表示? 这样也能支持 audio (audio 也有 extraData) image

Him188 avatar Dec 29 '21 14:12 Him188

能不能 generally 定义可读的序列化表示? 这样也能支持 audio (audio 也有 extraData)

这是属于代码上的实现,目前需要先确定新的格式再进行代码编写, 只是可以把新的 imageId 格式应用到 audio

Karlatemp avatar Dec 29 '21 15:12 Karlatemp

Image.equals: 由于不带 size 信息的图片发出去是不能显示的, 所以我觉得不能只比较 md5

Him188 avatar Dec 29 '21 15:12 Him188

@Karlatemp 如果能定义通用的序列化格式, 那么这个属性就不叫 imageId 而是叫 serialData 或者其他了, 也就不需要弃用, 因为它完全是一个新的概念

Him188 avatar Dec 29 '21 15:12 Him188

@Karlatemp 如果能定义通用的序列化格式, 那么这个属性就不叫 imageId 而是叫 serialData 或者其他了, 也就不需要弃用, 因为它完全是一个新的概念

实际上,我提起此议题的主要原因是当前id携带信息过少导致后续的更新麻烦,我是出于此目的才提起的此议题

Karlatemp avatar Dec 29 '21 16:12 Karlatemp

@Karlatemp 我知道, 我是在考虑不只是解决这个问题, 还考虑将来的扩展

Him188 avatar Dec 29 '21 16:12 Him188

我支持 Format 2, 更容易维护

Him188 avatar Dec 30 '21 14:12 Him188

既然只用于内部使用,我觉得可以用hex格式存储数据,无需考虑可读性

使用如:type+value的格式进行存储

01(imageid)02(width)03(height)04(format)...
01abcdabcdabcdabcd 025a00 033000 0401
(1440x768,jpg)

类型长度已经被限定,所以不需要额外附加长度

wyapx avatar May 04 '22 09:05 wyapx