parent
6686141d3b
commit
2424eeb74d
10 changed files with 56 additions and 22 deletions
|
|
@ -18,6 +18,7 @@ browser can't provide. This page lists the differences.
|
||||||
| Parallelism | Multi-threaded (rayon) | Single-threaded |
|
| Parallelism | Multi-threaded (rayon) | Single-threaded |
|
||||||
| GPU backend | Vulkan / DX12 / Metal (wgpu) | WebGL2 (WebGPU where available) |
|
| GPU backend | Vulkan / DX12 / Metal (wgpu) | WebGL2 (WebGPU where available) |
|
||||||
| Update check / external links | `ureq`, `open` | skipped / `window.open` |
|
| Update check / external links | `ureq`, `open` | skipped / `window.open` |
|
||||||
|
| External plugins | Native packages + Plugin Manager | **No** — native libraries cannot run in a browser |
|
||||||
|
|
||||||
## Details
|
## Details
|
||||||
|
|
||||||
|
|
@ -76,6 +77,14 @@ native and sequential `std` iterators on wasm, so the same call sites run in
|
||||||
parallel on the desktop and serially in the browser. Large drawings are slower
|
parallel on the desktop and serially in the browser. Large drawings are slower
|
||||||
on the web.
|
on the web.
|
||||||
|
|
||||||
|
### External plugins — web: unavailable
|
||||||
|
|
||||||
|
Marketplace plugins are native `.dll`, `.so`, or `.dylib` packages launched in
|
||||||
|
an isolated child process. Browsers cannot load those libraries or spawn the
|
||||||
|
plugin runner, so the web build does not show the Plugin Manager or register
|
||||||
|
its commands. Installed desktop plugins remain in the per-user plugins folder
|
||||||
|
and load again on the next desktop launch.
|
||||||
|
|
||||||
### Platform shims (`src/sys.rs`)
|
### Platform shims (`src/sys.rs`)
|
||||||
- `open_url`: `open::that` on native, `window.open(_blank)` on web.
|
- `open_url`: `open::that` on native, `window.open(_blank)` on web.
|
||||||
- `download_bytes`: web only (Blob + anchor download).
|
- `download_bytes`: web only (Blob + anchor download).
|
||||||
|
|
|
||||||
|
|
@ -333,8 +333,9 @@ plugin dead, and reports a `CallTimeout` error via the normal plugin error path.
|
||||||
|
|
||||||
## Marketplace
|
## Marketplace
|
||||||
|
|
||||||
The **Plugin Manager** (`PLUGINS` / `PLUGINMANAGER`, or the Start-page button)
|
The desktop **Plugin Manager** (`PLUGINS` / `PLUGINMANAGER`, or the Start-page
|
||||||
installs plugins from GitHub Releases:
|
button) installs plugins from GitHub Releases. It is hidden in the browser
|
||||||
|
build because marketplace packages are native dynamic libraries:
|
||||||
|
|
||||||
- **Curated registry** — [`plugins/registry.json`](../plugins/registry.json) in
|
- **Curated registry** — [`plugins/registry.json`](../plugins/registry.json) in
|
||||||
this repo lists discoverable plugins. The host fetches it from `main` at
|
this repo lists discoverable plugins. The host fetches it from `main` at
|
||||||
|
|
@ -343,7 +344,7 @@ installs plugins from GitHub Releases:
|
||||||
[`plugins/README.md`](../plugins/README.md)); merged PRs reach every user with
|
[`plugins/README.md`](../plugins/README.md)); merged PRs reach every user with
|
||||||
no app update.
|
no app update.
|
||||||
- **Manual link** — *Add a repository* (`owner/repo`) for unlisted or private
|
- **Manual link** — *Add a repository* (`owner/repo`) for unlisted or private
|
||||||
dev repos; linked repos persist in `settings.txt` (`plugin_repos=`).
|
dev repos; linked repos persist in `settings.json`.
|
||||||
- **Install / upgrade / reinstall** — pick a release from the dropdown and
|
- **Install / upgrade / reinstall** — pick a release from the dropdown and
|
||||||
*Install*; the host downloads the platform asset + `plugin.toml` into the
|
*Install*; the host downloads the platform asset + `plugin.toml` into the
|
||||||
plugins folder, checking `api_version` first. Reinstalling overwrites and
|
plugins folder, checking `api_version` first. Reinstalling overwrites and
|
||||||
|
|
|
||||||
|
|
@ -236,8 +236,6 @@ pub fn start_allowed(cmd: &str) -> bool {
|
||||||
| "REPORT"
|
| "REPORT"
|
||||||
| "CHANGELOG"
|
| "CHANGELOG"
|
||||||
| "ABOUT"
|
| "ABOUT"
|
||||||
| "PLUGINS"
|
|
||||||
| "PLUGINMANAGER"
|
|
||||||
| "DONATE"
|
| "DONATE"
|
||||||
| "WEBVERSION"
|
| "WEBVERSION"
|
||||||
| "HELP"
|
| "HELP"
|
||||||
|
|
@ -247,6 +245,8 @@ pub fn start_allowed(cmd: &str) -> bool {
|
||||||
| "CUILOAD"
|
| "CUILOAD"
|
||||||
| "CUIIMPORT"
|
| "CUIIMPORT"
|
||||||
)
|
)
|
||||||
|
|| (!cfg!(target_arch = "wasm32")
|
||||||
|
&& matches!(cmd, "PLUGINS" | "PLUGINMANAGER"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Autocomplete registry — one-shot commands ──────────────────────────────
|
// ── Autocomplete registry — one-shot commands ──────────────────────────────
|
||||||
|
|
|
||||||
|
|
@ -212,10 +212,17 @@ impl OpenCADStudio {
|
||||||
return Some(Task::done(Message::AboutOpen));
|
return Some(Task::done(Message::AboutOpen));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
"PLUGINS" | "PLUGINMANAGER" => {
|
"PLUGINS" | "PLUGINMANAGER" => {
|
||||||
return Some(Task::done(Message::PluginManagerOpen));
|
return Some(Task::done(Message::PluginManagerOpen));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
"PLUGINS" | "PLUGINMANAGER" => {
|
||||||
|
self.command_line
|
||||||
|
.push_info("External plugins are available in the desktop app.");
|
||||||
|
}
|
||||||
|
|
||||||
"CHANGELOG" => {
|
"CHANGELOG" => {
|
||||||
crate::sys::open_url("https://github.com/HakanSeven12/OpenCADStudio/releases");
|
crate::sys::open_url("https://github.com/HakanSeven12/OpenCADStudio/releases");
|
||||||
self.command_line.push_info("Opening release notes...");
|
self.command_line.push_info("Opening release notes...");
|
||||||
|
|
|
||||||
|
|
@ -1313,6 +1313,7 @@ impl ClipboardDeps {
|
||||||
pub enum ModalKind {
|
pub enum ModalKind {
|
||||||
About,
|
About,
|
||||||
Shortcuts,
|
Shortcuts,
|
||||||
|
#[cfg_attr(target_arch = "wasm32", allow(dead_code))]
|
||||||
PluginManager,
|
PluginManager,
|
||||||
UpdateNotice,
|
UpdateNotice,
|
||||||
Layers,
|
Layers,
|
||||||
|
|
|
||||||
|
|
@ -291,8 +291,11 @@ impl OpenCADStudio {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
pub(in crate::app) fn fetch_releases_task(&self, _repo: String) -> Task<Message> {
|
pub(in crate::app) fn fetch_releases_task(&self, repo: String) -> Task<Message> {
|
||||||
Task::none()
|
Task::done(Message::PluginReleasesFetched(
|
||||||
|
repo,
|
||||||
|
Err("External plugins are available in the desktop app.".to_string()),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Background task: fetch a repository README from its default branch.
|
/// Background task: fetch a repository README from its default branch.
|
||||||
|
|
@ -306,8 +309,11 @@ impl OpenCADStudio {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
pub(in crate::app) fn fetch_plugin_readme_task(&self, _repo: String) -> Task<Message> {
|
pub(in crate::app) fn fetch_plugin_readme_task(&self, repo: String) -> Task<Message> {
|
||||||
Task::none()
|
Task::done(Message::PluginReadmeFetched(
|
||||||
|
repo,
|
||||||
|
Err("Plugin details are available in the desktop app.".to_string()),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Background task: download and install the `tag` release of `owner/repo`.
|
/// Background task: download and install the `tag` release of `owner/repo`.
|
||||||
|
|
@ -328,7 +334,9 @@ impl OpenCADStudio {
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
pub(in crate::app) fn install_task(&self, _repo: String, _tag: String) -> Task<Message> {
|
pub(in crate::app) fn install_task(&self, _repo: String, _tag: String) -> Task<Message> {
|
||||||
Task::none()
|
Task::done(Message::PluginInstalled(Err(
|
||||||
|
"External plugins are available in the desktop app.".to_string(),
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gather the full persisted config (all sections) from live app state.
|
/// Gather the full persisted config (all sections) from live app state.
|
||||||
|
|
|
||||||
|
|
@ -4056,14 +4056,20 @@ impl OpenCADStudio {
|
||||||
|
|
||||||
// ── Plugin Manager window ─────────────────────────────────────
|
// ── Plugin Manager window ─────────────────────────────────────
|
||||||
Message::PluginManagerOpen => {
|
Message::PluginManagerOpen => {
|
||||||
// Refresh the on-disk external-plugin list each time the manager
|
#[cfg(target_arch = "wasm32")]
|
||||||
// opens so newly dropped-in packages show up.
|
{
|
||||||
self.external_plugins = crate::plugin::external::discover();
|
self.command_line
|
||||||
self.marketplace_status.clear();
|
.push_info("External plugins are available in the desktop app.");
|
||||||
self.active_modal = Some(super::ModalKind::PluginManager);
|
return Task::none();
|
||||||
// Fetch the curated registry and release lists for linked repos.
|
}
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
{
|
{
|
||||||
|
// Refresh the on-disk external-plugin list each time the manager
|
||||||
|
// opens so newly dropped-in packages show up.
|
||||||
|
self.external_plugins = crate::plugin::external::discover();
|
||||||
|
self.marketplace_status.clear();
|
||||||
|
self.active_modal = Some(super::ModalKind::PluginManager);
|
||||||
|
// Fetch the curated registry and release lists for linked repos.
|
||||||
self.plugin_registry_loading = true;
|
self.plugin_registry_loading = true;
|
||||||
self.plugin_registry_error = None;
|
self.plugin_registry_error = None;
|
||||||
self.plugin_registry_error_details_open = false;
|
self.plugin_registry_error_details_open = false;
|
||||||
|
|
@ -4100,8 +4106,6 @@ impl OpenCADStudio {
|
||||||
}
|
}
|
||||||
return Task::batch(tasks);
|
return Task::batch(tasks);
|
||||||
}
|
}
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
Task::none()
|
|
||||||
}
|
}
|
||||||
Message::PluginManagerClose => {
|
Message::PluginManagerClose => {
|
||||||
self.close_active_modal();
|
self.close_active_modal();
|
||||||
|
|
|
||||||
|
|
@ -2299,12 +2299,12 @@ pub(super) fn start_page_view<'a>(
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
outline_btn("Options", Message::OptionsOpen).into(),
|
outline_btn("Options", Message::OptionsOpen).into(),
|
||||||
outline_btn("Plugins", Message::PluginManagerOpen).into(),
|
|
||||||
];
|
];
|
||||||
// The web build is already in the browser, so only the desktop offers a
|
// External plugins are native dynamic libraries and the web build is
|
||||||
// link to the web version.
|
// already in the browser, so both actions are desktop-only.
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
{
|
{
|
||||||
|
secondary_items.push(outline_btn("Plugins", Message::PluginManagerOpen).into());
|
||||||
// Filled with the active theme's primary colour.
|
// Filled with the active theme's primary colour.
|
||||||
secondary_items.push(
|
secondary_items.push(
|
||||||
button(text("OCS Web").size(14))
|
button(text("OCS Web").size(14))
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@
|
||||||
//! <lib<name>.so | .dll | .dylib>
|
//! <lib<name>.so | .dll | .dylib>
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
|
#![cfg_attr(target_arch = "wasm32", allow(dead_code))]
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
/// One entry in the curated plugin registry (`plugins/registry.json`).
|
/// One entry in the curated plugin registry (`plugins/registry.json`).
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,9 @@ pub struct MarketView<'a> {
|
||||||
pub status: &'a str,
|
pub status: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the command names for autocomplete.
|
// External plugins are native dynamic libraries, so the browser build must not
|
||||||
|
// advertise a manager it cannot use.
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
inventory::submit!(crate::command::CommandRegistration {
|
inventory::submit!(crate::command::CommandRegistration {
|
||||||
names: &["PLUGINS", "PLUGINMANAGER"]
|
names: &["PLUGINS", "PLUGINMANAGER"]
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue