Skip to content

Commit 8fbe448

Browse files
Cache loaded identities
1 parent 26f31b6 commit 8fbe448

File tree

2 files changed

+44
-22
lines changed

2 files changed

+44
-22
lines changed

crates/icp/src/context/init.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,11 @@ pub fn initialize(
8787
let telemetry_data = Arc::new(crate::telemetry_data::TelemetryData::default());
8888

8989
// Identity loader
90-
let idload = Arc::new(identity::Loader {
91-
dir: dirs.identity().context(IdentityDirectorySnafu)?,
90+
let idload = Arc::new(identity::Loader::new(
91+
dirs.identity().context(IdentityDirectorySnafu)?,
9292
password_func,
93-
telemetry_data: telemetry_data.clone(),
94-
});
93+
telemetry_data.clone(),
94+
));
9595
if let Ok(mockdir) = std::env::var("ICP_CLI_KEYRING_MOCK_DIR") {
9696
keyring::set_default_credential_builder(Box::new(
9797
crate::identity::keyring_mock::MockKeyring {

crates/icp/src/identity/mod.rs

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
use std::sync::Arc;
1+
use std::sync::{Arc, Mutex};
22

33
use async_trait::async_trait;
44
use ic_agent::Identity;
55
use snafu::prelude::*;
66

7+
use std::collections::HashMap;
8+
79
use 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)]
7476
pub enum IdentitySelection {
7577
/// Current default
7678
Default,
@@ -106,20 +108,40 @@ pub trait Load: Sync + Send {
106108
pub type PasswordFunc = Box<dyn Fn() -> Result<String, String> + Send + Sync>;
107109

108110
pub 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]
115133
impl 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)]
168190
pub struct MockIdentityLoader {
169191
/// The default identity to return when IdentitySelection::Default is used

0 commit comments

Comments
 (0)