add localhost http post proxy support for onshape or other https -> http scenarios
This commit is contained in:
parent
ca3b515df5
commit
9bd0a4974d
7 changed files with 240 additions and 2 deletions
2
app.js
2
app.js
|
|
@ -281,7 +281,7 @@ function initModule(mod, file, dir) {
|
|||
logger.log({ module: file, dir });
|
||||
require_fresh(file)({
|
||||
// express functions added here show up at "/api/" url root
|
||||
api: api,
|
||||
api,
|
||||
adm: {
|
||||
setver(ver) { oversion = ver },
|
||||
crossOrigin(bool) { crossOrigin = bool }
|
||||
|
|
|
|||
172
docs/void/plan-face-provenance.md
Normal file
172
docs/void/plan-face-provenance.md
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
# Void Face Provenance Plan (Boundary-First, Split Faces)
|
||||
|
||||
## Goal
|
||||
|
||||
Track which portions of resulting solids come from which sketch extrude regions, including after union/subtract, while keeping storage compact and spline-ready.
|
||||
|
||||
## Decisions
|
||||
|
||||
1. Primary provenance is `boundary/region/surface-patch`, not raw triangle ownership.
|
||||
2. Triangle ownership is derived runtime index only (`tri -> surface_patch_id`) and can be rebuilt.
|
||||
3. Multi-source output faces must be split into multiple bounded surface patches so each patch has one canonical source region.
|
||||
4. Line/arc support ships first; segment model must support future spline kinds without schema redesign.
|
||||
|
||||
## Scope
|
||||
|
||||
In scope:
|
||||
|
||||
1. Extrude + boolean provenance tracking through rebuild pipeline.
|
||||
2. Face splitting by source-region boundaries.
|
||||
3. GeometryStore schema extension for stable patch-level IDs and source refs.
|
||||
4. Runtime mapping from picks (`face/edge`) to canonical patch and source region.
|
||||
|
||||
Out of scope (initial pass):
|
||||
|
||||
1. Native spline feature authoring.
|
||||
2. Long-lived persisted triangle provenance tables.
|
||||
3. Non-planar sketch-on-surface expansion beyond current behavior.
|
||||
|
||||
## Data Model Changes
|
||||
|
||||
Add/extend document `geometry_store` entities:
|
||||
|
||||
1. `segments[]`
|
||||
2. `kind: line | arc | spline`
|
||||
3. `geom`: kind-specific payload
|
||||
4. `sampled_polyline` (optional cache for hit testing/partitioning)
|
||||
|
||||
5. `boundaries[]`
|
||||
6. Ordered `segment_ids`
|
||||
7. `closed`, orientation, optional parent/child nesting
|
||||
|
||||
8. `regions[]`
|
||||
9. `outer_boundary_id`
|
||||
10. `hole_boundary_ids[]`
|
||||
11. `source`: canonical source ref (`profile:<sketch>:<profile>`)
|
||||
|
||||
12. New `surface_patches[]`
|
||||
13. `id`
|
||||
14. `surface_id` (geometric carrier face)
|
||||
15. `boundary_ids[]` (outer + holes)
|
||||
16. `source_region_id` (single canonical owner)
|
||||
17. `source_feature_id` (extrude feature)
|
||||
18. `solid_id`
|
||||
19. `status` (`direct`, `boolean-derived`, `rebound`)
|
||||
|
||||
20. New runtime-only `topology.patch_tri_index`
|
||||
21. Maps mesh triangles to `surface_patch_id` for selection/render acceleration.
|
||||
|
||||
## Kernel Boundary Changes (Manifold)
|
||||
|
||||
Current kernel adapter only round-trips positions/indices; relation metadata is dropped.
|
||||
|
||||
Planned update:
|
||||
|
||||
1. Preserve Manifold mesh relation fields where available (`runOriginalID`, `faceID`, related run metadata).
|
||||
2. Carry relation metadata through `extrudePolygons()` and `booleanMeshes()`.
|
||||
3. Emit relation-aware intermediate records to rebuild stage (not directly persisted).
|
||||
|
||||
This enables deterministic attribution from boolean output back to input generated solids/regions before patch splitting.
|
||||
|
||||
## Provenance Build Pipeline
|
||||
|
||||
### Stage A: Sketch Region Capture
|
||||
|
||||
1. Keep current closed-loop profile extraction for line/arc.
|
||||
2. Emit canonical `region_id = profile:<sketch>:<profile>`.
|
||||
3. Record region boundaries using generic segment schema (`line|arc` now, `spline` later).
|
||||
|
||||
### Stage B: Extrude Seed Patches
|
||||
|
||||
1. Extrude each selected sketch region.
|
||||
2. Seed cap/side patch candidates with direct source region refs.
|
||||
3. Preserve manifold relation fields in intermediate mesh record.
|
||||
|
||||
### Stage C: Boolean Attribution
|
||||
|
||||
1. Perform add/subtract/intersect with relation-carrying meshes.
|
||||
2. Build attribution map from output primitives/runs to source seed patches.
|
||||
3. Mark ambiguous/mixed carrier surfaces for partitioning.
|
||||
|
||||
### Stage D: Face Partitioning (Split Multi-Source Faces)
|
||||
|
||||
1. For each mixed carrier surface, project contributing source boundaries to surface-local space.
|
||||
2. Build planar arrangement, split into disjoint bounded cells.
|
||||
3. Assign each cell a single `source_region_id` by relation majority + geometric tie-break.
|
||||
4. Emit one `surface_patch` per bounded cell.
|
||||
|
||||
### Stage E: Runtime Topology Index
|
||||
|
||||
1. Build `tri -> surface_patch_id` map from patch partition output.
|
||||
2. Use map for selection hit resolution and hover highlighting.
|
||||
3. Rebuild index each solids rebuild; do not persist large triangle maps.
|
||||
|
||||
## Selection/Interaction Integration
|
||||
|
||||
1. Face pick resolves to `surface_patch_id` first, then `source_region_id`.
|
||||
2. Edge/boundary pick resolves to `boundary_id`/`segment_id` that belongs to a patch.
|
||||
3. Extrude-profile hover/highlight uses `source_region_id -> surface_patch[]` mapping.
|
||||
4. Remove fallback heuristics that infer provenance only from coarse `source.profile_keys`.
|
||||
|
||||
## Storage and Performance
|
||||
|
||||
1. Persist compact canonical graph (`segments/boundaries/regions/surface_patches`).
|
||||
2. Keep triangle-level maps runtime-only to avoid doc bloat and instability across remeshes.
|
||||
3. Cache partition signatures per carrier surface to avoid full repartition when unchanged.
|
||||
|
||||
## Migration Plan
|
||||
|
||||
### Phase 1: Schema and Adapters
|
||||
|
||||
1. Add `surface_patches` schema and runtime index container.
|
||||
2. Introduce generic segment schema (`kind + geom`) with current line/arc emitters.
|
||||
|
||||
### Phase 2: Kernel Metadata Plumbing
|
||||
|
||||
1. Extend solid kernel adapter to preserve manifold relation metadata.
|
||||
2. Pass relation metadata through worker/main rebuild paths.
|
||||
|
||||
### Phase 3: Patch Builder
|
||||
|
||||
1. Implement mixed-face detection.
|
||||
2. Implement local-space boundary arrangement and patch emission.
|
||||
3. Add deterministic patch IDs/signatures.
|
||||
|
||||
### Phase 4: Resolver Cutover
|
||||
|
||||
1. Switch face selection from coarse face groups to `surface_patch` entities.
|
||||
2. Update properties/tree hover mapping to patch/source-region links.
|
||||
|
||||
### Phase 5: Cleanup
|
||||
|
||||
1. Remove coarse provenance fallbacks once parity is validated.
|
||||
2. Keep compatibility reader for older docs without `surface_patches`.
|
||||
|
||||
## Validation Plan
|
||||
|
||||
Unit tests:
|
||||
|
||||
1. Region extraction determinism (line/arc).
|
||||
2. Mixed-face partitioning into disjoint bounded patches.
|
||||
3. Single-owner assignment per patch.
|
||||
4. Deterministic patch IDs under stable input.
|
||||
|
||||
Integration tests:
|
||||
|
||||
1. Two extrudes unioned: top face splits by source boundary and highlights per profile.
|
||||
2. Subtract operation: surviving walls/caps retain correct source region refs.
|
||||
3. Edit upstream sketch profile: downstream patch mapping updates without manual repair.
|
||||
4. Rebuild in worker vs main thread yields identical patch/source mapping.
|
||||
|
||||
Regression guardrails:
|
||||
|
||||
1. No persisted triangle tables in doc snapshots.
|
||||
2. No schema changes required to add spline segment kind later.
|
||||
3. Selection never reports mixed-source face entities.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
1. Every selectable resulting face area maps to exactly one `source_region_id`.
|
||||
2. Multi-source carrier faces are visibly and topologically split at source boundaries.
|
||||
3. Extrude profile hover/select maps accurately to resulting solid patches after booleans.
|
||||
4. GeometryStore stays compact and stable; triangle mapping is derived at runtime.
|
||||
0
mods/proxy/.debug
Normal file
0
mods/proxy/.debug
Normal file
0
mods/proxy/.electron
Normal file
0
mods/proxy/.electron
Normal file
54
mods/proxy/init.js
Normal file
54
mods/proxy/init.js
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
module.exports = async (server) => {
|
||||
|
||||
const { api, env, path, util } = server;
|
||||
|
||||
if (!(env.debug || env.electron)) {
|
||||
util.log('not a valid context for proxy');
|
||||
return;
|
||||
}
|
||||
|
||||
path.full({
|
||||
"/printer/print/start": proxy_post,
|
||||
"/server/files/upload": proxy_post,
|
||||
"/api/files/local": proxy_post,
|
||||
});
|
||||
|
||||
server.inject("kiri", "main.js");
|
||||
};
|
||||
|
||||
function proxy_post(req, res, next) {
|
||||
if (req.method === 'POST') {
|
||||
let { url, headers } = req;
|
||||
let chunks = [];
|
||||
let host = headers['x-host'];
|
||||
let apik = headers['x-api-key'] ?? '';
|
||||
let cont = headers['content-type'] ?? 'application/binary';
|
||||
req
|
||||
.on('data', data => chunks.push(data) )
|
||||
.on('end', () => {
|
||||
req.app.post = Buffer.concat(chunks);
|
||||
if (host) {
|
||||
fetch(host + url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': cont,
|
||||
'X-Api-Key': apik
|
||||
},
|
||||
body: req.app.post
|
||||
}).then(result => {
|
||||
console.log({ result });
|
||||
if (result.ok) {
|
||||
res.writeHead(200, 'OK');
|
||||
} else {
|
||||
res.writeHead(500, 'Failed to proxy');
|
||||
}
|
||||
res.end();
|
||||
});
|
||||
} else {
|
||||
console.log('drop proxy due to lack of host');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
}
|
||||
3
mods/proxy/main.js
Normal file
3
mods/proxy/main.js
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
self.kiri.load(api => {
|
||||
api.feature.proxy = true;
|
||||
}, 'Proxy');
|
||||
|
|
@ -247,7 +247,8 @@ function exportGCodeDialog(gcode, sections, info, names) {
|
|||
ajax = new XMLHttpRequest(),
|
||||
host = octo_host.value.toLowerCase(),
|
||||
apik = octo_apik.value,
|
||||
type = octo_type.value;
|
||||
type = octo_type.value,
|
||||
proxy = api.feature.proxy ? host : undefined;
|
||||
|
||||
if (host.indexOf("http") !== 0) {
|
||||
api.show.alert("host missing protocol (http:// or https://)");
|
||||
|
|
@ -262,6 +263,11 @@ function exportGCodeDialog(gcode, sections, info, names) {
|
|||
localSet('octo-apik', apik.trim());
|
||||
localSet('octo-type', type.trim());
|
||||
|
||||
if (proxy) {
|
||||
console.log('proxying request to', host);
|
||||
host = '';
|
||||
}
|
||||
|
||||
filename = $('print-filename').value + "." + fileext;
|
||||
form.append("file", getBlob(), filename);
|
||||
ajax.onreadystatechange = function() {
|
||||
|
|
@ -297,6 +303,9 @@ function exportGCodeDialog(gcode, sections, info, names) {
|
|||
} else {
|
||||
ajax.open("POST", host + "/api/files/local");
|
||||
}
|
||||
if (proxy) {
|
||||
ajax.setRequestHeader("X-Host", proxy);
|
||||
}
|
||||
if (apik) {
|
||||
ajax.setRequestHeader("X-Api-Key", apik);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue