Skip to main content

OperatorSessionStore

Trait OperatorSessionStore 

Source
pub trait OperatorSessionStore: Send + Sync {
    // Required methods
    fn name(&self) -> &str;
    fn put<'life0, 'async_trait>(
        &'life0 self,
        record: OperatorSessionRecord,
    ) -> Pin<Box<dyn Future<Output = Result<(), OperatorSessionStoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait;
    fn delete<'life0, 'life1, 'async_trait>(
        &'life0 self,
        sid: &'life1 SessionId,
    ) -> Pin<Box<dyn Future<Output = Result<(), OperatorSessionStoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;
    fn list<'life0, 'async_trait>(
        &'life0 self,
    ) -> Pin<Box<dyn Future<Output = Result<Vec<OperatorSessionRecord>, OperatorSessionStoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait;
}
Expand description

Persistence interface for Operator login-flow sessions.

Write-through contract on the server side: POST /v1/operators calls put before answering the mint, teardown (DELETE /v1/operators/:sid) calls delete, and a fresh boot calls list once to rehydrate its in-memory session map.

Required Methods§

Source

fn name(&self) -> &str

Backend name — for diagnostics/logging.

Source

fn put<'life0, 'async_trait>( &'life0 self, record: OperatorSessionRecord, ) -> Pin<Box<dyn Future<Output = Result<(), OperatorSessionStoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Insert or replace the row for record.sid. Upsert semantics: sids are freshly minted so a same-sid overwrite only happens on a deliberate re-put of the same session.

Source

fn delete<'life0, 'life1, 'async_trait>( &'life0 self, sid: &'life1 SessionId, ) -> Pin<Box<dyn Future<Output = Result<(), OperatorSessionStoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Delete the row for sid. NotFound when no such row exists.

Source

fn list<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<Vec<OperatorSessionRecord>, OperatorSessionStoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

List the sessions this store can decode, ascending by joined_at_secs (mint order, stable for deterministic rehydration).

§Contract: per row, not all-or-nothing

A backend that decodes at-rest bytes back into OperatorSessionRecord must not let one undecodable row fail the whole call. Such a row is skipped and reported with a tracing::warn! naming the row and the field that failed; the intact rows are still returned. An Err from this method therefore means the backend failed (the file is unreadable, the connection is gone) — never that one stored session went bad.

This matters because the sole caller is boot-time rehydration, and its own error path is fatal: an Err here takes mse serve down and every healthy session with it. Undecodable rows are reachable in practice — an older build could persist shapes a newer one rejects (sid: "op-<uuid>" predates the S-<hex> shape) — so all-or-nothing decoding means one stale row bricks the boot.

Skipping the row rather than defaulting the field is deliberate: a session restored minus a field it was minted with would come back claiming something other than what it is, and would fail later, elsewhere, and quietly. Dropping it is the observable choice.

§Backends that never decode

InMemoryOperatorSessionStore holds live OperatorSessionRecords, so no row of its can be undecodable and it never skips anything. That is consistent with the contract, not an exemption from it: “the sessions this store can decode” is every session it holds.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§