pub enum RefreshState {
Ready(Box<InventorySnapshot>),
RateLimited(RateLimited),
Unauthorized,
LockedOut {
retry_after: Duration,
},
Forbidden {
message: Option<String>,
},
Offline,
Failed {
status: Option<u16>,
message: String,
},
Cancelled,
}Expand description
One refresh’s outcome, as a value that can be stored, compared and rendered.
InventoryError cannot be any of those things — it owns a
reqwest::Error and a serde_json::Error, neither of which is Clone —
and the TUI needs a state it can hold in a snapshot and diff against the
previous frame. So the error is summarised into this enum exactly once, at
the gateway boundary, rather than each screen inventing its own summary.
g2’s Definition of Done names “loading, empty, unauthorized, rate-limited,
and offline states”; four of those are variants here, and “loading” and
“empty” are the caller’s (no state yet, and a Ready snapshot with nothing
in it).
Variants§
Ready(Box<InventorySnapshot>)
The refresh completed. Note that an empty snapshot is still Ready:
“this target has no runners” is an answer, and rendering it as a failure
is how an idle host looks broken.
RateLimited(RateLimited)
GitHub is rate limiting this credential.
The stored credential was rejected. Terminal until auth login.
LockedOut
GitHub’s temporary authentication lockout. The credential is fine.
Forbidden
A permissions answer. Re-authenticating will not change it.
Offline
GitHub could not be reached.
Failed
Anything else GitHub answered.
Cancelled
The caller withdrew the refresh.
Implementations§
Source§impl RefreshState
impl RefreshState
Sourcepub fn from_result(result: Result<InventorySnapshot, InventoryError>) -> Self
pub fn from_result(result: Result<InventorySnapshot, InventoryError>) -> Self
Summarise a completed refresh.
Sourcepub fn from_error(error: &InventoryError) -> Self
pub fn from_error(error: &InventoryError) -> Self
Summarise a failure without consuming it.
pub fn is_ready(&self) -> bool
pub fn snapshot(&self) -> Option<&InventorySnapshot>
Sourcepub fn retry_delay(&self, now: Timestamp) -> Option<Duration>
pub fn retry_delay(&self, now: Timestamp) -> Option<Duration>
How long to wait before trying again, or None when waiting is not what
this state needs.
04-subsystem-contracts.md: “Rate limiting increases the refresh delay
and is displayed, never hidden.” This is the increase. It is deliberately
None for RefreshState::Unauthorized and
RefreshState::Forbidden, which no amount of waiting fixes.
§An absolute floor, not an addend
The scheduling rule is next_attempt_at = now + retry_delay. It is not
the ordinary refresh interval plus this — adding the two would double
the wait for no benefit, because the gateway enforces the same window
itself: a request issued inside it is answered
InventoryError::RateLimited without a socket being opened
(RestInventory::rate_limit_backoff).
Trying too early is therefore cheap and self-correcting rather than
harmful. A suppressed request returns before RateLimited::detect is
ever reached, so an early attempt cannot ratchet the window outward by
this gateway’s own silence, and repeated attempts converge on the instant
GitHub named. What an addend buys is one wasted interval per limit; what
it costs is a dashboard that stays dark longer than GitHub asked for.
Note also that a RefreshState::RateLimited read back from
RestInventory::rate_limit_state carries the time remaining, not the
delay GitHub originally asked for — so this value shrinks as the window
elapses, which is another reason it reads as a deadline rather than as an
increment.
Trait Implementations§
Source§impl Clone for RefreshState
impl Clone for RefreshState
Source§fn clone(&self) -> RefreshState
fn clone(&self) -> RefreshState
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 RefreshState
impl Debug for RefreshState
Source§impl Display for RefreshState
impl Display for RefreshState
impl Eq for RefreshState
Source§impl PartialEq for RefreshState
impl PartialEq for RefreshState
impl StructuralPartialEq for RefreshState
Auto Trait Implementations§
impl Freeze for RefreshState
impl RefUnwindSafe for RefreshState
impl Send for RefreshState
impl Sync for RefreshState
impl Unpin for RefreshState
impl UnsafeUnpin for RefreshState
impl UnwindSafe for RefreshState
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<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.