notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

commit 28af9c22720183179f5907ac421a79d3cf04b3b4
parent f050de6b7a6e2fc8b95bad571c536ea6e3165893
Author: William Casarin <jb55@jb55.com>
Date:   Fri, 10 Jan 2025 07:13:29 -0800

Merge 'image-cache: use sha256 hash of url for key'

Link: https://github.com/damus-io/notedeck/pull/631

Diffstat:
MCargo.lock | 1+
MCargo.toml | 1+
Mcrates/notedeck/Cargo.toml | 1+
Mcrates/notedeck/src/imgcache.rs | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++--
Mcrates/notedeck_chrome/src/app.rs | 5+++++
5 files changed, 61 insertions(+), 2 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -2505,6 +2505,7 @@ dependencies = [ "security-framework", "serde", "serde_json", + "sha2", "strum", "strum_macros", "tempfile", diff --git a/Cargo.toml b/Cargo.toml @@ -52,6 +52,7 @@ url = "2.5.2" urlencoding = "2.1.3" uuid = { version = "1.10.0", features = ["v4"] } security-framework = "2.11.0" +sha2 = "0.10.8" [profile.small] inherits = 'release' diff --git a/crates/notedeck/Cargo.toml b/crates/notedeck/Cargo.toml @@ -22,6 +22,7 @@ serde = { workspace = true } hex = { workspace = true } thiserror = { workspace = true } puffin = { workspace = true, optional = true } +sha2 = { workspace = true } [dev-dependencies] tempfile = { workspace = true } diff --git a/crates/notedeck/src/imgcache.rs b/crates/notedeck/src/imgcache.rs @@ -5,9 +5,13 @@ use poll_promise::Promise; use egui::ColorImage; use std::collections::HashMap; -use std::fs::File; +use std::fs::{create_dir_all, File}; +use hex::ToHex; +use sha2::Digest; use std::path; +use std::path::PathBuf; +use tracing::warn; pub type ImageCacheValue = Promise<Result<TextureHandle>>; pub type ImageCacheMap = HashMap<String, ImageCacheValue>; @@ -46,6 +50,9 @@ impl ImageCache { pub fn write(cache_dir: &path::Path, url: &str, data: ColorImage) -> Result<()> { let file_path = cache_dir.join(Self::key(url)); + if let Some(p) = file_path.parent() { + create_dir_all(p)?; + } let file = File::options() .write(true) .create(true) @@ -64,7 +71,51 @@ impl ImageCache { } pub fn key(url: &str) -> String { - base32::encode(base32::Alphabet::Crockford, url.as_bytes()) + let k: String = sha2::Sha256::digest(url.as_bytes()).encode_hex(); + PathBuf::from(&k[0..2]) + .join(&k[2..4]) + .join(k) + .to_string_lossy() + .to_string() + } + + /// Migrate from base32 encoded url to sha256 url + sub-dir structure + pub fn migrate_v0(&self) -> Result<()> { + for file in std::fs::read_dir(&self.cache_dir)? { + let file = if let Ok(f) = file { + f + } else { + // not sure how this could fail, skip entry + continue; + }; + if !file.path().is_file() { + continue; + } + let old_filename = file.file_name().to_string_lossy().to_string(); + let old_url = if let Some(u) = + base32::decode(base32::Alphabet::Crockford, &old_filename) + .and_then(|s| String::from_utf8(s).ok()) + { + u + } else { + warn!("Invalid base32 filename: {}", &old_filename); + continue; + }; + let new_path = self.cache_dir.join(Self::key(&old_url)); + if let Some(p) = new_path.parent() { + create_dir_all(p)?; + } + + if let Err(e) = std::fs::rename(file.path(), &new_path) { + warn!( + "Failed to migrate file from {} to {}: {:?}", + file.path().display(), + new_path.display(), + e + ); + } + } + Ok(()) } pub fn map(&self) -> &ImageCacheMap { diff --git a/crates/notedeck_chrome/src/app.rs b/crates/notedeck_chrome/src/app.rs @@ -207,6 +207,11 @@ impl Notedeck { let tabs = Tabs::new(None); let app_rect_handler = AppSizeHandler::new(&path); + // migrate + if let Err(e) = img_cache.migrate_v0() { + error!("error migrating image cache: {e}"); + } + Self { ndb, img_cache,