v0.2.7-pre.002

This commit is contained in:
2026-08-22 16:39:13 +02:00
parent cf4b28df2b
commit b64a799c85
11 changed files with 1491 additions and 29 deletions

View 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;