Skip to content

Commit

Permalink
feat(cli): remove download-all default
Browse files Browse the repository at this point in the history
BREAKING CHANGE: focuses download behaviours through the  cmd, which handles syncing
and data management via account packet (local or live)
  • Loading branch information
joshuef committed Mar 29, 2024
1 parent fe9777f commit 3daf658
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 170 deletions.
166 changes: 68 additions & 98 deletions sn_cli/src/bin/subcommands/files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@
// KIND, either express or implied. Please review the Licences for the specific language governing
// permissions and limitations relating to use of the SAFE Network Software.

use autonomi::{
download_file, download_files, ChunkManager, Estimator, UploadedFile, UPLOADED_FILES,
};
use autonomi::{download_file, ChunkManager, Estimator, UploadedFile, UPLOADED_FILES};
use clap::Parser;
use color_eyre::{eyre::eyre, Help, Result};
use color_eyre::{eyre::eyre, Result};
use sn_client::protocol::storage::{Chunk, ChunkAddress, RetryStrategy};
use sn_client::{Client, FilesApi, BATCH_SIZE};
use std::{
Expand All @@ -37,14 +35,14 @@ pub enum FilesCmds {
///
/// If neither are, all the files uploaded by the current user will be downloaded again.
#[clap(name = "name")]
file_name: Option<OsString>,
file_name: OsString,
/// The hex address of a file.
///
/// If the address argument is used, the name argument must also be supplied.
///
/// If neither are, all the files uploaded by the current user will be downloaded again.
#[clap(name = "address")]
file_addr: Option<String>,
file_addr: String,
/// Flagging whether to show the holders of the uploaded chunks.
/// Default to be not showing.
#[clap(long, name = "show_holders", default_value = "false")]
Expand Down Expand Up @@ -81,107 +79,79 @@ pub(crate) async fn files_cmds(cmds: FilesCmds, client: &Client, root_dir: &Path
batch_size,
retry_strategy,
} => {
if (file_name.is_some() && file_addr.is_none())
|| (file_addr.is_some() && file_name.is_none())
{
return Err(
eyre!("Both the name and address must be supplied if either are used")
.suggestion(
"Please run the command again in the form 'files upload <name> <address>'",
),
);
}

let mut download_dir = root_dir.to_path_buf();
let mut download_file_name = file_name.clone();
if let Some(file_name) = file_name {
// file_name may direct the downloaded data to:
//
// the current directory (just a filename)
// eg safe files download myfile.txt ADDRESS
//
// a directory relative to the current directory (relative filename)
// eg safe files download my/relative/path/myfile.txt ADDRESS
//
// a directory relative to root of the filesystem (absolute filename)
// eg safe files download /home/me/mydir/myfile.txt ADDRESS
let file_name_path = Path::new(&file_name);
if file_name_path.is_dir() {
return Err(eyre!("Cannot download file to path: {:?}", file_name));
}
let file_name_dir = file_name_path.parent();
if file_name_dir.is_none() {
// just a filename, use the current_dir
download_dir = std::env::current_dir().unwrap_or(root_dir.to_path_buf());
} else if file_name_path.is_relative() {
// relative to the current directory. Make the relative path
// into an absolute path by joining it to current_dir
if let Some(relative_dir) = file_name_dir {
let current_dir = std::env::current_dir().unwrap_or(root_dir.to_path_buf());
download_dir = current_dir.join(relative_dir);
if !download_dir.exists() {
return Err(eyre!("Directory does not exist: {:?}", download_dir));
}
if let Some(path_file_name) = file_name_path.file_name() {
download_file_name = Some(OsString::from(path_file_name));
}
// file_name may direct the downloaded data to:
//
// the current directory (just a filename)
// eg safe files download myfile.txt ADDRESS
//
// a directory relative to the current directory (relative filename)
// eg safe files download my/relative/path/myfile.txt ADDRESS
//
// a directory relative to root of the filesystem (absolute filename)
// eg safe files download /home/me/mydir/myfile.txt ADDRESS
let file_name_path = Path::new(&file_name);
if file_name_path.is_dir() {
return Err(eyre!("Cannot download file to path: {:?}", file_name));
}
let file_name_dir = file_name_path.parent();
if file_name_dir.is_none() {
// just a filename, use the current_dir
download_dir = std::env::current_dir().unwrap_or(root_dir.to_path_buf());
} else if file_name_path.is_relative() {
// relative to the current directory. Make the relative path
// into an absolute path by joining it to current_dir
if let Some(relative_dir) = file_name_dir {
let current_dir = std::env::current_dir().unwrap_or(root_dir.to_path_buf());
download_dir = current_dir.join(relative_dir);
if !download_dir.exists() {
return Err(eyre!("Directory does not exist: {:?}", download_dir));
}
if let Some(path_file_name) = file_name_path.file_name() {
download_file_name = OsString::from(path_file_name);
}
} else {
// absolute dir
download_dir = file_name_dir.unwrap_or(root_dir).to_path_buf();
}
} else {
// absolute dir
download_dir = file_name_dir.unwrap_or(root_dir).to_path_buf();
}
let files_api: FilesApi = FilesApi::new(client.clone(), download_dir.clone());

match (download_file_name, file_addr) {
(Some(download_file_name), Some(address_provided)) => {
let bytes =
hex::decode(&address_provided).expect("Input address is not a hex string");
let xor_name_provided = XorName(
bytes
.try_into()
.expect("Failed to parse XorName from hex string"),
);
// try to read the data_map if it exists locally.
let uploaded_files_path = root_dir.join(UPLOADED_FILES);
let expected_data_map_location = uploaded_files_path.join(address_provided);
let local_data_map = {
if expected_data_map_location.exists() {
let uploaded_file_metadata =
UploadedFile::read(&expected_data_map_location)?;
let files_api: FilesApi = FilesApi::new(client.clone(), download_dir.clone());

uploaded_file_metadata.data_map.map(|bytes| Chunk {
address: ChunkAddress::new(xor_name_provided),
value: bytes,
})
} else {
None
}
};
let address_provided = file_addr;
let bytes = hex::decode(&address_provided).expect("Input address is not a hex string");
let xor_name_provided = XorName(
bytes
.try_into()
.expect("Failed to parse XorName from hex string"),
);
// try to read the data_map if it exists locally.
let uploaded_files_path = root_dir.join(UPLOADED_FILES);
let expected_data_map_location = uploaded_files_path.join(address_provided);
let local_data_map = {
if expected_data_map_location.exists() {
let uploaded_file_metadata = UploadedFile::read(&expected_data_map_location)?;

download_file(
files_api,
xor_name_provided,
(download_file_name, local_data_map),
&download_dir,
show_holders,
batch_size,
retry_strategy,
)
.await
}
_ => {
println!("Attempting to download all files uploaded by the current user...");
download_files(
&files_api,
root_dir,
show_holders,
batch_size,
retry_strategy,
)
.await?
uploaded_file_metadata.data_map.map(|bytes| Chunk {
address: ChunkAddress::new(xor_name_provided),
value: bytes,
})
} else {
None
}
}
};

download_file(
files_api,
xor_name_provided,
(download_file_name, local_data_map),
&download_dir,
show_holders,
batch_size,
retry_strategy,
)
.await
}
}
Ok(())
Expand Down
2 changes: 1 addition & 1 deletion sn_cli/src/files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ mod files_uploader;
mod upload;

pub use chunk_manager::ChunkManager;
pub use download::{download_file, download_files};
pub use download::download_file;
pub use estimate::Estimator;
pub use files_uploader::FilesUploader;
pub use upload::{UploadedFile, UPLOADED_FILES};
Expand Down
71 changes: 2 additions & 69 deletions sn_cli/src/files/download.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,86 +6,19 @@
// KIND, either express or implied. Please review the Licences for the specific language governing
// permissions and limitations relating to use of the SAFE Network Software.

use super::{
get_progress_bar,
upload::{UploadedFile, UPLOADED_FILES},
};
use super::get_progress_bar;

use std::collections::BTreeSet;
use std::ffi::OsString;
use std::path::Path;

use color_eyre::Result;
use indicatif::ProgressBar;
use walkdir::WalkDir;
use xor_name::XorName;

use sn_client::{
protocol::storage::{Chunk, ChunkAddress, RetryStrategy},
FilesApi, FilesDownload, FilesDownloadEvent,
};
use tracing::{debug, error, info};

/// The default folder to download files to.
const DOWNLOAD_FOLDER: &str = "safe_files";

pub async fn download_files(
files_api: &FilesApi,
root_dir: &Path,
show_holders: bool,
batch_size: usize,
retry_strategy: RetryStrategy,
) -> Result<()> {
info!("Downloading with batch size of {}", batch_size);
let uploaded_files_path = root_dir.join(UPLOADED_FILES);
let download_path = dirs_next::download_dir()
.unwrap_or(root_dir.to_path_buf())
.join(DOWNLOAD_FOLDER);
std::fs::create_dir_all(download_path.as_path())?;

#[allow(clippy::mutable_key_type)]
let mut uploaded_files = BTreeSet::new();

for entry in WalkDir::new(uploaded_files_path.clone()) {
let entry = entry?;
let path = entry.path();
if path.is_file() {
let hex_xorname = path
.file_name()
.expect("Uploaded file to have name")
.to_str()
.expect("Failed to convert path to string");
let bytes = hex::decode(hex_xorname)?;
let xor_name_bytes: [u8; 32] = bytes
.try_into()
.expect("Failed to parse XorName from hex string");
let xor_name = XorName(xor_name_bytes);
let address = ChunkAddress::new(xor_name);

let uploaded_file_metadata = UploadedFile::read(path)?;
let datamap_chunk = uploaded_file_metadata.data_map.map(|bytes| Chunk {
address,
value: bytes,
});
uploaded_files.insert((xor_name, (uploaded_file_metadata.filename, datamap_chunk)));
}
}

for (xorname, file_data) in uploaded_files.into_iter() {
download_file(
files_api.clone(),
xorname,
file_data,
&download_path,
show_holders,
batch_size,
retry_strategy,
)
.await;
}

Ok(())
}
use tracing::{debug, error};

pub async fn download_file(
files_api: FilesApi,
Expand Down
3 changes: 1 addition & 2 deletions sn_cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,5 @@ mod files;

pub use acc_packet::AccountPacket;
pub use files::{
download_file, download_files, ChunkManager, Estimator, FilesUploader, UploadedFile,
UPLOADED_FILES,
download_file, ChunkManager, Estimator, FilesUploader, UploadedFile, UPLOADED_FILES,
};

0 comments on commit 3daf658

Please sign in to comment.