app
Adom Desktop - Fusion 360 Bridge
Public Made by Adomby adom
Drive Autodesk Fusion 360 from the cloud via Adom Desktop: component libraries, IPC package generation, board layout, exports (STEP/Gerbers/BOM/CPL), fast APS cloud search, and parametric modeling.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
"""Adom Bridge — Fusion 360 Add-In.
Starts a localhost HTTP server on a background thread (port 8774).
Incoming commands are marshaled to the main Fusion thread via a CustomEvent,
so all Fusion API calls execute safely on the main thread.
"""
import adsk.core
import adsk.fusion
import traceback
# Module-level references kept alive for the add-in lifetime
_app = None
_ui = None
_custom_event = None
_event_handler = None
_http_thread = None
CUSTOM_EVENT_ID = "AdomBridgeCommandEvent"
class CommandEventHandler(adsk.core.CustomEventHandler):
"""Handles custom events fired from the HTTP background thread.
Each event's additionalInfo is a JSON string with {request_id, command, args}.
The handler dispatches to the appropriate command function, then stores
the result so the HTTP thread can return it.
"""
def __init__(self):
super().__init__()
def notify(self, args: adsk.core.CustomEventArgs):
try:
import json
from . import http_server
from .commands import dispatch_command
info = json.loads(args.additionalInfo)
request_id = info["request_id"]
command = info["command"]
cmd_args = info.get("args", {})
# Staleness check: if the HTTP waiter already timed out and
# bailed, skip the work entirely. Saves main-thread time on
# heavy exports whose caller already gave up.
if not http_server.is_request_alive(request_id):
adsk.core.Application.log(
f"AdomBridge: skipping stale request {request_id[:8]} ({command}) — HTTP waiter gone"
)
return
try:
result = dispatch_command(_app, command, cmd_args)
except Exception as e:
result = {"success": False, "error": f"Command error: {e}\n{traceback.format_exc()}"}
http_server.set_result(request_id, result)
except Exception:
traceback.print_exc()
def run(context):
"""Called by Fusion 360 when the add-in starts."""
global _app, _ui, _custom_event, _event_handler, _http_thread
try:
_app = adsk.core.Application.get()
_ui = _app.userInterface
# Register the custom event for thread marshaling
_custom_event = _app.registerCustomEvent(CUSTOM_EVENT_ID)
_event_handler = CommandEventHandler()
_custom_event.add(_event_handler)
# Start the HTTP server on a background daemon thread
from . import http_server
_http_thread = http_server.start(CUSTOM_EVENT_ID, _app)
# Log to the Text Commands palette (non-blocking)
adsk.core.Application.log(f"Adom Bridge add-in started (port 8774)")
except Exception:
# Only use messageBox for errors — worth blocking to show the user
if _ui:
_ui.messageBox(f"Adom Bridge failed to start:\n{traceback.format_exc()}")
def stop(context):
"""Called by Fusion 360 when the add-in stops."""
global _app, _ui, _custom_event, _event_handler, _http_thread
try:
# Stop HTTP server
from . import http_server
http_server.stop()
# Unregister custom event
if _app and _custom_event:
_app.unregisterCustomEvent(CUSTOM_EVENT_ID)
_custom_event = None
_event_handler = None
_http_thread = None
except Exception:
if _ui:
_ui.messageBox(f"Adom Bridge stop error:\n{traceback.format_exc()}")