v0.2.7-pre.002
This commit is contained in:
281
crates/ksp-onchain-transport-lib/src/ws_lifecycle.rs
Normal file
281
crates/ksp-onchain-transport-lib/src/ws_lifecycle.rs
Normal file
@@ -0,0 +1,281 @@
|
||||
// file: crates/ksp-onchain-transport-lib/src/ws_lifecycle.rs
|
||||
// version: 1
|
||||
|
||||
/// Stable local identity assigned to one physical WebSocket session.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub struct WsSessionId(std::num::NonZeroU64);
|
||||
|
||||
impl WsSessionId {
|
||||
/// Creates a session identity from a non-zero local value.
|
||||
#[must_use]
|
||||
pub const fn new(value: std::num::NonZeroU64) -> Self {
|
||||
return Self(value);
|
||||
}
|
||||
|
||||
/// Returns the stable local numeric value.
|
||||
#[must_use]
|
||||
pub const fn get(self) -> u64 {
|
||||
return self.0.get();
|
||||
}
|
||||
}
|
||||
|
||||
/// Stable local identity assigned to one logical WebSocket subscription.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub struct WsSubscriptionId(std::num::NonZeroU64);
|
||||
|
||||
impl WsSubscriptionId {
|
||||
/// Creates a subscription identity from a non-zero local value.
|
||||
#[must_use]
|
||||
pub const fn new(value: std::num::NonZeroU64) -> Self {
|
||||
return Self(value);
|
||||
}
|
||||
|
||||
/// Returns the stable local numeric value.
|
||||
#[must_use]
|
||||
pub const fn get(self) -> u64 {
|
||||
return self.0.get();
|
||||
}
|
||||
}
|
||||
|
||||
/// Observable lifecycle state of one physical WebSocket session.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum WsSessionState {
|
||||
/// No physical connection is currently active and no connection attempt is running.
|
||||
Disconnected,
|
||||
/// The actor is establishing the physical connection.
|
||||
Connecting,
|
||||
/// The physical connection is active.
|
||||
Active,
|
||||
/// The actor is reconnecting after an unexpected physical disconnect.
|
||||
Reconnecting {
|
||||
/// One-based reconnect attempt currently in progress or waiting for backoff.
|
||||
attempt: u32,
|
||||
},
|
||||
/// Explicit shutdown has started and new subscriptions are refused.
|
||||
Closing,
|
||||
/// Explicit shutdown completed.
|
||||
Closed,
|
||||
/// The session reached a terminal failure state.
|
||||
Failed,
|
||||
}
|
||||
|
||||
/// Observable lifecycle state of one logical WebSocket subscription.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum WsSubscriptionState {
|
||||
/// The local subscription exists but its initial subscribe request has not completed.
|
||||
Requested,
|
||||
/// The logical subscription is bound to an active remote subscription.
|
||||
Active,
|
||||
/// The logical subscription is being restored after reconnect.
|
||||
Resubscribing,
|
||||
/// Local cancellation has won and remote cleanup is in progress when possible.
|
||||
Cancelling,
|
||||
/// The logical subscription reached a non-error terminal state.
|
||||
Closed,
|
||||
/// The logical subscription reached a terminal failure state.
|
||||
Failed,
|
||||
}
|
||||
|
||||
/// Standard Solana subscription family represented by one logical WebSocket subscription.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
#[non_exhaustive]
|
||||
pub enum WsSubscriptionKind {
|
||||
/// `accountSubscribe` family.
|
||||
Account,
|
||||
/// `blockSubscribe` family.
|
||||
Block,
|
||||
/// `logsSubscribe` family.
|
||||
Logs,
|
||||
/// `programSubscribe` family.
|
||||
Program,
|
||||
/// `rootSubscribe` family.
|
||||
Root,
|
||||
/// `signatureSubscribe` family.
|
||||
Signature,
|
||||
/// `slotSubscribe` family.
|
||||
Slot,
|
||||
/// `slotsUpdatesSubscribe` family.
|
||||
SlotsUpdates,
|
||||
/// `voteSubscribe` family.
|
||||
Vote,
|
||||
}
|
||||
|
||||
impl WsSubscriptionKind {
|
||||
/// Returns the stable KSP descriptor for this standard subscription family.
|
||||
#[must_use]
|
||||
pub const fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::Account => "account",
|
||||
Self::Block => "block",
|
||||
Self::Logs => "logs",
|
||||
Self::Program => "program",
|
||||
Self::Root => "root",
|
||||
Self::Signature => "signature",
|
||||
Self::Slot => "slot",
|
||||
Self::SlotsUpdates => "slots_updates",
|
||||
Self::Vote => "vote",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Safe lifecycle projection for one logical WebSocket subscription.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct WsSubscriptionSnapshot {
|
||||
id: crate::WsSubscriptionId,
|
||||
kind: crate::WsSubscriptionKind,
|
||||
state: crate::WsSubscriptionState,
|
||||
remote_bound: bool,
|
||||
}
|
||||
|
||||
impl WsSubscriptionSnapshot {
|
||||
/// Creates one safe subscription lifecycle projection for Transport runtime internals.
|
||||
#[must_use]
|
||||
pub(crate) const fn new(id: crate::WsSubscriptionId, kind: crate::WsSubscriptionKind, state: crate::WsSubscriptionState, remote_bound: bool) -> Self {
|
||||
return Self { id, kind, state, remote_bound };
|
||||
}
|
||||
|
||||
/// Returns the stable local subscription identity.
|
||||
#[must_use]
|
||||
pub const fn id(&self) -> crate::WsSubscriptionId {
|
||||
return self.id;
|
||||
}
|
||||
|
||||
/// Returns the standard subscription family.
|
||||
#[must_use]
|
||||
pub const fn kind(&self) -> crate::WsSubscriptionKind {
|
||||
return self.kind;
|
||||
}
|
||||
|
||||
/// Returns the current logical lifecycle state.
|
||||
#[must_use]
|
||||
pub const fn state(&self) -> crate::WsSubscriptionState {
|
||||
return self.state;
|
||||
}
|
||||
|
||||
/// Returns whether a current remote subscription ID is bound internally.
|
||||
///
|
||||
/// The remote ID itself is deliberately absent because it is ephemeral across reconnects.
|
||||
#[must_use]
|
||||
pub const fn remote_bound(&self) -> bool {
|
||||
return self.remote_bound;
|
||||
}
|
||||
}
|
||||
|
||||
/// Safe runtime snapshot for one physical WebSocket session.
|
||||
///
|
||||
/// The snapshot deliberately contains logical endpoint metadata and local identities only. It never stores the endpoint URL, credentials, request payloads or
|
||||
/// raw notifications.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct WsSessionSnapshot {
|
||||
id: crate::WsSessionId,
|
||||
endpoint_name: std::string::String,
|
||||
provider: crate::WsProviderName,
|
||||
cluster: crate::WsClusterName,
|
||||
protocol: crate::WsProtocolKind,
|
||||
state: crate::WsSessionState,
|
||||
pending_request_count: usize,
|
||||
continuity_gap_count: u64,
|
||||
overflow_count: u64,
|
||||
subscriptions: std::vec::Vec<crate::WsSubscriptionSnapshot>,
|
||||
}
|
||||
|
||||
impl WsSessionSnapshot {
|
||||
/// Creates one safe session projection for Transport runtime internals.
|
||||
#[must_use]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn new(
|
||||
id: crate::WsSessionId,
|
||||
endpoint_name: impl std::convert::Into<std::string::String>,
|
||||
provider: crate::WsProviderName,
|
||||
cluster: crate::WsClusterName,
|
||||
protocol: crate::WsProtocolKind,
|
||||
state: crate::WsSessionState,
|
||||
pending_request_count: usize,
|
||||
continuity_gap_count: u64,
|
||||
overflow_count: u64,
|
||||
subscriptions: std::vec::Vec<crate::WsSubscriptionSnapshot>,
|
||||
) -> Self {
|
||||
return Self {
|
||||
id,
|
||||
endpoint_name: endpoint_name.into(),
|
||||
provider,
|
||||
cluster,
|
||||
protocol,
|
||||
state,
|
||||
pending_request_count,
|
||||
continuity_gap_count,
|
||||
overflow_count,
|
||||
subscriptions,
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns the stable local session identity.
|
||||
#[must_use]
|
||||
pub const fn id(&self) -> crate::WsSessionId {
|
||||
return self.id;
|
||||
}
|
||||
|
||||
/// Returns the safe logical endpoint name.
|
||||
#[must_use]
|
||||
pub fn endpoint_name(&self) -> &str {
|
||||
return self.endpoint_name.as_str();
|
||||
}
|
||||
|
||||
/// Returns the provider descriptor without endpoint credentials.
|
||||
#[must_use]
|
||||
pub const fn provider(&self) -> &crate::WsProviderName {
|
||||
return &self.provider;
|
||||
}
|
||||
|
||||
/// Returns the cluster descriptor.
|
||||
#[must_use]
|
||||
pub const fn cluster(&self) -> &crate::WsClusterName {
|
||||
return &self.cluster;
|
||||
}
|
||||
|
||||
/// Returns the WebSocket protocol family.
|
||||
#[must_use]
|
||||
pub const fn protocol(&self) -> crate::WsProtocolKind {
|
||||
return self.protocol;
|
||||
}
|
||||
|
||||
/// Returns the current physical session lifecycle state.
|
||||
#[must_use]
|
||||
pub const fn state(&self) -> crate::WsSessionState {
|
||||
return self.state;
|
||||
}
|
||||
|
||||
/// Returns the number of JSON-RPC requests currently awaiting responses.
|
||||
#[must_use]
|
||||
pub const fn pending_request_count(&self) -> usize {
|
||||
return self.pending_request_count;
|
||||
}
|
||||
|
||||
/// Returns the number of observed physical continuity gaps for this session.
|
||||
#[must_use]
|
||||
pub const fn continuity_gap_count(&self) -> u64 {
|
||||
return self.continuity_gap_count;
|
||||
}
|
||||
|
||||
/// Returns the cumulative number of notification queue overflows observed by this session.
|
||||
#[must_use]
|
||||
pub const fn overflow_count(&self) -> u64 {
|
||||
return self.overflow_count;
|
||||
}
|
||||
|
||||
/// Returns safe lifecycle projections for logical subscriptions owned by this session.
|
||||
#[must_use]
|
||||
pub fn subscriptions(&self) -> &[crate::WsSubscriptionSnapshot] {
|
||||
return self.subscriptions.as_slice();
|
||||
}
|
||||
|
||||
/// Returns the number of logical subscriptions currently projected by the session.
|
||||
#[must_use]
|
||||
pub fn subscription_count(&self) -> usize {
|
||||
return self.subscriptions.len();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "../unit_tests/ws_lifecycle.rs"]
|
||||
mod tests;
|
||||
Reference in New Issue
Block a user