refactor(web): drop legacy thumb migration

Keep thumbnail storage forward-only. Old recent entries gain previews when their drawings are reopened.
This commit is contained in:
Hakan Seven 2026-07-29 01:11:17 +03:00
commit fc97104c81
2 changed files with 4 additions and 75 deletions

View file

@ -41,14 +41,7 @@ pub fn extract_bytes(bytes: &[u8], max_dim: u32) -> Option<RgbaImage> {
let start = usize::try_from(base).ok()?;
let total = preview_container_len(bytes.get(start..start.checked_add(20)?)?)?;
let container = bytes.get(start..start.checked_add(total)?)?;
extract_container(container, base, max_dim)
}
/// Decode a preview container read from a DWG at `file_offset`. Exposing this
/// narrow entry point lets browser callers use `Blob.slice()` to migrate old
/// recent files without copying the entire drawing into memory.
pub fn extract_container(container: &[u8], file_offset: u64, max_dim: u32) -> Option<RgbaImage> {
let (format, data) = parse_preview_container(container, file_offset)?;
let (format, data) = parse_preview_container(container, base)?;
let img = decode(format, data)?;
Some(downscale(img, max_dim.max(1)))
}

View file

@ -94,28 +94,12 @@ async fn read_blob(blob: &web_sys::Blob) -> Result<Vec<u8>, String> {
Ok(js_sys::Uint8Array::new(&buffer).to_vec())
}
/// Load a cached preview. Records created before thumbnail sidecars existed are
/// migrated by slicing only the DWG header and preview container from the OPFS
/// file; the potentially large drawing body is never copied or parsed.
pub async fn read_thumbnail(name: &str) -> Result<Option<Thumbnail>, String> {
let directory = recent_directory(false).await?;
if let Ok(bytes) = read_entry(&directory, &thumbnail_key(name)).await {
if let Some(thumbnail) = decode_thumbnail(bytes) {
return Ok(Some(thumbnail));
}
match read_entry(&directory, &thumbnail_key(name)).await {
Ok(bytes) => Ok(decode_thumbnail(bytes)),
Err(_) => Ok(None),
}
let file = get_file(&directory, &cache_key(name)).await?;
let Some(image) = extract_embedded_thumbnail(&file).await? else {
return Ok(None);
};
let encoded = encode_thumbnail(image);
let thumbnail = decode_thumbnail(encoded.clone())
.ok_or_else(|| "generated recent thumbnail is invalid".to_string())?;
// Migration caching is best-effort: a readable drawing should still show
// its preview even if quota pressure prevents writing the sidecar.
let _ = write_entry(&directory, &thumbnail_key(name), &encoded).await;
Ok(Some(thumbnail))
}
pub async fn remove(name: &str) -> Result<(), String> {
@ -196,54 +180,6 @@ fn decode_thumbnail(bytes: Vec<u8>) -> Option<Thumbnail> {
})
}
async fn extract_embedded_thumbnail(
file: &web_sys::File,
) -> Result<Option<dwg_thumbnailer::RgbaImage>, String> {
let header = read_file_range(file, 0, 0x11).await?;
if header.get(..2) != Some(b"AC") {
return Ok(None);
}
let Some(offset) = header
.get(0x0D..0x11)
.and_then(|bytes| bytes.try_into().ok())
.map(i32::from_le_bytes)
.filter(|offset| *offset > 0)
else {
return Ok(None);
};
let offset = offset as u64;
let container_header = read_file_range(file, offset, offset + 20).await?;
let Some(overall) = container_header
.get(16..20)
.and_then(|bytes| bytes.try_into().ok())
.map(u32::from_le_bytes)
.map(u64::from)
.filter(|size| *size > 0 && *size <= 64 * 1024 * 1024)
else {
return Ok(None);
};
let Some(end) = offset
.checked_add(36)
.and_then(|end| end.checked_add(overall))
else {
return Ok(None);
};
let container = read_file_range(file, offset, end).await?;
Ok(dwg_thumbnailer::extract_container(
&container,
offset,
THUMBNAIL_MAX_DIM,
))
}
async fn read_file_range(file: &web_sys::File, start: u64, end: u64) -> Result<Vec<u8>, String> {
let blob: &web_sys::Blob = file.as_ref();
let slice = blob
.slice_with_f64_and_f64(start as f64, end as f64)
.map_err(js_error)?;
read_blob(&slice).await
}
fn js_error(value: wasm_bindgen::JsValue) -> String {
value
.as_string()