Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[draft] feat(cli): remove cmds #1536

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 1 addition & 3 deletions sn_cli/src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,7 @@ async fn main() -> Result<()> {
SubCmd::WatchOnlyWallet(cmds) => {
wo_wallet_cmds(cmds, &client, &client_data_dir_path, should_verify_store).await?
}
SubCmd::Files(cmds) => {
files_cmds(cmds, &client, &client_data_dir_path, should_verify_store).await?
}
SubCmd::Files(cmds) => files_cmds(cmds, &client, &client_data_dir_path).await?,
SubCmd::Folders(cmds) => {
folders_cmds(cmds, &client, &client_data_dir_path, should_verify_store).await?
}
Expand Down
246 changes: 71 additions & 175 deletions sn_cli/src/bin/subcommands/files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,15 @@
// 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, FilesUploader, UploadedFile,
UPLOADED_FILES,
};
use autonomi::{download_file, ChunkManager, Estimator, UploadedFile, UPLOADED_FILES};
use clap::Parser;
use color_eyre::{
eyre::{bail, eyre},
Help, Result,
};
use sn_client::{
protocol::storage::{Chunk, ChunkAddress, RetryStrategy},
UploadCfg,
};
use color_eyre::{eyre::eyre, Result};
use sn_client::protocol::storage::{Chunk, ChunkAddress, RetryStrategy};
use sn_client::{Client, FilesApi, BATCH_SIZE};
use std::{
ffi::OsString,
path::{Path, PathBuf},
};
use walkdir::WalkDir;
use xor_name::XorName;

#[derive(Parser, Debug)]
Expand All @@ -37,41 +27,22 @@ pub enum FilesCmds {
#[clap(long, name = "make_public", default_value = "false", short = 'p')]
make_data_public: bool,
},
Upload {
/// The location of the file(s) to upload.
///
/// Can be a file or a directory.
#[clap(name = "path", value_name = "PATH")]
file_path: PathBuf,
/// The batch_size to split chunks into parallel handling batches
/// during payment and upload processing.
#[clap(long, default_value_t = BATCH_SIZE, short='b')]
batch_size: usize,
/// Should the file be made accessible to all. (This is irreversible)
#[clap(long, name = "make_public", default_value = "false", short = 'p')]
make_data_public: bool,
/// Set the strategy to use on chunk upload failure. Does not modify the spend failure retry attempts yet.
///
/// Choose a retry strategy based on effort level, from 'quick' (least effort), through 'balanced',
/// to 'persistent' (most effort).
#[clap(long, default_value_t = RetryStrategy::Balanced, short = 'r', help = "Sets the retry strategy on upload failure. Options: 'quick' for minimal effort, 'balanced' for moderate effort, or 'persistent' for maximum effort.")]
retry_strategy: RetryStrategy,
},

Download {
/// The name to apply to the downloaded file.
///
/// If the name argument is used, the address argument must also be supplied.
///
/// 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 All @@ -88,12 +59,7 @@ pub enum FilesCmds {
},
}

pub(crate) async fn files_cmds(
cmds: FilesCmds,
client: &Client,
root_dir: &Path,
verify_store: bool,
) -> Result<()> {
pub(crate) async fn files_cmds(cmds: FilesCmds, client: &Client, root_dir: &Path) -> Result<()> {
match cmds {
FilesCmds::Estimate {
path,
Expand All @@ -105,158 +71,88 @@ pub(crate) async fn files_cmds(
.estimate_cost(path, make_data_public, root_dir)
.await?
}
FilesCmds::Upload {
file_path,
batch_size,
retry_strategy,
make_data_public,
} => {
let files_count = count_files_in_path_recursively(&file_path);

if files_count == 0 {
if file_path.is_dir() {
bail!(
"The directory specified for upload is empty. \
Please verify the provided path."
);
} else {
bail!("The provided file path is invalid. Please verify the path.");
}
}
let upload_cfg = UploadCfg {
batch_size,
verify_store,
retry_strategy,
..Default::default()
};
let files_uploader = FilesUploader::new(client.clone(), root_dir.to_path_buf())
.set_make_data_public(make_data_public)
.set_upload_cfg(upload_cfg)
.insert_path(&file_path);

let _summary = files_uploader.start_upload().await?;
}
FilesCmds::Download {
file_name,
file_addr,
show_holders,
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(())
}

fn count_files_in_path_recursively(file_path: &PathBuf) -> u32 {
let entries_iterator = WalkDir::new(file_path).into_iter().flatten();
let mut count = 0;

entries_iterator.for_each(|entry| {
if entry.file_type().is_file() {
count += 1;
}
});
count
}
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::{FilesUploadStatusNotifier, FilesUploadSummary, FilesUploader};
pub use upload::{UploadedFile, UPLOADED_FILES};
Expand Down