openzeppelin_monitor/services/blockchain/transports/midnight/ws.rs
1//! Midnight transport implementation for blockchain interactions.
2//!
3//! This module provides a client implementation for interacting with Midnight-compatible nodes
4//! by wrapping the WsTransportClient. This allows for consistent behavior with other
5//! transport implementations while providing specific Midnight-focused functionality.
6
7use reqwest_middleware::ClientWithMiddleware;
8use serde::Serialize;
9use serde_json::Value;
10
11use crate::{
12 models::Network,
13 services::blockchain::{
14 transports::{BlockchainTransport, RotatingTransport, WsTransportClient},
15 TransportError, WsConfig,
16 },
17};
18
19/// A client for interacting with Midnight-compatible blockchain nodes via WebSocket
20///
21/// This implementation wraps the WsTransportClient to provide consistent
22/// behavior with other transport implementations while offering Midnight-specific
23/// functionality. It handles WebSocket connection management, message handling,
24/// and endpoint rotation for Midnight-based networks.
25#[derive(Clone, Debug)]
26pub struct MidnightTransportClient {
27 /// The underlying WebSocket transport client that handles actual RPC communications
28 ws_client: WsTransportClient,
29}
30
31impl MidnightTransportClient {
32 /// Creates a new Midnight transport client by initializing a WebSocket transport client
33 ///
34 /// # Arguments
35 /// * `network` - Network configuration containing RPC URLs and other network details
36 ///
37 /// # Returns
38 /// * `Result<Self, anyhow::Error>` - A new client instance or connection error
39 pub async fn new(network: &Network, config: Option<WsConfig>) -> Result<Self, anyhow::Error> {
40 let ws_client = WsTransportClient::new(network, config).await?;
41 Ok(Self { ws_client })
42 }
43}
44
45#[async_trait::async_trait]
46impl BlockchainTransport for MidnightTransportClient {
47 /// Gets the current active RPC URL
48 ///
49 /// # Returns
50 /// * `String` - The currently active RPC endpoint URL
51 async fn get_current_url(&self) -> String {
52 self.ws_client.get_current_url().await
53 }
54
55 /// Sends a raw JSON-RPC request to the Midnight node via WebSocket
56 ///
57 /// # Arguments
58 /// * `method` - The JSON-RPC method to call
59 /// * `params` - Optional parameters to pass with the request
60 ///
61 /// # Returns
62 /// * `Result<Value, TransportError>` - The JSON response or error
63 async fn send_raw_request<P>(
64 &self,
65 method: &str,
66 params: Option<P>,
67 ) -> Result<Value, TransportError>
68 where
69 P: Into<Value> + Send + Clone + Serialize,
70 {
71 self.ws_client.send_raw_request(method, params).await
72 }
73
74 /// Update endpoint manager with a new client
75 ///
76 /// Note: Not applicable for WebSocket transport
77 fn update_endpoint_manager_client(
78 &mut self,
79 _client: ClientWithMiddleware,
80 ) -> Result<(), anyhow::Error> {
81 Err(anyhow::anyhow!(
82 "`update_endpoint_manager_client` not implemented for WebSocket transport"
83 ))
84 }
85}
86
87#[async_trait::async_trait]
88impl RotatingTransport for MidnightTransportClient {
89 /// Tests connection to a specific WebSocket URL
90 ///
91 /// # Arguments
92 /// * `url` - The WebSocket URL to test connection with
93 ///
94 /// # Returns
95 /// * `Result<(), anyhow::Error>` - Success or error status
96 async fn try_connect(&self, url: &str) -> Result<(), anyhow::Error> {
97 self.ws_client.try_connect(url).await
98 }
99
100 /// Updates the client to use a new WebSocket URL
101 ///
102 /// # Arguments
103 /// * `url` - The new WebSocket URL to use for subsequent requests
104 ///
105 /// # Returns
106 /// * `Result<(), anyhow::Error>` - Success or error status
107 async fn update_client(&self, url: &str) -> Result<(), anyhow::Error> {
108 self.ws_client.update_client(url).await
109 }
110}