pub struct CatchupSnapshot {
pub v: u8,
pub conversation_metas: Vec<CatchupConversationEntry>,
pub last_app_events_per_conv: Vec<CatchupAppEventEntry>,
}Expand description
[CR-13] Catchup snapshot delivered to a newly-linked device.
Populates the catchup_snapshot field of LinkingTicket so the new device boots
with a populated conversation list + last-known plaintext per conversation, instead
of an empty UI until peers re-Welcome.
group_state_bytes is reserved for the [CR-7] DeviceGroup-snapshot machinery; until
CR-7 lands it’s always empty (Vec::new()) on every meta. The encoding is forward-
compatible: a snapshot produced today will decode cleanly on a future SDK build that
understands CR-7, and a future-produced snapshot decodes on today’s SDK (we just ignore
the populated group_state_bytes).
last_app_events_per_conv is host-supplied — the SDK doesn’t store decrypted
plaintext on its own, so the host passes through whatever it wants the new device to
see on launch (typically: the last N AppEvent bytes per conversation).
Fields§
§v: u8Format version. 1 today; bumped on incompatible CBOR-shape changes.
conversation_metas: Vec<CatchupConversationEntry>Conversation list + per-conversation MLS state. group_state_bytes is empty
pre-CR-7; the field is reserved so the wire format doesn’t churn when CR-7 ships.
last_app_events_per_conv: Vec<CatchupAppEventEntry>Last-known decrypted AppEvent bytes per conversation. Host-supplied; opaque to
the SDK. Each entry is keyed by ConversationId.
Implementations§
Source§impl CatchupSnapshot
impl CatchupSnapshot
Sourcepub fn empty() -> Self
pub fn empty() -> Self
Build an empty snapshot (no metas, no events). Equivalent to “no catchup data.”
Sourcepub fn encode(&self) -> Result<Vec<u8>>
pub fn encode(&self) -> Result<Vec<u8>>
CBOR-encode for inclusion in a LinkingTicket::catchup_snapshot.
Returns Err(Error::Invalid) if the encoded size exceeds
CATCHUP_SNAPSHOT_HARD_CAP (256 KB). Sizes between the soft cap (64 KB) and the
hard cap log a warning but still succeed — they’re suboptimal but not refused.
Sourcepub fn encode_within_cap(self) -> Result<Vec<u8>>
pub fn encode_within_cap(self) -> Result<Vec<u8>>
CBOR-encode, guaranteeing the result fits under CATCHUP_SNAPSHOT_HARD_CAP
by shedding payload until it does — instead of erroring like [encode].
[encode] is the strict encoder used by conformance vectors and callers that
build their own bounded snapshots. build_linking_ticket, by contrast, snapshots
every conversation the user is in, so a user with many (or large) groups can
blow the 256 KB ticket cap through no fault of the host — and a hard error there
breaks device linking entirely (the new device can’t even join the DeviceGroup).
This method makes linking degrade gracefully instead of failing:
- Fast path — if the full snapshot already fits, return it.
- Drop
group_state_bytes(CR-7 per-group MLS state), largest first, until it fits. An emptygroup_state_bytesis an explicitly-supported receiver case (§CR-7): that conversation is caught up via the normal re-Welcome path instead of local import. Ping’s hosts (web + iOS) already re-admit every chat after linking, so dropping this state costs nothing functionally — only the “boot already able to decrypt” optimisation for the shed conversations. - If still over (pathological host-supplied
last_app_events), trimlast_app_events_per_convfrom the tail. - If still over (thousands of conversation_metas), drop metas from the tail. The new device then relies fully on normal sync — identical to the pre-CR-13 empty-snapshot behaviour.
Conversation metadata is preserved as long as it fits, so the common large-account case still boots with a populated conversation list. Whatever is shed is logged.
Sourcepub fn decode(bytes: &[u8]) -> Result<Self>
pub fn decode(bytes: &[u8]) -> Result<Self>
Decode a CBOR-encoded snapshot. Refuses sizes over CATCHUP_SNAPSHOT_HARD_CAP
to bound attacker-controlled allocation; refuses unknown v to avoid silently
dropping fields a future version added.
Trait Implementations§
Source§impl Clone for CatchupSnapshot
impl Clone for CatchupSnapshot
Source§fn clone(&self) -> CatchupSnapshot
fn clone(&self) -> CatchupSnapshot
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for CatchupSnapshot
impl Debug for CatchupSnapshot
Source§impl<'de> Deserialize<'de> for CatchupSnapshot
impl<'de> Deserialize<'de> for CatchupSnapshot
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Auto Trait Implementations§
impl Freeze for CatchupSnapshot
impl RefUnwindSafe for CatchupSnapshot
impl Send for CatchupSnapshot
impl Sync for CatchupSnapshot
impl Unpin for CatchupSnapshot
impl UnsafeUnpin for CatchupSnapshot
impl UnwindSafe for CatchupSnapshot
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Declassify for T
impl<T> Declassify for T
type Declassified = T
fn declassify(self) -> T
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more