mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
Rename ifcviewer-autodesk connector to bonsaiviewer-autodesk
Follows the host viewer's rename to Bonsai Viewer: directory, Python package, entry point, PyInstaller spec, keyring service, and on-disk config/cache paths all use the bonsaiviewer-autodesk name. CI workflow filename and path filters updated to match. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+7
-7
@@ -1,15 +1,15 @@
|
||||
name: Build IfcViewer Autodesk Connector
|
||||
name: Build Bonsai Viewer Autodesk Connector
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
paths:
|
||||
- 'src/ifcviewer-autodesk/**'
|
||||
- '.github/workflows/build-ifcviewer-autodesk.yml'
|
||||
- 'src/bonsaiviewer-autodesk/**'
|
||||
- '.github/workflows/build-bonsaiviewer-autodesk.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'src/ifcviewer-autodesk/**'
|
||||
- '.github/workflows/build-ifcviewer-autodesk.yml'
|
||||
- 'src/bonsaiviewer-autodesk/**'
|
||||
- '.github/workflows/build-bonsaiviewer-autodesk.yml'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: src/ifcviewer-autodesk
|
||||
working-directory: src/bonsaiviewer-autodesk
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
@@ -64,5 +64,5 @@ jobs:
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: autodesk-${{ matrix.os_label }}-${{ matrix.arch }}
|
||||
path: src/ifcviewer-autodesk/dist/autodesk-${{ matrix.os_label }}-${{ matrix.arch }}.zip
|
||||
path: src/bonsaiviewer-autodesk/dist/autodesk-${{ matrix.os_label }}-${{ matrix.arch }}.zip
|
||||
if-no-files-found: error
|
||||
+3
-3
@@ -129,6 +129,6 @@ src/ifcopenshell-python/ifcopenshell/express/*.exp.cache.dat
|
||||
*.py.tmp*
|
||||
*.json.tmp*
|
||||
|
||||
# ifcviewer-autodesk connector build artifacts
|
||||
/src/ifcviewer-autodesk/build/
|
||||
/src/ifcviewer-autodesk/dist/
|
||||
# bonsaiviewer-autodesk connector build artifacts
|
||||
/src/bonsaiviewer-autodesk/build/
|
||||
/src/bonsaiviewer-autodesk/dist/
|
||||
|
||||
+56
-56
@@ -1,13 +1,13 @@
|
||||
# IfcViewer cloud connectors
|
||||
# Bonsai Viewer cloud connectors
|
||||
|
||||
IfcViewer will have the capability to load and save projects and models from a
|
||||
Bonsai Viewer will have the capability to load and save projects and models from a
|
||||
cloud platform. Later on, there will be other resources stored on cloud
|
||||
platforms too, such as issues, clash results, and so on, but this behaviour is
|
||||
not currently designed.
|
||||
|
||||
Due to the variety of cloud platforms, the IfcViewer itself will depend on
|
||||
Due to the variety of cloud platforms, the Bonsai Viewer itself will depend on
|
||||
a "connector" to integrate with each platform. The connector is a separate
|
||||
application which will communicate to and from the IfcViewer.
|
||||
application which will communicate to and from the Bonsai Viewer.
|
||||
|
||||
The following types of resources may be managed with a connector:
|
||||
|
||||
@@ -18,7 +18,7 @@ The following types of resources may be managed with a connector:
|
||||
|
||||
## Communication protocol
|
||||
|
||||
The IfcViewer launches one connector process per session, on first use, and
|
||||
The Bonsai Viewer launches one connector process per session, on first use, and
|
||||
keeps it alive for the duration of the session. This allows the connector to
|
||||
maintain authentication tokens, browse state, in-flight downloads, and caches
|
||||
in memory across calls without re-authenticating on every request.
|
||||
@@ -28,18 +28,18 @@ Communication is over stdio using newline-delimited JSON-RPC 2.0:
|
||||
- Requests and responses are single-line JSON objects on the connector's
|
||||
stdin/stdout. Each message is terminated by a single `\n`.
|
||||
- The connector must not emit literal newlines inside a JSON message.
|
||||
- The connector may write arbitrary diagnostic output to stderr; the IfcViewer
|
||||
- The connector may write arbitrary diagnostic output to stderr; the Bonsai Viewer
|
||||
will not parse it.
|
||||
|
||||
The IfcViewer shuts a connector down by closing its stdin. The connector should
|
||||
exit cleanly. If it does not exit within a few seconds, the IfcViewer will
|
||||
The Bonsai Viewer shuts a connector down by closing its stdin. The connector should
|
||||
exit cleanly. If it does not exit within a few seconds, the Bonsai Viewer will
|
||||
terminate it.
|
||||
|
||||
## Connector scope
|
||||
|
||||
The IfcViewer has minimal knowledge about connectors. IfcViewer only knows how
|
||||
The Bonsai Viewer has minimal knowledge about connectors. Bonsai Viewer only knows how
|
||||
to work with local files. If it detects that a project or model is not local,
|
||||
it will invoke a connector. The connector's job is to resolve the IfcViewer's
|
||||
it will invoke a connector. The connector's job is to resolve the Bonsai Viewer's
|
||||
request back into a local file and cloud metadata. The connector must not
|
||||
modify the file in any way.
|
||||
|
||||
@@ -52,7 +52,7 @@ This makes connectors very flexible.
|
||||
A single project may have different resources coming from different connectors.
|
||||
For example, some models might be on one platform, and some projects hosted on
|
||||
another platform. The permissions regarding model access can be quite granular
|
||||
and therefore managed by the platform, and not IfcViewer.
|
||||
and therefore managed by the platform, and not Bonsai Viewer.
|
||||
|
||||
When a connector returns a local file, that file is required to be the sole
|
||||
child in its directory. This is because there may be adjacent temporary files,
|
||||
@@ -140,9 +140,9 @@ Note that cloud metadata (filename, cloud ID, revision, date modified, etc) is
|
||||
not specified nor stored in the .ifcfed. This is to be returned by the
|
||||
connector when requested.
|
||||
|
||||
The IfcViewer will display all returned cloud metadata as simple text strings.
|
||||
The Bonsai Viewer will display all returned cloud metadata as simple text strings.
|
||||
However some keys are treated specially and shown in more places in the
|
||||
IfcViewer UI for convenience:
|
||||
Bonsai Viewer UI for convenience:
|
||||
|
||||
- author
|
||||
- revision
|
||||
@@ -157,7 +157,7 @@ perfectly acceptable to give the user choice on whether to download all or some
|
||||
models, or use cache (even if outdated). The user can always reopen the project
|
||||
later.
|
||||
|
||||
1. The user presses a button in the IfcViewer UI that says "Open from Cloud"
|
||||
1. The user presses a button in the Bonsai Viewer UI that says "Open from Cloud"
|
||||
2. The user chooses a connector.
|
||||
3. The `pull_ifcfed_interactive` method is sent to the connector.
|
||||
```json
|
||||
@@ -171,8 +171,8 @@ later.
|
||||
```json
|
||||
{ "jsonrpc": "2.0", "id": "0", "result": { "path": "/path/to/project/file.ifcfed" } }
|
||||
```
|
||||
5. The IfcViewer loads the `path`. This constitutes a fresh session.
|
||||
6. The IfcViewer calls `pull_models`:
|
||||
5. The Bonsai Viewer loads the `path`. This constitutes a fresh session.
|
||||
6. The Bonsai Viewer calls `pull_models`:
|
||||
```json
|
||||
{ "jsonrpc": "2.0", "id": "1", "method": "pull_models", "params": [
|
||||
{ "display_name": ..., "id": ..., "source": ..., },
|
||||
@@ -185,7 +185,7 @@ later.
|
||||
{ "jsonrpc": "2.0", "id": "1", "result": [
|
||||
{ "path": "/path/to/foo.ifc" },
|
||||
{
|
||||
"path": "/path/to/model.ifc", # Used to load the model in IfcViewer
|
||||
"path": "/path/to/model.ifc", # Used to load the model in Bonsai Viewer
|
||||
"metadata": { "revision": "B", "date": "2nd Oct 2025" ... }, # Optional, used to display stats
|
||||
},
|
||||
null, # If skipped, error, etc
|
||||
@@ -193,8 +193,8 @@ later.
|
||||
...
|
||||
] }
|
||||
```
|
||||
8. The IfcViewer may call another connector with more models to be downloaded.
|
||||
9. The IfcViewer will load the downloaded models as regular files. Typically this will also result in the IfcViewer reading / writing a cache (e.g. .ifcview) alongside this file, but it is not expected that the connector will know or care about this.
|
||||
8. The Bonsai Viewer may call another connector with more models to be downloaded.
|
||||
9. The Bonsai Viewer will load the downloaded models as regular files. Typically this will also result in the Bonsai Viewer reading / writing a cache (e.g. .ifcview) alongside this file, but it is not expected that the connector will know or care about this.
|
||||
|
||||
## Sync cloud to local
|
||||
|
||||
@@ -205,8 +205,8 @@ the project has any cloud resources: a `.ifcfed.manifest` adjacent to the
|
||||
.ifcfed-refresh phase and the model-refresh phase are independent — only the
|
||||
first requires a manifest.
|
||||
|
||||
1. The user presses a button in the IfcViewer UI that says "Sync Cloud to Local"
|
||||
2. IfcViewer reads the .ifcfed.manifest and invokes the relevant connector with the manifest data with the `pull_ifcfed` method:
|
||||
1. The user presses a button in the Bonsai Viewer UI that says "Sync Cloud to Local"
|
||||
2. Bonsai Viewer reads the .ifcfed.manifest and invokes the relevant connector with the manifest data with the `pull_ifcfed` method:
|
||||
```json
|
||||
{ "jsonrpc": "2.0", "id": "0", "method": "pull_ifcfed", "params": {
|
||||
"connector": "mycompany", "version": "2", "url": ...
|
||||
@@ -223,16 +223,16 @@ first requires a manifest.
|
||||
4. Continue with step 5 of the "Open from cloud" workflow.
|
||||
|
||||
If no `.ifcfed.manifest` is present, steps 2–4 are skipped. The .ifcfed on
|
||||
disk is used as-is, and the IfcViewer continues from step 6 of the
|
||||
disk is used as-is, and the Bonsai Viewer continues from step 6 of the
|
||||
"Open from cloud" workflow (calling `pull_models` for any cloud-sourced models
|
||||
referenced in the .ifcfed).
|
||||
|
||||
Additionally, if the .ifcfed returned in step 3 is unchanged from the one
|
||||
already loaded (e.g. the connector served a cached copy because the cloud
|
||||
revision matched), the IfcViewer skips step 5 as well and continues from
|
||||
revision matched), the Bonsai Viewer skips step 5 as well and continues from
|
||||
step 6, preserving the current session rather than forcing an unnecessary
|
||||
fresh one. How "unchanged" is determined (byte equality, hash, mtime, etc.)
|
||||
is left to the IfcViewer.
|
||||
is left to the Bonsai Viewer.
|
||||
|
||||
## Save as to cloud
|
||||
|
||||
@@ -240,7 +240,7 @@ This pushes a .ifcfed to a fresh location on a cloud platform, chosen by the
|
||||
user. It is the "Save As" equivalent and is the only way to first establish a
|
||||
cloud location for a project that does not yet have a `.ifcfed.manifest`.
|
||||
|
||||
1. The user presses a button in the IfcViewer UI that says "Save As to Cloud"
|
||||
1. The user presses a button in the Bonsai Viewer UI that says "Save As to Cloud"
|
||||
2. The user chooses a connector.
|
||||
3. The `push_ifcfed_interactive` method is called with the path to the .ifcfed. The connector should treat this as a temporary .ifcfed file, as the real project may or may not be actually saved on disk.
|
||||
```json
|
||||
@@ -254,7 +254,7 @@ cloud location for a project that does not yet have a `.ifcfed.manifest`.
|
||||
```json
|
||||
{ "jsonrpc": "2.0", "id": "0", "result": { "path": "/path/to/project/file.ifcfed" } }
|
||||
```
|
||||
5. The IfcViewer "repoints" to the returned path. It is not necessary to do a full reload as no "changes" are made.
|
||||
5. The Bonsai Viewer "repoints" to the returned path. It is not necessary to do a full reload as no "changes" are made.
|
||||
|
||||
## Save to cloud
|
||||
|
||||
@@ -262,8 +262,8 @@ This pushes a .ifcfed back to the cloud location it originally came from,
|
||||
without prompting the user. It is the "Save" equivalent and is only available
|
||||
when there is a `.ifcfed.manifest` adjacent to the project.
|
||||
|
||||
1. The user presses a button in the IfcViewer UI that says "Save to Cloud"
|
||||
2. IfcViewer reads the .ifcfed.manifest and invokes the relevant connector with the `push_ifcfed` method, passing both the local path and the manifest data:
|
||||
1. The user presses a button in the Bonsai Viewer UI that says "Save to Cloud"
|
||||
2. Bonsai Viewer reads the .ifcfed.manifest and invokes the relevant connector with the `push_ifcfed` method, passing both the local path and the manifest data:
|
||||
```json
|
||||
{ "jsonrpc": "2.0", "id": "0", "method": "push_ifcfed", "params": {
|
||||
"path": "/tmp/path/to/project.ifcfed",
|
||||
@@ -278,18 +278,18 @@ when there is a `.ifcfed.manifest` adjacent to the project.
|
||||
```json
|
||||
{ "jsonrpc": "2.0", "id": "0", "result": { "path": "/path/to/project/file.ifcfed" } }
|
||||
```
|
||||
4. The IfcViewer "repoints" to the returned path. It is not necessary to do a full reload as no "changes" are made.
|
||||
4. The Bonsai Viewer "repoints" to the returned path. It is not necessary to do a full reload as no "changes" are made.
|
||||
|
||||
Conflict resolution for non-interactive push methods (the cloud copy moved on
|
||||
since the manifest or source was captured, the user lacks write permission,
|
||||
revision-pinning policies, etc.) is entirely the connector's responsibility.
|
||||
The connector may silently overwrite, prompt the user, refuse with a JSON-RPC
|
||||
error, or anything in between. The IfcViewer expresses no opinion. This rule
|
||||
error, or anything in between. The Bonsai Viewer expresses no opinion. This rule
|
||||
also applies to `push_model` below.
|
||||
|
||||
## Add model from cloud
|
||||
|
||||
1. The user presses a button in the IfcViewer UI that says "Add model from cloud"
|
||||
1. The user presses a button in the Bonsai Viewer UI that says "Add model from cloud"
|
||||
2. The user chooses a connector.
|
||||
3. The `pull_models_interactive` method is sent to the connector.
|
||||
```json
|
||||
@@ -305,16 +305,16 @@ also applies to `push_model` below.
|
||||
{
|
||||
"display_name": "bar.ifc", # Stored in .ifcfed
|
||||
"source": { "connector": "autodesk", ... }, # Stored in .ifcfed
|
||||
"path": "/path/to/model.ifc", # Used to load the model in IfcViewer
|
||||
"path": "/path/to/model.ifc", # Used to load the model in Bonsai Viewer
|
||||
"metadata": { "revision": "B", "date": "2nd Oct 2025" ... }, # Optional, used to display stats
|
||||
},
|
||||
{ ... },
|
||||
...
|
||||
] }
|
||||
```
|
||||
5. The IfcViewer updates the .ifcfed models section with new models using the
|
||||
5. The Bonsai Viewer updates the .ifcfed models section with new models using the
|
||||
"source" and "display\_name" from the provided data. The models are
|
||||
immediately loaded from the "path", and the IfcViewer stores the "metadata"
|
||||
immediately loaded from the "path", and the Bonsai Viewer stores the "metadata"
|
||||
for display. The path and metadata is never stored in the .ifcfed.
|
||||
|
||||
## Save model as to cloud
|
||||
@@ -323,7 +323,7 @@ This pushes a model to a fresh location on a cloud platform, chosen by the
|
||||
user. It is the "Save As" equivalent and is the only way to first establish a
|
||||
cloud `source` for a model whose current source is `local`.
|
||||
|
||||
1. The user presses a button in the IfcViewer UI that says "Save Model As to Cloud"
|
||||
1. The user presses a button in the Bonsai Viewer UI that says "Save Model As to Cloud"
|
||||
2. The user chooses a connector.
|
||||
3. The `push_model_interactive` method is sent to the connector with a path to the model to be uploaded (typically a file, but RocksDB databases can be a folder).
|
||||
```json
|
||||
@@ -342,7 +342,7 @@ cloud `source` for a model whose current source is `local`.
|
||||
"metadata": { "revision": "B", "date": "2nd Oct 2025" ... }, # Optional, used to display stats
|
||||
} }
|
||||
```
|
||||
5. The IfcViewer updates the .ifcfed models section with the new model metadata from the provided data.
|
||||
5. The Bonsai Viewer updates the .ifcfed models section with the new model metadata from the provided data.
|
||||
|
||||
## Save model to cloud
|
||||
|
||||
@@ -351,8 +351,8 @@ without prompting the user. It is the "Save" equivalent and is only available
|
||||
for models whose .ifcfed `source` already points at a cloud connector (i.e.
|
||||
anything other than `local`).
|
||||
|
||||
1. The user presses a button in the IfcViewer UI that says "Save Model to Cloud"
|
||||
2. IfcViewer invokes the connector named in the model's `source` with the `push_model` method, passing both the local path and the existing `source` object verbatim:
|
||||
1. The user presses a button in the Bonsai Viewer UI that says "Save Model to Cloud"
|
||||
2. Bonsai Viewer invokes the connector named in the model's `source` with the `push_model` method, passing both the local path and the existing `source` object verbatim:
|
||||
```json
|
||||
{ "jsonrpc": "2.0", "id": "0", "method": "push_model", "params": {
|
||||
"path": "/tmp/path/to/model.ifc",
|
||||
@@ -370,17 +370,17 @@ anything other than `local`).
|
||||
"metadata": { "revision": "C", "date": "19th May 2026" ... }, # Optional, used to display stats
|
||||
} }
|
||||
```
|
||||
4. The IfcViewer replaces the model's `source` in the .ifcfed and refreshes the stored metadata for display.
|
||||
4. The Bonsai Viewer replaces the model's `source` in the .ifcfed and refreshes the stored metadata for display.
|
||||
|
||||
## Connector settings (optional)
|
||||
|
||||
A connector MAY implement an `open_settings` method that the IfcViewer invokes
|
||||
A connector MAY implement an `open_settings` method that the Bonsai Viewer invokes
|
||||
when the user clicks the connector's settings entry (e.g. a gear icon next to
|
||||
the connector name). The connector is responsible for the entire settings UI:
|
||||
credentials, sign-out, default folders, anything connector-specific.
|
||||
|
||||
1. The user clicks the connector's settings entry in the IfcViewer UI.
|
||||
2. The IfcViewer sends `open_settings`:
|
||||
1. The user clicks the connector's settings entry in the Bonsai Viewer UI.
|
||||
2. The Bonsai Viewer sends `open_settings`:
|
||||
```json
|
||||
{ "jsonrpc": "2.0", "id": "0", "method": "open_settings" }
|
||||
```
|
||||
@@ -391,7 +391,7 @@ credentials, sign-out, default folders, anything connector-specific.
|
||||
```
|
||||
|
||||
If the connector returns a JSON-RPC `Method not found` error (code `-32601`),
|
||||
the IfcViewer should treat that connector as having no settings and hide its
|
||||
the Bonsai Viewer should treat that connector as having no settings and hide its
|
||||
settings entry. There is no other discovery mechanism — the viewer probes by
|
||||
calling the method when needed.
|
||||
|
||||
@@ -408,22 +408,22 @@ optional fields (for example a fresh display label for the connector).
|
||||
### Error Response
|
||||
|
||||
The connector owns all user-facing error handling: dialogs, retry prompts,
|
||||
re-auth flows, logs. The IfcViewer does not interpret or display connector
|
||||
re-auth flows, logs. The Bonsai Viewer does not interpret or display connector
|
||||
errors directly.
|
||||
|
||||
The protocol expresses only two outcomes:
|
||||
|
||||
- **Per-item soft failure** (one model in a batch failed, others succeeded):
|
||||
the connector returns `null` in that slot of the result array. The IfcViewer
|
||||
the connector returns `null` in that slot of the result array. The Bonsai Viewer
|
||||
skips it and continues.
|
||||
- **Whole-call hard failure** (the connector cannot service the request at
|
||||
all): the connector returns a JSON-RPC error object. The IfcViewer aborts
|
||||
the operation. The `error.message` may be logged by the IfcViewer for
|
||||
all): the connector returns a JSON-RPC error object. The Bonsai Viewer aborts
|
||||
the operation. The `error.message` may be logged by the Bonsai Viewer for
|
||||
diagnostics, but is not shown to the user — the connector is expected to
|
||||
have already surfaced the problem in its own UI.
|
||||
|
||||
Diagnostic detail (stack traces, codes, retry context) should be written to
|
||||
stderr, which the IfcViewer captures for logs.
|
||||
stderr, which the Bonsai Viewer captures for logs.
|
||||
|
||||
## Permissions
|
||||
|
||||
@@ -438,7 +438,7 @@ The viewer will tolerate partial failure and report skipped resources that the c
|
||||
## Connector discovery
|
||||
|
||||
A connector is shipped as a folder containing a `connector.json` manifest and
|
||||
an executable entry point. The IfcViewer discovers connectors by scanning a
|
||||
an executable entry point. The Bonsai Viewer discovers connectors by scanning a
|
||||
small, fixed set of locations for these folders.
|
||||
|
||||
### Connector bundle layout
|
||||
@@ -447,7 +447,7 @@ small, fixed set of locations for these folders.
|
||||
<some-connectors-dir>/
|
||||
autodesk/ # folder name is arbitrary; id comes from connector.json
|
||||
connector.json # required, at the folder root
|
||||
ifcviewer-autodesk # the executable (or a wrapper script)
|
||||
bonsaiviewer-autodesk # the executable (or a wrapper script)
|
||||
... # anything else the connector ships
|
||||
```
|
||||
|
||||
@@ -458,38 +458,38 @@ small, fixed set of locations for these folders.
|
||||
"id": "autodesk",
|
||||
"name": "Autodesk Forma",
|
||||
"version": "0.1.0",
|
||||
"exec": "./ifcviewer-autodesk"
|
||||
"exec": "./bonsaiviewer-autodesk"
|
||||
}
|
||||
```
|
||||
|
||||
- `id` — stable identifier used in `.ifcfed` `source.connector` fields and in
|
||||
`.ifcfed.manifest`. Must be unique across all discovered connectors.
|
||||
- `name` — human-readable label shown in the IfcViewer UI.
|
||||
- `name` — human-readable label shown in the Bonsai Viewer UI.
|
||||
- `version` — connector version string; informational only.
|
||||
- `exec` — path to the connector executable. Relative paths are resolved
|
||||
against the connector folder; absolute paths are used as-is. Bundled
|
||||
connectors should use a relative path so the bundle is self-contained.
|
||||
|
||||
On Windows, the IfcViewer will also try `<exec>.exe` if `<exec>` does not
|
||||
On Windows, the Bonsai Viewer will also try `<exec>.exe` if `<exec>` does not
|
||||
exist as written.
|
||||
|
||||
### Search locations
|
||||
|
||||
The IfcViewer scans the **user connectors directory**. The platform's per-user
|
||||
The Bonsai Viewer scans the **user connectors directory**. The platform's per-user
|
||||
application data location:
|
||||
|
||||
- Linux: `~/.local/share/IfcOpenShell/BonsaiViewer/connectors/`
|
||||
- macOS: `~/Library/Application Support/IfcOpenShell/BonsaiViewer/connectors/`
|
||||
- Windows: `%APPDATA%\IfcOpenShell\BonsaiViewer\connectors\`
|
||||
|
||||
The IfcViewer looks at every immediate subdirectory and treats it as a
|
||||
The Bonsai Viewer looks at every immediate subdirectory and treats it as a
|
||||
connector iff it contains a `connector.json`. Connectors are launched on
|
||||
demand when the user invokes a cloud workflow, not at startup.
|
||||
|
||||
### Conflicts and errors
|
||||
|
||||
- If two folders declare the same `id`, the one found earlier in directory
|
||||
order wins; the loser is skipped and a warning is written to the IfcViewer's
|
||||
order wins; the loser is skipped and a warning is written to the Bonsai Viewer's
|
||||
log.
|
||||
- A `connector.json` that is missing, unreadable, malformed, or missing
|
||||
required fields causes that folder to be skipped (with a log entry); other
|
||||
@@ -1,6 +1,6 @@
|
||||
# `ifcviewer-autodesk`
|
||||
# `bonsaiviewer-autodesk`
|
||||
|
||||
Autodesk Forma (APS / Docs) connector for IfcViewer.
|
||||
Autodesk Forma (APS / Docs) connector for Bonsai Viewer.
|
||||
|
||||
Implements the JSON-RPC connector contract defined in
|
||||
[`CLOUD_SYNC_PROTOCOL.md`](CLOUD_SYNC_PROTOCOL.md). The connector is a separate
|
||||
@@ -14,7 +14,7 @@ on Gentoo make sure `USE="tk"` is set for `dev-lang/python`).
|
||||
## Install
|
||||
|
||||
```bash
|
||||
cd src/ifcviewer-autodesk
|
||||
cd src/bonsaiviewer-autodesk
|
||||
python -m venv venv
|
||||
source venv/bin/activate
|
||||
pip install -e .
|
||||
@@ -23,7 +23,7 @@ pip install -e .
|
||||
## Run
|
||||
|
||||
```bash
|
||||
ifcviewer-autodesk
|
||||
bonsaiviewer-autodesk
|
||||
```
|
||||
|
||||
The connector launches without any configuration; on first run, invoke
|
||||
@@ -53,9 +53,9 @@ The connector reads the Autodesk client id from two places, in order:
|
||||
|
||||
The config directory is platform-specific:
|
||||
|
||||
- Linux: `~/.config/ifcviewer-autodesk/`
|
||||
- macOS: `~/Library/Application Support/ifcviewer-autodesk/`
|
||||
- Windows: `%APPDATA%\ifcviewer-autodesk\`
|
||||
- Linux: `~/.config/bonsaiviewer-autodesk/`
|
||||
- macOS: `~/Library/Application Support/bonsaiviewer-autodesk/`
|
||||
- Windows: `%APPDATA%\bonsaiviewer-autodesk\`
|
||||
|
||||
OAuth tokens are stored in the OS keychain (Secret Service on Linux, Keychain
|
||||
on macOS, Credential Manager on Windows), keyed by the client id, so changing
|
||||
@@ -66,7 +66,7 @@ the client id starts a fresh session.
|
||||
The connector owns its own cache. Resolved files live under (Linux):
|
||||
|
||||
```
|
||||
~/.cache/ifcviewer-autodesk/
|
||||
~/.cache/bonsaiviewer-autodesk/
|
||||
ifcfeds/<hash>/<name>.ifcfed[.manifest]
|
||||
models/<hash>/<filename>
|
||||
```
|
||||
+3
-3
@@ -2,9 +2,9 @@ from __future__ import annotations
|
||||
|
||||
import sys
|
||||
|
||||
from ifcviewer_autodesk.connector import AutodeskConnector
|
||||
from ifcviewer_autodesk.rpc import JsonRpcHost
|
||||
from ifcviewer_autodesk.ui import ensure_tk_app
|
||||
from bonsaiviewer_autodesk.connector import AutodeskConnector
|
||||
from bonsaiviewer_autodesk.rpc import JsonRpcHost
|
||||
from bonsaiviewer_autodesk.ui import ensure_tk_app
|
||||
|
||||
|
||||
def main() -> int:
|
||||
+1
-1
@@ -17,7 +17,7 @@ import httpx
|
||||
import keyring
|
||||
import keyring.errors
|
||||
|
||||
from ifcviewer_autodesk.rpc import JSONRPC_INTERNAL_ERROR, RpcError
|
||||
from bonsaiviewer_autodesk.rpc import JSONRPC_INTERNAL_ERROR, RpcError
|
||||
|
||||
|
||||
Progress = Callable[[str, str, "int | None"], None]
|
||||
+3
-3
@@ -13,12 +13,12 @@ def cache_root() -> Path:
|
||||
system = platform.system()
|
||||
if system == "Windows":
|
||||
base = os.environ.get("LOCALAPPDATA") or os.path.expanduser("~")
|
||||
root = Path(base) / "ifcviewer-autodesk" / "Cache"
|
||||
root = Path(base) / "bonsaiviewer-autodesk" / "Cache"
|
||||
elif system == "Darwin":
|
||||
root = Path.home() / "Library" / "Caches" / "ifcviewer-autodesk"
|
||||
root = Path.home() / "Library" / "Caches" / "bonsaiviewer-autodesk"
|
||||
else:
|
||||
base = os.environ.get("XDG_CACHE_HOME") or os.path.expanduser("~/.cache")
|
||||
root = Path(base) / "ifcviewer-autodesk"
|
||||
root = Path(base) / "bonsaiviewer-autodesk"
|
||||
root.mkdir(parents=True, exist_ok=True)
|
||||
return root
|
||||
|
||||
+5
-5
@@ -5,10 +5,10 @@ import traceback
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable
|
||||
|
||||
from ifcviewer_autodesk import cache, settings
|
||||
from ifcviewer_autodesk.autodesk import ApsClient, AuthSessionService, KeyringTokenStore
|
||||
from ifcviewer_autodesk.rpc import JSONRPC_INTERNAL_ERROR, JSONRPC_INVALID_PARAMS, RpcError
|
||||
from ifcviewer_autodesk.ui import BrowseDialog, SettingsDialog, progress_dialog, prompt_for_filename
|
||||
from bonsaiviewer_autodesk import cache, settings
|
||||
from bonsaiviewer_autodesk.autodesk import ApsClient, AuthSessionService, KeyringTokenStore
|
||||
from bonsaiviewer_autodesk.rpc import JSONRPC_INTERNAL_ERROR, JSONRPC_INVALID_PARAMS, RpcError
|
||||
from bonsaiviewer_autodesk.ui import BrowseDialog, SettingsDialog, progress_dialog, prompt_for_filename
|
||||
|
||||
|
||||
ApsProgress = Callable[[str, "int | None"], None]
|
||||
@@ -34,7 +34,7 @@ def _upload_callback(report: Report) -> ApsProgress:
|
||||
|
||||
|
||||
CONNECTOR_ID = "autodesk"
|
||||
KEYRING_SERVICE = "ifcviewer-autodesk"
|
||||
KEYRING_SERVICE = "bonsaiviewer-autodesk"
|
||||
DEFAULT_CALLBACK_URL = "http://localhost:8080/"
|
||||
DEFAULT_SCOPE = "data:read data:write data:create"
|
||||
|
||||
+3
-3
@@ -11,12 +11,12 @@ def config_root() -> Path:
|
||||
system = platform.system()
|
||||
if system == "Windows":
|
||||
base = os.environ.get("APPDATA") or os.path.expanduser("~")
|
||||
root = Path(base) / "ifcviewer-autodesk"
|
||||
root = Path(base) / "bonsaiviewer-autodesk"
|
||||
elif system == "Darwin":
|
||||
root = Path.home() / "Library" / "Application Support" / "ifcviewer-autodesk"
|
||||
root = Path.home() / "Library" / "Application Support" / "bonsaiviewer-autodesk"
|
||||
else:
|
||||
base = os.environ.get("XDG_CONFIG_HOME") or os.path.expanduser("~/.config")
|
||||
root = Path(base) / "ifcviewer-autodesk"
|
||||
root = Path(base) / "bonsaiviewer-autodesk"
|
||||
root.mkdir(parents=True, exist_ok=True)
|
||||
return root
|
||||
|
||||
+12
-5
@@ -6,12 +6,12 @@ from typing import TYPE_CHECKING, Any, Callable, Literal
|
||||
|
||||
import customtkinter as ctk
|
||||
|
||||
from ifcviewer_autodesk import settings
|
||||
from ifcviewer_autodesk.autodesk import ApsClient, AuthSessionService, KeyringTokenStore
|
||||
from ifcviewer_autodesk.rpc import JSONRPC_INTERNAL_ERROR, RpcError
|
||||
from bonsaiviewer_autodesk import settings
|
||||
from bonsaiviewer_autodesk.autodesk import ApsClient, AuthSessionService, KeyringTokenStore
|
||||
from bonsaiviewer_autodesk.rpc import JSONRPC_INTERNAL_ERROR, RpcError
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ifcviewer_autodesk.connector import AutodeskConnector
|
||||
from bonsaiviewer_autodesk.connector import AutodeskConnector
|
||||
|
||||
|
||||
MODEL_EXTENSIONS = (".ifc", ".ifcview", ".rdb", ".rdbview")
|
||||
@@ -161,10 +161,17 @@ class _ProgressContext:
|
||||
def __exit__(self, *_exc: object) -> None:
|
||||
if self.dialog is not None:
|
||||
try:
|
||||
self.dialog.withdraw()
|
||||
self.dialog.destroy()
|
||||
except tk.TclError:
|
||||
pass
|
||||
self.dialog = None
|
||||
try:
|
||||
root = ensure_tk_app()
|
||||
root.update_idletasks()
|
||||
root.update()
|
||||
except tk.TclError:
|
||||
pass
|
||||
|
||||
|
||||
def progress_dialog(message: str) -> _ProgressContext:
|
||||
@@ -629,7 +636,7 @@ class SettingsDialog(_BaseDialog):
|
||||
):
|
||||
return
|
||||
try:
|
||||
KeyringTokenStore(service_name="ifcviewer-autodesk", username=client_id).delete()
|
||||
KeyringTokenStore(service_name="bonsaiviewer-autodesk", username=client_id).delete()
|
||||
except RpcError as exc:
|
||||
show_error(title="Sign Out Failed", message=exc.message)
|
||||
return
|
||||
@@ -2,5 +2,5 @@
|
||||
"id": "autodesk",
|
||||
"name": "Autodesk Forma",
|
||||
"version": "0.1.0",
|
||||
"exec": "ifcviewer-autodesk"
|
||||
"exec": "bonsaiviewer-autodesk"
|
||||
}
|
||||
+6
-6
@@ -1,7 +1,7 @@
|
||||
# Packaging the Autodesk connector
|
||||
|
||||
The connector is shipped as a self-contained folder ready to drop into the
|
||||
IfcViewer connectors directory. PyInstaller bundles the Python interpreter,
|
||||
Bonsai Viewer connectors directory. PyInstaller bundles the Python interpreter,
|
||||
Qt, and all dependencies so end users do not need Python installed.
|
||||
|
||||
PyInstaller does **not** cross-compile. Each OS must build on itself —
|
||||
@@ -13,7 +13,7 @@ typically via a CI matrix.
|
||||
dist/
|
||||
autodesk/ # the connector folder, ready to install
|
||||
connector.json
|
||||
ifcviewer-autodesk[.exe]
|
||||
bonsaiviewer-autodesk[.exe]
|
||||
_internal/... # PyInstaller dependencies (Qt, Python, …)
|
||||
autodesk-<os>-<arch>.zip # the distribution archive
|
||||
```
|
||||
@@ -24,7 +24,7 @@ The folder is what Bonsai Viewer expects under
|
||||
## Build steps (any OS)
|
||||
|
||||
```bash
|
||||
cd src/ifcviewer-autodesk
|
||||
cd src/bonsaiviewer-autodesk
|
||||
python -m venv venv
|
||||
venv/bin/activate # or venv\Scripts\activate on Windows
|
||||
pip install -e ".[build]"
|
||||
@@ -34,7 +34,7 @@ python packaging/build.py
|
||||
The build:
|
||||
|
||||
1. cleans `dist/` and `build/`
|
||||
2. runs PyInstaller against `packaging/ifcviewer-autodesk.spec`
|
||||
2. runs PyInstaller against `packaging/bonsaiviewer-autodesk.spec`
|
||||
3. renames the produced folder to `autodesk/` and copies `connector.json` into it
|
||||
4. zips the folder as `autodesk-<os>-<arch>.zip`
|
||||
|
||||
@@ -72,7 +72,7 @@ builds do; on Gentoo make sure `USE="tk"` is set for `dev-lang/python`.
|
||||
any modern Python distribution).
|
||||
- The keyring backend is Credential Manager.
|
||||
- The `.exe` is built with `console=True` because the connector speaks
|
||||
JSON-RPC over stdio. The IfcViewer must launch the connector with
|
||||
JSON-RPC over stdio. The Bonsai Viewer must launch the connector with
|
||||
`CREATE_NO_WINDOW` (Qt: `QProcess::setCreateProcessArgumentsModifier`) so
|
||||
end users never see a console window flicker.
|
||||
- For distribution: sign the `.exe` with an Authenticode certificate to
|
||||
@@ -98,5 +98,5 @@ Bonsai Viewer picks up the connector on next launch.
|
||||
|
||||
- Signing / notarization (caller's responsibility per OS)
|
||||
- CI matrix (project-level concern)
|
||||
- Auto-update (the IfcViewer or the host installer handles this)
|
||||
- Auto-update (the Bonsai Viewer or the host installer handles this)
|
||||
- Universal macOS binaries via `lipo` (post-process step, not part of `build.py`)
|
||||
+5
-5
@@ -1,7 +1,7 @@
|
||||
# PyInstaller spec for the IfcViewer Autodesk connector (Tk + CustomTkinter).
|
||||
# PyInstaller spec for the Bonsai Viewer Autodesk connector (Tk + CustomTkinter).
|
||||
#
|
||||
# The connector talks JSON-RPC over stdio, so `console=True` is required to
|
||||
# attach stdin/stdout on Windows. The IfcViewer is expected to spawn the
|
||||
# attach stdin/stdout on Windows. The Bonsai Viewer is expected to spawn the
|
||||
# connector with the OS's "hide console window" flag on Windows
|
||||
# (CREATE_NO_WINDOW) so end users never see a console pop up.
|
||||
|
||||
@@ -22,7 +22,7 @@ HIDDEN_IMPORTS = [
|
||||
|
||||
|
||||
a = Analysis(
|
||||
[str(PROJECT_ROOT / "ifcviewer_autodesk" / "__main__.py")],
|
||||
[str(PROJECT_ROOT / "bonsaiviewer_autodesk" / "__main__.py")],
|
||||
pathex=[str(PROJECT_ROOT)],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
@@ -56,7 +56,7 @@ exe = EXE(
|
||||
a.scripts,
|
||||
[],
|
||||
exclude_binaries=True,
|
||||
name="ifcviewer-autodesk",
|
||||
name="bonsaiviewer-autodesk",
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
@@ -77,5 +77,5 @@ coll = COLLECT(
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
name="ifcviewer-autodesk",
|
||||
name="bonsaiviewer-autodesk",
|
||||
)
|
||||
+5
-5
@@ -1,12 +1,12 @@
|
||||
"""Build the Autodesk connector bundle for the current OS.
|
||||
|
||||
Each OS builds on itself (PyInstaller does not cross-compile). The output is a
|
||||
single zip ready to drop into the IfcViewer connectors directory:
|
||||
single zip ready to drop into the Bonsai Viewer connectors directory:
|
||||
|
||||
dist/autodesk-<os>-<arch>.zip
|
||||
autodesk/
|
||||
connector.json
|
||||
ifcviewer-autodesk[.exe]
|
||||
bonsaiviewer-autodesk[.exe]
|
||||
_internal/...
|
||||
|
||||
Usage:
|
||||
@@ -27,12 +27,12 @@ from pathlib import Path
|
||||
|
||||
PROJECT_ROOT = Path(__file__).resolve().parent.parent
|
||||
PACKAGING_DIR = PROJECT_ROOT / "packaging"
|
||||
SPEC_FILE = PACKAGING_DIR / "ifcviewer-autodesk.spec"
|
||||
SPEC_FILE = PACKAGING_DIR / "bonsaiviewer-autodesk.spec"
|
||||
DIST_DIR = PROJECT_ROOT / "dist"
|
||||
BUILD_DIR = PROJECT_ROOT / "build"
|
||||
|
||||
CONNECTOR_FOLDER_NAME = "autodesk"
|
||||
PYINSTALLER_OUTPUT_NAME = "ifcviewer-autodesk"
|
||||
PYINSTALLER_OUTPUT_NAME = "bonsaiviewer-autodesk"
|
||||
|
||||
|
||||
def _platform_tag() -> str:
|
||||
@@ -92,7 +92,7 @@ def _assemble_connector_folder(pyinstaller_output: Path) -> Path:
|
||||
# `pip install -e .` works for development. For the bundled folder, the
|
||||
# binary lives next to connector.json, so rewrite `exec` to a relative path.
|
||||
manifest = json.loads((PROJECT_ROOT / "connector.json").read_text(encoding="utf-8"))
|
||||
binary_name = "ifcviewer-autodesk.exe" if platform.system() == "Windows" else "ifcviewer-autodesk"
|
||||
binary_name = "bonsaiviewer-autodesk.exe" if platform.system() == "Windows" else "bonsaiviewer-autodesk"
|
||||
manifest["exec"] = f"./{binary_name}"
|
||||
(connector_dir / "connector.json").write_text(json.dumps(manifest, indent=2) + "\n", encoding="utf-8")
|
||||
|
||||
@@ -3,9 +3,9 @@ requires = ["setuptools>=69", "wheel"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "ifcviewer-autodesk"
|
||||
name = "bonsaiviewer-autodesk"
|
||||
version = "0.1.0"
|
||||
description = "Autodesk cloud connector for IfcViewer"
|
||||
description = "Autodesk cloud connector for Bonsai Viewer"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
@@ -24,4 +24,4 @@ include-package-data = true
|
||||
where = ["."]
|
||||
|
||||
[project.scripts]
|
||||
ifcviewer-autodesk = "ifcviewer_autodesk.__main__:main"
|
||||
bonsaiviewer-autodesk = "bonsaiviewer_autodesk.__main__:main"
|
||||
Reference in New Issue
Block a user