v0.2.7-pre.008
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-onchain-transport-lib/src/ws_subscription.rs
|
||||
// version: 2
|
||||
// version: 3
|
||||
|
||||
/// Typed handle for one logical Solana WebSocket subscription.
|
||||
///
|
||||
@@ -11,6 +11,7 @@ pub struct WsSubscription<T> {
|
||||
kind: crate::WsSubscriptionKind,
|
||||
notification_rx: tokio::sync::mpsc::Receiver<ksp_core_lib::Result<T>>,
|
||||
state_rx: tokio::sync::watch::Receiver<crate::WsSubscriptionState>,
|
||||
terminal_error_rx: tokio::sync::watch::Receiver<std::option::Option<ksp_core_lib::ErrorCode>>,
|
||||
command_tx: tokio::sync::mpsc::Sender<crate::WsSessionCommand>,
|
||||
command_timeout: std::time::Duration,
|
||||
}
|
||||
@@ -30,6 +31,7 @@ impl<T> WsSubscription<T> {
|
||||
kind: registration.kind,
|
||||
notification_rx,
|
||||
state_rx: registration.state_rx,
|
||||
terminal_error_rx: registration.terminal_error_rx,
|
||||
command_tx,
|
||||
command_timeout,
|
||||
};
|
||||
@@ -53,6 +55,14 @@ impl<T> WsSubscription<T> {
|
||||
return *self.state_rx.borrow();
|
||||
}
|
||||
|
||||
/// Returns the safe terminal error code when this logical subscription failed.
|
||||
///
|
||||
/// Successful local cancellation and normal completion use `None`. The value never contains remote payloads or endpoint credentials.
|
||||
#[must_use]
|
||||
pub fn terminal_error_code(&self) -> std::option::Option<ksp_core_lib::ErrorCode> {
|
||||
return *self.terminal_error_rx.borrow();
|
||||
}
|
||||
|
||||
/// Receives the next typed notification or terminal typed-decoding error.
|
||||
///
|
||||
/// The underlying queue is bounded by `WsSessionSettings::notification_queue_capacity`. `None` means the actor closed this logical subscription and no
|
||||
@@ -116,7 +126,7 @@ pub(crate) enum WsNotificationDispatchOutcome {
|
||||
Delivered,
|
||||
ReceiverClosed,
|
||||
QueueFull,
|
||||
DecodeFailed,
|
||||
DecodeFailed { code: ksp_core_lib::ErrorCode },
|
||||
}
|
||||
|
||||
/// Type-erased actor-owned dispatcher for one heterogeneous typed notification channel.
|
||||
@@ -130,16 +140,24 @@ where
|
||||
{
|
||||
let (notification_tx, notification_rx) = tokio::sync::mpsc::channel(capacity);
|
||||
let dispatcher = move |value: serde_json::Value| -> WsNotificationDispatchOutcome {
|
||||
let decoded = decoder(value);
|
||||
return match decoded {
|
||||
std::result::Result::Ok(notification) => match notification_tx.try_send(std::result::Result::Ok(notification)) {
|
||||
std::result::Result::Ok(()) => WsNotificationDispatchOutcome::Delivered,
|
||||
std::result::Result::Err(tokio::sync::mpsc::error::TrySendError::Closed(_)) => WsNotificationDispatchOutcome::ReceiverClosed,
|
||||
std::result::Result::Err(tokio::sync::mpsc::error::TrySendError::Full(_)) => WsNotificationDispatchOutcome::QueueFull,
|
||||
let permit = match notification_tx.try_reserve() {
|
||||
std::result::Result::Ok(permit) => permit,
|
||||
std::result::Result::Err(tokio::sync::mpsc::error::TrySendError::Closed(_)) => {
|
||||
return WsNotificationDispatchOutcome::ReceiverClosed;
|
||||
},
|
||||
std::result::Result::Err(tokio::sync::mpsc::error::TrySendError::Full(_)) => {
|
||||
return WsNotificationDispatchOutcome::QueueFull;
|
||||
},
|
||||
};
|
||||
return match decoder(value) {
|
||||
std::result::Result::Ok(notification) => {
|
||||
permit.send(std::result::Result::Ok(notification));
|
||||
WsNotificationDispatchOutcome::Delivered
|
||||
},
|
||||
std::result::Result::Err(error) => {
|
||||
let _ = notification_tx.try_send(std::result::Result::Err(error));
|
||||
WsNotificationDispatchOutcome::DecodeFailed
|
||||
let code = error.code();
|
||||
permit.send(std::result::Result::Err(error));
|
||||
WsNotificationDispatchOutcome::DecodeFailed { code }
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -151,6 +169,7 @@ pub(crate) struct WsSubscriptionRegistration {
|
||||
id: crate::WsSubscriptionId,
|
||||
kind: crate::WsSubscriptionKind,
|
||||
state_rx: tokio::sync::watch::Receiver<crate::WsSubscriptionState>,
|
||||
terminal_error_rx: tokio::sync::watch::Receiver<std::option::Option<ksp_core_lib::ErrorCode>>,
|
||||
}
|
||||
|
||||
impl WsSubscriptionRegistration {
|
||||
@@ -159,8 +178,9 @@ impl WsSubscriptionRegistration {
|
||||
id: crate::WsSubscriptionId,
|
||||
kind: crate::WsSubscriptionKind,
|
||||
state_rx: tokio::sync::watch::Receiver<crate::WsSubscriptionState>,
|
||||
terminal_error_rx: tokio::sync::watch::Receiver<std::option::Option<ksp_core_lib::ErrorCode>>,
|
||||
) -> Self {
|
||||
return Self { id, kind, state_rx };
|
||||
return Self { id, kind, state_rx, terminal_error_rx };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,6 +198,8 @@ pub(crate) struct WsSubscriptionRuntime {
|
||||
pub(crate) remote_id: std::option::Option<u64>,
|
||||
/// Lifecycle publisher observed by the public typed handle.
|
||||
pub(crate) state_tx: tokio::sync::watch::Sender<crate::WsSubscriptionState>,
|
||||
/// Safe terminal failure code publisher observed by the public typed handle.
|
||||
pub(crate) terminal_error_tx: tokio::sync::watch::Sender<std::option::Option<ksp_core_lib::ErrorCode>>,
|
||||
/// Type-erased dispatcher into the bounded typed notification channel.
|
||||
pub(crate) dispatcher: WsNotificationDispatcher,
|
||||
}
|
||||
@@ -185,7 +207,7 @@ pub(crate) struct WsSubscriptionRuntime {
|
||||
impl WsSubscriptionRuntime {
|
||||
/// Builds the safe session-snapshot projection for this runtime entry.
|
||||
pub(crate) fn snapshot(&self) -> crate::WsSubscriptionSnapshot {
|
||||
return crate::WsSubscriptionSnapshot::new(self.id, self.kind, self.state, self.remote_id.is_some());
|
||||
return crate::WsSubscriptionSnapshot::new(self.id, self.kind, self.state, self.remote_id.is_some(), *self.terminal_error_tx.borrow());
|
||||
}
|
||||
|
||||
/// Updates the runtime state and publishes it to the typed handle.
|
||||
@@ -193,6 +215,12 @@ impl WsSubscriptionRuntime {
|
||||
self.state = state;
|
||||
self.state_tx.send_replace(state);
|
||||
}
|
||||
|
||||
/// Publishes a terminal failure code before moving the logical subscription to `Failed`.
|
||||
pub(crate) fn fail_with_code(&mut self, code: ksp_core_lib::ErrorCode) {
|
||||
self.terminal_error_tx.send_replace(std::option::Option::Some(code));
|
||||
self.set_state(crate::WsSubscriptionState::Failed);
|
||||
}
|
||||
}
|
||||
|
||||
fn subscription_closed_error(session_id: crate::WsSessionId, subscription_id: crate::WsSubscriptionId, message: &'static str) -> ksp_core_lib::Error {
|
||||
|
||||
Reference in New Issue
Block a user