Compare commits
2 commits
e86b11d058
...
dc7eeaddfe
| Author | SHA1 | Date | |
|---|---|---|---|
| dc7eeaddfe | |||
| 3bf5d96e04 |
7 changed files with 218 additions and 30 deletions
102
Cargo.lock
generated
102
Cargo.lock
generated
|
|
@ -79,6 +79,12 @@ version = "2.9.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.10.1"
|
||||
|
|
@ -491,6 +497,18 @@ dependencies = [
|
|||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indicatif"
|
||||
version = "0.17.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235"
|
||||
dependencies = [
|
||||
"console",
|
||||
"number_prefix",
|
||||
"portable-atomic",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.1"
|
||||
|
|
@ -527,6 +545,16 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.172"
|
||||
|
|
@ -594,6 +622,12 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||
|
||||
[[package]]
|
||||
name = "number_prefix"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.3"
|
||||
|
|
@ -818,6 +852,7 @@ dependencies = [
|
|||
"dialoguer",
|
||||
"dirs-next",
|
||||
"env_logger",
|
||||
"indicatif",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
@ -1023,6 +1058,73 @@ version = "0.11.0+wasi-snapshot-preview1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "web-time"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "0.26.11"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ ctrlc = { version = "3.4.7", features = ["termination"] }
|
|||
dialoguer = { version = "0.11.0", default-features = false }
|
||||
dirs-next = "2.0.0"
|
||||
env_logger = "0.11.8"
|
||||
indicatif = { version = "0.17.11", default-features = false }
|
||||
log = "0.4.27"
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
serde_json = "1.0.140"
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ use std::{
|
|||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use console::style;
|
||||
use indicatif::{ProgressBar, ProgressStyle};
|
||||
use log::{debug, trace};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
@ -17,6 +19,8 @@ use super::{
|
|||
pub struct AppState {
|
||||
#[serde(skip)]
|
||||
file_name: PathBuf,
|
||||
#[serde(skip)]
|
||||
progress: Option<ProgressBar>,
|
||||
|
||||
alias: Alias,
|
||||
share: Share,
|
||||
|
|
@ -29,6 +33,15 @@ enum FileState {
|
|||
U(FileUploading),
|
||||
}
|
||||
|
||||
impl FileState {
|
||||
fn file_name(&self) -> &str {
|
||||
match self {
|
||||
FileState::C(checked) => checked.file_name(),
|
||||
FileState::U(uploading) => uploading.file_name(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
fn cache_dir() -> PathBuf {
|
||||
let dir_name = dirs_next::cache_dir()
|
||||
|
|
@ -61,6 +74,7 @@ impl AppState {
|
|||
|
||||
Self {
|
||||
file_name,
|
||||
progress: None,
|
||||
alias: state.alias,
|
||||
share: state.share,
|
||||
files: state.files,
|
||||
|
|
@ -79,12 +93,17 @@ impl AppState {
|
|||
|
||||
Ok(Self {
|
||||
file_name,
|
||||
progress: None,
|
||||
alias,
|
||||
share,
|
||||
files,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn file_names(&self) -> Vec<&str> {
|
||||
self.files.iter().map(FileState::file_name).collect()
|
||||
}
|
||||
|
||||
pub fn upload_chunk(
|
||||
&mut self,
|
||||
http: &ureq::Agent,
|
||||
|
|
@ -100,8 +119,34 @@ impl AppState {
|
|||
|
||||
debug!("{uploading} chunk {chunk_size}");
|
||||
|
||||
let pb = match self.progress {
|
||||
Some(ref pb) => pb,
|
||||
None => {
|
||||
self.progress = Some({
|
||||
let pb = {
|
||||
let ps = ProgressStyle::with_template(&format!(
|
||||
"{{msg:.yellow}}: {{bar:50.cyan/blue}} {{binary_bytes:.magenta}}{}{{binary_total_bytes:.magenta}} ({{elapsed}})",
|
||||
style("/").magenta(),
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
ProgressBar::new(uploading.size())
|
||||
.with_style(ps)
|
||||
.with_message(uploading.file_name().to_owned())
|
||||
.with_position(uploading.offset())
|
||||
};
|
||||
pb.tick();
|
||||
|
||||
pb
|
||||
});
|
||||
self.progress.as_ref().unwrap()
|
||||
}
|
||||
};
|
||||
pb.tick();
|
||||
|
||||
match uploading.upload_chunk(http, &self.alias, chunk_size) {
|
||||
ChunkState::Ok(upl) => {
|
||||
pb.set_position(upl.offset());
|
||||
self.files.push_front(FileState::U(upl));
|
||||
Ok(Some(()))
|
||||
}
|
||||
|
|
@ -111,6 +156,8 @@ impl AppState {
|
|||
}
|
||||
ChunkState::Finished(path) => {
|
||||
debug!("Finished {:?}!", path.display());
|
||||
pb.finish();
|
||||
self.progress = None;
|
||||
self.share.notify(http, &self.alias).unwrap();
|
||||
|
||||
Ok(self.files.front().map(drop))
|
||||
|
|
|
|||
65
src/main.rs
65
src/main.rs
|
|
@ -20,12 +20,18 @@ use appstate::AppState;
|
|||
use cli::Cli;
|
||||
|
||||
fn main() {
|
||||
println!(
|
||||
"{} to {}!",
|
||||
style("Welcome").magenta().bold(),
|
||||
style("ShrUpl").yellow().bold(),
|
||||
);
|
||||
|
||||
let stop = Arc::new(AtomicBool::new(false));
|
||||
|
||||
let stop_ctrlc = stop.clone();
|
||||
ctrlc::set_handler(move || {
|
||||
stop_ctrlc.store(true, Ordering::SeqCst);
|
||||
info!("stopping after chunk ...");
|
||||
info!("stopping as soon as possible ...");
|
||||
})
|
||||
.expect("Error setting Ctrl-C handler");
|
||||
|
||||
|
|
@ -43,37 +49,48 @@ fn main() {
|
|||
let mut state = AppState::try_resume(&args)
|
||||
.and_then(|state| {
|
||||
Confirm::with_theme(&ColorfulTheme::default())
|
||||
.with_prompt("Previous operation found. Continue?")
|
||||
.with_prompt("Continue previously stopped operation?")
|
||||
.default(true)
|
||||
.interact()
|
||||
.map_or(None, |b| b.then_some(state))
|
||||
})
|
||||
.unwrap_or_else(|| match AppState::from_args(&args, &agent) {
|
||||
Ok(state) => {
|
||||
state.save().unwrap();
|
||||
state
|
||||
}
|
||||
Err(e) => {
|
||||
if let Some(cause) = match e {
|
||||
ureq::Error::StatusCode(403) => Some("Alias ID"),
|
||||
ureq::Error::Io(_) => Some("URL"),
|
||||
_ => None,
|
||||
} {
|
||||
println!(
|
||||
"{} probably wrong: {} – {:?}",
|
||||
style("Error!").red(),
|
||||
style(cause).cyan(),
|
||||
style(e.to_string()).yellow()
|
||||
);
|
||||
} else {
|
||||
error!("unknown error: {e}");
|
||||
println!("{}", style("Unknown Error!").red());
|
||||
}
|
||||
.unwrap_or_else(|| {
|
||||
stop.load(Ordering::SeqCst).then(|| exit(0));
|
||||
|
||||
exit(1);
|
||||
match AppState::from_args(&args, &agent) {
|
||||
Ok(state) => {
|
||||
state.save().unwrap();
|
||||
state
|
||||
}
|
||||
Err(e) => {
|
||||
if let Some(cause) = match e {
|
||||
ureq::Error::StatusCode(403) => Some("Alias ID"),
|
||||
ureq::Error::Io(_) => Some("URL"),
|
||||
_ => None,
|
||||
} {
|
||||
info!("handling error: {e:?}");
|
||||
println!(
|
||||
"{} probably wrong: {} – {:?}",
|
||||
style("Error!").red().bold(),
|
||||
style(cause).cyan().italic(),
|
||||
style(e.to_string()).yellow()
|
||||
);
|
||||
} else {
|
||||
error!("unknown error: {e} – {e:?}");
|
||||
println!("{}", style("Unknown Error!").red().bold());
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
println!(
|
||||
"{} uploading: {}",
|
||||
style("ShrUpl").yellow().bold(),
|
||||
style(state.file_names().join(", ")).magenta(),
|
||||
);
|
||||
|
||||
info!("continuing with state: {state:?}");
|
||||
|
||||
loop {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,10 @@ impl FileChecked {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn file_name(&self) -> &str {
|
||||
self.path.file_name().unwrap().to_str().unwrap()
|
||||
}
|
||||
|
||||
pub fn start_upload(
|
||||
self,
|
||||
http: &ureq::Agent,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use std::{
|
||||
fmt::Display,
|
||||
fmt::{Debug, Display},
|
||||
fs::File,
|
||||
io::{self, Read, Seek, SeekFrom},
|
||||
path::PathBuf,
|
||||
|
|
@ -7,10 +7,7 @@ use std::{
|
|||
|
||||
use log::debug;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ureq::{
|
||||
Error::Other,
|
||||
http::{HeaderValue, StatusCode},
|
||||
};
|
||||
use ureq::http::{HeaderValue, StatusCode};
|
||||
|
||||
use super::{Alias, SharryAlias};
|
||||
|
||||
|
|
@ -71,6 +68,26 @@ impl FileUploading {
|
|||
Ok(bytes)
|
||||
}
|
||||
|
||||
pub fn file_name(&self) -> &str {
|
||||
self.path.file_name().unwrap().to_str().unwrap()
|
||||
}
|
||||
|
||||
pub fn offset<T>(&self) -> T
|
||||
where
|
||||
T: TryFrom<usize>,
|
||||
<T as TryFrom<usize>>::Error: Debug,
|
||||
{
|
||||
self.offset.try_into().unwrap()
|
||||
}
|
||||
|
||||
pub fn size<T>(&self) -> T
|
||||
where
|
||||
T: TryFrom<usize>,
|
||||
<T as TryFrom<usize>>::Error: Debug,
|
||||
{
|
||||
self.size.try_into().unwrap()
|
||||
}
|
||||
|
||||
pub fn upload_chunk(
|
||||
mut self,
|
||||
http: &ureq::Agent,
|
||||
|
|
|
|||
|
|
@ -7,5 +7,5 @@ mod share;
|
|||
|
||||
pub use alias::Alias;
|
||||
pub use api::{NewShareRequest, Uri};
|
||||
pub use file::{ChunkState, FileChecked, FileUploading};
|
||||
pub use file::{ChunkState, FileChecked, FileUploading, UploadError};
|
||||
pub use share::Share;
|
||||
|
|
|
|||
Loading…
Reference in a new issue