Skip to main content

blockchain_client/
client.rs

1use serde::{Deserialize, Serialize};
2use std::time::Duration;
3
4#[derive(Debug, Clone)]
5pub struct RpcConfig {
6    pub url: String,
7    pub username: String,
8    pub password: String,
9    pub timeout_secs: u64,
10    pub pool_max_idle_per_host: usize,
11    pub pool_idle_timeout_secs: u64,
12    pub tcp_keepalive_secs: u64,
13}
14
15impl RpcConfig {
16    pub fn new(url: String, username: String, password: String) -> Self {
17        Self {
18            url,
19            username,
20            password,
21            timeout_secs: 30,
22            pool_max_idle_per_host: 4,
23            pool_idle_timeout_secs: 300,
24            tcp_keepalive_secs: 60,
25        }
26    }
27
28    pub fn with_timeout(mut self, timeout_secs: u64) -> Self {
29        self.timeout_secs = timeout_secs;
30        self
31    }
32
33    pub fn with_pool_max_idle_per_host(mut self, pool_max_idle_per_host: usize) -> Self {
34        self.pool_max_idle_per_host = pool_max_idle_per_host.max(1);
35        self
36    }
37
38    pub fn with_pool_idle_timeout(mut self, pool_idle_timeout_secs: u64) -> Self {
39        self.pool_idle_timeout_secs = pool_idle_timeout_secs;
40        self
41    }
42
43    pub fn with_tcp_keepalive(mut self, tcp_keepalive_secs: u64) -> Self {
44        self.tcp_keepalive_secs = tcp_keepalive_secs;
45        self
46    }
47
48    pub fn with_connection_pool(
49        mut self,
50        pool_max_idle_per_host: usize,
51        pool_idle_timeout_secs: u64,
52        tcp_keepalive_secs: u64,
53    ) -> Self {
54        self.pool_max_idle_per_host = pool_max_idle_per_host.max(1);
55        self.pool_idle_timeout_secs = pool_idle_timeout_secs;
56        self.tcp_keepalive_secs = tcp_keepalive_secs;
57        self
58    }
59
60    pub fn timeout(&self) -> Duration {
61        Duration::from_secs(self.timeout_secs)
62    }
63
64    pub fn pool_idle_timeout(&self) -> Duration {
65        Duration::from_secs(self.pool_idle_timeout_secs)
66    }
67
68    pub fn tcp_keepalive(&self) -> Duration {
69        Duration::from_secs(self.tcp_keepalive_secs)
70    }
71}
72
73#[derive(Debug, Serialize)]
74pub struct JsonRpcRequest {
75    pub jsonrpc: String,
76    pub id: String,
77    pub method: String,
78    pub params: serde_json::Value,
79}
80
81impl JsonRpcRequest {
82    pub fn new(method: String, params: serde_json::Value) -> Self {
83        Self {
84            jsonrpc: "1.0".to_string(),
85            id: "blockchain-client".to_string(),
86            method,
87            params,
88        }
89    }
90}
91
92#[derive(Debug, Deserialize)]
93pub struct JsonRpcResponse<T> {
94    pub result: Option<T>,
95    pub error: Option<JsonRpcError>,
96    pub id: String,
97}
98
99#[derive(Debug, Deserialize)]
100pub struct JsonRpcError {
101    pub code: i32,
102    pub message: String,
103}
104
105#[cfg(test)]
106mod tests {
107    use super::RpcConfig;
108    use std::time::Duration;
109
110    #[test]
111    fn rpc_config_uses_pooling_defaults() {
112        let config = RpcConfig::new(
113            "http://localhost:9332".to_string(),
114            "user".to_string(),
115            "pass".to_string(),
116        );
117
118        assert_eq!(config.timeout(), Duration::from_secs(30));
119        assert_eq!(config.pool_max_idle_per_host, 4);
120        assert_eq!(config.pool_idle_timeout(), Duration::from_secs(300));
121        assert_eq!(config.tcp_keepalive(), Duration::from_secs(60));
122    }
123
124    #[test]
125    fn rpc_config_allows_pooling_overrides() {
126        let config = RpcConfig::new(
127            "http://localhost:9332".to_string(),
128            "user".to_string(),
129            "pass".to_string(),
130        )
131        .with_connection_pool(8, 600, 120)
132        .with_timeout(45);
133
134        assert_eq!(config.timeout(), Duration::from_secs(45));
135        assert_eq!(config.pool_max_idle_per_host, 8);
136        assert_eq!(config.pool_idle_timeout(), Duration::from_secs(600));
137        assert_eq!(config.tcp_keepalive(), Duration::from_secs(120));
138    }
139}