1- use std:: collections:: HashMap ;
1+ use std:: {
2+ collections:: HashMap ,
3+ sync:: { Arc , Mutex } ,
4+ } ;
25
36use crate :: {
47 client:: LedgerClient ,
@@ -28,7 +31,7 @@ impl Default for LedgerMode {
2831#[ derive( Debug ) ]
2932pub enum LedgerResult {
3033 /// A fully initialized LedgerClient
31- Client ( LedgerClient ) ,
34+ Client ( Arc < LedgerClient > ) ,
3235 /// A configuration-only LedgerClientConfig
3336 Config ( LedgerClientConfig ) ,
3437}
@@ -67,6 +70,8 @@ pub struct LedgerRouter {
6770 configs : HashMap < String , LedgerClientConfig > ,
6871 default_network : String ,
6972 mode : LedgerMode ,
73+ // cache thread-safe
74+ clients : Arc < Mutex < HashMap < String , Arc < LedgerClient > > > > ,
7075}
7176
7277impl LedgerRouter {
@@ -88,6 +93,7 @@ impl LedgerRouter {
8893 configs,
8994 default_network : default_network. unwrap_or ( DEFAULT_NETWORK ) . to_string ( ) ,
9095 mode : mode. unwrap_or_default ( ) ,
96+ clients : Arc :: new ( Mutex :: new ( HashMap :: new ( ) ) ) ,
9197 }
9298 }
9399
@@ -101,10 +107,15 @@ impl LedgerRouter {
101107 pub fn get_ledger_for_identifier ( & self , identifier : & str ) -> VdrResult < LedgerResult > {
102108 let network = Self :: extract_network ( identifier) ?;
103109
104- let config = self
110+ let ( resolved_network , config) = self
105111 . configs
106112 . get ( & network)
107- . or_else ( || self . configs . get ( & self . default_network ) )
113+ . map ( |c| ( network. clone ( ) , c) )
114+ . or_else ( || {
115+ self . configs
116+ . get ( & self . default_network )
117+ . map ( |c| ( self . default_network . clone ( ) , c) )
118+ } )
108119 . ok_or_else ( || {
109120 VdrError :: RouterConfigError ( format ! (
110121 "Ledger for network '{}' not configured and no default network defined" ,
@@ -114,13 +125,23 @@ impl LedgerRouter {
114125
115126 match self . mode {
116127 LedgerMode :: LedgerClient => {
117- let client = LedgerClient :: new (
128+ // cache lookup
129+ let mut cache = self . clients . lock ( ) . unwrap ( ) ;
130+
131+ if let Some ( client) = cache. get ( & resolved_network) . cloned ( ) {
132+ return Ok ( LedgerResult :: Client ( client) ) ;
133+ }
134+
135+ let client = Arc :: new ( LedgerClient :: new (
118136 config. chain_id ,
119137 & config. rpc_node ,
120138 & config. contract_configs ,
121139 config. network . as_deref ( ) ,
122140 config. quorum_config . as_ref ( ) ,
123- ) ?;
141+ ) ?) ;
142+
143+ cache. insert ( resolved_network. clone ( ) , client. clone ( ) ) ;
144+
124145 Ok ( LedgerResult :: Client ( client) )
125146 }
126147 LedgerMode :: ConfigOnly => Ok ( LedgerResult :: Config ( config. clone ( ) ) ) ,
@@ -151,14 +172,20 @@ impl LedgerRouter {
151172 ) ) ) ;
152173 }
153174
154- match parts. len ( ) {
155- 3 => Ok ( DEFAULT_NETWORK . to_string ( ) ) ,
156- n if n >= 4 => Ok ( parts[ 2 ] . to_string ( ) ) ,
157- _ => Err ( VdrError :: RouterConfigError ( format ! (
158- "Invalid did:ethr format: {}" ,
159- identifier
160- ) ) ) ,
175+ if parts. len ( ) == 3 {
176+ return Ok ( DEFAULT_NETWORK . to_string ( ) ) ;
161177 }
178+
179+ if parts. len ( ) >= 4 {
180+ return parts. get ( 2 ) . map ( |s| s. to_string ( ) ) . ok_or_else ( || {
181+ VdrError :: RouterConfigError ( format ! ( "Invalid did:ethr format: {}" , identifier) )
182+ } ) ;
183+ }
184+
185+ Err ( VdrError :: RouterConfigError ( format ! (
186+ "Invalid did:ethr format: {}" ,
187+ identifier
188+ ) ) )
162189 }
163190
164191 /// Submits a transaction to a ledger based on its identifier
@@ -194,16 +221,14 @@ impl LedgerRouter {
194221 }
195222
196223 let mut results = HashMap :: new ( ) ;
197- for ( network, config) in self . configs . iter ( ) {
198- let client = LedgerClient :: new (
199- config. chain_id ,
200- & config. rpc_node ,
201- & config. contract_configs ,
202- config. network . as_deref ( ) ,
203- config. quorum_config . as_ref ( ) ,
204- ) ?;
205- let ping_status = client. ping ( ) . await ?;
206- results. insert ( network. clone ( ) , ping_status) ;
224+ for ( network, _) in self . configs . iter ( ) {
225+ match self . get_ledger_for_identifier ( & format ! ( "did:ethr:{}:0x0" , network) ) ? {
226+ LedgerResult :: Client ( client) => {
227+ let ping_status = client. ping ( ) . await ?;
228+ results. insert ( network. clone ( ) , ping_status) ;
229+ }
230+ _ => { }
231+ }
207232 }
208233 Ok ( results)
209234 }
@@ -304,4 +329,10 @@ mod tests {
304329 LedgerResult :: Config ( _) => panic ! ( "Expected LedgerResult::Client, got Config" ) ,
305330 }
306331 }
332+
333+ #[ test]
334+ fn test_invalid_did_format ( ) {
335+ let err = LedgerRouter :: extract_network ( "invalid" ) . unwrap_err ( ) ;
336+ assert ! ( matches!( err, VdrError :: RouterConfigError ( _) ) ) ;
337+ }
307338}
0 commit comments