Rust · 3173 bytes Raw Blame History
1 use clap::Args;
2 use anyhow::{Context, Result};
3 use indicatif::{ProgressBar, ProgressStyle};
4 use std::path::PathBuf;
5 use tracing::info;
6 use humansize::{format_size, BINARY};
7
8 use crate::config::Config;
9 use crate::client::ZephyrClient;
10 use super::Command;
11
12 #[derive(Debug, Args)]
13 pub struct UploadCommand {
14 /// File path to upload
15 file: PathBuf,
16
17 /// Custom file name (defaults to original filename)
18 #[arg(short, long)]
19 name: Option<String>,
20
21 /// Show progress bar
22 #[arg(long, default_value = "true")]
23 progress: bool,
24
25 /// Verify upload after completion
26 #[arg(long)]
27 verify: bool,
28 }
29
30 #[async_trait::async_trait]
31 impl Command for UploadCommand {
32 async fn execute(&self, config: &Config) -> Result<()> {
33 info!("Uploading file: {:?}", self.file);
34
35 // Validate file exists and is readable
36 if !self.file.exists() {
37 anyhow::bail!("File does not exist: {:?}", self.file);
38 }
39
40 if !self.file.is_file() {
41 anyhow::bail!("Path is not a file: {:?}", self.file);
42 }
43
44 let metadata = tokio::fs::metadata(&self.file).await
45 .with_context(|| format!("Failed to read file metadata: {:?}", self.file))?;
46
47 let file_size = metadata.len();
48 let display_name = self.name.as_deref()
49 .or_else(|| self.file.file_name().and_then(|n| n.to_str()))
50 .unwrap_or("unknown");
51
52 println!("Uploading: {}", display_name);
53 println!(" Size: {}", format_size(file_size, BINARY));
54 println!(" Path: {:?}", self.file);
55
56 // Create progress bar
57 let progress = if self.progress {
58 let pb = ProgressBar::new(file_size);
59 pb.set_style(
60 ProgressStyle::default_bar()
61 .template("[{elapsed_precise}] {bar:40.cyan/blue} {percent}% {bytes}/{total_bytes} ETA: {eta}")
62 .unwrap()
63 .progress_chars("##-")
64 );
65 Some(pb)
66 } else {
67 None
68 };
69
70 let client = ZephyrClient::new(config);
71
72 // Upload the file
73 let upload_result = client.upload_file(&self.file).await
74 .context("Failed to upload file")?;
75
76 if let Some(pb) = progress {
77 pb.finish_with_message("Upload complete");
78 }
79
80 println!("✓ File uploaded successfully!");
81 println!(" File hash: {}", upload_result.file_hash);
82 println!(" Chunks: {}", upload_result.chunks_uploaded);
83
84 // Verify upload if requested
85 if self.verify {
86 println!("\nVerifying upload...");
87 let files = client.list_files().await
88 .context("Failed to list files for verification")?;
89
90 if files.iter().any(|f| f.hash == upload_result.file_hash) {
91 println!("✓ Upload verified successfully");
92 } else {
93 println!("⚠ Warning: Could not verify upload in file list");
94 }
95 }
96
97 println!("\nTo download this file later, use:");
98 println!(" zephyrfs download {}", upload_result.file_hash);
99
100 Ok(())
101 }
102 }