app
Fusion - the Fusion 360 Bridge
Public Made by Adomby adom
Drive Autodesk Fusion 360 from the cloud via Adom Bridge: component libraries, IPC package generation, board layout, exports (STEP/Gerbers/BOM/CPL), fast APS cloud search, and parametric modeling.
master
Drew Owens
The mechanical layer on 1.12.8 with the restart fixes (1.13.0-dev.1, add-in 1.0.23)
2ef0220
15d ago
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
"""Files the bridge exe and this add-in share for mechanical writes (rust/bridge/src/mech.rs).
The exe validates, admits and journals every write; this add-in only executes it. Three small
files carry what the exe cannot observe from outside Fusion:
- session.json: this add-in session's ID and transaction-probe state, for capabilities and
the exe's session check. Trusted by the exe only while the Fusion process that wrote it runs.
- dispatch/<id>.claim: created exclusively before a write executes. The exe creates it only to
expire a dispatch it gave up on, so exactly one side wins and "never ran" stays provable.
- dispatch/<id>.result.json: the exact result, kept for the exe when its reply is lost.
"""
import json
import os
import re
import time
from .journal import storage_root
PROTOCOL = "exe-journal-1"
_DISPATCH_ID = re.compile(r"[0-9a-f]{32}")
def _write_atomically(path, data):
staged = path.with_name(path.name + ".tmp")
with open(staged, "wb") as stream:
stream.write(data)
stream.flush()
os.fsync(stream.fileno())
os.replace(staged, path)
def publish_session(session_id, source_version, transactions):
root = storage_root()
root.mkdir(parents=True, exist_ok=True)
_write_atomically(root / "session.json", json.dumps({
"protocol": PROTOCOL, "sessionId": session_id, "pid": os.getpid(), "startedAt": time.time(),
"sourceVersion": source_version, "transactions": transactions}).encode("utf-8"))
def dispatch_id(dispatch):
"""The exe's dispatch ID, or None. Never a path: 32 lowercase hex characters only."""
value = dispatch.get("dispatchId") if isinstance(dispatch, dict) else None
return value if isinstance(value, str) and _DISPATCH_ID.fullmatch(value) else None
def claim(dispatch_id, document, args):
"""Win the dispatch before executing. False means the exe already expired it."""
folder = storage_root() / "dispatch"
folder.mkdir(parents=True, exist_ok=True)
try:
descriptor = os.open(folder / (dispatch_id + ".claim"), os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
except FileExistsError:
return False
# The claim is owned from here on; its contents only help the exe reconcile later.
try:
with os.fdopen(descriptor, "w", encoding="utf-8") as stream:
stream.write(json.dumps({"state": "started", "sessionId": args.get("sessionId"),
"operationId": args.get("operationId"), "observedDocument": document, "at": time.time()}))
stream.flush()
os.fsync(stream.fileno())
except (OSError, TypeError, ValueError):
pass
return True
def publish_result(dispatch_id, result):
folder = storage_root() / "dispatch"
_write_atomically(folder / (dispatch_id + ".result.json"),
json.dumps(result, sort_keys=True, separators=(",", ":"), allow_nan=False).encode("ascii"))