1#![cfg_attr(not(test), warn(unused_crate_dependencies))]
36#![cfg_attr(docsrs, feature(doc_cfg))]
37
38#[cfg(test)]
39mod tests;
40
41pub use http::{HeaderMap, HeaderValue};
42pub use jsonrpsee_core::client::Client as WsClient;
43pub use jsonrpsee_core::client::async_client::PingConfig;
44pub use jsonrpsee_core::client::async_client::RpcService;
45pub use jsonrpsee_core::middleware::RpcServiceBuilder;
46use jsonrpsee_core::middleware::layer::RpcLoggerLayer;
47pub use jsonrpsee_types as types;
48
49use jsonrpsee_client_transport::ws::{AsyncRead, AsyncWrite, WsTransportClientBuilder};
50use jsonrpsee_core::TEN_MB_SIZE_BYTES;
51use jsonrpsee_core::client::{ClientBuilder, Error, IdKind, MaybeSend, TransportReceiverT, TransportSenderT};
52use std::time::Duration;
53use url::Url;
54
55type Logger = tower::layer::util::Stack<RpcLoggerLayer, tower::layer::util::Identity>;
56
57#[cfg(feature = "tls")]
58pub use jsonrpsee_client_transport::ws::CustomCertStore;
59
60#[cfg(feature = "tls")]
61use jsonrpsee_client_transport::ws::CertificateStore;
62
63#[derive(Clone, Debug)]
89pub struct WsClientBuilder<RpcMiddleware = Logger> {
90 #[cfg(feature = "tls")]
91 certificate_store: CertificateStore,
92 max_request_size: u32,
93 max_response_size: u32,
94 max_frame_size: Option<u32>,
95 request_timeout: Duration,
96 connection_timeout: Duration,
97 ping_config: Option<PingConfig>,
98 headers: http::HeaderMap,
99 max_concurrent_requests: usize,
100 max_buffer_capacity_per_subscription: usize,
101 max_redirections: usize,
102 id_kind: IdKind,
103 tcp_no_delay: bool,
104 service_builder: RpcServiceBuilder<RpcMiddleware>,
105}
106
107impl Default for WsClientBuilder {
108 fn default() -> Self {
109 Self {
110 #[cfg(feature = "tls")]
111 certificate_store: CertificateStore::Native,
112 max_request_size: TEN_MB_SIZE_BYTES,
113 max_response_size: TEN_MB_SIZE_BYTES,
114 max_frame_size: None,
115 request_timeout: Duration::from_secs(60),
116 connection_timeout: Duration::from_secs(10),
117 ping_config: None,
118 headers: HeaderMap::new(),
119 max_concurrent_requests: 256,
120 max_buffer_capacity_per_subscription: 1024,
121 max_redirections: 5,
122 id_kind: IdKind::Number,
123 tcp_no_delay: true,
124 service_builder: RpcServiceBuilder::default().rpc_logger(1024),
125 }
126 }
127}
128
129impl WsClientBuilder {
130 pub fn new() -> WsClientBuilder {
132 WsClientBuilder::default()
133 }
134}
135
136impl<RpcMiddleware> WsClientBuilder<RpcMiddleware> {
137 #[cfg(feature = "tls")]
200 pub fn with_custom_cert_store(mut self, cfg: CustomCertStore) -> Self {
201 self.certificate_store = CertificateStore::Custom(cfg);
202 self
203 }
204
205 pub fn max_request_size(mut self, size: u32) -> Self {
207 self.max_request_size = size;
208 self
209 }
210
211 pub fn max_response_size(mut self, size: u32) -> Self {
213 self.max_response_size = size;
214 self
215 }
216
217 pub fn max_frame_size(mut self, size: u32) -> Self {
219 self.max_frame_size = Some(size);
220 self
221 }
222
223 pub fn request_timeout(mut self, timeout: Duration) -> Self {
225 self.request_timeout = timeout;
226 self
227 }
228
229 pub fn connection_timeout(mut self, timeout: Duration) -> Self {
231 self.connection_timeout = timeout;
232 self
233 }
234
235 pub fn enable_ws_ping(mut self, cfg: PingConfig) -> Self {
237 self.ping_config = Some(cfg);
238 self
239 }
240
241 pub fn disable_ws_ping(mut self) -> Self {
243 self.ping_config = None;
244 self
245 }
246
247 pub fn set_headers(mut self, headers: http::HeaderMap) -> Self {
249 self.headers = headers;
250 self
251 }
252
253 pub fn max_concurrent_requests(mut self, max: usize) -> Self {
255 self.max_concurrent_requests = max;
256 self
257 }
258
259 pub fn max_buffer_capacity_per_subscription(mut self, max: usize) -> Self {
261 self.max_buffer_capacity_per_subscription = max;
262 self
263 }
264
265 pub fn max_redirections(mut self, redirect: usize) -> Self {
267 self.max_redirections = redirect;
268 self
269 }
270
271 pub fn id_format(mut self, kind: IdKind) -> Self {
273 self.id_kind = kind;
274 self
275 }
276
277 pub fn set_tcp_no_delay(mut self, no_delay: bool) -> Self {
279 self.tcp_no_delay = no_delay;
280 self
281 }
282
283 pub fn set_rpc_middleware<T>(self, service_builder: RpcServiceBuilder<T>) -> WsClientBuilder<T> {
285 WsClientBuilder {
286 #[cfg(feature = "tls")]
287 certificate_store: self.certificate_store,
288 max_request_size: self.max_request_size,
289 max_response_size: self.max_response_size,
290 max_frame_size: self.max_frame_size,
291 request_timeout: self.request_timeout,
292 connection_timeout: self.connection_timeout,
293 ping_config: self.ping_config,
294 headers: self.headers,
295 max_concurrent_requests: self.max_concurrent_requests,
296 max_buffer_capacity_per_subscription: self.max_buffer_capacity_per_subscription,
297 max_redirections: self.max_redirections,
298 id_kind: self.id_kind,
299 tcp_no_delay: self.tcp_no_delay,
300 service_builder,
301 }
302 }
303
304 pub fn build_with_transport<S, R, Svc>(self, sender: S, receiver: R) -> WsClient<Svc>
310 where
311 S: TransportSenderT + Send,
312 R: TransportReceiverT + Send,
313 RpcMiddleware: tower::Layer<RpcService, Service = Svc> + Clone + Send + Sync + 'static,
314 {
315 let Self {
316 max_concurrent_requests,
317 request_timeout,
318 ping_config,
319 max_buffer_capacity_per_subscription,
320 id_kind,
321 tcp_no_delay,
322 service_builder,
323 ..
324 } = self;
325
326 let mut client = ClientBuilder::default()
327 .max_buffer_capacity_per_subscription(max_buffer_capacity_per_subscription)
328 .request_timeout(request_timeout)
329 .max_concurrent_requests(max_concurrent_requests)
330 .id_format(id_kind)
331 .set_tcp_no_delay(tcp_no_delay)
332 .set_rpc_middleware(service_builder);
333
334 if let Some(cfg) = ping_config {
335 client = client.enable_ws_ping(cfg);
336 }
337
338 client.build_with_tokio(sender, receiver)
339 }
340
341 pub async fn build_with_stream<S, T>(self, url: impl AsRef<str>, data_stream: T) -> Result<WsClient<S>, Error>
347 where
348 T: AsyncRead + AsyncWrite + Unpin + MaybeSend + 'static,
349 RpcMiddleware: tower::Layer<RpcService, Service = S> + Clone + Send + Sync + 'static,
350 {
351 let transport_builder = WsTransportClientBuilder {
352 #[cfg(feature = "tls")]
353 certificate_store: self.certificate_store.clone(),
354 connection_timeout: self.connection_timeout,
355 headers: self.headers.clone(),
356 max_request_size: self.max_request_size,
357 max_response_size: self.max_response_size,
358 max_frame_size: self.max_frame_size,
359 max_redirections: self.max_redirections,
360 tcp_no_delay: self.tcp_no_delay,
361 };
362
363 let uri = Url::parse(url.as_ref()).map_err(|e| Error::Transport(e.into()))?;
364 let (sender, receiver) =
365 transport_builder.build_with_stream(uri, data_stream).await.map_err(|e| Error::Transport(e.into()))?;
366
367 let ws_client = self.build_with_transport(sender, receiver);
368 Ok(ws_client)
369 }
370
371 pub async fn build<S>(self, url: impl AsRef<str>) -> Result<WsClient<S>, Error>
378 where
379 RpcMiddleware: tower::Layer<RpcService, Service = S> + Clone + Send + Sync + 'static,
380 {
381 let transport_builder = WsTransportClientBuilder {
382 #[cfg(feature = "tls")]
383 certificate_store: self.certificate_store.clone(),
384 connection_timeout: self.connection_timeout,
385 headers: self.headers.clone(),
386 max_request_size: self.max_request_size,
387 max_response_size: self.max_response_size,
388 max_frame_size: self.max_frame_size,
389 max_redirections: self.max_redirections,
390 tcp_no_delay: self.tcp_no_delay,
391 };
392
393 let uri = Url::parse(url.as_ref()).map_err(|e| Error::Transport(e.into()))?;
394 let (sender, receiver) = transport_builder.build(uri).await.map_err(|e| Error::Transport(e.into()))?;
395
396 let ws_client = self.build_with_transport(sender, receiver);
397 Ok(ws_client)
398 }
399}