From 41212a7a15198e53d205252a02069a7dd6ddadeb Mon Sep 17 00:00:00 2001 From: Martin Fischer Date: Sun, 25 Oct 2026 09:08:01 +0100 Subject: initial commit --- src/report.rs | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 src/report.rs (limited to 'src/report.rs') diff --git a/src/report.rs b/src/report.rs new file mode 100644 index 0000000..d776469 --- /dev/null +++ b/src/report.rs @@ -0,0 +1,57 @@ +use std::{fs, io, path::Path}; + +use atrium_api::app::bsky::richtext::facet::Main as Facet; +use serde::{Serialize, de::DeserializeOwned}; + +pub(crate) struct Post { + pub text: String, + pub facets: Vec, + /// Images to upload before creating the post record. + pub images: Vec, +} + +pub(crate) struct PostImage { + pub data: Vec, + pub alt: String, +} + +pub(crate) trait Report: Sized { + type State: Default + DeserializeOwned + Serialize; + + const STATE_FILE: &'static str; + + async fn generate(state: Self::State) -> Result<(Vec, Self::State), String>; + + async fn report() -> Result<(Vec, impl FnOnce() -> Result<(), String>), String> { + let state_path = Path::new(Self::STATE_FILE); + let state = load_state(state_path)?; + let (posts, new_state) = Self::generate(state).await?; + Ok((posts, move || save_state(state_path, &new_state))) + } +} + +fn load_state(path: &Path) -> Result +where + T: Default + DeserializeOwned, +{ + match fs::read(path) { + Ok(data) => serde_json::from_slice(&data) + .map_err(|error| format!("failed to parse {}: {error}", path.display())), + Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(T::default()), + Err(error) => Err(format!("failed to read {}: {error}", path.display())), + } +} + +fn save_state(path: &Path, state: &T) -> Result<(), String> +where + T: Serialize, +{ + let data = serde_json::to_vec_pretty(state) + .map_err(|error| format!("failed to serialize {}: {error}", path.display()))?; + let temporary_path = path.with_extension("json.tmp"); + + fs::write(&temporary_path, data) + .map_err(|error| format!("failed to write {}: {error}", temporary_path.display()))?; + fs::rename(&temporary_path, path) + .map_err(|error| format!("failed to replace {}: {error}", path.display())) +} -- cgit v1.3.1