web: restore deletes its snapshot by open identity, not name

Second review pass found the restore marker matched WebFileOpened by
display name: any same-named open finishing while the recovered one
was still queued deleted the only copy. The snapshot key now travels
with the queued file (tagged queue entries), the marker records the
open id assigned at dispatch, and success, failure, and cancel all
match that id. Cancelling an unrelated open no longer clears a
pending restore marker.

Also: the boot scan removes dead index rows (missing or zero-byte
snapshot files) that no other path could discard, and the drop
listener install only latches when the listeners really registered.

(cherry picked from commit c8777a857b)
This commit is contained in:
Afonsop authored and Hakan Seven committed 2026-10-12 12:02:04 +03:00
1 parent 3023cefea4
commit 7b467e16ea
5 files changed
+134 -67

No files matched your search

+9 -6
View File
@@ -927,11 +927,12 @@ pub(super) struct OpenCADStudio {
/// prompt still has to offer, one at a time.
#[cfg(target_arch = "wasm32")]
web_autosave_pending: Vec<crate::io::web_autosave::WebAutosaveEntry>,
/// The snapshot whose recovered open is queued: `(autosave key,
/// open name)`. The OPFS copy is the only one, so it is deleted only
/// once an open with exactly that name succeeds.
/// The snapshot whose recovered open is in flight: `(autosave key,
/// open id)`. The OPFS copy is the only one, so it is deleted only
/// once the open with exactly that id succeeds — identity, never the
/// display name (same-named files share one stored copy on web).
#[cfg(target_arch = "wasm32")]
web_autosave_consumed: Option<(String, String)>,
web_autosave_consumed: Option<(String, u64)>,
/// Autosave keys a web save wanted to remove while a snapshot round was
/// still writing (the round's late write would resurrect the snapshot
/// with a fresh mtime); the removes run when the round finishes.
@@ -2260,8 +2261,10 @@ pub enum Message {
FileDropped(PathBuf),
/// Web only: a drawing dragged onto the page — the DOM drop listener has
/// already read the bytes; this opens through the web-picker flow (#344).
/// The third field tags an autosave-restore file with its snapshot key so
/// the snapshot is deleted only when this exact open succeeds.
#[cfg(target_arch = "wasm32")]
WebFileDropped(String, Vec<u8>),
WebFileDropped(String, Vec<u8>, Option<String>),
/// Web only: Ctrl+V captured by a focused text field, whose iced-internal
/// paste is inert there — read the async clipboard instead (#346).
WebFieldPaste,
@@ -2337,7 +2340,7 @@ pub enum Message {
/// Web: the offered snapshot's bytes are in; queue them for the guarded
/// open poll. The OPFS copy is consumed only once that open succeeds.
#[cfg(target_arch = "wasm32")]
WebAutosaveBytes(String, Result<Vec<u8>, String>),
WebAutosaveBytes(String, String, Result<Vec<u8>, String>),
/// Web: one autosave round finished for all dirty tabs (serially).
#[cfg(target_arch = "wasm32")]
WebAutosaveSnapshotFinished(Result<(), String>),