pub struct Store<C: RecordCodec> { /* private fields */ }Expand description
The in-memory working set: every mutable piece of state
mail4agent-messenger’s core needs across a process lifetime, plus the
FlushGate that turns mutations into sealed records a shell persists.
Generic over the RecordCodec used to seal/open every record — see
the module doc’s “Sealing is a codec, not a concrete algorithm” section.
Implementations§
Source§impl<C: RecordCodec> Store<C>
impl<C: RecordCodec> Store<C>
Sourcepub fn new(device_id: DeviceId, codec: C) -> Self
pub fn new(device_id: DeviceId, codec: C) -> Self
Builds an empty working set for device_id, backed by codec for
every future flush export. Nothing is dirty yet — this is the
brand-new-device case (plan §4.1’s first unlock); a shell that
already has records from an earlier session calls Store::load
instead.
Sourcepub fn load(
records: impl IntoIterator<Item = SealedRecord>,
codec: C,
device_id: DeviceId,
) -> Result<Self, StoreError>
pub fn load( records: impl IntoIterator<Item = SealedRecord>, codec: C, device_id: DeviceId, ) -> Result<Self, StoreError>
Rebuilds a working set from sealed records a shell read back from
durable storage (plan decision #3’s MessengerCore::open). See the
module doc’s “Forward compatibility” section for what happens to a
key this version of the store does not recognize, and this type’s
own doc for what a recognized-but-malformed or a
recognized-but-uninterpretable key does.
Sourcepub fn take_flush_batch(&mut self) -> Option<FlushBatch>
pub fn take_flush_batch(&mut self) -> Option<FlushBatch>
Drains everything dirtied since the previous call into one
FlushBatch for a shell to write durably — see
FlushGate::take_batch.
Sourcepub fn ack_flush(&mut self, id: u64)
pub fn ack_flush(&mut self, id: u64)
Acknowledges that batch id has been durably written — see
FlushGate::ack.
Trait Implementations§
Source§impl<C: RecordCodec> CryptoStore for Store<C>
impl<C: RecordCodec> CryptoStore for Store<C>
Source§fn account(&self) -> Result<Option<&[u8]>, StoreError>
fn account(&self) -> Result<Option<&[u8]>, StoreError>
Source§fn save_account(&mut self, account: Vec<u8>) -> Result<(), StoreError>
fn save_account(&mut self, account: Vec<u8>) -> Result<(), StoreError>
Source§fn olm_sessions_for_device(
&self,
their_curve25519: &str,
) -> Result<Vec<Vec<u8>>, StoreError>
fn olm_sessions_for_device( &self, their_curve25519: &str, ) -> Result<Vec<Vec<u8>>, StoreError>
their_curve25519, ordered MOST-recently-used first (see
Store::save_olm_session’s own doc for what “used” means here).
At most [MAX_OLM_SESSIONS_PER_DEVICE] entries – older, less
recently used sessions are evicted, never accumulated. Empty (never
an error) if none exist yet.Source§fn save_olm_session(
&mut self,
their_curve25519: &str,
session_id: &str,
session: Vec<u8>,
) -> Result<(), StoreError>
fn save_olm_session( &mut self, their_curve25519: &str, session_id: &str, session: Vec<u8>, ) -> Result<(), StoreError>
session_id,
REPLACING any earlier record for the same (their_curve25519, session_id) pair and marking it the most-recently-used session for
that peer. This is a hard requirement, not an optimization: an Olm
session’s own pickle is its FULL ratchet state, including every
chain/message key it has ever derived and not yet forgotten. Keeping
an older snapshot of the SAME session_id around after a newer one
has been saved would mean an already-consumed message key survives
on disk somewhere the newer snapshot itself no longer has it –
exactly the forward-secrecy property Olm’s ratchet exists to
provide, and exactly the kind of stale state a decrypt path must
never be able to resurrect to replay an already-decrypted message.
A caller with a genuinely different session for the same peer
(e.g. two independently-established sessions from a real Olm race)
passes a different session_id and gets a second, independent
slot – up to [MAX_OLM_SESSIONS_PER_DEVICE] per peer; saving
beyond that evicts the least-recently-used one (its record is
deleted, riding in the same flush batch as this save).Source§fn inbound_group_session(
&self,
room_id: &RoomId,
session_id: &str,
) -> Result<Option<&[u8]>, StoreError>
fn inbound_group_session( &self, room_id: &RoomId, session_id: &str, ) -> Result<Option<&[u8]>, StoreError>
(room_id, session_id), if
this device has ever received one.Source§fn save_inbound_group_session(
&mut self,
room_id: &RoomId,
session_id: &str,
session: Vec<u8>,
) -> Result<(), StoreError>
fn save_inbound_group_session( &mut self, room_id: &RoomId, session_id: &str, session: Vec<u8>, ) -> Result<(), StoreError>
(room_id, session_id).Source§fn outbound_group_session(
&self,
room_id: &RoomId,
) -> Result<Option<&[u8]>, StoreError>
fn outbound_group_session( &self, room_id: &RoomId, ) -> Result<Option<&[u8]>, StoreError>
Source§fn save_outbound_group_session(
&mut self,
room_id: &RoomId,
session: Vec<u8>,
) -> Result<(), StoreError>
fn save_outbound_group_session( &mut self, room_id: &RoomId, session: Vec<u8>, ) -> Result<(), StoreError>
Source§fn devices_for_user(
&self,
user_id: &UserId,
) -> Result<Option<&[u8]>, StoreError>
fn devices_for_user( &self, user_id: &UserId, ) -> Result<Option<&[u8]>, StoreError>
user_id, if
any.Source§fn save_devices(
&mut self,
user_id: &UserId,
devices: Vec<u8>,
) -> Result<(), StoreError>
fn save_devices( &mut self, user_id: &UserId, devices: Vec<u8>, ) -> Result<(), StoreError>
user_id.Source§fn tracked_users(&self) -> Result<Vec<(UserId, bool)>, StoreError>
fn tracked_users(&self) -> Result<Vec<(UserId, bool)>, StoreError>
Source§fn mark_user_tracked(
&mut self,
user_id: &UserId,
outdated: bool,
) -> Result<(), StoreError>
fn mark_user_tracked( &mut self, user_id: &UserId, outdated: bool, ) -> Result<(), StoreError>
user_id, recording whether its device
list is known to be stale.Source§fn withheld_reason(
&self,
room_id: &RoomId,
session_id: &str,
) -> Result<Option<&[u8]>, StoreError>
fn withheld_reason( &self, room_id: &RoomId, session_id: &str, ) -> Result<Option<&[u8]>, StoreError>
(room_id, session_id), if
any.Source§fn save_withheld(
&mut self,
room_id: &RoomId,
session_id: &str,
code: Vec<u8>,
) -> Result<(), StoreError>
fn save_withheld( &mut self, room_id: &RoomId, session_id: &str, code: Vec<u8>, ) -> Result<(), StoreError>
(room_id, session_id).Source§fn backup_key(&self) -> Result<Option<&[u8]>, StoreError>
fn backup_key(&self) -> Result<Option<&[u8]>, StoreError>
Source§fn save_backup_key(&mut self, key: Vec<u8>) -> Result<(), StoreError>
fn save_backup_key(&mut self, key: Vec<u8>) -> Result<(), StoreError>
Source§fn cross_signing_keys(&self) -> Result<Option<&[u8]>, StoreError>
fn cross_signing_keys(&self) -> Result<Option<&[u8]>, StoreError>
Source§fn save_cross_signing_keys(&mut self, keys: Vec<u8>) -> Result<(), StoreError>
fn save_cross_signing_keys(&mut self, keys: Vec<u8>) -> Result<(), StoreError>
Source§impl<C: RecordCodec> FlushEpoch for Store<C>
impl<C: RecordCodec> FlushEpoch for Store<C>
Source§fn seal_for_request(&mut self) -> (RequiredSeq, Option<FlushBatch>)
fn seal_for_request(&mut self) -> (RequiredSeq, Option<FlushBatch>)
FlushBatch, returning the RequiredSeq a
request minted right now must wait on, plus that batch if one was
produced (None if nothing was pending). See the module doc’s
worked example for the exact rule this implements.Source§fn is_released(&self, required: RequiredSeq) -> bool
fn is_released(&self, required: RequiredSeq) -> bool
true iff every batch at or before required’s sequence id has
been acknowledged — i.e. it is safe to release a request that
recorded required as its RequiredSeq.Source§impl<C: RecordCodec> StateStore for Store<C>
impl<C: RecordCodec> StateStore for Store<C>
Source§fn sync_token(&self) -> Result<Option<&str>, StoreError>
fn sync_token(&self) -> Result<Option<&str>, StoreError>
/sync next_batch token from the most recent successful sync,
if any.Source§fn save_sync_token(&mut self, token: String) -> Result<(), StoreError>
fn save_sync_token(&mut self, token: String) -> Result<(), StoreError>
/sync next_batch token, replacing any earlier one.Source§fn room_state(&self, room_id: &RoomId) -> Result<Option<&[u8]>, StoreError>
fn room_state(&self, room_id: &RoomId) -> Result<Option<&[u8]>, StoreError>
room_id, if this store has one.Source§fn save_room_state(
&mut self,
room_id: &RoomId,
state: Vec<u8>,
) -> Result<(), StoreError>
fn save_room_state( &mut self, room_id: &RoomId, state: Vec<u8>, ) -> Result<(), StoreError>
room_id.Source§fn room_ids(&self) -> Result<Vec<RoomId>, StoreError>
fn room_ids(&self) -> Result<Vec<RoomId>, StoreError>
Source§fn pending_requests(&self) -> Result<Vec<PendingRequest>, StoreError>
fn pending_requests(&self) -> Result<Vec<PendingRequest>, StoreError>
Source§fn save_pending_request(
&mut self,
req: PendingRequest,
) -> Result<(), StoreError>
fn save_pending_request( &mut self, req: PendingRequest, ) -> Result<(), StoreError>
StateStore::delete_pending_request removes it).Source§fn delete_pending_request(&mut self, id: &RequestId) -> Result<(), StoreError>
fn delete_pending_request(&mut self, id: &RequestId) -> Result<(), StoreError>
id is not currently pending.Source§fn counters(&self) -> Result<Option<Counters>, StoreError>
fn counters(&self) -> Result<Option<Counters>, StoreError>
Counters, if this device has ever
minted a crate::ids::RequestId/crate::ids::TxnId before.
None only for a brand-new device — crate::core::MessengerCore::open
treats that the same as Counters::default().Source§fn save_counters(&mut self, counters: Counters) -> Result<(), StoreError>
fn save_counters(&mut self, counters: Counters) -> Result<(), StoreError>
counters, replacing any earlier value. Called every time
either sequence advances — see crate::core’s module doc for why
this write must land in the same flush batch as (or an earlier one
than) any request carrying the id it just minted.