feat(plugins): add BuiltinPlugin::on_load lifecycle callback

OpenCADStudio/plugins#901 (comment)

- Add BuiltinPlugin::on_load(&mut self, host: &mut dyn HostApi) with a default
  no-op implementation so existing plugins remain source-compatible.
- Invoke on_load once for V4 plugins immediately after the runner connects
  and before entering the request loop, giving plugins a HostApi surface to
  cache plugin_request_sender() or set up worker threads before any dispatch.
- V2/V3 plugins are unchanged: HostApi is only available during dispatch.
This commit is contained in:
Sebastian committed 2026-08-29 11:12:33 +02:00
1 parent 3024869de0
commit 996f6f7299
2 files changed
+22

No files matched your search

+10
View File
@@ -298,6 +298,16 @@ pub trait BuiltinPlugin: Send + Sync {
/// the V4 runner guarantees it is only called for plugins that report
/// API major 4 or newer.
fn on_notification(&mut self, _command_id: Option<u64>, _notification: HostNotification) {}
/// Lifecycle callback invoked once after the plugin has been loaded and its
/// manifest/ribbon have been accepted by the host. The plugin receives the
/// active document tab's `HostApi` so it can set up worker threads or cache
/// `plugin_request_sender()` before any user command runs.
///
/// Added after API v4. The default implementation does nothing, so existing
/// plugins remain source-compatible. The runner only calls this for plugins
/// that report API major 4 or newer.
fn on_load(&mut self, _host: &mut dyn HostApi) {}
}
/// A point-driven interactive command a plugin starts via
+12
View File
@@ -56,15 +56,27 @@ pub fn run(socket_name: &str, cdylib_path: &Path) -> Result<(), Box<dyn std::err
if version >= 4 {
let client = V4Client::connect_handshake(socket_name, &token)?;
// Give the plugin a chance to set up worker threads / cache the request
// sender before the host starts dispatching user commands.
invoke_on_load(&mut *plugin, &client, &interactive);
run_v4(&mut *plugin, &interactive, client)
} else {
let client = IpcClient::connect(socket_name)?;
eprintln!("[runner] connected to host");
client.send_handshake(&token)?;
// V2/V3 plugins receive HostApi only during dispatch, so on_load is not
// meaningful there; skip it to keep the old protocol unchanged.
run_v3(&*plugin, &interactive, client)
}
}
fn invoke_on_load(plugin: &mut dyn BuiltinPlugin, client: &V4Client, interactive: &InteractiveRegistry) {
let mut proxy = client.plugin_host_api(0, interactive.clone());
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
plugin.on_load(&mut proxy)
}));
}
fn run_v3(
plugin: &dyn BuiltinPlugin,
interactive: &InteractiveRegistry,