layer_climb_core/
cache.rs

1use anyhow::Result;
2use layer_climb_config::ChainConfig;
3use std::{
4    collections::HashMap,
5    sync::{Arc, Mutex},
6};
7
8use crate::network::rpc::{RpcClient, RpcTransport};
9
10/// This cache is on the QueryClient and can be used
11/// to either pre-populate the cache with resources created on the outside
12/// or reuse them between climb clients
13///
14/// however, the clients themselves hold onto their resoruces
15/// so a cache is _not_ needed if you're just cloning clients around
16#[derive(Clone)]
17pub struct ClimbCache {
18    #[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
19    grpc: Arc<Mutex<HashMap<String, tonic_web_wasm_client::Client>>>,
20    #[cfg(all(target_arch = "wasm32", not(target_os = "unknown")))]
21    #[allow(dead_code)]
22    grpc: Arc<Mutex<HashMap<String, crate::network::grpc_wasi::Client>>>,
23    #[cfg(not(target_arch = "wasm32"))]
24    grpc: Arc<Mutex<HashMap<String, tonic::transport::Channel>>>,
25    rpc: Arc<Mutex<HashMap<String, RpcClient>>>,
26    rpc_transport: Arc<dyn RpcTransport>,
27}
28
29impl ClimbCache {
30    pub fn new(rpc_transport: Arc<dyn RpcTransport>) -> Self {
31        Self {
32            grpc: Arc::new(Mutex::new(HashMap::new())),
33            rpc: Arc::new(Mutex::new(HashMap::new())),
34            rpc_transport,
35        }
36    }
37}
38
39impl ClimbCache {
40    pub fn get_rpc_client(&self, config: &ChainConfig) -> Option<RpcClient> {
41        match config.rpc_endpoint.as_ref() {
42            None => None,
43            Some(endpoint) => {
44                let rpc = { self.rpc.lock().unwrap().get(endpoint).cloned() };
45
46                Some(match rpc {
47                    Some(rpc) => rpc,
48                    None => {
49                        let rpc = RpcClient::new(endpoint.to_string(), self.rpc_transport.clone());
50                        self.rpc
51                            .lock()
52                            .unwrap()
53                            .insert(endpoint.to_string(), rpc.clone());
54                        rpc
55                    }
56                })
57            }
58        }
59    }
60}
61cfg_if::cfg_if! {
62    if #[cfg(all(target_arch = "wasm32", target_os = "unknown"))] {
63        impl ClimbCache {
64            pub async fn get_web_grpc(&self, chain_config: &ChainConfig) -> Result<Option<tonic_web_wasm_client::Client>> {
65                let endpoint = match chain_config.grpc_web_endpoint.as_ref() {
66                    Some(endpoint) => endpoint.to_string(),
67                    None => match chain_config.grpc_endpoint.as_ref() {
68                        Some(endpoint) => endpoint.to_string(),
69                        None => return Ok(None),
70                    }
71                };
72
73
74                let grpc = {
75                    self.grpc.lock().unwrap().get(&endpoint).cloned()
76                };
77
78                Ok(Some(match grpc {
79                    Some(grpc) => grpc,
80                    None => {
81                        let grpc = crate::network::grpc_web::make_grpc_client(endpoint.clone()).await?;
82                        self.grpc.lock().unwrap().insert(endpoint, grpc.clone());
83                        grpc
84                    }
85                }))
86            }
87        }
88    } else if #[cfg(target_arch = "wasm32")] {
89        impl ClimbCache {
90            pub async fn get_wasi_grpc(&self, _chain_config: &ChainConfig) -> Result<Option<crate::network::grpc_wasi::Client>> {
91                unimplemented!();
92            }
93        }
94    } else {
95        impl ClimbCache {
96            pub async fn get_grpc(&self, chain_config: &ChainConfig) -> Result<Option<tonic::transport::Channel>> {
97                match chain_config.grpc_endpoint.as_ref() {
98                    None => Ok(None),
99                    Some(endpoint) => {
100                        let grpc = {
101                            self.grpc.lock().unwrap().get(endpoint).cloned()
102                        };
103
104                        Ok(Some(match grpc {
105                            Some(grpc) => grpc,
106                            None => {
107                                tracing::debug!("Creating new grpc channel for {}", endpoint);
108                                let grpc = crate::network::grpc_native::make_grpc_channel(endpoint).await?;
109                                self.grpc.lock().unwrap().insert(endpoint.to_string(), grpc.clone());
110                                grpc
111                            }
112                        }))
113                    }
114                }
115            }
116        }
117    }
118}