[wip] impl Client for ureq::Agent
- wip: factor out `SavedState`
This commit is contained in:
parent
fb06725f05
commit
ed10f269c8
3 changed files with 69 additions and 84 deletions
|
|
@ -1,25 +1,21 @@
|
||||||
use std::{fmt, io, path::PathBuf, time::Duration};
|
use std::{fmt, io, time::Duration};
|
||||||
|
|
||||||
use console::style;
|
use console::style;
|
||||||
use indicatif::{ProgressBar, ProgressStyle};
|
use indicatif::{ProgressBar, ProgressStyle};
|
||||||
use log::{debug, trace};
|
use log::debug;
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
cachefile::CacheFile,
|
||||||
cli::Cli,
|
cli::Cli,
|
||||||
file::FileTrait,
|
file::FileTrait,
|
||||||
savedstate::SavedState,
|
|
||||||
sharry::{self, Client, ClientError},
|
sharry::{self, Client, ClientError},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
#[serde(skip)]
|
|
||||||
progress: Option<ProgressBar>,
|
progress: Option<ProgressBar>,
|
||||||
#[serde(skip)]
|
|
||||||
buffer: Vec<u8>,
|
buffer: Vec<u8>,
|
||||||
|
|
||||||
inner: SavedState,
|
inner: CacheFile,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for AppState {
|
impl fmt::Debug for AppState {
|
||||||
|
|
@ -31,23 +27,7 @@ impl fmt::Debug for AppState {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppState {
|
impl AppState {
|
||||||
fn cache_dir() -> PathBuf {
|
fn new(chunk_size: usize, inner: CacheFile) -> Self {
|
||||||
let dir_name = dirs_next::cache_dir()
|
|
||||||
.expect("could not determine cache directory")
|
|
||||||
.join("shrupl");
|
|
||||||
|
|
||||||
trace!("cachedir: {:?}", dir_name.display());
|
|
||||||
dir_name
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cache_file(args: &Cli) -> PathBuf {
|
|
||||||
let file_name = Self::cache_dir().join(format!("{}.json", args.get_hash()));
|
|
||||||
|
|
||||||
trace!("cachefile: {:?}", file_name.display());
|
|
||||||
file_name
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new(chunk_size: usize, inner: SavedState) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
progress: None,
|
progress: None,
|
||||||
buffer: vec![0; chunk_size * 1024 * 1024],
|
buffer: vec![0; chunk_size * 1024 * 1024],
|
||||||
|
|
@ -56,38 +36,26 @@ impl AppState {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_resume(args: &Cli) -> Option<Self> {
|
pub fn try_resume(args: &Cli) -> Option<Self> {
|
||||||
let file_name = Self::cache_file(args);
|
let inner = CacheFile::try_resume(args)
|
||||||
let inner = SavedState::load(&file_name)
|
.inspect_err(|e| debug!("could not resume from hash {:?}: {e}", args.get_hash()))
|
||||||
.inspect_err(|e| debug!("could not resume from {:?}: {e}", file_name.display()))
|
|
||||||
.ok()?;
|
.ok()?;
|
||||||
|
|
||||||
Some(Self::new(args.chunk_size, inner))
|
Some(Self::new(args.chunk_size, inner))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_args(args: &Cli, http: &impl Client) -> sharry::Result<Self> {
|
pub fn from_args(args: &Cli, http: &impl Client) -> sharry::Result<Self> {
|
||||||
let uri = args.get_uri();
|
|
||||||
let share_id = http.share_create(
|
let share_id = http.share_create(
|
||||||
&uri.endpoint("alias/upload/new"),
|
&args.get_uri().endpoint("alias/upload/new"),
|
||||||
&args.alias,
|
&args.alias,
|
||||||
args.get_share_request(),
|
args.get_share_request(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(Self::new(
|
Ok(Self::new(
|
||||||
args.chunk_size,
|
args.chunk_size,
|
||||||
SavedState::new(
|
CacheFile::from_args(args, share_id),
|
||||||
Self::cache_file(&args),
|
|
||||||
uri,
|
|
||||||
args.alias.clone(),
|
|
||||||
share_id,
|
|
||||||
&args.files,
|
|
||||||
),
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file_names(&self) -> Vec<&str> {
|
|
||||||
self.inner.file_names()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn upload_chunk(&mut self, http: &impl Client) -> sharry::Result<Option<()>> {
|
pub fn upload_chunk(&mut self, http: &impl Client) -> sharry::Result<Option<()>> {
|
||||||
let Some(mut uploading) = self.inner.pop_file(http) else {
|
let Some(mut uploading) = self.inner.pop_file(http) else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
|
|
@ -126,7 +94,7 @@ impl AppState {
|
||||||
|
|
||||||
http.file_patch(
|
http.file_patch(
|
||||||
chunk.get_patch_uri(),
|
chunk.get_patch_uri(),
|
||||||
&self.alias_id,
|
self.inner.alias_id(),
|
||||||
chunk.get_offset(),
|
chunk.get_offset(),
|
||||||
chunk.get_data(),
|
chunk.get_data(),
|
||||||
)?;
|
)?;
|
||||||
|
|
@ -142,16 +110,17 @@ impl AppState {
|
||||||
bar.finish();
|
bar.finish();
|
||||||
self.progress = None;
|
self.progress = None;
|
||||||
|
|
||||||
let endpoint = self
|
self.inner.share_notify(http).unwrap(); // HACK unwrap
|
||||||
.uri
|
|
||||||
.endpoint(format!("alias/mail/notify/{}", self.share_id));
|
|
||||||
http.share_notify(&endpoint, &self.alias_id).unwrap(); // HACK unwrap
|
|
||||||
|
|
||||||
Ok(self.inner.has_file().then_some(()))
|
Ok(self.inner.has_file().then_some(()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn file_names(&self) -> Vec<&str> {
|
||||||
|
self.inner.file_names()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn save(&self) -> io::Result<()> {
|
pub fn save(&self) -> io::Result<()> {
|
||||||
self.inner.save()
|
self.inner.save()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,14 @@ use std::{
|
||||||
collections::VecDeque,
|
collections::VecDeque,
|
||||||
fs,
|
fs,
|
||||||
io::{self, Write},
|
io::{self, Write},
|
||||||
path::{Path, PathBuf},
|
path::PathBuf,
|
||||||
};
|
};
|
||||||
|
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
cli::Cli,
|
||||||
file::{self, FileTrait},
|
file::{self, FileTrait},
|
||||||
sharry::{self, Client, Uri},
|
sharry::{self, Client, Uri},
|
||||||
};
|
};
|
||||||
|
|
@ -30,22 +31,18 @@ impl FileState {
|
||||||
fn start_upload(
|
fn start_upload(
|
||||||
self,
|
self,
|
||||||
http: &impl Client,
|
http: &impl Client,
|
||||||
uri: &Uri,
|
endpoint: &str,
|
||||||
alias_id: &str,
|
alias_id: &str,
|
||||||
share_id: &str,
|
|
||||||
) -> sharry::Result<file::Uploading> {
|
) -> sharry::Result<file::Uploading> {
|
||||||
match self {
|
match self {
|
||||||
FileState::C(checked) => {
|
FileState::C(checked) => checked.start_upload(http, endpoint, alias_id),
|
||||||
let endpoint = &uri.endpoint(format!("alias/upload/{share_id}/files/tus"));
|
|
||||||
checked.start_upload(http, endpoint, alias_id)
|
|
||||||
}
|
|
||||||
FileState::U(uploading) => Ok(uploading),
|
FileState::U(uploading) => Ok(uploading),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct SavedState {
|
pub struct CacheFile {
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
file_name: PathBuf,
|
file_name: PathBuf,
|
||||||
|
|
||||||
|
|
@ -55,35 +52,47 @@ pub struct SavedState {
|
||||||
files: VecDeque<FileState>,
|
files: VecDeque<FileState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SavedState {
|
impl CacheFile {
|
||||||
pub fn new(
|
fn cache_dir() -> PathBuf {
|
||||||
file_name: PathBuf,
|
let dir_name = dirs_next::cache_dir()
|
||||||
uri: Uri,
|
.expect("could not determine cache directory")
|
||||||
alias_id: String,
|
.join("shrupl");
|
||||||
share_id: String,
|
|
||||||
files: &Vec<file::Checked>,
|
trace!("cachedir: {:?}", dir_name.display());
|
||||||
) -> Self {
|
dir_name
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cache_file(args: &Cli) -> PathBuf {
|
||||||
|
let file_name = Self::cache_dir().join(format!("{}.json", args.get_hash()));
|
||||||
|
|
||||||
|
trace!("cachefile: {:?}", file_name.display());
|
||||||
|
file_name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_resume(args: &Cli) -> io::Result<Self> {
|
||||||
|
let file_name = Self::cache_file(args);
|
||||||
|
|
||||||
|
let state: Self = {
|
||||||
|
let file = fs::File::open(&file_name)?;
|
||||||
|
let reader = io::BufReader::new(file);
|
||||||
|
serde_json::from_reader(reader).map_err(io::Error::other)?
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self { file_name, ..state })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_args(args: &Cli, share_id: String) -> Self {
|
||||||
Self {
|
Self {
|
||||||
file_name,
|
file_name: Self::cache_file(&args),
|
||||||
uri,
|
uri: args.get_uri(),
|
||||||
alias_id,
|
alias_id: args.alias.clone(),
|
||||||
share_id,
|
share_id,
|
||||||
files: files.clone().into_iter().map(FileState::C).collect(),
|
files: args.files.clone().into_iter().map(FileState::C).collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load(file_name: &Path) -> io::Result<Self> {
|
pub fn alias_id(&self) -> &str {
|
||||||
let file = fs::File::open(file_name)?;
|
&self.alias_id
|
||||||
let state: Self =
|
|
||||||
serde_json::from_reader(io::BufReader::new(file)).map_err(io::Error::other)?;
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
file_name: file_name.to_owned(),
|
|
||||||
uri: state.uri,
|
|
||||||
alias_id: state.alias_id,
|
|
||||||
share_id: state.share_id,
|
|
||||||
files: state.files,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file_names(&self) -> Vec<&str> {
|
pub fn file_names(&self) -> Vec<&str> {
|
||||||
|
|
@ -96,11 +105,10 @@ impl SavedState {
|
||||||
|
|
||||||
pub fn pop_file(&mut self, http: &impl Client) -> Option<file::Uploading> {
|
pub fn pop_file(&mut self, http: &impl Client) -> Option<file::Uploading> {
|
||||||
if let Some(state) = self.files.pop_front() {
|
if let Some(state) = self.files.pop_front() {
|
||||||
Some(
|
let endpoint = self
|
||||||
state
|
.uri
|
||||||
.start_upload(http, &self.uri, &self.alias_id, &self.share_id)
|
.endpoint(format!("alias/upload/{}/files/tus", self.share_id));
|
||||||
.unwrap(),
|
Some(state.start_upload(http, &endpoint, &self.alias_id).unwrap()) // HACK unwrap
|
||||||
) // HACK unwrap
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
@ -110,6 +118,14 @@ impl SavedState {
|
||||||
self.files.push_front(FileState::U(file));
|
self.files.push_front(FileState::U(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn share_notify(&self, http: &impl Client) -> sharry::Result<()> {
|
||||||
|
let endpoint = self
|
||||||
|
.uri
|
||||||
|
.endpoint(format!("alias/mail/notify/{}", self.share_id));
|
||||||
|
|
||||||
|
http.share_notify(&endpoint, &self.alias_id)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn save(&self) -> io::Result<()> {
|
pub fn save(&self) -> io::Result<()> {
|
||||||
let cache_dir = self.file_name.parent().ok_or_else(|| {
|
let cache_dir = self.file_name.parent().ok_or_else(|| {
|
||||||
io::Error::other(format!("orphan file {:?}", self.file_name.display()))
|
io::Error::other(format!("orphan file {:?}", self.file_name.display()))
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
mod appstate;
|
mod appstate;
|
||||||
|
mod cachefile;
|
||||||
mod cli;
|
mod cli;
|
||||||
mod file;
|
mod file;
|
||||||
mod savedstate;
|
|
||||||
mod sharry;
|
mod sharry;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue