0.7.27 +Refactor

This commit is contained in:
2026-05-10 00:33:01 +02:00
parent cb2e8e7096
commit 1f0137b9de
261 changed files with 12308 additions and 8928 deletions

View File

@@ -10,7 +10,7 @@
/// Typed Solana PubSub notification payload.
#[derive(Clone, Debug)]
pub enum KbSolanaWsTypedNotification {
pub enum SolanaWsTypedNotification {
/// `accountNotification`
Account(solana_rpc_client_api::response::Response<solana_rpc_client_api::response::UiAccount>),
/// `blockNotification`
@@ -40,16 +40,16 @@ pub enum KbSolanaWsTypedNotification {
}
/// Parses a Solana JSON-RPC notification into an official typed payload.
pub fn parse_kb_solana_ws_typed_notification(
notification: &crate::KbJsonRpcWsNotification,
) -> Result<KbSolanaWsTypedNotification, crate::KbError> {
pub fn parse_solana_ws_typed_notification(
notification: &crate::JsonRpcWsNotification,
) -> Result<SolanaWsTypedNotification, crate::Error> {
if notification.method == "accountNotification" {
let parse_result = serde_json::from_value::<
solana_rpc_client_api::response::Response<solana_rpc_client_api::response::UiAccount>,
>(notification.params.result.clone());
return match parse_result {
Ok(value) => Ok(KbSolanaWsTypedNotification::Account(value)),
Err(error) => Err(crate::KbError::Json(format!(
Ok(value) => Ok(SolanaWsTypedNotification::Account(value)),
Err(error) => Err(crate::Error::Json(format!(
"cannot parse accountNotification payload: {error}"
))),
};
@@ -59,10 +59,10 @@ pub fn parse_kb_solana_ws_typed_notification(
notification.params.result.clone(),
);
return match parse_result {
Ok(value) => Ok(KbSolanaWsTypedNotification::Block(value)),
Err(error) => Err(crate::KbError::Json(format!(
"cannot parse blockNotification payload: {error}"
))),
Ok(value) => Ok(SolanaWsTypedNotification::Block(value)),
Err(error) => {
Err(crate::Error::Json(format!("cannot parse blockNotification payload: {error}")))
},
};
}
if notification.method == "logsNotification" {
@@ -72,9 +72,9 @@ pub fn parse_kb_solana_ws_typed_notification(
>,
>(notification.params.result.clone());
return match parse_result {
Ok(value) => Ok(KbSolanaWsTypedNotification::Logs(value)),
Ok(value) => Ok(SolanaWsTypedNotification::Logs(value)),
Err(error) => {
Err(crate::KbError::Json(format!("cannot parse logsNotification payload: {error}")))
Err(crate::Error::Json(format!("cannot parse logsNotification payload: {error}")))
},
};
}
@@ -85,8 +85,8 @@ pub fn parse_kb_solana_ws_typed_notification(
>,
>(notification.params.result.clone());
return match parse_result {
Ok(value) => Ok(KbSolanaWsTypedNotification::Program(value)),
Err(error) => Err(crate::KbError::Json(format!(
Ok(value) => Ok(SolanaWsTypedNotification::Program(value)),
Err(error) => Err(crate::Error::Json(format!(
"cannot parse programNotification payload: {error}"
))),
};
@@ -94,8 +94,8 @@ pub fn parse_kb_solana_ws_typed_notification(
if notification.method == "rootNotification" {
let root_option = notification.params.result.as_u64();
return match root_option {
Some(root) => Ok(KbSolanaWsTypedNotification::Root(root)),
None => Err(crate::KbError::Json(
Some(root) => Ok(SolanaWsTypedNotification::Root(root)),
None => Err(crate::Error::Json(
"cannot parse rootNotification payload: result is not a u64".to_string(),
)),
};
@@ -107,8 +107,8 @@ pub fn parse_kb_solana_ws_typed_notification(
>,
>(notification.params.result.clone());
return match parse_result {
Ok(value) => Ok(KbSolanaWsTypedNotification::Signature(value)),
Err(error) => Err(crate::KbError::Json(format!(
Ok(value) => Ok(SolanaWsTypedNotification::Signature(value)),
Err(error) => Err(crate::Error::Json(format!(
"cannot parse signatureNotification payload: {error}"
))),
};
@@ -118,9 +118,9 @@ pub fn parse_kb_solana_ws_typed_notification(
notification.params.result.clone(),
);
return match parse_result {
Ok(value) => Ok(KbSolanaWsTypedNotification::Slot(value)),
Ok(value) => Ok(SolanaWsTypedNotification::Slot(value)),
Err(error) => {
Err(crate::KbError::Json(format!("cannot parse slotNotification payload: {error}")))
Err(crate::Error::Json(format!("cannot parse slotNotification payload: {error}")))
},
};
}
@@ -129,8 +129,8 @@ pub fn parse_kb_solana_ws_typed_notification(
notification.params.result.clone(),
);
return match parse_result {
Ok(value) => Ok(KbSolanaWsTypedNotification::SlotsUpdates(value)),
Err(error) => Err(crate::KbError::Json(format!(
Ok(value) => Ok(SolanaWsTypedNotification::SlotsUpdates(value)),
Err(error) => Err(crate::Error::Json(format!(
"cannot parse slotsUpdatesNotification payload: {error}"
))),
};
@@ -140,13 +140,13 @@ pub fn parse_kb_solana_ws_typed_notification(
notification.params.result.clone(),
);
return match parse_result {
Ok(value) => Ok(KbSolanaWsTypedNotification::Vote(value)),
Ok(value) => Ok(SolanaWsTypedNotification::Vote(value)),
Err(error) => {
Err(crate::KbError::Json(format!("cannot parse voteNotification payload: {error}")))
Err(crate::Error::Json(format!("cannot parse voteNotification payload: {error}")))
},
};
}
return Err(crate::KbError::Json(format!(
return Err(crate::Error::Json(format!(
"unsupported Solana websocket notification method '{}'",
notification.method
)));
@@ -158,34 +158,34 @@ pub fn parse_kb_solana_ws_typed_notification(
/// - `Ok(Some(...))` for JSON-RPC notification-bearing events
/// - `Ok(None)` for events that do not carry a notification
/// - `Err(...)` when a notification is present but cannot be decoded
pub fn parse_kb_solana_ws_typed_notification_from_event(
pub fn parse_solana_ws_typed_notification_from_event(
event: &crate::WsEvent,
) -> Result<std::option::Option<KbSolanaWsTypedNotification>, crate::KbError> {
) -> Result<std::option::Option<SolanaWsTypedNotification>, crate::Error> {
match event {
crate::WsEvent::SubscriptionNotification { notification, .. } => {
let parse_result = parse_kb_solana_ws_typed_notification(notification);
let parse_result = parse_solana_ws_typed_notification(notification);
match parse_result {
Ok(value) => return Ok(Some(value)),
Err(error) => return Err(error),
}
},
crate::WsEvent::JsonRpcNotificationWithoutSubscription { notification, .. } => {
let parse_result = parse_kb_solana_ws_typed_notification(notification);
let parse_result = parse_solana_ws_typed_notification(notification);
match parse_result {
Ok(value) => return Ok(Some(value)),
Err(error) => return Err(error),
}
},
crate::WsEvent::JsonRpcMessage { message, .. } => match message {
crate::KbJsonRpcWsIncomingMessage::Notification(notification) => {
let parse_result = parse_kb_solana_ws_typed_notification(notification);
crate::JsonRpcWsIncomingMessage::Notification(notification) => {
let parse_result = parse_solana_ws_typed_notification(notification);
match parse_result {
Ok(value) => return Ok(Some(value)),
Err(error) => return Err(error),
}
},
crate::KbJsonRpcWsIncomingMessage::SuccessResponse(_) => return Ok(None),
crate::KbJsonRpcWsIncomingMessage::ErrorResponse(_) => return Ok(None),
crate::JsonRpcWsIncomingMessage::SuccessResponse(_) => return Ok(None),
crate::JsonRpcWsIncomingMessage::ErrorResponse(_) => return Ok(None),
},
_ => return Ok(None),
}
@@ -197,9 +197,9 @@ impl crate::WsClient {
&self,
pubkey: std::string::String,
config: std::option::Option<solana_rpc_client_api::config::RpcAccountInfoConfig>,
) -> Result<u64, crate::KbError> {
) -> Result<u64, crate::Error> {
let config_value_result =
kb_serialize_optional_config_value(config, "accountSubscribe config");
serialize_optional_config_value(config, "accountSubscribe config");
let config_value = match config_value_result {
Ok(config_value) => config_value,
Err(error) => return Err(error),
@@ -212,14 +212,13 @@ impl crate::WsClient {
&self,
filter: solana_rpc_client_api::config::RpcBlockSubscribeFilter,
config: std::option::Option<solana_rpc_client_api::config::RpcBlockSubscribeConfig>,
) -> Result<u64, crate::KbError> {
let filter_value_result = kb_serialize_required_value(filter, "blockSubscribe filter");
) -> Result<u64, crate::Error> {
let filter_value_result = serialize_required_value(filter, "blockSubscribe filter");
let filter_value = match filter_value_result {
Ok(filter_value) => filter_value,
Err(error) => return Err(error),
};
let config_value_result =
kb_serialize_optional_config_value(config, "blockSubscribe config");
let config_value_result = serialize_optional_config_value(config, "blockSubscribe config");
let config_value = match config_value_result {
Ok(config_value) => config_value,
Err(error) => return Err(error),
@@ -232,14 +231,13 @@ impl crate::WsClient {
&self,
filter: solana_rpc_client_api::config::RpcTransactionLogsFilter,
config: std::option::Option<solana_rpc_client_api::config::RpcTransactionLogsConfig>,
) -> Result<u64, crate::KbError> {
let filter_value_result = kb_serialize_required_value(filter, "logsSubscribe filter");
) -> Result<u64, crate::Error> {
let filter_value_result = serialize_required_value(filter, "logsSubscribe filter");
let filter_value = match filter_value_result {
Ok(filter_value) => filter_value,
Err(error) => return Err(error),
};
let config_value_result =
kb_serialize_optional_config_value(config, "logsSubscribe config");
let config_value_result = serialize_optional_config_value(config, "logsSubscribe config");
let config_value = match config_value_result {
Ok(config_value) => config_value,
Err(error) => return Err(error),
@@ -252,9 +250,9 @@ impl crate::WsClient {
&self,
program_id: std::string::String,
config: std::option::Option<solana_rpc_client_api::config::RpcProgramAccountsConfig>,
) -> Result<u64, crate::KbError> {
) -> Result<u64, crate::Error> {
let config_value_result =
kb_serialize_optional_config_value(config, "programSubscribe config");
serialize_optional_config_value(config, "programSubscribe config");
let config_value = match config_value_result {
Ok(config_value) => config_value,
Err(error) => return Err(error),
@@ -267,9 +265,9 @@ impl crate::WsClient {
&self,
signature: std::string::String,
config: std::option::Option<solana_rpc_client_api::config::RpcSignatureSubscribeConfig>,
) -> Result<u64, crate::KbError> {
) -> Result<u64, crate::Error> {
let config_value_result =
kb_serialize_optional_config_value(config, "signatureSubscribe config");
serialize_optional_config_value(config, "signatureSubscribe config");
let config_value = match config_value_result {
Ok(config_value) => config_value,
Err(error) => return Err(error),
@@ -278,10 +276,7 @@ impl crate::WsClient {
}
}
fn kb_serialize_required_value<T>(
value: T,
label: &str,
) -> Result<serde_json::Value, crate::KbError>
fn serialize_required_value<T>(value: T, label: &str) -> Result<serde_json::Value, crate::Error>
where
T: serde::Serialize,
{
@@ -289,15 +284,15 @@ where
match value_result {
Ok(value) => return Ok(value),
Err(error) => {
return Err(crate::KbError::Json(format!("cannot serialize {}: {error}", label)));
return Err(crate::Error::Json(format!("cannot serialize {}: {error}", label)));
},
}
}
fn kb_serialize_optional_config_value<T>(
fn serialize_optional_config_value<T>(
value: std::option::Option<T>,
label: &str,
) -> Result<std::option::Option<serde_json::Value>, crate::KbError>
) -> Result<std::option::Option<serde_json::Value>, crate::Error>
where
T: serde::Serialize,
{
@@ -307,10 +302,7 @@ where
match value_result {
Ok(value) => return Ok(Some(value)),
Err(error) => {
return Err(crate::KbError::Json(format!(
"cannot serialize {}: {error}",
label
)));
return Err(crate::Error::Json(format!("cannot serialize {}: {error}", label)));
},
}
},
@@ -321,7 +313,7 @@ where
#[cfg(test)]
mod tests {
fn make_test_ws_client() -> crate::WsClient {
let endpoint = crate::KbWsEndpointConfig {
let endpoint = crate::WsEndpointConfig {
name: "test_ws".to_string(),
enabled: true,
provider: "test".to_string(),
@@ -341,18 +333,18 @@ mod tests {
#[test]
fn parse_root_notification_works() {
let notification = crate::KbJsonRpcWsNotification {
let notification = crate::JsonRpcWsNotification {
jsonrpc: "2.0".to_string(),
method: "rootNotification".to_string(),
params: crate::KbJsonRpcWsNotificationParams {
params: crate::JsonRpcWsNotificationParams {
result: serde_json::Value::from(123u64),
subscription: 7,
},
};
let parsed = crate::parse_kb_solana_ws_typed_notification(&notification)
let parsed = crate::parse_solana_ws_typed_notification(&notification)
.expect("typed root notification parse must succeed");
match parsed {
crate::KbSolanaWsTypedNotification::Root(root) => {
crate::SolanaWsTypedNotification::Root(root) => {
assert_eq!(root, 123);
},
other => {
@@ -363,10 +355,10 @@ mod tests {
#[test]
fn parse_slot_notification_works() {
let notification = crate::KbJsonRpcWsNotification {
let notification = crate::JsonRpcWsNotification {
jsonrpc: "2.0".to_string(),
method: "slotNotification".to_string(),
params: crate::KbJsonRpcWsNotificationParams {
params: crate::JsonRpcWsNotificationParams {
result: serde_json::json!({
"parent": 10,
"root": 11,
@@ -376,10 +368,10 @@ mod tests {
},
};
let parsed = crate::parse_kb_solana_ws_typed_notification(&notification)
let parsed = crate::parse_solana_ws_typed_notification(&notification)
.expect("typed slot notification parse must succeed");
match parsed {
crate::KbSolanaWsTypedNotification::Slot(slot_info) => {
crate::SolanaWsTypedNotification::Slot(slot_info) => {
assert_eq!(slot_info.parent, 10);
assert_eq!(slot_info.root, 11);
assert_eq!(slot_info.slot, 12);
@@ -393,11 +385,10 @@ mod tests {
#[tokio::test]
async fn account_subscribe_typed_uses_same_send_path() {
let client = make_test_ws_client();
let result = client
.account_subscribe_typed("11111111111111111111111111111111".to_string(), None)
.await;
let result =
client.account_subscribe_typed(crate::SYSTEM_PROGRAM_ID.to_string(), None).await;
match result {
Err(crate::KbError::NotConnected(_)) => {},
Err(crate::Error::NotConnected(_)) => {},
other => {
panic!("unexpected result: {other:?}");
},
@@ -414,7 +405,7 @@ mod tests {
)
.await;
match result {
Err(crate::KbError::NotConnected(_)) => {},
Err(crate::Error::NotConnected(_)) => {},
other => {
panic!("unexpected result: {other:?}");
},