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"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
|
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bumpalo"
|
||||||
|
version = "3.17.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.10.1"
|
version = "1.10.1"
|
||||||
|
|
@ -491,6 +497,18 @@ dependencies = [
|
||||||
"hashbrown",
|
"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]]
|
[[package]]
|
||||||
name = "is_terminal_polyfill"
|
name = "is_terminal_polyfill"
|
||||||
version = "1.70.1"
|
version = "1.70.1"
|
||||||
|
|
@ -527,6 +545,16 @@ dependencies = [
|
||||||
"syn",
|
"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]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.172"
|
version = "0.2.172"
|
||||||
|
|
@ -594,6 +622,12 @@ version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "number_prefix"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.21.3"
|
version = "1.21.3"
|
||||||
|
|
@ -818,6 +852,7 @@ dependencies = [
|
||||||
"dialoguer",
|
"dialoguer",
|
||||||
"dirs-next",
|
"dirs-next",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
|
"indicatif",
|
||||||
"log",
|
"log",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
|
@ -1023,6 +1058,73 @@ version = "0.11.0+wasi-snapshot-preview1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
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]]
|
[[package]]
|
||||||
name = "webpki-roots"
|
name = "webpki-roots"
|
||||||
version = "0.26.11"
|
version = "0.26.11"
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ ctrlc = { version = "3.4.7", features = ["termination"] }
|
||||||
dialoguer = { version = "0.11.0", default-features = false }
|
dialoguer = { version = "0.11.0", default-features = false }
|
||||||
dirs-next = "2.0.0"
|
dirs-next = "2.0.0"
|
||||||
env_logger = "0.11.8"
|
env_logger = "0.11.8"
|
||||||
|
indicatif = { version = "0.17.11", default-features = false }
|
||||||
log = "0.4.27"
|
log = "0.4.27"
|
||||||
serde = { version = "1.0.219", features = ["derive"] }
|
serde = { version = "1.0.219", features = ["derive"] }
|
||||||
serde_json = "1.0.140"
|
serde_json = "1.0.140"
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ use std::{
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use console::style;
|
||||||
|
use indicatif::{ProgressBar, ProgressStyle};
|
||||||
use log::{debug, trace};
|
use log::{debug, trace};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
|
@ -17,6 +19,8 @@ use super::{
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
file_name: PathBuf,
|
file_name: PathBuf,
|
||||||
|
#[serde(skip)]
|
||||||
|
progress: Option<ProgressBar>,
|
||||||
|
|
||||||
alias: Alias,
|
alias: Alias,
|
||||||
share: Share,
|
share: Share,
|
||||||
|
|
@ -29,6 +33,15 @@ enum FileState {
|
||||||
U(FileUploading),
|
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 {
|
impl AppState {
|
||||||
fn cache_dir() -> PathBuf {
|
fn cache_dir() -> PathBuf {
|
||||||
let dir_name = dirs_next::cache_dir()
|
let dir_name = dirs_next::cache_dir()
|
||||||
|
|
@ -61,6 +74,7 @@ impl AppState {
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
file_name,
|
file_name,
|
||||||
|
progress: None,
|
||||||
alias: state.alias,
|
alias: state.alias,
|
||||||
share: state.share,
|
share: state.share,
|
||||||
files: state.files,
|
files: state.files,
|
||||||
|
|
@ -79,12 +93,17 @@ impl AppState {
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
file_name,
|
file_name,
|
||||||
|
progress: None,
|
||||||
alias,
|
alias,
|
||||||
share,
|
share,
|
||||||
files,
|
files,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn file_names(&self) -> Vec<&str> {
|
||||||
|
self.files.iter().map(FileState::file_name).collect()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn upload_chunk(
|
pub fn upload_chunk(
|
||||||
&mut self,
|
&mut self,
|
||||||
http: &ureq::Agent,
|
http: &ureq::Agent,
|
||||||
|
|
@ -100,8 +119,34 @@ impl AppState {
|
||||||
|
|
||||||
debug!("{uploading} chunk {chunk_size}");
|
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) {
|
match uploading.upload_chunk(http, &self.alias, chunk_size) {
|
||||||
ChunkState::Ok(upl) => {
|
ChunkState::Ok(upl) => {
|
||||||
|
pb.set_position(upl.offset());
|
||||||
self.files.push_front(FileState::U(upl));
|
self.files.push_front(FileState::U(upl));
|
||||||
Ok(Some(()))
|
Ok(Some(()))
|
||||||
}
|
}
|
||||||
|
|
@ -111,6 +156,8 @@ impl AppState {
|
||||||
}
|
}
|
||||||
ChunkState::Finished(path) => {
|
ChunkState::Finished(path) => {
|
||||||
debug!("Finished {:?}!", path.display());
|
debug!("Finished {:?}!", path.display());
|
||||||
|
pb.finish();
|
||||||
|
self.progress = None;
|
||||||
self.share.notify(http, &self.alias).unwrap();
|
self.share.notify(http, &self.alias).unwrap();
|
||||||
|
|
||||||
Ok(self.files.front().map(drop))
|
Ok(self.files.front().map(drop))
|
||||||
|
|
|
||||||
65
src/main.rs
65
src/main.rs
|
|
@ -20,12 +20,18 @@ use appstate::AppState;
|
||||||
use cli::Cli;
|
use cli::Cli;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
println!(
|
||||||
|
"{} to {}!",
|
||||||
|
style("Welcome").magenta().bold(),
|
||||||
|
style("ShrUpl").yellow().bold(),
|
||||||
|
);
|
||||||
|
|
||||||
let stop = Arc::new(AtomicBool::new(false));
|
let stop = Arc::new(AtomicBool::new(false));
|
||||||
|
|
||||||
let stop_ctrlc = stop.clone();
|
let stop_ctrlc = stop.clone();
|
||||||
ctrlc::set_handler(move || {
|
ctrlc::set_handler(move || {
|
||||||
stop_ctrlc.store(true, Ordering::SeqCst);
|
stop_ctrlc.store(true, Ordering::SeqCst);
|
||||||
info!("stopping after chunk ...");
|
info!("stopping as soon as possible ...");
|
||||||
})
|
})
|
||||||
.expect("Error setting Ctrl-C handler");
|
.expect("Error setting Ctrl-C handler");
|
||||||
|
|
||||||
|
|
@ -43,37 +49,48 @@ fn main() {
|
||||||
let mut state = AppState::try_resume(&args)
|
let mut state = AppState::try_resume(&args)
|
||||||
.and_then(|state| {
|
.and_then(|state| {
|
||||||
Confirm::with_theme(&ColorfulTheme::default())
|
Confirm::with_theme(&ColorfulTheme::default())
|
||||||
.with_prompt("Previous operation found. Continue?")
|
.with_prompt("Continue previously stopped operation?")
|
||||||
.default(true)
|
.default(true)
|
||||||
.interact()
|
.interact()
|
||||||
.map_or(None, |b| b.then_some(state))
|
.map_or(None, |b| b.then_some(state))
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| match AppState::from_args(&args, &agent) {
|
.unwrap_or_else(|| {
|
||||||
Ok(state) => {
|
stop.load(Ordering::SeqCst).then(|| exit(0));
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
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:?}");
|
info!("continuing with state: {state:?}");
|
||||||
|
|
||||||
loop {
|
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(
|
pub fn start_upload(
|
||||||
self,
|
self,
|
||||||
http: &ureq::Agent,
|
http: &ureq::Agent,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use std::{
|
use std::{
|
||||||
fmt::Display,
|
fmt::{Debug, Display},
|
||||||
fs::File,
|
fs::File,
|
||||||
io::{self, Read, Seek, SeekFrom},
|
io::{self, Read, Seek, SeekFrom},
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
|
|
@ -7,10 +7,7 @@ use std::{
|
||||||
|
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use ureq::{
|
use ureq::http::{HeaderValue, StatusCode};
|
||||||
Error::Other,
|
|
||||||
http::{HeaderValue, StatusCode},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{Alias, SharryAlias};
|
use super::{Alias, SharryAlias};
|
||||||
|
|
||||||
|
|
@ -71,6 +68,26 @@ impl FileUploading {
|
||||||
Ok(bytes)
|
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(
|
pub fn upload_chunk(
|
||||||
mut self,
|
mut self,
|
||||||
http: &ureq::Agent,
|
http: &ureq::Agent,
|
||||||
|
|
|
||||||
|
|
@ -7,5 +7,5 @@ mod share;
|
||||||
|
|
||||||
pub use alias::Alias;
|
pub use alias::Alias;
|
||||||
pub use api::{NewShareRequest, Uri};
|
pub use api::{NewShareRequest, Uri};
|
||||||
pub use file::{ChunkState, FileChecked, FileUploading};
|
pub use file::{ChunkState, FileChecked, FileUploading, UploadError};
|
||||||
pub use share::Share;
|
pub use share::Share;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue