struct AppState

This commit is contained in:
Jörn-Michael Miehe 2025-06-02 23:57:17 +00:00
parent fc38e51a03
commit d197c06688
8 changed files with 179 additions and 6 deletions

92
Cargo.lock generated
View file

@ -73,6 +73,12 @@ version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "bitflags"
version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
[[package]]
name = "bytes"
version = "1.10.1"
@ -187,6 +193,27 @@ dependencies = [
"powerfmt",
]
[[package]]
name = "dirs-next"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
dependencies = [
"cfg-if",
"dirs-sys-next",
]
[[package]]
name = "dirs-sys-next"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
dependencies = [
"libc",
"redox_users",
"winapi",
]
[[package]]
name = "displaydoc"
version = "0.2.5"
@ -460,6 +487,16 @@ version = "0.2.172"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
[[package]]
name = "libredox"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
dependencies = [
"bitflags",
"libc",
]
[[package]]
name = "litemap"
version = "0.8.0"
@ -565,6 +602,17 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_users"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
dependencies = [
"getrandom",
"libredox",
"thiserror",
]
[[package]]
name = "regex"
version = "1.11.1"
@ -701,9 +749,11 @@ name = "shrupl"
version = "0.1.0"
dependencies = [
"clap",
"dirs-next",
"env_logger",
"log",
"serde",
"serde_json",
"ureq",
]
@ -753,6 +803,26 @@ dependencies = [
"syn",
]
[[package]]
name = "thiserror"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "time"
version = "0.3.41"
@ -898,6 +968,28 @@ dependencies = [
"rustls-pki-types",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.52.0"

View file

@ -6,9 +6,11 @@ description = "ShrUpl is a tool to upload files to a Sharry Instance through a p
[dependencies]
clap = { version = "4.5.38", features = ["derive"] }
dirs-next = "2.0.0"
env_logger = "0.11.8"
log = "0.4.27"
serde = { version = "1.0.219", features = ["derive"] }
serde_json = "1.0.140"
ureq = { version = "3.0.11", features = ["json"] }
[profile.release]

49
src/appstate.rs Normal file
View file

@ -0,0 +1,49 @@
use std::{
fs,
io::{self, Write},
path::Path,
};
use log::{debug, trace};
use serde::{Deserialize, Serialize};
use super::{
cli::Cli,
sharry::{Alias, File, Share},
};
#[derive(Serialize, Deserialize, Debug)]
pub struct AppState {
alias: Alias,
share: Share,
files: Vec<File>,
}
impl AppState {
fn load(file_name: impl AsRef<Path>) -> io::Result<Self> {
let content = fs::read_to_string(file_name)?;
let state = serde_json::from_str(&content).map_err(io::Error::other)?;
Ok(state)
}
fn save(&self, file_name: impl AsRef<Path>) -> io::Result<()> {
let json = serde_json::to_string_pretty(self).map_err(io::Error::other)?;
let mut file = fs::File::create(file_name)?;
file.write_all(json.as_bytes())?;
Ok(())
}
pub fn try_resume(args: &Cli) -> Option<Self> {
let file_name = dirs_next::cache_dir()?
.join("shrupl")
.join(format!("{}.json", args.get_hash()));
trace!("loading from {}", file_name.display());
Self::load(&file_name)
.inspect_err(|e| debug!("could not resume from {}: {e}", file_name.display()))
.ok()
}
}

View file

@ -1,15 +1,18 @@
use std::time::Duration;
use std::{
hash::{DefaultHasher, Hash, Hasher},
time::Duration,
};
use clap::{Parser, builder::PossibleValuesParser};
use super::sharry::{File, Alias, Uri, NewShareRequest};
use super::sharry::{Alias, File, NewShareRequest, Uri};
#[derive(Parser, Debug, Hash)]
#[command(version, about, long_about = None)]
pub struct Cli {
/// Timeout in seconds for HTTP actions (set 0 or invalid to disable)
#[arg(
short, long,
short, long,
default_value = "10", value_name = "SECS",
value_parser = parse_seconds,
)]
@ -70,4 +73,18 @@ impl Cli {
pub fn get_share_request(&self) -> NewShareRequest {
NewShareRequest::new(&self.name, self.description.as_ref(), self.max_views)
}
pub fn get_hash(&self) -> String {
let file_refs = {
let mut refs: Vec<_> = self.files.iter().map(File::get_path).collect();
refs.sort_unstable();
refs
};
let mut hasher = DefaultHasher::new();
(self.get_alias(), file_refs).hash(&mut hasher);
format!("{:x}", hasher.finish())
}
}

View file

@ -1,3 +1,4 @@
mod appstate;
mod cli;
mod sharry;
@ -5,6 +6,7 @@ use clap::Parser;
use log::{error, info};
use ureq::Agent;
use appstate::AppState;
use cli::Cli;
use sharry::Share;
@ -20,6 +22,10 @@ fn main() {
.build()
.into();
if let Some(state) = AppState::try_resume(&args) {
info!("state: {state:?}");
}
let alias = args.get_alias();
let share = Share::create(&agent, &alias, args.get_share_request()).unwrap();
info!("share: {share:?}");

View file

@ -1,11 +1,12 @@
use std::fmt::{Debug, Display};
use log::debug;
use serde::{Deserialize, Serialize};
use ureq::RequestBuilder;
use super::api::Uri;
#[derive(Debug, Hash)]
#[derive(Serialize, Deserialize, Debug, Hash)]
pub struct Alias {
pub(super) api_uri: String,
pub(super) id: String,

View file

@ -9,6 +9,7 @@ use std::{
};
use log::{debug, error};
use serde::{Deserialize, Serialize};
use ureq::{Error::Other, http::StatusCode};
use super::{
@ -17,7 +18,7 @@ use super::{
};
pub use chunks::{Chunk, FileChunks};
#[derive(Debug, Clone)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct File {
abs_path: PathBuf,
name: String,
@ -52,6 +53,10 @@ impl File {
})
}
pub fn get_path(&self) -> &Path {
&self.abs_path
}
pub fn create(
self,
http: &ureq::Agent,

View file

@ -1,11 +1,12 @@
use log::debug;
use serde::{Deserialize, Serialize};
use super::{
alias::{Alias, SharryAlias},
api::{NewShareRequest, NewShareResponse, NotifyShareResponse},
};
#[derive(Debug)]
#[derive(Serialize, Deserialize, Debug)]
pub struct Share {
pub(super) id: String,
}