the avatar sweep keeps an avatar's sizes
Signed-off-by: dawn <90008@klbr.net>
71 unmodified lines7273747576777879808182838485868788237 unmodified linesExpand all326327328329321330331332333325334335336337338301 unmodified linesExpand all71 unmodified lines self.avatar_cid.as_deref()?, self.avatar_ext.as_deref()? )) }
/// the original, when it was small enough to keep, and the sizes made of it fn cached_avatar(&self) -> impl Iterator<Item = String> { let sized = self.avatar_cid.iter().flat_map(|cid| { crate::xrpc::social::AVATAR_SIZES .map(|size| crate::xrpc::social::sized_avatar(cid, size)) }); self.avatar_file().into_iter().chain(sized) }}
/// what a generation answers from the cache. verification times and failures don't countpub(crate) fn served_digest(stored: &StoredHandles) -> String {237 unmodified linesExpand all .await}
/// generations link their own copies, so removing one here is safe.fn sweep_avatars(avatars: &Path, stored: &StoredHandles) {pub(super) fn sweep_avatars(avatars: &Path, stored: &StoredHandles) { let kept: BTreeSet<String> = stored .entries .values() .filter_map(StoredHandle::avatar_file) .flat_map(StoredHandle::cached_avatar) .collect(); let Ok(entries) = std::fs::read_dir(avatars) else { return; };301 unmodified linesExpand all12334567969 unmodified linesExpand all97797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025547 unmodified linesExpand alluse super::handles::{ AUTHOR_REVERIFY_SECS, FailedPublish, Fetched, Named, StoredHandle, profile_of, published_description, refresh_handles_with, verify_unseen_with, published_description, refresh_handles_with, sweep_avatars, verify_unseen_with,};use super::*;use crate::config::IndexConfig;use crate::datastore::{Datastore, schema};969 unmodified linesExpand all );}
#[tokio::test]async fn an_avatar_cached_before_sizes_keeps_them_through_every_sync() { let root = tempfile::tempdir().unwrap(); let avatars = root.path().join("avatars"); let endpoint = url::Url::parse("https://pds.example.test/").unwrap(); let earlier = encoded(image::RgbImage::new(64, 64).into(), image::ImageFormat::Png); let cid = blob_cid(&earlier); std::fs::create_dir_all(&avatars).unwrap(); std::fs::write(avatars.join(format!("{cid}.png")), &earlier).unwrap(); std::fs::write(avatars.join("bafkreigone.png"), b"an avatar nobody names").unwrap(); let mut stored = StoredHandles::default(); let cached = fake_pds( BTreeMap::from([("org.tangled.actor.profile", avatar_ref(&cid))]), None, ); for sync in 0..2 { let found = profile_of(&cached, &avatars, "did:plc:verified", &endpoint) .await .unwrap(); let (avatar_cid, avatar_ext) = found.avatar.unzip(); stored.entries.insert( "did:plc:verified".into(), StoredHandle { handle: "ptr.pet".into(), verified_at_unix: sync, avatar_cid, avatar_ext, profile: None, }, ); sweep_avatars(&avatars, &stored); assert_eq!( sized(&avatars, &cid), vec![(42, 42), (96, 96), (192, 192)], "sync {sync}" ); assert!(avatars.join(format!("{cid}.png")).is_file()); assert!(!avatars.join("bafkreigone.png").exists()); }}
#[tokio::test]async fn the_tangled_profile_is_kept_within_the_lexicon() { use http::StatusCode; use serde_json::json; let root = tempfile::tempdir().unwrap();547 unmodified linesExpand all