ClientRuntime 与 LocalStore 契约¶
依赖:shared.md。SDK 独占连接、同步、游标、pending、REBUILD 与事件去重状态机;所有宿主只驱动这一份运行时。
pub trait LocalStore: Send + Sync {
async fn persist_pending(
&self,
request: SendMessage,
) -> Result<(), ClientRuntimeError>;
async fn apply_mailbox_page(
&self,
page: MailboxPage,
cursor: MailboxCursor,
) -> Result<Vec<MailboxEntry>, ClientRuntimeError>;
async fn resolve_pending(
&self,
committed: CommittedMessage,
content: MessageContent,
) -> Result<(), ClientRuntimeError>;
async fn pending(&self) -> Result<Vec<SendMessage>, ClientRuntimeError>;
async fn apply_history(
&self,
page: HistoryPage,
) -> Result<Vec<MessageRecord>, ClientRuntimeError>;
async fn cursor(&self) -> Result<Option<MailboxCursor>, ClientRuntimeError>;
async fn reset_for_rebuild(&self) -> Result<(), ClientRuntimeError>;
}
pub trait ClientRuntime: Send + Sync {
async fn connect(
&self,
request: ConnectRequest,
) -> Result<(), ClientRuntimeError>;
async fn send_message(
&self,
request: SendMessage,
) -> Result<(), ClientRuntimeError>;
async fn apply_mailbox_batch(
&self,
page: MailboxPage,
) -> Result<(), ClientRuntimeError>;
async fn pull_history(
&self,
query: HistoryQuery,
) -> Result<HistoryPage, ClientRuntimeError>;
async fn pull_members(
&self,
request: MemberPageRequest,
) -> Result<MemberPage, ClientRuntimeError>;
async fn begin_rebuild(
&self,
trim_watermark: MailboxSeq,
) -> Result<RebuildPlan, ClientRuntimeError>;
async fn finish_rebuild(
&self,
cursor: MailboxCursor,
) -> Result<(), ClientRuntimeError>;
async fn next_event(&self) -> Result<ClientEvent, ClientRuntimeError>;
}
前置条件¶
- 宿主创建 runtime 后必须显式调用一次
connect;未连接的网络命令返回ConnectRequired,不得隐式使用默认账户连接。 - 除测试显式选择
InMemoryForTest外,LocalStore必须是稳定的持久化位置。游标须一同保存 lane、epoch 和最后已应用序号。 apply_mailbox_batch只接受完整事件组;begin_rebuild只由CursorExpired路径触发。
后置条件¶
send_message先将 pending 原子写入本地库,再允许网络发送;ACK 丢失后重启仍可对账。- 邮箱批次中的消息、去重记录、会话投影和游标必须在同一逻辑事务中落库,游标只能在批次完整应用后推进;实时 Push 不得推进游标。
- 重连时 runtime 先同步邮箱,以发送者自己的
ClientMessageId对账 pending;命中则原位确认,未命中才以原 ID 重发。 resolve_pending与历史写入保留MessageType/custom_type;MessagesAdded只包含实际新增的条目。begin_rebuild保留 pending 和已有本地消息,先取权威会话列表、逐会话补历史,再由finish_rebuild持久新游标并恢复 pending 对账。- ACK 与 PONG 超期使状态离开
Online并进入重连;不会无限维持在线状态。
错误¶
CursorExpired必须触发 REBUILD,不能以空邮箱页或推进游标降级处理。- 本地迁移失败或版本过新时,
LocalStoreFailure后的重置必须同时丢弃游标与可重建数据、保留 pending,并发出LocalStoreReset事件。