forked from 1b-agent/opencadstudio-upstream
web: XREFs, data links & extraction, ARCHIVE transmittals, worker-side saves
The last four big web-vs-desktop gaps.
XREFs: XATTACH reads the picked drawing's bytes and registers them
name-keyed (the image/PDF-underlay pattern), pre-parses on the web
worker, and the commit merge produces the same xref block flow as
native. Opened drawings resolve xrefs from the registry (trailing-name
match) before cache build; unresolved references produce ONE warning
listing the names and the fix — drop the referenced files on the page
(drops and picker opens now register their bytes) and reopen or
XRELOAD. XRELOAD works off the registry on unsaved drawings too.
Data Link & Extraction: spreadsheet links read picked xlsx/csv bytes
(calamine from slices / CSV from string) through a session registry,
so preview, refresh, and table-insert work on web; extraction takes
external drawings via a multi-file picker parsed on the worker, and
outputs CSV/TXT/.dxex via download_bytes. The disabled 'Add folder'
button explains why.
ARCHIVE/ETRANSMIT: assembles the drawing plus registered images, PDF
underlays, and session plot tables into a deterministic ZIP (minimal
writer over flate2 — no new dependency) delivered as
{stem}_transmit.zip; skipped dependencies are reported by name.
Save/autosave off the UI thread: the parse worker gains a serialize
action (protocol v5) — the document is prepared once on the main
thread (clone, styles, dimension bake), then the DWG/DXF writer pass,
the dominant cost, runs on the worker; any worker failure falls back
to inline serialization with the identical shared implementation.
The save path also clears the dirty flag only when the tab didn't
change mid-write, and the runtime-fields sidecar now carries
graphic_data, fixing a pre-existing loss of raw DWG round-trip bytes
on web-opened documents.
This commit is contained in:
1 parent
c643a10ed9
commit
2e1006348b
44 files changed
+2564
-330
No files matched your search
@@ -8,23 +8,11 @@ use sha2::{Digest, Sha256};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
const HASH_MARKER: &str = "\nreport-source-sha256:";
|
||||
const PROTOCOL_VERSION: u16 = 4;
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
struct EntityRuntimeFields {
|
||||
handle: u64,
|
||||
linetype_handle: Option<u64>,
|
||||
color_book_handle: Option<u64>,
|
||||
face_visual_style_handle: Option<u64>,
|
||||
edge_visual_style_handle: Option<u64>,
|
||||
material_flags: u8,
|
||||
material_handle: Option<u64>,
|
||||
shadow_flags: u8,
|
||||
plotstyle_flags: u8,
|
||||
plotstyle_handle: Option<u64>,
|
||||
entity_mode: Option<u8>,
|
||||
has_ds_data: bool,
|
||||
}
|
||||
/// Version of the shared worker wire format (see `ocs_save`). Both sides of
|
||||
/// the boundary — this crate and the app's `io::web_worker` — check payloads
|
||||
/// against it.
|
||||
const PROTOCOL_VERSION: u16 = ocs_save::PROTOCOL_VERSION;
|
||||
|
||||
/// Parse DWG/DXF on a dedicated browser worker and return a compact serialized
|
||||
/// document. The main wasm instance only deserializes and installs it, so the
|
||||
@@ -147,6 +135,28 @@ pub fn sha256_document(bytes: Uint8Array) -> String {
|
||||
sha256_document_bytes(&bytes.to_vec())
|
||||
}
|
||||
|
||||
/// Serialize an already-prepared document to DWG/DXF bytes on the dedicated
|
||||
/// browser worker, so the expensive writer pass (bit-level DWG encoding /
|
||||
/// ASCII DXF formatting) never occupies the UI thread. `encoded_document` is
|
||||
/// the shared `ocs_save` request payload (document + runtime-field sidecar +
|
||||
/// target extension); the reply is the shared response payload (protocol
|
||||
/// version + `Result<bytes, error text>`). The main wasm instance only decodes
|
||||
/// the result — the save-side counterpart of [`parse_document`].
|
||||
#[wasm_bindgen]
|
||||
pub fn serialize_document(
|
||||
encoded_document: Uint8Array,
|
||||
report_stage: &Function,
|
||||
) -> Result<Uint8Array, JsValue> {
|
||||
console_error_panic_hook::set_once();
|
||||
report_stage.call1(&JsValue::NULL, &JsValue::from_str("decode document"))?;
|
||||
let (document, ext) = ocs_save::decode_request(&encoded_document.to_vec())?;
|
||||
report_stage.call1(&JsValue::NULL, &JsValue::from_str("serialize drawing"))?;
|
||||
let result = ocs_save::serialize_document(&document, &ext);
|
||||
report_stage.call1(&JsValue::NULL, &JsValue::from_str("copy output"))?;
|
||||
let encoded = ocs_save::encode_response(result)?;
|
||||
Ok(Uint8Array::from(encoded.as_slice()))
|
||||
}
|
||||
|
||||
fn report_fingerprint_needed(stats: &acadrust::ReadStats) -> bool {
|
||||
stats.recovered() || stats.skipped_source_records > 0 || !stats.stream_completed
|
||||
}
|
||||
@@ -178,33 +188,7 @@ fn encode_result(
|
||||
let runtime_fields = result
|
||||
.as_ref()
|
||||
.ok()
|
||||
.map(|outcome| {
|
||||
outcome
|
||||
.document
|
||||
.entities()
|
||||
.map(|entity| {
|
||||
let common = entity.common();
|
||||
EntityRuntimeFields {
|
||||
handle: common.handle.value(),
|
||||
linetype_handle: common.linetype_handle.map(|handle| handle.value()),
|
||||
color_book_handle: common.color_book_handle.map(|handle| handle.value()),
|
||||
face_visual_style_handle: common
|
||||
.face_visual_style_handle
|
||||
.map(|handle| handle.value()),
|
||||
edge_visual_style_handle: common
|
||||
.edge_visual_style_handle
|
||||
.map(|handle| handle.value()),
|
||||
material_flags: common.material_flags,
|
||||
material_handle: common.material_handle.map(|handle| handle.value()),
|
||||
shadow_flags: common.shadow_flags,
|
||||
plotstyle_flags: common.plotstyle_flags,
|
||||
plotstyle_handle: common.plotstyle_handle.map(|handle| handle.value()),
|
||||
entity_mode: common.entity_mode,
|
||||
has_ds_data: common.has_ds_data,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.map(|outcome| ocs_save::extract_entity_runtime_fields(&outcome.document))
|
||||
.unwrap_or_default();
|
||||
let encoded = bincode::serialize(&(
|
||||
PROTOCOL_VERSION,
|
||||
|
||||
Reference in new issue
Block a user