Spawn a plugin host subprocess and run the `initialize` handshake. `cwd` sets the working directory for the subprocess so that bare-specifier `import("pkg")` calls resolve against the correct `node_modules/`.
(
runtime: JsRuntime,
host_script: &str,
plugin_path: &str,
context: PluginContext,
cwd: Option<&std::path::Path>,
)
| 141 | /// `cwd` sets the working directory for the subprocess so that bare-specifier |
| 142 | /// `import("pkg")` calls resolve against the correct `node_modules/`. |
| 143 | pub async fn spawn( |
| 144 | runtime: JsRuntime, |
| 145 | host_script: &str, |
| 146 | plugin_path: &str, |
| 147 | context: PluginContext, |
| 148 | cwd: Option<&std::path::Path>, |
| 149 | ) -> Result<Self, PluginSubprocessError> { |
| 150 | let args = runtime.run_args(host_script); |
| 151 | let mut cmd = Command::new(runtime.command()); |
| 152 | cmd.args(&args) |
| 153 | .stdin(Stdio::piped()) |
| 154 | .stdout(Stdio::piped()) |
| 155 | .stderr(Stdio::inherit()) // plugin logs go to parent stderr |
| 156 | .kill_on_drop(true); |
| 157 | if let Some(dir) = cwd { |
| 158 | cmd.current_dir(dir); |
| 159 | } |
| 160 | |
| 161 | let mut child = cmd.spawn()?; |
| 162 | |
| 163 | let stdin = child |
| 164 | .stdin |
| 165 | .take() |
| 166 | .ok_or_else(|| PluginSubprocessError::Protocol("no stdin".into()))?; |
| 167 | let stdout = child |
| 168 | .stdout |
| 169 | .take() |
| 170 | .ok_or_else(|| PluginSubprocessError::Protocol("no stdout".into()))?; |
| 171 | |
| 172 | let mut this = Self { |
| 173 | name: String::new(), |
| 174 | stdin: Arc::new(Mutex::new(stdin)), |
| 175 | stdout: Arc::new(Mutex::new(BufReader::new(stdout))), |
| 176 | rpc_lock: Arc::new(Mutex::new(())), |
| 177 | process: Mutex::new(child), |
| 178 | request_id: AtomicU64::new(1), |
| 179 | hooks: Vec::new(), |
| 180 | auth_meta: None, |
| 181 | timeout: Duration::from_secs(30), |
| 182 | }; |
| 183 | |
| 184 | // Send initialize |
| 185 | let params = serde_json::json!({ |
| 186 | "pluginPath": plugin_path, |
| 187 | "context": context, |
| 188 | }); |
| 189 | let result: InitializeResult = this.call("initialize", Some(params)).await?; |
| 190 | |
| 191 | this.name = result.name; |
| 192 | this.hooks = result.hooks; |
| 193 | this.auth_meta = result.auth; |
| 194 | |
| 195 | Ok(this) |
| 196 | } |
| 197 | |
| 198 | // -- Accessors ---------------------------------------------------------- |
| 199 |
no test coverage detected