web: worker-route WBLOCK/SAVEALL/ARCHIVE; close the follow-up review

WBLOCK, SAVEALL, and web ARCHIVE now serialize through the Web Worker
like SAVE/AUTOSAVE: prepare on the main thread, writer pass on the
worker, inline fallback on any worker failure. SAVEALL clears each
tab's dirty flag under the same unchanged-tab race guard the single
save uses; ARCHIVE assembles the ZIP in the completion handler so the
transmittal matches the snapshot taken at command time.

The review of the previous fix commit found the collision refusal
still REPLACED the registry bytes — the exact silent retargeting it
was meant to prevent. The refusal now keeps the old registration, the
extraction settings picker reports refused picks in the wizard's error
slot (previously silent, and the stale collision flag could surface as
a wrong-file warning on an unrelated browse), and the xref registry's
same-name ambiguity is documented as a browser fundamental (native
distinguishes by folder): newest registration wins consistently for
resolution, ARCHIVE, and XRELOAD — matching what the drawing displays.
Also: the Quit pending-close survives a successful web tab-save
(continue the quit instead of dropping it), the last ZIP64 sentinel
(central size) is rejected like the other four, and the new behaviors
gained regression tests (collision keeps old bytes, registry eviction,
including the deadlock fix for the guard-scoping that test exposed).
This commit is contained in:
Afonsop committed 2026-09-18 02:27:16 +01:00
1 parent 6f429f2416
commit b635d56c00
7 files changed
+415 -83

No files matched your search

+51
View File
@@ -1367,6 +1367,25 @@ pub(super) struct PendingExternalChange {
set_current_path: bool,
}
/// One tab's slot in a web SAVEALL round (`saveall_web`): the tab identity,
/// download name and race-guard markers snapshot when serialization started,
/// plus the writer result — the future fills `result` in before the
/// completion message is built. The web counterpart of native's
/// `SaveOutcome`, minus the path/continuation bookkeeping SAVEALL never had.
#[derive(Debug, Clone)]
#[cfg(target_arch = "wasm32")]
pub struct WebSaveallEntry {
tab_id: u64,
path: PathBuf,
filename: String,
ext: String,
version: acadrust::DxfVersion,
geometry_epoch: u64,
edit_revision: u64,
camera_generation: u64,
result: Result<Vec<u8>, String>,
}
#[derive(Debug, Clone)]
#[cfg(not(target_arch = "wasm32"))]
pub struct SaveOutcome {
@@ -2323,6 +2342,38 @@ pub enum Message {
camera_generation: u64,
result: Result<Vec<u8>, String>,
},
/// Web WBLOCK: the serializer worker (or the inline fallback) produced
/// the block document bytes; download them under `filename`, then run
/// the same command-line bookkeeping as `WblockWriteFinished`.
#[cfg(target_arch = "wasm32")]
WebWblockSerialized {
block_name: String,
path: std::path::PathBuf,
filename: String,
result: Result<Vec<u8>, String>,
},
/// Web SAVEALL round completion: one entry per tab serialized on the
/// worker (or the inline fallback). Downloads fire per entry; dirty
/// flags clear only for tabs whose serialized snapshot is still current
/// (the same race guard a single web Save uses).
#[cfg(target_arch = "wasm32")]
WebSaveallSerialized {
skipped: usize,
results: Vec<WebSaveallEntry>,
},
/// Web ARCHIVE/ETRANSMIT completion: the serializer worker (or the
/// inline fallback) produced the drawing bytes; assemble the transmittal
/// ZIP from the dependencies collected at command time, download it and
/// report — including the skipped-dependency lines.
#[cfg(target_arch = "wasm32")]
WebArchiveSerialized {
cmd: String,
zip_name: String,
filename: String,
deps: Vec<crate::io::zip::ZipEntry>,
skipped: Vec<String>,
result: Result<Vec<u8>, String>,
},
/// Retry the failed save after the other application releases the file.
#[cfg(not(target_arch = "wasm32"))]
SaveFileInUseRetry,