Skip to content

Commit 76d23e5

Browse files
committed
feat: multi account user data support
1 parent 9219a4a commit 76d23e5

File tree

5 files changed

+768
-4
lines changed

5 files changed

+768
-4
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ant-cli/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ criterion = "0.5.1"
5858
eyre = "0.6.8"
5959
rand = { version = "~0.8.5", features = ["small_rng"] }
6060
rayon = "1.8.0"
61+
serial_test = "3.0"
6162
tempfile = "3.6.0"
6263

6364
[lints]

ant-cli/src/access/data_dir.rs

Lines changed: 88 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,107 @@
66
// KIND, either express or implied. Please review the Licences for the specific language governing
77
// permissions and limitations relating to use of the SAFE Network Software.
88

9+
use autonomi::Wallet;
910
use color_eyre::{
1011
Section,
1112
eyre::{Context, Result, eyre},
1213
};
1314
use std::path::PathBuf;
15+
use thiserror::Error;
1416

15-
pub fn get_client_data_dir_path() -> Result<PathBuf> {
17+
#[derive(Debug, Clone, Error)]
18+
pub enum DataDirError {
19+
#[error(
20+
"Multiple accounts found: {0:?}. Please specify which account to use or provide the SECRET_KEY for the account you want to use"
21+
)]
22+
MultipleAccounts(Vec<String>),
23+
#[error(
24+
"No existing user data directories found. Please provide the SECRET_KEY for the account you want to use"
25+
)]
26+
NoExistingUserDirFound,
27+
}
28+
29+
/// Get the base client data directory path
30+
pub(crate) fn get_client_data_dir_base() -> Result<PathBuf> {
1631
let mut home_dirs = dirs_next::data_dir()
1732
.ok_or_else(|| eyre!("Failed to obtain data dir, your OS might not be supported."))?;
1833
home_dirs.push("autonomi");
1934
home_dirs.push("client");
20-
std::fs::create_dir_all(home_dirs.as_path())
35+
Ok(home_dirs)
36+
}
37+
38+
/// Get the client data directory path
39+
/// Automatically detects the wallet directory to use:
40+
/// - If only one wallet directory exists, uses it
41+
/// - If multiple wallet directories exist, try to get wallet from environment else returns error
42+
/// - If no wallet directories exist, tries to get wallet from environment else returns error
43+
pub fn get_client_data_dir_path() -> Result<PathBuf> {
44+
let base_dir = get_client_data_dir_base()?;
45+
46+
// Check if there are any existing accounts user data directories
47+
let existing_users = get_existing_user_dirs()?;
48+
49+
let wallet_addr = match &existing_users[..] {
50+
// Exactly one account exists, use it
51+
[one] => one.clone(),
52+
// No accounts exist yet, try to get address from current environment
53+
// First try from SECRET_KEY env var
54+
[] => match get_wallet_pk() {
55+
Ok(pk) => pk,
56+
Err(_) => return Err(DataDirError::NoExistingUserDirFound.into()),
57+
},
58+
// Multiple wallets exist, try SECRET_KEY env var else return error
59+
[_, ..] => match get_wallet_pk() {
60+
Ok(pk) => pk,
61+
Err(_) => return Err(DataDirError::MultipleAccounts(existing_users).into()),
62+
},
63+
};
64+
65+
// Migrate legacy data if needed (user data stored directly under client/ without wallet address)
66+
super::data_dir_migration::migrate_legacy_data_if_needed(&wallet_addr)?;
67+
68+
// Create the wallet directory
69+
let mut wallet_dir = base_dir;
70+
wallet_dir.push(&wallet_addr);
71+
std::fs::create_dir_all(wallet_dir.as_path())
2172
.wrap_err("Failed to create data dir")
2273
.with_suggestion(|| {
2374
format!(
24-
"make sure you have the correct permissions to access the data dir: {home_dirs:?}"
75+
"make sure you have the correct permissions to access the data dir: {wallet_dir:?}"
2576
)
2677
})?;
27-
Ok(home_dirs)
78+
79+
Ok(wallet_dir)
80+
}
81+
82+
/// Get existing wallet directories under the client data dir
83+
fn get_existing_user_dirs() -> Result<Vec<String>> {
84+
let base_dir = get_client_data_dir_base()?;
85+
86+
if !base_dir.exists() {
87+
return Ok(Vec::new());
88+
}
89+
90+
let mut wallet_dirs = Vec::new();
91+
92+
if let Ok(entries) = std::fs::read_dir(&base_dir) {
93+
for entry in entries.flatten() {
94+
if entry.path().is_dir() {
95+
let dir_name = entry.file_name().to_string_lossy().to_string();
96+
// Check if it looks like a wallet address (starts with 0x and has the right length)
97+
if dir_name.starts_with("0x") && dir_name.len() == 42 {
98+
wallet_dirs.push(dir_name);
99+
}
100+
}
101+
}
102+
}
103+
104+
Ok(wallet_dirs)
105+
}
106+
107+
fn get_wallet_pk() -> Result<String> {
108+
let secret_key = crate::wallet::load_wallet_private_key()?;
109+
let wallet = Wallet::new_from_private_key(crate::wallet::DUMMY_NETWORK, &secret_key)
110+
.map_err(|_| eyre!("Invalid SECRET_KEY provided"))?;
111+
Ok(wallet.address().to_string())
28112
}

0 commit comments

Comments
 (0)