//! Request/response envelopes exchanged between the host and a plugin process. //! //! A single bidirectional socket is used. Each side sends either a request //! (expecting a response) or a response (to a previous request). This lets the //! host handle plugin RPCs inline while it waits for the result of a host→plugin //! request such as `Dispatch`, avoiding the need for two sockets or threads. //! //! Compatibility rule: new variants are appended at the end of every public enum //! (`HostRequest`, `HostResponse`, `PluginRequest`, `PluginResponse`, //! `RunnerHandshake`) so older plugins keep their bincode discriminant indices. //! The V4 additions are a separate frame layer in [`crate::ipc::v4`] and do not //! alter these enums. //! //! The pre-shared runner token is delivered through [`PLUGIN_TOKEN_ENV`] //! (`OCS_PLUGIN_TOKEN`). The runner must present the same token immediately //! after connecting or the host closes the connection. use serde::{Deserialize, Serialize}; use crate::host::{CommandSource, CommandStep, HostSettingValue}; use crate::manifest::ApiVersion; use crate::ribbon::owned::{OwnedPluginManifest, OwnedRibbonGroup}; pub use crate::host::PreviewWire; pub use codec::xdata::{ExtendedDataRecord, XDataValue}; pub use codec::{CadDocument, EntityType, Handle}; /// Events the host forwards to an active plugin `InteractiveCommand`. #[derive(Debug, Clone, Serialize, Deserialize)] pub enum InteractiveEvent { /// User clicked or specified a point coordinate. Point([f64; 3]), /// User pressed Enter or Return to complete input. Enter, /// User selected an existing entity in the drawing. ObjectPick { handle: Handle, pt: [f64; 3] }, /// User cancelled the prompt (e.g. pressed ESC), resetting interactive collection. Cancel, } /// Initial handshake sent by the plugin runner immediately after connecting. /// /// The runner proves it was spawned by this host by presenting a pre-shared /// token delivered through the `OCS_PLUGIN_TOKEN` environment variable. A /// mismatch causes the host to close the connection. /// /// `TokenV4` is appended as the last variant so the existing `Token(String)` /// variant keeps its bincode discriminant index (0), preserving V2/V3 wire /// compatibility. #[derive(Debug, Serialize, Deserialize)] pub enum RunnerHandshake { Token(String), TokenV4 { token: String, protocol_version: u32, }, } /// Environment variable through which the host passes the pre-shared /// authentication token to the plugin runner child process. pub const PLUGIN_TOKEN_ENV: &str = "OCS_PLUGIN_TOKEN"; /// Requests the host sends to the plugin runner. #[derive(Debug, Serialize, Deserialize)] pub enum HostRequest { GetManifest, GetRibbon, Dispatch { cmd: String, }, InteractiveEvent { command_id: u64, event: InteractiveEvent, }, GetPrompt { command_id: u64, }, NeedsEntityPick { command_id: u64, }, Shutdown, ExecuteCode { command_id: u64, source: CommandSource, code: String, tab_index: usize, }, /// V7: release an interactive command after completion or cancellation. DropInteractive { command_id: u64, }, /// V7: cursor move preview update during an interactive command. CursorMove { command_id: u64, pt: [f64; 3], }, } /// Responses the plugin runner sends back for `HostRequest`. #[derive(Debug, Serialize, Deserialize)] pub enum HostResponse { Bool(bool), CommandStep(Box), Text(String), Ribbon(Vec), Manifest(OwnedPluginManifest), Error(String), CodeExecutionResult(crate::host::ExecutionResult), PreviewWires(Vec), } /// Requests the plugin runner sends to the host. #[derive(Debug, Serialize, Deserialize)] pub enum PluginRequest { PushInfo(String), PushOutput(String), PushError(String), AddEntity(EntityType), /// Replace the existing entity carrying this entity's handle in place. UpdateEntity(EntityType), /// Delete the entity with `handle`. RemoveEntity { handle: Handle, }, BumpGeometry, ReadRecord { handle: Handle, app_name: String, }, WriteRecord { handle: Handle, record: ExtendedDataRecord, }, RemoveRecord { handle: Handle, app_name: String, }, PushUndo { label: String, }, SetDirty, StartInteractive { command_id: u64, }, DocumentSnapshot, /// Ask the host to create/refresh a shared-memory document view and return /// the file path + current version. OpenDocumentView, /// Add multiple entities in a single request. AddEntities(Vec), /// V4: ask the host to create/refresh a tab-keyed shared-memory document /// view and return the file path + current version. OpenDocumentViewV4 { tab_id: u64, }, /// V4: ask the host to close the tab-keyed shared-memory document view. CloseDocumentViewV4 { tab_id: u64, }, /// V4: ask the host for the stable tab identifier of the active tab. GetTabId, /// V5: ask the host for the filesystem path of the document in `tab_id`. DocumentPath { tab_id: u64, }, /// Add a layer to the active document with full initial properties. AddLayer(crate::host::LayerConfig), /// Modify specified properties of an existing layer in the active document. ModifyLayer(crate::host::LayerConfig), /// Run a command on the active document tab's command line (AutoLISP style). ExecuteCommand(String), /// Read a host-managed setting without nested command dispatch. GetSystemVariable { name: String, }, /// Change a host-managed setting without nested command dispatch. SetSystemVariable { name: String, value: HostSettingValue, }, /// V7: validate and replace existing entities in a single undo step. UpdateEntitiesTransaction { label: String, entities: Vec, }, /// V7: synchronous selection read/write for the dispatch tab. GetSelection, SetSelection { handles: Vec, }, /// V7 (additive): kernel-backed solid create or transform. SolidOperation { operation: crate::host::SolidOperation, }, /// V7 (additive): drawing table record create/modify/rename/delete. TableOperation { operation: crate::host::TableOperation, }, /// V7 (additive): drive an OCS command. RunCommand { request: crate::host::CommandRequest, }, /// V8 (additive): create an XRecord under a named-object-dictionary path. CreateXRecord { dictionary_path: Vec, name: String, entries: Vec, }, /// V8 (additive): read the entries of an existing XRecord. ReadXRecord { dictionary_path: Vec, name: String, }, /// V8 (additive): replace the entries of an existing XRecord. UpdateXRecord { dictionary_path: Vec, name: String, entries: Vec, }, /// V8 (additive): delete an XRecord and its dictionary entry. DeleteXRecord { dictionary_path: Vec, name: String, }, /// V8 (additive): list the XRecord names under a dictionary path. ListXRecords { dictionary_path: Vec, }, /// V9 (additive): mark an entity reference-only (plugin-owned display data). SetReferenceOnly { handle: Handle, reference_only: bool, }, } /// Responses the host sends back for `PluginRequest`. #[derive(Debug, Serialize, Deserialize)] pub enum PluginResponse { Ok, Bool(bool), Handle(Handle), Record(Option), Document(Box), Error(String), /// Path to the memory-mapped file and the current snapshot version. DocumentView { path: String, version: u64, }, Handles(Vec), /// V4: path to the tab-keyed memory-mapped file and current version. DocumentViewV4 { path: String, version: u64, }, /// V4: stable tab identifier of the active tab. TabId(u64), /// V5: filesystem path of the document in the requested tab, if any. DocumentPath(Option), /// Optional entity handle (e.g. from AddLayer). OptHandle(Option), SystemVariable(Option), SystemVariableResult(Result), EntityTransactionResult(Result<(), String>), Selection(Vec), SelectionResult(Result<(), String>), SolidResult(Result), TableResult(Result), CommandResult(Result), /// V8 (additive): handle of a created XRecord. XRecordCreateResult(Result), /// V8 (additive): entries of a read XRecord. XRecordEntries(Result, String>), /// V8 (additive): handle of an updated XRecord. XRecordUpdateResult(Result), /// V8 (additive): the removed XRecord, with its prior content. XRecordDeleteResult(Result), /// V8 (additive): XRecord names under a dictionary path. XRecordNames(Result, String>), /// V9 (additive): outcome of the reference-only designation. SetReferenceOnlyResult(Result<(), String>), } /// Messages sent from the host to the plugin runner. #[derive(Debug, Serialize, Deserialize)] pub enum HostToPlugin { Request(HostRequest), Response(Box), } /// Messages sent from the plugin runner to the host. #[derive(Debug, Serialize, Deserialize)] pub enum PluginToHost { Request(Box), Response(HostResponse), } /// Convenience helper for manifest serialization. impl From<&'static crate::manifest::PluginManifest> for OwnedPluginManifest { fn from(m: &'static crate::manifest::PluginManifest) -> Self { Self { id: m.id.to_string(), name: m.name.to_string(), version: m.version.to_string(), description: m.description.to_string(), api_version: m.api_version.major, ribbon_order: m.ribbon_order, xdata_apps: m.xdata_apps.iter().map(|s| s.to_string()).collect(), command_prefixes: m.command_prefixes.iter().map(|s| s.to_string()).collect(), } } } impl OwnedPluginManifest { pub fn api_version(&self) -> ApiVersion { ApiVersion { major: self.api_version, } } }