1- use std:: sync:: Arc ;
1+ use std:: sync:: { Arc , Mutex } ;
22
33use async_trait:: async_trait;
44use ic_agent:: Identity ;
55use snafu:: prelude:: * ;
66
7+ use std:: collections:: HashMap ;
8+
79use crate :: {
810 fs:: lock:: { DirectoryStructureLock , LockError , PathsAccess } ,
911 identity:: {
@@ -70,7 +72,7 @@ impl PathsAccess for IdentityPaths {
7072 }
7173}
7274
73- #[ derive( Clone , Debug , PartialEq ) ]
75+ #[ derive( Clone , Debug , PartialEq , Eq , Hash ) ]
7476pub enum IdentitySelection {
7577 /// Current default
7678 Default ,
@@ -106,20 +108,40 @@ pub trait Load: Sync + Send {
106108pub type PasswordFunc = Box < dyn Fn ( ) -> Result < String , String > + Send + Sync > ;
107109
108110pub struct Loader {
109- pub dir : IdentityDirectories ,
110- pub password_func : PasswordFunc ,
111- pub telemetry_data : Arc < TelemetryData > ,
111+ dir : IdentityDirectories ,
112+ password_func : PasswordFunc ,
113+ telemetry_data : Arc < TelemetryData > ,
114+ cache : Mutex < HashMap < IdentitySelection , Arc < dyn Identity > > > ,
115+ }
116+
117+ impl Loader {
118+ pub fn new (
119+ dir : IdentityDirectories ,
120+ password_func : PasswordFunc ,
121+ telemetry_data : Arc < TelemetryData > ,
122+ ) -> Self {
123+ Self {
124+ dir,
125+ password_func,
126+ telemetry_data,
127+ cache : Mutex :: new ( HashMap :: new ( ) ) ,
128+ }
129+ }
112130}
113131
114132#[ async_trait]
115133impl Load for Loader {
116134 async fn load ( & self , id : IdentitySelection ) -> Result < Arc < dyn Identity > , LoadError > {
135+ if let Some ( cached) = self . cache . lock ( ) . unwrap ( ) . get ( & id) {
136+ return Ok ( Arc :: clone ( cached) ) ;
137+ }
138+
117139 let password_func = & self . password_func ;
118140 let telemetry_data = & self . telemetry_data ;
119- match id {
141+ let identity = match & id {
120142 IdentitySelection :: Default => {
121143 self . dir
122- . with_read ( async |dirs| {
144+ . with_read ( async |dirs| -> Result < _ , LoadIdentityInContextError > {
123145 let list = IdentityList :: load_from ( dirs) ?;
124146 let default_name = manifest:: IdentityDefaults :: load_from ( dirs) ?. default ;
125147 let identity = load_identity ( dirs, & list, & default_name, password_func) ?;
@@ -128,42 +150,42 @@ impl Load for Loader {
128150 }
129151 Ok ( identity)
130152 } )
131- . await ?
153+ . await ??
132154 }
133155
134156 IdentitySelection :: Anonymous => {
135157 telemetry_data. set_identity_type ( IdentityStorageType :: Anonymous ) ;
136158 self . dir
137- . with_read ( async |dirs| {
159+ . with_read ( async |dirs| -> Result < _ , LoadIdentityInContextError > {
138160 Ok ( load_identity (
139161 dirs,
140162 & IdentityList :: load_from ( dirs) ?,
141163 "anonymous" ,
142164 || unreachable ! ( ) ,
143165 ) ?)
144166 } )
145- . await ?
167+ . await ??
146168 }
147169
148170 IdentitySelection :: Named ( name) => {
149171 self . dir
150- . with_read ( async |dirs| {
172+ . with_read ( async |dirs| -> Result < _ , LoadIdentityInContextError > {
151173 let list = IdentityList :: load_from ( dirs) ?;
152- let identity = load_identity ( dirs, & list, & name, password_func) ?;
153- if let Some ( spec) = list. identities . get ( & name) {
174+ let identity = load_identity ( dirs, & list, name, password_func) ?;
175+ if let Some ( spec) = list. identities . get ( name) {
154176 telemetry_data. set_identity_type ( spec. into ( ) ) ;
155177 }
156178 Ok ( identity)
157179 } )
158- . await ?
180+ . await ??
159181 }
160- }
182+ } ;
183+
184+ self . cache . lock ( ) . unwrap ( ) . insert ( id, Arc :: clone ( & identity) ) ;
185+ Ok ( identity)
161186 }
162187}
163188
164- #[ cfg( test) ]
165- use std:: collections:: HashMap ;
166-
167189#[ cfg( test) ]
168190pub struct MockIdentityLoader {
169191 /// The default identity to return when IdentitySelection::Default is used
0 commit comments