mirai
mirai copied to clipboard
ImageId 重设计提案
根据已有相关 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
}
mitadata 既然只供内部使用,那用 ProtoBuf 编码不就最小了?(其实主要还是简单)
使用 jvm 参数修改行为不太好,这种有格式的属性必须在编译期固定格式
既然根据经验,图片不包含大小和长宽就不能发送,就没没太大必要支持旧版 id 了。用户使用这种 id 一般都是为了储存或者通信,这些情况都需要保留数据
但由于用户有可能会处理 imageId 的内容,不能影响已经编译的代码。
一个绝对兼容的更新方式是保留 imageId 及其特性,新增 imageIdNew 或者其他较短命名的属性返回新版本。
另一个要有一些迁移才能兼容,但可以让 imageId 将来返回新版本的方式是:
- 添加一个属性返回新版本
- 修改 val imageId, inline get() = 旧版本,标注 deprecated
- 在一些版本后将 imageId 的 getter 改名为新版本的函数名,并返回新版本;添加 fun getImageId 标注 deprecated HIDDEN,返回旧版本
mitadata 既然只供内部使用,那用 ProtoBuf 编码不就最小了?(其实主要还是简单)
主要考虑到最终给出去的是一个 String, 直接 protobuf 需要经过一层 Hex/Base64/..., 可能会导致更长, 不过经过 gzip 后应该不会太长也行
就没没太大必要支持旧版 id 了
我觉得还是可以支持一下,提供最低限度的支持
但由于用户有可能会处理 imageId 的内容,不能影响已经编译的代码。
ID对用户的主要场景应该是作为标识,任何直接从ID中解析metadata或md5的行为都可能妨碍扩展性(可以另行讨论其必要性) 出于扩展性的考虑,提议新ID不做出过分具体的格式承诺,给出黑盒的String(为了便于序列化等场合,可承诺只包含字母及部分特定符号),并提供版本标号
mitadata 既然只供内部使用,那用 ProtoBuf 编码不就最小了?(其实主要还是简单)
即使如此,使id基本可读仍然可能有助于调试分析等场合
另需考虑id的唯一性比较意义在新ID如何成立 考虑是否需要规定比较行为使用 mainID or fullID(特别是考虑到服务器提供的metadata可能不可靠的情况下)
另需考虑id的唯一性比较意义在新ID如何成立 考虑是否需要规定比较行为使用 mainID or fullID(特别是考虑到服务器提供的metadata可能不可靠的情况下)
从底层来看 metadata 不一致也就是图片也是不相同的, 从此角度看满足 id 的意义
当然从最终显示效果来看, 是只比较图片文件内容的, 已经存在且已公开 Image.md5
, 可满足此角度判断, 可能需要再开个名为 contentId
的字段
我赞成将旧 id 定名为 contentId
其实这是不是就是在序列化图片?
其实这是不是就是在序列化图片?
是
的确相当于序列化,但是在许多场合,紧凑设计的image id 比多字段的Mirai code 或 JSON 要方便得多
能不能 generally 定义可读的序列化表示? 这样也能支持 audio (audio 也有 extraData)
能不能 generally 定义可读的序列化表示? 这样也能支持 audio (audio 也有 extraData)
这是属于代码上的实现,目前需要先确定新的格式再进行代码编写, 只是可以把新的 imageId 格式应用到 audio
Image.equals: 由于不带 size 信息的图片发出去是不能显示的, 所以我觉得不能只比较 md5
@Karlatemp 如果能定义通用的序列化格式, 那么这个属性就不叫 imageId 而是叫 serialData 或者其他了, 也就不需要弃用, 因为它完全是一个新的概念
@Karlatemp 如果能定义通用的序列化格式, 那么这个属性就不叫 imageId 而是叫 serialData 或者其他了, 也就不需要弃用, 因为它完全是一个新的概念
实际上,我提起此议题的主要原因是当前id携带信息过少导致后续的更新麻烦,我是出于此目的才提起的此议题
@Karlatemp 我知道, 我是在考虑不只是解决这个问题, 还考虑将来的扩展
我支持 Format 2, 更容易维护
既然只用于内部使用,我觉得可以用hex格式存储数据,无需考虑可读性
使用如:type+value的格式进行存储
01(imageid)02(width)03(height)04(format)...
01abcdabcdabcdabcd 025a00 033000 0401
(1440x768,jpg)
类型长度已经被限定,所以不需要额外附加长度