From 9f1e0cfc6c6f11370a4dfe4f473a30a07384925b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn-Michael=20Miehe?= <40151420+ldericher@users.noreply.github.com> Date: Thu, 12 Jun 2025 23:01:16 +0000 Subject: [PATCH] [wip] impl `Client` for `ureq::Agent` - Client is now owned by `AppState` - minor cleanups --- src/appstate.rs | 30 +++++++++++++++++++++++------- src/cli.rs | 17 ++++++++++++++++- src/main.rs | 11 ++--------- src/sharry/api.rs | 2 +- src/sharry/client.rs | 14 ++++---------- 5 files changed, 46 insertions(+), 28 deletions(-) diff --git a/src/appstate.rs b/src/appstate.rs index dae340e..b7e4709 100644 --- a/src/appstate.rs +++ b/src/appstate.rs @@ -19,6 +19,7 @@ pub struct AppState { current_bar: RefCell>, buffer: Vec, + http: ureq::Agent, inner: CacheFile, } @@ -30,11 +31,19 @@ impl fmt::Debug for AppState { } } +fn new_http(timeout: Option) -> ureq::Agent { + ureq::Agent::config_builder() + .timeout_global(timeout) + .build() + .into() +} + impl AppState { - fn new(chunk_size: usize, inner: CacheFile) -> Self { + fn new(chunk_size: usize, http: ureq::Agent, inner: CacheFile) -> Self { Self { current_bar: None.into(), buffer: vec![0; chunk_size * 1024 * 1024], + http, inner, } } @@ -44,10 +53,16 @@ impl AppState { .inspect_err(|e| debug!("could not resume from hash {:?}: {e}", args.get_hash())) .ok()?; - Some(Self::new(args.chunk_size, inner)) + Some(Self::new( + args.chunk_size, + new_http(args.get_timeout()), + inner, + )) } - pub fn from_args(args: &Cli, http: &impl Client) -> sharry::Result { + pub fn from_args(args: &Cli) -> sharry::Result { + let http = new_http(args.get_timeout()); + let share_id = http.share_create( &args.get_uri().endpoint("alias/upload/new"), &args.alias, @@ -56,6 +71,7 @@ impl AppState { Ok(Self::new( args.chunk_size, + http, CacheFile::from_args(args, share_id), )) } @@ -95,9 +111,9 @@ impl AppState { } } - pub fn upload_chunk(&mut self, http: &impl Client) -> sharry::Result> { - let Some(mut uploading) = self.inner.pop_file(http) else { - self.inner.share_notify(http).unwrap(); // HACK unwrap + pub fn upload_chunk(&mut self) -> sharry::Result> { + let Some(mut uploading) = self.inner.pop_file(&self.http) else { + self.inner.share_notify(&self.http).unwrap(); // HACK unwrap return Ok(None); }; @@ -110,7 +126,7 @@ impl AppState { .read(&mut self.buffer) .map_err(ClientError::from)?; - http.file_patch( + self.http.file_patch( chunk.get_patch_uri(), self.inner.alias_id(), chunk.get_offset(), diff --git a/src/cli.rs b/src/cli.rs index 070d9f7..d161e11 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,4 +1,5 @@ use std::{ + fmt, hash::{DefaultHasher, Hash, Hasher}, time::Duration, }; @@ -10,7 +11,7 @@ use super::{ sharry::{NewShareRequest, Uri}, }; -#[derive(Parser, Debug, Hash)] +#[derive(Parser, Hash)] #[command(version, about, long_about = None)] pub struct Cli { /// Timeout in seconds for HTTP actions (set 0 or invalid to disable) @@ -56,6 +57,20 @@ pub struct Cli { pub files: Vec, } +impl fmt::Debug for Cli { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Cli") + .field("uri", &self.get_uri()) + .field("alias", &self.alias) + .field("timeout", &self.get_timeout()) + .field("chunk_size", &self.chunk_size) + .field("share_request", &self.get_share_request()) + .field("files", &self.files) + .field("hash", &self.get_hash()) + .finish_non_exhaustive() + } +} + fn parse_seconds(data: &str) -> Result { data.parse().or(Ok(0)).map(Duration::from_secs) } diff --git a/src/main.rs b/src/main.rs index 8db94fd..2ca9d32 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,7 +16,6 @@ use clap::Parser; use console::style; use dialoguer::{Confirm, theme::ColorfulTheme}; use log::{error, info}; -use ureq::Agent; use appstate::AppState; use cli::Cli; @@ -76,12 +75,6 @@ fn main() { let args = Cli::parse(); info!("args: {args:?}"); - info!("timeout: {:?}", args.get_timeout()); - - let agent: Agent = Agent::config_builder() - .timeout_global(args.get_timeout()) - .build() - .into(); let mut state = AppState::try_resume(&args) .and_then(|state| { @@ -94,7 +87,7 @@ fn main() { .unwrap_or_else(|| { check_ctrlc(); - match AppState::from_args(&args, &agent) { + match AppState::from_args(&args) { Ok(state) => { state.save().unwrap(); // HACK unwrap state @@ -115,7 +108,7 @@ fn main() { ); loop { - match state.upload_chunk(&agent) { + match state.upload_chunk() { Err(e) => error!("error: {e:?}"), Ok(None) => { info!("all uploads done"); diff --git a/src/sharry/api.rs b/src/sharry/api.rs index 9f51932..5e0ed17 100644 --- a/src/sharry/api.rs +++ b/src/sharry/api.rs @@ -31,7 +31,7 @@ impl fmt::Display for Uri { } } -#[derive(Serialize)] +#[derive(Serialize, Debug)] #[allow(non_snake_case)] pub struct NewShareRequest { name: String, diff --git a/src/sharry/client.rs b/src/sharry/client.rs index 5299b02..68c6e49 100644 --- a/src/sharry/client.rs +++ b/src/sharry/client.rs @@ -21,7 +21,7 @@ pub trait Client { file_size: u64, ) -> Result; - fn file_patch(&self, patch_uri: &str, alias_id: &str, offset: u64, chunk: &[u8]) -> Result<()>; + fn file_patch(&self, endpoint: &str, alias_id: &str, offset: u64, chunk: &[u8]) -> Result<()>; } #[derive(Debug, Error)] @@ -86,8 +86,6 @@ impl Client for ureq::Agent { alias_id: &str, data: NewShareRequest, ) -> Result { - // let endpoint = uri.get_endpoint("alias/upload/new"); - let mut res = self .post(endpoint) .header("Sharry-Alias", alias_id) @@ -112,8 +110,6 @@ impl Client for ureq::Agent { } fn share_notify(&self, endpoint: &str, alias_id: &str) -> Result<()> { - // let endpoint = uri.get_endpoint(format!("alias/mail/notify/{}", share_id)); - let mut res = self .post(endpoint) .header("Sharry-Alias", alias_id) @@ -140,8 +136,6 @@ impl Client for ureq::Agent { file_name: &str, file_size: u64, ) -> Result { - // let endpoint = uri.get_endpoint(format!("alias/upload/{}/files/tus", share_id)); - let res = self .post(endpoint) .header("Sharry-Alias", alias_id) @@ -164,15 +158,15 @@ impl Client for ureq::Agent { Ok(location) } - fn file_patch(&self, patch_uri: &str, alias_id: &str, offset: u64, chunk: &[u8]) -> Result<()> { + fn file_patch(&self, endpoint: &str, alias_id: &str, offset: u64, chunk: &[u8]) -> Result<()> { let res = self - .patch(patch_uri) + .patch(endpoint) .header("Sharry-Alias", alias_id) .header("Upload-Offset", offset) .send(chunk) .map_err(ClientError::from)?; - trace!("{patch_uri:?} response: {res:?}"); + trace!("{endpoint:?} response: {res:?}"); ClientError::res_status_check(res.status(), ureq::http::StatusCode::NO_CONTENT)?; let res_offset = (res.headers().get("Upload-Offset"))