Meshline
简体中文规范下载 Markdown 原文

中文为规范基准;英文为维护译本。

账户消息时间线

客户端—中继协议 · 消息投递 · 消息方法

时间线模型

账户在同一中继上使用同一条只追加的消息时间线;不同中继的时间线相互独立。当前归属中继向该账户的本地时间线追加以下记录:

  • 该账户收到的每个 MessageEnvelope;
  • 该账户通过 message.send 发出且提供了 sender_boxes 的消息。

每条记录保存原信封和时间线所属账户的密钥盒。

中继为账户消息时间线分配非负 sequence,并永久保留该账户在本中继曾经分配的最高序号。后续分配的 sequence 必须大于该值,不要求连续。消息清理和中继重启不得使最高序号减小或重置。时间线头指该最高序号;尚未分配过序号时为 -1。

sequence 表示账户在本中继上的记录位置,不在不同账户或不同中继之间比较。历史缺口位置也以账户在对应中继上的时间线为范围。

时间线只负责保留期内的跨设备同步,不是永久聊天存储。客户端持久化的消息和协议状态才是长期记录。

客户端在所有中继之间按信封的 (from, message_id) 去重。首次接受的消息必须通过验证;此后收到相同逻辑消息键的记录时直接忽略,不得覆盖已接受内容或重复应用。

MessageTimelineEntry

MessageTimelineEntry 是同步响应中的一条可见记录。

字段 类型 必需 语义与约束
sequence integer 是 账户时间线位置;非负并严格递增
envelope MessageEnvelope 是 中继接受的原始消息信封
key_box MessageKeyBox 是 为当前设备封装原消息内容密钥的密钥盒
accepted_at integer 是 中继接受该记录的 Unix 秒

时间线所属账户必须是原信封的发送账户或接收账户。发送账户与接收账户不同时,客户端根据记录中信封的发送账户和目标账户判断方向;两者相同时是账户自身投递。

设备可见范围

一个入站 MessageEnvelope 在目标账户时间线中只占一个 sequence。中继在接受时确定该记录的设备可见范围:本账户密钥盒中当时有效的设备获准同步这一项;未知、尚未生效、已移除、已过期或已撤销的设备不能读取该项。

至少一台目标设备有效时,中继接受整条消息并按该范围提供同步;全部目标设备都不可用时,整个投递失败且不追加时间线。

发件记录只对本账户密钥盒中当时有效的设备可见。

同一设备 ID 被移除后又重新启用时,既有记录的设备可见范围保持不变,历史缺口的判定也不重置。

sequence 的间隔可能来自未分配的序号或设备不可见的记录,不得仅凭数值间隔判断历史丢失;历史缺口按消息保留与历史缺口的规则判定。

消息保留与历史缺口

每条记录的最低保留截止时间为 accepted_at 加中继接受该记录时的 message_retention,后续配置调整不得缩短该期限。当前配置通过 relay.info 的 limits 返回。投递结果的保留期见投递结果保留规则。

中继清理过期记录后,仍必须能够按设备可见范围和请求位置正确判断历史缺口。设备请求的位置之后至少存在一条原本对其可见、但完整内容已经过期的记录时,同步响应必须包含 has_retention_gap: true。未面向当前设备或接受时对应设备不可用的记录,不形成该设备的历史缺口。

消息时间线处理流程

客户端必须按 message.timeline.sync 的响应约束验证本页 certificates 数组,并按 MessageEnvelope 的规则验证记录中的信封。随后确认 key_box.device_id 与当前设备 ID 一致,并使用该 key_box 按端到端加密构造解封内容密钥并认证解密 payload。

应用来自其他账户的业务内容前,还必须验证发送关系或业务对象自身携带的授权材料;发送到其他账户的记录必须确认发送账户是本账户。账户自身投递必须确认信封两端都是本账户。

同一业务的状态变更必须按对应中继的 sequence 顺序生效。未知业务 $type 可以保存或忽略;无效或未通过授权验证的业务内容不得应用。

同步位置按账户和中继区分,作为 message.timeline.sync 的 after 参数。响应通过验证后,客户端可以使用该页最大的 sequence 继续同步;尚未开始同步时,使用 -1 或省略 after。空页不改变同步位置。