mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-12 18:43:26 +00:00
Add Bonsai Viewer docs
Create a standalone Sphinx docs tree for Bonsai Viewer and migrate the Autodesk connector Markdown documentation into RST.\n\nGenerated with the assistance of an AI coding tool.
This commit is contained in:
@@ -1,498 +0,0 @@
|
||||
# Bonsai Viewer cloud connectors
|
||||
|
||||
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 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 Bonsai Viewer.
|
||||
|
||||
The following types of resources may be managed with a connector:
|
||||
|
||||
- Projects (.ifcfed)
|
||||
- Models (.ifc, .rdb, .ifcview, .rdbview)
|
||||
- Issues (.bcf, not yet supported nor defined)
|
||||
- Specifications (.ids, not yet supported nor defined)
|
||||
|
||||
## Communication protocol
|
||||
|
||||
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.
|
||||
|
||||
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 Bonsai Viewer
|
||||
will not parse it.
|
||||
|
||||
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 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 Bonsai Viewer's
|
||||
request back into a local file and cloud metadata. The connector must not
|
||||
modify the file in any way.
|
||||
|
||||
A connector will handle anything necessary for the cloud platform (or arbitrary
|
||||
data source). This includes authentication, browsing files, filters and
|
||||
searches, selecting or pinning revisions, progress bars, cache,
|
||||
platform-specific requirements, etc. The connector may or may not display a UI.
|
||||
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 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,
|
||||
viewer-generated sidecar files, database locks or helpers (e.g. SQLite WAL), or
|
||||
where filenames are significant (and cannot be renamed to prevent collisions),
|
||||
or are actually directories containing other files.
|
||||
|
||||
The connector is expected to persist this cache until explicitly cleared by a
|
||||
user, because it will be used directly as a local path by the viewer. If a
|
||||
connector invalidates a cache, it can simply delete the entire directory. If a
|
||||
connector resolves to a new version of the file, it can create a fresh
|
||||
directory (thus all sidecar artefacts will be regenerated if needed). It is not
|
||||
prescribed how a connector manages cache.
|
||||
|
||||
## Resource: Projects
|
||||
|
||||
A project is defined using an `.ifcfed` file. The file stores settings (such as
|
||||
units, home view coordinates, saved searches, etc) and models.
|
||||
|
||||
For example:
|
||||
|
||||
```json
|
||||
# project.ifcfed
|
||||
{
|
||||
"created": "2026-04-29T21:22:36Z",
|
||||
"modified": "2026-04-29T21:22:36Z",
|
||||
"home_view": null,
|
||||
"models": ... # see Resources: Models,
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
A project may have a manifest file (with `.manifest` as a suffix), which may
|
||||
store metadata that a ifcfed was retrieved from a cloud source.
|
||||
|
||||
```json
|
||||
# project.ifcfed.manifest
|
||||
{
|
||||
"connector": "mycompany",
|
||||
# Arbitrary connector-specific data
|
||||
"version": "2",
|
||||
"url": "http://example.com/project.ifcfed",
|
||||
}
|
||||
```
|
||||
|
||||
## Resource: Models
|
||||
|
||||
The list of models is defined in the .ifcfed. Each model may either point to a
|
||||
local file (via the special "local" connector), or to a cloud file.
|
||||
|
||||
Cloud connections may store arbitrary source data as keys. For example, they
|
||||
might store a revision policy that determines whether the model is pinned to a
|
||||
particular revision or must always be the latest. This is completely up to the
|
||||
connector.
|
||||
|
||||
Here is an example of how models might be stored in an .ifcfed:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"display_name": "foo.ifc",
|
||||
"id": "0503642e-e2f6-4700-87fd-16479542e801",
|
||||
"source": {
|
||||
"connector": "local",
|
||||
"path": "path/to/foo.ifc" # Only for local
|
||||
},
|
||||
},
|
||||
{
|
||||
"display_name": "bar.ifc",
|
||||
"id": "5fc69e6a-1ff0-4d8a-82c6-2215df53d2ed",
|
||||
"source": {
|
||||
"connector": "autodesk",
|
||||
# Below is arbitrary data depending on the connector
|
||||
"version": "1",
|
||||
"hub_id": "b.hub123",
|
||||
"project_id": "b.project456",
|
||||
"item_id": "urn:adsk.wipprod:dm.lineage:abc",
|
||||
"version_id": "urn:adsk.wipprod:fs.file:vf.xyz?version=3"
|
||||
},
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
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 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
|
||||
Bonsai Viewer UI for convenience:
|
||||
|
||||
- author
|
||||
- revision
|
||||
- date
|
||||
|
||||
## Open from cloud workflow
|
||||
|
||||
This opens a .ifcfed from a cloud platform and constitutes a fresh session.
|
||||
Note that downloading the latest versions of all models immediately upon open
|
||||
is not required. At a minimum, only the .ifcfed needs to be opened. It is
|
||||
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 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
|
||||
{ "jsonrpc": "2.0", "id": "0", "method": "pull_ifcfed_interactive" }
|
||||
```
|
||||
4. The connector:
|
||||
- (Does optional workflow) authenticates, browses projects, filters files, etc
|
||||
- The user selects an .ifcfed file from the connector's UI
|
||||
- Downloads (or retrieves from cache) the cloud .ifcfed into a connector managed directory
|
||||
- The connector returns a path to the .ifcfed. The connector must also create an adjacent .ifcfed.manifest file:
|
||||
```json
|
||||
{ "jsonrpc": "2.0", "id": "0", "result": { "path": "/path/to/project/file.ifcfed" } }
|
||||
```
|
||||
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": ..., },
|
||||
{ "display_name": ..., "id": ..., "source": ..., },
|
||||
...
|
||||
] }
|
||||
```
|
||||
7. The connector handles downloading files. It may always check and download the latest version of the file, or be designed to pin to a particular revision, or give the user the option of not downloading a file, etc. or retrieves from its own cache, and returns a path.
|
||||
```json
|
||||
{ "jsonrpc": "2.0", "id": "1", "result": [
|
||||
{ "path": "/path/to/foo.ifc" },
|
||||
{
|
||||
"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
|
||||
{ "path": "/path/to/bar.ifc" },
|
||||
...
|
||||
] }
|
||||
```
|
||||
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
|
||||
|
||||
This refreshes cloud-sourced resources in the currently-open project to their
|
||||
latest cloud revisions, without prompting the user. It is available whenever
|
||||
the project has any cloud resources: a `.ifcfed.manifest` adjacent to the
|
||||
.ifcfed, or one or more models whose `source.connector` is not `local`. 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 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": ...
|
||||
} }
|
||||
```
|
||||
3. The connector does what it needs:
|
||||
- Authenticates (optional)
|
||||
- (Typically without user interaction) finds the .ifcfed on the cloud platform using the ifcfed manifest
|
||||
- Downloads (or retrieves from cache) the cloud .ifcfed into a connector managed directory
|
||||
- The connector returns a path to the .ifcfed. The connector must also create an adjacent .ifcfed.manifest file:
|
||||
```json
|
||||
{ "jsonrpc": "2.0", "id": "0", "result": { "path": "/path/to/project/file.ifcfed" } }
|
||||
```
|
||||
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 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 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 Bonsai Viewer.
|
||||
|
||||
## Save as to cloud
|
||||
|
||||
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 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
|
||||
{ "jsonrpc": "2.0", "id": "0", "method": "push_ifcfed_interactive", "params": { "path": "/tmp/path/to/project.ifcfed" } }
|
||||
```
|
||||
4. The connector does what it needs:
|
||||
- (Does optional workflow) authenticates, browses projects, filters files, etc
|
||||
- Selects existing or writes a new name for an .ifcfed file
|
||||
- Uploads .ifcfed file to the cloud platform
|
||||
- The connector returns a path to the .ifcfed. The connector must also create an adjacent .ifcfed.manifest file:
|
||||
```json
|
||||
{ "jsonrpc": "2.0", "id": "0", "result": { "path": "/path/to/project/file.ifcfed" } }
|
||||
```
|
||||
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
|
||||
|
||||
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 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",
|
||||
"manifest": { "connector": "mycompany", "version": "2", "url": "..." }
|
||||
} }
|
||||
```
|
||||
3. The connector does what it needs:
|
||||
- Authenticates (optional)
|
||||
- (Typically without user interaction) locates the existing .ifcfed on the cloud platform using the manifest data
|
||||
- Uploads the .ifcfed, overwriting or creating a new revision as the platform dictates
|
||||
- The connector returns a path to the .ifcfed and rewrites the adjacent .ifcfed.manifest if any of its fields have changed (e.g. a new version number):
|
||||
```json
|
||||
{ "jsonrpc": "2.0", "id": "0", "result": { "path": "/path/to/project/file.ifcfed" } }
|
||||
```
|
||||
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 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 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
|
||||
{ "jsonrpc": "2.0", "id": "0", "method": "pull_models_interactive" }
|
||||
```
|
||||
4. The connector does what it needs:
|
||||
- (Does optional workflow) authenticates, browses projects, filters files, etc
|
||||
- Selects a model (.ifc, .ifcview, .rdbview, .rdb, etc)
|
||||
- Downloads (or retrieves from cache) the model into a connector managed directory
|
||||
- The connector returns a successful result:
|
||||
```json
|
||||
{ "jsonrpc": "2.0", "id": "0", "result": [
|
||||
{
|
||||
"display_name": "bar.ifc", # Stored in .ifcfed
|
||||
"source": { "connector": "autodesk", ... }, # Stored in .ifcfed
|
||||
"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 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 Bonsai Viewer stores the "metadata"
|
||||
for display. The path and metadata is never stored in the .ifcfed.
|
||||
|
||||
## Save model as to cloud
|
||||
|
||||
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 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
|
||||
{ "jsonrpc": "2.0", "id": "0", "method": "push_model_interactive", "params": { "path": "/tmp/path/to/model.ifc" } }
|
||||
```
|
||||
4. The connector does what it needs:
|
||||
- (Does optional workflow) authenticates, browses projects, filters files, etc
|
||||
- Selects existing or types a new name for the model
|
||||
- Uploads the model (only the file in params, though the connector is free to do optional additional work) to the cloud platform
|
||||
- The connector returns a successful result:
|
||||
```json
|
||||
{ "jsonrpc": "2.0", "id": "0", "result": {
|
||||
"display_name": "bar.ifc", # Stored in .ifcfed
|
||||
"path": "/path/to/model.ifc",
|
||||
"source": { "connector": "autodesk", ... }, # Stored in .ifcfed
|
||||
"metadata": { "revision": "B", "date": "2nd Oct 2025" ... }, # Optional, used to display stats
|
||||
} }
|
||||
```
|
||||
5. The Bonsai Viewer updates the .ifcfed models section with the new model metadata from the provided data.
|
||||
|
||||
## Save model to cloud
|
||||
|
||||
This pushes a model back to the cloud location it originally came from,
|
||||
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 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",
|
||||
"source": { "connector": "autodesk", "hub_id": "b.hub123", "item_id": "...", ... }
|
||||
} }
|
||||
```
|
||||
3. The connector does what it needs:
|
||||
- Authenticates (optional)
|
||||
- (Typically without user interaction) locates the existing model on the cloud platform using the `source` data
|
||||
- Uploads the model, overwriting or creating a new revision as the platform dictates
|
||||
- The connector returns a successful result. The returned `source` reflects the just-uploaded revision (e.g. a new `version_id`) and replaces the existing one in the .ifcfed; `display_name` is omitted (the existing one is retained):
|
||||
```json
|
||||
{ "jsonrpc": "2.0", "id": "0", "result": {
|
||||
"source": { "connector": "autodesk", ... }, # Replaces existing source in .ifcfed
|
||||
"metadata": { "revision": "C", "date": "19th May 2026" ... }, # Optional, used to display stats
|
||||
} }
|
||||
```
|
||||
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 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 Bonsai Viewer UI.
|
||||
2. The Bonsai Viewer sends `open_settings`:
|
||||
```json
|
||||
{ "jsonrpc": "2.0", "id": "0", "method": "open_settings" }
|
||||
```
|
||||
3. The connector shows its own settings dialog. When the user closes it, the
|
||||
connector returns:
|
||||
```json
|
||||
{ "jsonrpc": "2.0", "id": "0", "result": {} }
|
||||
```
|
||||
|
||||
If the connector returns a JSON-RPC `Method not found` error (code `-32601`),
|
||||
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.
|
||||
|
||||
The connector is free to use this method for things like:
|
||||
|
||||
- Signing in / signing out
|
||||
- Setting API keys, client ids, or other credentials
|
||||
- Choosing default upload folders or revision policies
|
||||
- Clearing the connector's cache
|
||||
|
||||
The result object is currently always empty (`{}`); future revisions may add
|
||||
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 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 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 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 Bonsai Viewer captures for logs.
|
||||
|
||||
## Permissions
|
||||
|
||||
Permissions are completely managed by the connector. For example:
|
||||
|
||||
- one Autodesk model resolves successfully
|
||||
- one Aconex model fails with access denied
|
||||
- one Dropbox model resolves successfully
|
||||
|
||||
The viewer will tolerate partial failure and report skipped resources that the connector cannot resolve. A federation does not need to become all-or-nothing just because some remote models are permission-restricted.
|
||||
|
||||
## Connector discovery
|
||||
|
||||
A connector is shipped as a folder containing a `connector.json` manifest and
|
||||
an executable entry point. The Bonsai Viewer discovers connectors by scanning a
|
||||
small, fixed set of locations for these folders.
|
||||
|
||||
### Connector bundle layout
|
||||
|
||||
```
|
||||
<some-connectors-dir>/
|
||||
autodesk/ # folder name is arbitrary; id comes from connector.json
|
||||
connector.json # required, at the folder root
|
||||
bonsaiviewer-autodesk # the executable (or a wrapper script)
|
||||
... # anything else the connector ships
|
||||
```
|
||||
|
||||
### `connector.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "autodesk",
|
||||
"name": "Autodesk Forma",
|
||||
"version": "0.1.0",
|
||||
"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 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 Bonsai Viewer will also try `<exec>.exe` if `<exec>` does not
|
||||
exist as written.
|
||||
|
||||
### Search locations
|
||||
|
||||
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 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 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
|
||||
connectors are unaffected.
|
||||
- A connector whose `exec` cannot be resolved or launched is reported to the
|
||||
user only when the user actually tries to invoke it.
|
||||
@@ -1,100 +0,0 @@
|
||||
# `bonsaiviewer-autodesk`
|
||||
|
||||
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
|
||||
process the viewer launches and speaks to over stdio.
|
||||
|
||||
UI is built on **CustomTkinter** (Tcl/Tk under the hood), keeping the
|
||||
packaged connector around 50 MB unpacked / 21 MB zipped on Linux. The Python
|
||||
running this code must include `tkinter` (most distribution Python builds do;
|
||||
on Gentoo make sure `USE="tk"` is set for `dev-lang/python`).
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
cd src/bonsaiviewer-autodesk
|
||||
python -m venv venv
|
||||
source venv/bin/activate
|
||||
pip install -e .
|
||||
```
|
||||
|
||||
## Run
|
||||
|
||||
```bash
|
||||
bonsaiviewer-autodesk
|
||||
```
|
||||
|
||||
The connector launches without any configuration; on first run, invoke
|
||||
`open_settings` (or, equivalently, set the `APS_CLIENT_ID` env var) to
|
||||
configure the Autodesk client id and OAuth callback port.
|
||||
|
||||
Then send newline-delimited JSON-RPC 2.0 requests on `stdin`. Examples:
|
||||
|
||||
```json
|
||||
{"jsonrpc":"2.0","id":"0","method":"open_settings"}
|
||||
{"jsonrpc":"2.0","id":"1","method":"pull_ifcfed_interactive"}
|
||||
{"jsonrpc":"2.0","id":"2","method":"pull_models","params":[{"display_name":"foo.ifc","id":"abc","source":{"connector":"autodesk","hub_id":"b.hub","project_id":"b.proj","item_id":"urn:adsk...","version_id":"latest"}}]}
|
||||
{"jsonrpc":"2.0","id":"3","method":"push_ifcfed_interactive","params":{"path":"/tmp/project.ifcfed"}}
|
||||
{"jsonrpc":"2.0","id":"4","method":"push_ifcfed","params":{"path":"/tmp/project.ifcfed","manifest":{"connector":"autodesk","hub_id":"b.hub","project_id":"b.proj","item_id":"urn:adsk..."}}}
|
||||
```
|
||||
|
||||
The viewer is expected to launch this binary once per session and keep it alive
|
||||
until shutdown; closing the connector's `stdin` triggers a clean exit.
|
||||
|
||||
### Configuration
|
||||
|
||||
The connector reads the Autodesk client id from two places, in order:
|
||||
|
||||
1. The `APS_CLIENT_ID` environment variable (takes precedence — useful for dev
|
||||
overrides).
|
||||
2. `<config dir>/settings.json` (persisted via the settings dialog).
|
||||
|
||||
The OAuth callback host is always `localhost`. The callback port defaults to
|
||||
`8080` and can be changed in the settings dialog.
|
||||
|
||||
The config directory is platform-specific:
|
||||
|
||||
- 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
|
||||
the client id starts a fresh session.
|
||||
|
||||
## Cache
|
||||
|
||||
The connector owns its own cache. Resolved files live under (Linux):
|
||||
|
||||
```
|
||||
~/.cache/bonsaiviewer-autodesk/
|
||||
ifcfeds/<hash>/<name>.ifcfed[.manifest]
|
||||
models/<hash>/<filename>
|
||||
```
|
||||
|
||||
Each file is the sole child in its directory so the viewer can write sidecar
|
||||
files (e.g. `.ifcview`) next to it without colliding. A new resolved version of
|
||||
a model lands in a fresh `models/<hash>/` directory; the old directory may be
|
||||
removed manually to clear space.
|
||||
|
||||
## Status
|
||||
|
||||
What is implemented:
|
||||
|
||||
- Strict JSON-RPC 2.0 host over stdio
|
||||
- APS PKCE sign-in with keyring-backed token store
|
||||
- Hub / project / folder browsing (Qt UI)
|
||||
- `pull_ifcfed_interactive`, `pull_ifcfed`, `pull_models`, `pull_models_interactive`
|
||||
- `push_ifcfed_interactive`, `push_ifcfed`, `push_model_interactive`, `push_model`
|
||||
- `open_settings` — edit the client id and callback port, sign out
|
||||
- Connector-managed cache with sole-child invariant
|
||||
- Adjacent `.ifcfed.manifest` written/read alongside `.ifcfed` files
|
||||
|
||||
What is intentionally not implemented:
|
||||
|
||||
- JSON-RPC notifications for progress streaming (the connector shows its own
|
||||
progress dialog instead, per spec)
|
||||
- Cancellation of in-flight downloads
|
||||
- Subdirectory upload layouts inside push destinations (one flat file at a time)
|
||||
@@ -1,102 +0,0 @@
|
||||
# Packaging the Autodesk connector
|
||||
|
||||
The connector is shipped as a self-contained folder ready to drop into the
|
||||
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 —
|
||||
typically via a CI matrix.
|
||||
|
||||
## Output
|
||||
|
||||
```
|
||||
dist/
|
||||
autodesk/ # the connector folder, ready to install
|
||||
connector.json
|
||||
bonsaiviewer-autodesk[.exe]
|
||||
_internal/... # PyInstaller dependencies (Qt, Python, …)
|
||||
autodesk-<os>-<arch>.zip # the distribution archive
|
||||
```
|
||||
|
||||
The folder is what Bonsai Viewer expects under
|
||||
`~/.local/share/IfcOpenShell/BonsaiViewer/connectors/` (or the OS equivalent).
|
||||
|
||||
## Build steps (any OS)
|
||||
|
||||
```bash
|
||||
cd src/bonsaiviewer-autodesk
|
||||
python -m venv venv
|
||||
venv/bin/activate # or venv\Scripts\activate on Windows
|
||||
pip install -e ".[build]"
|
||||
python packaging/build.py
|
||||
```
|
||||
|
||||
The build:
|
||||
|
||||
1. cleans `dist/` and `build/`
|
||||
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`
|
||||
|
||||
The UI is Tcl/Tk via CustomTkinter, which keeps the bundle small. Expect
|
||||
~50 MB unpacked / ~21 MB zipped per OS. The Python used to run the build
|
||||
must include `tkinter` — most distribution and python-build-standalone
|
||||
builds do; on Gentoo make sure `USE="tk"` is set for `dev-lang/python`.
|
||||
|
||||
## Per-OS notes
|
||||
|
||||
### Linux
|
||||
|
||||
- Build on the **oldest glibc** you intend to support. Binaries built on a
|
||||
newer glibc will not run on older distributions. Ubuntu 22.04 LTS
|
||||
(glibc 2.35) is a reasonable lowest common denominator in 2026.
|
||||
- The keyring backend used at runtime is `SecretService` (gnome-keyring or
|
||||
KWallet); end users need a Secret Service provider running.
|
||||
- Output: `autodesk-linux-x86_64.zip` (and/or `arm64`).
|
||||
|
||||
### macOS
|
||||
|
||||
- Each architecture builds separately. To support both Apple Silicon and
|
||||
Intel, build on each and ship two zips, or post-process with `lipo` to
|
||||
produce universal binaries.
|
||||
- The keyring backend is the system Keychain.
|
||||
- For distribution outside the developer's machine you will need to
|
||||
**codesign** the executable and Tcl/Tk dylibs, and notarize the bundle.
|
||||
Unsigned binaries trigger Gatekeeper warnings. Codesigning is left to the
|
||||
caller; the spec's `codesign_identity` field can be wired up.
|
||||
- Output: `autodesk-macos-arm64.zip` and/or `autodesk-macos-x86_64.zip`.
|
||||
|
||||
### Windows
|
||||
|
||||
- Build with the Microsoft Visual C++ runtime available (usually present in
|
||||
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 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
|
||||
avoid SmartScreen warnings. Signing is left to the caller.
|
||||
- Output: `autodesk-windows-x86_64.zip`.
|
||||
|
||||
## Installing a built connector
|
||||
|
||||
```bash
|
||||
# Linux
|
||||
unzip dist/autodesk-linux-x86_64.zip -d ~/.local/share/IfcOpenShell/BonsaiViewer/connectors/
|
||||
|
||||
# macOS
|
||||
unzip dist/autodesk-macos-arm64.zip -d "~/Library/Application Support/IfcOpenShell/BonsaiViewer/connectors/"
|
||||
|
||||
# Windows (PowerShell)
|
||||
Expand-Archive dist\autodesk-windows-x86_64.zip -DestinationPath "$env:APPDATA\IfcOpenShell\BonsaiViewer\connectors\"
|
||||
```
|
||||
|
||||
Bonsai Viewer picks up the connector on next launch.
|
||||
|
||||
## Out of scope here
|
||||
|
||||
- Signing / notarization (caller's responsibility per OS)
|
||||
- CI matrix (project-level concern)
|
||||
- Auto-update (the Bonsai Viewer or the host installer handles this)
|
||||
- Universal macOS binaries via `lipo` (post-process step, not part of `build.py`)
|
||||
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
|
||||
name = "bonsaiviewer-autodesk"
|
||||
version = "0.1.0"
|
||||
description = "Autodesk cloud connector for Bonsai Viewer"
|
||||
readme = "README.md"
|
||||
readme = { text = "Autodesk cloud connector for Bonsai Viewer. See src/bonsaiviewer/docs/connectors/autodesk.rst in the IfcOpenShell repository.", content-type = "text/x-rst" }
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
"customtkinter>=5.2",
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
# Minimal makefile for Sphinx documentation
|
||||
|
||||
SPHINXOPTS ?=
|
||||
SPHINXBUILD ?= sphinx-build
|
||||
SOURCEDIR = .
|
||||
BUILDDIR = _build
|
||||
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
@echo ""
|
||||
@echo "You can also do 'make server' to launch html server for previously built html docs."
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
server:
|
||||
python -m http.server 8080 --directory $(BUILDDIR)/html
|
||||
.PHONY: server Makefile
|
||||
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
@import url("https://fonts.googleapis.com/css2?family=Nunito:wght@200;300;400;500;600;700;800&display=swap");
|
||||
@import url('https://fonts.googleapis.com/css2?family=Inconsolata:wght@200;300;400;500;600;700&display=swap');
|
||||
|
||||
h1, h2, h3, h4 {
|
||||
font-weight: normal;
|
||||
color: #7cbf33;
|
||||
background: -webkit-linear-gradient(0deg, #7cbf33, #049344);
|
||||
background-clip: border-box;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.toc-tree .reference:hover {
|
||||
color: #d98014;
|
||||
}
|
||||
|
||||
.sidebar-brand-text {
|
||||
font-size: 1rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.blockbutton {
|
||||
max-width: 500px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.blockbutton a {
|
||||
display: block;
|
||||
padding-top: 15px;
|
||||
padding-bottom: 15px;
|
||||
border-radius: 5px;
|
||||
background: #40b74c;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.blockbutton a:hover {
|
||||
background: #70ba35;
|
||||
}
|
||||
|
||||
.blockbutton a.download code {
|
||||
background: none !important;
|
||||
border: none !important;
|
||||
color: inherit !important;
|
||||
font-family: inherit !important;
|
||||
font-size: inherit !important;
|
||||
font-weight: bold;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.highlight .hll {
|
||||
background-color: #ffc2;
|
||||
}
|
||||
|
||||
section img {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.location-scene img {
|
||||
display: inline;
|
||||
border-radius: 0px;
|
||||
box-shadow: none;
|
||||
vertical-align: middle;
|
||||
margin-top: -3px;
|
||||
}
|
||||
|
||||
.location-scene p {
|
||||
margin: 0.75rem;
|
||||
}
|
||||
|
||||
.location-scene {
|
||||
border: 1px solid var(--color-admonition-title);
|
||||
background-color: var(--color-admonition-title-background);
|
||||
border-radius: 5px;
|
||||
font-style: italic;
|
||||
color: var(--color-admonition-text);
|
||||
}
|
||||
|
||||
img.transparent {
|
||||
width: auto;
|
||||
height: auto;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
img.icon {
|
||||
width: auto;
|
||||
height: auto;
|
||||
border-radius: 0px;
|
||||
box-shadow: none;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.content figure figcaption>p {
|
||||
font-style: italic;
|
||||
font-size: small;
|
||||
color: #808080;
|
||||
}
|
||||
|
||||
span.menuselection {
|
||||
border: 1px solid var(--color-admonition-title);
|
||||
background-color: var(--color-admonition-title-background);
|
||||
color: var(--color-admonition-text);
|
||||
border-radius: 5px;
|
||||
padding-left: 3px;
|
||||
padding-right: 3px;
|
||||
}
|
||||
|
||||
.toc-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
|
||||
grid-gap: 20px;
|
||||
list-style-type: none;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
# Configuration file for the Sphinx documentation builder.
|
||||
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
project = "Bonsai Viewer"
|
||||
copyright = f"2020-{datetime.now().year} IfcOpenShell Contributors"
|
||||
author = "IfcOpenShell Contributors"
|
||||
|
||||
cwd = os.path.dirname(os.path.realpath(__file__))
|
||||
with open(os.path.join(cwd, "..", "..", "..", "VERSION"), "r") as f:
|
||||
release = f.read().strip()
|
||||
|
||||
|
||||
extensions = ["sphinx.ext.autodoc", "sphinx.ext.autosectionlabel", "sphinx_copybutton"]
|
||||
|
||||
autosectionlabel_prefix_document = True
|
||||
autosectionlabel_maxdepth = 2
|
||||
|
||||
templates_path = []
|
||||
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", ".venv"]
|
||||
|
||||
|
||||
html_theme = "furo"
|
||||
html_static_path = ["_static"]
|
||||
html_css_files = ["custom.css"]
|
||||
|
||||
pygments_style = "one-dark"
|
||||
pygments_dark_style = "one-dark"
|
||||
|
||||
html_favicon = "https://ifcopenshell.org/assets/images/logo.png"
|
||||
html_logo = "https://ifcopenshell.org/assets/images/logo.png"
|
||||
html_theme_options = {
|
||||
"source_repository": "https://github.com/IfcOpenShell/IfcOpenShell/",
|
||||
"source_branch": "v0.8.0",
|
||||
"source_directory": "src/bonsaiviewer/docs/",
|
||||
"light_css_variables": {
|
||||
"color-brand-primary": "#39b54a",
|
||||
"color-brand-content": "#39b54a",
|
||||
"color-brand-visited": "#d9e021",
|
||||
"color-background-primary": "#f7f7f6",
|
||||
"color-background-secondary": "#eeeeec",
|
||||
"color-background-border": "#cfd0cb",
|
||||
"color-foreground-primary": "#2e3436",
|
||||
"color-sidebar-item-background--hover": "#f7f7f6",
|
||||
"color-link": "#39b54a",
|
||||
"color-link--visited": "#39b54a",
|
||||
"color-link--hover": "#d98014",
|
||||
"color-link--visited--hover": "#d98014",
|
||||
"color-admonition-text": "#651fff",
|
||||
"font-stack": "Nunito, -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji",
|
||||
},
|
||||
"dark_css_variables": {
|
||||
"color-brand-primary": "#39b54a",
|
||||
"color-brand-content": "#39b54a",
|
||||
"color-brand-visited": "#d9e021",
|
||||
"color-background-primary": "#2e3436",
|
||||
"color-background-border": "#2e3436",
|
||||
"color-foreground-primary": "#eeeeec",
|
||||
"color-sidebar-item-background--hover": "#2e3436",
|
||||
"color-link": "#39b54a",
|
||||
"color-link--visited": "#39b54a",
|
||||
"color-link--hover": "#d98014",
|
||||
"color-link--visited--hover": "#d98014",
|
||||
"color-admonition-text": "#EEEEEC",
|
||||
"font-stack": "Nunito, -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji",
|
||||
},
|
||||
"footer_icons": [
|
||||
{
|
||||
"name": "IfcOpenShell",
|
||||
"url": "https://ifcopenshell.org",
|
||||
"html": """
|
||||
<img src="https://ifcopenshell.org/assets/images/logo.png" style="width: auto;" />
|
||||
""",
|
||||
"class": "",
|
||||
},
|
||||
{
|
||||
"name": "GitHub",
|
||||
"url": "https://github.com/IfcOpenShell/IfcOpenShell/tree/v0.8.0/src/bonsaiviewer/docs",
|
||||
"html": """
|
||||
<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"></path>
|
||||
</svg>
|
||||
""",
|
||||
"class": "",
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
Autodesk Connector
|
||||
==================
|
||||
|
||||
The Autodesk connector integrates Bonsai Viewer with Autodesk Forma, APS, and
|
||||
Docs. It implements the cloud connector protocol and runs as a separate process
|
||||
that Bonsai Viewer launches and communicates with over standard input and
|
||||
standard output.
|
||||
|
||||
The connector UI is built with CustomTkinter. The Python runtime used for
|
||||
development or packaging must include ``tkinter``. On Gentoo, make sure
|
||||
``dev-lang/python`` is built with ``USE="tk"``.
|
||||
|
||||
Install
|
||||
-------
|
||||
|
||||
From the repository root:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd src/bonsaiviewer-autodesk
|
||||
python -m venv venv
|
||||
source venv/bin/activate
|
||||
pip install -e .
|
||||
|
||||
Run
|
||||
---
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
bonsaiviewer-autodesk
|
||||
|
||||
The connector launches without configuration. On first run, open the settings
|
||||
dialog, or set the ``APS_CLIENT_ID`` environment variable, to configure the
|
||||
Autodesk client ID and OAuth callback port.
|
||||
|
||||
For direct protocol testing, send newline-delimited JSON-RPC 2.0 requests on
|
||||
standard input:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{"jsonrpc":"2.0","id":"0","method":"open_settings"}
|
||||
{"jsonrpc":"2.0","id":"1","method":"pull_ifcfed_interactive"}
|
||||
{"jsonrpc":"2.0","id":"2","method":"pull_models","params":[{"display_name":"foo.ifc","id":"abc","source":{"connector":"autodesk","hub_id":"b.hub","project_id":"b.proj","item_id":"urn:adsk...","version_id":"latest"}}]}
|
||||
{"jsonrpc":"2.0","id":"3","method":"push_ifcfed_interactive","params":{"path":"/tmp/project.ifcfed"}}
|
||||
{"jsonrpc":"2.0","id":"4","method":"push_ifcfed","params":{"path":"/tmp/project.ifcfed","manifest":{"connector":"autodesk","hub_id":"b.hub","project_id":"b.proj","item_id":"urn:adsk..."}}}
|
||||
|
||||
Bonsai Viewer is expected to launch this binary once per session and keep it
|
||||
alive until shutdown. Closing the connector's standard input triggers a clean
|
||||
exit.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
The connector reads the Autodesk client ID from these places, in order:
|
||||
|
||||
1. ``APS_CLIENT_ID`` environment variable.
|
||||
2. ``settings.json`` in the connector config directory, written by the settings
|
||||
dialog.
|
||||
|
||||
The OAuth callback host is always ``localhost``. The callback port defaults to
|
||||
``8080`` and can be changed in the settings dialog.
|
||||
|
||||
The config directory is platform-specific:
|
||||
|
||||
- Linux: ``~/.config/bonsaiviewer-autodesk/``
|
||||
- macOS: ``~/Library/Application Support/bonsaiviewer-autodesk/``
|
||||
- Windows: ``%APPDATA%\bonsaiviewer-autodesk\``
|
||||
|
||||
OAuth tokens are stored in the OS keychain, keyed by the client ID. Changing
|
||||
the client ID starts a fresh sign-in session. The keychain backend is Secret
|
||||
Service on Linux, Keychain on macOS, and Credential Manager on Windows.
|
||||
|
||||
Cache
|
||||
-----
|
||||
|
||||
The connector owns its own cache. On Linux, resolved files live under:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
~/.cache/bonsaiviewer-autodesk/
|
||||
ifcfeds/<hash>/<name>.ifcfed[.manifest]
|
||||
models/<hash>/<filename>
|
||||
|
||||
Each resolved file is the sole child in its directory so Bonsai Viewer can
|
||||
write sidecar files, such as ``.ifcview``, next to it without colliding. A new
|
||||
resolved model version lands in a fresh ``models/<hash>/`` directory. Old cache
|
||||
directories may be removed manually to clear space.
|
||||
|
||||
Status
|
||||
------
|
||||
|
||||
Implemented:
|
||||
|
||||
- strict JSON-RPC 2.0 host over stdio
|
||||
- APS PKCE sign-in with keyring-backed token storage
|
||||
- hub, project, and folder browsing
|
||||
- ``pull_ifcfed_interactive``, ``pull_ifcfed``, ``pull_models``, and
|
||||
``pull_models_interactive``
|
||||
- ``push_ifcfed_interactive``, ``push_ifcfed``,
|
||||
``push_model_interactive``, and ``push_model``
|
||||
- ``open_settings`` for client ID, callback port, and sign-out
|
||||
- connector-managed cache with one resolved file per directory
|
||||
- adjacent ``.ifcfed.manifest`` files written and read alongside
|
||||
``.ifcfed`` files
|
||||
|
||||
Not implemented:
|
||||
|
||||
- JSON-RPC notifications for progress streaming; the connector shows its own
|
||||
progress dialog
|
||||
- cancellation of in-flight downloads
|
||||
- subdirectory upload layouts inside push destinations
|
||||
@@ -0,0 +1,130 @@
|
||||
Packaging the Autodesk Connector
|
||||
================================
|
||||
|
||||
The Autodesk connector is shipped as a self-contained folder that can be
|
||||
dropped into the Bonsai Viewer connectors directory. PyInstaller bundles the
|
||||
Python interpreter, Qt, and dependencies so end users do not need Python
|
||||
installed.
|
||||
|
||||
PyInstaller does not cross-compile. Each operating system must build its own
|
||||
package, typically through a CI matrix.
|
||||
|
||||
Output
|
||||
------
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
dist/
|
||||
autodesk/
|
||||
connector.json
|
||||
bonsaiviewer-autodesk[.exe]
|
||||
_internal/...
|
||||
autodesk-<os>-<arch>.zip
|
||||
|
||||
The ``autodesk/`` folder is what Bonsai Viewer expects under the
|
||||
``connectors`` directory bundled next to the viewer executable
|
||||
(``<application-dir>/connectors/``).
|
||||
|
||||
Build
|
||||
-----
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd src/bonsaiviewer-autodesk
|
||||
python -m venv venv
|
||||
source venv/bin/activate
|
||||
pip install -e ".[build]"
|
||||
python packaging/build.py
|
||||
|
||||
On Windows, activate the virtual environment with
|
||||
``venv\Scripts\activate``.
|
||||
|
||||
The build script:
|
||||
|
||||
1. cleans ``dist/`` and ``build/``
|
||||
2. runs PyInstaller against ``packaging/bonsaiviewer-autodesk.spec``
|
||||
3. renames the produced folder to ``autodesk/``
|
||||
4. copies ``connector.json`` into it
|
||||
5. zips the folder as ``autodesk-<os>-<arch>.zip``
|
||||
|
||||
The UI uses Tcl/Tk through CustomTkinter, which keeps the bundle small. Expect
|
||||
roughly 50 MB unpacked or 21 MB zipped per OS. The Python used to build must
|
||||
include ``tkinter``.
|
||||
|
||||
Linux
|
||||
-----
|
||||
|
||||
Build on the oldest glibc you intend to support. Binaries built on a newer
|
||||
glibc will not run on older distributions. Ubuntu 22.04 LTS, with glibc 2.35,
|
||||
is a reasonable lowest common denominator in 2026.
|
||||
|
||||
The runtime keyring backend is Secret Service, such as gnome-keyring or
|
||||
KWallet. End users need a Secret Service provider running.
|
||||
|
||||
Expected output: ``autodesk-linux-x86_64.zip`` and/or an ARM64 archive.
|
||||
|
||||
macOS
|
||||
-----
|
||||
|
||||
Each architecture builds separately. To support Apple Silicon and Intel, build
|
||||
on each architecture and ship two zips, or post-process with ``lipo`` to
|
||||
produce universal binaries.
|
||||
|
||||
The runtime keyring backend is the system Keychain. For distribution outside
|
||||
the developer's machine, codesign the executable and Tcl/Tk dylibs and notarize
|
||||
the bundle. Unsigned binaries trigger Gatekeeper warnings. Codesigning is left
|
||||
to the caller; the spec's ``codesign_identity`` field can be wired up.
|
||||
|
||||
Expected output: ``autodesk-macos-arm64.zip`` and/or
|
||||
``autodesk-macos-x86_64.zip``.
|
||||
|
||||
Windows
|
||||
-------
|
||||
|
||||
Build with the Microsoft Visual C++ runtime available, which is usually true
|
||||
for modern Python distributions. The runtime keyring backend is Credential
|
||||
Manager.
|
||||
|
||||
The executable is built with ``console=True`` because the connector speaks
|
||||
JSON-RPC over stdio. Bonsai Viewer must launch it without showing a console
|
||||
window, for example with Qt's ``QProcess::setCreateProcessArgumentsModifier``
|
||||
and ``CREATE_NO_WINDOW``.
|
||||
|
||||
For distribution, sign the executable with an Authenticode certificate to avoid
|
||||
SmartScreen warnings. Signing is left to the caller.
|
||||
|
||||
Expected output: ``autodesk-windows-x86_64.zip``.
|
||||
|
||||
Install a Built Connector
|
||||
-------------------------
|
||||
|
||||
Extract the zip into the ``connectors`` directory next to the Bonsai Viewer
|
||||
executable.
|
||||
|
||||
Linux:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
unzip dist/autodesk-linux-x86_64.zip -d <application-dir>/connectors/
|
||||
|
||||
macOS:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
unzip dist/autodesk-macos-arm64.zip -d "<application-dir>/connectors/"
|
||||
|
||||
Windows PowerShell:
|
||||
|
||||
.. code-block:: powershell
|
||||
|
||||
Expand-Archive dist\autodesk-windows-x86_64.zip -DestinationPath "<application-dir>\connectors\"
|
||||
|
||||
Bonsai Viewer discovers the connector on next launch.
|
||||
|
||||
Out of Scope
|
||||
------------
|
||||
|
||||
- signing and notarization
|
||||
- CI matrix setup
|
||||
- auto-update
|
||||
- universal macOS binaries via ``lipo``
|
||||
@@ -0,0 +1,384 @@
|
||||
Cloud Connector Protocol
|
||||
========================
|
||||
|
||||
Bonsai Viewer can load and save projects and models from cloud platforms
|
||||
through connectors. A connector is a separate application launched by Bonsai
|
||||
Viewer. It handles authentication, browsing, downloads, uploads, caching, and
|
||||
platform-specific behaviour.
|
||||
|
||||
The protocol currently covers:
|
||||
|
||||
- projects: ``.ifcfed``
|
||||
- models: ``.ifc``, ``.rdb``, ``.ifcview``, ``.rdbview``
|
||||
|
||||
Issues, clash results, specifications, and other resources are not yet defined.
|
||||
|
||||
Communication
|
||||
-------------
|
||||
|
||||
Bonsai Viewer launches one connector process per session, on first use, and
|
||||
keeps it alive for the duration of the session. Communication uses
|
||||
newline-delimited JSON-RPC 2.0 over standard input and standard output:
|
||||
|
||||
- requests and responses are single-line JSON objects
|
||||
- every message is terminated by a single newline
|
||||
- the connector must not emit literal newlines inside a JSON message
|
||||
- diagnostics may be written to standard error
|
||||
|
||||
Bonsai Viewer shuts down a connector by closing its standard input. The
|
||||
connector should exit cleanly. If it does not exit within a few seconds, Bonsai
|
||||
Viewer may terminate it.
|
||||
|
||||
Connector Scope
|
||||
---------------
|
||||
|
||||
Bonsai Viewer only works with local files. If a project or model is not local,
|
||||
the viewer asks a connector to resolve it. The connector returns a local path
|
||||
and optional cloud metadata. It must not modify the model file itself.
|
||||
|
||||
The connector handles anything specific to the cloud platform or data source:
|
||||
authentication, browsing, filtering, searches, revision pinning, progress UI,
|
||||
caches, and platform-specific rules. A connector may show its own UI or run
|
||||
without UI.
|
||||
|
||||
Returned files must be the sole child in their directory. This allows Bonsai
|
||||
Viewer to write adjacent sidecars, temporary files, database locks, or helper
|
||||
files without filename collisions. A connector may invalidate cached files by
|
||||
deleting the whole resolved directory. A new cloud revision should resolve to a
|
||||
fresh directory.
|
||||
|
||||
Projects
|
||||
--------
|
||||
|
||||
A project is an ``.ifcfed`` file. It stores project settings and model entries.
|
||||
|
||||
Example project:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"created": "2026-04-29T21:22:36Z",
|
||||
"modified": "2026-04-29T21:22:36Z",
|
||||
"home_view": null,
|
||||
"models": []
|
||||
}
|
||||
|
||||
A cloud-sourced project may have an adjacent ``.ifcfed.manifest`` file storing
|
||||
connector-specific source metadata.
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"connector": "mycompany",
|
||||
"version": "2",
|
||||
"url": "https://example.com/project.ifcfed"
|
||||
}
|
||||
|
||||
Models
|
||||
------
|
||||
|
||||
Models are listed in the ``.ifcfed`` file. A model may point to a local path or
|
||||
to a cloud connector source.
|
||||
|
||||
Cloud connector source data is intentionally connector-specific. For example,
|
||||
a connector may store whether a model is pinned to one revision or should
|
||||
always resolve to the latest revision.
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
[
|
||||
{
|
||||
"display_name": "foo.ifc",
|
||||
"id": "0503642e-e2f6-4700-87fd-16479542e801",
|
||||
"source": {
|
||||
"connector": "local",
|
||||
"path": "path/to/foo.ifc"
|
||||
}
|
||||
},
|
||||
{
|
||||
"display_name": "bar.ifc",
|
||||
"id": "5fc69e6a-1ff0-4d8a-82c6-2215df53d2ed",
|
||||
"source": {
|
||||
"connector": "autodesk",
|
||||
"version": "1",
|
||||
"hub_id": "b.hub123",
|
||||
"project_id": "b.project456",
|
||||
"item_id": "urn:adsk.wipprod:dm.lineage:abc",
|
||||
"version_id": "urn:adsk.wipprod:fs.file:vf.xyz?version=3"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
Cloud metadata such as filename, cloud ID, revision, and date modified is not
|
||||
specified or stored in the ``.ifcfed``. It is returned by the connector when
|
||||
requested. Bonsai Viewer displays returned cloud metadata as text. The keys
|
||||
``author``, ``revision``, and ``date`` may be shown in more prominent UI
|
||||
locations.
|
||||
|
||||
Open from Cloud
|
||||
---------------
|
||||
|
||||
``pull_ifcfed_interactive`` opens an ``.ifcfed`` from a cloud platform and
|
||||
starts a fresh session.
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{ "jsonrpc": "2.0", "id": "0", "method": "pull_ifcfed_interactive" }
|
||||
|
||||
The connector authenticates and lets the user browse or choose a project. It
|
||||
downloads or resolves the ``.ifcfed`` into a connector-managed directory,
|
||||
creates an adjacent ``.ifcfed.manifest``, and returns the local path:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{ "jsonrpc": "2.0", "id": "0", "result": { "path": "/path/to/project/file.ifcfed" } }
|
||||
|
||||
Bonsai Viewer loads the project, then calls ``pull_models`` for cloud-sourced
|
||||
models referenced by the ``.ifcfed``:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": "1",
|
||||
"method": "pull_models",
|
||||
"params": [
|
||||
{ "display_name": "bar.ifc", "id": "...", "source": { "connector": "autodesk" } }
|
||||
]
|
||||
}
|
||||
|
||||
The connector returns one result per requested model. A result may include
|
||||
optional metadata. ``null`` means that item was skipped or failed without
|
||||
aborting the whole batch.
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": "1",
|
||||
"result": [
|
||||
{
|
||||
"path": "/path/to/model.ifc",
|
||||
"metadata": { "revision": "B", "date": "2nd Oct 2025" }
|
||||
},
|
||||
null
|
||||
]
|
||||
}
|
||||
|
||||
Downloading the latest version of every model immediately is not required. A
|
||||
connector may download the latest file, use a pinned revision, offer the user a
|
||||
choice, skip a model, or return a cached file. The user can reopen or sync the
|
||||
project later.
|
||||
|
||||
Sync Cloud to Local
|
||||
-------------------
|
||||
|
||||
``pull_ifcfed`` refreshes the cloud-sourced project without prompting the user.
|
||||
It is available when the project has cloud resources: an adjacent
|
||||
``.ifcfed.manifest`` for the project itself, one or more cloud-sourced models,
|
||||
or both.
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": "0",
|
||||
"method": "pull_ifcfed",
|
||||
"params": {
|
||||
"connector": "mycompany",
|
||||
"version": "2",
|
||||
"url": "https://example.com/project.ifcfed"
|
||||
}
|
||||
}
|
||||
|
||||
The connector returns a local ``.ifcfed`` path and writes a fresh adjacent
|
||||
manifest. Bonsai Viewer then continues by calling ``pull_models`` for
|
||||
cloud-sourced models. The project-refresh phase and model-refresh phase are
|
||||
independent. If no manifest exists, the project refresh phase is skipped and
|
||||
Bonsai Viewer refreshes only cloud-sourced models.
|
||||
|
||||
If the returned ``.ifcfed`` is unchanged from the currently loaded file, Bonsai
|
||||
Viewer may skip the fresh-session reload and continue to model refresh. How
|
||||
"unchanged" is determined, such as byte equality, hash, or modified time, is
|
||||
left to Bonsai Viewer.
|
||||
|
||||
Save Projects to Cloud
|
||||
----------------------
|
||||
|
||||
``push_ifcfed_interactive`` is the cloud equivalent of Save As. It pushes an
|
||||
``.ifcfed`` to a new user-selected cloud location.
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": "0",
|
||||
"method": "push_ifcfed_interactive",
|
||||
"params": { "path": "/tmp/path/to/project.ifcfed" }
|
||||
}
|
||||
|
||||
The connector uploads the file, writes an adjacent manifest, and returns the
|
||||
resolved local path.
|
||||
|
||||
``push_ifcfed`` is the cloud equivalent of Save. It pushes back to the existing
|
||||
cloud location described by the manifest.
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": "0",
|
||||
"method": "push_ifcfed",
|
||||
"params": {
|
||||
"path": "/tmp/path/to/project.ifcfed",
|
||||
"manifest": {
|
||||
"connector": "mycompany",
|
||||
"version": "2",
|
||||
"url": "https://example.com/project.ifcfed"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
The connector may update the manifest if the cloud platform returns a new
|
||||
revision or version identifier.
|
||||
|
||||
Add and Save Models
|
||||
-------------------
|
||||
|
||||
``pull_models_interactive`` lets the user choose one or more cloud models to
|
||||
add to the current project.
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{ "jsonrpc": "2.0", "id": "0", "method": "pull_models_interactive" }
|
||||
|
||||
The connector returns model entries with ``display_name``, ``source``, a local
|
||||
``path``, and optional metadata:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": "0",
|
||||
"result": [
|
||||
{
|
||||
"display_name": "bar.ifc",
|
||||
"source": { "connector": "autodesk" },
|
||||
"path": "/path/to/model.ifc",
|
||||
"metadata": { "revision": "B", "date": "2nd Oct 2025" }
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Bonsai Viewer stores ``display_name`` and ``source`` in the ``.ifcfed`` and
|
||||
loads the model from ``path``. The path and metadata are not stored in the
|
||||
``.ifcfed``.
|
||||
|
||||
``push_model_interactive`` is Save Model As to Cloud:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": "0",
|
||||
"method": "push_model_interactive",
|
||||
"params": { "path": "/tmp/path/to/model.ifc" }
|
||||
}
|
||||
|
||||
``push_model`` saves a model back to the existing cloud location described by
|
||||
the model's ``source``:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": "0",
|
||||
"method": "push_model",
|
||||
"params": {
|
||||
"path": "/tmp/path/to/model.ifc",
|
||||
"source": { "connector": "autodesk", "hub_id": "b.hub123" }
|
||||
}
|
||||
}
|
||||
|
||||
The connector returns an updated ``source`` and optional metadata. Bonsai
|
||||
Viewer replaces the model's ``source`` in the ``.ifcfed``.
|
||||
|
||||
Conflict handling for non-interactive push methods is the connector's
|
||||
responsibility. The connector may overwrite, prompt, reject with a JSON-RPC
|
||||
error, or apply a platform-specific policy.
|
||||
|
||||
Settings and Errors
|
||||
-------------------
|
||||
|
||||
A connector may implement ``open_settings`` for credentials, sign-out, default
|
||||
folders, cache management, or other connector-specific settings.
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{ "jsonrpc": "2.0", "id": "0", "method": "open_settings" }
|
||||
|
||||
If a connector returns JSON-RPC ``Method not found`` with code ``-32601``,
|
||||
Bonsai Viewer treats it as having no settings UI.
|
||||
|
||||
The settings result is currently always an empty object. Future revisions may
|
||||
add optional fields, such as a refreshed display label for the connector.
|
||||
|
||||
The connector owns user-facing error handling. Bonsai Viewer understands only:
|
||||
|
||||
- per-item soft failure: ``null`` in a result array
|
||||
- whole-call hard failure: a JSON-RPC error object
|
||||
|
||||
Diagnostic details should be written to standard error for logs.
|
||||
|
||||
Permissions
|
||||
-----------
|
||||
|
||||
Permissions are entirely connector-managed. A federation may contain models
|
||||
from multiple platforms, and some resources may fail while others succeed.
|
||||
Bonsai Viewer tolerates partial failure and does not require all remote models
|
||||
to resolve successfully.
|
||||
|
||||
Discovery
|
||||
---------
|
||||
|
||||
A connector is shipped as a folder containing a ``connector.json`` manifest and
|
||||
an executable entry point.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
<connectors-dir>/
|
||||
autodesk/
|
||||
connector.json
|
||||
bonsaiviewer-autodesk
|
||||
...
|
||||
|
||||
Example ``connector.json``:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"id": "autodesk",
|
||||
"name": "Autodesk Forma",
|
||||
"version": "0.1.0",
|
||||
"exec": "./bonsaiviewer-autodesk"
|
||||
}
|
||||
|
||||
Fields:
|
||||
|
||||
- ``id`` is the stable identifier used in ``.ifcfed`` ``source.connector``
|
||||
fields and in ``.ifcfed.manifest`` files.
|
||||
- ``name`` is the human-readable UI label.
|
||||
- ``version`` is informational.
|
||||
- ``exec`` is the connector executable. Relative paths are resolved against the
|
||||
connector folder. On Windows, Bonsai Viewer also tries ``<exec>.exe`` if the
|
||||
path does not exist as written.
|
||||
|
||||
Bonsai Viewer scans the ``connectors`` directory bundled alongside the
|
||||
executable (``<application-dir>/connectors/``).
|
||||
|
||||
Every immediate subdirectory containing ``connector.json`` is treated as a
|
||||
connector. Connectors are launched on demand, not at startup.
|
||||
|
||||
If two folders declare the same ``id``, the first one wins and the other is
|
||||
skipped with a log warning. Malformed manifests or missing executables are
|
||||
reported when relevant without preventing other connectors from loading.
|
||||
@@ -0,0 +1,14 @@
|
||||
Connectors
|
||||
==========
|
||||
|
||||
Bonsai Viewer connectors are separate applications that let the viewer open
|
||||
and save projects or models from cloud platforms. The viewer itself works with
|
||||
local files; a connector resolves cloud resources into local cached files and
|
||||
returns the metadata needed to keep them connected to the cloud source.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
cloud_sync_protocol
|
||||
autodesk
|
||||
autodesk_packaging
|
||||
@@ -0,0 +1,45 @@
|
||||
Learn Bonsai Viewer
|
||||
===================
|
||||
|
||||
Hello world. Bonsai Viewer is a desktop application for opening, federating,
|
||||
and reviewing IFC models.
|
||||
|
||||
It is focused on fast model viewing rather than authoring. It works with IFC
|
||||
files and viewer-oriented formats such as ``.ifcview`` and ``.rdbview``.
|
||||
|
||||
.. only:: builder_html and (not singlehtml)
|
||||
|
||||
.. container:: toc-cards
|
||||
|
||||
.. container:: card
|
||||
|
||||
Getting started
|
||||
Open a model, navigate the scene, and inspect project data.
|
||||
|
||||
.. container:: card
|
||||
|
||||
Large models
|
||||
Use viewer caches and packaged formats for faster loading.
|
||||
|
||||
.. container:: card
|
||||
|
||||
Federation
|
||||
Combine multiple model files into one review session.
|
||||
|
||||
.. container:: card
|
||||
|
||||
:doc:`/connectors/index`
|
||||
Load models from external systems and cloud workflows.
|
||||
|
||||
.. container:: global-index-toc
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
:caption: Contents
|
||||
:maxdepth: 2
|
||||
|
||||
connectors/index
|
||||
|
||||
Need more help? Join the `live chat <https://osarch.org/chat/>`__ or `community
|
||||
forums <https://community.osarch.org>`__. Something strange happening? Please
|
||||
`report a bug <https://github.com/IfcOpenShell/IfcOpenShell/issues>`__.
|
||||
@@ -0,0 +1,35 @@
|
||||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=.
|
||||
set BUILDDIR=_build
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
|
||||
:end
|
||||
popd
|
||||
@@ -0,0 +1,3 @@
|
||||
sphinx
|
||||
furo
|
||||
sphinx-copybutton
|
||||
@@ -83,7 +83,7 @@ QString userConnectorsDir() {
|
||||
// Linux -> ~/.local/share
|
||||
// macOS -> ~/Library/Application Support
|
||||
// Win -> %APPDATA% (Roaming)
|
||||
// matching CLOUD_SYNC_PROTOCOL.md's listed locations.
|
||||
// matching the Bonsai Viewer connector protocol docs.
|
||||
const QString base = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
|
||||
return QDir(base).filePath("IfcOpenShell/BonsaiViewer/connectors");
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ struct ConnectorManifest {
|
||||
// otherwise a bare name for PATH lookup at launch
|
||||
};
|
||||
|
||||
// Scans the per-user connectors directory per CLOUD_SYNC_PROTOCOL.md.
|
||||
// Scans the per-user connectors directory per the connector protocol docs.
|
||||
// First match wins for any given id; duplicates and malformed manifests
|
||||
// are skipped with a qWarning. Returned in discovery order so first-wins
|
||||
// is observable to callers.
|
||||
|
||||
Reference in New Issue
Block a user